From e4798d26548b264be6604b45e4281244e96c9a09 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 11 May 2017 09:58:22 +0300 Subject: [PATCH 001/418] ASoC: davinci-mcasp: Support for one channel (mono) audio Mono audio can be achieved by configuring McASP to transmit/receive only during one timeslot. McASP will still going to generate clocks for the other slot(s), but will only use the single slot to transmit/receive. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-mcasp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 3c5a9804d3f5..56ec1d301ac2 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -629,7 +629,7 @@ static int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp, int stream, if (mcasp->tdm_mask[stream]) slots = hweight32(mcasp->tdm_mask[stream]); - for (i = 2; i <= slots; i++) + for (i = 1; i <= slots; i++) list[count++] = i; for (i = 2; i <= serializers; i++) @@ -1297,7 +1297,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_CHANNELS, - 2, max_channels); + 0, max_channels); snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, @@ -1459,13 +1459,13 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { .suspend = davinci_mcasp_suspend, .resume = davinci_mcasp_resume, .playback = { - .channels_min = 2, + .channels_min = 1, .channels_max = 32 * 16, .rates = DAVINCI_MCASP_RATES, .formats = DAVINCI_MCASP_PCM_FMTS, }, .capture = { - .channels_min = 2, + .channels_min = 1, .channels_max = 32 * 16, .rates = DAVINCI_MCASP_RATES, .formats = DAVINCI_MCASP_PCM_FMTS, @@ -1971,12 +1971,12 @@ static int davinci_mcasp_probe(struct platform_device *pdev) */ mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list = devm_kzalloc(mcasp->dev, sizeof(unsigned int) * - (32 + mcasp->num_serializer - 2), + (32 + mcasp->num_serializer - 1), GFP_KERNEL); mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list = devm_kzalloc(mcasp->dev, sizeof(unsigned int) * - (32 + mcasp->num_serializer - 2), + (32 + mcasp->num_serializer - 1), GFP_KERNEL); if (!mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list || From 03ba791df98d15d07ea74075122af71e35c7611c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 11 May 2017 13:44:38 +0200 Subject: [PATCH 002/418] ASoC: rt5514: fix gcc-7 warning gcc-7 warns that there is a duplicate 'const' specifier in some variables that are declared using the SOC_ENUM_SINGLE_DECL macro: sound/soc/codecs/rt5514.c:398:14: error: duplicate 'const' declaration specifier [-Werror=duplicate-decl-specifier] static const SOC_ENUM_SINGLE_DECL( sound/soc/codecs/rt5514.c:405:14: error: duplicate 'const' declaration specifier [-Werror=duplicate-decl-specifier] static const SOC_ENUM_SINGLE_DECL( This removes one to fix the warning. Fixes: 4a6180ea7399 ("ASoC: rt5514: add rt5514 codec driver") Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index f91221b1ddf0..28ab9e2bb051 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); From 27a655c4bd8d9851c0f2ef9ec0d3793d068acbe9 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 11 May 2017 13:44:39 +0200 Subject: [PATCH 003/418] ASoC: rt5665: fix gcc-7 warning gcc-7 warns that there is a duplicate 'const' specifier in some variables that are declared using the SOC_ENUM_SINGLE_DECL macro: sound/soc/codecs/rt5665.c:915:14: error: duplicate 'const' declaration specifier [-Werror=duplicate-decl-specifier] static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_01_adc_enum, sound/soc/codecs/rt5665.c:918:14: error: duplicate 'const' declaration specifier [-Werror=duplicate-decl-specifier] static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_23_adc_enum, sound/soc/codecs/rt5665.c:921:14: error: duplicate 'const' declaration specifier [-Werror=duplicate-decl-specifier] static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_45_adc_enum, sound/soc/codecs/rt5665.c:924:14: error: duplicate 'const' declaration specifier [-Werror=duplicate-decl-specifier] static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_67_adc_enum, ... This removes one to fix the 68 warnings in this file Fixes: 33ada14a26c8 ("ASoC: add rt5665 codec driver") Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 136 +++++++++++++++++++------------------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 8cd22307f5b6..14b0cf89edf5 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -912,46 +912,46 @@ static const char * const rt5665_data_select[] = { "L/R", "R/L", "L/L", "R/R" }; -static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_01_adc_enum, +static SOC_ENUM_SINGLE_DECL(rt5665_if1_1_01_adc_enum, RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT01_SFT, rt5665_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_23_adc_enum, +static SOC_ENUM_SINGLE_DECL(rt5665_if1_1_23_adc_enum, RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT23_SFT, rt5665_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_45_adc_enum, +static SOC_ENUM_SINGLE_DECL(rt5665_if1_1_45_adc_enum, RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT45_SFT, rt5665_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_67_adc_enum, +static SOC_ENUM_SINGLE_DECL(rt5665_if1_1_67_adc_enum, RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT67_SFT, rt5665_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_01_adc_enum, +static SOC_ENUM_SINGLE_DECL(rt5665_if1_2_01_adc_enum, RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT01_SFT, rt5665_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_23_adc_enum, +static SOC_ENUM_SINGLE_DECL(rt5665_if1_2_23_adc_enum, RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT23_SFT, rt5665_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_45_adc_enum, +static SOC_ENUM_SINGLE_DECL(rt5665_if1_2_45_adc_enum, RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT45_SFT, rt5665_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_67_adc_enum, +static SOC_ENUM_SINGLE_DECL(rt5665_if1_2_67_adc_enum, RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT67_SFT, rt5665_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5665_if2_1_dac_enum, +static SOC_ENUM_SINGLE_DECL(rt5665_if2_1_dac_enum, RT5665_DIG_INF2_DATA, RT5665_IF2_1_DAC_SEL_SFT, rt5665_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5665_if2_1_adc_enum, +static SOC_ENUM_SINGLE_DECL(rt5665_if2_1_adc_enum, RT5665_DIG_INF2_DATA, RT5665_IF2_1_ADC_SEL_SFT, rt5665_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5665_if2_2_dac_enum, +static SOC_ENUM_SINGLE_DECL(rt5665_if2_2_dac_enum, RT5665_DIG_INF2_DATA, RT5665_IF2_2_DAC_SEL_SFT, rt5665_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5665_if2_2_adc_enum, +static SOC_ENUM_SINGLE_DECL(rt5665_if2_2_adc_enum, RT5665_DIG_INF2_DATA, RT5665_IF2_2_ADC_SEL_SFT, rt5665_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5665_if3_dac_enum, +static SOC_ENUM_SINGLE_DECL(rt5665_if3_dac_enum, RT5665_DIG_INF3_DATA, RT5665_IF3_DAC_SEL_SFT, rt5665_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5665_if3_adc_enum, +static SOC_ENUM_SINGLE_DECL(rt5665_if3_adc_enum, RT5665_DIG_INF3_DATA, RT5665_IF3_ADC_SEL_SFT, rt5665_data_select); static const struct snd_kcontrol_new rt5665_if1_1_01_adc_swap_mux = @@ -1819,14 +1819,14 @@ static const char * const rt5665_dac2_src[] = { "IF1 DAC2", "IF2_1 DAC", "IF2_2 DAC", "IF3 DAC", "Mono ADC MIX" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_dac_l2_enum, RT5665_DAC2_CTRL, RT5665_DAC_L2_SEL_SFT, rt5665_dac2_src); static const struct snd_kcontrol_new rt5665_dac_l2_mux = SOC_DAPM_ENUM("Digital DAC L2 Source", rt5665_dac_l2_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_dac_r2_enum, RT5665_DAC2_CTRL, RT5665_DAC_R2_SEL_SFT, rt5665_dac2_src); @@ -1839,14 +1839,14 @@ static const char * const rt5665_dac3_src[] = { "IF1 DAC2", "IF2_1 DAC", "IF2_2 DAC", "IF3 DAC", "STO2 ADC MIX" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_dac_l3_enum, RT5665_DAC3_CTRL, RT5665_DAC_L3_SEL_SFT, rt5665_dac3_src); static const struct snd_kcontrol_new rt5665_dac_l3_mux = SOC_DAPM_ENUM("Digital DAC L3 Source", rt5665_dac_l3_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_dac_r3_enum, RT5665_DAC3_CTRL, RT5665_DAC_R3_SEL_SFT, rt5665_dac3_src); @@ -1859,14 +1859,14 @@ static const char * const rt5665_sto1_adc1_src[] = { "DD Mux", "ADC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_sto1_adc1l_enum, RT5665_STO1_ADC_MIXER, RT5665_STO1_ADC1L_SRC_SFT, rt5665_sto1_adc1_src); static const struct snd_kcontrol_new rt5665_sto1_adc1l_mux = SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5665_sto1_adc1l_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_sto1_adc1r_enum, RT5665_STO1_ADC_MIXER, RT5665_STO1_ADC1R_SRC_SFT, rt5665_sto1_adc1_src); @@ -1879,14 +1879,14 @@ static const char * const rt5665_sto1_adc_src[] = { "ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_sto1_adcl_enum, RT5665_STO1_ADC_MIXER, RT5665_STO1_ADCL_SRC_SFT, rt5665_sto1_adc_src); static const struct snd_kcontrol_new rt5665_sto1_adcl_mux = SOC_DAPM_ENUM("Stereo1 ADCL Source", rt5665_sto1_adcl_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_sto1_adcr_enum, RT5665_STO1_ADC_MIXER, RT5665_STO1_ADCR_SRC_SFT, rt5665_sto1_adc_src); @@ -1899,14 +1899,14 @@ static const char * const rt5665_sto1_adc2_src[] = { "DAC MIX", "DMIC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_sto1_adc2l_enum, RT5665_STO1_ADC_MIXER, RT5665_STO1_ADC2L_SRC_SFT, rt5665_sto1_adc2_src); static const struct snd_kcontrol_new rt5665_sto1_adc2l_mux = SOC_DAPM_ENUM("Stereo1 ADC2L Source", rt5665_sto1_adc2l_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_sto1_adc2r_enum, RT5665_STO1_ADC_MIXER, RT5665_STO1_ADC2R_SRC_SFT, rt5665_sto1_adc2_src); @@ -1919,7 +1919,7 @@ static const char * const rt5665_sto1_dmic_src[] = { "DMIC1", "DMIC2" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_sto1_dmic_enum, RT5665_STO1_ADC_MIXER, RT5665_STO1_DMIC_SRC_SFT, rt5665_sto1_dmic_src); @@ -1931,7 +1931,7 @@ static const char * const rt5665_sto1_dd_l_src[] = { "STO2 DAC", "MONO DAC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_sto1_dd_l_enum, RT5665_STO1_ADC_MIXER, RT5665_STO1_DD_L_SRC_SFT, rt5665_sto1_dd_l_src); @@ -1943,7 +1943,7 @@ static const char * const rt5665_sto1_dd_r_src[] = { "STO2 DAC", "MONO DAC", "AEC REF" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_sto1_dd_r_enum, RT5665_STO1_ADC_MIXER, RT5665_STO1_DD_R_SRC_SFT, rt5665_sto1_dd_r_src); @@ -1956,7 +1956,7 @@ static const char * const rt5665_mono_adc_l2_src[] = { "DAC MIXL", "DMIC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_mono_adc_l2_enum, RT5665_MONO_ADC_MIXER, RT5665_MONO_ADC_L2_SRC_SFT, rt5665_mono_adc_l2_src); @@ -1970,7 +1970,7 @@ static const char * const rt5665_mono_adc_l1_src[] = { "DD Mux", "ADC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_mono_adc_l1_enum, RT5665_MONO_ADC_MIXER, RT5665_MONO_ADC_L1_SRC_SFT, rt5665_mono_adc_l1_src); @@ -1982,14 +1982,14 @@ static const char * const rt5665_mono_dd_src[] = { "STO2 DAC", "MONO DAC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_mono_dd_l_enum, RT5665_MONO_ADC_MIXER, RT5665_MONO_DD_L_SRC_SFT, rt5665_mono_dd_src); static const struct snd_kcontrol_new rt5665_mono_dd_l_mux = SOC_DAPM_ENUM("Mono DD L Source", rt5665_mono_dd_l_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_mono_dd_r_enum, RT5665_MONO_ADC_MIXER, RT5665_MONO_DD_R_SRC_SFT, rt5665_mono_dd_src); @@ -2002,14 +2002,14 @@ static const char * const rt5665_mono_adc_src[] = { "ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_mono_adc_l_enum, RT5665_MONO_ADC_MIXER, RT5665_MONO_ADC_L_SRC_SFT, rt5665_mono_adc_src); static const struct snd_kcontrol_new rt5665_mono_adc_l_mux = SOC_DAPM_ENUM("Mono ADC L Source", rt5665_mono_adc_l_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_mono_adcr_enum, RT5665_MONO_ADC_MIXER, RT5665_MONO_ADC_R_SRC_SFT, rt5665_mono_adc_src); @@ -2022,7 +2022,7 @@ static const char * const rt5665_mono_dmic_l_src[] = { "DMIC1 L", "DMIC2 L" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_mono_dmic_l_enum, RT5665_MONO_ADC_MIXER, RT5665_MONO_DMIC_L_SRC_SFT, rt5665_mono_dmic_l_src); @@ -2035,7 +2035,7 @@ static const char * const rt5665_mono_adc_r2_src[] = { "DAC MIXR", "DMIC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_mono_adc_r2_enum, RT5665_MONO_ADC_MIXER, RT5665_MONO_ADC_R2_SRC_SFT, rt5665_mono_adc_r2_src); @@ -2048,7 +2048,7 @@ static const char * const rt5665_mono_adc_r1_src[] = { "DD Mux", "ADC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_mono_adc_r1_enum, RT5665_MONO_ADC_MIXER, RT5665_MONO_ADC_R1_SRC_SFT, rt5665_mono_adc_r1_src); @@ -2061,7 +2061,7 @@ static const char * const rt5665_mono_dmic_r_src[] = { "DMIC1 R", "DMIC2 R" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_mono_dmic_r_enum, RT5665_MONO_ADC_MIXER, RT5665_MONO_DMIC_R_SRC_SFT, rt5665_mono_dmic_r_src); @@ -2075,14 +2075,14 @@ static const char * const rt5665_sto2_adc1_src[] = { "DD Mux", "ADC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_sto2_adc1l_enum, RT5665_STO2_ADC_MIXER, RT5665_STO2_ADC1L_SRC_SFT, rt5665_sto2_adc1_src); static const struct snd_kcontrol_new rt5665_sto2_adc1l_mux = SOC_DAPM_ENUM("Stereo2 ADC1L Source", rt5665_sto2_adc1l_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_sto2_adc1r_enum, RT5665_STO2_ADC_MIXER, RT5665_STO2_ADC1R_SRC_SFT, rt5665_sto2_adc1_src); @@ -2095,14 +2095,14 @@ static const char * const rt5665_sto2_adc_src[] = { "ADC1 L", "ADC1 R", "ADC2 L" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_sto2_adcl_enum, RT5665_STO2_ADC_MIXER, RT5665_STO2_ADCL_SRC_SFT, rt5665_sto2_adc_src); static const struct snd_kcontrol_new rt5665_sto2_adcl_mux = SOC_DAPM_ENUM("Stereo2 ADCL Source", rt5665_sto2_adcl_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_sto2_adcr_enum, RT5665_STO2_ADC_MIXER, RT5665_STO2_ADCR_SRC_SFT, rt5665_sto2_adc_src); @@ -2115,14 +2115,14 @@ static const char * const rt5665_sto2_adc2_src[] = { "DAC MIX", "DMIC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_sto2_adc2l_enum, RT5665_STO2_ADC_MIXER, RT5665_STO2_ADC2L_SRC_SFT, rt5665_sto2_adc2_src); static const struct snd_kcontrol_new rt5665_sto2_adc2l_mux = SOC_DAPM_ENUM("Stereo2 ADC2L Source", rt5665_sto2_adc2l_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_sto2_adc2r_enum, RT5665_STO2_ADC_MIXER, RT5665_STO2_ADC2R_SRC_SFT, rt5665_sto2_adc2_src); @@ -2135,7 +2135,7 @@ static const char * const rt5665_sto2_dmic_src[] = { "DMIC1", "DMIC2" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_sto2_dmic_enum, RT5665_STO2_ADC_MIXER, RT5665_STO2_DMIC_SRC_SFT, rt5665_sto2_dmic_src); @@ -2147,7 +2147,7 @@ static const char * const rt5665_sto2_dd_l_src[] = { "STO2 DAC", "MONO DAC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_sto2_dd_l_enum, RT5665_STO2_ADC_MIXER, RT5665_STO2_DD_L_SRC_SFT, rt5665_sto2_dd_l_src); @@ -2159,7 +2159,7 @@ static const char * const rt5665_sto2_dd_r_src[] = { "STO2 DAC", "MONO DAC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_sto2_dd_r_enum, RT5665_STO2_ADC_MIXER, RT5665_STO2_DD_R_SRC_SFT, rt5665_sto2_dd_r_src); @@ -2172,14 +2172,14 @@ static const char * const rt5665_dac1_src[] = { "IF1 DAC1", "IF2_1 DAC", "IF2_2 DAC", "IF3 DAC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_dac_r1_enum, RT5665_AD_DA_MIXER, RT5665_DAC1_R_SEL_SFT, rt5665_dac1_src); static const struct snd_kcontrol_new rt5665_dac_r1_mux = SOC_DAPM_ENUM("DAC R1 Source", rt5665_dac_r1_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_dac_l1_enum, RT5665_AD_DA_MIXER, RT5665_DAC1_L_SEL_SFT, rt5665_dac1_src); @@ -2192,14 +2192,14 @@ static const char * const rt5665_dig_dac_mix_src[] = { "Stereo1 DAC Mixer", "Stereo2 DAC Mixer", "Mono DAC Mixer" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_dig_dac_mixl_enum, RT5665_A_DAC1_MUX, RT5665_DAC_MIX_L_SFT, rt5665_dig_dac_mix_src); static const struct snd_kcontrol_new rt5665_dig_dac_mixl_mux = SOC_DAPM_ENUM("DAC Digital Mixer L Source", rt5665_dig_dac_mixl_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_dig_dac_mixr_enum, RT5665_A_DAC1_MUX, RT5665_DAC_MIX_R_SFT, rt5665_dig_dac_mix_src); @@ -2212,14 +2212,14 @@ static const char * const rt5665_alg_dac1_src[] = { "Stereo1 DAC Mixer", "DAC1", "DMIC1" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_alg_dac_l1_enum, RT5665_A_DAC1_MUX, RT5665_A_DACL1_SFT, rt5665_alg_dac1_src); static const struct snd_kcontrol_new rt5665_alg_dac_l1_mux = SOC_DAPM_ENUM("Analog DAC L1 Source", rt5665_alg_dac_l1_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_alg_dac_r1_enum, RT5665_A_DAC1_MUX, RT5665_A_DACR1_SFT, rt5665_alg_dac1_src); @@ -2232,14 +2232,14 @@ static const char * const rt5665_alg_dac2_src[] = { "Mono DAC Mixer", "DAC2" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_alg_dac_l2_enum, RT5665_A_DAC2_MUX, RT5665_A_DACL2_SFT, rt5665_alg_dac2_src); static const struct snd_kcontrol_new rt5665_alg_dac_l2_mux = SOC_DAPM_ENUM("Analog DAC L2 Source", rt5665_alg_dac_l2_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_alg_dac_r2_enum, RT5665_A_DAC2_MUX, RT5665_A_DACR2_SFT, rt5665_alg_dac2_src); @@ -2253,7 +2253,7 @@ static const char * const rt5665_if2_1_adc_in_src[] = { "IF1 DAC2", "IF2_2 DAC", "IF3 DAC", "DAC1 MIX" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_if2_1_adc_in_enum, RT5665_DIG_INF2_DATA, RT5665_IF2_1_ADC_IN_SFT, rt5665_if2_1_adc_in_src); @@ -2266,7 +2266,7 @@ static const char * const rt5665_if2_2_adc_in_src[] = { "IF1 DAC2", "IF2_1 DAC", "IF3 DAC", "DAC1 MIX" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_if2_2_adc_in_enum, RT5665_DIG_INF2_DATA, RT5665_IF2_2_ADC_IN_SFT, rt5665_if2_2_adc_in_src); @@ -2280,7 +2280,7 @@ static const char * const rt5665_if3_adc_in_src[] = { "IF1 DAC2", "IF2_1 DAC", "IF2_2 DAC", "DAC1 MIX" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_if3_adc_in_enum, RT5665_DIG_INF3_DATA, RT5665_IF3_ADC_IN_SFT, rt5665_if3_adc_in_src); @@ -2293,14 +2293,14 @@ static const char * const rt5665_pdm_src[] = { "Stereo1 DAC", "Stereo2 DAC", "Mono DAC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_pdm_l_enum, RT5665_PDM_OUT_CTRL, RT5665_PDM1_L_SFT, rt5665_pdm_src); static const struct snd_kcontrol_new rt5665_pdm_l_mux = SOC_DAPM_ENUM("PDM L Source", rt5665_pdm_l_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_pdm_r_enum, RT5665_PDM_OUT_CTRL, RT5665_PDM1_R_SFT, rt5665_pdm_src); @@ -2314,7 +2314,7 @@ static const char * const rt5665_if1_1_adc1_data_src[] = { "STO1 ADC", "IF2_1 DAC", }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_if1_1_adc1_data_enum, RT5665_TDM_CTRL_3, RT5665_IF1_ADC1_SEL_SFT, rt5665_if1_1_adc1_data_src); @@ -2326,7 +2326,7 @@ static const char * const rt5665_if1_1_adc2_data_src[] = { "STO2 ADC", "IF2_2 DAC", }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_if1_1_adc2_data_enum, RT5665_TDM_CTRL_3, RT5665_IF1_ADC2_SEL_SFT, rt5665_if1_1_adc2_data_src); @@ -2338,7 +2338,7 @@ static const char * const rt5665_if1_1_adc3_data_src[] = { "MONO ADC", "IF3 DAC", }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_if1_1_adc3_data_enum, RT5665_TDM_CTRL_3, RT5665_IF1_ADC3_SEL_SFT, rt5665_if1_1_adc3_data_src); @@ -2350,7 +2350,7 @@ static const char * const rt5665_if1_2_adc1_data_src[] = { "STO1 ADC", "IF1 DAC", }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_if1_2_adc1_data_enum, RT5665_TDM_CTRL_4, RT5665_IF1_ADC1_SEL_SFT, rt5665_if1_2_adc1_data_src); @@ -2362,7 +2362,7 @@ static const char * const rt5665_if1_2_adc2_data_src[] = { "STO2 ADC", "IF2_1 DAC", }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_if1_2_adc2_data_enum, RT5665_TDM_CTRL_4, RT5665_IF1_ADC2_SEL_SFT, rt5665_if1_2_adc2_data_src); @@ -2374,7 +2374,7 @@ static const char * const rt5665_if1_2_adc3_data_src[] = { "MONO ADC", "IF2_2 DAC", }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_if1_2_adc3_data_enum, RT5665_TDM_CTRL_4, RT5665_IF1_ADC3_SEL_SFT, rt5665_if1_2_adc3_data_src); @@ -2386,7 +2386,7 @@ static const char * const rt5665_if1_2_adc4_data_src[] = { "DAC1", "IF3 DAC", }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_if1_2_adc4_data_enum, RT5665_TDM_CTRL_4, RT5665_IF1_ADC4_SEL_SFT, rt5665_if1_2_adc4_data_src); @@ -2401,14 +2401,14 @@ static const char * const rt5665_tdm_adc_data_src[] = { "4123", "4132", "4213", "4231", "4312", "4321" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_tdm1_adc_data_enum, RT5665_TDM_CTRL_3, RT5665_TDM_ADC_SEL_SFT, rt5665_tdm_adc_data_src); static const struct snd_kcontrol_new rt5665_tdm1_adc_mux = SOC_DAPM_ENUM("TDM1 ADC Mux", rt5665_tdm1_adc_data_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5665_tdm2_adc_data_enum, RT5665_TDM_CTRL_4, RT5665_TDM_ADC_SEL_SFT, rt5665_tdm_adc_data_src); From ec185f95401e36f398b39706705f10d7fe7ff058 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 8 May 2017 02:28:13 +0000 Subject: [PATCH 004/418] ASoC: ak4613: disable asymmetric audio interface format Asymmetric audio interface formats exist in ak4613 by same register settings. Capture Playback 24bit LEFT_J 16bit RIGHT_J 24bit LEFT_J 20bit RIGHT_J 24bit LEFT_J 24bit RIGHT_J 24bit LEFT_J 24bit LEFT_J 24bit I2S 24bit I2S These asymmetric formats makes driver / behavior difficult. It is not HW limitation, but SW limitation. To makes code reading easy, this patch removes asymmetric format support. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/ak4613.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index b2dfddead227..557ac16d43e2 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -139,9 +139,7 @@ static const struct reg_default ak4613_reg[] = { #define AUDIO_IFACE(b, fmt) { b, SND_SOC_DAIFMT_##fmt } static const struct ak4613_interface ak4613_iface[] = { /* capture */ /* playback */ - [0] = { AUDIO_IFACE(24, LEFT_J), AUDIO_IFACE(16, RIGHT_J) }, - [1] = { AUDIO_IFACE(24, LEFT_J), AUDIO_IFACE(20, RIGHT_J) }, - [2] = { AUDIO_IFACE(24, LEFT_J), AUDIO_IFACE(24, RIGHT_J) }, + /* [0] - [2] are not supported */ [3] = { AUDIO_IFACE(24, LEFT_J), AUDIO_IFACE(24, LEFT_J) }, [4] = { AUDIO_IFACE(24, I2S), AUDIO_IFACE(24, I2S) }, }; @@ -262,11 +260,9 @@ static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) fmt &= SND_SOC_DAIFMT_FORMAT_MASK; switch (fmt) { - case SND_SOC_DAIFMT_RIGHT_J: case SND_SOC_DAIFMT_LEFT_J: case SND_SOC_DAIFMT_I2S: priv->fmt = fmt; - break; default: return -EINVAL; @@ -286,13 +282,8 @@ static bool ak4613_dai_fmt_matching(const struct ak4613_interface *iface, if (fmts->fmt != fmt) return false; - if (fmt == SND_SOC_DAIFMT_RIGHT_J) { - if (fmts->width != width) - return false; - } else { - if (fmts->width < width) - return false; - } + if (fmts->width != width) + return false; return true; } @@ -420,8 +411,7 @@ static const struct snd_soc_dai_ops ak4613_dai_ops = { SNDRV_PCM_RATE_96000 |\ SNDRV_PCM_RATE_176400 |\ SNDRV_PCM_RATE_192000) -#define AK4613_PCM_FMTBIT (SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S24_LE) +#define AK4613_PCM_FMTBIT (SNDRV_PCM_FMTBIT_S24_LE) static struct snd_soc_dai_driver ak4613_dai = { .name = "ak4613-hifi", From c0116be3d191393928d39791d203a4495d77b66c Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Thu, 4 May 2017 14:09:11 +0530 Subject: [PATCH 005/418] ASoC: Intel: Skylake: Fix typo for token d0i3 caps Signed-off-by: Subhransu S. Prusty Acked-by: Vinod Koul Signed-off-by: Mark Brown --- include/uapi/sound/snd_sst_tokens.h | 5 +++-- sound/soc/intel/skylake/skl-topology.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/uapi/sound/snd_sst_tokens.h b/include/uapi/sound/snd_sst_tokens.h index 93392bedcc58..89b82f6256ad 100644 --- a/include/uapi/sound/snd_sst_tokens.h +++ b/include/uapi/sound/snd_sst_tokens.h @@ -213,8 +213,9 @@ enum SKL_TKNS { SKL_TKN_U32_LIB_COUNT, SKL_TKN_STR_LIB_NAME, SKL_TKN_U32_PMODE, - SKL_TKL_U32_D0I3_CAPS, - SKL_TKN_MAX = SKL_TKL_U32_D0I3_CAPS, + SKL_TKL_U32_D0I3_CAPS, /* Typo added at v4.10 */ + SKL_TKN_U32_D0I3_CAPS = SKL_TKL_U32_D0I3_CAPS, + SKL_TKN_MAX = SKL_TKN_U32_D0I3_CAPS, }; #endif diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 3a99712e44a8..b28199a5348c 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -1995,7 +1995,7 @@ static int skl_tplg_get_token(struct device *dev, mconfig->converter = tkn_elem->value; break; - case SKL_TKL_U32_D0I3_CAPS: + case SKL_TKN_U32_D0I3_CAPS: mconfig->d0i3_caps = tkn_elem->value; break; From 9f3b777f1de9ff5d17f7259b8f7da5e9d4303e87 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 2 May 2017 22:33:01 +0900 Subject: [PATCH 006/418] ASoC: codecs: msm8916: fix invalid cast to bool type A function snd_soc_update_bits() is an application of regmap_update_bits_base(). This function takes some arguments for bitmask and new value, thus the arguments should be a type which has width. However bool is used to variable for the argument. This brings truncation and results in invalid operation. This commit fixes this bug by using unsigned int type, instead of bool. This bug is detected by sparse: smsm8916-wcd-analog.c:809:43: warning: odd constant _Bool cast (40 becomes 1) smsm8916-wcd-analog.c:814:43: warning: odd constant _Bool cast (40 becomes 1) Fixes: 585e881e5b9e ("ASoC: codecs: Add msm8916-wcd analog codec") Signed-off-by: Takashi Sakamoto Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-analog.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index d8e8590746af..a78802920c3c 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -223,8 +223,8 @@ struct pm8916_wcd_analog_priv { u16 codec_version; struct clk *mclk; struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; - bool micbias1_cap_mode; - bool micbias2_cap_mode; + unsigned int micbias1_cap_mode; + unsigned int micbias2_cap_mode; }; static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" }; @@ -285,7 +285,7 @@ static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec) static int pm8916_wcd_analog_enable_micbias_ext(struct snd_soc_codec *codec, int event, - int reg, u32 cap_mode) + int reg, unsigned int cap_mode) { switch (event) { case SND_SOC_DAPM_POST_PMU: From 2a54e845f6e5069666e1749bd952abdc0413910d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 2 May 2017 22:33:02 +0900 Subject: [PATCH 007/418] ASoC: hisilicon: localize functions without external linkage A driver for hi6210 sound interface on hi6220 boards includes some functions which has no external linkage. These functions should have static qualifier. This commit adds the qualifier to localize the functions. This issue is detected by sparse: hi6210-i2s.c:100:5: warning: symbol 'hi6210_i2s_startup' was not declared. Should it be static? hi6210-i2s.c:178:6: warning: symbol 'hi6210_i2s_shutdown' was not declared. Should it be static? hi6210-i2s.c:527:27: warning: symbol 'hi6210_i2s_dai_init' was not declared. Should it be static? Signed-off-by: Takashi Sakamoto Signed-off-by: Mark Brown --- sound/soc/hisilicon/hi6210-i2s.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c index 45163e5202f5..b193d3beb253 100644 --- a/sound/soc/hisilicon/hi6210-i2s.c +++ b/sound/soc/hisilicon/hi6210-i2s.c @@ -97,8 +97,8 @@ static inline u32 hi6210_read_reg(struct hi6210_i2s *i2s, int reg) return readl(i2s->base + reg); } -int hi6210_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) +static int hi6210_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) { struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev); int ret, n; @@ -175,8 +175,9 @@ int hi6210_i2s_startup(struct snd_pcm_substream *substream, return 0; } -void hi6210_i2s_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) + +static void hi6210_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) { struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev); int n; @@ -524,7 +525,7 @@ static struct snd_soc_dai_ops hi6210_i2s_dai_ops = { .shutdown = hi6210_i2s_shutdown, }; -struct snd_soc_dai_driver hi6210_i2s_dai_init = { +static const struct snd_soc_dai_driver hi6210_i2s_dai_init = { .probe = hi6210_i2s_dai_probe, .playback = { .channels_min = 2, From 65db85fba1df213ff80d6f3cbafee244c58f6ec3 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 2 May 2017 22:33:03 +0900 Subject: [PATCH 008/418] ASoC: intel: atom: localize variable without external linkage A driver for Intel SST driver for old atom platform includes a variable which has no external linkage. These functions should have static qualifier. This commit adds the qualifier to localize the variable. This issue is detected by sparse: sst.c:261:1: warning: symbol 'dev_attr_firmware_version' was not declared. Should it be static? Cc: Sebastien Guiriec Cc: Vinod Koul Signed-off-by: Takashi Sakamoto Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index f9ba71315e33..d97556a3772c 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -258,7 +258,7 @@ static ssize_t firmware_version_show(struct device *dev, } -DEVICE_ATTR_RO(firmware_version); +static DEVICE_ATTR_RO(firmware_version); static const struct attribute *sst_fw_version_attrs[] = { &dev_attr_firmware_version.attr, From 51827c41c9ce07293b094691673e6ec23dfdc5e8 Mon Sep 17 00:00:00 2001 From: Tomas Vilda Date: Sat, 13 May 2017 00:29:37 +0300 Subject: [PATCH 009/418] ASoC: tlv320dac31xx: Fix mistype in tlv320dac31xx codec Signed-off-by: Tomas Vilda Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index f8a90ba8cd71..d7d03c92cb8a 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1210,7 +1210,7 @@ static const struct snd_soc_dai_ops aic31xx_dai_ops = { static struct snd_soc_dai_driver dac31xx_dai_driver[] = { { - .name = "tlv32dac31xx-hifi", + .name = "tlv320dac31xx-hifi", .playback = { .stream_name = "Playback", .channels_min = 2, From 3c0a98c595d87b9c961bafa755c2c0f3c031249c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 10 May 2017 11:29:40 +0100 Subject: [PATCH 010/418] ASoC: Intel: sst: fix spelling mistake: "allocationf" -> "allocation" Trivial fix to spelling mistake in dev_err message. Also replace "fail" with "failure". Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 21cac1c8dd4c..b082b31023d5 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -690,7 +690,7 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) snd_dma_continuous_data(GFP_DMA), SST_MIN_BUFFER, SST_MAX_BUFFER); if (retval) { - dev_err(rtd->dev, "dma buffer allocationf fail\n"); + dev_err(rtd->dev, "dma buffer allocation failure\n"); return retval; } } From fa1014302791a1e436387e93a90f38717d7f9b03 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Tue, 2 May 2017 09:42:58 +0800 Subject: [PATCH 011/418] ASoC: nau8824: TDM support Support TDM format for NAU88L24. Signed-off-by: John Hsu Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8824.c | 52 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/nau8824.h | 12 +++++++++ 2 files changed, 64 insertions(+) diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index cca974d26136..3a309b18035e 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -1124,6 +1124,57 @@ static int nau8824_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +/** + * nau8824_set_tdm_slot - configure DAI TDM. + * @dai: DAI + * @tx_mask: Bitmask representing active TX slots. Ex. + * 0xf for normal 4 channel TDM. + * 0xf0 for shifted 4 channel TDM + * @rx_mask: Bitmask [0:1] representing active DACR RX slots. + * Bitmask [2:3] representing active DACL RX slots. + * 00=CH0,01=CH1,10=CH2,11=CH3. Ex. + * 0xf for DACL/R selecting TDM CH3. + * 0xf0 for DACL/R selecting shifted TDM CH3. + * @slots: Number of slots in use. + * @slot_width: Width in bits for each slot. + * + * Configures a DAI for TDM operation. Only support 4 slots TDM. + */ +static int nau8824_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec); + unsigned int tslot_l = 0, ctrl_val = 0; + + if (slots > 4 || ((tx_mask & 0xf0) && (tx_mask & 0xf)) || + ((rx_mask & 0xf0) && (rx_mask & 0xf)) || + ((rx_mask & 0xf0) && (tx_mask & 0xf)) || + ((rx_mask & 0xf) && (tx_mask & 0xf0))) + return -EINVAL; + + ctrl_val |= (NAU8824_TDM_MODE | NAU8824_TDM_OFFSET_EN); + if (tx_mask & 0xf0) { + tslot_l = 4 * slot_width; + ctrl_val |= (tx_mask >> 4); + } else { + ctrl_val |= tx_mask; + } + if (rx_mask & 0xf0) + ctrl_val |= ((rx_mask >> 4) << NAU8824_TDM_DACR_RX_SFT); + else + ctrl_val |= (rx_mask << NAU8824_TDM_DACR_RX_SFT); + + regmap_update_bits(nau8824->regmap, NAU8824_REG_TDM_CTRL, + NAU8824_TDM_MODE | NAU8824_TDM_OFFSET_EN | + NAU8824_TDM_DACL_RX_MASK | NAU8824_TDM_DACR_RX_MASK | + NAU8824_TDM_TX_MASK, ctrl_val); + regmap_update_bits(nau8824->regmap, NAU8824_REG_PORT0_LEFT_TIME_SLOT, + NAU8824_TSLOT_L_MASK, tslot_l); + + return 0; +} + /** * nau8824_calc_fll_param - Calculate FLL parameters. * @fll_in: external clock provided to codec. @@ -1440,6 +1491,7 @@ static struct snd_soc_codec_driver nau8824_codec_driver = { static const struct snd_soc_dai_ops nau8824_dai_ops = { .hw_params = nau8824_hw_params, .set_fmt = nau8824_set_fmt, + .set_tdm_slot = nau8824_set_tdm_slot, }; #define NAU8824_RATES SNDRV_PCM_RATE_8000_192000 diff --git a/sound/soc/codecs/nau8824.h b/sound/soc/codecs/nau8824.h index 87ac9a382aed..21eae2431c83 100644 --- a/sound/soc/codecs/nau8824.h +++ b/sound/soc/codecs/nau8824.h @@ -258,6 +258,18 @@ #define NAU8824_I2S_MS_SLAVE (0 << NAU8824_I2S_MS_SFT) #define NAU8824_I2S_BLK_DIV_MASK 0x7 +/* PORT0_LEFT_TIME_SLOT (0x1E) */ +#define NAU8824_TSLOT_L_MASK 0x3ff + +/* TDM_CTRL (0x20) */ +#define NAU8824_TDM_MODE (0x1 << 15) +#define NAU8824_TDM_OFFSET_EN (0x1 << 14) +#define NAU8824_TDM_DACL_RX_SFT 6 +#define NAU8824_TDM_DACL_RX_MASK (0x3 << NAU8824_TDM_DACL_RX_SFT) +#define NAU8824_TDM_DACR_RX_SFT 4 +#define NAU8824_TDM_DACR_RX_MASK (0x3 << NAU8824_TDM_DACR_RX_SFT) +#define NAU8824_TDM_TX_MASK 0xf + /* ADC_FILTER_CTRL (0x24) */ #define NAU8824_ADC_SYNC_DOWN_MASK 0x3 #define NAU8824_ADC_SYNC_DOWN_32 0 From d60bc8d6c6d7e5f9765852b0be57de639ba65808 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Tue, 2 May 2017 10:42:56 +0800 Subject: [PATCH 012/418] ASoC: rt5514: Add more width and channels support in the TDM mode This patch adds more width and channels support in the TDM mode. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514.c | 23 +++++++++++++++++++++-- sound/soc/codecs/rt5514.h | 6 ++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index f91221b1ddf0..ff97360c03db 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -906,9 +906,23 @@ static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, if (rx_mask || tx_mask) val |= RT5514_TDM_MODE; - if (slots == 4) + switch (slots) { + case 4: val |= RT5514_TDMSLOT_SEL_RX_4CH | RT5514_TDMSLOT_SEL_TX_4CH; + break; + case 6: + val |= RT5514_TDMSLOT_SEL_RX_6CH | RT5514_TDMSLOT_SEL_TX_6CH; + break; + + case 8: + val |= RT5514_TDMSLOT_SEL_RX_8CH | RT5514_TDMSLOT_SEL_TX_8CH; + break; + + case 2: + default: + break; + } switch (slot_width) { case 20: @@ -919,6 +933,10 @@ static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, val |= RT5514_CH_LEN_RX_24 | RT5514_CH_LEN_TX_24; break; + case 25: + val |= RT5514_TDM_MODE2; + break; + case 32: val |= RT5514_CH_LEN_RX_32 | RT5514_CH_LEN_TX_32; break; @@ -930,7 +948,8 @@ static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL1, RT5514_TDM_MODE | RT5514_TDMSLOT_SEL_RX_MASK | RT5514_TDMSLOT_SEL_TX_MASK | - RT5514_CH_LEN_RX_MASK | RT5514_CH_LEN_TX_MASK, val); + RT5514_CH_LEN_RX_MASK | RT5514_CH_LEN_TX_MASK | + RT5514_TDM_MODE2, val); return 0; } diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h index 5d343fb6d125..02bc212a86d9 100644 --- a/sound/soc/codecs/rt5514.h +++ b/sound/soc/codecs/rt5514.h @@ -117,6 +117,8 @@ #define RT5514_POW_ADCFEDL_BIT 0 /* RT5514_I2S_CTRL1 (0x2010) */ +#define RT5514_TDM_MODE2 (0x1 << 30) +#define RT5514_TDM_MODE2_SFT 30 #define RT5514_TDM_MODE (0x1 << 28) #define RT5514_TDM_MODE_SFT 28 #define RT5514_I2S_LR_MASK (0x1 << 26) @@ -136,6 +138,8 @@ #define RT5514_TDMSLOT_SEL_RX_MASK (0x3 << 10) #define RT5514_TDMSLOT_SEL_RX_SFT 10 #define RT5514_TDMSLOT_SEL_RX_4CH (0x1 << 10) +#define RT5514_TDMSLOT_SEL_RX_6CH (0x2 << 10) +#define RT5514_TDMSLOT_SEL_RX_8CH (0x3 << 10) #define RT5514_CH_LEN_RX_MASK (0x3 << 8) #define RT5514_CH_LEN_RX_SFT 8 #define RT5514_CH_LEN_RX_16 (0x0 << 8) @@ -145,6 +149,8 @@ #define RT5514_TDMSLOT_SEL_TX_MASK (0x3 << 6) #define RT5514_TDMSLOT_SEL_TX_SFT 6 #define RT5514_TDMSLOT_SEL_TX_4CH (0x1 << 6) +#define RT5514_TDMSLOT_SEL_TX_6CH (0x2 << 6) +#define RT5514_TDMSLOT_SEL_TX_8CH (0x3 << 6) #define RT5514_CH_LEN_TX_MASK (0x3 << 4) #define RT5514_CH_LEN_TX_SFT 4 #define RT5514_CH_LEN_TX_16 (0x0 << 4) From 30b7d88de034a2b5c4f20c0cd05c792d9b619d70 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 2 May 2017 11:00:39 +0800 Subject: [PATCH 013/418] ASoC: rt5665: add ADC STO2 ASRC support "ADC Stereo2 Filter" is with ASRC supported. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 14b0cf89edf5..26bf157ca293 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -2684,6 +2684,8 @@ static const struct snd_soc_dapm_widget rt5665_dapm_widgets[] = { RT5665_DAC_MONO_R_ASRC_SFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5665_ASRC_1, RT5665_ADC_STO1_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5665_ASRC_1, + RT5665_ADC_STO2_ASRC_SFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("ADC Mono L ASRC", 1, RT5665_ASRC_1, RT5665_ADC_MONO_L_ASRC_SFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("ADC Mono R ASRC", 1, RT5665_ASRC_1, @@ -3227,6 +3229,7 @@ static const struct snd_soc_dapm_route rt5665_dapm_routes[] = { /*ASRC*/ {"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc}, + {"ADC Stereo2 Filter", NULL, "ADC STO2 ASRC", is_using_asrc}, {"ADC Mono Left Filter", NULL, "ADC Mono L ASRC", is_using_asrc}, {"ADC Mono Right Filter", NULL, "ADC Mono R ASRC", is_using_asrc}, {"DAC Mono Left Filter", NULL, "DAC Mono L ASRC", is_using_asrc}, From 5c7e7d586a4318faa3f580ef6f950b8d3bc93d95 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 12 May 2017 14:34:38 +0200 Subject: [PATCH 014/418] ALSA: us122l: clean up US144 handling Use the device-id table and a private flag to determine the device type (US122 or US144) rather than spreading product-id conditionals throughout the driver. This USB driver currently depends on X86 (why?), but we should still add the missing endianness conversions when accessing the USB device-descriptor fields. Compile-tested only. Signed-off-by: Johan Hovold Signed-off-by: Takashi Iwai --- sound/usb/usx2y/us122l.c | 36 ++++++++++++++++++------------------ sound/usb/usx2y/us122l.h | 2 ++ 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index e118bdca983d..a33e31b2fc2f 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -46,8 +46,10 @@ MODULE_PARM_DESC(id, "ID string for "NAME_ALLCAPS"."); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable "NAME_ALLCAPS"."); -static int snd_us122l_card_used[SNDRV_CARDS]; +/* driver_info flags */ +#define US122L_FLAG_US144 BIT(0) +static int snd_us122l_card_used[SNDRV_CARDS]; static int us122l_create_usbmidi(struct snd_card *card) { @@ -198,8 +200,7 @@ static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file) if (!us122l->first) us122l->first = file; - if (us122l->dev->descriptor.idProduct == USB_ID_US144 || - us122l->dev->descriptor.idProduct == USB_ID_US144MKII) { + if (us122l->is_us144) { iface = usb_ifnum_to_if(us122l->dev, 0); usb_autopm_get_interface(iface); } @@ -214,8 +215,7 @@ static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file) struct usb_interface *iface; snd_printdd(KERN_DEBUG "%p %p\n", hw, file); - if (us122l->dev->descriptor.idProduct == USB_ID_US144 || - us122l->dev->descriptor.idProduct == USB_ID_US144MKII) { + if (us122l->is_us144) { iface = usb_ifnum_to_if(us122l->dev, 0); usb_autopm_put_interface(iface); } @@ -483,8 +483,7 @@ static bool us122l_create_card(struct snd_card *card) int err; struct us122l *us122l = US122L(card); - if (us122l->dev->descriptor.idProduct == USB_ID_US144 || - us122l->dev->descriptor.idProduct == USB_ID_US144MKII) { + if (us122l->is_us144) { err = usb_set_interface(us122l->dev, 0, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); @@ -503,8 +502,7 @@ static bool us122l_create_card(struct snd_card *card) if (!us122l_start(us122l, 44100, 256)) return false; - if (us122l->dev->descriptor.idProduct == USB_ID_US144 || - us122l->dev->descriptor.idProduct == USB_ID_US144MKII) + if (us122l->is_us144) err = us144_create_usbmidi(card); else err = us122l_create_usbmidi(card); @@ -536,7 +534,8 @@ static void snd_us122l_free(struct snd_card *card) static int usx2y_create_card(struct usb_device *device, struct usb_interface *intf, - struct snd_card **cardp) + struct snd_card **cardp, + unsigned long flags) { int dev; struct snd_card *card; @@ -556,6 +555,7 @@ static int usx2y_create_card(struct usb_device *device, US122L(card)->dev = device; mutex_init(&US122L(card)->mutex); init_waitqueue_head(&US122L(card)->sk.sleep); + US122L(card)->is_us144 = flags & US122L_FLAG_US144; INIT_LIST_HEAD(&US122L(card)->midi_list); strcpy(card->driver, "USB "NAME_ALLCAPS""); sprintf(card->shortname, "TASCAM "NAME_ALLCAPS""); @@ -579,7 +579,7 @@ static int us122l_usb_probe(struct usb_interface *intf, struct snd_card *card; int err; - err = usx2y_create_card(device, intf, &card); + err = usx2y_create_card(device, intf, &card, device_id->driver_info); if (err < 0) return err; @@ -607,9 +607,8 @@ static int snd_us122l_probe(struct usb_interface *intf, struct snd_card *card; int err; - if ((device->descriptor.idProduct == USB_ID_US144 || - device->descriptor.idProduct == USB_ID_US144MKII) - && device->speed == USB_SPEED_HIGH) { + if (id->driver_info & US122L_FLAG_US144 && + device->speed == USB_SPEED_HIGH) { snd_printk(KERN_ERR "disable ehci-hcd to run US-144 \n"); return -ENODEV; } @@ -703,8 +702,7 @@ static int snd_us122l_resume(struct usb_interface *intf) mutex_lock(&us122l->mutex); /* needed, doesn't restart without: */ - if (us122l->dev->descriptor.idProduct == USB_ID_US144 || - us122l->dev->descriptor.idProduct == USB_ID_US144MKII) { + if (us122l->is_us144) { err = usb_set_interface(us122l->dev, 0, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); @@ -747,7 +745,8 @@ static struct usb_device_id snd_us122l_usb_id_table[] = { { /* US-144 only works at USB1.1! Disable module ehci-hcd. */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x0644, - .idProduct = USB_ID_US144 + .idProduct = USB_ID_US144, + .driver_info = US122L_FLAG_US144 }, { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, @@ -757,7 +756,8 @@ static struct usb_device_id snd_us122l_usb_id_table[] = { { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x0644, - .idProduct = USB_ID_US144MKII + .idProduct = USB_ID_US144MKII, + .driver_info = US122L_FLAG_US144 }, { /* terminator */ } }; diff --git a/sound/usb/usx2y/us122l.h b/sound/usb/usx2y/us122l.h index f263b3f96c86..3e2a2d0041ee 100644 --- a/sound/usb/usx2y/us122l.h +++ b/sound/usb/usx2y/us122l.h @@ -16,6 +16,8 @@ struct us122l { struct list_head midi_list; atomic_t mmap_count; + + bool is_us144; }; From 6c1df232731f83621fd6d590aa1a2325ceefaed9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 12 May 2017 14:34:39 +0200 Subject: [PATCH 015/418] ALSA: us122l: enable compile testing This USB driver currently depends on X86 for some undocumented reason. Since it compiles just fine for arm, we can at least enable compile testing. Signed-off-by: Johan Hovold Signed-off-by: Takashi Iwai --- sound/usb/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index a452ad7cec40..f61b5662bb89 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -91,7 +91,7 @@ config SND_USB_CAIAQ_INPUT config SND_USB_US122L tristate "Tascam US-122L USB driver" - depends on X86 + depends on X86 || COMPILE_TEST select SND_HWDEP select SND_RAWMIDI help From 5f976f58917eafbd8f725b9b7c0efcf6937e0e83 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 12 May 2017 10:02:08 +0200 Subject: [PATCH 016/418] ALSA: vx222: Use container_of() The vx222 driver is using the explicit cast from the parent class pointer, but it'll be broken when the structure field randomization is applied. Use container_of() in a modern manner, instead. Signed-off-by: Takashi Iwai --- sound/pci/vx222/vx222.c | 4 ++-- sound/pci/vx222/vx222.h | 2 ++ sound/pci/vx222/vx222_ops.c | 26 +++++++++++++------------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index ecbaf473fc1e..55861849d7df 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c @@ -116,7 +116,7 @@ static struct snd_vx_hardware vx222_mic_hw = { */ static int snd_vx222_free(struct vx_core *chip) { - struct snd_vx222 *vx = (struct snd_vx222 *)chip; + struct snd_vx222 *vx = to_vx222(chip); if (chip->irq >= 0) free_irq(chip->irq, (void*)chip); @@ -158,7 +158,7 @@ static int snd_vx222_create(struct snd_card *card, struct pci_dev *pci, pci_disable_device(pci); return -ENOMEM; } - vx = (struct snd_vx222 *)chip; + vx = to_vx222(chip); vx->pci = pci; if ((err = pci_request_regions(pci, CARD_NAME)) < 0) { diff --git a/sound/pci/vx222/vx222.h b/sound/pci/vx222/vx222.h index 2f0d78f609a6..cae355c8ed28 100644 --- a/sound/pci/vx222/vx222.h +++ b/sound/pci/vx222/vx222.h @@ -39,6 +39,8 @@ struct snd_vx222 { int mic_level; /* mic level for vx222 mic */ }; +#define to_vx222(x) container_of(x, struct snd_vx222, core) + /* we use a lookup table with 148 values, see vx_mixer.c */ #define VX2_AKM_LEVEL_MAX 0x93 diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index 7df1663ea510..d4298af6d3ee 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c @@ -86,7 +86,7 @@ static int vx2_reg_index[VX_REG_MAX] = { static inline unsigned long vx2_reg_addr(struct vx_core *_chip, int reg) { - struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + struct snd_vx222 *chip = to_vx222(_chip); return chip->port[vx2_reg_index[reg]] + vx2_reg_offset[reg]; } @@ -159,7 +159,7 @@ static void vx2_outl(struct vx_core *chip, int offset, unsigned int val) static void vx2_reset_dsp(struct vx_core *_chip) { - struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + struct snd_vx222 *chip = to_vx222(_chip); /* set the reset dsp bit to 0 */ vx_outl(chip, CDSP, chip->regCDSP & ~VX_CDSP_DSP_RESET_MASK); @@ -174,7 +174,7 @@ static void vx2_reset_dsp(struct vx_core *_chip) static int vx2_test_xilinx(struct vx_core *_chip) { - struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + struct snd_vx222 *chip = to_vx222(_chip); unsigned int data; dev_dbg(_chip->card->dev, "testing xilinx...\n"); @@ -479,7 +479,7 @@ static int vx2_test_and_ack(struct vx_core *chip) */ static void vx2_validate_irq(struct vx_core *_chip, int enable) { - struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + struct snd_vx222 *chip = to_vx222(_chip); /* Set the interrupt enable bit to 1 in CDSP register */ if (enable) { @@ -730,7 +730,7 @@ static void vx2_old_write_codec_bit(struct vx_core *chip, int codec, unsigned in */ static void vx2_reset_codec(struct vx_core *_chip) { - struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + struct snd_vx222 *chip = to_vx222(_chip); /* Set the reset CODEC bit to 0. */ vx_outl(chip, CDSP, chip->regCDSP &~ VX_CDSP_CODEC_RESET_MASK); @@ -772,7 +772,7 @@ static void vx2_reset_codec(struct vx_core *_chip) */ static void vx2_change_audio_source(struct vx_core *_chip, int src) { - struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + struct snd_vx222 *chip = to_vx222(_chip); switch (src) { case VX_AUDIO_SRC_DIGITAL: @@ -791,7 +791,7 @@ static void vx2_change_audio_source(struct vx_core *_chip, int src) */ static void vx2_set_clock_source(struct vx_core *_chip, int source) { - struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + struct snd_vx222 *chip = to_vx222(_chip); if (source == INTERNAL_QUARTZ) chip->regCFG &= ~VX_CFG_CLOCKIN_SEL_MASK; @@ -805,7 +805,7 @@ static void vx2_set_clock_source(struct vx_core *_chip, int source) */ static void vx2_reset_board(struct vx_core *_chip, int cold_reset) { - struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + struct snd_vx222 *chip = to_vx222(_chip); /* initialize the register values */ chip->regCDSP = VX_CDSP_CODEC_RESET_MASK | VX_CDSP_DSP_RESET_MASK ; @@ -878,7 +878,7 @@ static int vx_input_level_info(struct snd_kcontrol *kcontrol, struct snd_ctl_ele static int vx_input_level_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct vx_core *_chip = snd_kcontrol_chip(kcontrol); - struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + struct snd_vx222 *chip = to_vx222(_chip); mutex_lock(&_chip->mixer_mutex); ucontrol->value.integer.value[0] = chip->input_level[0]; ucontrol->value.integer.value[1] = chip->input_level[1]; @@ -889,7 +889,7 @@ static int vx_input_level_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem static int vx_input_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct vx_core *_chip = snd_kcontrol_chip(kcontrol); - struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + struct snd_vx222 *chip = to_vx222(_chip); if (ucontrol->value.integer.value[0] < 0 || ucontrol->value.integer.value[0] > MIC_LEVEL_MAX) return -EINVAL; @@ -922,7 +922,7 @@ static int vx_mic_level_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ static int vx_mic_level_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct vx_core *_chip = snd_kcontrol_chip(kcontrol); - struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + struct snd_vx222 *chip = to_vx222(_chip); ucontrol->value.integer.value[0] = chip->mic_level; return 0; } @@ -930,7 +930,7 @@ static int vx_mic_level_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct vx_core *_chip = snd_kcontrol_chip(kcontrol); - struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + struct snd_vx222 *chip = to_vx222(_chip); if (ucontrol->value.integer.value[0] < 0 || ucontrol->value.integer.value[0] > MIC_LEVEL_MAX) return -EINVAL; @@ -973,7 +973,7 @@ static const struct snd_kcontrol_new vx_control_mic_level = { static int vx2_add_mic_controls(struct vx_core *_chip) { - struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + struct snd_vx222 *chip = to_vx222(_chip); int err; if (_chip->type != VX_TYPE_MIC) From 020c5260c2b16469b99c65c37982b4be4c435b56 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 9 May 2017 19:18:36 +0300 Subject: [PATCH 017/418] ALSA: atmel: Remove AVR32 bits from the driver AVR32 is gone. Now it's time to clean up the driver by removing leftovers that was used by AVR32 related code. Acked-by: Nicolas Ferre Signed-off-by: Andy Shevchenko Signed-off-by: Takashi Iwai --- sound/atmel/Kconfig | 13 +- sound/atmel/Makefile | 2 - sound/atmel/abdac.c | 610 ------------------------------------------- sound/atmel/ac97c.c | 435 +++++------------------------- 4 files changed, 68 insertions(+), 992 deletions(-) delete mode 100644 sound/atmel/abdac.c diff --git a/sound/atmel/Kconfig b/sound/atmel/Kconfig index 94de43a096f1..d789cbcb9106 100644 --- a/sound/atmel/Kconfig +++ b/sound/atmel/Kconfig @@ -1,18 +1,11 @@ -menu "Atmel devices (AVR32 and AT91)" - depends on AVR32 || ARCH_AT91 - -config SND_ATMEL_ABDAC - tristate "Atmel Audio Bitstream DAC (ABDAC) driver" - select SND_PCM - depends on DW_DMAC && AVR32 - help - ALSA sound driver for the Atmel Audio Bitstream DAC (ABDAC). +menu "Atmel devices (AT91)" + depends on ARCH_AT91 config SND_ATMEL_AC97C tristate "Atmel AC97 Controller (AC97C) driver" select SND_PCM select SND_AC97_CODEC - depends on (DW_DMAC && AVR32) || ARCH_AT91 + depends on ARCH_AT91 help ALSA sound driver for the Atmel AC97 controller. diff --git a/sound/atmel/Makefile b/sound/atmel/Makefile index 219dcfac6086..d4009d1430ed 100644 --- a/sound/atmel/Makefile +++ b/sound/atmel/Makefile @@ -1,5 +1,3 @@ -snd-atmel-abdac-objs := abdac.o snd-atmel-ac97c-objs := ac97c.o -obj-$(CONFIG_SND_ATMEL_ABDAC) += snd-atmel-abdac.o obj-$(CONFIG_SND_ATMEL_AC97C) += snd-atmel-ac97c.o diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c deleted file mode 100644 index 558618802000..000000000000 --- a/sound/atmel/abdac.c +++ /dev/null @@ -1,610 +0,0 @@ -/* - * Driver for the Atmel on-chip Audio Bitstream DAC (ABDAC) - * - * Copyright (C) 2006-2009 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -/* DAC register offsets */ -#define DAC_DATA 0x0000 -#define DAC_CTRL 0x0008 -#define DAC_INT_MASK 0x000c -#define DAC_INT_EN 0x0010 -#define DAC_INT_DIS 0x0014 -#define DAC_INT_CLR 0x0018 -#define DAC_INT_STATUS 0x001c - -/* Bitfields in CTRL */ -#define DAC_SWAP_OFFSET 30 -#define DAC_SWAP_SIZE 1 -#define DAC_EN_OFFSET 31 -#define DAC_EN_SIZE 1 - -/* Bitfields in INT_MASK/INT_EN/INT_DIS/INT_STATUS/INT_CLR */ -#define DAC_UNDERRUN_OFFSET 28 -#define DAC_UNDERRUN_SIZE 1 -#define DAC_TX_READY_OFFSET 29 -#define DAC_TX_READY_SIZE 1 - -/* Bit manipulation macros */ -#define DAC_BIT(name) \ - (1 << DAC_##name##_OFFSET) -#define DAC_BF(name, value) \ - (((value) & ((1 << DAC_##name##_SIZE) - 1)) \ - << DAC_##name##_OFFSET) -#define DAC_BFEXT(name, value) \ - (((value) >> DAC_##name##_OFFSET) \ - & ((1 << DAC_##name##_SIZE) - 1)) -#define DAC_BFINS(name, value, old) \ - (((old) & ~(((1 << DAC_##name##_SIZE) - 1) \ - << DAC_##name##_OFFSET)) \ - | DAC_BF(name, value)) - -/* Register access macros */ -#define dac_readl(port, reg) \ - __raw_readl((port)->regs + DAC_##reg) -#define dac_writel(port, reg, value) \ - __raw_writel((value), (port)->regs + DAC_##reg) - -/* - * ABDAC supports a maximum of 6 different rates from a generic clock. The - * generic clock has a power of two divider, which gives 6 steps from 192 kHz - * to 5112 Hz. - */ -#define MAX_NUM_RATES 6 -/* ALSA seems to use rates between 192000 Hz and 5112 Hz. */ -#define RATE_MAX 192000 -#define RATE_MIN 5112 - -enum { - DMA_READY = 0, -}; - -struct atmel_abdac_dma { - struct dma_chan *chan; - struct dw_cyclic_desc *cdesc; -}; - -struct atmel_abdac { - struct clk *pclk; - struct clk *sample_clk; - struct platform_device *pdev; - struct atmel_abdac_dma dma; - - struct snd_pcm_hw_constraint_list constraints_rates; - struct snd_pcm_substream *substream; - struct snd_card *card; - struct snd_pcm *pcm; - - void __iomem *regs; - unsigned long flags; - unsigned int rates[MAX_NUM_RATES]; - unsigned int rates_num; - int irq; -}; - -#define get_dac(card) ((struct atmel_abdac *)(card)->private_data) - -/* This function is called by the DMA driver. */ -static void atmel_abdac_dma_period_done(void *arg) -{ - struct atmel_abdac *dac = arg; - snd_pcm_period_elapsed(dac->substream); -} - -static int atmel_abdac_prepare_dma(struct atmel_abdac *dac, - struct snd_pcm_substream *substream, - enum dma_data_direction direction) -{ - struct dma_chan *chan = dac->dma.chan; - struct dw_cyclic_desc *cdesc; - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned long buffer_len, period_len; - - /* - * We don't do DMA on "complex" transfers, i.e. with - * non-halfword-aligned buffers or lengths. - */ - if (runtime->dma_addr & 1 || runtime->buffer_size & 1) { - dev_dbg(&dac->pdev->dev, "too complex transfer\n"); - return -EINVAL; - } - - buffer_len = frames_to_bytes(runtime, runtime->buffer_size); - period_len = frames_to_bytes(runtime, runtime->period_size); - - cdesc = dw_dma_cyclic_prep(chan, runtime->dma_addr, buffer_len, - period_len, DMA_MEM_TO_DEV); - if (IS_ERR(cdesc)) { - dev_dbg(&dac->pdev->dev, "could not prepare cyclic DMA\n"); - return PTR_ERR(cdesc); - } - - cdesc->period_callback = atmel_abdac_dma_period_done; - cdesc->period_callback_param = dac; - - dac->dma.cdesc = cdesc; - - set_bit(DMA_READY, &dac->flags); - - return 0; -} - -static struct snd_pcm_hardware atmel_abdac_hw = { - .info = (SNDRV_PCM_INFO_MMAP - | SNDRV_PCM_INFO_MMAP_VALID - | SNDRV_PCM_INFO_INTERLEAVED - | SNDRV_PCM_INFO_BLOCK_TRANSFER - | SNDRV_PCM_INFO_RESUME - | SNDRV_PCM_INFO_PAUSE), - .formats = (SNDRV_PCM_FMTBIT_S16_BE), - .rates = (SNDRV_PCM_RATE_KNOT), - .rate_min = RATE_MIN, - .rate_max = RATE_MAX, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 64 * 4096, - .period_bytes_min = 4096, - .period_bytes_max = 4096, - .periods_min = 6, - .periods_max = 64, -}; - -static int atmel_abdac_open(struct snd_pcm_substream *substream) -{ - struct atmel_abdac *dac = snd_pcm_substream_chip(substream); - - dac->substream = substream; - atmel_abdac_hw.rate_max = dac->rates[dac->rates_num - 1]; - atmel_abdac_hw.rate_min = dac->rates[0]; - substream->runtime->hw = atmel_abdac_hw; - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &dac->constraints_rates); -} - -static int atmel_abdac_close(struct snd_pcm_substream *substream) -{ - struct atmel_abdac *dac = snd_pcm_substream_chip(substream); - dac->substream = NULL; - return 0; -} - -static int atmel_abdac_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct atmel_abdac *dac = snd_pcm_substream_chip(substream); - int retval; - - retval = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params)); - if (retval < 0) - return retval; - /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ - if (retval == 1) - if (test_and_clear_bit(DMA_READY, &dac->flags)) - dw_dma_cyclic_free(dac->dma.chan); - - return retval; -} - -static int atmel_abdac_hw_free(struct snd_pcm_substream *substream) -{ - struct atmel_abdac *dac = snd_pcm_substream_chip(substream); - if (test_and_clear_bit(DMA_READY, &dac->flags)) - dw_dma_cyclic_free(dac->dma.chan); - return snd_pcm_lib_free_pages(substream); -} - -static int atmel_abdac_prepare(struct snd_pcm_substream *substream) -{ - struct atmel_abdac *dac = snd_pcm_substream_chip(substream); - int retval; - - retval = clk_set_rate(dac->sample_clk, 256 * substream->runtime->rate); - if (retval) - return retval; - - if (!test_bit(DMA_READY, &dac->flags)) - retval = atmel_abdac_prepare_dma(dac, substream, DMA_TO_DEVICE); - - return retval; -} - -static int atmel_abdac_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct atmel_abdac *dac = snd_pcm_substream_chip(substream); - int retval = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ - case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ - case SNDRV_PCM_TRIGGER_START: - clk_prepare_enable(dac->sample_clk); - retval = dw_dma_cyclic_start(dac->dma.chan); - if (retval) - goto out; - dac_writel(dac, CTRL, DAC_BIT(EN)); - break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ - case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ - case SNDRV_PCM_TRIGGER_STOP: - dw_dma_cyclic_stop(dac->dma.chan); - dac_writel(dac, DATA, 0); - dac_writel(dac, CTRL, 0); - clk_disable_unprepare(dac->sample_clk); - break; - default: - retval = -EINVAL; - break; - } -out: - return retval; -} - -static snd_pcm_uframes_t -atmel_abdac_pointer(struct snd_pcm_substream *substream) -{ - struct atmel_abdac *dac = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_uframes_t frames; - unsigned long bytes; - - bytes = dw_dma_get_src_addr(dac->dma.chan); - bytes -= runtime->dma_addr; - - frames = bytes_to_frames(runtime, bytes); - if (frames >= runtime->buffer_size) - frames -= runtime->buffer_size; - - return frames; -} - -static irqreturn_t abdac_interrupt(int irq, void *dev_id) -{ - struct atmel_abdac *dac = dev_id; - u32 status; - - status = dac_readl(dac, INT_STATUS); - if (status & DAC_BIT(UNDERRUN)) { - dev_err(&dac->pdev->dev, "underrun detected\n"); - dac_writel(dac, INT_CLR, DAC_BIT(UNDERRUN)); - } else { - dev_err(&dac->pdev->dev, "spurious interrupt (status=0x%x)\n", - status); - dac_writel(dac, INT_CLR, status); - } - - return IRQ_HANDLED; -} - -static struct snd_pcm_ops atmel_abdac_ops = { - .open = atmel_abdac_open, - .close = atmel_abdac_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = atmel_abdac_hw_params, - .hw_free = atmel_abdac_hw_free, - .prepare = atmel_abdac_prepare, - .trigger = atmel_abdac_trigger, - .pointer = atmel_abdac_pointer, -}; - -static int atmel_abdac_pcm_new(struct atmel_abdac *dac) -{ - struct snd_pcm_hardware hw = atmel_abdac_hw; - struct snd_pcm *pcm; - int retval; - - retval = snd_pcm_new(dac->card, dac->card->shortname, - dac->pdev->id, 1, 0, &pcm); - if (retval) - return retval; - - strcpy(pcm->name, dac->card->shortname); - pcm->private_data = dac; - pcm->info_flags = 0; - dac->pcm = pcm; - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &atmel_abdac_ops); - - retval = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - &dac->pdev->dev, hw.periods_min * hw.period_bytes_min, - hw.buffer_bytes_max); - - return retval; -} - -static bool filter(struct dma_chan *chan, void *slave) -{ - struct dw_dma_slave *dws = slave; - - if (dws->dma_dev == chan->device->dev) { - chan->private = dws; - return true; - } else - return false; -} - -static int set_sample_rates(struct atmel_abdac *dac) -{ - long new_rate = RATE_MAX; - int retval = -EINVAL; - int index = 0; - - /* we start at 192 kHz and work our way down to 5112 Hz */ - while (new_rate >= RATE_MIN && index < (MAX_NUM_RATES + 1)) { - new_rate = clk_round_rate(dac->sample_clk, 256 * new_rate); - if (new_rate <= 0) - break; - /* make sure we are below the ABDAC clock */ - if (index < MAX_NUM_RATES && - new_rate <= clk_get_rate(dac->pclk)) { - dac->rates[index] = new_rate / 256; - index++; - } - /* divide by 256 and then by two to get next rate */ - new_rate /= 256 * 2; - } - - if (index) { - int i; - - /* reverse array, smallest go first */ - for (i = 0; i < (index / 2); i++) { - unsigned int tmp = dac->rates[index - 1 - i]; - dac->rates[index - 1 - i] = dac->rates[i]; - dac->rates[i] = tmp; - } - - dac->constraints_rates.count = index; - dac->constraints_rates.list = dac->rates; - dac->constraints_rates.mask = 0; - dac->rates_num = index; - - retval = 0; - } - - return retval; -} - -static int atmel_abdac_probe(struct platform_device *pdev) -{ - struct snd_card *card; - struct atmel_abdac *dac; - struct resource *regs; - struct atmel_abdac_pdata *pdata; - struct clk *pclk; - struct clk *sample_clk; - int retval; - int irq; - - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!regs) { - dev_dbg(&pdev->dev, "no memory resource\n"); - return -ENXIO; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_dbg(&pdev->dev, "could not get IRQ number\n"); - return irq; - } - - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_dbg(&pdev->dev, "no platform data\n"); - return -ENXIO; - } - - pclk = clk_get(&pdev->dev, "pclk"); - if (IS_ERR(pclk)) { - dev_dbg(&pdev->dev, "no peripheral clock\n"); - return PTR_ERR(pclk); - } - sample_clk = clk_get(&pdev->dev, "sample_clk"); - if (IS_ERR(sample_clk)) { - dev_dbg(&pdev->dev, "no sample clock\n"); - retval = PTR_ERR(sample_clk); - goto out_put_pclk; - } - clk_prepare_enable(pclk); - - retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, - SNDRV_DEFAULT_STR1, THIS_MODULE, - sizeof(struct atmel_abdac), &card); - if (retval) { - dev_dbg(&pdev->dev, "could not create sound card device\n"); - goto out_put_sample_clk; - } - - dac = get_dac(card); - - dac->irq = irq; - dac->card = card; - dac->pclk = pclk; - dac->sample_clk = sample_clk; - dac->pdev = pdev; - - retval = set_sample_rates(dac); - if (retval < 0) { - dev_dbg(&pdev->dev, "could not set supported rates\n"); - goto out_free_card; - } - - dac->regs = ioremap(regs->start, resource_size(regs)); - if (!dac->regs) { - dev_dbg(&pdev->dev, "could not remap register memory\n"); - retval = -ENOMEM; - goto out_free_card; - } - - /* make sure the DAC is silent and disabled */ - dac_writel(dac, DATA, 0); - dac_writel(dac, CTRL, 0); - - retval = request_irq(irq, abdac_interrupt, 0, "abdac", dac); - if (retval) { - dev_dbg(&pdev->dev, "could not request irq\n"); - goto out_unmap_regs; - } - - if (pdata->dws.dma_dev) { - dma_cap_mask_t mask; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - dac->dma.chan = dma_request_channel(mask, filter, &pdata->dws); - if (dac->dma.chan) { - struct dma_slave_config dma_conf = { - .dst_addr = regs->start + DAC_DATA, - .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, - .src_maxburst = 1, - .dst_maxburst = 1, - .direction = DMA_MEM_TO_DEV, - .device_fc = false, - }; - - dmaengine_slave_config(dac->dma.chan, &dma_conf); - } - } - if (!pdata->dws.dma_dev || !dac->dma.chan) { - dev_dbg(&pdev->dev, "DMA not available\n"); - retval = -ENODEV; - goto out_unmap_regs; - } - - strcpy(card->driver, "Atmel ABDAC"); - strcpy(card->shortname, "Atmel ABDAC"); - sprintf(card->longname, "Atmel Audio Bitstream DAC"); - - retval = atmel_abdac_pcm_new(dac); - if (retval) { - dev_dbg(&pdev->dev, "could not register ABDAC pcm device\n"); - goto out_release_dma; - } - - retval = snd_card_register(card); - if (retval) { - dev_dbg(&pdev->dev, "could not register sound card\n"); - goto out_release_dma; - } - - platform_set_drvdata(pdev, card); - - dev_info(&pdev->dev, "Atmel ABDAC at 0x%p using %s\n", - dac->regs, dev_name(&dac->dma.chan->dev->device)); - - return retval; - -out_release_dma: - dma_release_channel(dac->dma.chan); - dac->dma.chan = NULL; -out_unmap_regs: - iounmap(dac->regs); -out_free_card: - snd_card_free(card); -out_put_sample_clk: - clk_put(sample_clk); - clk_disable_unprepare(pclk); -out_put_pclk: - clk_put(pclk); - return retval; -} - -#ifdef CONFIG_PM_SLEEP -static int atmel_abdac_suspend(struct device *pdev) -{ - struct snd_card *card = dev_get_drvdata(pdev); - struct atmel_abdac *dac = card->private_data; - - dw_dma_cyclic_stop(dac->dma.chan); - clk_disable_unprepare(dac->sample_clk); - clk_disable_unprepare(dac->pclk); - - return 0; -} - -static int atmel_abdac_resume(struct device *pdev) -{ - struct snd_card *card = dev_get_drvdata(pdev); - struct atmel_abdac *dac = card->private_data; - - clk_prepare_enable(dac->pclk); - clk_prepare_enable(dac->sample_clk); - if (test_bit(DMA_READY, &dac->flags)) - dw_dma_cyclic_start(dac->dma.chan); - - return 0; -} - -static SIMPLE_DEV_PM_OPS(atmel_abdac_pm, atmel_abdac_suspend, atmel_abdac_resume); -#define ATMEL_ABDAC_PM_OPS &atmel_abdac_pm -#else -#define ATMEL_ABDAC_PM_OPS NULL -#endif - -static int atmel_abdac_remove(struct platform_device *pdev) -{ - struct snd_card *card = platform_get_drvdata(pdev); - struct atmel_abdac *dac = get_dac(card); - - clk_put(dac->sample_clk); - clk_disable_unprepare(dac->pclk); - clk_put(dac->pclk); - - dma_release_channel(dac->dma.chan); - dac->dma.chan = NULL; - iounmap(dac->regs); - free_irq(dac->irq, dac); - snd_card_free(card); - - return 0; -} - -static struct platform_driver atmel_abdac_driver = { - .remove = atmel_abdac_remove, - .driver = { - .name = "atmel_abdac", - .pm = ATMEL_ABDAC_PM_OPS, - }, -}; - -static int __init atmel_abdac_init(void) -{ - return platform_driver_probe(&atmel_abdac_driver, - atmel_abdac_probe); -} -module_init(atmel_abdac_init); - -static void __exit atmel_abdac_exit(void) -{ - platform_driver_unregister(&atmel_abdac_driver); -} -module_exit(atmel_abdac_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Driver for Atmel Audio Bitstream DAC (ABDAC)"); -MODULE_AUTHOR("Hans-Christian Egtvedt "); diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 6dad042630d8..65e6948e3995 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -11,8 +11,6 @@ #include #include #include -#include -#include #include #include #include @@ -34,36 +32,14 @@ #include #include -#include -#include - -#ifdef CONFIG_AVR32 -#include -#else -#define cpu_is_at32ap7000() 0 -#endif - #include "ac97c.h" -enum { - DMA_TX_READY = 0, - DMA_RX_READY, - DMA_TX_CHAN_PRESENT, - DMA_RX_CHAN_PRESENT, -}; - /* Serialize access to opened variable */ static DEFINE_MUTEX(opened_mutex); -struct atmel_ac97c_dma { - struct dma_chan *rx_chan; - struct dma_chan *tx_chan; -}; - struct atmel_ac97c { struct clk *pclk; struct platform_device *pdev; - struct atmel_ac97c_dma dma; struct snd_pcm_substream *playback_substream; struct snd_pcm_substream *capture_substream; @@ -74,7 +50,6 @@ struct atmel_ac97c { u64 cur_format; unsigned int cur_rate; - unsigned long flags; int playback_period, capture_period; /* Serialize access to opened variable */ spinlock_t lock; @@ -91,65 +66,6 @@ struct atmel_ac97c { #define ac97c_readl(chip, reg) \ __raw_readl((chip)->regs + AC97C_##reg) -/* This function is called by the DMA driver. */ -static void atmel_ac97c_dma_playback_period_done(void *arg) -{ - struct atmel_ac97c *chip = arg; - snd_pcm_period_elapsed(chip->playback_substream); -} - -static void atmel_ac97c_dma_capture_period_done(void *arg) -{ - struct atmel_ac97c *chip = arg; - snd_pcm_period_elapsed(chip->capture_substream); -} - -static int atmel_ac97c_prepare_dma(struct atmel_ac97c *chip, - struct snd_pcm_substream *substream, - enum dma_transfer_direction direction) -{ - struct dma_chan *chan; - struct dw_cyclic_desc *cdesc; - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned long buffer_len, period_len; - - /* - * We don't do DMA on "complex" transfers, i.e. with - * non-halfword-aligned buffers or lengths. - */ - if (runtime->dma_addr & 1 || runtime->buffer_size & 1) { - dev_dbg(&chip->pdev->dev, "too complex transfer\n"); - return -EINVAL; - } - - if (direction == DMA_MEM_TO_DEV) - chan = chip->dma.tx_chan; - else - chan = chip->dma.rx_chan; - - buffer_len = frames_to_bytes(runtime, runtime->buffer_size); - period_len = frames_to_bytes(runtime, runtime->period_size); - - cdesc = dw_dma_cyclic_prep(chan, runtime->dma_addr, buffer_len, - period_len, direction); - if (IS_ERR(cdesc)) { - dev_dbg(&chip->pdev->dev, "could not prepare cyclic DMA\n"); - return PTR_ERR(cdesc); - } - - if (direction == DMA_MEM_TO_DEV) { - cdesc->period_callback = atmel_ac97c_dma_playback_period_done; - set_bit(DMA_TX_READY, &chip->flags); - } else { - cdesc->period_callback = atmel_ac97c_dma_capture_period_done; - set_bit(DMA_RX_READY, &chip->flags); - } - - cdesc->period_callback_param = chip; - - return 0; -} - static struct snd_pcm_hardware atmel_ac97c_hw = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID @@ -254,13 +170,7 @@ static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream, params_buffer_bytes(hw_params)); if (retval < 0) return retval; - /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ - if (cpu_is_at32ap7000()) { - /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ - if (retval == 1) - if (test_and_clear_bit(DMA_TX_READY, &chip->flags)) - dw_dma_cyclic_free(chip->dma.tx_chan); - } + /* Set restrictions to params. */ mutex_lock(&opened_mutex); chip->cur_rate = params_rate(hw_params); @@ -280,10 +190,6 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream, params_buffer_bytes(hw_params)); if (retval < 0) return retval; - /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ - if (cpu_is_at32ap7000() && retval == 1) - if (test_and_clear_bit(DMA_RX_READY, &chip->flags)) - dw_dma_cyclic_free(chip->dma.rx_chan); /* Set restrictions to params. */ mutex_lock(&opened_mutex); @@ -294,26 +200,6 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream, return retval; } -static int atmel_ac97c_playback_hw_free(struct snd_pcm_substream *substream) -{ - struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); - if (cpu_is_at32ap7000()) { - if (test_and_clear_bit(DMA_TX_READY, &chip->flags)) - dw_dma_cyclic_free(chip->dma.tx_chan); - } - return snd_pcm_lib_free_pages(substream); -} - -static int atmel_ac97c_capture_hw_free(struct snd_pcm_substream *substream) -{ - struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); - if (cpu_is_at32ap7000()) { - if (test_and_clear_bit(DMA_RX_READY, &chip->flags)) - dw_dma_cyclic_free(chip->dma.rx_chan); - } - return snd_pcm_lib_free_pages(substream); -} - static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); @@ -349,8 +235,6 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) switch (runtime->format) { case SNDRV_PCM_FORMAT_S16_LE: - if (cpu_is_at32ap7000()) - word |= AC97C_CMR_CEM_LITTLE; break; case SNDRV_PCM_FORMAT_S16_BE: /* fall through */ word &= ~(AC97C_CMR_CEM_LITTLE); @@ -389,18 +273,11 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n", runtime->rate); - if (cpu_is_at32ap7000()) { - if (!test_bit(DMA_TX_READY, &chip->flags)) - retval = atmel_ac97c_prepare_dma(chip, substream, - DMA_MEM_TO_DEV); - } else { - /* Initialize and start the PDC */ - writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR); - writel(block_size / 2, chip->regs + ATMEL_PDC_TCR); - writel(runtime->dma_addr + block_size, - chip->regs + ATMEL_PDC_TNPR); - writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR); - } + /* Initialize and start the PDC */ + writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR); + writel(block_size / 2, chip->regs + ATMEL_PDC_TCR); + writel(runtime->dma_addr + block_size, chip->regs + ATMEL_PDC_TNPR); + writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR); return retval; } @@ -440,8 +317,6 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) switch (runtime->format) { case SNDRV_PCM_FORMAT_S16_LE: - if (cpu_is_at32ap7000()) - word |= AC97C_CMR_CEM_LITTLE; break; case SNDRV_PCM_FORMAT_S16_BE: /* fall through */ word &= ~(AC97C_CMR_CEM_LITTLE); @@ -480,18 +355,11 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n", runtime->rate); - if (cpu_is_at32ap7000()) { - if (!test_bit(DMA_RX_READY, &chip->flags)) - retval = atmel_ac97c_prepare_dma(chip, substream, - DMA_DEV_TO_MEM); - } else { - /* Initialize and start the PDC */ - writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR); - writel(block_size / 2, chip->regs + ATMEL_PDC_RCR); - writel(runtime->dma_addr + block_size, - chip->regs + ATMEL_PDC_RNPR); - writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR); - } + /* Initialize and start the PDC */ + writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR); + writel(block_size / 2, chip->regs + ATMEL_PDC_RCR); + writel(runtime->dma_addr + block_size, chip->regs + ATMEL_PDC_RNPR); + writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR); return retval; } @@ -501,7 +369,6 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); unsigned long camr, ptcr = 0; - int retval = 0; camr = ac97c_readl(chip, CAMR); @@ -509,35 +376,23 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START: - if (cpu_is_at32ap7000()) { - retval = dw_dma_cyclic_start(chip->dma.tx_chan); - if (retval) - goto out; - } else { - ptcr = ATMEL_PDC_TXTEN; - } + ptcr = ATMEL_PDC_TXTEN; camr |= AC97C_CMR_CENA | AC97C_CSR_ENDTX; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ case SNDRV_PCM_TRIGGER_STOP: - if (cpu_is_at32ap7000()) - dw_dma_cyclic_stop(chip->dma.tx_chan); - else - ptcr |= ATMEL_PDC_TXTDIS; + ptcr |= ATMEL_PDC_TXTDIS; if (chip->opened <= 1) camr &= ~AC97C_CMR_CENA; break; default: - retval = -EINVAL; - goto out; + return -EINVAL; } ac97c_writel(chip, CAMR, camr); - if (!cpu_is_at32ap7000()) - writel(ptcr, chip->regs + ATMEL_PDC_PTCR); -out: - return retval; + writel(ptcr, chip->regs + ATMEL_PDC_PTCR); + return 0; } static int @@ -545,7 +400,6 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); unsigned long camr, ptcr = 0; - int retval = 0; camr = ac97c_readl(chip, CAMR); ptcr = readl(chip->regs + ATMEL_PDC_PTSR); @@ -554,35 +408,23 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START: - if (cpu_is_at32ap7000()) { - retval = dw_dma_cyclic_start(chip->dma.rx_chan); - if (retval) - goto out; - } else { - ptcr = ATMEL_PDC_RXTEN; - } + ptcr = ATMEL_PDC_RXTEN; camr |= AC97C_CMR_CENA | AC97C_CSR_ENDRX; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ case SNDRV_PCM_TRIGGER_STOP: - if (cpu_is_at32ap7000()) - dw_dma_cyclic_stop(chip->dma.rx_chan); - else - ptcr |= (ATMEL_PDC_RXTDIS); + ptcr |= ATMEL_PDC_RXTDIS; if (chip->opened <= 1) camr &= ~AC97C_CMR_CENA; break; default: - retval = -EINVAL; - break; + return -EINVAL; } ac97c_writel(chip, CAMR, camr); - if (!cpu_is_at32ap7000()) - writel(ptcr, chip->regs + ATMEL_PDC_PTCR); -out: - return retval; + writel(ptcr, chip->regs + ATMEL_PDC_PTCR); + return 0; } static snd_pcm_uframes_t @@ -593,10 +435,7 @@ atmel_ac97c_playback_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t frames; unsigned long bytes; - if (cpu_is_at32ap7000()) - bytes = dw_dma_get_src_addr(chip->dma.tx_chan); - else - bytes = readl(chip->regs + ATMEL_PDC_TPR); + bytes = readl(chip->regs + ATMEL_PDC_TPR); bytes -= runtime->dma_addr; frames = bytes_to_frames(runtime, bytes); @@ -613,10 +452,7 @@ atmel_ac97c_capture_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t frames; unsigned long bytes; - if (cpu_is_at32ap7000()) - bytes = dw_dma_get_dst_addr(chip->dma.rx_chan); - else - bytes = readl(chip->regs + ATMEL_PDC_RPR); + bytes = readl(chip->regs + ATMEL_PDC_RPR); bytes -= runtime->dma_addr; frames = bytes_to_frames(runtime, bytes); @@ -630,7 +466,7 @@ static struct snd_pcm_ops atmel_ac97_playback_ops = { .close = atmel_ac97c_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = atmel_ac97c_playback_hw_params, - .hw_free = atmel_ac97c_playback_hw_free, + .hw_free = snd_pcm_lib_free_pages, .prepare = atmel_ac97c_playback_prepare, .trigger = atmel_ac97c_playback_trigger, .pointer = atmel_ac97c_playback_pointer, @@ -641,7 +477,7 @@ static struct snd_pcm_ops atmel_ac97_capture_ops = { .close = atmel_ac97c_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = atmel_ac97c_capture_hw_params, - .hw_free = atmel_ac97c_capture_hw_free, + .hw_free = snd_pcm_lib_free_pages, .prepare = atmel_ac97c_capture_prepare, .trigger = atmel_ac97c_capture_trigger, .pointer = atmel_ac97c_capture_pointer, @@ -666,49 +502,40 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "", casr & AC97C_CSR_TXRDY ? " TXRDY" : "", !casr ? " NONE" : ""); - if (!cpu_is_at32ap7000()) { - if ((casr & camr) & AC97C_CSR_ENDTX) { - runtime = chip->playback_substream->runtime; - block_size = frames_to_bytes(runtime, - runtime->period_size); - chip->playback_period++; + if ((casr & camr) & AC97C_CSR_ENDTX) { + runtime = chip->playback_substream->runtime; + block_size = frames_to_bytes(runtime, runtime->period_size); + chip->playback_period++; - if (chip->playback_period == runtime->periods) - chip->playback_period = 0; - next_period = chip->playback_period + 1; - if (next_period == runtime->periods) - next_period = 0; + if (chip->playback_period == runtime->periods) + chip->playback_period = 0; + next_period = chip->playback_period + 1; + if (next_period == runtime->periods) + next_period = 0; - offset = block_size * next_period; + offset = block_size * next_period; - writel(runtime->dma_addr + offset, - chip->regs + ATMEL_PDC_TNPR); - writel(block_size / 2, - chip->regs + ATMEL_PDC_TNCR); + writel(runtime->dma_addr + offset, chip->regs + ATMEL_PDC_TNPR); + writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR); - snd_pcm_period_elapsed( - chip->playback_substream); - } - if ((casr & camr) & AC97C_CSR_ENDRX) { - runtime = chip->capture_substream->runtime; - block_size = frames_to_bytes(runtime, - runtime->period_size); - chip->capture_period++; + snd_pcm_period_elapsed(chip->playback_substream); + } + if ((casr & camr) & AC97C_CSR_ENDRX) { + runtime = chip->capture_substream->runtime; + block_size = frames_to_bytes(runtime, runtime->period_size); + chip->capture_period++; - if (chip->capture_period == runtime->periods) - chip->capture_period = 0; - next_period = chip->capture_period + 1; - if (next_period == runtime->periods) - next_period = 0; + if (chip->capture_period == runtime->periods) + chip->capture_period = 0; + next_period = chip->capture_period + 1; + if (next_period == runtime->periods) + next_period = 0; - offset = block_size * next_period; + offset = block_size * next_period; - writel(runtime->dma_addr + offset, - chip->regs + ATMEL_PDC_RNPR); - writel(block_size / 2, - chip->regs + ATMEL_PDC_RNCR); - snd_pcm_period_elapsed(chip->capture_substream); - } + writel(runtime->dma_addr + offset, chip->regs + ATMEL_PDC_RNPR); + writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR); + snd_pcm_period_elapsed(chip->capture_substream); } retval = IRQ_HANDLED; } @@ -763,29 +590,20 @@ static int atmel_ac97c_pcm_new(struct atmel_ac97c *chip) { struct snd_pcm *pcm; struct snd_pcm_hardware hw = atmel_ac97c_hw; - int capture, playback, retval, err; + int retval; - capture = test_bit(DMA_RX_CHAN_PRESENT, &chip->flags); - playback = test_bit(DMA_TX_CHAN_PRESENT, &chip->flags); - - if (!cpu_is_at32ap7000()) { - err = snd_ac97_pcm_assign(chip->ac97_bus, - ARRAY_SIZE(at91_ac97_pcm_defs), - at91_ac97_pcm_defs); - if (err) - return err; - } - retval = snd_pcm_new(chip->card, chip->card->shortname, - 0, playback, capture, &pcm); + retval = snd_ac97_pcm_assign(chip->ac97_bus, + ARRAY_SIZE(at91_ac97_pcm_defs), + at91_ac97_pcm_defs); if (retval) return retval; - if (capture) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, - &atmel_ac97_capture_ops); - if (playback) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, - &atmel_ac97_playback_ops); + retval = snd_pcm_new(chip->card, chip->card->shortname, 0, 1, 1, &pcm); + if (retval) + return retval; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &atmel_ac97_capture_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &atmel_ac97_playback_ops); retval = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, &chip->pdev->dev, hw.periods_min * hw.period_bytes_min, @@ -875,17 +693,6 @@ timed_out: return 0xffff; } -static bool filter(struct dma_chan *chan, void *slave) -{ - struct dw_dma_slave *dws = slave; - - if (dws->dma_dev == chan->device->dev) { - chan->private = dws; - return true; - } else - return false; -} - static void atmel_ac97c_reset(struct atmel_ac97c *chip) { ac97c_writel(chip, MR, 0); @@ -971,12 +778,7 @@ static int atmel_ac97c_probe(struct platform_device *pdev) return -ENXIO; } - if (cpu_is_at32ap7000()) { - pclk = clk_get(&pdev->dev, "pclk"); - } else { - pclk = clk_get(&pdev->dev, "ac97_clk"); - } - + pclk = clk_get(&pdev->dev, "ac97_clk"); if (IS_ERR(pclk)) { dev_dbg(&pdev->dev, "no peripheral clock\n"); return PTR_ERR(pclk); @@ -1047,88 +849,16 @@ static int atmel_ac97c_probe(struct platform_device *pdev) goto err_ac97_bus; } - if (cpu_is_at32ap7000()) { - if (pdata->rx_dws.dma_dev) { - dma_cap_mask_t mask; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - chip->dma.rx_chan = dma_request_channel(mask, filter, - &pdata->rx_dws); - if (chip->dma.rx_chan) { - struct dma_slave_config dma_conf = { - .src_addr = regs->start + AC97C_CARHR + - 2, - .src_addr_width = - DMA_SLAVE_BUSWIDTH_2_BYTES, - .src_maxburst = 1, - .dst_maxburst = 1, - .direction = DMA_DEV_TO_MEM, - .device_fc = false, - }; - - dmaengine_slave_config(chip->dma.rx_chan, - &dma_conf); - } - - dev_info(&chip->pdev->dev, "using %s for DMA RX\n", - dev_name(&chip->dma.rx_chan->dev->device)); - set_bit(DMA_RX_CHAN_PRESENT, &chip->flags); - } - - if (pdata->tx_dws.dma_dev) { - dma_cap_mask_t mask; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - chip->dma.tx_chan = dma_request_channel(mask, filter, - &pdata->tx_dws); - if (chip->dma.tx_chan) { - struct dma_slave_config dma_conf = { - .dst_addr = regs->start + AC97C_CATHR + - 2, - .dst_addr_width = - DMA_SLAVE_BUSWIDTH_2_BYTES, - .src_maxburst = 1, - .dst_maxburst = 1, - .direction = DMA_MEM_TO_DEV, - .device_fc = false, - }; - - dmaengine_slave_config(chip->dma.tx_chan, - &dma_conf); - } - - dev_info(&chip->pdev->dev, "using %s for DMA TX\n", - dev_name(&chip->dma.tx_chan->dev->device)); - set_bit(DMA_TX_CHAN_PRESENT, &chip->flags); - } - - if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) && - !test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) { - dev_dbg(&pdev->dev, "DMA not available\n"); - retval = -ENODEV; - goto err_dma; - } - } else { - /* Just pretend that we have DMA channel(for at91 i is actually - * the PDC) */ - set_bit(DMA_RX_CHAN_PRESENT, &chip->flags); - set_bit(DMA_TX_CHAN_PRESENT, &chip->flags); - } - retval = atmel_ac97c_pcm_new(chip); if (retval) { dev_dbg(&pdev->dev, "could not register ac97 pcm device\n"); - goto err_dma; + goto err_ac97_bus; } retval = snd_card_register(card); if (retval) { dev_dbg(&pdev->dev, "could not register sound card\n"); - goto err_dma; + goto err_ac97_bus; } platform_set_drvdata(pdev, card); @@ -1138,17 +868,6 @@ static int atmel_ac97c_probe(struct platform_device *pdev) return 0; -err_dma: - if (cpu_is_at32ap7000()) { - if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) - dma_release_channel(chip->dma.rx_chan); - if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) - dma_release_channel(chip->dma.tx_chan); - clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags); - clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags); - chip->dma.rx_chan = NULL; - chip->dma.tx_chan = NULL; - } err_ac97_bus: if (gpio_is_valid(chip->reset_pin)) gpio_free(chip->reset_pin); @@ -1170,14 +889,7 @@ static int atmel_ac97c_suspend(struct device *pdev) struct snd_card *card = dev_get_drvdata(pdev); struct atmel_ac97c *chip = card->private_data; - if (cpu_is_at32ap7000()) { - if (test_bit(DMA_RX_READY, &chip->flags)) - dw_dma_cyclic_stop(chip->dma.rx_chan); - if (test_bit(DMA_TX_READY, &chip->flags)) - dw_dma_cyclic_stop(chip->dma.tx_chan); - } clk_disable_unprepare(chip->pclk); - return 0; } @@ -1187,12 +899,6 @@ static int atmel_ac97c_resume(struct device *pdev) struct atmel_ac97c *chip = card->private_data; clk_prepare_enable(chip->pclk); - if (cpu_is_at32ap7000()) { - if (test_bit(DMA_RX_READY, &chip->flags)) - dw_dma_cyclic_start(chip->dma.rx_chan); - if (test_bit(DMA_TX_READY, &chip->flags)) - dw_dma_cyclic_start(chip->dma.tx_chan); - } return 0; } @@ -1219,17 +925,6 @@ static int atmel_ac97c_remove(struct platform_device *pdev) iounmap(chip->regs); free_irq(chip->irq, chip); - if (cpu_is_at32ap7000()) { - if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) - dma_release_channel(chip->dma.rx_chan); - if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) - dma_release_channel(chip->dma.tx_chan); - clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags); - clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags); - chip->dma.rx_chan = NULL; - chip->dma.tx_chan = NULL; - } - snd_card_free(card); return 0; From 14bebd01c5f5306c804bcb78d008df3a149dd0b3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 9 May 2017 19:18:37 +0300 Subject: [PATCH 018/418] dmaengine: dw: Remove AVR32 bits from the driver AVR32 is gone. Now it's time to clean up the driver by removing leftovers that was used by AVR32 related code. Signed-off-by: Andy Shevchenko Acked-by: Vinod Koul Signed-off-by: Takashi Iwai --- drivers/dma/dw/Kconfig | 7 +- drivers/dma/dw/core.c | 332 +---------------------------------------- drivers/dma/dw/regs.h | 50 ++----- include/linux/dma/dw.h | 21 --- 4 files changed, 14 insertions(+), 396 deletions(-) diff --git a/drivers/dma/dw/Kconfig b/drivers/dma/dw/Kconfig index 5a37b9fcf40d..04b9728c1d26 100644 --- a/drivers/dma/dw/Kconfig +++ b/drivers/dma/dw/Kconfig @@ -6,17 +6,12 @@ config DW_DMAC_CORE tristate select DMA_ENGINE -config DW_DMAC_BIG_ENDIAN_IO - bool - config DW_DMAC tristate "Synopsys DesignWare AHB DMA platform driver" select DW_DMAC_CORE - select DW_DMAC_BIG_ENDIAN_IO if AVR32 - default y if CPU_AT32AP7000 help Support the Synopsys DesignWare AHB DMA controller. This - can be integrated in chips such as the Atmel AT32ap7000. + can be integrated in chips such as the Intel Cherrytrail. config DW_DMAC_PCI tristate "Synopsys DesignWare AHB DMA PCI driver" diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index e500950dad82..f43e6dafe446 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -561,92 +561,14 @@ static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc) dwc_descriptor_complete(dwc, bad_desc, true); } -/* --------------------- Cyclic DMA API extensions -------------------- */ - -dma_addr_t dw_dma_get_src_addr(struct dma_chan *chan) -{ - struct dw_dma_chan *dwc = to_dw_dma_chan(chan); - return channel_readl(dwc, SAR); -} -EXPORT_SYMBOL(dw_dma_get_src_addr); - -dma_addr_t dw_dma_get_dst_addr(struct dma_chan *chan) -{ - struct dw_dma_chan *dwc = to_dw_dma_chan(chan); - return channel_readl(dwc, DAR); -} -EXPORT_SYMBOL(dw_dma_get_dst_addr); - -/* Called with dwc->lock held and all DMAC interrupts disabled */ -static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc, - u32 status_block, u32 status_err, u32 status_xfer) -{ - unsigned long flags; - - if (status_block & dwc->mask) { - void (*callback)(void *param); - void *callback_param; - - dev_vdbg(chan2dev(&dwc->chan), "new cyclic period llp 0x%08x\n", - channel_readl(dwc, LLP)); - dma_writel(dw, CLEAR.BLOCK, dwc->mask); - - callback = dwc->cdesc->period_callback; - callback_param = dwc->cdesc->period_callback_param; - - if (callback) - callback(callback_param); - } - - /* - * Error and transfer complete are highly unlikely, and will most - * likely be due to a configuration error by the user. - */ - if (unlikely(status_err & dwc->mask) || - unlikely(status_xfer & dwc->mask)) { - unsigned int i; - - dev_err(chan2dev(&dwc->chan), - "cyclic DMA unexpected %s interrupt, stopping DMA transfer\n", - status_xfer ? "xfer" : "error"); - - spin_lock_irqsave(&dwc->lock, flags); - - dwc_dump_chan_regs(dwc); - - dwc_chan_disable(dw, dwc); - - /* Make sure DMA does not restart by loading a new list */ - channel_writel(dwc, LLP, 0); - channel_writel(dwc, CTL_LO, 0); - channel_writel(dwc, CTL_HI, 0); - - dma_writel(dw, CLEAR.BLOCK, dwc->mask); - dma_writel(dw, CLEAR.ERROR, dwc->mask); - dma_writel(dw, CLEAR.XFER, dwc->mask); - - for (i = 0; i < dwc->cdesc->periods; i++) - dwc_dump_lli(dwc, dwc->cdesc->desc[i]); - - spin_unlock_irqrestore(&dwc->lock, flags); - } - - /* Re-enable interrupts */ - channel_set_bit(dw, MASK.BLOCK, dwc->mask); -} - -/* ------------------------------------------------------------------------- */ - static void dw_dma_tasklet(unsigned long data) { struct dw_dma *dw = (struct dw_dma *)data; struct dw_dma_chan *dwc; - u32 status_block; u32 status_xfer; u32 status_err; unsigned int i; - status_block = dma_readl(dw, RAW.BLOCK); status_xfer = dma_readl(dw, RAW.XFER); status_err = dma_readl(dw, RAW.ERROR); @@ -655,8 +577,7 @@ static void dw_dma_tasklet(unsigned long data) for (i = 0; i < dw->dma.chancnt; i++) { dwc = &dw->chan[i]; if (test_bit(DW_DMA_IS_CYCLIC, &dwc->flags)) - dwc_handle_cyclic(dw, dwc, status_block, status_err, - status_xfer); + dev_vdbg(dw->dma.dev, "Cyclic xfer is not implemented\n"); else if (status_err & (1 << i)) dwc_handle_error(dw, dwc); else if (status_xfer & (1 << i)) @@ -1264,255 +1185,6 @@ static void dwc_free_chan_resources(struct dma_chan *chan) dev_vdbg(chan2dev(chan), "%s: done\n", __func__); } -/* --------------------- Cyclic DMA API extensions -------------------- */ - -/** - * dw_dma_cyclic_start - start the cyclic DMA transfer - * @chan: the DMA channel to start - * - * Must be called with soft interrupts disabled. Returns zero on success or - * -errno on failure. - */ -int dw_dma_cyclic_start(struct dma_chan *chan) -{ - struct dw_dma_chan *dwc = to_dw_dma_chan(chan); - struct dw_dma *dw = to_dw_dma(chan->device); - unsigned long flags; - - if (!test_bit(DW_DMA_IS_CYCLIC, &dwc->flags)) { - dev_err(chan2dev(&dwc->chan), "missing prep for cyclic DMA\n"); - return -ENODEV; - } - - spin_lock_irqsave(&dwc->lock, flags); - - /* Enable interrupts to perform cyclic transfer */ - channel_set_bit(dw, MASK.BLOCK, dwc->mask); - - dwc_dostart(dwc, dwc->cdesc->desc[0]); - - spin_unlock_irqrestore(&dwc->lock, flags); - - return 0; -} -EXPORT_SYMBOL(dw_dma_cyclic_start); - -/** - * dw_dma_cyclic_stop - stop the cyclic DMA transfer - * @chan: the DMA channel to stop - * - * Must be called with soft interrupts disabled. - */ -void dw_dma_cyclic_stop(struct dma_chan *chan) -{ - struct dw_dma_chan *dwc = to_dw_dma_chan(chan); - struct dw_dma *dw = to_dw_dma(dwc->chan.device); - unsigned long flags; - - spin_lock_irqsave(&dwc->lock, flags); - - dwc_chan_disable(dw, dwc); - - spin_unlock_irqrestore(&dwc->lock, flags); -} -EXPORT_SYMBOL(dw_dma_cyclic_stop); - -/** - * dw_dma_cyclic_prep - prepare the cyclic DMA transfer - * @chan: the DMA channel to prepare - * @buf_addr: physical DMA address where the buffer starts - * @buf_len: total number of bytes for the entire buffer - * @period_len: number of bytes for each period - * @direction: transfer direction, to or from device - * - * Must be called before trying to start the transfer. Returns a valid struct - * dw_cyclic_desc if successful or an ERR_PTR(-errno) if not successful. - */ -struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, - dma_addr_t buf_addr, size_t buf_len, size_t period_len, - enum dma_transfer_direction direction) -{ - struct dw_dma_chan *dwc = to_dw_dma_chan(chan); - struct dma_slave_config *sconfig = &dwc->dma_sconfig; - struct dw_cyclic_desc *cdesc; - struct dw_cyclic_desc *retval = NULL; - struct dw_desc *desc; - struct dw_desc *last = NULL; - u8 lms = DWC_LLP_LMS(dwc->dws.m_master); - unsigned long was_cyclic; - unsigned int reg_width; - unsigned int periods; - unsigned int i; - unsigned long flags; - - spin_lock_irqsave(&dwc->lock, flags); - if (dwc->nollp) { - spin_unlock_irqrestore(&dwc->lock, flags); - dev_dbg(chan2dev(&dwc->chan), - "channel doesn't support LLP transfers\n"); - return ERR_PTR(-EINVAL); - } - - if (!list_empty(&dwc->queue) || !list_empty(&dwc->active_list)) { - spin_unlock_irqrestore(&dwc->lock, flags); - dev_dbg(chan2dev(&dwc->chan), - "queue and/or active list are not empty\n"); - return ERR_PTR(-EBUSY); - } - - was_cyclic = test_and_set_bit(DW_DMA_IS_CYCLIC, &dwc->flags); - spin_unlock_irqrestore(&dwc->lock, flags); - if (was_cyclic) { - dev_dbg(chan2dev(&dwc->chan), - "channel already prepared for cyclic DMA\n"); - return ERR_PTR(-EBUSY); - } - - retval = ERR_PTR(-EINVAL); - - if (unlikely(!is_slave_direction(direction))) - goto out_err; - - dwc->direction = direction; - - if (direction == DMA_MEM_TO_DEV) - reg_width = __ffs(sconfig->dst_addr_width); - else - reg_width = __ffs(sconfig->src_addr_width); - - periods = buf_len / period_len; - - /* Check for too big/unaligned periods and unaligned DMA buffer. */ - if (period_len > (dwc->block_size << reg_width)) - goto out_err; - if (unlikely(period_len & ((1 << reg_width) - 1))) - goto out_err; - if (unlikely(buf_addr & ((1 << reg_width) - 1))) - goto out_err; - - retval = ERR_PTR(-ENOMEM); - - cdesc = kzalloc(sizeof(struct dw_cyclic_desc), GFP_KERNEL); - if (!cdesc) - goto out_err; - - cdesc->desc = kzalloc(sizeof(struct dw_desc *) * periods, GFP_KERNEL); - if (!cdesc->desc) - goto out_err_alloc; - - for (i = 0; i < periods; i++) { - desc = dwc_desc_get(dwc); - if (!desc) - goto out_err_desc_get; - - switch (direction) { - case DMA_MEM_TO_DEV: - lli_write(desc, dar, sconfig->dst_addr); - lli_write(desc, sar, buf_addr + period_len * i); - lli_write(desc, ctllo, (DWC_DEFAULT_CTLLO(chan) - | DWC_CTLL_DST_WIDTH(reg_width) - | DWC_CTLL_SRC_WIDTH(reg_width) - | DWC_CTLL_DST_FIX - | DWC_CTLL_SRC_INC - | DWC_CTLL_INT_EN)); - - lli_set(desc, ctllo, sconfig->device_fc ? - DWC_CTLL_FC(DW_DMA_FC_P_M2P) : - DWC_CTLL_FC(DW_DMA_FC_D_M2P)); - - break; - case DMA_DEV_TO_MEM: - lli_write(desc, dar, buf_addr + period_len * i); - lli_write(desc, sar, sconfig->src_addr); - lli_write(desc, ctllo, (DWC_DEFAULT_CTLLO(chan) - | DWC_CTLL_SRC_WIDTH(reg_width) - | DWC_CTLL_DST_WIDTH(reg_width) - | DWC_CTLL_DST_INC - | DWC_CTLL_SRC_FIX - | DWC_CTLL_INT_EN)); - - lli_set(desc, ctllo, sconfig->device_fc ? - DWC_CTLL_FC(DW_DMA_FC_P_P2M) : - DWC_CTLL_FC(DW_DMA_FC_D_P2M)); - - break; - default: - break; - } - - lli_write(desc, ctlhi, period_len >> reg_width); - cdesc->desc[i] = desc; - - if (last) - lli_write(last, llp, desc->txd.phys | lms); - - last = desc; - } - - /* Let's make a cyclic list */ - lli_write(last, llp, cdesc->desc[0]->txd.phys | lms); - - dev_dbg(chan2dev(&dwc->chan), - "cyclic prepared buf %pad len %zu period %zu periods %d\n", - &buf_addr, buf_len, period_len, periods); - - cdesc->periods = periods; - dwc->cdesc = cdesc; - - return cdesc; - -out_err_desc_get: - while (i--) - dwc_desc_put(dwc, cdesc->desc[i]); -out_err_alloc: - kfree(cdesc); -out_err: - clear_bit(DW_DMA_IS_CYCLIC, &dwc->flags); - return (struct dw_cyclic_desc *)retval; -} -EXPORT_SYMBOL(dw_dma_cyclic_prep); - -/** - * dw_dma_cyclic_free - free a prepared cyclic DMA transfer - * @chan: the DMA channel to free - */ -void dw_dma_cyclic_free(struct dma_chan *chan) -{ - struct dw_dma_chan *dwc = to_dw_dma_chan(chan); - struct dw_dma *dw = to_dw_dma(dwc->chan.device); - struct dw_cyclic_desc *cdesc = dwc->cdesc; - unsigned int i; - unsigned long flags; - - dev_dbg(chan2dev(&dwc->chan), "%s\n", __func__); - - if (!cdesc) - return; - - spin_lock_irqsave(&dwc->lock, flags); - - dwc_chan_disable(dw, dwc); - - dma_writel(dw, CLEAR.BLOCK, dwc->mask); - dma_writel(dw, CLEAR.ERROR, dwc->mask); - dma_writel(dw, CLEAR.XFER, dwc->mask); - - spin_unlock_irqrestore(&dwc->lock, flags); - - for (i = 0; i < cdesc->periods; i++) - dwc_desc_put(dwc, cdesc->desc[i]); - - kfree(cdesc->desc); - kfree(cdesc); - - dwc->cdesc = NULL; - - clear_bit(DW_DMA_IS_CYCLIC, &dwc->flags); -} -EXPORT_SYMBOL(dw_dma_cyclic_free); - -/*----------------------------------------------------------------------*/ - int dw_dma_probe(struct dw_dma_chip *chip) { struct dw_dma_platform_data *pdata; @@ -1642,7 +1314,7 @@ int dw_dma_probe(struct dw_dma_chip *chip) if (autocfg) { unsigned int r = DW_DMA_MAX_NR_CHANNELS - i - 1; void __iomem *addr = &__dw_regs(dw)->DWC_PARAMS[r]; - unsigned int dwc_params = dma_readl_native(addr); + unsigned int dwc_params = readl(addr); dev_dbg(chip->dev, "DWC_PARAMS[%d]: 0x%08x\n", i, dwc_params); diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h index 32a328721c88..09e7dfdbb790 100644 --- a/drivers/dma/dw/regs.h +++ b/drivers/dma/dw/regs.h @@ -116,20 +116,6 @@ struct dw_dma_regs { DW_REG(GLOBAL_CFG); }; -/* - * Big endian I/O access when reading and writing to the DMA controller - * registers. This is needed on some platforms, like the Atmel AVR32 - * architecture. - */ - -#ifdef CONFIG_DW_DMAC_BIG_ENDIAN_IO -#define dma_readl_native ioread32be -#define dma_writel_native iowrite32be -#else -#define dma_readl_native readl -#define dma_writel_native writel -#endif - /* Bitfields in DW_PARAMS */ #define DW_PARAMS_NR_CHAN 8 /* number of channels */ #define DW_PARAMS_NR_MASTER 11 /* number of AHB masters */ @@ -280,7 +266,6 @@ struct dw_dma_chan { unsigned long flags; struct list_head active_list; struct list_head queue; - struct dw_cyclic_desc *cdesc; unsigned int descs_allocated; @@ -302,9 +287,9 @@ __dwc_regs(struct dw_dma_chan *dwc) } #define channel_readl(dwc, name) \ - dma_readl_native(&(__dwc_regs(dwc)->name)) + readl(&(__dwc_regs(dwc)->name)) #define channel_writel(dwc, name, val) \ - dma_writel_native((val), &(__dwc_regs(dwc)->name)) + writel((val), &(__dwc_regs(dwc)->name)) static inline struct dw_dma_chan *to_dw_dma_chan(struct dma_chan *chan) { @@ -333,9 +318,9 @@ static inline struct dw_dma_regs __iomem *__dw_regs(struct dw_dma *dw) } #define dma_readl(dw, name) \ - dma_readl_native(&(__dw_regs(dw)->name)) + readl(&(__dw_regs(dw)->name)) #define dma_writel(dw, name, val) \ - dma_writel_native((val), &(__dw_regs(dw)->name)) + writel((val), &(__dw_regs(dw)->name)) #define idma32_readq(dw, name) \ hi_lo_readq(&(__dw_regs(dw)->name)) @@ -352,43 +337,30 @@ static inline struct dw_dma *to_dw_dma(struct dma_device *ddev) return container_of(ddev, struct dw_dma, dma); } -#ifdef CONFIG_DW_DMAC_BIG_ENDIAN_IO -typedef __be32 __dw32; -#else -typedef __le32 __dw32; -#endif - /* LLI == Linked List Item; a.k.a. DMA block descriptor */ struct dw_lli { /* values that are not changed by hardware */ - __dw32 sar; - __dw32 dar; - __dw32 llp; /* chain to next lli */ - __dw32 ctllo; + __le32 sar; + __le32 dar; + __le32 llp; /* chain to next lli */ + __le32 ctllo; /* values that may get written back: */ - __dw32 ctlhi; + __le32 ctlhi; /* sstat and dstat can snapshot peripheral register state. * silicon config may discard either or both... */ - __dw32 sstat; - __dw32 dstat; + __le32 sstat; + __le32 dstat; }; struct dw_desc { /* FIRST values the hardware uses */ struct dw_lli lli; -#ifdef CONFIG_DW_DMAC_BIG_ENDIAN_IO -#define lli_set(d, reg, v) ((d)->lli.reg |= cpu_to_be32(v)) -#define lli_clear(d, reg, v) ((d)->lli.reg &= ~cpu_to_be32(v)) -#define lli_read(d, reg) be32_to_cpu((d)->lli.reg) -#define lli_write(d, reg, v) ((d)->lli.reg = cpu_to_be32(v)) -#else #define lli_set(d, reg, v) ((d)->lli.reg |= cpu_to_le32(v)) #define lli_clear(d, reg, v) ((d)->lli.reg &= ~cpu_to_le32(v)) #define lli_read(d, reg) le32_to_cpu((d)->lli.reg) #define lli_write(d, reg, v) ((d)->lli.reg = cpu_to_le32(v)) -#endif /* THEN values for driver housekeeping */ struct list_head desc_node; diff --git a/include/linux/dma/dw.h b/include/linux/dma/dw.h index b63b25814d77..e166cac8e870 100644 --- a/include/linux/dma/dw.h +++ b/include/linux/dma/dw.h @@ -50,25 +50,4 @@ static inline int dw_dma_probe(struct dw_dma_chip *chip) { return -ENODEV; } static inline int dw_dma_remove(struct dw_dma_chip *chip) { return 0; } #endif /* CONFIG_DW_DMAC_CORE */ -/* DMA API extensions */ -struct dw_desc; - -struct dw_cyclic_desc { - struct dw_desc **desc; - unsigned long periods; - void (*period_callback)(void *param); - void *period_callback_param; -}; - -struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, - dma_addr_t buf_addr, size_t buf_len, size_t period_len, - enum dma_transfer_direction direction); -void dw_dma_cyclic_free(struct dma_chan *chan); -int dw_dma_cyclic_start(struct dma_chan *chan); -void dw_dma_cyclic_stop(struct dma_chan *chan); - -dma_addr_t dw_dma_get_src_addr(struct dma_chan *chan); - -dma_addr_t dw_dma_get_dst_addr(struct dma_chan *chan); - #endif /* _DMA_DW_H */ From 2e0de6ea956ff429cf11bd1a92d7444bc6000698 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 12 May 2017 10:03:35 +0200 Subject: [PATCH 019/418] ALSA: vxpocket: Use container_of() The vxpocket driver is using the explicit cast from the parent class pointer, but it'll be broken when the structure field randomization is applied. Use container_of() in a modern manner, instead. Signed-off-by: Takashi Iwai --- sound/pcmcia/vx/vxp_mixer.c | 10 +++++----- sound/pcmcia/vx/vxp_ops.c | 28 ++++++++++++++-------------- sound/pcmcia/vx/vxpocket.c | 4 ++-- sound/pcmcia/vx/vxpocket.h | 2 ++ 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/sound/pcmcia/vx/vxp_mixer.c b/sound/pcmcia/vx/vxp_mixer.c index a4a664259f0d..1ca3eef9e305 100644 --- a/sound/pcmcia/vx/vxp_mixer.c +++ b/sound/pcmcia/vx/vxp_mixer.c @@ -43,7 +43,7 @@ static int vx_mic_level_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ static int vx_mic_level_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct vx_core *_chip = snd_kcontrol_chip(kcontrol); - struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + struct snd_vxpocket *chip = to_vxpocket(_chip); ucontrol->value.integer.value[0] = chip->mic_level; return 0; } @@ -51,7 +51,7 @@ static int vx_mic_level_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct vx_core *_chip = snd_kcontrol_chip(kcontrol); - struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + struct snd_vxpocket *chip = to_vxpocket(_chip); unsigned int val = ucontrol->value.integer.value[0]; if (val > MIC_LEVEL_MAX) @@ -88,7 +88,7 @@ static struct snd_kcontrol_new vx_control_mic_level = { static int vx_mic_boost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct vx_core *_chip = snd_kcontrol_chip(kcontrol); - struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + struct snd_vxpocket *chip = to_vxpocket(_chip); ucontrol->value.integer.value[0] = chip->mic_level; return 0; } @@ -96,7 +96,7 @@ static int vx_mic_boost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v static int vx_mic_boost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct vx_core *_chip = snd_kcontrol_chip(kcontrol); - struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + struct snd_vxpocket *chip = to_vxpocket(_chip); int val = !!ucontrol->value.integer.value[0]; mutex_lock(&_chip->mixer_mutex); if (chip->mic_level != val) { @@ -120,7 +120,7 @@ static struct snd_kcontrol_new vx_control_mic_boost = { int vxp_add_mic_controls(struct vx_core *_chip) { - struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + struct snd_vxpocket *chip = to_vxpocket(_chip); int err; /* mute input levels */ diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c index 5f97791f00d7..8cde40226355 100644 --- a/sound/pcmcia/vx/vxp_ops.c +++ b/sound/pcmcia/vx/vxp_ops.c @@ -50,7 +50,7 @@ static int vxp_reg_offset[VX_REG_MAX] = { static inline unsigned long vxp_reg_addr(struct vx_core *_chip, int reg) { - struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + struct snd_vxpocket *chip = to_vxpocket(_chip); return chip->port + vxp_reg_offset[reg]; } @@ -110,7 +110,7 @@ static int vx_check_magic(struct vx_core *chip) static void vxp_reset_dsp(struct vx_core *_chip) { - struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + struct snd_vxpocket *chip = to_vxpocket(_chip); /* set the reset dsp bit to 1 */ vx_outb(chip, CDSP, chip->regCDSP | VXP_CDSP_DSP_RESET_MASK); @@ -128,7 +128,7 @@ static void vxp_reset_dsp(struct vx_core *_chip) */ static void vxp_reset_codec(struct vx_core *_chip) { - struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + struct snd_vxpocket *chip = to_vxpocket(_chip); /* Set the reset CODEC bit to 1. */ vx_outb(chip, CDSP, chip->regCDSP | VXP_CDSP_CODEC_RESET_MASK); @@ -147,7 +147,7 @@ static void vxp_reset_codec(struct vx_core *_chip) */ static int vxp_load_xilinx_binary(struct vx_core *_chip, const struct firmware *fw) { - struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + struct snd_vxpocket *chip = to_vxpocket(_chip); unsigned int i; int c; int regCSUER, regRUER; @@ -280,7 +280,7 @@ static int vxp_load_dsp(struct vx_core *vx, int index, const struct firmware *fw */ static int vxp_test_and_ack(struct vx_core *_chip) { - struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + struct snd_vxpocket *chip = to_vxpocket(_chip); /* not booted yet? */ if (! (_chip->chip_status & VX_STAT_XILINX_LOADED)) @@ -307,7 +307,7 @@ static int vxp_test_and_ack(struct vx_core *_chip) */ static void vxp_validate_irq(struct vx_core *_chip, int enable) { - struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + struct snd_vxpocket *chip = to_vxpocket(_chip); /* Set the interrupt enable bit to 1 in CDSP register */ if (enable) @@ -323,7 +323,7 @@ static void vxp_validate_irq(struct vx_core *_chip, int enable) */ static void vx_setup_pseudo_dma(struct vx_core *_chip, int do_write) { - struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + struct snd_vxpocket *chip = to_vxpocket(_chip); /* Interrupt mode and HREQ pin enabled for host transmit / receive data transfers */ vx_outb(chip, ICR, do_write ? ICR_TREQ : ICR_RREQ); @@ -343,7 +343,7 @@ static void vx_setup_pseudo_dma(struct vx_core *_chip, int do_write) */ static void vx_release_pseudo_dma(struct vx_core *_chip) { - struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + struct snd_vxpocket *chip = to_vxpocket(_chip); /* Disable DMA and 16-bit accesses */ chip->regDIALOG &= ~(VXP_DLG_DMAWRITE_SEL_MASK| @@ -403,7 +403,7 @@ static void vxp_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime, static void vxp_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime, struct vx_pipe *pipe, int count) { - struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip; + struct snd_vxpocket *pchip = to_vxpocket(chip); long port = vxp_reg_addr(chip, VX_DMA); int offset = pipe->hw_ptr; unsigned short *addr = (unsigned short *)(runtime->dma_area + offset); @@ -467,7 +467,7 @@ static void vxp_write_codec_reg(struct vx_core *chip, int codec, unsigned int da */ void vx_set_mic_boost(struct vx_core *chip, int boost) { - struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip; + struct snd_vxpocket *pchip = to_vxpocket(chip); if (chip->chip_status & VX_STAT_IS_STALE) return; @@ -509,7 +509,7 @@ static int vx_compute_mic_level(int level) */ void vx_set_mic_level(struct vx_core *chip, int level) { - struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip; + struct snd_vxpocket *pchip = to_vxpocket(chip); if (chip->chip_status & VX_STAT_IS_STALE) return; @@ -528,7 +528,7 @@ void vx_set_mic_level(struct vx_core *chip, int level) */ static void vxp_change_audio_source(struct vx_core *_chip, int src) { - struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + struct snd_vxpocket *chip = to_vxpocket(_chip); switch (src) { case VX_AUDIO_SRC_DIGITAL: @@ -568,7 +568,7 @@ static void vxp_change_audio_source(struct vx_core *_chip, int src) */ static void vxp_set_clock_source(struct vx_core *_chip, int source) { - struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + struct snd_vxpocket *chip = to_vxpocket(_chip); if (source == INTERNAL_QUARTZ) chip->regCDSP &= ~VXP_CDSP_CLOCKIN_SEL_MASK; @@ -583,7 +583,7 @@ static void vxp_set_clock_source(struct vx_core *_chip, int source) */ static void vxp_reset_board(struct vx_core *_chip, int cold_reset) { - struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + struct snd_vxpocket *chip = to_vxpocket(_chip); chip->regCDSP = 0; chip->regDIALOG = 0; diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index b16f42deed67..ca0d19e723fd 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -155,7 +155,7 @@ static int snd_vxpocket_new(struct snd_card *card, int ibl, } chip->ibl.size = ibl; - vxp = (struct snd_vxpocket *)chip; + vxp = to_vxpocket(chip); vxp->p_dev = link; link->priv = chip; @@ -187,7 +187,7 @@ static int snd_vxpocket_assign_resources(struct vx_core *chip, int port, int irq { int err; struct snd_card *card = chip->card; - struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; + struct snd_vxpocket *vxp = to_vxpocket(chip); snd_printdd(KERN_DEBUG "vxpocket assign resources: port = 0x%x, irq = %d\n", port, irq); vxp->port = port; diff --git a/sound/pcmcia/vx/vxpocket.h b/sound/pcmcia/vx/vxpocket.h index 13d658c1a216..26f4255e132e 100644 --- a/sound/pcmcia/vx/vxpocket.h +++ b/sound/pcmcia/vx/vxpocket.h @@ -43,6 +43,8 @@ struct snd_vxpocket { struct pcmcia_device *p_dev; }; +#define to_vxpocket(x) container_of(x, struct snd_vxpocket, core) + extern struct snd_vx_ops snd_vxpocket_ops; void vx_set_mic_boost(struct vx_core *chip, int boost); From 239480ab92a52544748749c8445f4e12495e4f69 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 12 May 2017 10:47:16 +0200 Subject: [PATCH 020/418] ALSA: ak411x: Use array instead of offsetof() The ak4113, ak4114 and ak4117 i2c drivers have some tricky codes to access the struct fields in the callback. This can be simplified by replacing the struct fields with the array. Signed-off-by: Takashi Iwai --- include/sound/ak4113.h | 13 +++++++++---- include/sound/ak4114.h | 13 +++++++++---- include/sound/ak4117.h | 13 +++++++++---- sound/i2c/other/ak4113.c | 23 +++++++++++------------ sound/i2c/other/ak4114.c | 23 +++++++++++------------ sound/i2c/other/ak4117.c | 23 +++++++++++------------ 6 files changed, 60 insertions(+), 48 deletions(-) diff --git a/include/sound/ak4113.h b/include/sound/ak4113.h index 58c145620c3c..b2d09fd09559 100644 --- a/include/sound/ak4113.h +++ b/include/sound/ak4113.h @@ -281,6 +281,14 @@ typedef void (ak4113_write_t)(void *private_data, unsigned char addr, unsigned char data); typedef unsigned char (ak4113_read_t)(void *private_data, unsigned char addr); +enum { + AK4113_PARITY_ERRORS, + AK4113_V_BIT_ERRORS, + AK4113_QCRC_ERRORS, + AK4113_CCRC_ERRORS, + AK4113_NUM_ERRORS +}; + struct ak4113 { struct snd_card *card; ak4113_write_t *write; @@ -292,10 +300,7 @@ struct ak4113 { unsigned char regmap[AK4113_WRITABLE_REGS]; struct snd_kcontrol *kctls[AK4113_CONTROLS]; struct snd_pcm_substream *substream; - unsigned long parity_errors; - unsigned long v_bit_errors; - unsigned long qcrc_errors; - unsigned long ccrc_errors; + unsigned long errors[AK4113_NUM_ERRORS]; unsigned char rcs0; unsigned char rcs1; unsigned char rcs2; diff --git a/include/sound/ak4114.h b/include/sound/ak4114.h index b6feb7e225f2..39df064c82fc 100644 --- a/include/sound/ak4114.h +++ b/include/sound/ak4114.h @@ -163,6 +163,14 @@ typedef void (ak4114_write_t)(void *private_data, unsigned char addr, unsigned char data); typedef unsigned char (ak4114_read_t)(void *private_data, unsigned char addr); +enum { + AK4114_PARITY_ERRORS, + AK4114_V_BIT_ERRORS, + AK4114_QCRC_ERRORS, + AK4114_CCRC_ERRORS, + AK4114_NUM_ERRORS +}; + struct ak4114 { struct snd_card *card; ak4114_write_t * write; @@ -176,10 +184,7 @@ struct ak4114 { struct snd_kcontrol *kctls[AK4114_CONTROLS]; struct snd_pcm_substream *playback_substream; struct snd_pcm_substream *capture_substream; - unsigned long parity_errors; - unsigned long v_bit_errors; - unsigned long qcrc_errors; - unsigned long ccrc_errors; + unsigned long errors[AK4114_NUM_ERRORS]; unsigned char rcs0; unsigned char rcs1; struct delayed_work work; diff --git a/include/sound/ak4117.h b/include/sound/ak4117.h index 1e8178171baf..5fab517cfe46 100644 --- a/include/sound/ak4117.h +++ b/include/sound/ak4117.h @@ -155,6 +155,14 @@ typedef void (ak4117_write_t)(void *private_data, unsigned char addr, unsigned char data); typedef unsigned char (ak4117_read_t)(void *private_data, unsigned char addr); +enum { + AK4117_PARITY_ERRORS, + AK4117_V_BIT_ERRORS, + AK4117_QCRC_ERRORS, + AK4117_CCRC_ERRORS, + AK4117_NUM_ERRORS +}; + struct ak4117 { struct snd_card *card; ak4117_write_t * write; @@ -165,10 +173,7 @@ struct ak4117 { unsigned char regmap[5]; struct snd_kcontrol *kctls[AK4117_CONTROLS]; struct snd_pcm_substream *substream; - unsigned long parity_errors; - unsigned long v_bit_errors; - unsigned long qcrc_errors; - unsigned long ccrc_errors; + unsigned long errors[AK4117_NUM_ERRORS]; unsigned char rcs0; unsigned char rcs1; unsigned char rcs2; diff --git a/sound/i2c/other/ak4113.c b/sound/i2c/other/ak4113.c index 2183e9ebaa6d..4099e6062d3c 100644 --- a/sound/i2c/other/ak4113.c +++ b/sound/i2c/other/ak4113.c @@ -199,12 +199,11 @@ static int snd_ak4113_in_error_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct ak4113 *chip = snd_kcontrol_chip(kcontrol); - long *ptr; spin_lock_irq(&chip->lock); - ptr = (long *)(((char *)chip) + kcontrol->private_value); - ucontrol->value.integer.value[0] = *ptr; - *ptr = 0; + ucontrol->value.integer.value[0] = + chip->errors[kcontrol->private_value]; + chip->errors[kcontrol->private_value] = 0; spin_unlock_irq(&chip->lock); return 0; } @@ -373,7 +372,7 @@ static struct snd_kcontrol_new snd_ak4113_iec958_controls[] = { SNDRV_CTL_ELEM_ACCESS_VOLATILE, .info = snd_ak4113_in_error_info, .get = snd_ak4113_in_error_get, - .private_value = offsetof(struct ak4113, parity_errors), + .private_value = AK4113_PARITY_ERRORS, }, { .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -382,7 +381,7 @@ static struct snd_kcontrol_new snd_ak4113_iec958_controls[] = { SNDRV_CTL_ELEM_ACCESS_VOLATILE, .info = snd_ak4113_in_error_info, .get = snd_ak4113_in_error_get, - .private_value = offsetof(struct ak4113, v_bit_errors), + .private_value = AK4113_V_BIT_ERRORS, }, { .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -391,7 +390,7 @@ static struct snd_kcontrol_new snd_ak4113_iec958_controls[] = { SNDRV_CTL_ELEM_ACCESS_VOLATILE, .info = snd_ak4113_in_error_info, .get = snd_ak4113_in_error_get, - .private_value = offsetof(struct ak4113, ccrc_errors), + .private_value = AK4113_CCRC_ERRORS, }, { .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -400,7 +399,7 @@ static struct snd_kcontrol_new snd_ak4113_iec958_controls[] = { SNDRV_CTL_ELEM_ACCESS_VOLATILE, .info = snd_ak4113_in_error_info, .get = snd_ak4113_in_error_get, - .private_value = offsetof(struct ak4113, qcrc_errors), + .private_value = AK4113_QCRC_ERRORS, }, { .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -551,13 +550,13 @@ int snd_ak4113_check_rate_and_errors(struct ak4113 *ak4113, unsigned int flags) rcs2 = reg_read(ak4113, AK4113_REG_RCS2); spin_lock_irqsave(&ak4113->lock, _flags); if (rcs0 & AK4113_PAR) - ak4113->parity_errors++; + ak4113->errors[AK4113_PARITY_ERRORS]++; if (rcs0 & AK4113_V) - ak4113->v_bit_errors++; + ak4113->errors[AK4113_V_BIT_ERRORS]++; if (rcs2 & AK4113_CCRC) - ak4113->ccrc_errors++; + ak4113->errors[AK4113_CCRC_ERRORS]++; if (rcs2 & AK4113_QCRC) - ak4113->qcrc_errors++; + ak4113->errors[AK4113_QCRC_ERRORS]++; c0 = (ak4113->rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC | AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK)) ^ (rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC | diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index d53c9bb36281..7fb1aeb46915 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -194,12 +194,11 @@ static int snd_ak4114_in_error_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct ak4114 *chip = snd_kcontrol_chip(kcontrol); - long *ptr; spin_lock_irq(&chip->lock); - ptr = (long *)(((char *)chip) + kcontrol->private_value); - ucontrol->value.integer.value[0] = *ptr; - *ptr = 0; + ucontrol->value.integer.value[0] = + chip->errors[kcontrol->private_value]; + chip->errors[kcontrol->private_value] = 0; spin_unlock_irq(&chip->lock); return 0; } @@ -341,7 +340,7 @@ static struct snd_kcontrol_new snd_ak4114_iec958_controls[] = { .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, .info = snd_ak4114_in_error_info, .get = snd_ak4114_in_error_get, - .private_value = offsetof(struct ak4114, parity_errors), + .private_value = AK4114_PARITY_ERRORS, }, { .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -349,7 +348,7 @@ static struct snd_kcontrol_new snd_ak4114_iec958_controls[] = { .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, .info = snd_ak4114_in_error_info, .get = snd_ak4114_in_error_get, - .private_value = offsetof(struct ak4114, v_bit_errors), + .private_value = AK4114_V_BIT_ERRORS, }, { .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -357,7 +356,7 @@ static struct snd_kcontrol_new snd_ak4114_iec958_controls[] = { .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, .info = snd_ak4114_in_error_info, .get = snd_ak4114_in_error_get, - .private_value = offsetof(struct ak4114, ccrc_errors), + .private_value = AK4114_CCRC_ERRORS, }, { .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -365,7 +364,7 @@ static struct snd_kcontrol_new snd_ak4114_iec958_controls[] = { .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, .info = snd_ak4114_in_error_info, .get = snd_ak4114_in_error_get, - .private_value = offsetof(struct ak4114, qcrc_errors), + .private_value = AK4114_QCRC_ERRORS, }, { .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -581,13 +580,13 @@ int snd_ak4114_check_rate_and_errors(struct ak4114 *ak4114, unsigned int flags) rcs0 = reg_read(ak4114, AK4114_REG_RCS0); spin_lock_irqsave(&ak4114->lock, _flags); if (rcs0 & AK4114_PAR) - ak4114->parity_errors++; + ak4114->errors[AK4114_PARITY_ERRORS]++; if (rcs1 & AK4114_V) - ak4114->v_bit_errors++; + ak4114->errors[AK4114_V_BIT_ERRORS]++; if (rcs1 & AK4114_CCRC) - ak4114->ccrc_errors++; + ak4114->errors[AK4114_CCRC_ERRORS]++; if (rcs1 & AK4114_QCRC) - ak4114->qcrc_errors++; + ak4114->errors[AK4114_QCRC_ERRORS]++; c0 = (ak4114->rcs0 & (AK4114_QINT | AK4114_CINT | AK4114_PEM | AK4114_AUDION | AK4114_AUTO | AK4114_UNLCK)) ^ (rcs0 & (AK4114_QINT | AK4114_CINT | AK4114_PEM | AK4114_AUDION | AK4114_AUTO | AK4114_UNLCK)); c1 = (ak4114->rcs1 & 0xf0) ^ (rcs1 & 0xf0); diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c index 0702f0552d19..3ab099fb8c15 100644 --- a/sound/i2c/other/ak4117.c +++ b/sound/i2c/other/ak4117.c @@ -168,12 +168,11 @@ static int snd_ak4117_in_error_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct ak4117 *chip = snd_kcontrol_chip(kcontrol); - long *ptr; spin_lock_irq(&chip->lock); - ptr = (long *)(((char *)chip) + kcontrol->private_value); - ucontrol->value.integer.value[0] = *ptr; - *ptr = 0; + ucontrol->value.integer.value[0] = + chip->errors[kcontrol->private_value]; + chip->errors[kcontrol->private_value] = 0; spin_unlock_irq(&chip->lock); return 0; } @@ -328,7 +327,7 @@ static struct snd_kcontrol_new snd_ak4117_iec958_controls[] = { .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, .info = snd_ak4117_in_error_info, .get = snd_ak4117_in_error_get, - .private_value = offsetof(struct ak4117, parity_errors), + .private_value = AK4117_PARITY_ERRORS, }, { .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -336,7 +335,7 @@ static struct snd_kcontrol_new snd_ak4117_iec958_controls[] = { .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, .info = snd_ak4117_in_error_info, .get = snd_ak4117_in_error_get, - .private_value = offsetof(struct ak4117, v_bit_errors), + .private_value = AK4117_V_BIT_ERRORS, }, { .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -344,7 +343,7 @@ static struct snd_kcontrol_new snd_ak4117_iec958_controls[] = { .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, .info = snd_ak4117_in_error_info, .get = snd_ak4117_in_error_get, - .private_value = offsetof(struct ak4117, ccrc_errors), + .private_value = AK4117_CCRC_ERRORS, }, { .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -352,7 +351,7 @@ static struct snd_kcontrol_new snd_ak4117_iec958_controls[] = { .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, .info = snd_ak4117_in_error_info, .get = snd_ak4117_in_error_get, - .private_value = offsetof(struct ak4117, qcrc_errors), + .private_value = AK4117_QCRC_ERRORS, }, { .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -470,13 +469,13 @@ int snd_ak4117_check_rate_and_errors(struct ak4117 *ak4117, unsigned int flags) // printk(KERN_DEBUG "AK IRQ: rcs0 = 0x%x, rcs1 = 0x%x, rcs2 = 0x%x\n", rcs0, rcs1, rcs2); spin_lock_irqsave(&ak4117->lock, _flags); if (rcs0 & AK4117_PAR) - ak4117->parity_errors++; + ak4117->errors[AK4117_PARITY_ERRORS]++; if (rcs0 & AK4117_V) - ak4117->v_bit_errors++; + ak4117->errors[AK4117_V_BIT_ERRORS]++; if (rcs2 & AK4117_CCRC) - ak4117->ccrc_errors++; + ak4117->errors[AK4117_CCRC_ERRORS]++; if (rcs2 & AK4117_QCRC) - ak4117->qcrc_errors++; + ak4117->errors[AK4117_QCRC_ERRORS]++; c0 = (ak4117->rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)) ^ (rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)); c1 = (ak4117->rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)) ^ From 58f30d650c7f5275d4d57e62862970e1078af462 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 12 May 2017 11:35:17 +0200 Subject: [PATCH 021/418] ALSA: pcm: Build pcm notifier code conditionally The PCM notifier code is used only by OSS emulation layer, so we can build it conditionally for reducing the size. Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 15 ++++++++------- sound/core/pcm.c | 33 ++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 361749e60799..eb16912d6046 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -531,13 +531,6 @@ struct snd_pcm { #endif }; -struct snd_pcm_notify { - int (*n_register) (struct snd_pcm * pcm); - int (*n_disconnect) (struct snd_pcm * pcm); - int (*n_unregister) (struct snd_pcm * pcm); - struct list_head list; -}; - /* * Registering */ @@ -552,7 +545,15 @@ int snd_pcm_new_internal(struct snd_card *card, const char *id, int device, struct snd_pcm **rpcm); int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count); +#if IS_ENABLED(CONFIG_SND_PCM_OSS) +struct snd_pcm_notify { + int (*n_register) (struct snd_pcm * pcm); + int (*n_disconnect) (struct snd_pcm * pcm); + int (*n_unregister) (struct snd_pcm * pcm); + struct list_head list; +}; int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree); +#endif /* * Native I/O diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8e980aa678d0..24acbfb5c531 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -36,8 +36,10 @@ MODULE_DESCRIPTION("Midlevel PCM code for ALSA."); MODULE_LICENSE("GPL"); static LIST_HEAD(snd_pcm_devices); -static LIST_HEAD(snd_pcm_notify_list); static DEFINE_MUTEX(register_mutex); +#if IS_ENABLED(CONFIG_SND_PCM_OSS) +static LIST_HEAD(snd_pcm_notify_list); +#endif static int snd_pcm_free(struct snd_pcm *pcm); static int snd_pcm_dev_free(struct snd_device *device); @@ -884,16 +886,23 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) put_device(&pstr->dev); } +#if IS_ENABLED(CONFIG_SND_PCM_OSS) +#define pcm_call_notify(pcm, call) \ + do { \ + struct snd_pcm_notify *_notify; \ + list_for_each_entry(_notify, &snd_pcm_notify_list, list) \ + _notify->call(pcm); \ + } while (0) +#else +#define pcm_call_notify(pcm, call) /* NOP */ +#endif + static int snd_pcm_free(struct snd_pcm *pcm) { - struct snd_pcm_notify *notify; - if (!pcm) return 0; - if (!pcm->internal) { - list_for_each_entry(notify, &snd_pcm_notify_list, list) - notify->n_unregister(pcm); - } + if (!pcm->internal) + pcm_call_notify(pcm, n_unregister); if (pcm->private_free) pcm->private_free(pcm); snd_pcm_lib_preallocate_free_for_all(pcm); @@ -1069,7 +1078,6 @@ static int snd_pcm_dev_register(struct snd_device *device) { int cidx, err; struct snd_pcm_substream *substream; - struct snd_pcm_notify *notify; struct snd_pcm *pcm; if (snd_BUG_ON(!device || !device->device_data)) @@ -1107,8 +1115,7 @@ static int snd_pcm_dev_register(struct snd_device *device) snd_pcm_timer_init(substream); } - list_for_each_entry(notify, &snd_pcm_notify_list, list) - notify->n_register(pcm); + pcm_call_notify(pcm, n_register); unlock: mutex_unlock(®ister_mutex); @@ -1118,7 +1125,6 @@ static int snd_pcm_dev_register(struct snd_device *device) static int snd_pcm_dev_disconnect(struct snd_device *device) { struct snd_pcm *pcm = device->device_data; - struct snd_pcm_notify *notify; struct snd_pcm_substream *substream; int cidx; @@ -1138,8 +1144,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) } } if (!pcm->internal) { - list_for_each_entry(notify, &snd_pcm_notify_list, list) - notify->n_disconnect(pcm); + pcm_call_notify(pcm, n_disconnect); } for (cidx = 0; cidx < 2; cidx++) { if (!pcm->internal) @@ -1151,6 +1156,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) return 0; } +#if IS_ENABLED(CONFIG_SND_PCM_OSS) /** * snd_pcm_notify - Add/remove the notify list * @notify: PCM notify list @@ -1183,6 +1189,7 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) return 0; } EXPORT_SYMBOL(snd_pcm_notify); +#endif /* CONFIG_SND_PCM_OSS */ #ifdef CONFIG_SND_PROC_FS /* From 6d2412b80aabf5d77400fbb960ee041475df86aa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 12 May 2017 11:44:03 +0200 Subject: [PATCH 022/418] ALSA: Use IS_ENABLED() in common headers Simplify the ifdef conditions with IS_ENABLED() macro in the common sound headers. No functional changes. Signed-off-by: Takashi Iwai --- include/sound/core.h | 6 +++--- include/sound/mixer_oss.h | 2 +- include/sound/opl3.h | 4 ++-- include/sound/pcm.h | 10 +++++----- include/sound/rawmidi.h | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/sound/core.h b/include/sound/core.h index f7d8c10c4c45..55385588eefa 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -142,7 +142,7 @@ struct snd_card { wait_queue_head_t power_sleep; #endif -#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_MIXER_OSS) struct snd_mixer_oss *mixer_oss; int mixer_oss_change_count; #endif @@ -243,7 +243,7 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size extern struct snd_card *snd_cards[SNDRV_CARDS]; int snd_card_locked(int card); -#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_MIXER_OSS) #define SND_MIXER_OSS_NOTIFY_REGISTER 0 #define SND_MIXER_OSS_NOTIFY_DISCONNECT 1 #define SND_MIXER_OSS_NOTIFY_FREE 2 @@ -394,7 +394,7 @@ static inline void snd_printdd(const char *format, ...) {} #define SNDRV_OSS_VERSION ((3<<16)|(8<<8)|(1<<4)|(0)) /* 3.8.1a */ /* for easier backward-porting */ -#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE) +#if IS_ENABLED(CONFIG_GAMEPORT) #define gameport_set_dev_parent(gp,xdev) ((gp)->dev.parent = (xdev)) #define gameport_set_port_data(gp,r) ((gp)->port_data = (r)) #define gameport_get_port_data(gp) (gp)->port_data diff --git a/include/sound/mixer_oss.h b/include/sound/mixer_oss.h index 13cb0b430a1b..930da10fb65b 100644 --- a/include/sound/mixer_oss.h +++ b/include/sound/mixer_oss.h @@ -22,7 +22,7 @@ * */ -#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_MIXER_OSS) #define SNDRV_OSS_MAX_MIXERS 32 diff --git a/include/sound/opl3.h b/include/sound/opl3.h index 6ba670707831..5a87641c6ae4 100644 --- a/include/sound/opl3.h +++ b/include/sound/opl3.h @@ -321,7 +321,7 @@ struct snd_opl3 { unsigned char fm_mode; /* OPL mode, see SNDRV_DM_FM_MODE_XXX */ unsigned char rhythm; /* percussion mode flag */ unsigned char max_voices; /* max number of voices */ -#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) +#if IS_ENABLED(CONFIG_SND_SEQUENCER) #define SNDRV_OPL3_MODE_SYNTH 0 /* OSS - voices allocated by application */ #define SNDRV_OPL3_MODE_SEQ 1 /* ALSA - driver handles voice allocation */ int synth_mode; /* synth mode */ @@ -374,7 +374,7 @@ int snd_opl3_release(struct snd_hwdep * hw, struct file *file); void snd_opl3_reset(struct snd_opl3 * opl3); -#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) +#if IS_ENABLED(CONFIG_SND_SEQUENCER) long snd_opl3_write(struct snd_hwdep *hw, const char __user *buf, long count, loff_t *offset); int snd_opl3_load_patch(struct snd_opl3 *opl3, diff --git a/include/sound/pcm.h b/include/sound/pcm.h index eb16912d6046..3f084486868f 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -34,7 +34,7 @@ #define snd_pcm_substream_chip(substream) ((substream)->private_data) #define snd_pcm_chip(pcm) ((pcm)->private_data) -#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_PCM_OSS) #include #endif @@ -418,7 +418,7 @@ struct snd_pcm_runtime { struct snd_pcm_audio_tstamp_report audio_tstamp_report; struct timespec driver_tstamp; -#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_PCM_OSS) /* -- OSS things -- */ struct snd_pcm_oss_runtime oss; #endif @@ -464,7 +464,7 @@ struct snd_pcm_substream { unsigned int f_flags; void (*pcm_release)(struct snd_pcm_substream *); struct pid *pid; -#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_PCM_OSS) /* -- OSS things -- */ struct snd_pcm_oss_substream oss; #endif @@ -494,7 +494,7 @@ struct snd_pcm_str { unsigned int substream_count; unsigned int substream_opened; struct snd_pcm_substream *substream; -#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_PCM_OSS) /* -- OSS things -- */ struct snd_pcm_oss_stream oss; #endif @@ -526,7 +526,7 @@ struct snd_pcm { void (*private_free) (struct snd_pcm *pcm); bool internal; /* pcm is for internal use only */ bool nonatomic; /* whole PCM operations are in non-atomic context */ -#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_PCM_OSS) struct snd_pcm_oss oss; #endif }; diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index 492a3ca7f17b..6665cb29e1a2 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -30,7 +30,7 @@ #include #include -#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) +#if IS_ENABLED(CONFIG_SND_SEQUENCER) #include #endif @@ -144,7 +144,7 @@ struct snd_rawmidi { struct snd_info_entry *proc_entry; -#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) +#if IS_ENABLED(CONFIG_SND_SEQUENCER) struct snd_seq_device *seq_dev; #endif }; From 88faa38435cbfdf3e733a670a009683eb7057cdc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 12 May 2017 11:44:54 +0200 Subject: [PATCH 023/418] ALSA: cmi8238: Use IS_ENABLED() Simplify the ifdef conditions with IS_ENABLED() macro. No functional changes. Signed-off-by: Takashi Iwai --- sound/isa/cmi8328.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c index 8e1756c3b9bb..d09e456107ad 100644 --- a/sound/isa/cmi8328.c +++ b/sound/isa/cmi8328.c @@ -26,7 +26,7 @@ MODULE_AUTHOR("Ondrej Zary "); MODULE_DESCRIPTION("C-Media CMI8328"); MODULE_LICENSE("GPL"); -#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE) +#if IS_ENABLED(CONFIG_GAMEPORT) #define SUPPORT_JOYSTICK 1 #endif From 2e2d4cb450e951b90629b3f988c48ed01c69c1ac Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 12 May 2017 11:52:06 +0200 Subject: [PATCH 024/418] ALSA: opl4: Use IS_REACHABLE() Rewrite the complex ifdef condition with IS_REACHABLE(). The ifdef in opl4_local.h was without defined(MODLE) check, but this is likely the oversight. Use IS_REACHABLE() here as well. Acked-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/drivers/opl4/opl4_lib.c | 4 ++-- sound/drivers/opl4/opl4_local.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c index 89c7aa04b3bc..240656e54400 100644 --- a/sound/drivers/opl4/opl4_lib.c +++ b/sound/drivers/opl4/opl4_lib.c @@ -153,7 +153,7 @@ static int snd_opl4_detect(struct snd_opl4 *opl4) return 0; } -#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) +#if IS_REACHABLE(CONFIG_SND_SEQUENCER) static void snd_opl4_seq_dev_free(struct snd_seq_device *seq_dev) { struct snd_opl4 *opl4 = seq_dev->private_data; @@ -249,7 +249,7 @@ int snd_opl4_create(struct snd_card *card, snd_opl4_create_mixer(opl4); snd_opl4_create_proc(opl4); -#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) +#if IS_REACHABLE(CONFIG_SND_SEQUENCER) opl4->seq_client = -1; if (opl4->hardware < OPL3_HW_OPL4_ML) snd_opl4_create_seq_dev(opl4, seq_device); diff --git a/sound/drivers/opl4/opl4_local.h b/sound/drivers/opl4/opl4_local.h index 9a41bdebce6b..d5bac93f8245 100644 --- a/sound/drivers/opl4/opl4_local.h +++ b/sound/drivers/opl4/opl4_local.h @@ -184,7 +184,7 @@ struct snd_opl4 { #endif struct mutex access_mutex; -#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) +#if IS_REACHABLE(CONFIG_SND_SEQUENCER) int used; int seq_dev_num; From a0af56de2c6defd7b0b7fec990fca819621d3c62 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 12 May 2017 11:54:26 +0200 Subject: [PATCH 025/418] ALSA: sb: Use IS_REACHABLE() Replace the complex ifdef conditions with IS_REACHABLE() macro. No functional changes. Signed-off-by: Takashi Iwai --- sound/isa/sb/emu8000.c | 2 +- sound/isa/sb/sb16.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index ec180708f160..0b5c4cf3abfa 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -1138,7 +1138,7 @@ snd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports, snd_emu8000_free(hw); return err; } -#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) +#if IS_REACHABLE(CONFIG_SND_SEQUENCER) if (snd_seq_device_new(card, index, SNDRV_SEQ_DEV_ID_EMU8000, sizeof(struct snd_emu8000*), &awe) >= 0) { strcpy(awe->name, "EMU-8000"); diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c index 3b2e4f405ff2..31ab09b3b049 100644 --- a/sound/isa/sb/sb16.c +++ b/sound/isa/sb/sb16.c @@ -62,7 +62,7 @@ MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB AWE 32}," #define SNDRV_DEBUG_IRQ #endif -#if defined(SNDRV_SBAWE) && (defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))) +#if defined(SNDRV_SBAWE) && IS_REACHABLE(CONFIG_SND_SEQUENCER) #define SNDRV_SBAWE_EMU8000 #endif From 667011706707f91f53122259f62d260cfc01a96d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 12 May 2017 11:55:17 +0200 Subject: [PATCH 026/418] ALSA: cs4281: Fix the leftover comment The comment at endif line was forgotten to be corrected when the condition was converted to IS_REACHABLE(). Fix it, too. Signed-off-by: Takashi Iwai --- sound/pci/cs4281.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index f870697aca67..ee7ba4b0b47b 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -1296,7 +1296,7 @@ static void snd_cs4281_free_gameport(struct cs4281 *chip) #else static inline int snd_cs4281_create_gameport(struct cs4281 *chip) { return -ENOSYS; } static inline void snd_cs4281_free_gameport(struct cs4281 *chip) { } -#endif /* CONFIG_GAMEPORT || (MODULE && CONFIG_GAMEPORT_MODULE) */ +#endif /* IS_REACHABLE(CONFIG_GAMEPORT) */ static int snd_cs4281_free(struct cs4281 *chip) { From 52204718b1f04a84feadd86f3eab5b4da365306f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 14 May 2017 12:38:44 -0300 Subject: [PATCH 027/418] ALSA: pcm: fix the comments that refers to kernel-doc The markup inside the #if 0 comment actually refers to a kernel-doc markup. As we're getting rid of DocBook update it. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 3f084486868f..c609b891c4c2 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -1055,7 +1055,7 @@ int snd_pcm_format_unsigned(snd_pcm_format_t format); int snd_pcm_format_linear(snd_pcm_format_t format); int snd_pcm_format_little_endian(snd_pcm_format_t format); int snd_pcm_format_big_endian(snd_pcm_format_t format); -#if 0 /* just for DocBook */ +#if 0 /* just for kernel-doc */ /** * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian * @format: the format to check From a717777dbfc4bffc0606439a162144994ae02b14 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 12:04:08 +0200 Subject: [PATCH 028/418] ALSA: hda - Simplify bound-beep mute control for ALC268 The beep mute switch for ALC268 needs to touch two NIDs, and we used to apply the bind-mixer stuff. But the use case for ALC268 is fairly easy to convert to an open-code in a shorter form. Since this is the only user of the bind-ctls, we can clean up the common helper codes later. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 37 ++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 58df440013c5..87e1368de4d5 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2573,18 +2573,37 @@ static int patch_alc262(struct hda_codec *codec) * ALC268 */ /* bind Beep switches of both NID 0x0f and 0x10 */ -static const struct hda_bind_ctls alc268_bind_beep_sw = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT), - 0 - }, -}; +static int alc268_beep_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned long pval; + int err; + + mutex_lock(&codec->control_mutex); + pval = kcontrol->private_value; + kcontrol->private_value = (pval & ~0xff) | 0x0f; + err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); + if (err >= 0) { + kcontrol->private_value = (pval & ~0xff) | 0x10; + err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); + } + kcontrol->private_value = pval; + mutex_unlock(&codec->control_mutex); + return err; +} static const struct snd_kcontrol_new alc268_beep_mixer[] = { HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT), - HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Beep Playback Switch", + .subdevice = HDA_SUBDEV_AMP_FLAG, + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc268_beep_switch_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT) + }, { } }; From 698f5ee33bd8e9b728d4b8511df4109200bca95f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 12:13:45 +0200 Subject: [PATCH 029/418] ALSA: hda - Move bind-mixer switch codes to generic parser The generic parser is the only user of the bind-mixer controls, so we can move the code there and clean up the core helper. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 66 ------------------------------------- sound/pci/hda/hda_generic.c | 46 ++++++++++++++++++++++++-- sound/pci/hda/hda_local.h | 17 ---------- 3 files changed, 44 insertions(+), 85 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 70bb365a08d2..29f243679a21 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2117,72 +2117,6 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put); -/* - * bound volume controls - * - * bind multiple volumes (# indices, from 0) - */ - -#define AMP_VAL_IDX_SHIFT 19 -#define AMP_VAL_IDX_MASK (0x0f<<19) - -/** - * snd_hda_mixer_bind_switch_get - Get callback for a bound volume control - * @kcontrol: ctl element - * @ucontrol: pointer to get/store the data - * - * The control element is supposed to have the private_value field - * set up via HDA_BIND_MUTE*() macros. - */ -int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned long pval; - int err; - - mutex_lock(&codec->control_mutex); - pval = kcontrol->private_value; - kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ - err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); - kcontrol->private_value = pval; - mutex_unlock(&codec->control_mutex); - return err; -} -EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_get); - -/** - * snd_hda_mixer_bind_switch_put - Put callback for a bound volume control - * @kcontrol: ctl element - * @ucontrol: pointer to get/store the data - * - * The control element is supposed to have the private_value field - * set up via HDA_BIND_MUTE*() macros. - */ -int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned long pval; - int i, indices, err = 0, change = 0; - - mutex_lock(&codec->control_mutex); - pval = kcontrol->private_value; - indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; - for (i = 0; i < indices; i++) { - kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) | - (i << AMP_VAL_IDX_SHIFT); - err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - if (err < 0) - break; - change |= err; - } - kcontrol->private_value = pval; - mutex_unlock(&codec->control_mutex); - return err < 0 ? err : change; -} -EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_put); - /** * snd_hda_mixer_bind_ctls_info - Info callback for a generic bound control * @kcontrol: referred ctl element diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 2842c82363c0..557ecfcad158 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -948,6 +948,8 @@ static void resume_path_from_idx(struct hda_codec *codec, int path_idx) static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +static int hda_gen_bind_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); @@ -970,7 +972,7 @@ static const struct snd_kcontrol_new control_templates[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_bind_switch_get, + .get = hda_gen_bind_mute_get, .put = hda_gen_bind_mute_put, /* replaced */ .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0), }, @@ -1101,11 +1103,51 @@ static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); } +/* + * Bound mute controls + */ +#define AMP_VAL_IDX_SHIFT 19 +#define AMP_VAL_IDX_MASK (0x0f<<19) + +static int hda_gen_bind_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned long pval; + int err; + + mutex_lock(&codec->control_mutex); + pval = kcontrol->private_value; + kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ + err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); + kcontrol->private_value = pval; + mutex_unlock(&codec->control_mutex); + return err; +} + static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned long pval; + int i, indices, err = 0, change = 0; + sync_auto_mute_bits(kcontrol, ucontrol); - return snd_hda_mixer_bind_switch_put(kcontrol, ucontrol); + + mutex_lock(&codec->control_mutex); + pval = kcontrol->private_value; + indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; + for (i = 0; i < indices; i++) { + kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) | + (i << AMP_VAL_IDX_SHIFT); + err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); + if (err < 0) + break; + change |= err; + } + kcontrol->private_value = pval; + mutex_unlock(&codec->control_mutex); + return err < 0 ? err : change; } /* any ctl assigned to the path with the given index? */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index d0e066e4c985..b73339199a8b 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -178,23 +178,6 @@ void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook); #define HDA_AMP_UNMUTE 0x00 #define HDA_AMP_VOLMASK 0x7f -/* mono switch binding multiple inputs */ -#define HDA_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = snd_hda_mixer_amp_switch_info, \ - .get = snd_hda_mixer_bind_switch_get, \ - .put = snd_hda_mixer_bind_switch_put, \ - .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, indices, direction) } - -/* stereo switch binding multiple inputs */ -#define HDA_BIND_MUTE(xname,nid,indices,dir) \ - HDA_BIND_MUTE_MONO(xname,nid,3,indices,dir) - -int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); - /* more generic bound controls */ struct hda_ctl_ops { snd_kcontrol_info_t *info; From 3db9e970e3b174a6c964c4dcc1df4939cc6d0387 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 12:15:16 +0200 Subject: [PATCH 030/418] ALSA: hda - Remove the generic bind ctl helpers Now all the users of this workaround code is gone, and we can finally remove the legacy codes from the core HD-audio module. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 124 -------------------------------------- sound/pci/hda/hda_local.h | 44 -------------- 2 files changed, 168 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 29f243679a21..187a9c717fb5 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2117,130 +2117,6 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put); -/** - * snd_hda_mixer_bind_ctls_info - Info callback for a generic bound control - * @kcontrol: referred ctl element - * @uinfo: pointer to get/store the data - * - * The control element is supposed to have the private_value field - * set up via HDA_BIND_VOL() or HDA_BIND_SW() macros. - */ -int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hda_bind_ctls *c; - int err; - - mutex_lock(&codec->control_mutex); - c = (struct hda_bind_ctls *)kcontrol->private_value; - kcontrol->private_value = *c->values; - err = c->ops->info(kcontrol, uinfo); - kcontrol->private_value = (long)c; - mutex_unlock(&codec->control_mutex); - return err; -} -EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_info); - -/** - * snd_hda_mixer_bind_ctls_get - Get callback for a generic bound control - * @kcontrol: ctl element - * @ucontrol: pointer to get/store the data - * - * The control element is supposed to have the private_value field - * set up via HDA_BIND_VOL() or HDA_BIND_SW() macros. - */ -int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hda_bind_ctls *c; - int err; - - mutex_lock(&codec->control_mutex); - c = (struct hda_bind_ctls *)kcontrol->private_value; - kcontrol->private_value = *c->values; - err = c->ops->get(kcontrol, ucontrol); - kcontrol->private_value = (long)c; - mutex_unlock(&codec->control_mutex); - return err; -} -EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_get); - -/** - * snd_hda_mixer_bind_ctls_put - Put callback for a generic bound control - * @kcontrol: ctl element - * @ucontrol: pointer to get/store the data - * - * The control element is supposed to have the private_value field - * set up via HDA_BIND_VOL() or HDA_BIND_SW() macros. - */ -int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hda_bind_ctls *c; - unsigned long *vals; - int err = 0, change = 0; - - mutex_lock(&codec->control_mutex); - c = (struct hda_bind_ctls *)kcontrol->private_value; - for (vals = c->values; *vals; vals++) { - kcontrol->private_value = *vals; - err = c->ops->put(kcontrol, ucontrol); - if (err < 0) - break; - change |= err; - } - kcontrol->private_value = (long)c; - mutex_unlock(&codec->control_mutex); - return err < 0 ? err : change; -} -EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_put); - -/** - * snd_hda_mixer_bind_tlv - TLV callback for a generic bound control - * @kcontrol: ctl element - * @op_flag: operation flag - * @size: byte size of input TLV - * @tlv: TLV data - * - * The control element is supposed to have the private_value field - * set up via HDA_BIND_VOL() macro. - */ -int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, - unsigned int size, unsigned int __user *tlv) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hda_bind_ctls *c; - int err; - - mutex_lock(&codec->control_mutex); - c = (struct hda_bind_ctls *)kcontrol->private_value; - kcontrol->private_value = *c->values; - err = c->ops->tlv(kcontrol, op_flag, size, tlv); - kcontrol->private_value = (long)c; - mutex_unlock(&codec->control_mutex); - return err; -} -EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_tlv); - -struct hda_ctl_ops snd_hda_bind_vol = { - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = snd_hda_mixer_amp_volume_put, - .tlv = snd_hda_mixer_amp_tlv -}; -EXPORT_SYMBOL_GPL(snd_hda_bind_vol); - -struct hda_ctl_ops snd_hda_bind_sw = { - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = snd_hda_mixer_amp_switch_put, - .tlv = snd_hda_mixer_amp_tlv -}; -EXPORT_SYMBOL_GPL(snd_hda_bind_sw); - /* * SPDIF out controls */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index b73339199a8b..5b5c324c99b9 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -178,50 +178,6 @@ void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook); #define HDA_AMP_UNMUTE 0x00 #define HDA_AMP_VOLMASK 0x7f -/* more generic bound controls */ -struct hda_ctl_ops { - snd_kcontrol_info_t *info; - snd_kcontrol_get_t *get; - snd_kcontrol_put_t *put; - snd_kcontrol_tlv_rw_t *tlv; -}; - -extern struct hda_ctl_ops snd_hda_bind_vol; /* for bind-volume with TLV */ -extern struct hda_ctl_ops snd_hda_bind_sw; /* for bind-switch */ - -struct hda_bind_ctls { - struct hda_ctl_ops *ops; - unsigned long values[]; -}; - -int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo); -int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, - unsigned int size, unsigned int __user *tlv); - -#define HDA_BIND_VOL(xname, bindrec) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ - SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,\ - .info = snd_hda_mixer_bind_ctls_info,\ - .get = snd_hda_mixer_bind_ctls_get,\ - .put = snd_hda_mixer_bind_ctls_put,\ - .tlv = { .c = snd_hda_mixer_bind_tlv },\ - .private_value = (long) (bindrec) } -#define HDA_BIND_SW(xname, bindrec) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,\ - .name = xname, \ - .info = snd_hda_mixer_bind_ctls_info,\ - .get = snd_hda_mixer_bind_ctls_get,\ - .put = snd_hda_mixer_bind_ctls_put,\ - .private_value = (long) (bindrec) } - /* * SPDIF I/O */ From 99b5c5bb9a5435a5ae5d46445ac0f2bf6aa5ee52 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 12:29:37 +0200 Subject: [PATCH 031/418] ALSA: hda - Remove the use of set_fs() set_fs() is used in HD-audio vmaster code to retrieve the TLV data of each slave kctl. Since the slave is supposed to be a standard amp kctl, we can call directly the supposed tlv callback instead of the indirect call, so that we can remove the set_fs() hack. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 59 ++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 187a9c717fb5..ff9c7968b562 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1477,6 +1477,30 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put); +/* inquiry the amp caps and convert to TLV */ +static void get_ctl_amp_tlv(struct snd_kcontrol *kcontrol, unsigned int *tlv) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = get_amp_nid(kcontrol); + int dir = get_amp_direction(kcontrol); + unsigned int ofs = get_amp_offset(kcontrol); + bool min_mute = get_amp_min_mute(kcontrol); + u32 caps, val1, val2; + + caps = query_amp_caps(codec, nid, dir); + val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; + val2 = (val2 + 1) * 25; + val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); + val1 += ofs; + val1 = ((int)val1) * ((int)val2); + if (min_mute || (caps & AC_AMPCAP_MIN_MUTE)) + val2 |= TLV_DB_SCALE_MUTE; + tlv[0] = SNDRV_CTL_TLVT_DB_SCALE; + tlv[1] = 2 * sizeof(unsigned int); + tlv[2] = val1; + tlv[3] = val2; +} + /** * snd_hda_mixer_amp_volume_put - TLV callback for a standard AMP mixer volume * @kcontrol: ctl element @@ -1490,30 +1514,12 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put); int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *_tlv) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = get_amp_nid(kcontrol); - int dir = get_amp_direction(kcontrol); - unsigned int ofs = get_amp_offset(kcontrol); - bool min_mute = get_amp_min_mute(kcontrol); - u32 caps, val1, val2; + unsigned int tlv[4]; if (size < 4 * sizeof(unsigned int)) return -ENOMEM; - caps = query_amp_caps(codec, nid, dir); - val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; - val2 = (val2 + 1) * 25; - val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); - val1 += ofs; - val1 = ((int)val1) * ((int)val2); - if (min_mute || (caps & AC_AMPCAP_MIN_MUTE)) - val2 |= TLV_DB_SCALE_MUTE; - if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv)) - return -EFAULT; - if (put_user(2 * sizeof(unsigned int), _tlv + 1)) - return -EFAULT; - if (put_user(val1, _tlv + 2)) - return -EFAULT; - if (put_user(val2, _tlv + 3)) + get_ctl_amp_tlv(kcontrol, tlv); + if (copy_to_user(_tlv, tlv, sizeof(tlv))) return -EFAULT; return 0; } @@ -1807,13 +1813,10 @@ static int get_kctl_0dB_offset(struct hda_codec *codec, const int *tlv = NULL; int val = -1; - if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - /* FIXME: set_fs() hack for obtaining user-space TLV data */ - mm_segment_t fs = get_fs(); - set_fs(get_ds()); - if (!kctl->tlv.c(kctl, 0, sizeof(_tlv), _tlv)) - tlv = _tlv; - set_fs(fs); + if ((kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) && + kctl->tlv.c == snd_hda_mixer_amp_tlv) { + get_ctl_amp_tlv(kctl, _tlv); + tlv = _tlv; } else if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) tlv = kctl->tlv.p; if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE) { From f0049e166bef59ed36cff5052cc99015ca0583a8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 12:34:09 +0200 Subject: [PATCH 032/418] ALSA: hda - Fix a typo in comment Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index ff9c7968b562..0593d674de95 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1502,7 +1502,7 @@ static void get_ctl_amp_tlv(struct snd_kcontrol *kcontrol, unsigned int *tlv) } /** - * snd_hda_mixer_amp_volume_put - TLV callback for a standard AMP mixer volume + * snd_hda_mixer_amp_tlv - TLV callback for a standard AMP mixer volume * @kcontrol: ctl element * @op_flag: operation flag * @size: byte size of input TLV From 88c125b6330f8648ca5e7b216d95c4560ac9a604 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 12:35:03 +0200 Subject: [PATCH 033/418] ALSA: hda - Remove superfluous header inclusions Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0593d674de95..821aad374a06 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -19,13 +19,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include #include #include -#include #include #include #include From 3ac8226fc8483d321679ec1fec6f471e30c14104 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 13:47:41 +0200 Subject: [PATCH 034/418] ALSA: opl3: Kill unused set_fs() snd_enter_user() and snd_leave_user() that call set_fs() are the dead code in opl3 driver. Let's rip them off. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/drivers/opl3/opl3_oss.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c index c1cb249acfaa..22c3e4bca220 100644 --- a/sound/drivers/opl3/opl3_oss.c +++ b/sound/drivers/opl3/opl3_oss.c @@ -27,20 +27,6 @@ static int snd_opl3_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd, static int snd_opl3_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format, const char __user *buf, int offs, int count); static int snd_opl3_reset_seq_oss(struct snd_seq_oss_arg *arg); -/* */ - -static inline mm_segment_t snd_enter_user(void) -{ - mm_segment_t fs = get_fs(); - set_fs(get_ds()); - return fs; -} - -static inline void snd_leave_user(mm_segment_t fs) -{ - set_fs(fs); -} - /* operators */ extern struct snd_midi_op opl3_ops; From d42fe63d58392f29e82e17c02f10e8cd3f45f17f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 17:11:34 +0200 Subject: [PATCH 035/418] ALSA: emu10k1: Get rid of set_fs() usage Instead of set_fs() hackery, do the straight memcpy() by passing a flag indicating the kernel space operation. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emufx.c | 127 ++++++++++++++++++++++---------------- 1 file changed, 73 insertions(+), 54 deletions(-) diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 56fc47bd6dba..dc585959ca32 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -310,21 +310,6 @@ static const u32 onoff_table[2] = { 0x00000000, 0x00000001 }; -/* - */ - -static inline mm_segment_t snd_enter_user(void) -{ - mm_segment_t fs = get_fs(); - set_fs(get_ds()); - return fs; -} - -static inline void snd_leave_user(mm_segment_t fs) -{ - set_fs(fs); -} - /* * controls */ @@ -538,7 +523,8 @@ unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc) } static int snd_emu10k1_gpr_poke(struct snd_emu10k1 *emu, - struct snd_emu10k1_fx8010_code *icode) + struct snd_emu10k1_fx8010_code *icode, + bool in_kernel) { int gpr; u32 val; @@ -546,7 +532,9 @@ static int snd_emu10k1_gpr_poke(struct snd_emu10k1 *emu, for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) { if (!test_bit(gpr, icode->gpr_valid)) continue; - if (get_user(val, &icode->gpr_map[gpr])) + if (in_kernel) + val = *(u32 *)&icode->gpr_map[gpr]; + else if (get_user(val, &icode->gpr_map[gpr])) return -EFAULT; snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, val); } @@ -569,7 +557,8 @@ static int snd_emu10k1_gpr_peek(struct snd_emu10k1 *emu, } static int snd_emu10k1_tram_poke(struct snd_emu10k1 *emu, - struct snd_emu10k1_fx8010_code *icode) + struct snd_emu10k1_fx8010_code *icode, + bool in_kernel) { int tram; u32 addr, val; @@ -577,9 +566,14 @@ static int snd_emu10k1_tram_poke(struct snd_emu10k1 *emu, for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) { if (!test_bit(tram, icode->tram_valid)) continue; - if (get_user(val, &icode->tram_data_map[tram]) || - get_user(addr, &icode->tram_addr_map[tram])) - return -EFAULT; + if (in_kernel) { + val = *(u32 *)&icode->tram_data_map[tram]; + addr = *(u32 *)&icode->tram_addr_map[tram]; + } else { + if (get_user(val, &icode->tram_data_map[tram]) || + get_user(addr, &icode->tram_addr_map[tram])) + return -EFAULT; + } snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, val); if (!emu->audigy) { snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr); @@ -615,16 +609,22 @@ static int snd_emu10k1_tram_peek(struct snd_emu10k1 *emu, } static int snd_emu10k1_code_poke(struct snd_emu10k1 *emu, - struct snd_emu10k1_fx8010_code *icode) + struct snd_emu10k1_fx8010_code *icode, + bool in_kernel) { u32 pc, lo, hi; for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) { if (!test_bit(pc / 2, icode->code_valid)) continue; - if (get_user(lo, &icode->code[pc + 0]) || - get_user(hi, &icode->code[pc + 1])) - return -EFAULT; + if (in_kernel) { + lo = *(u32 *)&icode->code[pc + 0]; + hi = *(u32 *)&icode->code[pc + 1]; + } else { + if (get_user(lo, &icode->code[pc + 0]) || + get_user(hi, &icode->code[pc + 1])) + return -EFAULT; + } snd_emu10k1_efx_write(emu, pc + 0, lo); snd_emu10k1_efx_write(emu, pc + 1, hi); } @@ -665,14 +665,16 @@ snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id) #define MAX_TLV_SIZE 256 -static unsigned int *copy_tlv(const unsigned int __user *_tlv) +static unsigned int *copy_tlv(const unsigned int __user *_tlv, bool in_kernel) { unsigned int data[2]; unsigned int *tlv; if (!_tlv) return NULL; - if (copy_from_user(data, _tlv, sizeof(data))) + if (in_kernel) + memcpy(data, (void *)_tlv, sizeof(data)); + else if (copy_from_user(data, _tlv, sizeof(data))) return NULL; if (data[1] >= MAX_TLV_SIZE) return NULL; @@ -680,7 +682,9 @@ static unsigned int *copy_tlv(const unsigned int __user *_tlv) if (!tlv) return NULL; memcpy(tlv, data, sizeof(data)); - if (copy_from_user(tlv + 2, _tlv + 2, data[1])) { + if (in_kernel) { + memcpy(tlv + 2, (void *)(_tlv + 2), data[1]); + } else if (copy_from_user(tlv + 2, _tlv + 2, data[1])) { kfree(tlv); return NULL; } @@ -690,7 +694,7 @@ static unsigned int *copy_tlv(const unsigned int __user *_tlv) static int copy_gctl(struct snd_emu10k1 *emu, struct snd_emu10k1_fx8010_control_gpr *gctl, struct snd_emu10k1_fx8010_control_gpr __user *_gctl, - int idx) + int idx, bool in_kernel) { struct snd_emu10k1_fx8010_control_old_gpr __user *octl; @@ -718,7 +722,8 @@ static int copy_gctl_to_user(struct snd_emu10k1 *emu, } static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, - struct snd_emu10k1_fx8010_code *icode) + struct snd_emu10k1_fx8010_code *icode, + bool in_kernel) { unsigned int i; struct snd_ctl_elem_id __user *_id; @@ -728,7 +733,9 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, for (i = 0, _id = icode->gpr_del_controls; i < icode->gpr_del_control_count; i++, _id++) { - if (copy_from_user(&id, _id, sizeof(id))) + if (in_kernel) + id = *(struct snd_ctl_elem_id *)_id; + else if (copy_from_user(&id, _id, sizeof(id))) return -EFAULT; if (snd_emu10k1_look_for_ctl(emu, &id) == NULL) return -ENOENT; @@ -738,7 +745,8 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, return -ENOMEM; err = 0; for (i = 0; i < icode->gpr_add_control_count; i++) { - if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) { + if (copy_gctl(emu, gctl, icode->gpr_add_controls, i, + in_kernel)) { err = -EFAULT; goto __error; } @@ -759,7 +767,8 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, } for (i = 0; i < icode->gpr_list_control_count; i++) { /* FIXME: we need to check the WRITE access */ - if (copy_gctl(emu, gctl, icode->gpr_list_controls, i)) { + if (copy_gctl(emu, gctl, icode->gpr_list_controls, i, + in_kernel)) { err = -EFAULT; goto __error; } @@ -781,7 +790,8 @@ static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl) } static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, - struct snd_emu10k1_fx8010_code *icode) + struct snd_emu10k1_fx8010_code *icode, + bool in_kernel) { unsigned int i, j; struct snd_emu10k1_fx8010_control_gpr *gctl; @@ -800,7 +810,8 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, } for (i = 0; i < icode->gpr_add_control_count; i++) { - if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) { + if (copy_gctl(emu, gctl, icode->gpr_add_controls, i, + in_kernel)) { err = -EFAULT; goto __error; } @@ -821,7 +832,7 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, knew.device = gctl->id.device; knew.subdevice = gctl->id.subdevice; knew.info = snd_emu10k1_gpr_ctl_info; - knew.tlv.p = copy_tlv(gctl->tlv); + knew.tlv.p = copy_tlv(gctl->tlv, in_kernel); if (knew.tlv.p) knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ; @@ -873,7 +884,8 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, } static int snd_emu10k1_del_controls(struct snd_emu10k1 *emu, - struct snd_emu10k1_fx8010_code *icode) + struct snd_emu10k1_fx8010_code *icode, + bool in_kernel) { unsigned int i; struct snd_ctl_elem_id id; @@ -883,7 +895,9 @@ static int snd_emu10k1_del_controls(struct snd_emu10k1 *emu, for (i = 0, _id = icode->gpr_del_controls; i < icode->gpr_del_control_count; i++, _id++) { - if (copy_from_user(&id, _id, sizeof(id))) + if (in_kernel) + id = *(struct snd_ctl_elem_id *)_id; + else if (copy_from_user(&id, _id, sizeof(id))) return -EFAULT; down_write(&card->controls_rwsem); ctl = snd_emu10k1_look_for_ctl(emu, &id); @@ -941,12 +955,14 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu, } static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu, - struct snd_emu10k1_fx8010_code *icode) + struct snd_emu10k1_fx8010_code *icode, + bool in_kernel) { int err = 0; mutex_lock(&emu->fx8010.lock); - if ((err = snd_emu10k1_verify_controls(emu, icode)) < 0) + err = snd_emu10k1_verify_controls(emu, icode, in_kernel); + if (err < 0) goto __error; strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name)); /* stop FX processor - this may be dangerous, but it's better to miss @@ -956,11 +972,20 @@ static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu, else snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP); /* ok, do the main job */ - if ((err = snd_emu10k1_del_controls(emu, icode)) < 0 || - (err = snd_emu10k1_gpr_poke(emu, icode)) < 0 || - (err = snd_emu10k1_tram_poke(emu, icode)) < 0 || - (err = snd_emu10k1_code_poke(emu, icode)) < 0 || - (err = snd_emu10k1_add_controls(emu, icode)) < 0) + err = snd_emu10k1_del_controls(emu, icode, in_kernel); + if (err < 0) + goto __error; + err = snd_emu10k1_gpr_poke(emu, icode, in_kernel); + if (err < 0) + goto __error; + err = snd_emu10k1_tram_poke(emu, icode, in_kernel); + if (err < 0) + goto __error; + err = snd_emu10k1_code_poke(emu, icode, in_kernel); + if (err < 0) + goto __error; + err = snd_emu10k1_add_controls(emu, icode, in_kernel); + if (err < 0) goto __error; /* start FX processor when the DSP code is updated */ if (emu->audigy) @@ -1179,7 +1204,6 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) struct snd_emu10k1_fx8010_code *icode = NULL; struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl; u32 *gpr_map; - mm_segment_t seg; err = -ENOMEM; icode = kzalloc(sizeof(*icode), GFP_KERNEL); @@ -1739,13 +1763,11 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) while (ptr < 0x400) A_OP(icode, &ptr, 0x0f, 0xc0, 0xc0, 0xcf, 0xc0); - seg = snd_enter_user(); icode->gpr_add_control_count = nctl; icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls; emu->support_tlv = 1; /* support TLV */ - err = snd_emu10k1_icode_poke(emu, icode); + err = snd_emu10k1_icode_poke(emu, icode, true); emu->support_tlv = 0; /* clear again */ - snd_leave_user(seg); __err: kfree(controls); @@ -1817,7 +1839,6 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) struct snd_emu10k1_fx8010_pcm_rec *ipcm = NULL; struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl; u32 *gpr_map; - mm_segment_t seg; err = -ENOMEM; icode = kzalloc(sizeof(*icode), GFP_KERNEL); @@ -2368,13 +2389,11 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) if ((err = snd_emu10k1_fx8010_tram_setup(emu, ipcm->buffer_size)) < 0) goto __err; - seg = snd_enter_user(); icode->gpr_add_control_count = i; icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls; emu->support_tlv = 1; /* support TLV */ - err = snd_emu10k1_icode_poke(emu, icode); + err = snd_emu10k1_icode_poke(emu, icode, true); emu->support_tlv = 0; /* clear again */ - snd_leave_user(seg); if (err >= 0) err = snd_emu10k1_ipcm_poke(emu, ipcm); __err: @@ -2537,7 +2556,7 @@ static int snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw, struct file *file, un icode = memdup_user(argp, sizeof(*icode)); if (IS_ERR(icode)) return PTR_ERR(icode); - res = snd_emu10k1_icode_poke(emu, icode); + res = snd_emu10k1_icode_poke(emu, icode, false); kfree(icode); return res; case SNDRV_EMU10K1_IOCTL_CODE_PEEK: From 29b59b35480422d2a4acd843f18c3acf30c9eb59 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 16 May 2017 10:42:04 +0200 Subject: [PATCH 036/418] ALSA: Enable build with m68k By some reason in the ancient history, we disabled the build of ALSA drivers for m68k. Since we'd like to move sound/oss/dmasound stuff into ALSA for the complete drop of the legacy OSS stuff, let's try to start building with m68k. Signed-off-by: Takashi Iwai --- sound/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/Kconfig b/sound/Kconfig index 6a215a8c0490..d2fadbec8d51 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -56,7 +56,7 @@ config SOUND_OSS_CORE_PRECLAIM source "sound/oss/dmasound/Kconfig" -if !M68K && !UML +if !UML menuconfig SND tristate "Advanced Linux Sound Architecture" @@ -125,7 +125,7 @@ source "sound/oss/Kconfig" endif # SOUND_PRIME -endif # !M68K +endif # !UML endif # SOUND From 8b674308a26a774896652dafe0dac7ee297eed9b Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 17 May 2017 08:48:17 +0900 Subject: [PATCH 037/418] ALSA: pcm: add const qualifier for read-only table for sampling rate There's a read-only table for each sampling rate, while it doesn't have const qualifier and can be modified. This commit add the qualifier. As a result, a symbol for the table moves from .data section to .rodata. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 13dec5ec93f2..d5a967b57bb4 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1986,8 +1986,10 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params, #error "Change this table" #endif -static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, - 48000, 64000, 88200, 96000, 176400, 192000 }; +static const unsigned int rates[] = { + 5512, 8000, 11025, 16000, 22050, 32000, 44100, + 48000, 64000, 88200, 96000, 176400, 192000 +}; const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = { .count = ARRAY_SIZE(rates), From b55f9fdcd3f0b3da7c9d4b6c67d75a1878653221 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 17 May 2017 08:48:20 +0900 Subject: [PATCH 038/418] ALSA: pcm: use helper function to refer parameter as read-only ALSA pcm core has hw_param_interval_c() to pick up parameter with const qualifier for safe programming. This commit applies it to the cases. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_oss.c | 4 ++-- sound/core/pcm_drm_eld.c | 8 ++++---- sound/core/pcm_lib.c | 3 ++- sound/core/pcm_native.c | 3 ++- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 36baf962f9b0..2a473513bd54 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -799,7 +799,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream, static int choose_rate(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, unsigned int best_rate) { - struct snd_interval *it; + const struct snd_interval *it; struct snd_pcm_hw_params *save; unsigned int rate, prev; @@ -807,7 +807,7 @@ static int choose_rate(struct snd_pcm_substream *substream, if (save == NULL) return -ENOMEM; *save = *params; - it = hw_param_interval(save, SNDRV_PCM_HW_PARAM_RATE); + it = hw_param_interval_c(save, SNDRV_PCM_HW_PARAM_RATE); /* try multiples of the best rate */ rate = best_rate; diff --git a/sound/core/pcm_drm_eld.c b/sound/core/pcm_drm_eld.c index e70379fb63d0..9881d087756f 100644 --- a/sound/core/pcm_drm_eld.c +++ b/sound/core/pcm_drm_eld.c @@ -29,13 +29,13 @@ static int eld_limit_rates(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_interval *r = hw_param_interval(params, rule->var); - struct snd_interval *c; + const struct snd_interval *c; unsigned int rate_mask = 7, i; const u8 *sad, *eld = rule->private; sad = drm_eld_sad(eld); if (sad) { - c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + c = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3) { unsigned max_channels = sad_max_channels(sad); @@ -57,7 +57,7 @@ static int eld_limit_channels(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_interval *c = hw_param_interval(params, rule->var); - struct snd_interval *r; + const struct snd_interval *r; struct snd_interval t = { .min = 1, .max = 2, .integer = 1, }; unsigned int i; const u8 *sad, *eld = rule->private; @@ -67,7 +67,7 @@ static int eld_limit_channels(struct snd_pcm_hw_params *params, unsigned int rate_mask = 0; /* Convert the rate interval to a mask */ - r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + r = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); for (i = 0; i < ARRAY_SIZE(eld_rates); i++) if (r->min <= eld_rates[i] && r->max >= eld_rates[i]) rate_mask |= BIT(i); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 5088d4b8db22..af439e5554b6 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1415,7 +1415,8 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, unsigned int l = (unsigned long) rule->private; int width = l & 0xffff; unsigned int msbits = l >> 16; - struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); + const struct snd_interval *i = + hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); if (!snd_interval_single(i)) return 0; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index d5a967b57bb4..f3a3580eb44c 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1940,7 +1940,8 @@ static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { unsigned int k; - struct snd_interval *i = hw_param_interval(params, rule->deps[0]); + const struct snd_interval *i = + hw_param_interval_c(params, rule->deps[0]); struct snd_mask m; struct snd_mask *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); snd_mask_any(&m); From e76bf3c4b4e456fa8f2c729fa1e8c644857529a8 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 17 May 2017 08:48:19 +0900 Subject: [PATCH 039/418] ALSA: pcm/oss: refer to parameters instead of copying to reduce usage of kernel stack Some functions in compatibility layer for Open Sound System interface has local variable to copy some parameters in runtime of PCM substream, while this can be replaced with reference of pointers to parameter itself. This brings an advantage to reduce usage of kernel stack. This commit applies this idea. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_oss.c | 16 ++++++++-------- sound/core/oss/pcm_plugin.c | 5 +++-- sound/core/oss/pcm_plugin.h | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 2a473513bd54..e306f05ce51d 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -848,7 +848,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, int direct; snd_pcm_format_t format, sformat; int n; - struct snd_mask sformat_mask; + const struct snd_mask *sformat_mask; struct snd_mask mask; if (trylock) { @@ -891,18 +891,18 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, format = snd_pcm_oss_format_from(runtime->oss.format); - sformat_mask = *hw_param_mask(sparams, SNDRV_PCM_HW_PARAM_FORMAT); + sformat_mask = hw_param_mask_c(sparams, SNDRV_PCM_HW_PARAM_FORMAT); if (direct) sformat = format; else - sformat = snd_pcm_plug_slave_format(format, &sformat_mask); + sformat = snd_pcm_plug_slave_format(format, sformat_mask); if ((__force int)sformat < 0 || - !snd_mask_test(&sformat_mask, (__force int)sformat)) { + !snd_mask_test(sformat_mask, (__force int)sformat)) { for (sformat = (__force snd_pcm_format_t)0; (__force int)sformat <= (__force int)SNDRV_PCM_FORMAT_LAST; sformat = (__force snd_pcm_format_t)((__force int)sformat + 1)) { - if (snd_mask_test(&sformat_mask, (__force int)sformat) && + if (snd_mask_test(sformat_mask, (__force int)sformat) && snd_pcm_oss_format_to(sformat) >= 0) break; } @@ -1780,7 +1780,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) int direct; struct snd_pcm_hw_params *params; unsigned int formats = 0; - struct snd_mask format_mask; + const struct snd_mask *format_mask; int fmt; if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) @@ -1802,12 +1802,12 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) return -ENOMEM; _snd_pcm_hw_params_any(params); err = snd_pcm_hw_refine(substream, params); - format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); kfree(params); if (err < 0) return err; for (fmt = 0; fmt < 32; ++fmt) { - if (snd_mask_test(&format_mask, fmt)) { + if (snd_mask_test(format_mask, fmt)) { int f = snd_pcm_oss_format_to(fmt); if (f >= 0) formats |= f; diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index 727ac44d39f4..cadc93792868 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -266,7 +266,8 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pc return frames; } -static int snd_pcm_plug_formats(struct snd_mask *mask, snd_pcm_format_t format) +static int snd_pcm_plug_formats(const struct snd_mask *mask, + snd_pcm_format_t format) { struct snd_mask formats = *mask; u64 linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | @@ -309,7 +310,7 @@ static snd_pcm_format_t preferred_formats[] = { }; snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, - struct snd_mask *format_mask) + const struct snd_mask *format_mask) { int i; diff --git a/sound/core/oss/pcm_plugin.h b/sound/core/oss/pcm_plugin.h index a5035c2369a6..38e2c14cb893 100644 --- a/sound/core/oss/pcm_plugin.h +++ b/sound/core/oss/pcm_plugin.h @@ -126,7 +126,7 @@ int snd_pcm_plug_format_plugins(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *slave_params); snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, - struct snd_mask *format_mask); + const struct snd_mask *format_mask); int snd_pcm_plugin_append(struct snd_pcm_plugin *plugin); From b46fe5d9607c2a14618c746a02892ead0f0f4637 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 17 May 2017 08:48:18 +0900 Subject: [PATCH 040/418] ALSA: pcm: constify function local and read-only table In a function snd_pcm_hw_params_choose(), target parameters are arranged into a table. Though each entry of this table is read-only, they don't have const qualifier. This commit adds the qualifier. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index af439e5554b6..ab4b1d1e44ee 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1734,7 +1734,7 @@ EXPORT_SYMBOL(snd_pcm_hw_param_last); int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params) { - static int vars[] = { + static const int vars[] = { SNDRV_PCM_HW_PARAM_ACCESS, SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT, @@ -1745,7 +1745,8 @@ int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, SNDRV_PCM_HW_PARAM_TICK_TIME, -1 }; - int err, *v; + const int *v; + int err; for (v = vars; *v != -1; v++) { if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE) From b98ae9ad559fea64dee5fcc8e3ba4bf936ceb5e6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 15 May 2017 10:33:59 +0200 Subject: [PATCH 041/418] ASoC: rt5665: Fix uninitialized warning in rt5665_i2s_pin_event() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With gcc 4.1.2: sound/soc/codecs/rt5665.c: In function ‘rt5665_i2s_pin_event’: sound/soc/codecs/rt5665.c:2610: warning: ‘mask1’ may be used uninitialized in this function sound/soc/codecs/rt5665.c:2610: warning: ‘val2’ may be used uninitialized in this function sound/soc/codecs/rt5665.c:2610: warning: ‘val1’ may be used uninitialized in this function The first one is currently a false positive, as rt5665_i2s_pin_event() is never called with snd_soc_dapm_widget.shift set to a value not handled by the switch() statement. But that may change, so preinitialize mask1 to fix this, like is already done for mask2. The last two are false-positives, the compiler is just not smart enough to notice the mask and val variables are always used together. Fixes: 9b5d3865b3b410d2 ("ASoC: rt5665: set i2s pin share configuration") Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 26bf157ca293..c0f36d85ee4d 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -2607,7 +2607,7 @@ static int rt5665_i2s_pin_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - unsigned int val1, val2, mask1, mask2 = 0; + unsigned int val1, val2, mask1 = 0, mask2 = 0; switch (w->shift) { case RT5665_PWR_I2S2_1_BIT: @@ -2635,13 +2635,17 @@ static int rt5665_i2s_pin_event(struct snd_soc_dapm_widget *w, } switch (event) { case SND_SOC_DAPM_PRE_PMU: - snd_soc_update_bits(codec, RT5665_GPIO_CTRL_1, mask1, val1); + if (mask1) + snd_soc_update_bits(codec, RT5665_GPIO_CTRL_1, + mask1, val1); if (mask2) snd_soc_update_bits(codec, RT5665_GPIO_CTRL_2, mask2, val2); break; case SND_SOC_DAPM_POST_PMD: - snd_soc_update_bits(codec, RT5665_GPIO_CTRL_1, mask1, 0); + if (mask1) + snd_soc_update_bits(codec, RT5665_GPIO_CTRL_1, + mask1, 0); if (mask2) snd_soc_update_bits(codec, RT5665_GPIO_CTRL_2, mask2, 0); From 00bab23f72100a5fd8a3030f81d0af07a859ed17 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Apr 2017 01:31:16 +0000 Subject: [PATCH 042/418] of-graph: export symbol of_phandle_iterator_init/next of_for_each_phandle() uses of_phandle_iterator_init/next but it isn't exported. So kernel module complile will say ERROR: "of_phandle_iterator_init" [xxx.ko] undefined! ERROR: "of_phandle_iterator_next" [xxx.ko] undefined! This patch solved this issue Signed-off-by: Kuninori Morimoto Acked-by: Rob Herring Signed-off-by: Mark Brown --- drivers/of/base.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/of/base.c b/drivers/of/base.c index 28d5f53bc631..5db6aa1688e9 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1601,6 +1601,7 @@ int of_phandle_iterator_init(struct of_phandle_iterator *it, return 0; } +EXPORT_SYMBOL_GPL(of_phandle_iterator_init); int of_phandle_iterator_next(struct of_phandle_iterator *it) { @@ -1670,6 +1671,7 @@ err: return -EINVAL; } +EXPORT_SYMBOL_GPL(of_phandle_iterator_next); int of_phandle_iterator_args(struct of_phandle_iterator *it, uint32_t *args, From 4c9c3d595f1bad021cc126d20879df4016801736 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Apr 2017 01:31:42 +0000 Subject: [PATCH 043/418] of_graph: add of_graph_get_remote_endpoint() It should use same method to get same result. To getting remote-endpoint node, let's use of_graph_get_remote_endpoint() Signed-off-by: Kuninori Morimoto Acked-by: Rob Herring Signed-off-by: Mark Brown --- drivers/of/base.c | 18 ++++++++++++++++-- include/linux/of_graph.h | 8 ++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index 5db6aa1688e9..b169508a9b56 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2486,6 +2486,20 @@ struct device_node *of_graph_get_endpoint_by_regs( } EXPORT_SYMBOL(of_graph_get_endpoint_by_regs); +/** + * of_graph_get_remote_endpoint() - get remote endpoint node + * @node: pointer to a local endpoint device_node + * + * Return: Remote endpoint node associated with remote endpoint node linked + * to @node. Use of_node_put() on it when done. + */ +struct device_node *of_graph_get_remote_endpoint(const struct device_node *node) +{ + /* Get remote endpoint node. */ + return of_parse_phandle(node, "remote-endpoint", 0); +} +EXPORT_SYMBOL(of_graph_get_remote_endpoint); + /** * of_graph_get_remote_port_parent() - get remote port's parent node * @node: pointer to a local endpoint device_node @@ -2500,7 +2514,7 @@ struct device_node *of_graph_get_remote_port_parent( unsigned int depth; /* Get remote endpoint node. */ - np = of_parse_phandle(node, "remote-endpoint", 0); + np = of_graph_get_remote_endpoint(node); /* Walk 3 levels up only if there is 'ports' node. */ for (depth = 3; depth && np; depth--) { @@ -2524,7 +2538,7 @@ struct device_node *of_graph_get_remote_port(const struct device_node *node) struct device_node *np; /* Get remote endpoint node. */ - np = of_parse_phandle(node, "remote-endpoint", 0); + np = of_graph_get_remote_endpoint(node); if (!np) return NULL; return of_get_next_parent(np); diff --git a/include/linux/of_graph.h b/include/linux/of_graph.h index abdb02eaef06..0c9473a169dd 100644 --- a/include/linux/of_graph.h +++ b/include/linux/of_graph.h @@ -48,6 +48,8 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, struct device_node *previous); struct device_node *of_graph_get_endpoint_by_regs( const struct device_node *parent, int port_reg, int reg); +struct device_node *of_graph_get_remote_endpoint( + const struct device_node *node); struct device_node *of_graph_get_remote_port_parent( const struct device_node *node); struct device_node *of_graph_get_remote_port(const struct device_node *node); @@ -80,6 +82,12 @@ static inline struct device_node *of_graph_get_endpoint_by_regs( return NULL; } +static inline struct device_node *of_graph_get_remote_endpoint( + const struct device_node *node) +{ + return NULL; +} + static inline struct device_node *of_graph_get_remote_port_parent( const struct device_node *node) { From 0ef472a973ebbfc20f2f12769e77a8cfd3612778 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Apr 2017 01:32:17 +0000 Subject: [PATCH 044/418] of_graph: add of_graph_get_port_parent() Linux kernel already has of_graph_get_remote_port_parent(), but, sometimes we want to get own port parent. This patch adds of_graph_get_port_parent() Signed-off-by: Kuninori Morimoto Acked-by: Rob Herring Signed-off-by: Mark Brown --- drivers/of/base.c | 30 ++++++++++++++++++++++-------- include/linux/of_graph.h | 7 +++++++ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index b169508a9b56..4c305599a664 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2500,6 +2500,27 @@ struct device_node *of_graph_get_remote_endpoint(const struct device_node *node) } EXPORT_SYMBOL(of_graph_get_remote_endpoint); +/** + * of_graph_get_port_parent() - get port's parent node + * @node: pointer to a local endpoint device_node + * + * Return: device node associated with endpoint node linked + * to @node. Use of_node_put() on it when done. + */ +struct device_node *of_graph_get_port_parent(struct device_node *node) +{ + unsigned int depth; + + /* Walk 3 levels up only if there is 'ports' node. */ + for (depth = 3; depth && node; depth--) { + node = of_get_next_parent(node); + if (depth == 2 && of_node_cmp(node->name, "ports")) + break; + } + return node; +} +EXPORT_SYMBOL(of_graph_get_port_parent); + /** * of_graph_get_remote_port_parent() - get remote port's parent node * @node: pointer to a local endpoint device_node @@ -2511,18 +2532,11 @@ struct device_node *of_graph_get_remote_port_parent( const struct device_node *node) { struct device_node *np; - unsigned int depth; /* Get remote endpoint node. */ np = of_graph_get_remote_endpoint(node); - /* Walk 3 levels up only if there is 'ports' node. */ - for (depth = 3; depth && np; depth--) { - np = of_get_next_parent(np); - if (depth == 2 && of_node_cmp(np->name, "ports")) - break; - } - return np; + return of_graph_get_port_parent(np); } EXPORT_SYMBOL(of_graph_get_remote_port_parent); diff --git a/include/linux/of_graph.h b/include/linux/of_graph.h index 0c9473a169dd..9db632d16cbc 100644 --- a/include/linux/of_graph.h +++ b/include/linux/of_graph.h @@ -50,6 +50,7 @@ struct device_node *of_graph_get_endpoint_by_regs( const struct device_node *parent, int port_reg, int reg); struct device_node *of_graph_get_remote_endpoint( const struct device_node *node); +struct device_node *of_graph_get_port_parent(struct device_node *node); struct device_node *of_graph_get_remote_port_parent( const struct device_node *node); struct device_node *of_graph_get_remote_port(const struct device_node *node); @@ -88,6 +89,12 @@ static inline struct device_node *of_graph_get_remote_endpoint( return NULL; } +static inline struct device_node *of_graph_get_port_parent( + struct device_node *node) +{ + return NULL; +} + static inline struct device_node *of_graph_get_remote_port_parent( const struct device_node *node) { From ac1e6958d3be29a28889b09e4eec1798eccc1606 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Apr 2017 01:32:47 +0000 Subject: [PATCH 045/418] of_graph: add of_graph_get_endpoint_count() OF graph want to count its endpoint number, same as of_get_child_count(). This patch adds of_graph_get_endpoint_count() Signed-off-by: Kuninori Morimoto Acked-by: Rob Herring Signed-off-by: Mark Brown --- drivers/of/base.c | 12 ++++++++++++ include/linux/of_graph.h | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/drivers/of/base.c b/drivers/of/base.c index 4c305599a664..cb1c49ae3b88 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2559,6 +2559,18 @@ struct device_node *of_graph_get_remote_port(const struct device_node *node) } EXPORT_SYMBOL(of_graph_get_remote_port); +int of_graph_get_endpoint_count(const struct device_node *np) +{ + struct device_node *endpoint; + int num = 0; + + for_each_endpoint_of_node(np, endpoint) + num++; + + return num; +} +EXPORT_SYMBOL(of_graph_get_endpoint_count); + /** * of_graph_get_remote_node() - get remote parent device_node for given port/endpoint * @node: pointer to parent device_node containing graph port/endpoint diff --git a/include/linux/of_graph.h b/include/linux/of_graph.h index 9db632d16cbc..3e058f05ab04 100644 --- a/include/linux/of_graph.h +++ b/include/linux/of_graph.h @@ -43,6 +43,7 @@ struct of_endpoint { #ifdef CONFIG_OF int of_graph_parse_endpoint(const struct device_node *node, struct of_endpoint *endpoint); +int of_graph_get_endpoint_count(const struct device_node *np); struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id); struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, struct device_node *previous); @@ -64,6 +65,11 @@ static inline int of_graph_parse_endpoint(const struct device_node *node, return -ENOSYS; } +static inline int of_graph_get_endpoint_count(const struct device_node *np) +{ + return 0; +} + static inline struct device_node *of_graph_get_port_by_id( struct device_node *node, u32 id) { From 5711c97920377827da4bbc18233ffb08c6e3bbef Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Apr 2017 01:33:24 +0000 Subject: [PATCH 046/418] ASoC: soc-core: enable "dai-format" on snd_soc_of_parse_daifmt() Current snd_soc_of_parse_daifmt() detects [prefix]format, but "format" was unclear in some case. This patch checks "dai-format" first, and try to check "[prefix]format" if "dai-format" was not exist. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index aae099c0e502..ab7a07f86ab8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3960,11 +3960,15 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, prefix = ""; /* - * check "[prefix]format = xxx" + * check "dai-format = xxx" + * or "[prefix]format = xxx" * SND_SOC_DAIFMT_FORMAT_MASK area */ - snprintf(prop, sizeof(prop), "%sformat", prefix); - ret = of_property_read_string(np, prop, &str); + ret = of_property_read_string(np, "dai-format", &str); + if (ret < 0) { + snprintf(prop, sizeof(prop), "%sformat", prefix); + ret = of_property_read_string(np, prop, &str); + } if (ret == 0) { for (i = 0; i < ARRAY_SIZE(of_fmt_table); i++) { if (strcmp(str, of_fmt_table[i].name) == 0) { From dedfaa1eedc7309252989a7defab4d565a9f481b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Apr 2017 01:34:49 +0000 Subject: [PATCH 047/418] ASoC: simple-card-utils: enable "label" on asoc_simple_card_parse_card_name Current asoc_simple_card_parse_card_name() detects [prefix]name, but in generally, we uses "label" for user visible names. This patch enables it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card-utils.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 343b291fc372..c5ab8ad2a5ce 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -81,15 +81,21 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_set_dailink_name); int asoc_simple_card_parse_card_name(struct snd_soc_card *card, char *prefix) { - char prop[128]; int ret; - snprintf(prop, sizeof(prop), "%sname", prefix); + if (!prefix) + prefix = ""; /* Parse the card name from DT */ - ret = snd_soc_of_parse_card_name(card, prop); - if (ret < 0) - return ret; + ret = snd_soc_of_parse_card_name(card, "label"); + if (ret < 0) { + char prop[128]; + + snprintf(prop, sizeof(prop), "%sname", prefix); + ret = snd_soc_of_parse_card_name(card, prop); + if (ret < 0) + return ret; + } if (!card->name && card->dai_link) card->name = card->dai_link->name; From 1689333f8311f5952ee69d64adf242028dc7e6c6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Apr 2017 01:35:18 +0000 Subject: [PATCH 048/418] ASoC: simple-card-utils: add asoc_simple_card_parse_graph_dai() simple-card already has asoc_simple_card_parse_dai(), but graph base parsing needs graph specific version of it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 10 +++++ sound/soc/generic/simple-card-utils.c | 57 +++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index af58d2362975..efab584af11b 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -60,6 +60,16 @@ int asoc_simple_card_parse_dai(struct device_node *node, const char *cells_name, int *is_single_links); +#define asoc_simple_card_parse_graph_cpu(ep, dai_link) \ + asoc_simple_card_parse_graph_dai(ep, &dai_link->cpu_of_node, \ + &dai_link->cpu_dai_name) +#define asoc_simple_card_parse_graph_codec(ep, dai_link) \ + asoc_simple_card_parse_graph_dai(ep, &dai_link->codec_of_node, \ + &dai_link->codec_dai_name) +int asoc_simple_card_parse_graph_dai(struct device_node *ep, + struct device_node **endpoint_np, + const char **dai_name); + int asoc_simple_card_init_dai(struct snd_soc_dai *dai, struct asoc_simple_dai *simple_dai); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index c5ab8ad2a5ce..5a3d51e45938 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -10,6 +10,7 @@ #include #include #include +#include #include int asoc_simple_card_parse_daifmt(struct device *dev, @@ -171,6 +172,62 @@ int asoc_simple_card_parse_dai(struct device_node *node, } EXPORT_SYMBOL_GPL(asoc_simple_card_parse_dai); +static int asoc_simple_card_get_dai_id(struct device_node *ep) +{ + struct device_node *node; + struct device_node *endpoint; + int i, id; + + node = of_graph_get_port_parent(ep); + + i = 0; + id = -1; + for_each_endpoint_of_node(node, endpoint) { + if (endpoint == ep) + id = i; + i++; + } + if (id < 0) + return -ENODEV; + + return id; +} + +int asoc_simple_card_parse_graph_dai(struct device_node *ep, + struct device_node **dai_of_node, + const char **dai_name) +{ + struct device_node *node; + struct of_phandle_args args; + int ret; + + if (!ep) + return 0; + if (!dai_name) + return 0; + + /* + * of_graph_get_port_parent() will call + * of_node_put(). So, call of_node_get() here + */ + of_node_get(ep); + node = of_graph_get_port_parent(ep); + + /* Get dai->name */ + args.np = node; + args.args[0] = asoc_simple_card_get_dai_id(ep); + args.args_count = (of_graph_get_endpoint_count(node) > 1); + + ret = snd_soc_get_dai_name(&args, dai_name); + if (ret < 0) + return ret; + + *dai_of_node = node; + + return 0; +} +EXPORT_SYMBOL_GPL(asoc_simple_card_parse_graph_dai); + int asoc_simple_card_init_dai(struct snd_soc_dai *dai, struct asoc_simple_dai *simple_dai) { From 2d4e31de5bb2b5fbdbcd8a3bfec0eae0bd4ca409 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Apr 2017 01:35:41 +0000 Subject: [PATCH 049/418] ASoC: add audio-graph-card document "Audio Graph Card" = "Simple Card" + "OF-graph" Signed-off-by: Kuninori Morimoto Reviewed-by: Rob Herring Signed-off-by: Mark Brown --- .../bindings/sound/audio-graph-card.txt | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/audio-graph-card.txt diff --git a/Documentation/devicetree/bindings/sound/audio-graph-card.txt b/Documentation/devicetree/bindings/sound/audio-graph-card.txt new file mode 100644 index 000000000000..bac4b1b1060f --- /dev/null +++ b/Documentation/devicetree/bindings/sound/audio-graph-card.txt @@ -0,0 +1,124 @@ +Audio Graph Card: + +Audio Graph Card specifies audio DAI connections of SoC <-> codec. +It is based on common bindings for device graphs. +see ${LINUX}/Documentation/devicetree/bindings/graph.txt + +Basically, Audio Graph Card property is same as Simple Card. +see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt + +Below are same as Simple-Card. + +- label +- dai-format +- frame-master +- bitclock-master +- bitclock-inversion +- frame-inversion +- dai-tdm-slot-num +- dai-tdm-slot-width +- clocks / system-clock-frequency + +Required properties: + +- compatible : "audio-graph-card"; +- dais : list of CPU DAI port{s} + +Example: Single DAI case + + sound_card { + compatible = "audio-graph-card"; + + dais = <&cpu_port>; + }; + + dai-controller { + ... + cpu_port: port { + cpu_endpoint: endpoint { + remote-endpoint = <&codec_endpoint>; + + dai-format = "left_j"; + ... + }; + }; + }; + + audio-codec { + ... + port { + codec_endpoint: endpoint { + remote-endpoint = <&cpu_endpoint>; + }; + }; + }; + +Example: Multi DAI case + + sound-card { + compatible = "audio-graph-card"; + + label = "sound-card"; + + dais = <&cpu_port0 + &cpu_port1 + &cpu_port2>; + }; + + audio-codec@0 { + ... + port { + codec0_endpoint: endpoint { + remote-endpoint = <&cpu_endpoint0>; + }; + }; + }; + + audio-codec@1 { + ... + port { + codec1_endpoint: endpoint { + remote-endpoint = <&cpu_endpoint1>; + }; + }; + }; + + audio-codec@2 { + ... + port { + codec2_endpoint: endpoint { + remote-endpoint = <&cpu_endpoint2>; + }; + }; + }; + + dai-controller { + ... + ports { + cpu_port0: port@0 { + cpu_endpoint0: endpoint { + remote-endpoint = <&codec0_endpoint>; + + dai-format = "left_j"; + ... + }; + }; + cpu_port1: port@1 { + cpu_endpoint1: endpoint { + remote-endpoint = <&codec1_endpoint>; + + dai-format = "i2s"; + ... + }; + }; + cpu_port2: port@2 { + cpu_endpoint2: endpoint { + remote-endpoint = <&codec2_endpoint>; + + dai-format = "i2s"; + ... + }; + }; + }; + }; + From 2692c1c63c29cad3bec090c3e6ed9e692ca66683 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Apr 2017 01:36:08 +0000 Subject: [PATCH 050/418] ASoC: add audio-graph-card support OF-graph base DT binding are used on V4L2, and ALSA SoC is using different style of DT today. Now ALSA SoC supports simple-card driver for generic/simple sound card. In the future, V4L2 / ALSA will support HDMI, and then, DT bindings between V4L2 / ALSA should be merged. This patch adds new Audio Graph Card which is OF-graph base of simple-card Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/Kconfig | 8 + sound/soc/generic/Makefile | 2 + sound/soc/generic/audio-graph-card.c | 308 +++++++++++++++++++++++++++ 3 files changed, 318 insertions(+) create mode 100644 sound/soc/generic/audio-graph-card.c diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig index d023959b8cd6..121a48e8bb7d 100644 --- a/sound/soc/generic/Kconfig +++ b/sound/soc/generic/Kconfig @@ -14,3 +14,11 @@ config SND_SIMPLE_SCU_CARD help This option enables generic simple SCU sound card support. It supports DPCM of multi CPU single Codec system. + +config SND_AUDIO_GRAPH_CARD + tristate "ASoC Audio Graph sound card support" + depends on OF + select SND_SIMPLE_CARD_UTILS + help + This option enables generic simple simple sound card support + with OF-graph DT bindings. diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile index ee750f3023ba..670068f257b9 100644 --- a/sound/soc/generic/Makefile +++ b/sound/soc/generic/Makefile @@ -1,7 +1,9 @@ snd-soc-simple-card-utils-objs := simple-card-utils.o snd-soc-simple-card-objs := simple-card.o snd-soc-simple-scu-card-objs := simple-scu-card.o +snd-soc-audio-graph-card-objs := audio-graph-card.o obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-card.o +obj-$(CONFIG_SND_AUDIO_GRAPH_CARD) += snd-soc-audio-graph-card.o diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c new file mode 100644 index 000000000000..07e010d38596 --- /dev/null +++ b/sound/soc/generic/audio-graph-card.c @@ -0,0 +1,308 @@ +/* + * ASoC audio graph sound card support + * + * Copyright (C) 2016 Renesas Solutions Corp. + * Kuninori Morimoto + * + * based on ${LINUX}/sound/soc/generic/simple-card.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct graph_card_data { + struct snd_soc_card snd_card; + struct graph_dai_props { + struct asoc_simple_dai cpu_dai; + struct asoc_simple_dai codec_dai; + } *dai_props; + struct snd_soc_dai_link *dai_link; +}; + +#define graph_priv_to_card(priv) (&(priv)->snd_card) +#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i)) +#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev) +#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i)) + +static int asoc_graph_card_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); + int ret; + + ret = clk_prepare_enable(dai_props->cpu_dai.clk); + if (ret) + return ret; + + ret = clk_prepare_enable(dai_props->codec_dai.clk); + if (ret) + clk_disable_unprepare(dai_props->cpu_dai.clk); + + return ret; +} + +static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); + + clk_disable_unprepare(dai_props->cpu_dai.clk); + + clk_disable_unprepare(dai_props->codec_dai.clk); +} + +static struct snd_soc_ops asoc_graph_card_ops = { + .startup = asoc_graph_card_startup, + .shutdown = asoc_graph_card_shutdown, +}; + +static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) +{ + struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *codec = rtd->codec_dai; + struct snd_soc_dai *cpu = rtd->cpu_dai; + struct graph_dai_props *dai_props = + graph_priv_to_props(priv, rtd->num); + int ret; + + ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai); + if (ret < 0) + return ret; + + ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai); + if (ret < 0) + return ret; + + return 0; +} + +static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, + struct graph_card_data *priv, + int idx) +{ + struct device *dev = graph_priv_to_dev(priv); + struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx); + struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai; + struct asoc_simple_dai *codec_dai = &dai_props->codec_dai; + struct snd_soc_card *card = graph_priv_to_card(priv); + struct device_node *cpu_ep = of_get_next_child(cpu_port, NULL); + struct device_node *codec_ep = of_graph_get_remote_endpoint(cpu_ep); + struct device_node *rcpu_ep = of_graph_get_remote_endpoint(codec_ep); + int ret; + + if (rcpu_ep != cpu_ep) { + dev_err(dev, "remote-endpoint missmatch (%s/%s/%s)\n", + cpu_ep->name, codec_ep->name, rcpu_ep->name); + ret = -EINVAL; + goto dai_link_of_err; + } + + ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep, + NULL, &dai_link->dai_fmt); + if (ret < 0) + goto dai_link_of_err; + + /* + * we need to consider "mclk-fs" around here + * see simple-card + */ + + ret = asoc_simple_card_parse_graph_cpu(cpu_ep, dai_link); + if (ret < 0) + goto dai_link_of_err; + + ret = asoc_simple_card_parse_graph_codec(codec_ep, dai_link); + if (ret < 0) + goto dai_link_of_err; + + ret = snd_soc_of_parse_tdm_slot(cpu_ep, + &cpu_dai->tx_slot_mask, + &cpu_dai->rx_slot_mask, + &cpu_dai->slots, + &cpu_dai->slot_width); + if (ret < 0) + goto dai_link_of_err; + + ret = snd_soc_of_parse_tdm_slot(codec_ep, + &codec_dai->tx_slot_mask, + &codec_dai->rx_slot_mask, + &codec_dai->slots, + &codec_dai->slot_width); + if (ret < 0) + goto dai_link_of_err; + + ret = asoc_simple_card_parse_clk_cpu(dev, cpu_ep, dai_link, cpu_dai); + if (ret < 0) + goto dai_link_of_err; + + ret = asoc_simple_card_parse_clk_codec(dev, codec_ep, dai_link, codec_dai); + if (ret < 0) + goto dai_link_of_err; + + ret = asoc_simple_card_canonicalize_dailink(dai_link); + if (ret < 0) + goto dai_link_of_err; + + ret = asoc_simple_card_set_dailink_name(dev, dai_link, + "%s-%s", + dai_link->cpu_dai_name, + dai_link->codec_dai_name); + if (ret < 0) + goto dai_link_of_err; + + dai_link->ops = &asoc_graph_card_ops; + dai_link->init = asoc_graph_card_dai_init; + + dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); + dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt); + dev_dbg(dev, "\tcpu : %s / %d\n", + dai_link->cpu_dai_name, + cpu_dai->sysclk); + dev_dbg(dev, "\tcodec : %s / %d\n", + dai_link->codec_dai_name, + codec_dai->sysclk); + + asoc_simple_card_canonicalize_cpu(dai_link, + card->num_links == 1); + +dai_link_of_err: + of_node_put(cpu_ep); + of_node_put(rcpu_ep); + of_node_put(codec_ep); + + return ret; +} + +static int asoc_graph_card_parse_of(struct graph_card_data *priv) +{ + struct of_phandle_iterator it; + struct device *dev = graph_priv_to_dev(priv); + struct snd_soc_card *card = graph_priv_to_card(priv); + struct device_node *node = dev->of_node; + int rc, idx = 0; + int ret; + + /* + * we need to consider "widgets", "routing", "mclk-fs" around here + * see simple-card + */ + + of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { + ret = asoc_graph_card_dai_link_of(it.node, priv, idx++); + of_node_put(it.node); + if (ret < 0) + return ret; + } + + return asoc_simple_card_parse_card_name(card, NULL); +} + +static int asoc_graph_get_dais_count(struct device *dev) +{ + struct of_phandle_iterator it; + struct device_node *node = dev->of_node; + int count = 0; + int rc; + + of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { + count++; + of_node_put(it.node); + } + + return count; +} + +static int asoc_graph_card_probe(struct platform_device *pdev) +{ + struct graph_card_data *priv; + struct snd_soc_dai_link *dai_link; + struct graph_dai_props *dai_props; + struct device *dev = &pdev->dev; + struct snd_soc_card *card; + int num, ret; + + /* Allocate the private data and the DAI link array */ + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + num = asoc_graph_get_dais_count(dev); + if (num == 0) + return -EINVAL; + + dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL); + dai_link = devm_kzalloc(dev, sizeof(*dai_link) * num, GFP_KERNEL); + if (!dai_props || !dai_link) + return -ENOMEM; + + priv->dai_props = dai_props; + priv->dai_link = dai_link; + + /* Init snd_soc_card */ + card = graph_priv_to_card(priv); + card->owner = THIS_MODULE; + card->dev = dev; + card->dai_link = dai_link; + card->num_links = num; + + ret = asoc_graph_card_parse_of(priv); + if (ret < 0) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "parse error %d\n", ret); + goto err; + } + + snd_soc_card_set_drvdata(card, priv); + + ret = devm_snd_soc_register_card(dev, card); + if (ret >= 0) + return ret; +err: + asoc_simple_card_clean_reference(card); + + return ret; +} + +static int asoc_graph_card_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + return asoc_simple_card_clean_reference(card); +} + +static const struct of_device_id asoc_graph_of_match[] = { + { .compatible = "audio-graph-card", }, + {}, +}; +MODULE_DEVICE_TABLE(of, asoc_graph_of_match); + +static struct platform_driver asoc_graph_card = { + .driver = { + .name = "asoc-audio-graph-card", + .of_match_table = asoc_graph_of_match, + }, + .probe = asoc_graph_card_probe, + .remove = asoc_graph_card_remove, +}; +module_platform_driver(asoc_graph_card); + +MODULE_ALIAS("platform:asoc-audio-graph-card"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ASoC Audio Graph Sound Card"); +MODULE_AUTHOR("Kuninori Morimoto "); From 0378bb966765e06fdb0e00d592a6fcfbb71afa3c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 26 Apr 2017 02:26:30 +0000 Subject: [PATCH 051/418] ASoC: rsnd: move "renesas,rsrc-card" to "simple-scu-audio-card" on Document "renesas,rsrc-card" is exchanged to "simple-scu-card". Let's update Document Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../bindings/sound/renesas,rsnd.txt | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 15a7316e4c91..3332910a9a11 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -83,11 +83,11 @@ SRC can convert [xx]Hz to [yy]Hz. Then, it has below 2 modes ** Asynchronous mode ------------------ -You need to use "renesas,rsrc-card" sound card for it. +You need to use "simple-scu-audio-card" sound card for it. example) sound { - compatible = "renesas,rsrc-card"; + compatible = "simple-scu-audio-card"; ... /* * SRC Asynchronous mode setting @@ -97,12 +97,12 @@ example) * Inputed 48kHz data will be converted to * system specified Hz */ - convert-rate = <48000>; + simple-audio-card,convert-rate = <48000>; ... - cpu { + simple-audio-card,cpu { sound-dai = <&rcar_sound>; }; - codec { + simple-audio-card,codec { ... }; }; @@ -141,23 +141,23 @@ For more detail information, see below ${LINUX}/sound/soc/sh/rcar/ctu.c - comment of header -You need to use "renesas,rsrc-card" sound card for it. +You need to use "simple-scu-audio-card" sound card for it. example) sound { - compatible = "renesas,rsrc-card"; + compatible = "simple-scu-audio-card"; ... /* * CTU setting * All input data will be converted to 2ch * as output data */ - convert-channels = <2>; + simple-audio-card,convert-channels = <2>; ... - cpu { + simple-audio-card,cpu { sound-dai = <&rcar_sound>; }; - codec { + simple-audio-card,codec { ... }; }; @@ -190,22 +190,22 @@ and these sounds will be merged by MIX. aplay -D plughw:0,0 xxxx.wav & aplay -D plughw:0,1 yyyy.wav -You need to use "renesas,rsrc-card" sound card for it. +You need to use "simple-scu-audio-card" sound card for it. Ex) [MEM] -> [SRC1] -> [CTU02] -+-> [MIX0] -> [DVC0] -> [SSI0] | [MEM] -> [SRC2] -> [CTU03] -+ sound { - compatible = "renesas,rsrc-card"; + compatible = "simple-scu-audio-card"; ... - cpu@0 { + simple-audio-card,cpu@0 { sound-dai = <&rcar_sound 0>; }; - cpu@1 { + simple-audio-card,cpu@1 { sound-dai = <&rcar_sound 1>; }; - codec { + simple-audio-card,codec { ... }; }; From 5b3889f80a79d9b73f73e19ba9a001c2d47ab47f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 26 Apr 2017 02:26:48 +0000 Subject: [PATCH 052/418] ASoC: rsnd: add missing clocks/clock-names on Document Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/renesas,rsnd.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 3332910a9a11..13cb21d53b8b 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -368,6 +368,10 @@ Required properties: see below for detail. - #sound-dai-cells : it must be 0 if your system is using single DAI it must be 1 if your system is using multi DAI +- clocks : References to SSI/SRC/MIX/CTU/DVC/AUDIO_CLK clocks. +- clock-names : List of necessary clock names. + "ssi-all", "ssi.X", "src.X", "mix.X", "ctu.X", + "dvc.X", "clk_a", "clk_b", "clk_c", "clk_i" Optional properties: - #clock-cells : it must be 0 if your system has audio_clkout From 0c343a35bfecdf26c7041781815f3b639a45d93a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 14 May 2017 17:53:21 +0100 Subject: [PATCH 053/418] ASoC: hdmi-codec: fix spelling mistake: "deteced" -> "detected" Trivial fix to spelling mistake in dev_err message Signed-off-by: Colin Ian King Acked-by: Kuninori Morimoto 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 8c5ae1fc23a9..a3f15149afcf 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -819,7 +819,7 @@ static int hdmi_codec_probe(struct platform_device *pdev) mutex_unlock(&hdmi_mutex); if (hd->cnt >= ARRAY_SIZE(hdmi_dai_name)) { - dev_err(dev, "too many hdmi codec are deteced\n"); + dev_err(dev, "too many hdmi codec are detected\n"); return -EINVAL; } From a9b10dddd6d86e6004a9f310c68888229f75e041 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 May 2017 01:57:27 +0000 Subject: [PATCH 054/418] ASoC: rsnd: remove un-used OUF_SRCO/I macro Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 20b5b2ec625e..a8ab26d70a8b 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -12,10 +12,6 @@ #define SRC_NAME "src" -/* SRCx_STATUS */ -#define OUF_SRCO ((1 << 12) | (1 << 13)) -#define OUF_SRCI ((1 << 9) | (1 << 8)) - /* SCU_SYSTEM_STATUS0/1 */ #define OUF_SRC(id) ((1 << (id + 16)) | (1 << id)) From 607ee05828dadfb1e65ea8d0db3c0728c6fab0df Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 May 2017 01:57:52 +0000 Subject: [PATCH 055/418] ASoC: rsnd: remove mismatch explain comment from src.c Before, src.c cares SRC and SSIU, but now SSIU is cared by ssiu.c by commit c7f69ab5364d ("ASoC: rsnd: use mod base common method on SSIU"). This patch removes mismatched explanation for SRC/SSIU from src.c Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index a8ab26d70a8b..e4bde0c8d93a 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -51,20 +51,6 @@ struct rsnd_src { * */ -/* - * src.c is caring... - * - * Gen1 - * - * [mem] -> [SRU] -> [SSI] - * |--------| - * - * Gen2 - * - * [mem] -> [SRC] -> [SSIU] -> [SSI] - * |-----------------| - */ - static void rsnd_src_activation(struct rsnd_mod *mod) { rsnd_mod_write(mod, SRC_SWRSR, 0); From 9654f5eba994c8732bfdb4c3b81bc5e18d25e970 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 May 2017 01:58:56 +0000 Subject: [PATCH 056/418] ASoC: rsnd: clkout-lr-asynchronous is AUDIO_CLKOUT related property clkout-lr-asynchronous is AUDIO_CLKOUT related property, thus, it should be handled by rsnd_adg_get_clkout(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 66203d107a11..cb4eab0e24ce 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -480,6 +480,9 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, if (req_rate[0] % 48000 == 0) adg->flags = AUDIO_OUT_48; + if (of_get_property(np, "clkout-lr-asynchronous", NULL)) + adg->flags = LRCLK_ASYNC; + /* * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC * have 44.1kHz or 48kHz base clocks for now. @@ -578,7 +581,6 @@ int rsnd_adg_probe(struct rsnd_priv *priv) { struct rsnd_adg *adg; struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *np = dev->of_node; int ret; adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL); @@ -595,9 +597,6 @@ int rsnd_adg_probe(struct rsnd_priv *priv) rsnd_adg_get_clkin(priv, adg); rsnd_adg_get_clkout(priv, adg); - if (of_get_property(np, "clkout-lr-asynchronous", NULL)) - adg->flags = LRCLK_ASYNC; - priv->adg = adg; rsnd_adg_clk_enable(priv); From 1f6bbe64abd7dc1997fa31a9e550eadf170961d5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 May 2017 01:59:22 +0000 Subject: [PATCH 057/418] ASoC: rsnd: remove error pointer for adg->clkout[i] commit d7f298197a22f11b38059f257842dac7c30a564c ("ASoC: rcar: fixup of_clk_add_provider() usage for multi clkout") added adg->clkout[i] = ERR_PTR(-ENOENT), but, adg->clkout[i] are assumed NULL or clk pointer. This patch fix it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index cb4eab0e24ce..36bece8621b7 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -556,7 +556,6 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, clk = clk_register_fixed_rate(dev, clkout_name[i], parent_clk_name, 0, req_rate[0]); - adg->clkout[i] = ERR_PTR(-ENOENT); if (!IS_ERR(clk)) adg->clkout[i] = clk; } From 2adcea7e22d382e2becf5671e92296f79672b957 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 17 May 2017 07:59:20 +0000 Subject: [PATCH 058/418] ASoC: rsnd: need to call nolock_stop if nolock_start was failed rsnd_dai_call() is counting the called number of start/stop functions. nolock_stop should be called if nolock_start was failed. Otherwise, nolock_start doesn't called in 2nd play. This patch solved this issue. Signed-off-by: Kuninori Morimoto Reported-by: Hiroyuki Yokoyama Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 1744015408c3..3c47af1990cb 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -715,11 +715,16 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, { struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + int ret; /* * call rsnd_dai_call without spinlock */ - return rsnd_dai_call(nolock_start, io, priv); + ret = rsnd_dai_call(nolock_start, io, priv); + if (ret < 0) + rsnd_dai_call(nolock_stop, io, priv); + + return ret; } static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, From 374503c6109e60f48fa9b11341b14466f07bd3f4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 17 May 2017 06:50:32 +0000 Subject: [PATCH 059/418] ASoC: rsnd: check src mod pointer for rsnd_mod_id() Without this patch, gcc 4.9.x says sound/soc/sh/rcar/cmd.c: In function 'rsnd_cmd_init': sound/soc/sh/rcar/cmd.c:85:14: warning: array subscript is below array\ bounds [-Warray-bounds] data = path[rsnd_mod_id(src)] | Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/cmd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c index 7d92a24b7cfa..98835e9d1d7d 100644 --- a/sound/soc/sh/rcar/cmd.c +++ b/sound/soc/sh/rcar/cmd.c @@ -82,6 +82,9 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, [9] = 0x2, }; + if (unlikely(!src)) + return -EIO; + data = path[rsnd_mod_id(src)] | cmd_case[rsnd_mod_id(src)] << 16; } From 18fe7869764c0b86e8ce6539bbb6e528f1d9928f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 16 May 2017 16:24:56 +0000 Subject: [PATCH 060/418] ASoC: rt5665: make local symbol rt5665_i2c_driver static Fixes the following sparse warnings: sound/soc/codecs/rt5665.c:4928:19: warning: symbol 'rt5665_i2c_driver' was not declared. Should it be static? Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index c0f36d85ee4d..7420010fd8e9 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4929,7 +4929,7 @@ static struct acpi_device_id rt5665_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt5665_acpi_match); #endif -struct i2c_driver rt5665_i2c_driver = { +static struct i2c_driver rt5665_i2c_driver = { .driver = { .name = "rt5665", .of_match_table = of_match_ptr(rt5665_of_match), From 3048e76c93bccf875a49025870de08aed86c4692 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 16 May 2017 19:20:00 +0200 Subject: [PATCH 061/418] ASoC: fsi: Move inline fsi_stream_is_play() before use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With gcc 4.1.2: sound/soc/sh/fsi.c:304: warning: ‘fsi_stream_is_play’ declared inline after being called sound/soc/sh/fsi.c:304: warning: previous declaration of ‘fsi_stream_is_play’ was here Move fsi_stream_is_play() up to fix this, removing the need for a forward declaration as well. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index ead520182e26..7c4bdd82bb95 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -301,7 +301,12 @@ struct fsi_master { spinlock_t lock; }; -static int fsi_stream_is_play(struct fsi_priv *fsi, struct fsi_stream *io); +static inline int fsi_stream_is_play(struct fsi_priv *fsi, + struct fsi_stream *io) +{ + return &fsi->playback == io; +} + /* * basic read write function @@ -489,12 +494,6 @@ static void fsi_count_fifo_err(struct fsi_priv *fsi) /* * fsi_stream_xx() function */ -static inline int fsi_stream_is_play(struct fsi_priv *fsi, - struct fsi_stream *io) -{ - return &fsi->playback == io; -} - static inline struct fsi_stream *fsi_stream_get(struct fsi_priv *fsi, struct snd_pcm_substream *substream) { From cd187753dc24e269080520aae5ee753414ba9edc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 15 May 2017 11:32:01 +0200 Subject: [PATCH 062/418] ASoC: atmel: Use IS_ENABLED() Simplify the ifdef conditions with IS_ENABLED() macro. No functional changes. Signed-off-by: Takashi Iwai Acked-by: Alexandre Belloni Acked-by: Nicolas Ferre Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-pcm.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h index 6eaf081cad50..4b27aed40a51 100644 --- a/sound/soc/atmel/atmel-pcm.h +++ b/sound/soc/atmel/atmel-pcm.h @@ -83,8 +83,7 @@ struct atmel_pcm_dma_params { #define ssc_readx(base, reg) (__raw_readl((base) + (reg))) #define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg)) -#if defined(CONFIG_SND_ATMEL_SOC_PDC) || \ - defined(CONFIG_SND_ATMEL_SOC_PDC_MODULE) +#if IS_ENABLED(CONFIG_SND_ATMEL_SOC_PDC) int atmel_pcm_pdc_platform_register(struct device *dev); void atmel_pcm_pdc_platform_unregister(struct device *dev); #else @@ -97,8 +96,7 @@ static inline void atmel_pcm_pdc_platform_unregister(struct device *dev) } #endif -#if defined(CONFIG_SND_ATMEL_SOC_DMA) || \ - defined(CONFIG_SND_ATMEL_SOC_DMA_MODULE) +#if IS_ENABLED(CONFIG_SND_ATMEL_SOC_DMA) int atmel_pcm_dma_platform_register(struct device *dev); void atmel_pcm_dma_platform_unregister(struct device *dev); #else From 6d3edf866ffa7a9348cfc30d9f58270e4f8d068e Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Mon, 15 May 2017 19:02:07 +0800 Subject: [PATCH 063/418] ASoC: rt5514: Add ACPI match ID This patch adds the ACPI match ID for rt5514 codec. Signed-off-by: Hsin-Yu Chao Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index ff97360c03db..5c30c4d64ebe 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -1095,6 +1096,14 @@ static const struct of_device_id rt5514_of_match[] = { MODULE_DEVICE_TABLE(of, rt5514_of_match); #endif +#ifdef CONFIG_ACPI +static struct acpi_device_id rt5514_acpi_match[] = { + { "10EC5514", 0}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, rt5514_acpi_match); +#endif + static int rt5514_parse_dt(struct rt5514_priv *rt5514, struct device *dev) { device_property_read_u32(dev, "realtek,dmic-init-delay-ms", @@ -1198,6 +1207,7 @@ static const struct dev_pm_ops rt5514_i2_pm_ops = { static struct i2c_driver rt5514_i2c_driver = { .driver = { .name = "rt5514", + .acpi_match_table = ACPI_PTR(rt5514_acpi_match), .of_match_table = of_match_ptr(rt5514_of_match), .pm = &rt5514_i2_pm_ops, }, From 9aee03f39c13fc674f5973baa69d13e32b45b535 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 18 May 2017 15:35:54 +0200 Subject: [PATCH 064/418] ALSA: pcm: use "do {} while (0)" for empty macro Recent compilers produce a harmless warning for the new pcm_call_notify() macro when CONFIG_SND_PCM_OSS is disabled: sound/core/pcm.c: In function 'snd_pcm_free': sound/core/pcm.c:905:37: error: suggest braces around empty body in an 'if' statement [-Werror=empty-body] This turns the empty macro into a 'do {} while (0)' statement to avoid the warning. Fixes: 58f30d650c7f ("ALSA: pcm: Build pcm notifier code conditionally") Signed-off-by: Arnd Bergmann Signed-off-by: Takashi Iwai --- sound/core/pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 24acbfb5c531..d30dba0ee688 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -894,7 +894,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) _notify->call(pcm); \ } while (0) #else -#define pcm_call_notify(pcm, call) /* NOP */ +#define pcm_call_notify(pcm, call) do {} while (0) #endif static int snd_pcm_free(struct snd_pcm *pcm) From dcab5fb7a5b0472e035da7dfe21168802c1b9d3b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 18 May 2017 15:35:55 +0200 Subject: [PATCH 065/418] ALSA: pcm/oss: mark snd_pcm_plug_slave_format arg as const Only one of the two declarations has the const modifier in the argument list, so we get a warning when CONFIG_SND_PCM_OSS_PLUGINS is disabled: sound/core/oss/pcm_oss.c: In function 'snd_pcm_oss_change_params': sound/core/oss/pcm_oss.c:898:47: error: passing argument 2 of 'snd_pcm_plug_slave_format' discards 'const' qualifier from pointer target type [-Werror=discarded-qualifiers] This makes the two declarations match again. Fixes: e76bf3c4b4e4 ("ALSA: pcm/oss: refer to parameters instead of copying to reduce usage of kernel stack") Signed-off-by: Arnd Bergmann Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_plugin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/oss/pcm_plugin.h b/sound/core/oss/pcm_plugin.h index 38e2c14cb893..73c068abaca5 100644 --- a/sound/core/oss/pcm_plugin.h +++ b/sound/core/oss/pcm_plugin.h @@ -172,7 +172,7 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, static inline snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size) { return drv_size; } static inline snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t clt_size) { return clt_size; } -static inline int snd_pcm_plug_slave_format(int format, struct snd_mask *format_mask) { return format; } +static inline int snd_pcm_plug_slave_format(int format, const struct snd_mask *format_mask) { return format; } #endif From 0e54153b6685712c1e0eaa31c0c199fdce121b28 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Fri, 19 May 2017 15:32:25 +0100 Subject: [PATCH 066/418] ASoC: da7213: Update driver to use device_property* FW functions The driver now supports ACPI based initialisation as well as DT and old pdata methods. However the FW data handling still uses DT specific calls to read firmware data (of_property*) so for ACPI based initialisation the FW data will only be set to default values. This patch updates the FW handling to use device_property* calls instead so that both ACPI and DT are handled as expected. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7213.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 024d83fa6a7f..c3e11897f8ae 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -13,6 +13,8 @@ */ #include +#include +#include #include #include #include @@ -1606,12 +1608,12 @@ static enum da7213_dmic_clk_rate } static struct da7213_platform_data - *da7213_of_to_pdata(struct snd_soc_codec *codec) + *da7213_fw_to_pdata(struct snd_soc_codec *codec) { - struct device_node *np = codec->dev->of_node; + struct device *dev = codec->dev; struct da7213_platform_data *pdata; - const char *of_str; - u32 of_val32; + const char *fw_str; + u32 fw_val32; pdata = devm_kzalloc(codec->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) { @@ -1619,29 +1621,29 @@ static struct da7213_platform_data return NULL; } - if (of_property_read_u32(np, "dlg,micbias1-lvl", &of_val32) >= 0) - pdata->micbias1_lvl = da7213_of_micbias_lvl(codec, of_val32); + if (device_property_read_u32(dev, "dlg,micbias1-lvl", &fw_val32) >= 0) + pdata->micbias1_lvl = da7213_of_micbias_lvl(codec, fw_val32); else pdata->micbias1_lvl = DA7213_MICBIAS_2_2V; - if (of_property_read_u32(np, "dlg,micbias2-lvl", &of_val32) >= 0) - pdata->micbias2_lvl = da7213_of_micbias_lvl(codec, of_val32); + if (device_property_read_u32(dev, "dlg,micbias2-lvl", &fw_val32) >= 0) + pdata->micbias2_lvl = da7213_of_micbias_lvl(codec, fw_val32); else pdata->micbias2_lvl = DA7213_MICBIAS_2_2V; - if (!of_property_read_string(np, "dlg,dmic-data-sel", &of_str)) - pdata->dmic_data_sel = da7213_of_dmic_data_sel(codec, of_str); + if (!device_property_read_string(dev, "dlg,dmic-data-sel", &fw_str)) + pdata->dmic_data_sel = da7213_of_dmic_data_sel(codec, fw_str); else pdata->dmic_data_sel = DA7213_DMIC_DATA_LRISE_RFALL; - if (!of_property_read_string(np, "dlg,dmic-samplephase", &of_str)) + if (!device_property_read_string(dev, "dlg,dmic-samplephase", &fw_str)) pdata->dmic_samplephase = - da7213_of_dmic_samplephase(codec, of_str); + da7213_of_dmic_samplephase(codec, fw_str); else pdata->dmic_samplephase = DA7213_DMIC_SAMPLE_ON_CLKEDGE; - if (of_property_read_u32(np, "dlg,dmic-clkrate", &of_val32) >= 0) - pdata->dmic_clk_rate = da7213_of_dmic_clkrate(codec, of_val32); + if (device_property_read_u32(dev, "dlg,dmic-clkrate", &fw_val32) >= 0) + pdata->dmic_clk_rate = da7213_of_dmic_clkrate(codec, fw_val32); else pdata->dmic_clk_rate = DA7213_DMIC_CLK_3_0MHZ; @@ -1713,10 +1715,9 @@ static int da7213_probe(struct snd_soc_codec *codec) DA7213_LINE_AMP_OE, DA7213_LINE_AMP_OE); /* Handle DT/Platform data */ - if (codec->dev->of_node) - da7213->pdata = da7213_of_to_pdata(codec); - else - da7213->pdata = dev_get_platdata(codec->dev); + da7213->pdata = dev_get_platdata(codec->dev); + if (!da7213->pdata) + da7213->pdata = da7213_fw_to_pdata(codec); /* Set platform data values */ if (da7213->pdata) { From c6d112e442fed7b471a7a2fcedea529622f9ec3a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 19 May 2017 00:57:21 +0000 Subject: [PATCH 067/418] ASoC: simple-card: tidyup return method from probe() Current return method from probe() is very confusable. This patch tidyup it to normal return method Reported-by: Dan Carpenter Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 2c9dedab5184..4dacaf78a0de 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -497,8 +497,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, priv); ret = devm_snd_soc_register_card(dev, card); - if (ret >= 0) - return ret; + if (ret < 0) + goto err; + + return 0; err: asoc_simple_card_clean_reference(card); From c73df77d72de28ad72973d3c3103a5361e1440fb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 19 May 2017 00:57:44 +0000 Subject: [PATCH 068/418] ASoC: simple-scu-card: tidyup return method from probe() Current return method from probe() is very confusable. This patch tidyup it to normal return method Reported-by: Dan Carpenter Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-scu-card.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index dcbcab230d1b..9b9b01e12149 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -298,8 +298,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, priv); ret = devm_snd_soc_register_card(dev, card); - if (ret >= 0) - return ret; + if (ret < 0) + goto err; + + return 0; err: asoc_simple_card_clean_reference(card); From ecea931350cedae8ee24abe6a65619f46a3a9c14 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 19 May 2017 00:58:00 +0000 Subject: [PATCH 069/418] ASoC: audio-graph-card: tidyup return method from probe() Current return method from probe() is very confusable. This patch tidyup it to normal return method Reported-by: Dan Carpenter Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 07e010d38596..f41b0393ffca 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -271,8 +271,10 @@ static int asoc_graph_card_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, priv); ret = devm_snd_soc_register_card(dev, card); - if (ret >= 0) - return ret; + if (ret < 0) + goto err; + + return 0; err: asoc_simple_card_clean_reference(card); From a619f049f23be98510aa0cae774cdc553c54e0e9 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 18 May 2017 08:48:15 +0100 Subject: [PATCH 070/418] ASoC: audio-graph-card: fix spelling mistake: "missmatch" -> "mismatch" Trivial fix to spelling mistake in dev_err message Signed-off-by: Colin Ian King Acked-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index f41b0393ffca..93c167a91d2d 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -107,7 +107,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, int ret; if (rcpu_ep != cpu_ep) { - dev_err(dev, "remote-endpoint missmatch (%s/%s/%s)\n", + dev_err(dev, "remote-endpoint mismatch (%s/%s/%s)\n", cpu_ep->name, codec_ep->name, rcpu_ep->name); ret = -EINVAL; goto dai_link_of_err; From 55cfebfede61cedf60289a7bd20e93a1c83a39a9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 May 2017 01:44:27 +0000 Subject: [PATCH 071/418] ASoC: simple-scu-card: cleanup documentation simple-scu-card is almost same as simple-card. This is already explained in document. But simple-card and simple-scu-card both has same explanation for same property. This patch forward explantion to simple-card if possible to avoid duplication. This patch also cleanup DT binding example which is not good matching to simple-scu-card. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../bindings/sound/simple-scu-card.txt | 65 +++++++------------ 1 file changed, 24 insertions(+), 41 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/simple-scu-card.txt b/Documentation/devicetree/bindings/sound/simple-scu-card.txt index d6fe47ed09af..e894cef1d314 100644 --- a/Documentation/devicetree/bindings/sound/simple-scu-card.txt +++ b/Documentation/devicetree/bindings/sound/simple-scu-card.txt @@ -1,35 +1,29 @@ -ASoC simple SCU Sound Card +ASoC Simple SCU Sound Card -Simple-Card specifies audio DAI connections of SoC <-> codec. +Simple SCU Sound Card is "Simple Sound Card" + "ALSA DPCM". +For example, you can use this driver if you want to exchange sampling rate convert, +Mixing, etc... Required properties: - compatible : "simple-scu-audio-card" "renesas,rsrc-card" - Optional properties: -- simple-audio-card,name : User specified audio sound card name, one string - property. -- simple-audio-card,cpu : CPU sub-node -- simple-audio-card,codec : CODEC sub-node +- simple-audio-card,name : see simple-audio-card.txt +- simple-audio-card,cpu : see simple-audio-card.txt +- simple-audio-card,codec : see simple-audio-card.txt Optional subnode properties: -- simple-audio-card,format : CPU/CODEC common audio format. - "i2s", "right_j", "left_j" , "dsp_a" - "dsp_b", "ac97", "pdm", "msb", "lsb" -- simple-audio-card,frame-master : Indicates dai-link frame master. - phandle to a cpu or codec subnode. -- simple-audio-card,bitclock-master : Indicates dai-link bit clock master. - phandle to a cpu or codec subnode. -- simple-audio-card,bitclock-inversion : bool property. Add this if the - dai-link uses bit clock inversion. -- simple-audio-card,frame-inversion : bool property. Add this if the - dai-link uses frame clock inversion. +- simple-audio-card,format : see simple-audio-card.txt +- simple-audio-card,frame-master : see simple-audio-card.txt +- simple-audio-card,bitclock-master : see simple-audio-card.txt +- simple-audio-card,bitclock-inversion : see simple-audio-card.txt +- simple-audio-card,frame-inversion : see simple-audio-card.txt - simple-audio-card,convert-rate : platform specified sampling rate convert - simple-audio-card,convert-channels : platform specified converted channel size (2 - 8 ch) -- simple-audio-card,prefix : see audio-routing +- simple-audio-card,prefix : see routing - simple-audio-card,routing : 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. Valid names for sources. @@ -38,19 +32,11 @@ Optional subnode properties: Required CPU/CODEC subnodes properties: -- sound-dai : phandle and port of CPU/CODEC +- sound-dai : see simple-audio-card.txt Optional CPU/CODEC subnodes properties: -- clocks / system-clock-frequency : specify subnode's clock if needed. - it can be specified via "clocks" if system has - clock node (= common clock), or "system-clock-frequency" - (if system doens't support common clock) - If a clock is specified, it is - enabled with clk_prepare_enable() - in dai startup() and disabled with - clk_disable_unprepare() in dai - shutdown(). +- clocks / system-clock-frequency : see simple-audio-card.txt Example 1. Sampling Rate Covert @@ -59,11 +45,10 @@ sound { simple-audio-card,name = "rsnd-ak4643"; simple-audio-card,format = "left_j"; - simple-audio-card,format = "left_j"; simple-audio-card,bitclock-master = <&sndcodec>; simple-audio-card,frame-master = <&sndcodec>; - simple-audio-card,convert-rate = <48000>; /* see audio_clk_a */ + simple-audio-card,convert-rate = <48000>; simple-audio-card,prefix = "ak4642"; simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback", @@ -79,20 +64,18 @@ sound { }; }; -Example 2. 2 CPU 1 Codec +Example 2. 2 CPU 1 Codec (Mixing) sound { - compatible = "renesas,rsrc-card"; + compatible = "simple-scu-audio-card"; - card-name = "rsnd-ak4643"; - format = "left_j"; - bitclock-master = <&dpcmcpu>; - frame-master = <&dpcmcpu>; + simple-audio-card,name = "rsnd-ak4643"; + simple-audio-card,format = "left_j"; + simple-audio-card,bitclock-master = <&dpcmcpu>; + simple-audio-card,frame-master = <&dpcmcpu>; - convert-rate = <48000>; /* see audio_clk_a */ - - audio-prefix = "ak4642"; - audio-routing = "ak4642 Playback", "DAI0 Playback", + simple-audio-card,prefix = "ak4642"; + simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback", "ak4642 Playback", "DAI1 Playback"; dpcmcpu: cpu@0 { From b7c752d68aee9c066cb0bd2f24ee73aed64575e8 Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Thu, 18 May 2017 16:32:36 +0100 Subject: [PATCH 072/418] ASoC: cs35l35: Add Boost Inductor Calculation Add the Boost Inductor parameters based off the size of the inductor on the HW setup Signed-off-by: Brian Austin Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- include/sound/cs35l35.h | 2 + sound/soc/codecs/cs35l35.c | 82 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/cs35l35.h | 6 +++ 3 files changed, 90 insertions(+) diff --git a/include/sound/cs35l35.h b/include/sound/cs35l35.h index 29da899e17e4..d69cd7847afd 100644 --- a/include/sound/cs35l35.h +++ b/include/sound/cs35l35.h @@ -99,6 +99,8 @@ struct cs35l35_platform_data { bool shared_bst; /* Specifies this amp is using an external boost supply */ bool ext_bst; + /* Inductor Value */ + int boost_ind; /* ClassH Algorithm */ struct classh_cfg classh_algo; /* Monitor Config */ diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index f8aef5869b03..c6eabb8610f0 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -756,6 +756,76 @@ static int cs35l35_codec_set_sysclk(struct snd_soc_codec *codec, return ret; } +static int cs35l35_boost_inductor(struct cs35l35_private *cs35l35, + int inductor) +{ + struct regmap *regmap = cs35l35->regmap; + unsigned int bst_ipk = 0; + + /* + * Digital Boost Converter Configuration for feedback, + * ramping, switching frequency, and estimation block seeding. + */ + + regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, + CS35L35_BST_CONV_SWFREQ_MASK, 0x00); + + regmap_read(regmap, CS35L35_BST_PEAK_I, &bst_ipk); + bst_ipk &= CS35L35_BST_IPK_MASK; + + switch (inductor) { + case 1000: /* 1 uH */ + regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x24); + regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x24); + regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, + CS35L35_BST_CONV_LBST_MASK, 0x00); + + if (bst_ipk < 0x04) + regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B); + else + regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x4E); + break; + case 1200: /* 1.2 uH */ + regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x20); + regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x20); + regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, + CS35L35_BST_CONV_LBST_MASK, 0x01); + + if (bst_ipk < 0x04) + regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B); + else + regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x47); + break; + case 1500: /* 1.5uH */ + regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x20); + regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x20); + regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, + CS35L35_BST_CONV_LBST_MASK, 0x02); + + if (bst_ipk < 0x04) + regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B); + else + regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x3C); + break; + case 2200: /* 2.2uH */ + regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x19); + regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x25); + regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, + CS35L35_BST_CONV_LBST_MASK, 0x03); + + if (bst_ipk < 0x04) + regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B); + else + regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x23); + break; + default: + dev_err(cs35l35->dev, "Invalid Inductor Value %d uH\n", + inductor); + return -EINVAL; + } + return 0; +} + static int cs35l35_codec_probe(struct snd_soc_codec *codec) { struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); @@ -775,6 +845,10 @@ static int cs35l35_codec_probe(struct snd_soc_codec *codec) cs35l35->pdata.bst_ipk << CS35L35_BST_IPK_SHIFT); + ret = cs35l35_boost_inductor(cs35l35, cs35l35->pdata.boost_ind); + if (ret) + return ret; + if (cs35l35->pdata.gain_zc) regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, CS35L35_AMP_GAIN_ZC_MASK, @@ -1198,6 +1272,14 @@ static int cs35l35_handle_of_data(struct i2c_client *i2c_client, pdata->bst_ipk = (val32 - 1680) / 110; } + ret = of_property_read_u32(np, "cirrus,boost-ind-nanohenry", &val32); + if (ret >= 0) { + pdata->boost_ind = val32; + } else { + dev_err(&i2c_client->dev, "Inductor not specified.\n"); + return -EINVAL; + } + if (of_property_read_u32(np, "cirrus,sp-drv-strength", &val32) >= 0) pdata->sp_drv_str = val32; if (of_property_read_u32(np, "cirrus,sp-drv-unused", &val32) >= 0) diff --git a/sound/soc/codecs/cs35l35.h b/sound/soc/codecs/cs35l35.h index 5a6e43a87c4d..621bfef70d03 100644 --- a/sound/soc/codecs/cs35l35.h +++ b/sound/soc/codecs/cs35l35.h @@ -200,6 +200,12 @@ #define CS35L35_SP_I2S_DRV_MASK 0x03 #define CS35L35_SP_I2S_DRV_SHIFT 0 +/* Boost Converter Config */ +#define CS35L35_BST_CONV_COEFF_MASK 0xFF +#define CS35L35_BST_CONV_SLOPE_MASK 0xFF +#define CS35L35_BST_CONV_LBST_MASK 0x03 +#define CS35L35_BST_CONV_SWFREQ_MASK 0xF0 + /* Class H Algorithm Control */ #define CS35L35_CH_STEREO_MASK 0x40 #define CS35L35_CH_STEREO_SHIFT 6 From cff7597a46454cf0ef0de7340dfb3f6bc0855777 Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Thu, 18 May 2017 16:32:37 +0100 Subject: [PATCH 073/418] ASoC: cs35l35: Add DT handling for Inductor Need to specify the inductor size in nH. This is a required property. Signed-off-by: Brian Austin Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/cs35l35.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/cs35l35.txt b/Documentation/devicetree/bindings/sound/cs35l35.txt index 016b768bc722..77ee75c39233 100644 --- a/Documentation/devicetree/bindings/sound/cs35l35.txt +++ b/Documentation/devicetree/bindings/sound/cs35l35.txt @@ -16,6 +16,9 @@ Required properties: (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for further information relating to interrupt properties) + - cirrus,boost-ind-nanohenry: Inductor value for boost converter. The value is + in nH and they can be values of 1000nH, 1200nH, 1500nH, and 2200nH. + Optional properties: - reset-gpios : gpio used to reset the amplifier From 486fb9590302f811d44fa15401e1736679d33736 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 18 May 2017 16:32:38 +0100 Subject: [PATCH 074/418] ASoC: cs35l35: Correctly handle 0 for bst_ipk Zero is a totally valid value to specify for the bst_ipk, as such we should append CS35L35_VALID_PDATA to ensure that it actually makes it into the register value. Signed-off-by: Charles Keepax 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 c6eabb8610f0..375be49b7fd0 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -1269,7 +1269,7 @@ static int cs35l35_handle_of_data(struct i2c_client *i2c_client, return -EINVAL; } - pdata->bst_ipk = (val32 - 1680) / 110; + pdata->bst_ipk = ((val32 - 1680) / 110) | CS35L35_VALID_PDATA; } ret = of_property_read_u32(np, "cirrus,boost-ind-nanohenry", &val32); From da23173d5c6558b7435e71a4ad947390a9012c6c Mon Sep 17 00:00:00 2001 From: olivier moysan Date: Thu, 18 May 2017 17:19:51 +0200 Subject: [PATCH 075/418] ASoC: stm32: Document STM32 I2S bindings Add documentation of device tree bindings for STM32 SPI/I2S. Signed-off-by: olivier moysan Signed-off-by: Mark Brown --- .../bindings/sound/st,stm32-i2s.txt | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-i2s.txt diff --git a/Documentation/devicetree/bindings/sound/st,stm32-i2s.txt b/Documentation/devicetree/bindings/sound/st,stm32-i2s.txt new file mode 100644 index 000000000000..4bda52042402 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/st,stm32-i2s.txt @@ -0,0 +1,62 @@ +STMicroelectronics STM32 SPI/I2S Controller + +The SPI/I2S block supports I2S/PCM protocols when configured on I2S mode. +Only some SPI instances support I2S. + +Required properties: + - compatible: Must be "st,stm32h7-i2s" + - reg: Offset and length of the device's register set. + - interrupts: Must contain the interrupt line id. + - clocks: Must contain phandle and clock specifier pairs for each entry + in clock-names. + - clock-names: Must contain "i2sclk", "pclk", "x8k" and "x11k". + "i2sclk": clock which feeds the internal clock generator + "pclk": clock which feeds the peripheral bus interface + "x8k": I2S parent clock for sampling rates multiple of 8kHz. + "x11k": I2S parent clock for sampling rates multiple of 11.025kHz. + - dmas: DMA specifiers for tx and rx dma. + See Documentation/devicetree/bindings/dma/stm32-dma.txt. + - dma-names: Identifier for each DMA request line. Must be "tx" and "rx". + - pinctrl-names: should contain only value "default" + - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt + +Optional properties: + - resets: Reference to a reset controller asserting the reset controller + +The device node should contain one 'port' child node with one child 'endpoint' +node, according to the bindings defined in Documentation/devicetree/bindings/ +graph.txt. + +Example: +sound_card { + compatible = "audio-graph-card"; + dais = <&i2s2_port>; +}; + +i2s2: audio-controller@40003800 { + compatible = "st,stm32h7-i2s"; + reg = <0x40003800 0x400>; + interrupts = <36>; + clocks = <&rcc PCLK1>, <&rcc SPI2_CK>, <&rcc PLL1_Q>, <&rcc PLL2_P>; + clock-names = "pclk", "i2sclk", "x8k", "x11k"; + dmas = <&dmamux2 2 39 0x400 0x1>, + <&dmamux2 3 40 0x400 0x1>; + dma-names = "rx", "tx"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2s2>; + + i2s2_port: port@0 { + cpu_endpoint: endpoint { + remote-endpoint = <&codec_endpoint>; + format = "i2s"; + }; + }; +}; + +audio-codec { + codec_port: port@0 { + codec_endpoint: endpoint { + remote-endpoint = <&cpu_endpoint>; + }; + }; +}; From e4e6ec7b127c97fbfa92161d0fc69f526f603e97 Mon Sep 17 00:00:00 2001 From: olivier moysan Date: Thu, 18 May 2017 17:19:52 +0200 Subject: [PATCH 076/418] ASoC: stm32: Add I2S driver Add I2S ASoC driver for STM32. This version of the driver supports only exclusive playback and capture interface. Signed-off-by: olivier moysan Signed-off-by: Mark Brown --- sound/soc/stm/Kconfig | 2 +- sound/soc/stm/Makefile | 4 + sound/soc/stm/stm32_i2s.c | 941 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 946 insertions(+), 1 deletion(-) create mode 100644 sound/soc/stm/stm32_i2s.c diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index 972970f0890a..a6372de54042 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -5,4 +5,4 @@ menuconfig SND_SOC_STM32 select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO help - Say Y if you want to enable ASoC-support for STM32 + Say Y if you want to enable ASoC support for STM32 diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile index e466a4759698..82519313c0b4 100644 --- a/sound/soc/stm/Makefile +++ b/sound/soc/stm/Makefile @@ -4,3 +4,7 @@ obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai-sub.o snd-soc-stm32-sai-objs := stm32_sai.o obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai.o + +# I2S +snd-soc-stm32-i2s-objs := stm32_i2s.o +obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-i2s.o diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c new file mode 100644 index 000000000000..22152a1ca733 --- /dev/null +++ b/sound/soc/stm/stm32_i2s.c @@ -0,0 +1,941 @@ +/* + * STM32 ALSA SoC Digital Audio Interface (I2S) driver. + * + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author(s): Olivier Moysan for STMicroelectronics. + * + * License terms: GPL V2.0. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define STM32_I2S_CR1_REG 0x0 +#define STM32_I2S_CFG1_REG 0x08 +#define STM32_I2S_CFG2_REG 0x0C +#define STM32_I2S_IER_REG 0x10 +#define STM32_I2S_SR_REG 0x14 +#define STM32_I2S_IFCR_REG 0x18 +#define STM32_I2S_TXDR_REG 0X20 +#define STM32_I2S_RXDR_REG 0x30 +#define STM32_I2S_CGFR_REG 0X50 + +/* Bit definition for SPI2S_CR1 register */ +#define I2S_CR1_SPE BIT(0) +#define I2S_CR1_CSTART BIT(9) +#define I2S_CR1_CSUSP BIT(10) +#define I2S_CR1_HDDIR BIT(11) +#define I2S_CR1_SSI BIT(12) +#define I2S_CR1_CRC33_17 BIT(13) +#define I2S_CR1_RCRCI BIT(14) +#define I2S_CR1_TCRCI BIT(15) + +/* Bit definition for SPI_CFG2 register */ +#define I2S_CFG2_IOSWP_SHIFT 15 +#define I2S_CFG2_IOSWP BIT(I2S_CFG2_IOSWP_SHIFT) +#define I2S_CFG2_LSBFRST BIT(23) +#define I2S_CFG2_AFCNTR BIT(31) + +/* Bit definition for SPI_CFG1 register */ +#define I2S_CFG1_FTHVL_SHIFT 5 +#define I2S_CFG1_FTHVL_MASK GENMASK(8, I2S_CFG1_FTHVL_SHIFT) +#define I2S_CFG1_FTHVL_SET(x) ((x) << I2S_CFG1_FTHVL_SHIFT) + +#define I2S_CFG1_TXDMAEN BIT(15) +#define I2S_CFG1_RXDMAEN BIT(14) + +/* Bit definition for SPI2S_IER register */ +#define I2S_IER_RXPIE BIT(0) +#define I2S_IER_TXPIE BIT(1) +#define I2S_IER_DPXPIE BIT(2) +#define I2S_IER_EOTIE BIT(3) +#define I2S_IER_TXTFIE BIT(4) +#define I2S_IER_UDRIE BIT(5) +#define I2S_IER_OVRIE BIT(6) +#define I2S_IER_CRCEIE BIT(7) +#define I2S_IER_TIFREIE BIT(8) +#define I2S_IER_MODFIE BIT(9) +#define I2S_IER_TSERFIE BIT(10) + +/* Bit definition for SPI2S_SR register */ +#define I2S_SR_RXP BIT(0) +#define I2S_SR_TXP BIT(1) +#define I2S_SR_DPXP BIT(2) +#define I2S_SR_EOT BIT(3) +#define I2S_SR_TXTF BIT(4) +#define I2S_SR_UDR BIT(5) +#define I2S_SR_OVR BIT(6) +#define I2S_SR_CRCERR BIT(7) +#define I2S_SR_TIFRE BIT(8) +#define I2S_SR_MODF BIT(9) +#define I2S_SR_TSERF BIT(10) +#define I2S_SR_SUSP BIT(11) +#define I2S_SR_TXC BIT(12) +#define I2S_SR_RXPLVL GENMASK(14, 13) +#define I2S_SR_RXWNE BIT(15) + +#define I2S_SR_MASK GENMASK(15, 0) + +/* Bit definition for SPI_IFCR register */ +#define I2S_IFCR_EOTC BIT(3) +#define I2S_IFCR_TXTFC BIT(4) +#define I2S_IFCR_UDRC BIT(5) +#define I2S_IFCR_OVRC BIT(6) +#define I2S_IFCR_CRCEC BIT(7) +#define I2S_IFCR_TIFREC BIT(8) +#define I2S_IFCR_MODFC BIT(9) +#define I2S_IFCR_TSERFC BIT(10) +#define I2S_IFCR_SUSPC BIT(11) + +#define I2S_IFCR_MASK GENMASK(11, 3) + +/* Bit definition for SPI_I2SCGFR register */ +#define I2S_CGFR_I2SMOD BIT(0) + +#define I2S_CGFR_I2SCFG_SHIFT 1 +#define I2S_CGFR_I2SCFG_MASK GENMASK(3, I2S_CGFR_I2SCFG_SHIFT) +#define I2S_CGFR_I2SCFG_SET(x) ((x) << I2S_CGFR_I2SCFG_SHIFT) + +#define I2S_CGFR_I2SSTD_SHIFT 4 +#define I2S_CGFR_I2SSTD_MASK GENMASK(5, I2S_CGFR_I2SSTD_SHIFT) +#define I2S_CGFR_I2SSTD_SET(x) ((x) << I2S_CGFR_I2SSTD_SHIFT) + +#define I2S_CGFR_PCMSYNC BIT(7) + +#define I2S_CGFR_DATLEN_SHIFT 8 +#define I2S_CGFR_DATLEN_MASK GENMASK(9, I2S_CGFR_DATLEN_SHIFT) +#define I2S_CGFR_DATLEN_SET(x) ((x) << I2S_CGFR_DATLEN_SHIFT) + +#define I2S_CGFR_CHLEN_SHIFT 10 +#define I2S_CGFR_CHLEN BIT(I2S_CGFR_CHLEN_SHIFT) +#define I2S_CGFR_CKPOL BIT(11) +#define I2S_CGFR_FIXCH BIT(12) +#define I2S_CGFR_WSINV BIT(13) +#define I2S_CGFR_DATFMT BIT(14) + +#define I2S_CGFR_I2SDIV_SHIFT 16 +#define I2S_CGFR_I2SDIV_BIT_H 23 +#define I2S_CGFR_I2SDIV_MASK GENMASK(I2S_CGFR_I2SDIV_BIT_H,\ + I2S_CGFR_I2SDIV_SHIFT) +#define I2S_CGFR_I2SDIV_SET(x) ((x) << I2S_CGFR_I2SDIV_SHIFT) +#define I2S_CGFR_I2SDIV_MAX ((1 << (I2S_CGFR_I2SDIV_BIT_H -\ + I2S_CGFR_I2SDIV_SHIFT)) - 1) + +#define I2S_CGFR_ODD_SHIFT 24 +#define I2S_CGFR_ODD BIT(I2S_CGFR_ODD_SHIFT) +#define I2S_CGFR_MCKOE BIT(25) + +enum i2s_master_mode { + I2S_MS_NOT_SET, + I2S_MS_MASTER, + I2S_MS_SLAVE, +}; + +enum i2s_mode { + I2S_I2SMOD_TX_SLAVE, + I2S_I2SMOD_RX_SLAVE, + I2S_I2SMOD_TX_MASTER, + I2S_I2SMOD_RX_MASTER, + I2S_I2SMOD_FD_SLAVE, + I2S_I2SMOD_FD_MASTER, +}; + +enum i2s_fifo_th { + I2S_FIFO_TH_NONE, + I2S_FIFO_TH_ONE_QUARTER, + I2S_FIFO_TH_HALF, + I2S_FIFO_TH_THREE_QUARTER, + I2S_FIFO_TH_FULL, +}; + +enum i2s_std { + I2S_STD_I2S, + I2S_STD_LEFT_J, + I2S_STD_RIGHT_J, + I2S_STD_DSP, +}; + +enum i2s_datlen { + I2S_I2SMOD_DATLEN_16, + I2S_I2SMOD_DATLEN_24, + I2S_I2SMOD_DATLEN_32, +}; + +#define STM32_I2S_DAI_NAME_SIZE 20 +#define STM32_I2S_FIFO_SIZE 16 + +#define STM32_I2S_IS_MASTER(x) ((x)->ms_flg == I2S_MS_MASTER) +#define STM32_I2S_IS_SLAVE(x) ((x)->ms_flg == I2S_MS_SLAVE) + +/** + * @regmap_conf: I2S register map configuration pointer + * @egmap: I2S register map pointer + * @pdev: device data pointer + * @dai_drv: DAI driver pointer + * @dma_data_tx: dma configuration data for tx channel + * @dma_data_rx: dma configuration data for tx channel + * @substream: PCM substream data pointer + * @i2sclk: kernel clock feeding the I2S clock generator + * @pclk: peripheral clock driving bus interface + * @x8kclk: I2S parent clock for sampling frequencies multiple of 8kHz + * @x11kclk: I2S parent clock for sampling frequencies multiple of 11kHz + * @base: mmio register base virtual address + * @phys_addr: I2S registers physical base address + * @lock_fd: lock to manage race conditions in full duplex mode + * @dais_name: DAI name + * @mclk_rate: master clock frequency (Hz) + * @fmt: DAI protocol + * @refcount: keep count of opened streams on I2S + * @ms_flg: master mode flag. + */ +struct stm32_i2s_data { + const struct regmap_config *regmap_conf; + struct regmap *regmap; + struct platform_device *pdev; + struct snd_soc_dai_driver *dai_drv; + struct snd_dmaengine_dai_dma_data dma_data_tx; + struct snd_dmaengine_dai_dma_data dma_data_rx; + struct snd_pcm_substream *substream; + struct clk *i2sclk; + struct clk *pclk; + struct clk *x8kclk; + struct clk *x11kclk; + void __iomem *base; + dma_addr_t phys_addr; + spinlock_t lock_fd; /* Manage race conditions for full duplex */ + char dais_name[STM32_I2S_DAI_NAME_SIZE]; + unsigned int mclk_rate; + unsigned int fmt; + int refcount; + int ms_flg; +}; + +static irqreturn_t stm32_i2s_isr(int irq, void *devid) +{ + struct stm32_i2s_data *i2s = (struct stm32_i2s_data *)devid; + struct platform_device *pdev = i2s->pdev; + u32 sr, ier; + unsigned long flags; + int err = 0; + + regmap_read(i2s->regmap, STM32_I2S_SR_REG, &sr); + regmap_read(i2s->regmap, STM32_I2S_IER_REG, &ier); + + flags = sr & ier; + if (!flags) { + dev_dbg(&pdev->dev, "Spurious IRQ sr=0x%08x, ier=0x%08x\n", + sr, ier); + return IRQ_NONE; + } + + regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, + I2S_IFCR_MASK, flags); + + if (flags & I2S_SR_OVR) { + dev_dbg(&pdev->dev, "Overrun\n"); + err = 1; + } + + if (flags & I2S_SR_UDR) { + dev_dbg(&pdev->dev, "Underrun\n"); + err = 1; + } + + if (flags & I2S_SR_TIFRE) + dev_dbg(&pdev->dev, "Frame error\n"); + + if (err) + snd_pcm_stop_xrun(i2s->substream); + + return IRQ_HANDLED; +} + +static bool stm32_i2s_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case STM32_I2S_CR1_REG: + case STM32_I2S_CFG1_REG: + case STM32_I2S_CFG2_REG: + case STM32_I2S_IER_REG: + case STM32_I2S_SR_REG: + case STM32_I2S_IFCR_REG: + case STM32_I2S_TXDR_REG: + case STM32_I2S_RXDR_REG: + case STM32_I2S_CGFR_REG: + return true; + default: + return false; + } +} + +static bool stm32_i2s_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case STM32_I2S_TXDR_REG: + case STM32_I2S_RXDR_REG: + return true; + default: + return false; + } +} + +static bool stm32_i2s_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case STM32_I2S_CR1_REG: + case STM32_I2S_CFG1_REG: + case STM32_I2S_CFG2_REG: + case STM32_I2S_IER_REG: + case STM32_I2S_IFCR_REG: + case STM32_I2S_TXDR_REG: + case STM32_I2S_CGFR_REG: + return true; + default: + return false; + } +} + +static int stm32_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) +{ + struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); + u32 cgfr; + u32 cgfr_mask = I2S_CGFR_I2SSTD_MASK | I2S_CGFR_CKPOL | + I2S_CGFR_WSINV | I2S_CGFR_I2SCFG_MASK; + + dev_dbg(cpu_dai->dev, "fmt %x\n", fmt); + + /* + * winv = 0 : default behavior (high/low) for all standards + * ckpol = 0 for all standards. + */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + cgfr = I2S_CGFR_I2SSTD_SET(I2S_STD_I2S); + break; + case SND_SOC_DAIFMT_MSB: + cgfr = I2S_CGFR_I2SSTD_SET(I2S_STD_LEFT_J); + break; + case SND_SOC_DAIFMT_LSB: + cgfr = I2S_CGFR_I2SSTD_SET(I2S_STD_RIGHT_J); + break; + case SND_SOC_DAIFMT_DSP_A: + cgfr = I2S_CGFR_I2SSTD_SET(I2S_STD_DSP); + break; + /* DSP_B not mapped on I2S PCM long format. 1 bit offset does not fit */ + default: + dev_err(cpu_dai->dev, "Unsupported protocol %#x\n", + fmt & SND_SOC_DAIFMT_FORMAT_MASK); + return -EINVAL; + } + + /* DAI clock strobing */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + cgfr |= I2S_CGFR_CKPOL; + break; + case SND_SOC_DAIFMT_NB_IF: + cgfr |= I2S_CGFR_WSINV; + break; + case SND_SOC_DAIFMT_IB_IF: + cgfr |= I2S_CGFR_CKPOL; + cgfr |= I2S_CGFR_WSINV; + break; + default: + dev_err(cpu_dai->dev, "Unsupported strobing %#x\n", + fmt & SND_SOC_DAIFMT_INV_MASK); + return -EINVAL; + } + + /* DAI clock master masks */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + i2s->ms_flg = I2S_MS_SLAVE; + break; + case SND_SOC_DAIFMT_CBS_CFS: + i2s->ms_flg = I2S_MS_MASTER; + break; + default: + dev_err(cpu_dai->dev, "Unsupported mode %#x\n", + fmt & SND_SOC_DAIFMT_MASTER_MASK); + return -EINVAL; + } + + i2s->fmt = fmt; + return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, + cgfr_mask, cgfr); +} + +static int stm32_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); + + dev_dbg(cpu_dai->dev, "I2S MCLK frequency is %uHz\n", freq); + + if ((dir == SND_SOC_CLOCK_OUT) && STM32_I2S_IS_MASTER(i2s)) { + i2s->mclk_rate = freq; + + /* Enable master clock if master mode and mclk-fs are set */ + return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, + I2S_CGFR_MCKOE, I2S_CGFR_MCKOE); + } + + return 0; +} + +static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai, + struct snd_pcm_hw_params *params) +{ + struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long i2s_clock_rate; + unsigned int tmp, div, real_div, nb_bits, frame_len; + unsigned int rate = params_rate(params); + int ret; + u32 cgfr, cgfr_mask; + bool odd; + + if (!(rate % 11025)) + clk_set_parent(i2s->i2sclk, i2s->x11kclk); + else + clk_set_parent(i2s->i2sclk, i2s->x8kclk); + i2s_clock_rate = clk_get_rate(i2s->i2sclk); + + /* + * mckl = mclk_ratio x ws + * i2s mode : mclk_ratio = 256 + * dsp mode : mclk_ratio = 128 + * + * mclk on + * i2s mode : div = i2s_clk / (mclk_ratio * ws) + * dsp mode : div = i2s_clk / (mclk_ratio * ws) + * mclk off + * i2s mode : div = i2s_clk / (nb_bits x ws) + * dsp mode : div = i2s_clk / (nb_bits x ws) + */ + if (i2s->mclk_rate) { + tmp = DIV_ROUND_CLOSEST(i2s_clock_rate, i2s->mclk_rate); + } else { + frame_len = 32; + if ((i2s->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == + SND_SOC_DAIFMT_DSP_A) + frame_len = 16; + + /* master clock not enabled */ + ret = regmap_read(i2s->regmap, STM32_I2S_CGFR_REG, &cgfr); + if (ret < 0) + return ret; + + nb_bits = frame_len * ((cgfr & I2S_CGFR_CHLEN) + 1); + tmp = DIV_ROUND_CLOSEST(i2s_clock_rate, (nb_bits * rate)); + } + + /* Check the parity of the divider */ + odd = tmp & 0x1; + + /* Compute the div prescaler */ + div = tmp >> 1; + + cgfr = I2S_CGFR_I2SDIV_SET(div) | (odd << I2S_CGFR_ODD_SHIFT); + cgfr_mask = I2S_CGFR_I2SDIV_MASK | I2S_CGFR_ODD; + + real_div = ((2 * div) + odd); + dev_dbg(cpu_dai->dev, "I2S clk: %ld, SCLK: %d\n", + i2s_clock_rate, rate); + dev_dbg(cpu_dai->dev, "Divider: 2*%d(div)+%d(odd) = %d\n", + div, odd, real_div); + + if (((div == 1) && odd) || (div > I2S_CGFR_I2SDIV_MAX)) { + dev_err(cpu_dai->dev, "Wrong divider setting\n"); + return -EINVAL; + } + + if (!div && !odd) + dev_warn(cpu_dai->dev, "real divider forced to 1\n"); + + ret = regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, + cgfr_mask, cgfr); + if (ret < 0) + return ret; + + /* Set bitclock and frameclock to their inactive state */ + return regmap_update_bits(i2s->regmap, STM32_I2S_CFG2_REG, + I2S_CFG2_AFCNTR, I2S_CFG2_AFCNTR); +} + +static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, + struct snd_pcm_hw_params *params, + struct snd_pcm_substream *substream) +{ + struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); + int format = params_width(params); + u32 cfgr, cfgr_mask, cfg1, cfg1_mask; + bool playback_flg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + unsigned int fthlv; + int ret; + + if ((params_channels(params) == 1) && + ((i2s->fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_DSP_A)) { + dev_err(cpu_dai->dev, "Mono mode supported only by DSP_A\n"); + return -EINVAL; + } + + switch (format) { + case 16: + cfgr = I2S_CGFR_DATLEN_SET(I2S_I2SMOD_DATLEN_16); + cfgr_mask = I2S_CGFR_DATLEN_MASK; + break; + case 32: + cfgr = I2S_CGFR_DATLEN_SET(I2S_I2SMOD_DATLEN_32) | + I2S_CGFR_CHLEN; + cfgr_mask = I2S_CGFR_DATLEN_MASK | I2S_CGFR_CHLEN; + break; + default: + dev_err(cpu_dai->dev, "Unexpected format %d", format); + return -EINVAL; + } + + if (STM32_I2S_IS_SLAVE(i2s)) { + if (playback_flg) + cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_TX_SLAVE); + else + cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_RX_SLAVE); + + /* As data length is either 16 or 32 bits, fixch always set */ + cfgr |= I2S_CGFR_FIXCH; + cfgr_mask |= I2S_CGFR_FIXCH; + } else { + if (playback_flg) + cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_TX_MASTER); + else + cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_RX_MASTER); + } + cfgr_mask |= I2S_CGFR_I2SCFG_MASK; + + ret = regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, + cfgr_mask, cfgr); + if (ret < 0) + return ret; + + cfg1 = I2S_CFG1_RXDMAEN; + if (playback_flg) + cfg1 = I2S_CFG1_TXDMAEN; + cfg1_mask = cfg1; + + fthlv = STM32_I2S_FIFO_SIZE * I2S_FIFO_TH_ONE_QUARTER / 4; + cfg1 |= I2S_CFG1_FTHVL_SET(fthlv - 1); + cfg1_mask |= I2S_CFG1_FTHVL_MASK; + + return regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG, + cfg1_mask, cfg1); +} + +static int stm32_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); + int ret, ier; + + i2s->substream = substream; + + spin_lock(&i2s->lock_fd); + if (i2s->refcount) { + dev_err(cpu_dai->dev, "%s stream already started\n", + (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + "Capture" : "Playback")); + spin_unlock(&i2s->lock_fd); + return -EBUSY; + } + i2s->refcount = 1; + spin_unlock(&i2s->lock_fd); + + ret = regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, + I2S_IFCR_MASK, I2S_IFCR_MASK); + if (ret < 0) + return ret; + + /* Enable ITs */ + ier = I2S_IER_OVRIE | I2S_IER_UDRIE; + if (STM32_I2S_IS_SLAVE(i2s)) + ier |= I2S_IER_TIFREIE; + + return regmap_update_bits(i2s->regmap, STM32_I2S_IER_REG, ier, ier); +} + +static int stm32_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai) +{ + struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); + int ret; + + ret = stm32_i2s_configure(cpu_dai, params, substream); + if (ret < 0) { + dev_err(cpu_dai->dev, "Configuration returned error %d\n", ret); + return ret; + } + + if (STM32_I2S_IS_MASTER(i2s)) + ret = stm32_i2s_configure_clock(cpu_dai, params); + + return ret; +} + +static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *cpu_dai) +{ + struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); + bool playback_flg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + u32 cfg1_mask; + int ret; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + /* Enable i2s */ + dev_dbg(cpu_dai->dev, "start I2S\n"); + + ret = regmap_update_bits(i2s->regmap, STM32_I2S_CR1_REG, + I2S_CR1_SPE, I2S_CR1_SPE); + if (ret < 0) { + dev_err(cpu_dai->dev, "Error %d enabling I2S\n", ret); + return ret; + } + + ret = regmap_update_bits(i2s->regmap, STM32_I2S_CR1_REG, + I2S_CR1_CSTART, I2S_CR1_CSTART); + if (ret < 0) { + dev_err(cpu_dai->dev, "Error %d starting I2S\n", ret); + return ret; + } + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + dev_dbg(cpu_dai->dev, "stop I2S\n"); + + ret = regmap_update_bits(i2s->regmap, STM32_I2S_CR1_REG, + I2S_CR1_SPE, 0); + if (ret < 0) { + dev_err(cpu_dai->dev, "Error %d disabling I2S\n", ret); + return ret; + } + + cfg1_mask = I2S_CFG1_RXDMAEN; + if (playback_flg) + cfg1_mask = I2S_CFG1_TXDMAEN; + + regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG, + cfg1_mask, 0); + break; + default: + return -EINVAL; + } + + return 0; +} + +static void stm32_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); + + i2s->substream = NULL; + + spin_lock(&i2s->lock_fd); + i2s->refcount = 0; + spin_unlock(&i2s->lock_fd); + + regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, + I2S_CGFR_MCKOE, (unsigned int)~I2S_CGFR_MCKOE); +} + +static int stm32_i2s_dai_probe(struct snd_soc_dai *cpu_dai) +{ + struct stm32_i2s_data *i2s = dev_get_drvdata(cpu_dai->dev); + struct snd_dmaengine_dai_dma_data *dma_data_tx = &i2s->dma_data_tx; + struct snd_dmaengine_dai_dma_data *dma_data_rx = &i2s->dma_data_rx; + + /* Buswidth will be set by framework */ + dma_data_tx->addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; + dma_data_tx->addr = (dma_addr_t)(i2s->phys_addr) + STM32_I2S_TXDR_REG; + dma_data_tx->maxburst = 1; + dma_data_rx->addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; + dma_data_rx->addr = (dma_addr_t)(i2s->phys_addr) + STM32_I2S_RXDR_REG; + dma_data_rx->maxburst = 1; + + snd_soc_dai_init_dma_data(cpu_dai, dma_data_tx, dma_data_rx); + + return 0; +} + +static const struct regmap_config stm32_h7_i2s_regmap_conf = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = STM32_I2S_CGFR_REG, + .readable_reg = stm32_i2s_readable_reg, + .volatile_reg = stm32_i2s_volatile_reg, + .writeable_reg = stm32_i2s_writeable_reg, + .fast_io = true, +}; + +static const struct snd_soc_dai_ops stm32_i2s_pcm_dai_ops = { + .set_sysclk = stm32_i2s_set_sysclk, + .set_fmt = stm32_i2s_set_dai_fmt, + .startup = stm32_i2s_startup, + .hw_params = stm32_i2s_hw_params, + .trigger = stm32_i2s_trigger, + .shutdown = stm32_i2s_shutdown, +}; + +static const struct snd_pcm_hardware stm32_i2s_pcm_hw = { + .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP, + .buffer_bytes_max = 8 * PAGE_SIZE, + .period_bytes_max = 2048, + .periods_min = 2, + .periods_max = 8, +}; + +static const struct snd_dmaengine_pcm_config stm32_i2s_pcm_config = { + .pcm_hardware = &stm32_i2s_pcm_hw, + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, + .prealloc_buffer_size = PAGE_SIZE * 8, +}; + +static const struct snd_soc_component_driver stm32_i2s_component = { + .name = "stm32-i2s", +}; + +static void stm32_i2s_dai_init(struct snd_soc_pcm_stream *stream, + char *stream_name) +{ + stream->stream_name = stream_name; + stream->channels_min = 1; + stream->channels_max = 2; + stream->rates = SNDRV_PCM_RATE_8000_192000; + stream->formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE; +} + +static int stm32_i2s_dais_init(struct platform_device *pdev, + struct stm32_i2s_data *i2s) +{ + struct snd_soc_dai_driver *dai_ptr; + + dai_ptr = devm_kzalloc(&pdev->dev, sizeof(struct snd_soc_dai_driver), + GFP_KERNEL); + if (!dai_ptr) + return -ENOMEM; + + snprintf(i2s->dais_name, STM32_I2S_DAI_NAME_SIZE, + "%s", dev_name(&pdev->dev)); + + dai_ptr->probe = stm32_i2s_dai_probe; + dai_ptr->ops = &stm32_i2s_pcm_dai_ops; + dai_ptr->name = i2s->dais_name; + dai_ptr->id = 1; + stm32_i2s_dai_init(&dai_ptr->playback, "playback"); + stm32_i2s_dai_init(&dai_ptr->capture, "capture"); + i2s->dai_drv = dai_ptr; + + return 0; +} + +static const struct of_device_id stm32_i2s_ids[] = { + { + .compatible = "st,stm32h7-i2s", + .data = &stm32_h7_i2s_regmap_conf + }, + {}, +}; + +static int stm32_i2s_parse_dt(struct platform_device *pdev, + struct stm32_i2s_data *i2s) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id; + struct reset_control *rst; + struct resource *res; + int irq, ret; + + if (!np) + return -ENODEV; + + of_id = of_match_device(stm32_i2s_ids, &pdev->dev); + if (of_id) + i2s->regmap_conf = (const struct regmap_config *)of_id->data; + else + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2s->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(i2s->base)) + return PTR_ERR(i2s->base); + + i2s->phys_addr = res->start; + + /* Get clocks */ + i2s->pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(i2s->pclk)) { + dev_err(&pdev->dev, "Could not get pclk\n"); + return PTR_ERR(i2s->pclk); + } + + i2s->i2sclk = devm_clk_get(&pdev->dev, "i2sclk"); + if (IS_ERR(i2s->i2sclk)) { + dev_err(&pdev->dev, "Could not get i2sclk\n"); + return PTR_ERR(i2s->i2sclk); + } + + i2s->x8kclk = devm_clk_get(&pdev->dev, "x8k"); + if (IS_ERR(i2s->x8kclk)) { + dev_err(&pdev->dev, "missing x8k parent clock\n"); + return PTR_ERR(i2s->x8kclk); + } + + i2s->x11kclk = devm_clk_get(&pdev->dev, "x11k"); + if (IS_ERR(i2s->x11kclk)) { + dev_err(&pdev->dev, "missing x11k parent clock\n"); + return PTR_ERR(i2s->x11kclk); + } + + /* Get irqs */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); + return -ENOENT; + } + + ret = devm_request_irq(&pdev->dev, irq, stm32_i2s_isr, IRQF_ONESHOT, + dev_name(&pdev->dev), i2s); + if (ret) { + dev_err(&pdev->dev, "irq request returned %d\n", ret); + return ret; + } + + /* Reset */ + rst = devm_reset_control_get(&pdev->dev, NULL); + if (!IS_ERR(rst)) { + reset_control_assert(rst); + udelay(2); + reset_control_deassert(rst); + } + + return 0; +} + +static int stm32_i2s_probe(struct platform_device *pdev) +{ + struct stm32_i2s_data *i2s; + int ret; + + i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); + if (!i2s) + return -ENOMEM; + + ret = stm32_i2s_parse_dt(pdev, i2s); + if (ret) + return ret; + + i2s->pdev = pdev; + i2s->ms_flg = I2S_MS_NOT_SET; + spin_lock_init(&i2s->lock_fd); + platform_set_drvdata(pdev, i2s); + + ret = stm32_i2s_dais_init(pdev, i2s); + if (ret) + return ret; + + i2s->regmap = devm_regmap_init_mmio(&pdev->dev, i2s->base, + i2s->regmap_conf); + if (IS_ERR(i2s->regmap)) { + dev_err(&pdev->dev, "regmap init failed\n"); + return PTR_ERR(i2s->regmap); + } + + ret = clk_prepare_enable(i2s->pclk); + if (ret) { + dev_err(&pdev->dev, "Enable pclk failed: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(i2s->i2sclk); + if (ret) { + dev_err(&pdev->dev, "Enable i2sclk failed: %d\n", ret); + goto err_pclk_disable; + } + + ret = devm_snd_soc_register_component(&pdev->dev, &stm32_i2s_component, + i2s->dai_drv, 1); + if (ret) + goto err_clocks_disable; + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, + &stm32_i2s_pcm_config, 0); + if (ret) + goto err_clocks_disable; + + /* Set SPI/I2S in i2s mode */ + ret = regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, + I2S_CGFR_I2SMOD, I2S_CGFR_I2SMOD); + if (ret) + goto err_clocks_disable; + + return ret; + +err_clocks_disable: + clk_disable_unprepare(i2s->i2sclk); +err_pclk_disable: + clk_disable_unprepare(i2s->pclk); + + return ret; +} + +static int stm32_i2s_remove(struct platform_device *pdev) +{ + struct stm32_i2s_data *i2s = platform_get_drvdata(pdev); + + clk_disable_unprepare(i2s->i2sclk); + clk_disable_unprepare(i2s->pclk); + + return 0; +} + +MODULE_DEVICE_TABLE(of, stm32_i2s_ids); + +static struct platform_driver stm32_i2s_driver = { + .driver = { + .name = "st,stm32-i2s", + .of_match_table = stm32_i2s_ids, + }, + .probe = stm32_i2s_probe, + .remove = stm32_i2s_remove, +}; + +module_platform_driver(stm32_i2s_driver); + +MODULE_DESCRIPTION("STM32 Soc i2s Interface"); +MODULE_AUTHOR("Olivier Moysan, "); +MODULE_ALIAS("platform:stm32-i2s"); +MODULE_LICENSE("GPL v2"); From e7cc49b8adf25e7bae6acaeb37036ef8726b902c Mon Sep 17 00:00:00 2001 From: olivier moysan Date: Thu, 18 May 2017 17:19:53 +0200 Subject: [PATCH 077/418] ASoC: stm32: Add full duplex support to i2s This patch allows to use i2s interface either as single audio path (rx or tx), or bidirectional audio path. This patch is added separately, as the driver does not follow recommended use of the interface, to support this configuration. Signed-off-by: olivier moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 87 +++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 22152a1ca733..8052629a89df 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -489,7 +489,6 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); int format = params_width(params); u32 cfgr, cfgr_mask, cfg1, cfg1_mask; - bool playback_flg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); unsigned int fthlv; int ret; @@ -515,19 +514,13 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, } if (STM32_I2S_IS_SLAVE(i2s)) { - if (playback_flg) - cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_TX_SLAVE); - else - cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_RX_SLAVE); + cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_FD_SLAVE); /* As data length is either 16 or 32 bits, fixch always set */ cfgr |= I2S_CGFR_FIXCH; cfgr_mask |= I2S_CGFR_FIXCH; } else { - if (playback_flg) - cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_TX_MASTER); - else - cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_RX_MASTER); + cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_FD_MASTER); } cfgr_mask |= I2S_CGFR_I2SCFG_MASK; @@ -536,9 +529,7 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, if (ret < 0) return ret; - cfg1 = I2S_CFG1_RXDMAEN; - if (playback_flg) - cfg1 = I2S_CFG1_TXDMAEN; + cfg1 = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN; cfg1_mask = cfg1; fthlv = STM32_I2S_FIFO_SIZE * I2S_FIFO_TH_ONE_QUARTER / 4; @@ -553,32 +544,15 @@ static int stm32_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); - int ret, ier; i2s->substream = substream; spin_lock(&i2s->lock_fd); - if (i2s->refcount) { - dev_err(cpu_dai->dev, "%s stream already started\n", - (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - "Capture" : "Playback")); - spin_unlock(&i2s->lock_fd); - return -EBUSY; - } - i2s->refcount = 1; + i2s->refcount++; spin_unlock(&i2s->lock_fd); - ret = regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, - I2S_IFCR_MASK, I2S_IFCR_MASK); - if (ret < 0) - return ret; - - /* Enable ITs */ - ier = I2S_IER_OVRIE | I2S_IER_UDRIE; - if (STM32_I2S_IS_SLAVE(i2s)) - ier |= I2S_IER_TIFREIE; - - return regmap_update_bits(i2s->regmap, STM32_I2S_IER_REG, ier, ier); + return regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, + I2S_IFCR_MASK, I2S_IFCR_MASK); } static int stm32_i2s_hw_params(struct snd_pcm_substream *substream, @@ -605,7 +579,7 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, { struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); bool playback_flg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); - u32 cfg1_mask; + u32 cfg1_mask, ier; int ret; switch (cmd) { @@ -628,10 +602,48 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, dev_err(cpu_dai->dev, "Error %d starting I2S\n", ret); return ret; } + + regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, + I2S_IFCR_MASK, I2S_IFCR_MASK); + + if (playback_flg) { + ier = I2S_IER_UDRIE; + } else { + ier = I2S_IER_OVRIE; + + spin_lock(&i2s->lock_fd); + if (i2s->refcount == 1) + /* dummy write to trigger capture */ + regmap_write(i2s->regmap, + STM32_I2S_TXDR_REG, 0); + spin_unlock(&i2s->lock_fd); + } + + if (STM32_I2S_IS_SLAVE(i2s)) + ier |= I2S_IER_TIFREIE; + + regmap_update_bits(i2s->regmap, STM32_I2S_IER_REG, ier, ier); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (playback_flg) + regmap_update_bits(i2s->regmap, STM32_I2S_IER_REG, + I2S_IER_UDRIE, + (unsigned int)~I2S_IER_UDRIE); + else + regmap_update_bits(i2s->regmap, STM32_I2S_IER_REG, + I2S_IER_OVRIE, + (unsigned int)~I2S_IER_OVRIE); + + spin_lock(&i2s->lock_fd); + i2s->refcount--; + if (i2s->refcount) { + spin_unlock(&i2s->lock_fd); + break; + } + spin_unlock(&i2s->lock_fd); + dev_dbg(cpu_dai->dev, "stop I2S\n"); ret = regmap_update_bits(i2s->regmap, STM32_I2S_CR1_REG, @@ -641,10 +653,7 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } - cfg1_mask = I2S_CFG1_RXDMAEN; - if (playback_flg) - cfg1_mask = I2S_CFG1_TXDMAEN; - + cfg1_mask = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN; regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG, cfg1_mask, 0); break; @@ -662,10 +671,6 @@ static void stm32_i2s_shutdown(struct snd_pcm_substream *substream, i2s->substream = NULL; - spin_lock(&i2s->lock_fd); - i2s->refcount = 0; - spin_unlock(&i2s->lock_fd); - regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, I2S_CGFR_MCKOE, (unsigned int)~I2S_CGFR_MCKOE); } From 11d0f8ed6dc3e553b20329bc85f2a1aefb5f180f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 May 2017 01:27:48 +0000 Subject: [PATCH 078/418] ASoC: rsnd: add support graph base DT phase 1 To enable OF-graph base DT on rsnd driver, and to keep compatible previous normal sound card style, it need to support both "rcar_sound,dai" and "ports" (or "port") on DT. This patch modify rsnd_dai_of_node() to parse "rcar_sound,dai" and "ports" (or "port") as phase 1. It can detect graph base style, but do nothing at this point. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 39 ++++++++++++++++++++++++++++++++++++++- sound/soc/sh/rcar/rsnd.h | 2 +- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 3c47af1990cb..72a3139b70c3 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -774,6 +774,42 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, of_node_put(node); } +static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv, + int *is_graph) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *np = dev->of_node; + struct device_node *dai_node; + struct device_node *ret; + + *is_graph = 0; + + /* + * parse both previous dai (= rcar_sound,dai), and + * graph dai (= ports/port) + */ + dai_node = of_get_child_by_name(np, RSND_NODE_DAI); + if (dai_node) { + ret = dai_node; + goto of_node_compatible; + } + + ret = np; + + dai_node = of_graph_get_next_endpoint(np, NULL); + if (dai_node) + goto of_node_graph; + + return NULL; + +of_node_graph: + *is_graph = 1; +of_node_compatible: + of_node_put(dai_node); + + return ret; +} + static int rsnd_dai_probe(struct rsnd_priv *priv) { struct device_node *dai_node; @@ -785,9 +821,10 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) struct rsnd_dai *rdai; struct device *dev = rsnd_priv_to_dev(priv); int nr, dai_i, io_i; + int is_graph; int ret; - dai_node = rsnd_dai_of_node(priv); + dai_node = rsnd_dai_of_node(priv, &is_graph); nr = of_get_child_count(dai_node); if (!nr) { ret = -EINVAL; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index dbf4163427e8..4d8e0584b644 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -475,7 +476,6 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); int rsnd_dai_connect(struct rsnd_mod *mod, struct rsnd_dai_stream *io, enum rsnd_mod_type type); -#define rsnd_dai_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DAI) /* * R-Car Gen1/Gen2 From 4d4b334bda47f1b7b57f7aca9bc19b7e317d764d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 May 2017 01:28:06 +0000 Subject: [PATCH 079/418] ASoC: rsnd: add support graph base DT phase 2 To enable OF-graph base DT on rsnd driver, and to keep compatible previous normal sound card style, it need to support both "rcar_sound,dai" and "ports" (or "port") on DT. This patch parses both style. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 161 +++++++++++++++++++++------------------ 1 file changed, 85 insertions(+), 76 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 72a3139b70c3..41b2e782b0bf 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -810,33 +810,95 @@ of_node_compatible: return ret; } +static void __rsnd_dai_probe(struct rsnd_priv *priv, + struct device_node *dai_np, + int dai_i, int is_graph) +{ + struct device_node *playback, *capture; + struct rsnd_dai_stream *io_playback; + struct rsnd_dai_stream *io_capture; + struct snd_soc_dai_driver *drv; + struct rsnd_dai *rdai; + struct device *dev = rsnd_priv_to_dev(priv); + int io_i; + + rdai = rsnd_rdai_get(priv, dai_i); + drv = priv->daidrv + dai_i; + io_playback = &rdai->playback; + io_capture = &rdai->capture; + + snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i); + + rdai->priv = priv; + drv->name = rdai->name; + drv->ops = &rsnd_soc_dai_ops; + + snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE, + "DAI%d Playback", dai_i); + drv->playback.rates = RSND_RATES; + drv->playback.formats = RSND_FMTS; + drv->playback.channels_min = 2; + drv->playback.channels_max = 6; + drv->playback.stream_name = rdai->playback.name; + + snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE, + "DAI%d Capture", dai_i); + drv->capture.rates = RSND_RATES; + drv->capture.formats = RSND_FMTS; + drv->capture.channels_min = 2; + drv->capture.channels_max = 6; + drv->capture.stream_name = rdai->capture.name; + + rdai->playback.rdai = rdai; + rdai->capture.rdai = rdai; + rsnd_set_slot(rdai, 2, 1); /* default */ + + for (io_i = 0;; io_i++) { + playback = of_parse_phandle(dai_np, "playback", io_i); + capture = of_parse_phandle(dai_np, "capture", io_i); + + if (!playback && !capture) + break; + + rsnd_parse_connect_ssi(rdai, playback, capture); + rsnd_parse_connect_src(rdai, playback, capture); + rsnd_parse_connect_ctu(rdai, playback, capture); + rsnd_parse_connect_mix(rdai, playback, capture); + rsnd_parse_connect_dvc(rdai, playback, capture); + + of_node_put(playback); + of_node_put(capture); + } + + dev_dbg(dev, "%s (%s/%s)\n", rdai->name, + rsnd_io_to_mod_ssi(io_playback) ? "play" : " -- ", + rsnd_io_to_mod_ssi(io_capture) ? "capture" : " -- "); +} + static int rsnd_dai_probe(struct rsnd_priv *priv) { struct device_node *dai_node; struct device_node *dai_np; - struct device_node *playback, *capture; - struct rsnd_dai_stream *io_playback; - struct rsnd_dai_stream *io_capture; - struct snd_soc_dai_driver *rdrv, *drv; - struct rsnd_dai *rdai; + struct snd_soc_dai_driver *rdrv; struct device *dev = rsnd_priv_to_dev(priv); - int nr, dai_i, io_i; + struct rsnd_dai *rdai; + int nr; int is_graph; - int ret; + int dai_i; dai_node = rsnd_dai_of_node(priv, &is_graph); - nr = of_get_child_count(dai_node); - if (!nr) { - ret = -EINVAL; - goto rsnd_dai_probe_done; - } + if (is_graph) + nr = of_graph_get_endpoint_count(dai_node); + else + nr = of_get_child_count(dai_node); + + if (!nr) + return -EINVAL; rdrv = devm_kzalloc(dev, sizeof(*rdrv) * nr, GFP_KERNEL); rdai = devm_kzalloc(dev, sizeof(*rdai) * nr, GFP_KERNEL); - if (!rdrv || !rdai) { - ret = -ENOMEM; - goto rsnd_dai_probe_done; - } + if (!rdrv || !rdai) + return -ENOMEM; priv->rdai_nr = nr; priv->daidrv = rdrv; @@ -846,68 +908,15 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) * parse all dai */ dai_i = 0; - for_each_child_of_node(dai_node, dai_np) { - rdai = rsnd_rdai_get(priv, dai_i); - drv = rdrv + dai_i; - io_playback = &rdai->playback; - io_capture = &rdai->capture; - - snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i); - - rdai->priv = priv; - drv->name = rdai->name; - drv->ops = &rsnd_soc_dai_ops; - - snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE, - "DAI%d Playback", dai_i); - drv->playback.rates = RSND_RATES; - drv->playback.formats = RSND_FMTS; - drv->playback.channels_min = 2; - drv->playback.channels_max = 6; - drv->playback.stream_name = rdai->playback.name; - - snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE, - "DAI%d Capture", dai_i); - drv->capture.rates = RSND_RATES; - drv->capture.formats = RSND_FMTS; - drv->capture.channels_min = 2; - drv->capture.channels_max = 6; - drv->capture.stream_name = rdai->capture.name; - - rdai->playback.rdai = rdai; - rdai->capture.rdai = rdai; - rsnd_set_slot(rdai, 2, 1); /* default */ - - for (io_i = 0;; io_i++) { - playback = of_parse_phandle(dai_np, "playback", io_i); - capture = of_parse_phandle(dai_np, "capture", io_i); - - if (!playback && !capture) - break; - - rsnd_parse_connect_ssi(rdai, playback, capture); - rsnd_parse_connect_src(rdai, playback, capture); - rsnd_parse_connect_ctu(rdai, playback, capture); - rsnd_parse_connect_mix(rdai, playback, capture); - rsnd_parse_connect_dvc(rdai, playback, capture); - - of_node_put(playback); - of_node_put(capture); - } - - dai_i++; - - dev_dbg(dev, "%s (%s/%s)\n", rdai->name, - rsnd_io_to_mod_ssi(io_playback) ? "play" : " -- ", - rsnd_io_to_mod_ssi(io_capture) ? "capture" : " -- "); + if (is_graph) { + for_each_endpoint_of_node(dai_node, dai_np) + __rsnd_dai_probe(priv, dai_np, dai_i++, is_graph); + } else { + for_each_child_of_node(dai_node, dai_np) + __rsnd_dai_probe(priv, dai_np, dai_i++, is_graph); } - ret = 0; - -rsnd_dai_probe_done: - of_node_put(dai_node); - - return ret; + return 0; } /* From 7fa72cca39a042228965a578b9249216082591e0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 May 2017 01:28:22 +0000 Subject: [PATCH 080/418] ASoC: rsnd: add HDMI output support Renesas R-Car Gen3 can output HDMI sound if SSIU/SSI are connected to R-Car built-in HDMI device (R-Car Gen3 built-in HDMI device will be controlled by DRM/KMS driver). If SSIx was connected to HDMI0/1 on DT, SSI driver will detect it automatically by this patch. Note is that now Renesas R-Car sound driver is assuming that it is using OF-graph base simple card for HDMI sound. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/Kconfig | 2 +- sound/soc/sh/rcar/core.c | 7 +++-- sound/soc/sh/rcar/gen.c | 2 ++ sound/soc/sh/rcar/rsnd.h | 9 +++++++ sound/soc/sh/rcar/ssi.c | 58 ++++++++++++++++++++++++++++++++++++++++ sound/soc/sh/rcar/ssiu.c | 37 +++++++++++++++++++++++++ 6 files changed, 112 insertions(+), 3 deletions(-) diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 147ebecfed94..1aa5cd77ca24 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -38,7 +38,7 @@ config SND_SOC_RCAR tristate "R-Car series SRU/SCU/SSIU/SSI support" depends on COMMON_CLK depends on OF || COMPILE_TEST - select SND_SIMPLE_CARD + select SND_SIMPLE_CARD_UTILS select REGMAP_MMIO help This option enables R-Car SRU/SCU/SSIU/SSI sound support diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 41b2e782b0bf..080431543141 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -909,8 +909,11 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) */ dai_i = 0; if (is_graph) { - for_each_endpoint_of_node(dai_node, dai_np) - __rsnd_dai_probe(priv, dai_np, dai_i++, is_graph); + for_each_endpoint_of_node(dai_node, dai_np) { + __rsnd_dai_probe(priv, dai_np, dai_i, is_graph); + rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i); + dai_i++; + } } else { for_each_child_of_node(dai_node, dai_np) __rsnd_dai_probe(priv, dai_np, dai_i++, is_graph); diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 63b6d3c28021..99f93a17511e 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -219,6 +219,8 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) RSND_GEN_S_REG(SSI_SYS_STATUS5, 0x884), RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888), RSND_GEN_S_REG(SSI_SYS_STATUS7, 0x88c), + RSND_GEN_S_REG(HDMI0_SEL, 0x9e0), + RSND_GEN_S_REG(HDMI1_SEL, 0x9e4), /* FIXME: it needs SSI_MODE2/3 in the future */ RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 4d8e0584b644..037e33ffa69d 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -170,6 +170,8 @@ enum rsnd_reg { RSND_REG_SSI_SYS_STATUS5, RSND_REG_SSI_SYS_STATUS6, RSND_REG_SSI_SYS_STATUS7, + RSND_REG_HDMI0_SEL, + RSND_REG_HDMI1_SEL, /* SSI */ RSND_REG_SSICR, @@ -646,6 +648,13 @@ int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io); +#define RSND_SSI_HDMI_PORT0 0xf0 +#define RSND_SSI_HDMI_PORT1 0xf1 +int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io); +void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv, + struct device_node *endpoint, + int dai_i); + #define rsnd_ssi_is_pin_sharing(io) \ __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 135c5669f796..d0602c189736 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -11,6 +11,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include #include #include "rsnd.h" #define RSND_SSI_NAME_SIZE 16 @@ -81,6 +82,8 @@ struct rsnd_ssi { /* flags */ #define RSND_SSI_CLK_PIN_SHARE (1 << 0) #define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */ +#define RSND_SSI_HDMI0 (1 << 2) /* for HDMI0 */ +#define RSND_SSI_HDMI1 (1 << 3) /* for HDMI1 */ #define for_each_rsnd_ssi(pos, priv, i) \ for (i = 0; \ @@ -99,6 +102,20 @@ struct rsnd_ssi { #define rsnd_ssi_is_run_mods(mod, io) \ (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod))) +int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io) +{ + struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + + if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_HDMI0) + return RSND_SSI_HDMI_PORT0; + + if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_HDMI1) + return RSND_SSI_HDMI_PORT1; + + return 0; +} + int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) { struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); @@ -835,6 +852,47 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, of_node_put(node); } +static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv, + struct rsnd_dai_stream *io, + struct device_node *remote_ep) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); + struct rsnd_ssi *ssi; + + if (!mod) + return; + + ssi = rsnd_mod_to_ssi(mod); + + if (strstr(remote_ep->full_name, "hdmi0")) { + ssi->flags |= RSND_SSI_HDMI0; + dev_dbg(dev, "%s[%d] connected to HDMI0\n", + rsnd_mod_name(mod), rsnd_mod_id(mod)); + } + + if (strstr(remote_ep->full_name, "hdmi1")) { + ssi->flags |= RSND_SSI_HDMI1; + dev_dbg(dev, "%s[%d] connected to HDMI1\n", + rsnd_mod_name(mod), rsnd_mod_id(mod)); + } +} + +void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv, + struct device_node *endpoint, + int dai_i) +{ + struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); + struct device_node *remote_ep; + + remote_ep = of_graph_get_remote_endpoint(endpoint); + if (!remote_ep) + return; + + __rsnd_ssi_parse_hdmi_connection(priv, &rdai->playback, remote_ep); + __rsnd_ssi_parse_hdmi_connection(priv, &rdai->capture, remote_ep); +} + struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) { if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 14fafdaf1395..13d648ef1ed6 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -123,6 +123,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + int hdmi = rsnd_ssi_hdmi_port(io); int ret; ret = rsnd_ssiu_init(mod, io, priv); @@ -149,6 +150,42 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, rsnd_get_dalign(mod, io)); } + if (hdmi) { + enum rsnd_mod_type rsnd_ssi_array[] = { + RSND_MOD_SSIM1, + RSND_MOD_SSIM2, + RSND_MOD_SSIM3, + }; + struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *pos; + u32 val; + int i, shift; + + i = rsnd_mod_id(ssi_mod); + + /* output all same SSI as default */ + val = i << 16 | + i << 20 | + i << 24 | + i << 28 | + i; + + for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) { + shift = (i * 4) + 16; + val = (val & ~(0xF << shift)) | + rsnd_mod_id(pos) << shift; + } + + switch (hdmi) { + case RSND_SSI_HDMI_PORT0: + rsnd_mod_write(mod, HDMI0_SEL, val); + break; + case RSND_SSI_HDMI_PORT1: + rsnd_mod_write(mod, HDMI1_SEL, val); + break; + } + } + return 0; } From f839cc1cbd29f2160ef4e621b920e254cc84133a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 May 2017 20:04:23 +0200 Subject: [PATCH 081/418] ALSA: pcm: Use a common helper for PCM state check and hwsync The mostly same codes for checking the current PCM state and calling hwsync are found in a few places. This patch simplifies them by creating a common helper function. It also fixes a couple of cases where we missed the proper state check (e.g. PAUSED state wasn't handled in rewind and snd_pcm_hwsync()), too. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 153 +++++++++------------------------------- 1 file changed, 35 insertions(+), 118 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index f3a3580eb44c..93bd2c662c1d 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2431,6 +2431,30 @@ static int snd_pcm_release(struct inode *inode, struct file *file) return 0; } +/* check and update PCM state; return 0 or a negative error + * call this inside PCM lock + */ +static int do_pcm_hwsync(struct snd_pcm_substream *substream) +{ + switch (substream->runtime->status->state) { + case SNDRV_PCM_STATE_DRAINING: + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + return -EBADFD; + /* Fall through */ + case SNDRV_PCM_STATE_RUNNING: + return snd_pcm_update_hw_ptr(substream); + case SNDRV_PCM_STATE_PREPARED: + case SNDRV_PCM_STATE_PAUSED: + return 0; + case SNDRV_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + case SNDRV_PCM_STATE_XRUN: + return -EPIPE; + default: + return -EBADFD; + } +} + static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream, snd_pcm_uframes_t frames) { @@ -2443,25 +2467,9 @@ static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *subst return 0; snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_PREPARED: - break; - case SNDRV_PCM_STATE_DRAINING: - case SNDRV_PCM_STATE_RUNNING: - if (snd_pcm_update_hw_ptr(substream) >= 0) - break; - /* Fall through */ - case SNDRV_PCM_STATE_XRUN: - ret = -EPIPE; + ret = do_pcm_hwsync(substream); + if (ret < 0) goto __end; - case SNDRV_PCM_STATE_SUSPENDED: - ret = -ESTRPIPE; - goto __end; - default: - ret = -EBADFD; - goto __end; - } - hw_avail = snd_pcm_playback_hw_avail(runtime); if (hw_avail <= 0) { ret = 0; @@ -2491,25 +2499,9 @@ static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substr return 0; snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_PREPARED: - case SNDRV_PCM_STATE_DRAINING: - break; - case SNDRV_PCM_STATE_RUNNING: - if (snd_pcm_update_hw_ptr(substream) >= 0) - break; - /* Fall through */ - case SNDRV_PCM_STATE_XRUN: - ret = -EPIPE; + ret = do_pcm_hwsync(substream); + if (ret < 0) goto __end; - case SNDRV_PCM_STATE_SUSPENDED: - ret = -ESTRPIPE; - goto __end; - default: - ret = -EBADFD; - goto __end; - } - hw_avail = snd_pcm_capture_hw_avail(runtime); if (hw_avail <= 0) { ret = 0; @@ -2539,26 +2531,9 @@ static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *subs return 0; snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_PREPARED: - case SNDRV_PCM_STATE_PAUSED: - break; - case SNDRV_PCM_STATE_DRAINING: - case SNDRV_PCM_STATE_RUNNING: - if (snd_pcm_update_hw_ptr(substream) >= 0) - break; - /* Fall through */ - case SNDRV_PCM_STATE_XRUN: - ret = -EPIPE; + ret = do_pcm_hwsync(substream); + if (ret < 0) goto __end; - case SNDRV_PCM_STATE_SUSPENDED: - ret = -ESTRPIPE; - goto __end; - default: - ret = -EBADFD; - goto __end; - } - avail = snd_pcm_playback_avail(runtime); if (avail <= 0) { ret = 0; @@ -2588,26 +2563,9 @@ static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *subst return 0; snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_PREPARED: - case SNDRV_PCM_STATE_DRAINING: - case SNDRV_PCM_STATE_PAUSED: - break; - case SNDRV_PCM_STATE_RUNNING: - if (snd_pcm_update_hw_ptr(substream) >= 0) - break; - /* Fall through */ - case SNDRV_PCM_STATE_XRUN: - ret = -EPIPE; + ret = do_pcm_hwsync(substream); + if (ret < 0) goto __end; - case SNDRV_PCM_STATE_SUSPENDED: - ret = -ESTRPIPE; - goto __end; - default: - ret = -EBADFD; - goto __end; - } - avail = snd_pcm_capture_avail(runtime); if (avail <= 0) { ret = 0; @@ -2627,33 +2585,10 @@ static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *subst static int snd_pcm_hwsync(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; int err; snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_DRAINING: - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - goto __badfd; - /* Fall through */ - case SNDRV_PCM_STATE_RUNNING: - if ((err = snd_pcm_update_hw_ptr(substream)) < 0) - break; - /* Fall through */ - case SNDRV_PCM_STATE_PREPARED: - err = 0; - break; - case SNDRV_PCM_STATE_SUSPENDED: - err = -ESTRPIPE; - break; - case SNDRV_PCM_STATE_XRUN: - err = -EPIPE; - break; - default: - __badfd: - err = -EBADFD; - break; - } + err = do_pcm_hwsync(substream); snd_pcm_stream_unlock_irq(substream); return err; } @@ -2666,31 +2601,13 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream, snd_pcm_sframes_t n = 0; snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_DRAINING: - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - goto __badfd; - /* Fall through */ - case SNDRV_PCM_STATE_RUNNING: - if ((err = snd_pcm_update_hw_ptr(substream)) < 0) - break; - /* Fall through */ - case SNDRV_PCM_STATE_PREPARED: - case SNDRV_PCM_STATE_SUSPENDED: - err = 0; + err = do_pcm_hwsync(substream); + if (!err) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) n = snd_pcm_playback_hw_avail(runtime); else n = snd_pcm_capture_avail(runtime); n += runtime->delay; - break; - case SNDRV_PCM_STATE_XRUN: - err = -EPIPE; - break; - default: - __badfd: - err = -EBADFD; - break; } snd_pcm_stream_unlock_irq(substream); if (!err) From e0327a0f214154b517fa2b325acd8d42736ac95b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 May 2017 20:16:44 +0200 Subject: [PATCH 082/418] ALSA: pcm: Simplify forward/rewind codes Factor out the common codes in snd_pcm_*_forward() and *_rewind() functions to simplify the codes. No functional changes. Reviewd-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 118 +++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 68 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 93bd2c662c1d..ecde57afa45a 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2455,34 +2455,58 @@ static int do_pcm_hwsync(struct snd_pcm_substream *substream) } } +/* increase the appl_ptr; returns the processed frames */ +static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream, + snd_pcm_uframes_t frames, + snd_pcm_sframes_t avail) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_sframes_t appl_ptr; + + if (avail <= 0) + return 0; + if (frames > (snd_pcm_uframes_t)avail) + frames = avail; + appl_ptr = runtime->control->appl_ptr + frames; + if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) + appl_ptr -= runtime->boundary; + runtime->control->appl_ptr = appl_ptr; + return frames; +} + +/* decrease the appl_ptr; returns the processed frames */ +static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream, + snd_pcm_uframes_t frames, + snd_pcm_sframes_t avail) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_sframes_t appl_ptr; + + if (avail <= 0) + return 0; + if (frames > (snd_pcm_uframes_t)avail) + frames = avail; + appl_ptr = runtime->control->appl_ptr - frames; + if (appl_ptr < 0) + appl_ptr += runtime->boundary; + runtime->control->appl_ptr = appl_ptr; + return frames; +} + static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream, snd_pcm_uframes_t frames) { struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_sframes_t appl_ptr; snd_pcm_sframes_t ret; - snd_pcm_sframes_t hw_avail; if (frames == 0) return 0; snd_pcm_stream_lock_irq(substream); ret = do_pcm_hwsync(substream); - if (ret < 0) - goto __end; - hw_avail = snd_pcm_playback_hw_avail(runtime); - if (hw_avail <= 0) { - ret = 0; - goto __end; - } - if (frames > (snd_pcm_uframes_t)hw_avail) - frames = hw_avail; - appl_ptr = runtime->control->appl_ptr - frames; - if (appl_ptr < 0) - appl_ptr += runtime->boundary; - runtime->control->appl_ptr = appl_ptr; - ret = frames; - __end: + if (!ret) + ret = rewind_appl_ptr(substream, frames, + snd_pcm_playback_hw_avail(runtime)); snd_pcm_stream_unlock_irq(substream); return ret; } @@ -2491,30 +2515,16 @@ static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substr snd_pcm_uframes_t frames) { struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_sframes_t appl_ptr; snd_pcm_sframes_t ret; - snd_pcm_sframes_t hw_avail; if (frames == 0) return 0; snd_pcm_stream_lock_irq(substream); ret = do_pcm_hwsync(substream); - if (ret < 0) - goto __end; - hw_avail = snd_pcm_capture_hw_avail(runtime); - if (hw_avail <= 0) { - ret = 0; - goto __end; - } - if (frames > (snd_pcm_uframes_t)hw_avail) - frames = hw_avail; - appl_ptr = runtime->control->appl_ptr - frames; - if (appl_ptr < 0) - appl_ptr += runtime->boundary; - runtime->control->appl_ptr = appl_ptr; - ret = frames; - __end: + if (!ret) + ret = rewind_appl_ptr(substream, frames, + snd_pcm_capture_hw_avail(runtime)); snd_pcm_stream_unlock_irq(substream); return ret; } @@ -2523,30 +2533,16 @@ static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *subs snd_pcm_uframes_t frames) { struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_sframes_t appl_ptr; snd_pcm_sframes_t ret; - snd_pcm_sframes_t avail; if (frames == 0) return 0; snd_pcm_stream_lock_irq(substream); ret = do_pcm_hwsync(substream); - if (ret < 0) - goto __end; - avail = snd_pcm_playback_avail(runtime); - if (avail <= 0) { - ret = 0; - goto __end; - } - if (frames > (snd_pcm_uframes_t)avail) - frames = avail; - appl_ptr = runtime->control->appl_ptr + frames; - if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) - appl_ptr -= runtime->boundary; - runtime->control->appl_ptr = appl_ptr; - ret = frames; - __end: + if (!ret) + ret = forward_appl_ptr(substream, frames, + snd_pcm_playback_avail(runtime)); snd_pcm_stream_unlock_irq(substream); return ret; } @@ -2555,30 +2551,16 @@ static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *subst snd_pcm_uframes_t frames) { struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_sframes_t appl_ptr; snd_pcm_sframes_t ret; - snd_pcm_sframes_t avail; if (frames == 0) return 0; snd_pcm_stream_lock_irq(substream); ret = do_pcm_hwsync(substream); - if (ret < 0) - goto __end; - avail = snd_pcm_capture_avail(runtime); - if (avail <= 0) { - ret = 0; - goto __end; - } - if (frames > (snd_pcm_uframes_t)avail) - frames = avail; - appl_ptr = runtime->control->appl_ptr + frames; - if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) - appl_ptr -= runtime->boundary; - runtime->control->appl_ptr = appl_ptr; - ret = frames; - __end: + if (!ret) + ret = forward_appl_ptr(substream, frames, + snd_pcm_capture_avail(runtime)); snd_pcm_stream_unlock_irq(substream); return ret; } From 3a84d6c940e666d85b1c58bbcda2248c54faa898 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 17 May 2017 17:08:56 +0530 Subject: [PATCH 083/418] ALSA: sound/isa: constify snd_kcontrol_new structures Declare snd_kcontrol_new structures as const as they are only passed an argument to the function snd_ctl_new1. This argument is of type const, so snd_kcontrol_new structures having this property can be made const. Done using Coccinelle: @r disable optional_qualifier@ identifier x; position p; @@ static struct snd_kcontrol_new x@p={...}; @ok@ identifier r.x; position p; @@ snd_ctl_new1(&x@p,...) @bad@ position p != {r.p,ok.p}; identifier r.x; @@ x@p @depends on !bad disable optional_qualifier@ identifier r.x; @@ +const struct snd_kcontrol_new x; Signed-off-by: Bhumika Goyal Signed-off-by: Takashi Iwai --- sound/isa/gus/gus_main.c | 2 +- sound/isa/gus/gus_pcm.c | 4 ++-- sound/isa/sb/sb16_csp.c | 4 ++-- sound/isa/sb/sb16_main.c | 2 +- sound/isa/sscape.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index 4490ee442ff4..3cf9b13c780a 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c @@ -82,7 +82,7 @@ static int snd_gus_joystick_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el return change; } -static struct snd_kcontrol_new snd_gus_joystick_control = { +static const struct snd_kcontrol_new snd_gus_joystick_control = { .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = "Joystick Speed", .info = snd_gus_joystick_info, diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index 06505999155f..33c1891f469a 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c @@ -809,7 +809,7 @@ static int snd_gf1_pcm_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ return change; } -static struct snd_kcontrol_new snd_gf1_pcm_volume_control = +static const struct snd_kcontrol_new snd_gf1_pcm_volume_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Volume", @@ -818,7 +818,7 @@ static struct snd_kcontrol_new snd_gf1_pcm_volume_control = .put = snd_gf1_pcm_volume_put }; -static struct snd_kcontrol_new snd_gf1_pcm_volume_control1 = +static const struct snd_kcontrol_new snd_gf1_pcm_volume_control1 = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "GPCM Playback Volume", diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index 48da2276683d..fa5780bb0c68 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -1029,7 +1029,7 @@ static int snd_sb_qsound_space_put(struct snd_kcontrol *kcontrol, struct snd_ctl return change; } -static struct snd_kcontrol_new snd_sb_qsound_switch = { +static const struct snd_kcontrol_new snd_sb_qsound_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "3D Control - Switch", .info = snd_sb_qsound_switch_info, @@ -1037,7 +1037,7 @@ static struct snd_kcontrol_new snd_sb_qsound_switch = { .put = snd_sb_qsound_switch_put }; -static struct snd_kcontrol_new snd_sb_qsound_space = { +static const struct snd_kcontrol_new snd_sb_qsound_space = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "3D Control - Space", .info = snd_sb_qsound_space_info, diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c index 8b2d6c6bfe97..4be1350f6649 100644 --- a/sound/isa/sb/sb16_main.c +++ b/sound/isa/sb/sb16_main.c @@ -737,7 +737,7 @@ static int snd_sb16_dma_control_put(struct snd_kcontrol *kcontrol, struct snd_ct return change; } -static struct snd_kcontrol_new snd_sb16_dma_control = { +static const struct snd_kcontrol_new snd_sb16_dma_control = { .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = "16-bit DMA Allocation", .info = snd_sb16_dma_control_info, diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 54f5758a1bb3..1cd2908e4f12 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -671,7 +671,7 @@ __skip_change: return change; } -static struct snd_kcontrol_new midi_mixer_ctl = { +static const struct snd_kcontrol_new midi_mixer_ctl = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "MIDI", .info = sscape_midi_info, From 6ba1ad386c30487aaa18a56da71fa12591131dd6 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 17 May 2017 17:20:46 +0530 Subject: [PATCH 084/418] ALSA: ice1712: constify snd_kcontrol_new structures Declare snd_kcontrol_new structures as const as they are only passed an argument to the function snd_ctl_new1. This argument is of type const, so snd_kcontrol_new structures having this property can be made const. Done using Coccinelle: @r disable optional_qualifier@ identifier x; position p; @@ static struct snd_kcontrol_new x@p={...}; @ok@ identifier r.x; position p; @@ snd_ctl_new1(&x@p,...) @bad@ position p != {r.p,ok.p}; identifier r.x; @@ x@p @depends on !bad disable optional_qualifier@ identifier r.x; @@ +const struct snd_kcontrol_new x; Signed-off-by: Bhumika Goyal Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1712.c | 6 +++--- sound/pci/ice1712/ice1724.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 1d8612cabb9e..6b650ab2a084 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -1401,7 +1401,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] = { }, }; -static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch = { +static const struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "H/W Multi Capture Switch", .info = snd_ice1712_pro_mixer_switch_info, @@ -1420,7 +1420,7 @@ static const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch = { .count = 2, }; -static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume = { +static const struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), @@ -2165,7 +2165,7 @@ static int snd_ice1712_pro_route_spdif_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route = { +static const struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "H/W Playback Route", .info = snd_ice1712_pro_route_info, diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 9cd6e55c0642..785188140f6b 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -2142,7 +2142,7 @@ static int snd_vt1724_pro_route_spdif_put(struct snd_kcontrol *kcontrol, digital_route_shift(idx)); } -static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route = +static const struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "H/W Playback Route", From 30b5817e092159feb36b29eb5d7b31e28866280e Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 17 May 2017 17:39:03 +0530 Subject: [PATCH 085/418] ALSA: cs46xx: constify snd_kcontrol_new structures Declare snd_kcontrol_new structures as const as they are only passed an argument to the function snd_ctl_new1. This argument is of type const, so snd_kcontrol_new structures having this property can be made const. Done using Coccinelle: @r disable optional_qualifier@ identifier x; position p; @@ static struct snd_kcontrol_new x@p={...}; @ok@ identifier r.x; position p; @@ snd_ctl_new1(&x@p,...) @bad@ position p != {r.p,ok.p}; identifier r.x; @@ x@p @depends on !bad disable optional_qualifier@ identifier r.x; @@ +const struct snd_kcontrol_new x; Signed-off-by: Bhumika Goyal Signed-off-by: Takashi Iwai --- sound/pci/cs46xx/cs46xx_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index e4cf3187b4dd..00fa52e9a2f2 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -2371,7 +2371,7 @@ static int snd_cs46xx_front_dup_put(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] ? 0 : 0x200); } -static struct snd_kcontrol_new snd_cs46xx_front_dup_ctl = { +static const struct snd_kcontrol_new snd_cs46xx_front_dup_ctl = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Duplicate Front", .info = snd_mixer_boolean_info, From 665170f73101e2e52c15495d606df5d1da478697 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 17 May 2017 17:43:30 +0530 Subject: [PATCH 086/418] ALSA: mixart: constify snd_kcontrol_new structures Declare snd_kcontrol_new structures as const as they are only passed an argument to the function snd_ctl_new1. This argument is of type const, so snd_kcontrol_new structures having this property can be made const. Done using Coccinelle: @r disable optional_qualifier@ identifier x; position p; @@ static struct snd_kcontrol_new x@p={...}; @ok@ identifier r.x; position p; @@ snd_ctl_new1(&x@p,...) @bad@ position p != {r.p,ok.p}; identifier r.x; @@ x@p @depends on !bad disable optional_qualifier@ identifier r.x; @@ +const struct snd_kcontrol_new x; Signed-off-by: Bhumika Goyal Signed-off-by: Takashi Iwai --- sound/pci/mixart/mixart_mixer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c index 4a4616aac787..2b9496a66c77 100644 --- a/sound/pci/mixart/mixart_mixer.c +++ b/sound/pci/mixart/mixart_mixer.c @@ -404,7 +404,7 @@ static int mixart_analog_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e static const DECLARE_TLV_DB_SCALE(db_scale_analog, -9600, 50, 0); -static struct snd_kcontrol_new mixart_control_analog_level = { +static const struct snd_kcontrol_new mixart_control_analog_level = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), @@ -897,7 +897,7 @@ static int mixart_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem static const DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0); -static struct snd_kcontrol_new snd_mixart_pcm_vol = +static const struct snd_kcontrol_new snd_mixart_pcm_vol = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -951,7 +951,7 @@ static int mixart_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ return changed; } -static struct snd_kcontrol_new mixart_control_pcm_switch = { +static const struct snd_kcontrol_new mixart_control_pcm_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* name will be filled later */ .count = MIXART_PLAYBACK_STREAMS, From a02cb8f8def634159b60c3a4d6ba16e471b46e0c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 May 2017 22:22:21 +0900 Subject: [PATCH 087/418] ALSA: firewire: remove support for 16 bit PCM samples in playback substream In IEC 61883-6, AM824 is described as format of data block. In this format, one data block consists of several data channels, which is aligned to 32 bit. One data channel has 8 bit label field and 24 bit data field. PCM frames are transferred in Multi Bit Linear Audio (MBLA) data channel. This channel can include 16/20/24 bit PCM sample. As long as I know, models which support IEC 61883-1/6 doesn't allow to switch bit length of PCM sample in MBLA data channel. They always transmit/receive PCM frames of 24 bit length. This can be seen for the other models which support protocols similar to IEC 61883-1/6. On the other hand, current drivers for these protocols supports 16 bit length PCM sample in playback substream. In this case, PCM sample is put into the MBLA data channel with 8 bit padding in LSB side. Although 16 bit PCM sample is major because it's in CD format, this doesn't represent device capability as is. This commit removes support for 16 bit PCM samples in playback substream. Signed-off-by: Takashi Sakamoto Acked-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-am824.c | 71 +----------------------- sound/firewire/amdtp-am824.h | 6 +- sound/firewire/bebob/bebob_pcm.c | 4 -- sound/firewire/dice/dice-pcm.c | 6 -- sound/firewire/digi00x/amdtp-dot.c | 63 +-------------------- sound/firewire/digi00x/digi00x-pcm.c | 7 +-- sound/firewire/digi00x/digi00x.h | 1 - sound/firewire/fireworks/fireworks_pcm.c | 4 -- sound/firewire/oxfw/oxfw-pcm.c | 4 -- sound/firewire/tascam/amdtp-tascam.c | 62 +-------------------- sound/firewire/tascam/tascam-pcm.c | 7 +-- sound/firewire/tascam/tascam.h | 1 - 12 files changed, 9 insertions(+), 227 deletions(-) diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c index bebddc60fde8..23ccddb20de1 100644 --- a/sound/firewire/amdtp-am824.c +++ b/sound/firewire/amdtp-am824.c @@ -38,10 +38,6 @@ struct amdtp_am824 { u8 pcm_positions[AM824_MAX_CHANNELS_FOR_PCM]; u8 midi_position; - void (*transfer_samples)(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames); - unsigned int frame_multiplier; }; @@ -177,32 +173,6 @@ static void write_pcm_s32(struct amdtp_stream *s, } } -static void write_pcm_s16(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames) -{ - struct amdtp_am824 *p = s->protocol; - struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, i, c; - const u16 *src; - - channels = p->pcm_channels; - src = (void *)runtime->dma_area + - frames_to_bytes(runtime, s->pcm_buffer_pointer); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; - - for (i = 0; i < frames; ++i) { - for (c = 0; c < channels; ++c) { - buffer[p->pcm_positions[c]] = - cpu_to_be32((*src << 8) | 0x42000000); - src++; - } - buffer += s->data_block_quadlets; - if (--remaining_frames == 0) - src = (void *)runtime->dma_area; - } -} - static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, __be32 *buffer, unsigned int frames) @@ -241,43 +211,6 @@ static void write_pcm_silence(struct amdtp_stream *s, } } -/** - * amdtp_am824_set_pcm_format - set the PCM format - * @s: the AMDTP stream to configure - * @format: the format of the ALSA PCM device - * - * The sample format must be set after the other parameters (rate/PCM channels/ - * MIDI) and before the stream is started, and must not be changed while the - * stream is running. - */ -void amdtp_am824_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format) -{ - struct amdtp_am824 *p = s->protocol; - - if (WARN_ON(amdtp_stream_pcm_running(s))) - return; - - switch (format) { - default: - WARN_ON(1); - /* fall through */ - case SNDRV_PCM_FORMAT_S16: - if (s->direction == AMDTP_OUT_STREAM) { - p->transfer_samples = write_pcm_s16; - break; - } - WARN_ON(1); - /* fall through */ - case SNDRV_PCM_FORMAT_S32: - if (s->direction == AMDTP_OUT_STREAM) - p->transfer_samples = write_pcm_s32; - else - p->transfer_samples = read_pcm_s32; - break; - } -} -EXPORT_SYMBOL_GPL(amdtp_am824_set_pcm_format); - /** * amdtp_am824_add_pcm_hw_constraints - add hw constraints for PCM substream * @s: the AMDTP stream for AM824 data block, must be initialized. @@ -407,7 +340,7 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, __be32 *buffe unsigned int pcm_frames; if (pcm) { - p->transfer_samples(s, pcm, buffer, data_blocks); + write_pcm_s32(s, pcm, buffer, data_blocks); pcm_frames = data_blocks * p->frame_multiplier; } else { write_pcm_silence(s, buffer, data_blocks); @@ -428,7 +361,7 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, __be32 *buffe unsigned int pcm_frames; if (pcm) { - p->transfer_samples(s, pcm, buffer, data_blocks); + read_pcm_s32(s, pcm, buffer, data_blocks); pcm_frames = data_blocks * p->frame_multiplier; } else { pcm_frames = 0; diff --git a/sound/firewire/amdtp-am824.h b/sound/firewire/amdtp-am824.h index 73b07b3109db..b56e61fc997d 100644 --- a/sound/firewire/amdtp-am824.h +++ b/sound/firewire/amdtp-am824.h @@ -8,8 +8,7 @@ #define AM824_IN_PCM_FORMAT_BITS SNDRV_PCM_FMTBIT_S32 -#define AM824_OUT_PCM_FORMAT_BITS (SNDRV_PCM_FMTBIT_S16 | \ - SNDRV_PCM_FMTBIT_S32) +#define AM824_OUT_PCM_FORMAT_BITS SNDRV_PCM_FMTBIT_S32 /* * This module supports maximum 64 PCM channels for one PCM stream @@ -41,9 +40,6 @@ void amdtp_am824_set_midi_position(struct amdtp_stream *s, int amdtp_am824_add_pcm_hw_constraints(struct amdtp_stream *s, struct snd_pcm_runtime *runtime); -void amdtp_am824_set_pcm_format(struct amdtp_stream *s, - snd_pcm_format_t format); - void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port, struct snd_rawmidi_substream *midi); diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index 9e27eb8e1dd4..e2f023f3cd9f 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -224,8 +224,6 @@ pcm_capture_hw_params(struct snd_pcm_substream *substream, mutex_unlock(&bebob->mutex); } - amdtp_am824_set_pcm_format(&bebob->tx_stream, params_format(hw_params)); - return 0; } static int @@ -246,8 +244,6 @@ pcm_playback_hw_params(struct snd_pcm_substream *substream, mutex_unlock(&bebob->mutex); } - amdtp_am824_set_pcm_format(&bebob->rx_stream, params_format(hw_params)); - return 0; } diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 6074fe1f00f7..b633805a885f 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -146,7 +146,6 @@ static int capture_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_dice *dice = substream->private_data; - struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; int err; err = snd_pcm_lib_alloc_vmalloc_buffer(substream, @@ -160,15 +159,12 @@ static int capture_hw_params(struct snd_pcm_substream *substream, mutex_unlock(&dice->mutex); } - amdtp_am824_set_pcm_format(stream, params_format(hw_params)); - return 0; } static int playback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_dice *dice = substream->private_data; - struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; int err; err = snd_pcm_lib_alloc_vmalloc_buffer(substream, @@ -182,8 +178,6 @@ static int playback_hw_params(struct snd_pcm_substream *substream, mutex_unlock(&dice->mutex); } - amdtp_am824_set_pcm_format(stream, params_format(hw_params)); - return 0; } diff --git a/sound/firewire/digi00x/amdtp-dot.c b/sound/firewire/digi00x/amdtp-dot.c index a4688545339c..1453c34ce99f 100644 --- a/sound/firewire/digi00x/amdtp-dot.c +++ b/sound/firewire/digi00x/amdtp-dot.c @@ -48,10 +48,6 @@ struct amdtp_dot { struct snd_rawmidi_substream *midi[MAX_MIDI_PORTS]; int midi_fifo_used[MAX_MIDI_PORTS]; int midi_fifo_limit; - - void (*transfer_samples)(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames); }; /* @@ -173,32 +169,6 @@ static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, } } -static void write_pcm_s16(struct amdtp_stream *s, struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames) -{ - struct amdtp_dot *p = s->protocol; - struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, i, c; - const u16 *src; - - channels = p->pcm_channels; - src = (void *)runtime->dma_area + - frames_to_bytes(runtime, s->pcm_buffer_pointer); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; - - buffer++; - for (i = 0; i < frames; ++i) { - for (c = 0; c < channels; ++c) { - buffer[c] = cpu_to_be32((*src << 8) | 0x40000000); - dot_encode_step(&p->state, &buffer[c]); - src++; - } - buffer += s->data_block_quadlets; - if (--remaining_frames == 0) - src = (void *)runtime->dma_area; - } -} - static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, __be32 *buffer, unsigned int frames) { @@ -351,33 +321,6 @@ int amdtp_dot_add_pcm_hw_constraints(struct amdtp_stream *s, return amdtp_stream_add_pcm_hw_constraints(s, runtime); } -void amdtp_dot_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format) -{ - struct amdtp_dot *p = s->protocol; - - if (WARN_ON(amdtp_stream_pcm_running(s))) - return; - - switch (format) { - default: - WARN_ON(1); - /* fall through */ - case SNDRV_PCM_FORMAT_S16: - if (s->direction == AMDTP_OUT_STREAM) { - p->transfer_samples = write_pcm_s16; - break; - } - WARN_ON(1); - /* fall through */ - case SNDRV_PCM_FORMAT_S32: - if (s->direction == AMDTP_OUT_STREAM) - p->transfer_samples = write_pcm_s32; - else - p->transfer_samples = read_pcm_s32; - break; - } -} - void amdtp_dot_midi_trigger(struct amdtp_stream *s, unsigned int port, struct snd_rawmidi_substream *midi) { @@ -392,13 +335,12 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, unsigned int data_blocks, unsigned int *syt) { - struct amdtp_dot *p = (struct amdtp_dot *)s->protocol; struct snd_pcm_substream *pcm; unsigned int pcm_frames; pcm = ACCESS_ONCE(s->pcm); if (pcm) { - p->transfer_samples(s, pcm, buffer, data_blocks); + read_pcm_s32(s, pcm, buffer, data_blocks); pcm_frames = data_blocks; } else { pcm_frames = 0; @@ -414,13 +356,12 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, unsigned int data_blocks, unsigned int *syt) { - struct amdtp_dot *p = (struct amdtp_dot *)s->protocol; struct snd_pcm_substream *pcm; unsigned int pcm_frames; pcm = ACCESS_ONCE(s->pcm); if (pcm) { - p->transfer_samples(s, pcm, buffer, data_blocks); + write_pcm_s32(s, pcm, buffer, data_blocks); pcm_frames = data_blocks; } else { write_pcm_silence(s, buffer, data_blocks); diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c index 68d1c52db051..6379f67416d7 100644 --- a/sound/firewire/digi00x/digi00x-pcm.c +++ b/sound/firewire/digi00x/digi00x-pcm.c @@ -88,8 +88,7 @@ static int pcm_init_hw_params(struct snd_dg00x *dg00x, substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S32; s = &dg00x->tx_stream; } else { - substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S16 | - SNDRV_PCM_FMTBIT_S32; + substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S32; s = &dg00x->rx_stream; } @@ -184,8 +183,6 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, mutex_unlock(&dg00x->mutex); } - amdtp_dot_set_pcm_format(&dg00x->tx_stream, params_format(hw_params)); - return 0; } @@ -206,8 +203,6 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream, mutex_unlock(&dg00x->mutex); } - amdtp_dot_set_pcm_format(&dg00x->rx_stream, params_format(hw_params)); - return 0; } diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h index 1275a50956c0..4dd1bbf2ed3c 100644 --- a/sound/firewire/digi00x/digi00x.h +++ b/sound/firewire/digi00x/digi00x.h @@ -121,7 +121,6 @@ int amdtp_dot_set_parameters(struct amdtp_stream *s, unsigned int rate, void amdtp_dot_reset(struct amdtp_stream *s); int amdtp_dot_add_pcm_hw_constraints(struct amdtp_stream *s, struct snd_pcm_runtime *runtime); -void amdtp_dot_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format); void amdtp_dot_midi_trigger(struct amdtp_stream *s, unsigned int port, struct snd_rawmidi_substream *midi); diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index 9171702f7d0b..f10aec117998 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -257,8 +257,6 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, mutex_unlock(&efw->mutex); } - amdtp_am824_set_pcm_format(&efw->tx_stream, params_format(hw_params)); - return 0; } static int pcm_playback_hw_params(struct snd_pcm_substream *substream, @@ -278,8 +276,6 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream, mutex_unlock(&efw->mutex); } - amdtp_am824_set_pcm_format(&efw->rx_stream, params_format(hw_params)); - return 0; } diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index f3530f89a025..d4594f7115ae 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -244,8 +244,6 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, mutex_unlock(&oxfw->mutex); } - amdtp_am824_set_pcm_format(&oxfw->tx_stream, params_format(hw_params)); - return 0; } static int pcm_playback_hw_params(struct snd_pcm_substream *substream, @@ -265,8 +263,6 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream, mutex_unlock(&oxfw->mutex); } - amdtp_am824_set_pcm_format(&oxfw->rx_stream, params_format(hw_params)); - return 0; } diff --git a/sound/firewire/tascam/amdtp-tascam.c b/sound/firewire/tascam/amdtp-tascam.c index 9dd0fccd5ccc..6aff1fc1c72d 100644 --- a/sound/firewire/tascam/amdtp-tascam.c +++ b/sound/firewire/tascam/amdtp-tascam.c @@ -14,10 +14,6 @@ struct amdtp_tscm { unsigned int pcm_channels; - - void (*transfer_samples)(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames); }; int amdtp_tscm_set_parameters(struct amdtp_stream *s, unsigned int rate) @@ -62,31 +58,6 @@ static void write_pcm_s32(struct amdtp_stream *s, } } -static void write_pcm_s16(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames) -{ - struct amdtp_tscm *p = s->protocol; - struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, i, c; - const u16 *src; - - channels = p->pcm_channels; - src = (void *)runtime->dma_area + - frames_to_bytes(runtime, s->pcm_buffer_pointer); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; - - for (i = 0; i < frames; ++i) { - for (c = 0; c < channels; ++c) { - buffer[c] = cpu_to_be32(*src << 16); - src++; - } - buffer += s->data_block_quadlets; - if (--remaining_frames == 0) - src = (void *)runtime->dma_area; - } -} - static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, __be32 *buffer, unsigned int frames) @@ -146,44 +117,16 @@ int amdtp_tscm_add_pcm_hw_constraints(struct amdtp_stream *s, return amdtp_stream_add_pcm_hw_constraints(s, runtime); } -void amdtp_tscm_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format) -{ - struct amdtp_tscm *p = s->protocol; - - if (WARN_ON(amdtp_stream_pcm_running(s))) - return; - - switch (format) { - default: - WARN_ON(1); - /* fall through */ - case SNDRV_PCM_FORMAT_S16: - if (s->direction == AMDTP_OUT_STREAM) { - p->transfer_samples = write_pcm_s16; - break; - } - WARN_ON(1); - /* fall through */ - case SNDRV_PCM_FORMAT_S32: - if (s->direction == AMDTP_OUT_STREAM) - p->transfer_samples = write_pcm_s32; - else - p->transfer_samples = read_pcm_s32; - break; - } -} - static unsigned int process_tx_data_blocks(struct amdtp_stream *s, __be32 *buffer, unsigned int data_blocks, unsigned int *syt) { - struct amdtp_tscm *p = (struct amdtp_tscm *)s->protocol; struct snd_pcm_substream *pcm; pcm = ACCESS_ONCE(s->pcm); if (data_blocks > 0 && pcm) - p->transfer_samples(s, pcm, buffer, data_blocks); + read_pcm_s32(s, pcm, buffer, data_blocks); /* A place holder for control messages. */ @@ -195,7 +138,6 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, unsigned int data_blocks, unsigned int *syt) { - struct amdtp_tscm *p = (struct amdtp_tscm *)s->protocol; struct snd_pcm_substream *pcm; /* This field is not used. */ @@ -203,7 +145,7 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, pcm = ACCESS_ONCE(s->pcm); if (pcm) - p->transfer_samples(s, pcm, buffer, data_blocks); + write_pcm_s32(s, pcm, buffer, data_blocks); else write_pcm_silence(s, buffer, data_blocks); diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c index f5dd6ce6b6f1..6207588d7c73 100644 --- a/sound/firewire/tascam/tascam-pcm.c +++ b/sound/firewire/tascam/tascam-pcm.c @@ -48,8 +48,7 @@ static int pcm_init_hw_params(struct snd_tscm *tscm, stream = &tscm->tx_stream; pcm_channels = tscm->spec->pcm_capture_analog_channels; } else { - runtime->hw.formats = - SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S32; + runtime->hw.formats = SNDRV_PCM_FMTBIT_S32; stream = &tscm->rx_stream; pcm_channels = tscm->spec->pcm_playback_analog_channels; } @@ -125,8 +124,6 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, mutex_unlock(&tscm->mutex); } - amdtp_tscm_set_pcm_format(&tscm->tx_stream, params_format(hw_params)); - return 0; } @@ -147,8 +144,6 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream, mutex_unlock(&tscm->mutex); } - amdtp_tscm_set_pcm_format(&tscm->rx_stream, params_format(hw_params)); - return 0; } diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h index 08ecfae5c584..a5bd167eb5d9 100644 --- a/sound/firewire/tascam/tascam.h +++ b/sound/firewire/tascam/tascam.h @@ -131,7 +131,6 @@ int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit, int amdtp_tscm_set_parameters(struct amdtp_stream *s, unsigned int rate); int amdtp_tscm_add_pcm_hw_constraints(struct amdtp_stream *s, struct snd_pcm_runtime *runtime); -void amdtp_tscm_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format); int snd_tscm_stream_get_rate(struct snd_tscm *tscm, unsigned int *rate); int snd_tscm_stream_get_clock(struct snd_tscm *tscm, From 53e7bf452584e73df8a529a2b157a1225a52637f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 22 May 2017 17:43:04 +0200 Subject: [PATCH 088/418] ALSA: control: Simplify snd_ctl_elem_list() implementation This patch simplifies the code of snd_ctl_elem_list() in the following ways: - Avoid a vmalloc() temporary buffer but do copy in each iteration; the vmalloc buffer was introduced at the time we took the spinlock for the ctl element management. - Use the standard list_for_each_entry() macro - Merge two loops into one; it used to be a loop for skipping until offset becomes zero and another loop to copy the data. They can be folded into a single loop easily. Reviewed-by: Takashi Sakamoto Tested-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/control.c | 68 ++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 43 deletions(-) diff --git a/sound/core/control.c b/sound/core/control.c index c109b82eef4b..47080da8451a 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -747,11 +747,11 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl, static int snd_ctl_elem_list(struct snd_card *card, struct snd_ctl_elem_list __user *_list) { - struct list_head *plist; struct snd_ctl_elem_list list; struct snd_kcontrol *kctl; - struct snd_ctl_elem_id *dst, *id; + struct snd_ctl_elem_id id; unsigned int offset, space, jidx; + int err = 0; if (copy_from_user(&list, _list, sizeof(list))) return -EFAULT; @@ -760,52 +760,34 @@ static int snd_ctl_elem_list(struct snd_card *card, /* try limit maximum space */ if (space > 16384) return -ENOMEM; + down_read(&card->controls_rwsem); + list.count = card->controls_count; + list.used = 0; if (space > 0) { - /* allocate temporary buffer for atomic operation */ - dst = vmalloc(space * sizeof(struct snd_ctl_elem_id)); - if (dst == NULL) - return -ENOMEM; - down_read(&card->controls_rwsem); - list.count = card->controls_count; - plist = card->controls.next; - while (plist != &card->controls) { - if (offset == 0) - break; - kctl = snd_kcontrol(plist); - if (offset < kctl->count) - break; - offset -= kctl->count; - plist = plist->next; - } - list.used = 0; - id = dst; - while (space > 0 && plist != &card->controls) { - kctl = snd_kcontrol(plist); - for (jidx = offset; space > 0 && jidx < kctl->count; jidx++) { - snd_ctl_build_ioff(id, kctl, jidx); - id++; - space--; - list.used++; + list_for_each_entry(kctl, &card->controls, list) { + if (offset >= kctl->count) { + offset -= kctl->count; + continue; + } + for (jidx = offset; jidx < kctl->count; jidx++) { + snd_ctl_build_ioff(&id, kctl, jidx); + if (copy_to_user(list.pids + list.used, &id, + sizeof(id))) { + err = -EFAULT; + goto out; + } + list.used++; + if (!--space) + goto out; } - plist = plist->next; offset = 0; } - up_read(&card->controls_rwsem); - if (list.used > 0 && - copy_to_user(list.pids, dst, - list.used * sizeof(struct snd_ctl_elem_id))) { - vfree(dst); - return -EFAULT; - } - vfree(dst); - } else { - down_read(&card->controls_rwsem); - list.count = card->controls_count; - up_read(&card->controls_rwsem); } - if (copy_to_user(_list, &list, sizeof(list))) - return -EFAULT; - return 0; + out: + up_read(&card->controls_rwsem); + if (!err && copy_to_user(_list, &list, sizeof(list))) + err = -EFAULT; + return err; } static bool validate_element_member_dimension(struct snd_ctl_elem_info *info) From c2c86a97175f552fd32b339426a489c7af818123 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 14:33:44 +0200 Subject: [PATCH 089/418] ALSA: pcm: Remove set_fs() in PCM core code PCM core code has a few usages of set_fs(), mostly for two codepaths: - The DELAY ioctl call from pcm_compat.c - The ioctl wrapper in kernel context for PCM OSS and other This patch removes the set_fs() usage in these places by a slight code refactoring. For the former point, snd_pcm_delay() is changed to return the value directly instead of putting the value to the given address. Each caller stores the result in an appropriate manner. For fixing the latter, snd_pcm_lib_kernel_ioctl() is changed to call the functions directly as well. For achieving it, now the function accepts only the limited set of ioctls that have been used, so far. The primary user of this function is the PCM OSS layer, and the only other user is USB UAC1 gadget driver. Both drivers don't need the full set of ioctls. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_compat.c | 12 ++--- sound/core/pcm_native.c | 104 ++++++++++++++++++++++++---------------- 2 files changed, 68 insertions(+), 48 deletions(-) diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 1f64ab0c2a95..8a0f8d51e95d 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -27,17 +27,13 @@ static int snd_pcm_ioctl_delay_compat(struct snd_pcm_substream *substream, s32 __user *src) { snd_pcm_sframes_t delay; - mm_segment_t fs; - int err; - fs = snd_enter_user(); - err = snd_pcm_delay(substream, &delay); - snd_leave_user(fs); - if (err < 0) - return err; + delay = snd_pcm_delay(substream); + if (delay < 0) + return delay; if (put_user(delay, src)) return -EFAULT; - return err; + return 0; } static int snd_pcm_ioctl_rewind_compat(struct snd_pcm_substream *substream, diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index ecde57afa45a..889364cbced8 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -181,20 +181,6 @@ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, } EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore); -static inline mm_segment_t snd_enter_user(void) -{ - mm_segment_t fs = get_fs(); - set_fs(get_ds()); - return fs; -} - -static inline void snd_leave_user(mm_segment_t fs) -{ - set_fs(fs); -} - - - int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) { struct snd_pcm_runtime *runtime; @@ -1081,6 +1067,7 @@ static const struct action_ops snd_pcm_action_start = { * @substream: the PCM substream instance * * Return: Zero if successful, or a negative error code. + * The stream lock must be acquired before calling this function. */ int snd_pcm_start(struct snd_pcm_substream *substream) { @@ -1088,6 +1075,13 @@ int snd_pcm_start(struct snd_pcm_substream *substream) SNDRV_PCM_STATE_RUNNING); } +/* take the stream lock and start the streams */ +static int snd_pcm_start_lock_irq(struct snd_pcm_substream *substream) +{ + return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, + SNDRV_PCM_STATE_RUNNING); +} + /* * stop callbacks */ @@ -2575,8 +2569,7 @@ static int snd_pcm_hwsync(struct snd_pcm_substream *substream) return err; } -static int snd_pcm_delay(struct snd_pcm_substream *substream, - snd_pcm_sframes_t __user *res) +static snd_pcm_sframes_t snd_pcm_delay(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; int err; @@ -2592,10 +2585,7 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream, n += runtime->delay; } snd_pcm_stream_unlock_irq(substream); - if (!err) - if (put_user(n, res)) - err = -EFAULT; - return err; + return err < 0 ? err : n; } static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, @@ -2683,7 +2673,7 @@ static int snd_pcm_common_ioctl1(struct file *file, case SNDRV_PCM_IOCTL_RESET: return snd_pcm_reset(substream); case SNDRV_PCM_IOCTL_START: - return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING); + return snd_pcm_start_lock_irq(substream); case SNDRV_PCM_IOCTL_LINK: return snd_pcm_link(substream, (int)(unsigned long) arg); case SNDRV_PCM_IOCTL_UNLINK: @@ -2695,7 +2685,16 @@ static int snd_pcm_common_ioctl1(struct file *file, case SNDRV_PCM_IOCTL_HWSYNC: return snd_pcm_hwsync(substream); case SNDRV_PCM_IOCTL_DELAY: - return snd_pcm_delay(substream, arg); + { + snd_pcm_sframes_t delay = snd_pcm_delay(substream); + snd_pcm_sframes_t __user *res = arg; + + if (delay < 0) + return delay; + if (put_user(delay, res)) + return -EFAULT; + return 0; + } case SNDRV_PCM_IOCTL_SYNC_PTR: return snd_pcm_sync_ptr(substream, arg); #ifdef CONFIG_SND_SUPPORT_OLD_API @@ -2909,30 +2908,55 @@ static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, (void __user *)arg); } +/** + * snd_pcm_kernel_ioctl - Execute PCM ioctl in the kernel-space + * @substream: PCM substream + * @cmd: IOCTL cmd + * @arg: IOCTL argument + * + * The function is provided primarily for OSS layer and USB gadget drivers, + * and it allows only the limited set of ioctls (hw_params, sw_params, + * prepare, start, drain, drop, forward). + */ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg) { - mm_segment_t fs; - int result; + snd_pcm_uframes_t *frames = arg; + snd_pcm_sframes_t result; - fs = snd_enter_user(); - switch (substream->stream) { - case SNDRV_PCM_STREAM_PLAYBACK: - result = snd_pcm_playback_ioctl1(NULL, substream, cmd, - (void __user *)arg); - break; - case SNDRV_PCM_STREAM_CAPTURE: - result = snd_pcm_capture_ioctl1(NULL, substream, cmd, - (void __user *)arg); - break; - default: - result = -EINVAL; - break; + switch (cmd) { + case SNDRV_PCM_IOCTL_FORWARD: + { + /* provided only for OSS; capture-only and no value returned */ + if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) + return -EINVAL; + result = snd_pcm_capture_forward(substream, *frames); + return result < 0 ? result : 0; + } + case SNDRV_PCM_IOCTL_HW_PARAMS: + return snd_pcm_hw_params(substream, arg); + case SNDRV_PCM_IOCTL_SW_PARAMS: + return snd_pcm_sw_params(substream, arg); + case SNDRV_PCM_IOCTL_PREPARE: + return snd_pcm_prepare(substream, NULL); + case SNDRV_PCM_IOCTL_START: + return snd_pcm_start_lock_irq(substream); + case SNDRV_PCM_IOCTL_DRAIN: + return snd_pcm_drain(substream, NULL); + case SNDRV_PCM_IOCTL_DROP: + return snd_pcm_drop(substream); + case SNDRV_PCM_IOCTL_DELAY: + { + result = snd_pcm_delay(substream); + if (result < 0) + return result; + *frames = result; + return 0; + } + default: + return -EINVAL; } - snd_leave_user(fs); - return result; } - EXPORT_SYMBOL(snd_pcm_kernel_ioctl); static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, From ffb73b08e79418fbf3f2ea44a7818a6715399d2c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 22 May 2017 17:39:13 +0200 Subject: [PATCH 090/418] ALSA: info: Use kvzalloc() for a temporary write buffer We used to use kmalloc (more exactly, krealloc()) for creating and growing the temporary buffer for text proc write. It can grow up to 16kB, and it's already a bit doubtful whether it's always safe to use kmalloc(). With the recent addition of kvmalloc(), we can have a better chance for succeed of memory allocation, so let's switch to that new API. Signed-off-by: Takashi Iwai --- sound/core/info.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/core/info.c b/sound/core/info.c index 8ab72e0f5932..fc14ebe751d8 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -344,12 +344,12 @@ static ssize_t snd_info_text_entry_write(struct file *file, } } if (next > buf->len) { - char *nbuf = krealloc(buf->buffer, PAGE_ALIGN(next), - GFP_KERNEL | __GFP_ZERO); + char *nbuf = kvzalloc(PAGE_ALIGN(next), GFP_KERNEL); if (!nbuf) { err = -ENOMEM; goto error; } + kvfree(buf->buffer); buf->buffer = nbuf; buf->len = PAGE_ALIGN(next); } @@ -427,7 +427,7 @@ static int snd_info_text_entry_release(struct inode *inode, struct file *file) single_release(inode, file); kfree(data->rbuffer); if (data->wbuffer) { - kfree(data->wbuffer->buffer); + kvfree(data->wbuffer->buffer); kfree(data->wbuffer); } From 679d026932f23112e89e0466742a9c06f8160635 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 23 May 2017 09:20:13 +0100 Subject: [PATCH 091/418] ASoC: da7218: Fix incorrect usage of bitwise '&' operator for SRM check In the SRM lock check section of code the '&' bitwise operator is used as part of checking lock status. Functionally the code works as intended, but the conditional statement is a boolean comparison so should really use '&&' logical operator instead. This commit rectifies this discrepancy. Signed-off-by: Adam Thomson Reviewed-by: Takashi Sakamoto Signed-off-by: Mark Brown --- sound/soc/codecs/da7218.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index d256ebf9e309..6e1940eb0653 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c @@ -1457,7 +1457,7 @@ static int da7218_dai_event(struct snd_soc_dapm_widget *w, ++i; msleep(DA7218_SRM_CHECK_DELAY); } - } while ((i < DA7218_SRM_CHECK_TRIES) & (!success)); + } while ((i < DA7218_SRM_CHECK_TRIES) && (!success)); if (!success) dev_warn(codec->dev, "SRM failed to lock\n"); From 4e361d3c962dda16e27d81e7aa9202828a8f7371 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 24 May 2017 10:04:30 +0900 Subject: [PATCH 092/418] ALSA: control: remove entry limitation for list operation In current implementation of ALSA control core, list operation has a limitation to handle 16384 entries at once. This seems due to allocation in kernel space to copy data from user space. With a commit 53e7bf452584 ("ALSA: control: Simplify snd_ctl_elem_list() implementation"), for the operation, ALSA control core copies data into user space directly. No need to care of kernel spaces anymore. This commit purges the limitation. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/control.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/core/control.c b/sound/core/control.c index 47080da8451a..ecd358213b83 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -757,9 +757,7 @@ static int snd_ctl_elem_list(struct snd_card *card, return -EFAULT; offset = list.offset; space = list.space; - /* try limit maximum space */ - if (space > 16384) - return -ENOMEM; + down_read(&card->controls_rwsem); list.count = card->controls_count; list.used = 0; From 7ac45d1635a4cd2e99a4b11903d4a2815ca1b27b Mon Sep 17 00:00:00 2001 From: Julian Scheel Date: Wed, 24 May 2017 12:28:23 +0200 Subject: [PATCH 093/418] ASoC: simple-card: Fix misleading error message In case cpu could not be found the error message would always refer to /codec/ not being found in DT. Fix this by catching the cpu node not found case explicitly. Signed-off-by: Julian Scheel Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 2c9dedab5184..565d057f0d14 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -233,13 +233,19 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, snprintf(prop, sizeof(prop), "%scpu", prefix); cpu = of_get_child_by_name(node, prop); + if (!cpu) { + ret = -EINVAL; + dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); + goto dai_link_of_err; + } + snprintf(prop, sizeof(prop), "%splat", prefix); plat = of_get_child_by_name(node, prop); snprintf(prop, sizeof(prop), "%scodec", prefix); codec = of_get_child_by_name(node, prop); - if (!cpu || !codec) { + if (!codec) { ret = -EINVAL; dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); goto dai_link_of_err; From b08a20f58d2efcd88bf5276e34cd4020028accb7 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Wed, 24 May 2017 18:05:59 +0800 Subject: [PATCH 094/418] ASoC: sun8i-codec-analog: split out mbias Allwinner V3s features an analog codec without MBIAS pin. Split out this part, in order to prepare for the V3s analog codec. Signed-off-by: Icenowy Zheng Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec-analog.c | 35 ++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c index 6c17c99c2c8d..edcc3eb7cd9a 100644 --- a/sound/soc/sunxi/sun8i-codec-analog.c +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -289,11 +289,6 @@ static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = { /* Microphone input */ SND_SOC_DAPM_INPUT("MIC1"), - /* Microphone Bias */ - SND_SOC_DAPM_SUPPLY("MBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, - SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN, - 0, NULL, 0), - /* Mic input path */ SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN, 0, NULL, 0), @@ -453,6 +448,27 @@ static int sun8i_codec_add_headphone(struct snd_soc_component *cmpnt) return 0; } +/* mbias specific widget */ +static const struct snd_soc_dapm_widget sun8i_codec_mbias_widgets[] = { + SND_SOC_DAPM_SUPPLY("MBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN, + 0, NULL, 0), +}; + +static int sun8i_codec_add_mbias(struct snd_soc_component *cmpnt) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); + struct device *dev = cmpnt->dev; + int ret; + + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_mbias_widgets, + ARRAY_SIZE(sun8i_codec_mbias_widgets)); + if (ret) + dev_err(dev, "Failed to add MBIAS DAPM widgets: %d\n", ret); + + return ret; +} + /* hmic specific widget */ static const struct snd_soc_dapm_widget sun8i_codec_hmic_widgets[] = { SND_SOC_DAPM_SUPPLY("HBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, @@ -679,6 +695,7 @@ struct sun8i_codec_analog_quirks { bool has_hmic; bool has_linein; bool has_lineout; + bool has_mbias; bool has_mic2; }; @@ -686,12 +703,14 @@ static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = { .has_headphone = true, .has_hmic = true, .has_linein = true, + .has_mbias = true, .has_mic2 = true, }; static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = { .has_linein = true, .has_lineout = true, + .has_mbias = true, .has_mic2 = true, }; @@ -734,6 +753,12 @@ static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt) return ret; } + if (quirks->has_mbias) { + ret = sun8i_codec_add_mbias(cmpnt); + if (ret) + return ret; + } + if (quirks->has_mic2) { ret = sun8i_codec_add_mic2(cmpnt); if (ret) From 6298117a5c5c5c5217b59640d6df7fe078fa7d88 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 24 May 2017 10:59:38 +0100 Subject: [PATCH 095/418] ASoC: wm_adsp: Fix type warning in sprintf The shift member of struct soc_mixer_control is unsigned int. Signed-off-by: Richard Fitzgerald 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 20695b691aff..a7dc76030ee4 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -2654,7 +2654,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; char preload[32]; - snprintf(preload, ARRAY_SIZE(preload), "DSP%d Preload", mc->shift); + snprintf(preload, ARRAY_SIZE(preload), "DSP%u Preload", mc->shift); dsp->preloaded = ucontrol->value.integer.value[0]; From f6db09488f58372909728cea5a7c063ebf78f386 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 24 May 2017 10:59:39 +0100 Subject: [PATCH 096/418] ASoC: wm_adsp: Remove unused member of struct wm_coeff_ctl_ops The xinfo member of struct wm_coeff_ctl_ops is never used. Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index a7dc76030ee4..5aff83be375c 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -482,8 +482,6 @@ struct wm_coeff_ctl_ops { struct snd_ctl_elem_value *ucontrol); int (*xput)(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); - int (*xinfo)(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo); }; struct wm_coeff_ctl { From 140385d87adce8d00864667f5132770ac5a13dac Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 23 May 2017 12:05:09 -0700 Subject: [PATCH 097/418] ASoC: cht_bsw_max98090_ti: Remove unused function cht_get_codec_dai() Looks like the function has never been used since it was added by commit 17119a465706 ("ASoC: Intel: Add Cherrytrail & Braswell machine driver cht_bsw_max98090_ti"). Removing it fixes the following warning when building with clang: sound/soc/intel/boards/cht_bsw_max98090_ti.c:42:35: error: unused function 'cht_get_codec_dai' [-Werror,-Wunused-function] Signed-off-by: Matthias Kaehlcke Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 742bc0d4e681..20755ecc7f9e 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -39,18 +39,6 @@ struct cht_mc_private { bool ts3a227e_present; }; -static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) -{ - struct snd_soc_pcm_runtime *rtd; - - list_for_each_entry(rtd, &card->rtd_list, list) { - if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, - strlen(CHT_CODEC_DAI))) - return rtd->codec_dai; - } - return NULL; -} - static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), From 177e27133ae9c9f5cbc306feaaa53d8fbc75e45f Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 23 May 2017 16:03:39 +0100 Subject: [PATCH 098/418] ASoC: cs4271: Remove unnecessary additional variable definition The function already defines a ret variable at the top and makes no particular use of the shadowed definition, as such remove the redundant definition. Signed-off-by: Charles Keepax Acked-by: Paul Handrigan Signed-off-by: Mark Brown --- sound/soc/codecs/cs4271.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index e78b5f055f25..d8824773dc29 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -674,8 +674,6 @@ static int cs4271_common_probe(struct device *dev, cs4271->gpio_nreset = cs4271plat->gpio_nreset; if (gpio_is_valid(cs4271->gpio_nreset)) { - int ret; - ret = devm_gpio_request(dev, cs4271->gpio_nreset, "CS4271 Reset"); if (ret < 0) From 9a075265c6dc040e2946d21f4f9d082495bd5460 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 22 May 2017 17:12:58 -0700 Subject: [PATCH 099/418] ASoC: Intel: sst: Remove unused function sst_restore_shim64() Looks like the function has never been used since it was added by commit b0d94acd634a ("ASoC: Intel: mrfld - add shim save restore"). Removing it fixes the following warning when building with clang: sound/soc/intel/atom/sst/sst.c:360:20: error: unused function 'sst_restore_shim64' [-Werror,-Wunused-function] Signed-off-by: Matthias Kaehlcke Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index d97556a3772c..2d43b8693c0c 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -397,22 +397,6 @@ static inline void sst_save_shim64(struct intel_sst_drv *ctx, spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags); } -static inline void sst_restore_shim64(struct intel_sst_drv *ctx, - void __iomem *shim, - struct sst_shim_regs64 *shim_regs) -{ - unsigned long irq_flags; - - /* - * we only need to restore IMRX for this case, rest will be - * initialize by FW or driver when firmware is loaded - */ - spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags); - sst_shim_write64(shim, SST_IMRX, shim_regs->imrx); - sst_shim_write64(shim, SST_CSR, shim_regs->csr); - spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags); -} - void sst_configure_runtime_pm(struct intel_sst_drv *ctx) { pm_runtime_set_autosuspend_delay(ctx->dev, SST_SUSPEND_DELAY); From 133e6e5c27340fe2205537373e50d43881a0f745 Mon Sep 17 00:00:00 2001 From: Shreyas NC Date: Mon, 15 May 2017 19:44:31 +0530 Subject: [PATCH 100/418] ASoC: Intel: Skylake: Support for multiple data blocks Module init params are additional data block in the module private data. Skylake driver doesn't yet have support to parse multiple data blocks if it appears in private data. Add support for parsing of multiple data blocks and module init params. Signed-off-by: Shreyas NC Signed-off-by: Subhransu S. Prusty Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index b28199a5348c..4c3bdff092bd 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -2070,6 +2070,16 @@ static int skl_tplg_get_token(struct device *dev, break; + case SKL_TKN_U32_CAPS_SET_PARAMS: + mconfig->formats_config.set_params = + tkn_elem->value; + break; + + case SKL_TKN_U32_CAPS_PARAMS_ID: + mconfig->formats_config.param_id = + tkn_elem->value; + break; + case SKL_TKN_U32_PROC_DOMAIN: mconfig->domain = tkn_elem->value; @@ -2147,7 +2157,7 @@ static int skl_tplg_get_tokens(struct device *dev, tuple_size += tkn_count * sizeof(*tkn_elem); } - return 0; + return off; } /* @@ -2198,10 +2208,11 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, num_blocks = ret; off += array->size; - array = (struct snd_soc_tplg_vendor_array *)(tplg_w->priv.data + off); - /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */ while (num_blocks > 0) { + array = (struct snd_soc_tplg_vendor_array *) + (tplg_w->priv.data + off); + ret = skl_tplg_get_desc_blocks(dev, array); if (ret < 0) @@ -2237,7 +2248,9 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, memcpy(mconfig->formats_config.caps, data, mconfig->formats_config.caps_size); --num_blocks; + ret = mconfig->formats_config.caps_size; } + off += ret; } return 0; From edc692e5059450350bba38446dc330a31de964f4 Mon Sep 17 00:00:00 2001 From: Naveen M Date: Mon, 15 May 2017 13:42:11 +0530 Subject: [PATCH 101/418] ASoC: Intel: Convert atom machine data to C99 style C99 style struct initialization helps in readability as well as initialization of variables not specified as NULL. Patch modifies all atom machine data. Suggested-by: Takashi Iwai Signed-off-by: Naveen M Signed-off-by: Vinod Koul Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 207 +++++++++++++++++++++------- 1 file changed, 161 insertions(+), 46 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index dd250b8b26f2..193c4d7b35f5 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -453,12 +453,20 @@ static const struct dmi_system_id cht_table[] = { static struct sst_acpi_mach cht_surface_mach = { - "10EC5640", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, - &chv_platform_data }; + .id = "10EC5640", + .drv_name = "cht-bsw-rt5645", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "cht-bsw", + .pdata = &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 }; + .id = "10EC5640", + .drv_name = "cht-bsw-rt5672", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "cht-bsw", + .pdata = &byt_rvp_platform_data, +}; static struct sst_acpi_mach *cht_quirk(void *arg) { @@ -486,68 +494,175 @@ static struct sst_acpi_mach *byt_quirk(void *arg) static struct sst_acpi_mach sst_acpi_bytcr[] = { - {"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 }, - {"INTCCFFD", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, - &byt_rvp_platform_data }, - {"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL, - &byt_rvp_platform_data }, - {"DLGS7212", "bytcht_da7213", "intel/fw_sst_0f28.bin", "bytcht_da7213", NULL, - &byt_rvp_platform_data }, - {"DLGS7213", "bytcht_da7213", "intel/fw_sst_0f28.bin", "bytcht_da7213", NULL, - &byt_rvp_platform_data }, + { + .id = "10EC5640", + .drv_name = "bytcr_rt5640", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcr_rt5640", + .machine_quirk = byt_quirk, + .pdata = &byt_rvp_platform_data, + }, + { + .id = "10EC5642", + .drv_name = "bytcr_rt5640", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcr_rt5640", + .pdata = &byt_rvp_platform_data + }, + { + .id = "INTCCFFD", + .drv_name = "bytcr_rt5640", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcr_rt5640", + .pdata = &byt_rvp_platform_data + }, + { + .id = "10EC5651", + .drv_name = "bytcr_rt5651", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcr_rt5651", + .pdata = &byt_rvp_platform_data + }, + { + .id = "DLGS7212", + .drv_name = "bytcht_da7213", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcht_da7213", + .pdata = &byt_rvp_platform_data + }, + { + .id = "DLGS7213", + .drv_name = "bytcht_da7213", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcht_da7213", + .pdata = &byt_rvp_platform_data + }, /* some Baytrail platforms rely on RT5645, use CHT machine driver */ - {"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL, - &byt_rvp_platform_data }, - {"10EC5648", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL, - &byt_rvp_platform_data }, + { + .id = "10EC5645", + .drv_name = "cht-bsw-rt5645", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "cht-bsw", + .pdata = &byt_rvp_platform_data + }, + { + .id = "10EC5648", + .drv_name = "cht-bsw-rt5645", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "cht-bsw", + .pdata = &byt_rvp_platform_data + }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) /* * This is always last in the table so that it is selected only when * enabled explicitly and there is no codec-related information in SSDT */ - {"80860F28", "bytcht_nocodec", "intel/fw_sst_0f28.bin", "bytcht_nocodec", NULL, - &byt_rvp_platform_data }, + { + .id = "80860F28", + .drv_name = "bytcht_nocodec", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcht_nocodec", + .pdata = &byt_rvp_platform_data + }, #endif {}, }; /* Cherryview-based platforms: CherryTrail and Braswell */ static struct sst_acpi_mach sst_acpi_chv[] = { - {"10EC5670", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, - &chv_platform_data }, - {"10EC5672", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, - &chv_platform_data }, - {"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, - &chv_platform_data }, - {"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, - &chv_platform_data }, - {"10EC3270", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, - &chv_platform_data }, + { + .id = "10EC5670", + .drv_name = "cht-bsw-rt5672", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "cht-bsw", + .pdata = &chv_platform_data + }, + { + .id = "10EC5672", + .drv_name = "cht-bsw-rt5672", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "cht-bsw", + .pdata = &chv_platform_data + }, + { + .id = "10EC5645", + .drv_name = "cht-bsw-rt5645", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "cht-bsw", + .pdata = &chv_platform_data + }, + { + .id = "10EC5650", + .drv_name = "cht-bsw-rt5645", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "cht-bsw", + .pdata = &chv_platform_data + }, + { + .id = "10EC3270", + .drv_name = "cht-bsw-rt5645", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "cht-bsw", + .pdata = &chv_platform_data + }, - {"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, - &chv_platform_data }, - {"DLGS7212", "bytcht_da7213", "intel/fw_sst_22a8.bin", "bytcht_da7213", NULL, - &chv_platform_data }, - {"DLGS7213", "bytcht_da7213", "intel/fw_sst_22a8.bin", "bytcht_da7213", NULL, - &chv_platform_data }, + { + .id = "193C9890", + .drv_name = "cht-bsw-max98090", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "cht-bsw", + .pdata = &chv_platform_data + }, + { + .id = "DLGS7212", + .drv_name = "bytcht_da7213", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "bytcht_da7213", + .pdata = &chv_platform_data + }, + { + .id = "DLGS7213", + .drv_name = "bytcht_da7213", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "bytcht_da7213", + .pdata = &chv_platform_data + }, /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ - {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk, - &chv_platform_data }, - {"10EC3276", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", NULL, - &chv_platform_data }, + { + .id = "10EC5640", + .drv_name = "bytcr_rt5640", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "bytcr_rt5640", + .machine_quirk = cht_quirk, + .pdata = &chv_platform_data + }, + { + .id = "10EC3276", + .drv_name = "bytcr_rt5640", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "bytcr_rt5640", + .pdata = &chv_platform_data + }, /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */ - {"10EC5651", "bytcr_rt5651", "intel/fw_sst_22a8.bin", "bytcr_rt5651", NULL, - &chv_platform_data }, + { + .id = "10EC5651", + .drv_name = "bytcr_rt5651", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "bytcr_rt5651", + .pdata = &chv_platform_data + }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) /* * This is always last in the table so that it is selected only when * enabled explicitly and there is no codec-related information in SSDT */ - {"808622A8", "bytcht_nocodec", "intel/fw_sst_22a8.bin", "bytcht_nocodec", NULL, - &chv_platform_data }, + { + .id = "808622A8", + .drv_name = "bytcht_nocodec", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "bytcht_nocodec", + .pdata = &chv_platform_data + }, #endif {}, }; From 9bf70cd4cd9f82a5f914fbf1fa0d32eff7a5d892 Mon Sep 17 00:00:00 2001 From: Naveen M Date: Mon, 15 May 2017 13:42:12 +0530 Subject: [PATCH 102/418] ASoC: Intel: Convert skl machine data to C99 style C99 style struct initialization helps in readability as well as initialization of variables not specified as NULL. Patch modifies all skl machine data. Suggested-by: Takashi Iwai Signed-off-by: Naveen M Signed-off-by: Vinod Koul Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 60 ++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 4c9b5781282b..a4d1121595b6 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -877,28 +877,66 @@ static void skl_remove(struct pci_dev *pci) } static struct sst_acpi_mach sst_skl_devdata[] = { - { "INT343A", "skl_alc286s_i2s", "intel/dsp_fw_release.bin", NULL, NULL, NULL }, - { "INT343B", "skl_n88l25_s4567", "intel/dsp_fw_release.bin", - NULL, NULL, &skl_dmic_data }, - { "MX98357A", "skl_n88l25_m98357a", "intel/dsp_fw_release.bin", - NULL, NULL, &skl_dmic_data }, + { + .id = "INT343A", + .drv_name = "skl_alc286s_i2s", + .fw_filename = "intel/dsp_fw_release.bin", + }, + { + .id = "INT343B", + .drv_name = "skl_n88l25_s4567", + .fw_filename = "intel/dsp_fw_release.bin", + .pdata = &skl_dmic_data + }, + { + .id = "MX98357A", + .drv_name = "skl_n88l25_m98357a", + .fw_filename = "intel/dsp_fw_release.bin", + .pdata = &skl_dmic_data + }, {} }; static struct sst_acpi_mach sst_bxtp_devdata[] = { - { "INT343A", "bxt_alc298s_i2s", "intel/dsp_fw_bxtn.bin", NULL, NULL, NULL }, - { "DLGS7219", "bxt_da7219_max98357a_i2s", "intel/dsp_fw_bxtn.bin", NULL, NULL, NULL }, + { + .id = "INT343A", + .drv_name = "bxt_alc298s_i2s", + .fw_filename = "intel/dsp_fw_bxtn.bin", + }, + { + .id = "DLGS7219", + .drv_name = "bxt_da7219_max98357a_i2s", + .fw_filename = "intel/dsp_fw_bxtn.bin", + }, }; static struct sst_acpi_mach sst_kbl_devdata[] = { - { "INT343A", "kbl_alc286s_i2s", "intel/dsp_fw_kbl.bin", NULL, NULL, NULL }, - { "INT343B", "kbl_n88l25_s4567", "intel/dsp_fw_kbl.bin", NULL, NULL, &skl_dmic_data }, - { "MX98357A", "kbl_n88l25_m98357a", "intel/dsp_fw_kbl.bin", NULL, NULL, &skl_dmic_data }, + { + .id = "INT343A", + .drv_name = "kbl_alc286s_i2s", + .fw_filename = "intel/dsp_fw_kbl.bin", + }, + { + .id = "INT343B", + .drv_name = "kbl_n88l25_s4567", + .fw_filename = "intel/dsp_fw_kbl.bin", + .pdata = &skl_dmic_data + }, + { + .id = "MX98357A", + .drv_name = "kbl_n88l25_m98357a", + .fw_filename = "intel/dsp_fw_kbl.bin", + .pdata = &skl_dmic_data + }, {} }; static struct sst_acpi_mach sst_glk_devdata[] = { - { "INT343A", "glk_alc298s_i2s", "intel/dsp_fw_glk.bin", NULL, NULL, NULL }, + { + .id = "INT343A", + .drv_name = "glk_alc298s_i2s", + .fw_filename = "intel/dsp_fw_glk.bin", + }, }; /* PCI IDs */ From 915ae2b9f0fe0357a8f9cc53a7eb18ded03d11a4 Mon Sep 17 00:00:00 2001 From: Naveen M Date: Mon, 15 May 2017 13:42:13 +0530 Subject: [PATCH 103/418] ASoC: Intel: Create a helper to search for matching machine Create a helper function to search for a matching machine based on HID. No functional change Signed-off-by: Naveen M Signed-off-by: Harsha Priya Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-acpi.h | 3 +++ sound/soc/intel/common/sst-match-acpi.c | 19 +++++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h index 214e000667ae..3649d3b08c9e 100644 --- a/sound/soc/intel/common/sst-acpi.h +++ b/sound/soc/intel/common/sst-acpi.h @@ -43,6 +43,9 @@ static inline bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], /* acpi match */ struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines); +/* acpi check hid */ +bool sst_acpi_check_hid(const u8 hid[ACPI_ID_LEN]); + /* Descriptor for SST ASoC machine driver */ struct sst_acpi_mach { /* ACPI ID for the matching machine driver. Audio codec for instance */ diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c index 1070f3ad23e5..f4af3d144b82 100644 --- a/sound/soc/intel/common/sst-match-acpi.c +++ b/sound/soc/intel/common/sst-match-acpi.c @@ -63,15 +63,26 @@ static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level, return AE_OK; } +bool sst_acpi_check_hid(const u8 hid[ACPI_ID_LEN]) +{ + acpi_status status; + bool found = false; + + status = acpi_get_devices(hid, sst_acpi_mach_match, &found, NULL); + + if (ACPI_FAILURE(status)) + return false; + + return found; +} +EXPORT_SYMBOL_GPL(sst_acpi_check_hid); + struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines) { struct sst_acpi_mach *mach; - bool found = false; for (mach = machines; mach->id[0]; mach++) - if (ACPI_SUCCESS(acpi_get_devices(mach->id, - sst_acpi_mach_match, - &found, NULL)) && found) + if (sst_acpi_check_hid(mach->id) == true) return mach; return NULL; } From 7827d66946ad3af734ed46d1d68c23fa6974595c Mon Sep 17 00:00:00 2001 From: Naveen M Date: Mon, 15 May 2017 13:42:14 +0530 Subject: [PATCH 104/418] ASoC: Move quirk to identify correct machine driver sst_acpi_mach has a quirk field to handle board specific quirks. Patch moves quirk call to sst_acpi_find_machine() instead of calling it in respective driver Signed-off-by: Naveen M Signed-off-by: Subhransu S. Prusty Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 2 -- sound/soc/intel/common/sst-match-acpi.c | 12 +++++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 193c4d7b35f5..592f6afaf2a5 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -303,8 +303,6 @@ static int sst_acpi_probe(struct platform_device *pdev) dev_err(dev, "No matching machine driver found\n"); return -ENODEV; } - if (mach->machine_quirk) - mach = mach->machine_quirk(mach); pdata = mach->pdata; diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c index f4af3d144b82..88e4977578b5 100644 --- a/sound/soc/intel/common/sst-match-acpi.c +++ b/sound/soc/intel/common/sst-match-acpi.c @@ -81,9 +81,15 @@ struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines) { struct sst_acpi_mach *mach; - for (mach = machines; mach->id[0]; mach++) - if (sst_acpi_check_hid(mach->id) == true) - return mach; + for (mach = machines; mach->id[0]; mach++) { + if (sst_acpi_check_hid(mach->id) == true) { + if (mach->machine_quirk == NULL) + return mach; + + if (mach->machine_quirk(mach) != NULL) + return mach; + } + } return NULL; } EXPORT_SYMBOL_GPL(sst_acpi_find_machine); From 54746dabf770eb268d302f2f770d6dacea24f08a Mon Sep 17 00:00:00 2001 From: Naveen M Date: Mon, 15 May 2017 13:42:15 +0530 Subject: [PATCH 105/418] ASoC: Improve machine driver selection based on quirk data Use quirk function to select the correct machine driver by checking all codecs instead of only one based on quirk data. Signed-off-by: Naveen M Signed-off-by: Harsha Priya Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-acpi.h | 20 ++++++++++++++++++++ sound/soc/intel/common/sst-match-acpi.c | 18 ++++++++++++++++++ sound/soc/intel/skylake/skl.c | 14 ++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h index 3649d3b08c9e..afe9b87b8bd5 100644 --- a/sound/soc/intel/common/sst-acpi.h +++ b/sound/soc/intel/common/sst-acpi.h @@ -58,5 +58,25 @@ struct sst_acpi_mach { /* board name */ const char *board; struct sst_acpi_mach * (*machine_quirk)(void *arg); + const void *quirk_data; void *pdata; }; + +#define SST_ACPI_MAX_CODECS 3 + +/** + * struct sst_codecs: Structure to hold secondary codec information apart from + * the matched one, this data will be passed to the quirk function to match + * with the ACPI detected devices + * + * @num_codecs: number of secondary codecs used in the platform + * @codecs: holds the codec IDs + * + */ +struct sst_codecs { + int num_codecs; + u8 codecs[SST_ACPI_MAX_CODECS][ACPI_ID_LEN]; +}; + +/* check all codecs */ +struct sst_acpi_mach *sst_acpi_codec_list(void *arg); diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c index 88e4977578b5..56d26f36a3cb 100644 --- a/sound/soc/intel/common/sst-match-acpi.c +++ b/sound/soc/intel/common/sst-match-acpi.c @@ -151,5 +151,23 @@ bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], } EXPORT_SYMBOL_GPL(sst_acpi_find_package_from_hid); +struct sst_acpi_mach *sst_acpi_codec_list(void *arg) +{ + struct sst_acpi_mach *mach = arg; + struct sst_codecs *codec_list = (struct sst_codecs *) mach->quirk_data; + int i; + + if (mach->quirk_data == NULL) + return mach; + + for (i = 0; i < codec_list->num_codecs; i++) { + if (sst_acpi_check_hid(codec_list->codecs[i]) != true) + return NULL; + } + + return mach; +} +EXPORT_SYMBOL_GPL(sst_acpi_codec_list); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel Common ACPI Match module"); diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index a4d1121595b6..ceb7734d74ed 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -876,6 +876,10 @@ static void skl_remove(struct pci_dev *pci) dev_set_drvdata(&pci->dev, NULL); } +static struct sst_codecs skl_codecs = { 1, {"NAU88L25"} }; +static struct sst_codecs kbl_codecs = { 1, {"NAU88L25"} }; +static struct sst_codecs bxt_codecs = { 1, {"MX98357A"} }; + static struct sst_acpi_mach sst_skl_devdata[] = { { .id = "INT343A", @@ -886,12 +890,16 @@ static struct sst_acpi_mach sst_skl_devdata[] = { .id = "INT343B", .drv_name = "skl_n88l25_s4567", .fw_filename = "intel/dsp_fw_release.bin", + .machine_quirk = sst_acpi_codec_list, + .quirk_data = &skl_codecs, .pdata = &skl_dmic_data }, { .id = "MX98357A", .drv_name = "skl_n88l25_m98357a", .fw_filename = "intel/dsp_fw_release.bin", + .machine_quirk = sst_acpi_codec_list, + .quirk_data = &skl_codecs, .pdata = &skl_dmic_data }, {} @@ -907,6 +915,8 @@ static struct sst_acpi_mach sst_bxtp_devdata[] = { .id = "DLGS7219", .drv_name = "bxt_da7219_max98357a_i2s", .fw_filename = "intel/dsp_fw_bxtn.bin", + .machine_quirk = sst_acpi_codec_list, + .quirk_data = &bxt_codecs, }, }; @@ -920,12 +930,16 @@ static struct sst_acpi_mach sst_kbl_devdata[] = { .id = "INT343B", .drv_name = "kbl_n88l25_s4567", .fw_filename = "intel/dsp_fw_kbl.bin", + .machine_quirk = sst_acpi_codec_list, + .quirk_data = &kbl_codecs, .pdata = &skl_dmic_data }, { .id = "MX98357A", .drv_name = "kbl_n88l25_m98357a", .fw_filename = "intel/dsp_fw_kbl.bin", + .machine_quirk = sst_acpi_codec_list, + .quirk_data = &kbl_codecs, .pdata = &skl_dmic_data }, {} From ec040dd5ef6478222fc4ed5b0ffced7bc95d2f27 Mon Sep 17 00:00:00 2001 From: Naveen M Date: Mon, 15 May 2017 13:42:16 +0530 Subject: [PATCH 106/418] ASoC: Intel: Add Kabylake Realtek Maxim machine driver This patch adds Kabylake I2S machine driver which uses codecs MAX98927 as speakers and RT5663 as headset, configured to ssp0 & ssp1 respectively. Signed-off-by: Naveen M Signed-off-by: Harsha Priya Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 15 + sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/kbl_rt5663_max98927.c | 687 +++++++++++++++++++ 3 files changed, 704 insertions(+) create mode 100644 sound/soc/intel/boards/kbl_rt5663_max98927.c diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 67968ef3bbda..a9c50d022e73 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -226,6 +226,21 @@ config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH connector If unsure select "N". +config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH + tristate "ASoC Audio driver for KBL with RT5663 and MAX98927 in I2S Mode" + depends on X86_INTEL_LPSS && I2C + select SND_SOC_INTEL_SST + select SND_SOC_INTEL_SKYLAKE + select SND_SOC_RT5663 + select SND_SOC_MAX98927 + select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI + help + This adds support for ASoC Onboard Codec I2S machine driver. This will + create an alsa sound card for RT5663 + MAX98927. + Say Y if you have such a device. + If unsure select "N". + config SND_SOC_INTEL_SKYLAKE tristate select SND_HDA_EXT_CORE diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 56896e09445d..c92ebcac0222 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -12,6 +12,7 @@ snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o +snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o snd-soc-skl_rt286-objs := skl_rt286.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o @@ -30,6 +31,7 @@ obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o +obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c new file mode 100644 index 000000000000..f9ba97788157 --- /dev/null +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -0,0 +1,687 @@ +/* + * Intel Kabylake I2S Machine Driver with MAXIM98927 + * and RT5663 Codecs + * + * Copyright (C) 2017, Intel Corporation. All rights reserved. + * + * Modified from: + * Intel Skylake I2S Machine driver + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/rt5663.h" +#include "../../codecs/hdac_hdmi.h" +#include "../skylake/skl.h" + +#define KBL_REALTEK_CODEC_DAI "rt5663-aif" +#define KBL_MAXIM_CODEC_DAI "max98927-aif1" +#define DMIC_CH(p) p->list[p->count-1] +#define MAXIM_DEV0_NAME "i2c-MX98927:00" +#define MAXIM_DEV1_NAME "i2c-MX98927:01" + +static struct snd_soc_card kabylake_audio_card; +static const struct snd_pcm_hw_constraint_list *dmic_constraints; +static struct snd_soc_jack skylake_hdmi[3]; + +struct kbl_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct kbl_rt5663_private { + struct snd_soc_jack kabylake_headset; + struct list_head hdmi_pcm_list; +}; + +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, + KBL_DPCM_AUDIO_HDMI3_PB, +}; + +static const struct snd_kcontrol_new kabylake_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), +}; + +static const struct snd_soc_dapm_widget kabylake_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + 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), + +}; + +static const struct snd_soc_dapm_route kabylake_map[] = { + /* HP jack connectors - unknown if we have jack detection */ + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + + /* speaker */ + { "Left Spk", NULL, "Left BE_OUT" }, + { "Right Spk", NULL, "Right BE_OUT" }, + + /* other jacks */ + { "IN1P", NULL, "Headset Mic" }, + { "IN1N", NULL, "Headset Mic" }, + { "DMic", NULL, "SoC DMIC" }, + + { "HDMI", NULL, "hif5 Output" }, + { "DP", NULL, "hif6 Output" }, + + /* CODEC BE connections */ + { "Left HiFi Playback", NULL, "ssp0 Tx" }, + { "Right HiFi Playback", NULL, "ssp0 Tx" }, + { "ssp0 Tx", NULL, "codec0_out" }, + + { "AIF Playback", NULL, "ssp1 Tx" }, + { "ssp1 Tx", NULL, "codec1_out" }, + + { "codec0_in", NULL, "ssp1 Rx" }, + { "ssp1 Rx", NULL, "AIF Capture" }, + + /* DMIC */ + { "dmic01_hifi", NULL, "DMIC01 Rx" }, + { "DMIC01 Rx", NULL, "DMIC AIF" }, + + { "hifi3", NULL, "iDisp3 Tx"}, + { "iDisp3 Tx", NULL, "iDisp3_out"}, + { "hifi2", NULL, "iDisp2 Tx"}, + { "iDisp2 Tx", NULL, "iDisp2_out"}, + { "hifi1", NULL, "iDisp1 Tx"}, + { "iDisp1 Tx", NULL, "iDisp1_out"}, +}; + +static struct snd_soc_codec_conf max98927_codec_conf[] = { + { + .dev_name = MAXIM_DEV0_NAME, + .name_prefix = "Right", + }, + { + .dev_name = MAXIM_DEV1_NAME, + .name_prefix = "Left", + }, +}; + +static struct snd_soc_dai_link_component max98927_codec_components[] = { + { /* Left */ + .name = MAXIM_DEV0_NAME, + .dai_name = KBL_MAXIM_CODEC_DAI, + }, + { /* Right */ + .name = MAXIM_DEV1_NAME, + .dai_name = KBL_MAXIM_CODEC_DAI, + }, +}; + +static int kabylake_rt5663_fe_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + struct snd_soc_dapm_context *dapm; + struct snd_soc_component *component = rtd->cpu_dai->component; + + dapm = snd_soc_component_get_dapm(component); + ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); + if (ret) { + dev_err(rtd->dev, "Ref Cap ignore suspend failed %d\n", ret); + return ret; + } + + return ret; +} + +static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_codec *codec = rtd->codec; + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new(&kabylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, &ctx->kabylake_headset, + NULL, 0); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); + return ret; + } + + rt5663_set_jack_detect(codec, &ctx->kabylake_headset); + ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); + if (ret) { + dev_err(rtd->dev, "SoC DMIC ignore suspend failed %d\n", ret); + return ret; + } + + return ret; +} + +static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) +{ + struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct kbl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = KBL_DPCM_AUDIO_HDMI1_PB; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) +{ + struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct kbl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = KBL_DPCM_AUDIO_HDMI2_PB; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) +{ + struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct kbl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = KBL_DPCM_AUDIO_HDMI3_PB; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +static unsigned int rates[] = { + 48000, +}; + +static struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, +}; + +static unsigned int channels[] = { + 2, +}; + +static struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, +}; + +static int kbl_fe_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + /* + * On this platform for PCM device we support, + * 48Khz + * stereo + * 16 bit audio + */ + + runtime->hw.channels_max = 2; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); + + return 0; +} + +static const struct snd_soc_ops kabylake_rt5663_fe_ops = { + .startup = kbl_fe_startup, +}; + +static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + 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); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + /* set SSP1 to 24 bit */ + snd_mask_none(fmt); + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, + RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN); + /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */ + rt5663_sel_asrc_clk_src(codec_dai->codec, RT5663_DA_STEREO_FILTER, 1); + + if (ret < 0) + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + + return ret; +} + +static struct snd_soc_ops kabylake_rt5663_ops = { + .hw_params = kabylake_rt5663_hw_params, +}; + +static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2) + channels->min = channels->max = 2; + else + channels->min = channels->max = 4; + + return 0; +} + +static unsigned int channels_dmic[] = { + 2, 4, +}; + +static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { + .count = ARRAY_SIZE(channels_dmic), + .list = channels_dmic, + .mask = 0, +}; + +static const unsigned int dmic_2ch[] = { + 2, +}; + +static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { + .count = ARRAY_SIZE(dmic_2ch), + .list = dmic_2ch, + .mask = 0, +}; + +static int kabylake_dmic_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_max = DMIC_CH(dmic_constraints); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + dmic_constraints); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); +} + +static struct snd_soc_ops kabylake_dmic_ops = { + .startup = kabylake_dmic_startup, +}; + +static unsigned int rates_16000[] = { + 16000, +}; + +static 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 skylaye_refcap_ops = { + .startup = kabylake_refcap_startup, +}; + +/* kabylake digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link kabylake_dais[] = { + /* Front End DAI links */ + [KBL_DPCM_AUDIO_PB] = { + .name = "Kbl Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .init = kabylake_rt5663_fe_init, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .ops = &kabylake_rt5663_fe_ops, + }, + [KBL_DPCM_AUDIO_CP] = { + .name = "Kbl Audio Capture Port", + .stream_name = "Audio Record", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_capture = 1, + .ops = &kabylake_rt5663_fe_ops, + }, + [KBL_DPCM_AUDIO_REF_CP] = { + .name = "Kbl Audio Reference cap", + .stream_name = "Wake on Voice", + .cpu_dai_name = "Reference Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &skylaye_refcap_ops, + }, + [KBL_DPCM_AUDIO_DMIC_CP] = { + .name = "Kbl Audio DMIC cap", + .stream_name = "dmiccap", + .cpu_dai_name = "DMIC Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &kabylake_dmic_ops, + }, + [KBL_DPCM_AUDIO_HDMI1_PB] = { + .name = "Kbl HDMI Port1", + .stream_name = "Hdmi1", + .cpu_dai_name = "HDMI1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI2_PB] = { + .name = "Kbl HDMI Port2", + .stream_name = "Hdmi2", + .cpu_dai_name = "HDMI2 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI3_PB] = { + .name = "Kbl HDMI Port3", + .stream_name = "Hdmi3", + .cpu_dai_name = "HDMI3 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .init = NULL, + .nonatomic = 1, + .dynamic = 1, + }, + + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "SSP0-Codec", + .id = 0, + .cpu_dai_name = "SSP0 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codecs = max98927_codec_components, + .num_codecs = ARRAY_SIZE(max98927_codec_components), + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp_fixup, + .dpcm_playback = 1, + }, + { + /* SSP1 - Codec */ + .name = "SSP1-Codec", + .id = 1, + .cpu_dai_name = "SSP1 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codec_name = "i2c-10EC5663:00", + .codec_dai_name = KBL_REALTEK_CODEC_DAI, + .init = kabylake_rt5663_codec_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp_fixup, + .ops = &kabylake_rt5663_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + { + .name = "dmic01", + .id = 2, + .cpu_dai_name = "DMIC01 Pin", + .codec_name = "dmic-codec", + .codec_dai_name = "dmic-hifi", + .platform_name = "0000:00:1f.3", + .be_hw_params_fixup = kabylake_dmic_fixup, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + }, + { + .name = "iDisp1", + .id = 3, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = kabylake_hdmi1_init, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .id = 4, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi2_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .id = 5, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi3_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + +#define NAME_SIZE 32 +static int kabylake_card_late_probe(struct snd_soc_card *card) +{ + struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(card); + struct kbl_hdmi_pcm *pcm; + int err, i = 0; + char jack_name[NAME_SIZE]; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &skylake_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &skylake_hdmi[i]); + if (err < 0) + return err; + + i++; + } + + return 0; +} + +/* kabylake audio machine driver for SPT + RT5663 */ +static struct snd_soc_card kabylake_audio_card = { + .name = "kblrt5663max", + .owner = THIS_MODULE, + .dai_link = kabylake_dais, + .num_links = ARRAY_SIZE(kabylake_dais), + .controls = kabylake_controls, + .num_controls = ARRAY_SIZE(kabylake_controls), + .dapm_widgets = kabylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), + .dapm_routes = kabylake_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_map), + .codec_conf = max98927_codec_conf, + .num_configs = ARRAY_SIZE(max98927_codec_conf), + .fully_routed = true, + .late_probe = kabylake_card_late_probe, +}; + +static int kabylake_audio_probe(struct platform_device *pdev) +{ + struct kbl_rt5663_private *ctx; + struct skl_machine_pdata *pdata; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + kabylake_audio_card.dev = &pdev->dev; + snd_soc_card_set_drvdata(&kabylake_audio_card, ctx); + + pdata = dev_get_drvdata(&pdev->dev); + if (pdata) + dmic_constraints = pdata->dmic_num == 2 ? + &constraints_dmic_2ch : &constraints_dmic_channels; + + return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card); +} + +static const struct platform_device_id kbl_board_ids[] = { + { .name = "kbl_rt5663_m98927" }, + { } +}; + +static struct platform_driver kabylake_audio = { + .probe = kabylake_audio_probe, + .driver = { + .name = "kbl_rt5663_m98927", + .pm = &snd_soc_pm_ops, + }, + .id_table = kbl_board_ids, +}; + +module_platform_driver(kabylake_audio) + +/* Module information */ +MODULE_DESCRIPTION("Audio Machine driver-RT5663 & MAX98927 in I2S mode"); +MODULE_AUTHOR("Naveen M "); +MODULE_AUTHOR("Harsha Priya "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:kbl_rt5663_m98927"); From 0809d9871d1066634f8abae9ecfbdfadecb8cd35 Mon Sep 17 00:00:00 2001 From: Naveen M Date: Mon, 15 May 2017 13:42:17 +0530 Subject: [PATCH 107/418] ASoC: Intel: Add Kabylake RT5663+MAX98927 machine driver entry Adds kbl_rt5663_max98927_i2s machine driver entry into machine table Signed-off-by: Naveen M Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index ceb7734d74ed..4ebae850c559 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -879,6 +879,7 @@ static void skl_remove(struct pci_dev *pci) static struct sst_codecs skl_codecs = { 1, {"NAU88L25"} }; static struct sst_codecs kbl_codecs = { 1, {"NAU88L25"} }; static struct sst_codecs bxt_codecs = { 1, {"MX98357A"} }; +static struct sst_codecs kbl_poppy_codecs = { 1, {"10EC5663"} }; static struct sst_acpi_mach sst_skl_devdata[] = { { @@ -942,6 +943,15 @@ static struct sst_acpi_mach sst_kbl_devdata[] = { .quirk_data = &kbl_codecs, .pdata = &skl_dmic_data }, + { + .id = "MX98927", + .drv_name = "kbl_rt5663_m98927", + .fw_filename = "intel/dsp_fw_kbl.bin", + .machine_quirk = sst_acpi_codec_list, + .quirk_data = &kbl_poppy_codecs, + .pdata = &skl_dmic_data + }, + {} }; From a180e8b988437b3e84a1b501ac4d073467602ca6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 May 2017 01:39:25 +0000 Subject: [PATCH 108/418] ASoC: add snd_soc_get_dai_id() function ALSA SoC needs to know connected DAI ID for detecting. It is not a big problem if device/driver was only for sound, but getting DAI ID will be difficult if device includes both Video/Sound, like HDMI. To solve this issue, this patch adds new snd_soc_get_dai_id() and its related .of_xlate_dai_id callback on component driver. In below case, we can handle Sound port (= port@2) as ID = 0 if .of_xlate_dai_id has its support. hdmi { port@0 { /* VIDEO */ }; port@1 { /* VIDEO */ }; port@2 { /* SOUND */ }; }; Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 3 +++ sound/soc/soc-core.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 5170fd81e1fd..9c94b97c17f8 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -803,6 +803,8 @@ struct snd_soc_component_driver { int (*of_xlate_dai_name)(struct snd_soc_component *component, struct of_phandle_args *args, const char **dai_name); + int (*of_xlate_dai_id)(struct snd_soc_component *comment, + struct device_node *endpoint); void (*seq_notifier)(struct snd_soc_component *, enum snd_soc_dapm_type, int subseq); int (*stream_event)(struct snd_soc_component *, int event); @@ -1676,6 +1678,7 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, const char *prefix, 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, const char **dai_name); int snd_soc_of_get_dai_name(struct device_node *of_node, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index aae099c0e502..b0fb17082691 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -4044,6 +4045,42 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); +int snd_soc_get_dai_id(struct device_node *ep) +{ + struct snd_soc_component *pos; + struct device_node *node; + int ret; + + node = of_graph_get_port_parent(ep); + + /* + * For example HDMI case, HDMI has video/sound port, + * but ALSA SoC needs sound port number only. + * Thus counting HDMI DT port/endpoint doesn't work. + * Then, it should have .of_xlate_dai_id + */ + ret = -ENOTSUPP; + mutex_lock(&client_mutex); + list_for_each_entry(pos, &component_list, list) { + struct device_node *component_of_node = pos->dev->of_node; + + if (!component_of_node && pos->dev->parent) + component_of_node = pos->dev->parent->of_node; + + if (component_of_node != node) + continue; + + if (pos->driver->of_xlate_dai_id) + ret = pos->driver->of_xlate_dai_id(pos, ep); + + break; + } + mutex_unlock(&client_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_get_dai_id); + int snd_soc_get_dai_name(struct of_phandle_args *args, const char **dai_name) { From 73b17f1a65c881fcf97109d77056006da2d40152 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 May 2017 01:39:44 +0000 Subject: [PATCH 109/418] ASoC: simple-card-utils: support snd_soc_get_dai_id() ALSA SoC needs to know connected DAI ID for detecting. It is not a big problem if device/driver was only for sound, but getting DAI ID will be difficult if device includes both Video/Sound, like HDMI. To solve this issue, this patch adds new snd_soc_get_dai_id() and its related .of_xlate_dai_id callback on component driver. In below case, we can handle Sound port (= port@2) as ID = 0 if .of_xlate_dai_id has its support. hdmi { port@0 { /* VIDEO */ }; port@1 { /* VIDEO */ }; port@2 { /* SOUND */ }; }; Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card-utils.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 5a3d51e45938..fe726e83d0bd 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -177,9 +177,18 @@ static int asoc_simple_card_get_dai_id(struct device_node *ep) struct device_node *node; struct device_node *endpoint; int i, id; + int ret; + + ret = snd_soc_get_dai_id(ep); + if (ret != -ENOTSUPP) + return ret; node = of_graph_get_port_parent(ep); + /* + * Non HDMI sound case, counting port/endpoint on its DT + * is enough. Let's count it. + */ i = 0; id = -1; for_each_endpoint_of_node(node, endpoint) { From 24069b589b02cc1292761b0f72623dd50ad1e19c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 May 2017 01:40:02 +0000 Subject: [PATCH 110/418] ASoC: hdmi-codec: remove multi detection support DesignWare HDMI driver (= dw-hdmi) is supporting HDMI sound, and its probe function was calling sound binding function multiple times as same HDMI device different port. Because of this behavior, commit 9731f82d601 ("ASoC: hdmi-codec: enable multi probe for ...") was added for multi detection case. But, this DesignWare HDMI detection/bind code was exchanged/adjusted by commit 69497eb9234 ("drm: bridge: dw-hdmi: Implement DRM bridge..."). Now, all DesignWare HDMI sound ports are detected as 1 bindng function. Because of this, hdmi-codec multi detection support is no longer needed. Thus, this patch removes commit 9731f82d601 ("ASoC: hdmi-codec: enable multi probe for ..."), and its related commit 340327a62c4 ("ASoC: hdmi-codec: Fix hdmi_of_xlate_dai_name...") commit 8480ac56795 ("ASoC: hdmi-codec: remove HDMI device unregister") commit 0c343a35bfe ("ASoC: hdmi-codec: fix spelling mistake: ...) Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 88 ++--------------------------------- 1 file changed, 3 insertions(+), 85 deletions(-) diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index a3f15149afcf..8659b76b066a 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -25,17 +25,6 @@ #include /* This is only to get MAX_ELD_BYTES */ -struct hdmi_device { - struct device *dev; - struct list_head list; - int cnt; -}; -#define pos_to_hdmi_device(pos) container_of((pos), struct hdmi_device, list) -LIST_HEAD(hdmi_device_list); -static DEFINE_MUTEX(hdmi_mutex); - -#define DAI_NAME_SIZE 16 - #define HDMI_CODEC_CHMAP_IDX_UNKNOWN -1 struct hdmi_codec_channel_map_table { @@ -702,6 +691,7 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, } static struct snd_soc_dai_driver hdmi_i2s_dai = { + .name = "i2s-hifi", .id = DAI_ID_I2S, .playback = { .stream_name = "Playback", @@ -716,6 +706,7 @@ static struct snd_soc_dai_driver hdmi_i2s_dai = { }; static const struct snd_soc_dai_driver hdmi_spdif_dai = { + .name = "spdif-hifi", .id = DAI_ID_SPDIF, .playback = { .stream_name = "Playback", @@ -728,32 +719,6 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { .pcm_new = hdmi_codec_pcm_new, }; -static char hdmi_dai_name[][DAI_NAME_SIZE] = { - "hdmi-hifi.0", - "hdmi-hifi.1", - "hdmi-hifi.2", - "hdmi-hifi.3", -}; - -static int hdmi_of_xlate_dai_name(struct snd_soc_component *component, - struct of_phandle_args *args, - const char **dai_name) -{ - int id; - - if (args->args_count) - id = args->args[0]; - else - id = 0; - - if (id < ARRAY_SIZE(hdmi_dai_name)) { - *dai_name = hdmi_dai_name[id]; - return 0; - } - - return -EAGAIN; -} - static struct snd_soc_codec_driver hdmi_codec = { .component_driver = { .controls = hdmi_controls, @@ -762,7 +727,6 @@ static struct snd_soc_codec_driver hdmi_codec = { .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), .dapm_routes = hdmi_routes, .num_dapm_routes = ARRAY_SIZE(hdmi_routes), - .of_xlate_dai_name = hdmi_of_xlate_dai_name, }, }; @@ -771,8 +735,6 @@ static int hdmi_codec_probe(struct platform_device *pdev) struct hdmi_codec_pdata *hcd = pdev->dev.platform_data; struct device *dev = &pdev->dev; struct hdmi_codec_priv *hcp; - struct hdmi_device *hd; - struct list_head *pos; int dai_count, i = 0; int ret; @@ -794,35 +756,6 @@ static int hdmi_codec_probe(struct platform_device *pdev) if (!hcp) return -ENOMEM; - hd = NULL; - mutex_lock(&hdmi_mutex); - list_for_each(pos, &hdmi_device_list) { - struct hdmi_device *tmp = pos_to_hdmi_device(pos); - - if (tmp->dev == dev->parent) { - hd = tmp; - break; - } - } - - if (!hd) { - hd = devm_kzalloc(dev, sizeof(*hd), GFP_KERNEL); - if (!hd) { - mutex_unlock(&hdmi_mutex); - return -ENOMEM; - } - - hd->dev = dev->parent; - - list_add_tail(&hd->list, &hdmi_device_list); - } - mutex_unlock(&hdmi_mutex); - - if (hd->cnt >= ARRAY_SIZE(hdmi_dai_name)) { - dev_err(dev, "too many hdmi codec are detected\n"); - return -EINVAL; - } - hcp->hcd = *hcd; mutex_init(&hcp->current_stream_lock); @@ -835,14 +768,11 @@ static int hdmi_codec_probe(struct platform_device *pdev) hcp->daidrv[i] = hdmi_i2s_dai; hcp->daidrv[i].playback.channels_max = hcd->max_i2s_channels; - hcp->daidrv[i].name = hdmi_dai_name[hd->cnt++]; i++; } - if (hcd->spdif) { + if (hcd->spdif) hcp->daidrv[i] = hdmi_spdif_dai; - hcp->daidrv[i].name = hdmi_dai_name[hd->cnt++]; - } ret = snd_soc_register_codec(dev, &hdmi_codec, hcp->daidrv, dai_count); @@ -859,20 +789,8 @@ static int hdmi_codec_probe(struct platform_device *pdev) static int hdmi_codec_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct list_head *pos; struct hdmi_codec_priv *hcp; - mutex_lock(&hdmi_mutex); - list_for_each(pos, &hdmi_device_list) { - struct hdmi_device *tmp = pos_to_hdmi_device(pos); - - if (tmp->dev == dev->parent) { - list_del(pos); - break; - } - } - mutex_unlock(&hdmi_mutex); - hcp = dev_get_drvdata(dev); kfree(hcp->chmap_info); snd_soc_unregister_codec(dev); From 96203fb4237bf70f0fd0fa307ca2975077db3ceb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 May 2017 01:40:20 +0000 Subject: [PATCH 111/418] ASoC: hdmi-codec: add .get_dai_id support ALSA SoC needs to know connected DAI ID for probing. It is not a big problem if device/driver was only for sound, but getting DAI ID will be difficult if device includes both Video/Sound, like HDMI. To solve this issue, this patch adds new .get_dai_id callback on hdmi_codec_ops Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/hdmi-codec.h | 9 +++++++++ sound/soc/codecs/hdmi-codec.c | 13 +++++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h index 915c4357945c..9483c55f871b 100644 --- a/include/sound/hdmi-codec.h +++ b/include/sound/hdmi-codec.h @@ -18,9 +18,11 @@ #ifndef __HDMI_CODEC_H__ #define __HDMI_CODEC_H__ +#include #include #include #include +#include #include /* @@ -87,6 +89,13 @@ struct hdmi_codec_ops { */ int (*get_eld)(struct device *dev, void *data, uint8_t *buf, size_t len); + + /* + * Getting DAI ID + * Optional + */ + int (*get_dai_id)(struct snd_soc_component *comment, + struct device_node *endpoint); }; /* HDMI codec initalization data */ diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 8659b76b066a..6d05161b625d 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -719,6 +719,18 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { .pcm_new = hdmi_codec_pcm_new, }; +static int hdmi_of_xlate_dai_id(struct snd_soc_component *component, + struct device_node *endpoint) +{ + struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component); + int ret = -ENOTSUPP; /* see snd_soc_get_dai_id() */ + + if (hcp->hcd.ops->get_dai_id) + ret = hcp->hcd.ops->get_dai_id(component, endpoint); + + return ret; +} + static struct snd_soc_codec_driver hdmi_codec = { .component_driver = { .controls = hdmi_controls, @@ -727,6 +739,7 @@ static struct snd_soc_codec_driver hdmi_codec = { .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), .dapm_routes = hdmi_routes, .num_dapm_routes = ARRAY_SIZE(hdmi_routes), + .of_xlate_dai_id = hdmi_of_xlate_dai_id, }, }; From 097a7fe369421347405d448a5ee1d37087cad4ad Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 23 May 2017 22:40:20 +0900 Subject: [PATCH 112/418] ALSA: gus: remove unused local flag ALSA driver series for devices of Gravis Ultra Sound includes local variable 'snd_gf1_pcm_use_dma'. Although this is a flag to change behaviours of local implementations for 'struct snd_pcm_ops.copy' and 'struct snd_pcm_ops.silence', it's invariable during module lifetime. This commit removes this local variable and the relevant operations. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/isa/gus/gus_pcm.c | 45 ++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index 33c1891f469a..0cc3f272edf1 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c @@ -61,8 +61,6 @@ struct gus_pcm_private { int final_volume; }; -static int snd_gf1_pcm_use_dma = 1; - static void snd_gf1_pcm_block_change_ack(struct snd_gus_card * gus, void *private_data) { struct gus_pcm_private *pcmp = private_data; @@ -363,7 +361,9 @@ static int snd_gf1_pcm_playback_copy(struct snd_pcm_substream *substream, { struct snd_pcm_runtime *runtime = substream->runtime; struct gus_pcm_private *pcmp = runtime->private_data; + struct snd_gus_card *gus = pcmp->gus; unsigned int bpos, len; + int w16, invert; bpos = samples_to_bytes(runtime, pos) + (voice * (pcmp->dma_size / 2)); len = samples_to_bytes(runtime, count); @@ -373,18 +373,14 @@ static int snd_gf1_pcm_playback_copy(struct snd_pcm_substream *substream, return -EIO; if (copy_from_user(runtime->dma_area + bpos, src, len)) return -EFAULT; - if (snd_gf1_pcm_use_dma && len > 32) { - return snd_gf1_pcm_block_change(substream, bpos, pcmp->memory + bpos, len); - } else { - struct snd_gus_card *gus = pcmp->gus; - int err, w16, invert; + if (len > 32) + return snd_gf1_pcm_block_change(substream, bpos, + pcmp->memory + bpos, len); - w16 = (snd_pcm_format_width(runtime->format) == 16); - invert = snd_pcm_format_unsigned(runtime->format); - if ((err = snd_gf1_pcm_poke_block(gus, runtime->dma_area + bpos, pcmp->memory + bpos, len, w16, invert)) < 0) - return err; - } - return 0; + w16 = (snd_pcm_format_width(runtime->format) == 16); + invert = snd_pcm_format_unsigned(runtime->format); + return snd_gf1_pcm_poke_block(gus, runtime->dma_area + bpos, + pcmp->memory + bpos, len, w16, invert); } static int snd_gf1_pcm_playback_silence(struct snd_pcm_substream *substream, @@ -394,7 +390,9 @@ static int snd_gf1_pcm_playback_silence(struct snd_pcm_substream *substream, { struct snd_pcm_runtime *runtime = substream->runtime; struct gus_pcm_private *pcmp = runtime->private_data; + struct snd_gus_card *gus = pcmp->gus; unsigned int bpos, len; + int w16, invert; bpos = samples_to_bytes(runtime, pos) + (voice * (pcmp->dma_size / 2)); len = samples_to_bytes(runtime, count); @@ -402,19 +400,16 @@ static int snd_gf1_pcm_playback_silence(struct snd_pcm_substream *substream, return -EIO; if (snd_BUG_ON(bpos + len > pcmp->dma_size)) return -EIO; - snd_pcm_format_set_silence(runtime->format, runtime->dma_area + bpos, count); - if (snd_gf1_pcm_use_dma && len > 32) { - return snd_gf1_pcm_block_change(substream, bpos, pcmp->memory + bpos, len); - } else { - struct snd_gus_card *gus = pcmp->gus; - int err, w16, invert; + snd_pcm_format_set_silence(runtime->format, runtime->dma_area + bpos, + count); + if (len > 32) + return snd_gf1_pcm_block_change(substream, bpos, + pcmp->memory + bpos, len); - w16 = (snd_pcm_format_width(runtime->format) == 16); - invert = snd_pcm_format_unsigned(runtime->format); - if ((err = snd_gf1_pcm_poke_block(gus, runtime->dma_area + bpos, pcmp->memory + bpos, len, w16, invert)) < 0) - return err; - } - return 0; + w16 = (snd_pcm_format_width(runtime->format) == 16); + invert = snd_pcm_format_unsigned(runtime->format); + return snd_gf1_pcm_poke_block(gus, runtime->dma_area + bpos, + pcmp->memory + bpos, len, w16, invert); } static int snd_gf1_pcm_playback_hw_params(struct snd_pcm_substream *substream, From 6dbaf8b913f2976ee776beb7c8bb0c52c7066ced Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 23 May 2017 22:40:42 +0900 Subject: [PATCH 113/418] ALSA: sb: remove needless evaluation in implementation for copy callback In design of ALSA pcm core, 'struct snd_pcm_ops.copy' is expected to copy PCM frames, according to frame alignment on intermediate buffer for userspace and dedicated buffer for data transmission. In this callback, value of 'channel' argument depends on the frame alignment, which drivers registers to runtime of PCM substream. When target devices can handle non-interleaved buffer, this value has positive value, otherwise negative. ALSA driver for PCM component of EMU8000 chip is programmed with local macro to switch the frame alignment. The 'copy' operation in non-interleaved side has evaluation of the 'channel' argument (actually it's 'voice' argument). This is useless. This commit remove the evaluation. [tiwai: the negative channel argument was the inheritance from the old code where -1 was meant for interleaved mode. The mix-up was dropped meanwhile, thus it's correct to assume that we receive no longer -1 there, and it's safe to cleanup the relevant code. Also, voice=0 for channel==1 is trivial, and it can be dropped, too.] Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/isa/sb/emu8000_pcm.c | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c index 32f234f494e5..c480024422af 100644 --- a/sound/isa/sb/emu8000_pcm.c +++ b/sound/isa/sb/emu8000_pcm.c @@ -450,20 +450,8 @@ static int emu8k_pcm_copy(struct snd_pcm_substream *subs, struct snd_emu8000 *emu = rec->emu; snd_emu8000_write_wait(emu, 1); - if (voice == -1) { - unsigned short *buf = src; - int i, err; - count /= rec->voices; - for (i = 0; i < rec->voices; i++) { - err = emu8k_transfer_block(emu, pos + rec->loop_start[i], buf, count); - if (err < 0) - return err; - buf += count; - } - return 0; - } else { - return emu8k_transfer_block(emu, pos + rec->loop_start[voice], src, count); - } + return emu8k_transfer_block(emu, pos + rec->loop_start[voice], src, + count); } /* make a channel block silence */ @@ -487,17 +475,7 @@ static int emu8k_pcm_silence(struct snd_pcm_substream *subs, struct snd_emu8000 *emu = rec->emu; snd_emu8000_write_wait(emu, 1); - if (voice == -1 && rec->voices == 1) - voice = 0; - if (voice == -1) { - int err; - err = emu8k_silence_block(emu, pos + rec->loop_start[0], count / 2); - if (err < 0) - return err; - return emu8k_silence_block(emu, pos + rec->loop_start[1], count / 2); - } else { - return emu8k_silence_block(emu, pos + rec->loop_start[voice], count); - } + return emu8k_silence_block(emu, pos + rec->loop_start[voice], count); } #else /* interleave */ From 9629581258cb520a413a4240fc4254a45e0a81df Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 May 2017 18:31:03 +0200 Subject: [PATCH 114/418] ALSA: pcm: Fix negative appl_ptr handling in pcm-indirect helpers The indirect-PCM helper codes have an implicit assumption that the appl_ptr always increases. But the PCM core may deal with the decrement of appl_ptr via rewind ioctls, and it may screw up the buffer pointer management. This patch adds the negative appl_ptr diff in transfer functions and let returning an error instead of always accepting the appl_ptr updates. The callers are usually PCM ack callbacks, and they pass the error to the upper layer accordingly. Signed-off-by: Takashi Iwai --- include/sound/pcm-indirect.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/sound/pcm-indirect.h b/include/sound/pcm-indirect.h index 1df7acaaa535..7ade285328cf 100644 --- a/include/sound/pcm-indirect.h +++ b/include/sound/pcm-indirect.h @@ -43,7 +43,7 @@ typedef void (*snd_pcm_indirect_copy_t)(struct snd_pcm_substream *substream, /* * helper function for playback ack callback */ -static inline void +static inline int snd_pcm_indirect_playback_transfer(struct snd_pcm_substream *substream, struct snd_pcm_indirect *rec, snd_pcm_indirect_copy_t copy) @@ -56,6 +56,8 @@ snd_pcm_indirect_playback_transfer(struct snd_pcm_substream *substream, if (diff) { if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) diff += runtime->boundary; + if (diff < 0) + return -EINVAL; rec->sw_ready += (int)frames_to_bytes(runtime, diff); rec->appl_ptr = appl_ptr; } @@ -82,6 +84,7 @@ snd_pcm_indirect_playback_transfer(struct snd_pcm_substream *substream, rec->hw_ready += bytes; rec->sw_ready -= bytes; } + return 0; } /* @@ -109,7 +112,7 @@ snd_pcm_indirect_playback_pointer(struct snd_pcm_substream *substream, /* * helper function for capture ack callback */ -static inline void +static inline int snd_pcm_indirect_capture_transfer(struct snd_pcm_substream *substream, struct snd_pcm_indirect *rec, snd_pcm_indirect_copy_t copy) @@ -121,6 +124,8 @@ snd_pcm_indirect_capture_transfer(struct snd_pcm_substream *substream, if (diff) { if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) diff += runtime->boundary; + if (diff < 0) + return -EINVAL; rec->sw_ready -= frames_to_bytes(runtime, diff); rec->appl_ptr = appl_ptr; } @@ -147,6 +152,7 @@ snd_pcm_indirect_capture_transfer(struct snd_pcm_substream *substream, rec->hw_ready -= bytes; rec->sw_ready += bytes; } + return 0; } /* From 0f21e57decaa2c49ace8436781cd4672d3637ddc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 May 2017 18:41:45 +0200 Subject: [PATCH 115/418] ALSA: mips: Deliver indirect-PCM transfer error Now that the indirect-PCM transfer helper gives back an error, we should return the error from ack callbacks. Signed-off-by: Takashi Iwai --- sound/mips/hal2.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c index 00fc9241d266..684dc4ddef41 100644 --- a/sound/mips/hal2.c +++ b/sound/mips/hal2.c @@ -616,10 +616,9 @@ static int hal2_playback_ack(struct snd_pcm_substream *substream) struct hal2_codec *dac = &hal2->dac; dac->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2; - snd_pcm_indirect_playback_transfer(substream, - &dac->pcm_indirect, - hal2_playback_transfer); - return 0; + return snd_pcm_indirect_playback_transfer(substream, + &dac->pcm_indirect, + hal2_playback_transfer); } static int hal2_capture_open(struct snd_pcm_substream *substream) @@ -707,10 +706,9 @@ static int hal2_capture_ack(struct snd_pcm_substream *substream) struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); struct hal2_codec *adc = &hal2->adc; - snd_pcm_indirect_capture_transfer(substream, - &adc->pcm_indirect, - hal2_capture_transfer); - return 0; + return snd_pcm_indirect_capture_transfer(substream, + &adc->pcm_indirect, + hal2_capture_transfer); } static struct snd_pcm_ops hal2_playback_ops = { From cebf6bfe5e32f07d94785f5cf893d19cf7c1c303 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 May 2017 18:48:36 +0200 Subject: [PATCH 116/418] ALSA: cs46xx: Deliver indirect-PCM transfer error Now that the indirect-PCM transfer helper gives back an error, we should return the error from ack callbacks. Signed-off-by: Takashi Iwai --- sound/pci/cs46xx/cs46xx_lib.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 00fa52e9a2f2..ae2aad52ea6f 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -887,8 +887,8 @@ static int snd_cs46xx_playback_transfer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_cs46xx_pcm * cpcm = runtime->private_data; - snd_pcm_indirect_playback_transfer(substream, &cpcm->pcm_rec, snd_cs46xx_pb_trans_copy); - return 0; + return snd_pcm_indirect_playback_transfer(substream, &cpcm->pcm_rec, + snd_cs46xx_pb_trans_copy); } static void snd_cs46xx_cp_trans_copy(struct snd_pcm_substream *substream, @@ -903,8 +903,8 @@ static void snd_cs46xx_cp_trans_copy(struct snd_pcm_substream *substream, static int snd_cs46xx_capture_transfer(struct snd_pcm_substream *substream) { struct snd_cs46xx *chip = snd_pcm_substream_chip(substream); - snd_pcm_indirect_capture_transfer(substream, &chip->capt.pcm_rec, snd_cs46xx_cp_trans_copy); - return 0; + return snd_pcm_indirect_capture_transfer(substream, &chip->capt.pcm_rec, + snd_cs46xx_cp_trans_copy); } static snd_pcm_uframes_t snd_cs46xx_playback_direct_pointer(struct snd_pcm_substream *substream) From 00277e2b5ffcf9ffb3afb5f728f7f01ad165cbff Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 May 2017 18:49:23 +0200 Subject: [PATCH 117/418] ALSA: emu10k1: Deliver indirect-PCM transfer error Now that the indirect-PCM transfer helper gives back an error, we should return the error from ack callbacks. Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emupcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index ef1cf530c929..bdda29f335f6 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1632,8 +1632,8 @@ static int snd_emu10k1_fx8010_playback_transfer(struct snd_pcm_substream *substr struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number]; - snd_pcm_indirect_playback_transfer(substream, &pcm->pcm_rec, fx8010_pb_trans_copy); - return 0; + return snd_pcm_indirect_playback_transfer(substream, &pcm->pcm_rec, + fx8010_pb_trans_copy); } static int snd_emu10k1_fx8010_playback_hw_params(struct snd_pcm_substream *substream, From 3e02c5a60e182708005973e34a439d1e25ace9b5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 May 2017 18:49:45 +0200 Subject: [PATCH 118/418] ALSA: rme32: Deliver indirect-PCM transfer error Now that the indirect-PCM transfer helper gives back an error, we should return the error from ack callbacks. Signed-off-by: Takashi Iwai --- sound/pci/rme32.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 96d15db65dfd..f9b424056d0f 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -1157,9 +1157,8 @@ static int snd_rme32_playback_fd_ack(struct snd_pcm_substream *substream) if (rme32->running & (1 << SNDRV_PCM_STREAM_CAPTURE)) rec->hw_queue_size -= cprec->hw_ready; spin_unlock(&rme32->lock); - snd_pcm_indirect_playback_transfer(substream, rec, - snd_rme32_pb_trans_copy); - return 0; + return snd_pcm_indirect_playback_transfer(substream, rec, + snd_rme32_pb_trans_copy); } static void snd_rme32_cp_trans_copy(struct snd_pcm_substream *substream, @@ -1174,9 +1173,8 @@ static void snd_rme32_cp_trans_copy(struct snd_pcm_substream *substream, static int snd_rme32_capture_fd_ack(struct snd_pcm_substream *substream) { struct rme32 *rme32 = snd_pcm_substream_chip(substream); - snd_pcm_indirect_capture_transfer(substream, &rme32->capture_pcm, - snd_rme32_cp_trans_copy); - return 0; + return snd_pcm_indirect_capture_transfer(substream, &rme32->capture_pcm, + snd_rme32_cp_trans_copy); } static snd_pcm_uframes_t From 9ce7b9cf64dc1a48a074033a83c8ea314b38540c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 May 2017 18:51:03 +0200 Subject: [PATCH 119/418] staging: bcm2835-audio: Deliver indirect-PCM transfer error Now that the indirect-PCM transfer helper gives back an error, we should return the error from ack callbacks. Acked-by: Eric Anholt Signed-off-by: Takashi Iwai --- drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c index e8cf0b97bf02..3637ddf909a4 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c @@ -353,9 +353,8 @@ static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream) struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect; pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max; - snd_pcm_indirect_playback_transfer(substream, pcm_indirect, - snd_bcm2835_pcm_transfer); - return 0; + return snd_pcm_indirect_playback_transfer(substream, pcm_indirect, + snd_bcm2835_pcm_transfer); } /* trigger callback */ From 9027c4639ef1e3254779e3033f229133222445f7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 May 2017 20:22:33 +0200 Subject: [PATCH 120/418] ALSA: pcm: Call ack() whenever appl_ptr is updated Although the ack callback is supposed to be called at each appl_ptr or hw_ptr update, we missed a few opportunities: namely, forward, rewind and sync_ptr. Formerly calling ack at rewind may have leaded to unexpected results due to the forgotten negative appl_ptr update in indirect-PCM helper, which is the major user of the PCM ack callback. But now we fixed this oversights, thus we can call ack callback safely even at rewind callback -- of course with the proper handling of the error from the callback. This patch adds the calls of ack callback in the places mentioned in the above. Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 46 +++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 889364cbced8..5be549cf91e5 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2449,13 +2449,35 @@ static int do_pcm_hwsync(struct snd_pcm_substream *substream) } } -/* increase the appl_ptr; returns the processed frames */ +/* update to the given appl_ptr and call ack callback if needed; + * when an error is returned, take back to the original value + */ +static int apply_appl_ptr(struct snd_pcm_substream *substream, + snd_pcm_uframes_t appl_ptr) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_uframes_t old_appl_ptr = runtime->control->appl_ptr; + int ret; + + runtime->control->appl_ptr = appl_ptr; + if (substream->ops->ack) { + ret = substream->ops->ack(substream); + if (ret < 0) { + runtime->control->appl_ptr = old_appl_ptr; + return ret; + } + } + return 0; +} + +/* increase the appl_ptr; returns the processed frames or a negative error */ static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream, snd_pcm_uframes_t frames, snd_pcm_sframes_t avail) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_sframes_t appl_ptr; + int ret; if (avail <= 0) return 0; @@ -2464,17 +2486,18 @@ static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream, appl_ptr = runtime->control->appl_ptr + frames; if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) appl_ptr -= runtime->boundary; - runtime->control->appl_ptr = appl_ptr; - return frames; + ret = apply_appl_ptr(substream, appl_ptr); + return ret < 0 ? ret : frames; } -/* decrease the appl_ptr; returns the processed frames */ +/* decrease the appl_ptr; returns the processed frames or a negative error */ static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream, snd_pcm_uframes_t frames, snd_pcm_sframes_t avail) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_sframes_t appl_ptr; + int ret; if (avail <= 0) return 0; @@ -2483,8 +2506,8 @@ static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream, appl_ptr = runtime->control->appl_ptr - frames; if (appl_ptr < 0) appl_ptr += runtime->boundary; - runtime->control->appl_ptr = appl_ptr; - return frames; + ret = apply_appl_ptr(substream, appl_ptr); + return ret < 0 ? ret : frames; } static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream, @@ -2610,10 +2633,15 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, return err; } snd_pcm_stream_lock_irq(substream); - if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) - control->appl_ptr = sync_ptr.c.control.appl_ptr; - else + if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) { + err = apply_appl_ptr(substream, sync_ptr.c.control.appl_ptr); + if (err < 0) { + snd_pcm_stream_unlock_irq(substream); + return err; + } + } else { sync_ptr.c.control.appl_ptr = control->appl_ptr; + } if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) control->avail_min = sync_ptr.c.control.avail_min; else From 2c4842d3b6b3cf6db0f21e487da7e9bd3aa23090 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 26 May 2017 09:30:46 +0900 Subject: [PATCH 121/418] ALSA: pcm: add local header file for snd-pcm module Several files are used to construct PCM core module, a.k.a snd-pcm. Although available APIs are described in 'include/sound/pcm.h', some of them are not exported as symbols in kernel space. Such APIs are just for module local usage. This commit adds module local header file and move some function prototypes into it so that scopes of them are controlled properly and developers get no confusion from unavailable symbols. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 32 -------------------------- sound/core/pcm.c | 2 ++ sound/core/pcm_lib.c | 2 ++ sound/core/pcm_local.h | 51 +++++++++++++++++++++++++++++++++++++++++ sound/core/pcm_misc.c | 3 +++ sound/core/pcm_native.c | 2 ++ 6 files changed, 60 insertions(+), 32 deletions(-) create mode 100644 sound/core/pcm_local.h diff --git a/include/sound/pcm.h b/include/sound/pcm.h index c609b891c4c2..79fedf517070 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -969,12 +969,6 @@ static inline unsigned int params_buffer_bytes(const struct snd_pcm_hw_params *p } int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v); -void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c); -void snd_interval_div(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c); -void snd_interval_muldivk(const struct snd_interval *a, const struct snd_interval *b, - unsigned int k, struct snd_interval *c); -void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k, - const struct snd_interval *b, struct snd_interval *c); int snd_interval_list(struct snd_interval *i, unsigned int count, const unsigned int *list, unsigned int mask); int snd_interval_ranges(struct snd_interval *i, unsigned int count, @@ -985,15 +979,9 @@ int snd_interval_ratnum(struct snd_interval *i, void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params); void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var); -int snd_pcm_hw_params_choose(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); int snd_pcm_hw_refine(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); -int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream); -int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream); - -int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var, - u_int32_t mask); int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var, u_int64_t mask); int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var, @@ -1081,10 +1069,6 @@ void snd_pcm_set_ops(struct snd_pcm * pcm, int direction, void snd_pcm_set_sync(struct snd_pcm_substream *substream); int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg); -int snd_pcm_update_state(struct snd_pcm_substream *substream, - struct snd_pcm_runtime *runtime); -int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); -void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr); void snd_pcm_period_elapsed(struct snd_pcm_substream *substream); snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, @@ -1096,8 +1080,6 @@ snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream, snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream, void __user **bufs, snd_pcm_uframes_t frames); -extern const struct snd_pcm_hw_constraint_list snd_pcm_known_rates; - int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime); unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate); unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit); @@ -1131,20 +1113,6 @@ static inline void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substrea } } -/* - * Timer interface - */ - -#ifdef CONFIG_SND_PCM_TIMER -void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream); -void snd_pcm_timer_init(struct snd_pcm_substream *substream); -void snd_pcm_timer_done(struct snd_pcm_substream *substream); -#else -static inline void -snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream) {} -static inline void snd_pcm_timer_init(struct snd_pcm_substream *substream) {} -static inline void snd_pcm_timer_done(struct snd_pcm_substream *substream) {} -#endif /** * snd_pcm_gettime - Fill the timespec depending on the timestamp mode * @runtime: PCM runtime instance diff --git a/sound/core/pcm.c b/sound/core/pcm.c index d30dba0ee688..4b3290447398 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -31,6 +31,8 @@ #include #include +#include "pcm_local.h" + MODULE_AUTHOR("Jaroslav Kysela , Abramo Bagnara "); MODULE_DESCRIPTION("Midlevel PCM code for ALSA."); MODULE_LICENSE("GPL"); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index ab4b1d1e44ee..e50548af4004 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -33,6 +33,8 @@ #include #include +#include "pcm_local.h" + #ifdef CONFIG_SND_PCM_XRUN_DEBUG #define CREATE_TRACE_POINTS #include "pcm_trace.h" diff --git a/sound/core/pcm_local.h b/sound/core/pcm_local.h new file mode 100644 index 000000000000..34c66decaaf2 --- /dev/null +++ b/sound/core/pcm_local.h @@ -0,0 +1,51 @@ +/* + * pcm_local.h - a local header file for snd-pcm module. + * + * Copyright (c) Takashi Sakamoto + * + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#ifndef __SOUND_CORE_PCM_LOCAL_H +#define __SOUND_CORE_PCM_LOCAL_H + +extern const struct snd_pcm_hw_constraint_list snd_pcm_known_rates; + +void snd_interval_mul(const struct snd_interval *a, + const struct snd_interval *b, struct snd_interval *c); +void snd_interval_div(const struct snd_interval *a, + const struct snd_interval *b, struct snd_interval *c); +void snd_interval_muldivk(const struct snd_interval *a, + const struct snd_interval *b, + unsigned int k, struct snd_interval *c); +void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k, + const struct snd_interval *b, struct snd_interval *c); + +int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream); +int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream); + +int snd_pcm_hw_params_choose(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); + +int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, + snd_pcm_hw_param_t var, u_int32_t mask); + +int snd_pcm_update_state(struct snd_pcm_substream *substream, + struct snd_pcm_runtime *runtime); +int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); + +void snd_pcm_playback_silence(struct snd_pcm_substream *substream, + snd_pcm_uframes_t new_hw_ptr); + +#ifdef CONFIG_SND_PCM_TIMER +void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream); +void snd_pcm_timer_init(struct snd_pcm_substream *substream); +void snd_pcm_timer_done(struct snd_pcm_substream *substream); +#else +static inline void +snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream) {} +static inline void snd_pcm_timer_init(struct snd_pcm_substream *substream) {} +static inline void snd_pcm_timer_done(struct snd_pcm_substream *substream) {} +#endif + +#endif /* __SOUND_CORE_PCM_LOCAL_H */ diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index 53dc37357bca..dd8383e29315 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -23,6 +23,9 @@ #include #include #include + +#include "pcm_local.h" + #define SND_PCM_FORMAT_UNKNOWN (-1) /* NOTE: "signed" prefix must be given below since the default char is diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 5be549cf91e5..bf5d0f2acfb9 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -37,6 +37,8 @@ #include #include +#include "pcm_local.h" + /* * Compatibility */ From 503ada8a6d00c70f5b6fe37249e9a5e2f9c9e202 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 26 May 2017 10:47:07 +0100 Subject: [PATCH 122/418] ASoC: wm_adsp: Fix typo in algorithm list warning message The list terminator is 0xbedead but the message warning if it wasn't found was showing that 0xbeadead was expected. Signed-off-by: Richard Fitzgerald 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 5aff83be375c..65c059b5ffd7 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -1888,7 +1888,7 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs, } if (be32_to_cpu(val) != 0xbedead) - adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n", + adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n", pos + len, be32_to_cpu(val)); alg = kzalloc(len * 2, GFP_KERNEL | GFP_DMA); From 155b8f3aa633dbce887cded6b6b9399a3c62683e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 25 May 2017 01:51:31 +0000 Subject: [PATCH 123/418] ASoC: simple-card-utils: remove strict limitation of bit/frame master Current asoc_simple_card_parse_daifmt is keeping backward compatibility for bitmaster/framemaster which didn't use phandle. The keep compatibility, it is checking prefix length, but it is too strict. let's loosen it. Otherwise, OF-graph base sound card which doesn't have prefix can't detect daifmt. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card-utils.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index fe726e83d0bd..9c7f5b91b90a 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -21,14 +21,13 @@ int asoc_simple_card_parse_daifmt(struct device *dev, { struct device_node *bitclkmaster = NULL; struct device_node *framemaster = NULL; - int prefix_len = prefix ? strlen(prefix) : 0; unsigned int daifmt; daifmt = snd_soc_of_parse_daifmt(node, prefix, &bitclkmaster, &framemaster); daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; - if (prefix_len && !bitclkmaster && !framemaster) { + if (!bitclkmaster && !framemaster) { /* * No dai-link level and master setting was not found from * sound node level, revert back to legacy DT parsing and From 6a9a440681f2170b9a07b1cf28c6aa7532c307c8 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 27 May 2017 15:50:44 +0800 Subject: [PATCH 124/418] ASoC: zx-i2s: fix harsh noise with 16-bit audio The audio parameter setup in zx_i2s_hw_params() works fine with 32-bit samples, but for 16-bit ones, all we can hear is harsh noises. As suggested by vendor driver code, DMA burst size and TS width should always be 32 bits, no matter audio sample is 16-bit or 32-bit. Follow the suggestion above to fix the harsh noise issue seen with 16-bit audio samples. Signed-off-by: Shawn Guo Signed-off-by: Mark Brown --- sound/soc/zte/zx-i2s.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/zte/zx-i2s.c b/sound/soc/zte/zx-i2s.c index a865f37c2a56..a7f7a56e0a2d 100644 --- a/sound/soc/zte/zx-i2s.c +++ b/sound/soc/zte/zx-i2s.c @@ -226,11 +226,12 @@ static int zx_i2s_hw_params(struct snd_pcm_substream *substream, struct zx_i2s_info *i2s = snd_soc_dai_get_drvdata(socdai); struct snd_dmaengine_dai_dma_data *dma_data; unsigned int lane, ch_num, len, ret = 0; + unsigned int ts_width = 32; unsigned long val; unsigned long chn_cfg; dma_data = snd_soc_dai_get_dma_data(socdai, substream); - dma_data->addr_width = params_width(params) >> 3; + dma_data->addr_width = ts_width >> 3; val = readl_relaxed(i2s->reg_base + ZX_I2S_TIMING_CTRL); val &= ~(ZX_I2S_TIMING_TS_WIDTH_MASK | ZX_I2S_TIMING_DATA_SIZE_MASK | @@ -251,7 +252,7 @@ static int zx_i2s_hw_params(struct snd_pcm_substream *substream, dev_err(socdai->dev, "Unknown data format\n"); return -EINVAL; } - val |= ZX_I2S_TIMING_TS_WIDTH(len) | ZX_I2S_TIMING_DATA_SIZE(len); + val |= ZX_I2S_TIMING_TS_WIDTH(ts_width) | ZX_I2S_TIMING_DATA_SIZE(len); ch_num = params_channels(params); switch (ch_num) { From be10ee2cd351818738097c782b4493e09c6d14f6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 May 2017 01:44:46 +0000 Subject: [PATCH 125/418] ASoC: add audio-graph-scu-card document Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../bindings/sound/audio-graph-scu-card.txt | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt diff --git a/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt b/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt new file mode 100644 index 000000000000..b2dd23fd2135 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt @@ -0,0 +1,72 @@ +Audio-Graph-SCU-Card: + +Audio-Graph-SCU-Card is "Audio-Graph-Card" + "ALSA DPCM". + +It is based on common bindings for device graphs. +see ${LINUX}/Documentation/devicetree/bindings/graph.txt + +Basically, Audio-Graph-SCU-Card property is same as +Simple-Card / Simple-SCU-Card / Audio-Graph-Card. +see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt + ${LINUX}/Documentation/devicetree/bindings/sound/simple-scu-card.txt + ${LINUX}/Documentation/devicetree/bindings/sound/audio-graph-card.txt + +Below are same as Simple-Card / Audio-Graph-Card. + +- label +- dai-format +- frame-master +- bitclock-master +- bitclock-inversion +- frame-inversion +- dai-tdm-slot-num +- dai-tdm-slot-width +- clocks / system-clock-frequency + +Below are same as Simple-SCU-Card. + +- convert-rate +- convert-channels +- prefix +- routing + +Required properties: + +- compatible : "audio-graph-scu-card"; +- dais : list of CPU DAI port{s} + +Example + + sound_card { + compatible = "audio-graph-scu-card"; + + label = "sound-card"; + prefix = "codec"; + routing = "codec Playback", "DAI0 Playback", + "codec Playback", "DAI1 Playback"; + convert-rate = <48000>; + + dais = <&cpu_port>; + }; + + audio-codec { + ... + + port { + codec_endpoint: endpoint { + remote-endpoint = <&cpu_endpoint>; + }; + }; + }; + + dai-controller { + ... + cpu_port: port { + cpu_endpoint: endpoint { + remote-endpoint = <&codec_endpoint>; + + dai-format = "left_j"; + ... + }; + }; + }; From 87f937b45f7dacfb09e6f7dddb2db8484dc0e8e3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 May 2017 01:45:37 +0000 Subject: [PATCH 126/418] ASoC: add audio-graph-scu-card support OF-graph base DT binding is used on V4L2, and ALSA SoC is using different style of DT today. Now ALSA SoC supports simple-card driver for generic/simple sound card, and we have simple-scu-card driver for simple-card + ALSA DPCM case. In the future, V4L2 / ALSA will support HDMI, and then, DT bindings between V4L2 / ALSA should be merged. This patch adds new Audio Graph SCU Card which is OF-graph base of simple-scu-card Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/Kconfig | 9 + sound/soc/generic/Makefile | 2 + sound/soc/generic/audio-graph-scu-card.c | 416 +++++++++++++++++++++++ 3 files changed, 427 insertions(+) create mode 100644 sound/soc/generic/audio-graph-scu-card.c diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig index 121a48e8bb7d..c954be0a0f96 100644 --- a/sound/soc/generic/Kconfig +++ b/sound/soc/generic/Kconfig @@ -22,3 +22,12 @@ config SND_AUDIO_GRAPH_CARD help This option enables generic simple simple sound card support with OF-graph DT bindings. + +config SND_AUDIO_GRAPH_SCU_CARD + tristate "ASoC Audio Graph SCU sound card support" + depends on OF + select SND_SIMPLE_CARD_UTILS + help + This option enables generic simple SCU sound card support + with OF-graph DT bindings. + It supports DPCM of multi CPU single Codec ststem. diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile index 670068f257b9..9e000523a3b4 100644 --- a/sound/soc/generic/Makefile +++ b/sound/soc/generic/Makefile @@ -2,8 +2,10 @@ snd-soc-simple-card-utils-objs := simple-card-utils.o snd-soc-simple-card-objs := simple-card.o snd-soc-simple-scu-card-objs := simple-scu-card.o snd-soc-audio-graph-card-objs := audio-graph-card.o +snd-soc-audio-graph-scu-card-objs := audio-graph-scu-card.o obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-card.o obj-$(CONFIG_SND_AUDIO_GRAPH_CARD) += snd-soc-audio-graph-card.o +obj-$(CONFIG_SND_AUDIO_GRAPH_SCU_CARD) += snd-soc-audio-graph-scu-card.o diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c new file mode 100644 index 000000000000..64e8b9728580 --- /dev/null +++ b/sound/soc/generic/audio-graph-scu-card.c @@ -0,0 +1,416 @@ +/* + * ASoC audio graph SCU sound card support + * + * Copyright (C) 2017 Renesas Solutions Corp. + * Kuninori Morimoto + * + * based on + * ${LINUX}/sound/soc/generic/simple-scu-card.c + * ${LINUX}/sound/soc/generic/audio-graph-card.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct graph_card_data { + struct snd_soc_card snd_card; + struct snd_soc_codec_conf codec_conf; + struct asoc_simple_dai *dai_props; + struct snd_soc_dai_link *dai_link; + u32 convert_rate; + u32 convert_channels; +}; + +#define graph_priv_to_card(priv) (&(priv)->snd_card) +#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i)) +#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev) +#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i)) + +static int asoc_graph_card_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num); + + return clk_prepare_enable(dai_props->clk); +} + +static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num); + + clk_disable_unprepare(dai_props->clk); +} + +static struct snd_soc_ops asoc_graph_card_ops = { + .startup = asoc_graph_card_startup, + .shutdown = asoc_graph_card_shutdown, +}; + +static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) +{ + struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai; + struct snd_soc_dai_link *dai_link; + struct asoc_simple_dai *dai_props; + int num = rtd->num; + + dai_link = graph_priv_to_link(priv, num); + dai_props = graph_priv_to_props(priv, num); + dai = dai_link->dynamic ? + rtd->cpu_dai : + rtd->codec_dai; + + return asoc_simple_card_init_dai(dai, dai_props); +} + +static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct graph_card_data *priv = 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); + + if (priv->convert_rate) + rate->min = + rate->max = priv->convert_rate; + + if (priv->convert_channels) + channels->min = + channels->max = priv->convert_channels; + + return 0; +} + +static int asoc_graph_card_dai_link_of(struct device_node *ep, + struct graph_card_data *priv, + unsigned int daifmt, + int idx, int is_fe) +{ + struct device *dev = graph_priv_to_dev(priv); + struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx); + struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, idx); + struct snd_soc_card *card = graph_priv_to_card(priv); + int ret; + + if (is_fe) { + /* BE is dummy */ + dai_link->codec_of_node = NULL; + dai_link->codec_dai_name = "snd-soc-dummy-dai"; + dai_link->codec_name = "snd-soc-dummy"; + + /* FE settings */ + dai_link->dynamic = 1; + dai_link->dpcm_merged_format = 1; + + ret = asoc_simple_card_parse_graph_cpu(ep, dai_link); + if (ret) + return ret; + + ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai_props); + if (ret < 0) + return ret; + + ret = asoc_simple_card_set_dailink_name(dev, dai_link, + "fe.%s", + dai_link->cpu_dai_name); + if (ret < 0) + return ret; + + /* card->num_links includes Codec */ + asoc_simple_card_canonicalize_cpu(dai_link, + (card->num_links - 1) == 1); + } else { + /* FE is dummy */ + dai_link->cpu_of_node = NULL; + dai_link->cpu_dai_name = "snd-soc-dummy-dai"; + dai_link->cpu_name = "snd-soc-dummy"; + + /* BE settings */ + dai_link->no_pcm = 1; + dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup; + + ret = asoc_simple_card_parse_graph_codec(ep, dai_link); + if (ret < 0) + return ret; + + ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai_props); + if (ret < 0) + return ret; + + ret = asoc_simple_card_set_dailink_name(dev, dai_link, + "be.%s", + dai_link->codec_dai_name); + if (ret < 0) + return ret; + + snd_soc_of_parse_audio_prefix(card, + &priv->codec_conf, + dai_link->codec_of_node, + "prefix"); + } + + ret = snd_soc_of_parse_tdm_slot(ep, + &dai_props->tx_slot_mask, + &dai_props->rx_slot_mask, + &dai_props->slots, + &dai_props->slot_width); + if (ret) + return ret; + + ret = asoc_simple_card_canonicalize_dailink(dai_link); + if (ret < 0) + return ret; + + dai_link->dai_fmt = daifmt; + dai_link->dpcm_playback = 1; + dai_link->dpcm_capture = 1; + dai_link->ops = &asoc_graph_card_ops; + dai_link->init = asoc_graph_card_dai_init; + + dev_dbg(dev, "\t%s / %04x / %d\n", + dai_link->name, + dai_link->dai_fmt, + dai_props->sysclk); + + return 0; +} + +static int asoc_graph_card_parse_of(struct graph_card_data *priv) +{ + struct of_phandle_iterator it; + struct device *dev = graph_priv_to_dev(priv); + struct snd_soc_card *card = graph_priv_to_card(priv); + struct device_node *node = dev->of_node; + struct device_node *cpu_port; + struct device_node *cpu_ep; + struct device_node *codec_ep; + struct device_node *rcpu_ep; + unsigned int daifmt = 0; + int dai_idx, ret; + int rc, codec; + + if (!node) + return -EINVAL; + + /* + * we need to consider "widgets", "mclk-fs" around here + * see simple-card + */ + + ret = snd_soc_of_parse_audio_routing(card, "routing"); + if (ret) + return ret; + + /* sampling rate convert */ + of_property_read_u32(node, "convert-rate", &priv->convert_rate); + + /* channels transfer */ + of_property_read_u32(node, "convert-channels", &priv->convert_channels); + + /* + * it supports multi CPU, single CODEC only here + * see asoc_graph_get_dais_count + */ + + /* find 1st codec */ + of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { + cpu_port = it.node; + cpu_ep = of_get_next_child(cpu_port, NULL); + codec_ep = of_graph_get_remote_endpoint(cpu_ep); + rcpu_ep = of_graph_get_remote_endpoint(codec_ep); + + of_node_put(cpu_port); + of_node_put(cpu_ep); + of_node_put(codec_ep); + of_node_put(rcpu_ep); + + if (!codec_ep) + continue; + + if (rcpu_ep != cpu_ep) { + dev_err(dev, "remote-endpoint missmatch (%s/%s/%s)\n", + cpu_ep->name, codec_ep->name, rcpu_ep->name); + ret = -EINVAL; + goto parse_of_err; + } + + ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep, + NULL, &daifmt); + if (ret < 0) + goto parse_of_err; + } + + dai_idx = 0; + for (codec = 0; codec < 2; codec++) { + /* + * To listup valid sounds continuously, + * detect all CPU-dummy first, and + * detect all dummy-Codec second + */ + of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { + cpu_port = it.node; + cpu_ep = of_get_next_child(cpu_port, NULL); + codec_ep = of_graph_get_remote_endpoint(cpu_ep); + + of_node_put(cpu_port); + of_node_put(cpu_ep); + of_node_put(codec_ep); + + if (codec) { + if (!codec_ep) + continue; + + /* Back-End (= Codec) */ + ret = asoc_graph_card_dai_link_of(codec_ep, priv, daifmt, dai_idx++, 0); + if (ret < 0) + goto parse_of_err; + } else { + /* Front-End (= CPU) */ + ret = asoc_graph_card_dai_link_of(cpu_ep, priv, daifmt, dai_idx++, 1); + if (ret < 0) + goto parse_of_err; + } + } + } + + ret = asoc_simple_card_parse_card_name(card, NULL); + if (ret) + goto parse_of_err; + + dev_dbg(dev, "New card: %s\n", + card->name ? card->name : ""); + dev_dbg(dev, "convert_rate %d\n", priv->convert_rate); + dev_dbg(dev, "convert_channels %d\n", priv->convert_channels); + + ret = 0; + +parse_of_err: + return ret; +} + +static int asoc_graph_get_dais_count(struct device *dev) +{ + struct of_phandle_iterator it; + struct device_node *node = dev->of_node; + struct device_node *cpu_port; + struct device_node *cpu_ep; + struct device_node *codec_ep; + int count = 0; + int rc; + + of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { + cpu_port = it.node; + cpu_ep = of_get_next_child(cpu_port, NULL); + codec_ep = of_graph_get_remote_endpoint(cpu_ep); + + of_node_put(cpu_port); + of_node_put(cpu_ep); + of_node_put(codec_ep); + + if (cpu_ep) + count++; + if (codec_ep) + count++; + } + + return count; +} + +static int asoc_graph_card_probe(struct platform_device *pdev) +{ + struct graph_card_data *priv; + struct snd_soc_dai_link *dai_link; + struct asoc_simple_dai *dai_props; + struct device *dev = &pdev->dev; + struct snd_soc_card *card; + int num, ret; + + /* Allocate the private data and the DAI link array */ + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + num = asoc_graph_get_dais_count(dev); + if (num == 0) + return -EINVAL; + + dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL); + dai_link = devm_kzalloc(dev, sizeof(*dai_link) * num, GFP_KERNEL); + if (!dai_props || !dai_link) + return -ENOMEM; + + priv->dai_props = dai_props; + priv->dai_link = dai_link; + + /* Init snd_soc_card */ + card = graph_priv_to_card(priv); + card->owner = THIS_MODULE; + card->dev = dev; + card->dai_link = priv->dai_link; + card->num_links = num; + card->codec_conf = &priv->codec_conf; + card->num_configs = 1; + + ret = asoc_graph_card_parse_of(priv); + if (ret < 0) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "parse error %d\n", ret); + goto err; + } + + snd_soc_card_set_drvdata(card, priv); + + ret = devm_snd_soc_register_card(dev, card); + if (ret >= 0) + return ret; +err: + asoc_simple_card_clean_reference(card); + + return ret; +} + +static int asoc_graph_card_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + return asoc_simple_card_clean_reference(card); +} + +static const struct of_device_id asoc_graph_of_match[] = { + { .compatible = "audio-graph-scu-card", }, + {}, +}; +MODULE_DEVICE_TABLE(of, asoc_graph_of_match); + +static struct platform_driver asoc_graph_card = { + .driver = { + .name = "asoc-audio-graph-scu-card", + .of_match_table = asoc_graph_of_match, + }, + .probe = asoc_graph_card_probe, + .remove = asoc_graph_card_remove, +}; +module_platform_driver(asoc_graph_card); + +MODULE_ALIAS("platform:asoc-audio-graph-scu-card"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ASoC Audio Graph SCU Sound Card"); +MODULE_AUTHOR("Kuninori Morimoto "); From 1a2af56431781e7d6db746a1b7ae796443028dfa Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 19 May 2017 00:58:19 +0000 Subject: [PATCH 127/418] ASoC: audio-graph-scu-card: tidyup return method from probe() Current return method from probe() is very confusable. This patch tidyup it to normal return method Reported-by: Dan Carpenter Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-scu-card.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c index 64e8b9728580..c5c52d1f500c 100644 --- a/sound/soc/generic/audio-graph-scu-card.c +++ b/sound/soc/generic/audio-graph-scu-card.c @@ -379,8 +379,10 @@ static int asoc_graph_card_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, priv); ret = devm_snd_soc_register_card(dev, card); - if (ret >= 0) - return ret; + if (ret < 0) + goto err; + + return 0; err: asoc_simple_card_clean_reference(card); From 905e46acd3272d04566fec49afbd7ad9e2ed9ae3 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sat, 27 May 2017 20:16:15 +0530 Subject: [PATCH 128/418] ALSA: declare snd_kcontrol_new structures as const Declare snd_kcontrol_new structures as const as they are only passed an argument to the function snd_ctl_new1. This argument is of type const, so snd_kcontrol_new structures having this property can be made const. Done using Coccinelle: @r disable optional_qualifier@ identifier x; position p; @@ static struct snd_kcontrol_new x@p={...}; @ok@ identifier r.x; position p; @@ snd_ctl_new1(&x@p,...) @bad@ position p != {r.p,ok.p}; identifier r.x; @@ x@p @depends on !bad disable optional_qualifier@ identifier r.x; @@ +const struct snd_kcontrol_new x; Cross compiled these files: sound/aoa/codecs/tas.c - powerpc sound/mips/{hal2.c/sgio2audio.c} - mips sound/ppc/{awacs.c/beep.c/tumbler.c} - powerpc sound/soc/sh/siu_dai.c - sh Could not find an architecture to compile sound/sh/aica.c. Signed-off-by: Bhumika Goyal Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/aoa/codecs/tas.c | 14 +++++++------- sound/aoa/fabrics/layout.c | 8 ++++---- sound/core/ctljack.c | 2 +- sound/drivers/vx/vx_mixer.c | 24 ++++++++++++------------ sound/firewire/bebob/bebob_maudio.c | 8 ++++---- sound/mips/hal2.c | 4 ++-- sound/mips/sgio2audio.c | 14 +++++++------- sound/pcmcia/vx/vxp_mixer.c | 4 ++-- sound/ppc/awacs.c | 4 ++-- sound/ppc/beep.c | 2 +- sound/ppc/tumbler.c | 8 ++++---- sound/sh/aica.c | 4 ++-- sound/soc/sh/siu_dai.c | 4 ++-- sound/usb/mixer_quirks.c | 2 +- 14 files changed, 51 insertions(+), 51 deletions(-) diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c index 78ed1ffbf786..733b6365dad6 100644 --- a/sound/aoa/codecs/tas.c +++ b/sound/aoa/codecs/tas.c @@ -271,7 +271,7 @@ static int tas_snd_vol_put(struct snd_kcontrol *kcontrol, return 1; } -static struct snd_kcontrol_new volume_control = { +static const struct snd_kcontrol_new volume_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -314,7 +314,7 @@ static int tas_snd_mute_put(struct snd_kcontrol *kcontrol, return 1; } -static struct snd_kcontrol_new mute_control = { +static const struct snd_kcontrol_new mute_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -426,7 +426,7 @@ static int tas_snd_drc_range_put(struct snd_kcontrol *kcontrol, return 1; } -static struct snd_kcontrol_new drc_range_control = { +static const struct snd_kcontrol_new drc_range_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DRC Range", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -466,7 +466,7 @@ static int tas_snd_drc_switch_put(struct snd_kcontrol *kcontrol, return 1; } -static struct snd_kcontrol_new drc_switch_control = { +static const struct snd_kcontrol_new drc_switch_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DRC Range Switch", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -524,7 +524,7 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol, return 1; } -static struct snd_kcontrol_new capture_source_control = { +static const struct snd_kcontrol_new capture_source_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* If we name this 'Input Source', it properly shows up in * alsamixer as a selection, * but it's shown under the @@ -586,7 +586,7 @@ static int tas_snd_treble_put(struct snd_kcontrol *kcontrol, return 1; } -static struct snd_kcontrol_new treble_control = { +static const struct snd_kcontrol_new treble_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Treble", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -637,7 +637,7 @@ static int tas_snd_bass_put(struct snd_kcontrol *kcontrol, return 1; } -static struct snd_kcontrol_new bass_control = { +static const struct snd_kcontrol_new bass_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Bass", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, diff --git a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/layout.c index a0c4a5de809c..1eddf8fa188f 100644 --- a/sound/aoa/fabrics/layout.c +++ b/sound/aoa/fabrics/layout.c @@ -707,7 +707,7 @@ static int detect_choice_put(struct snd_kcontrol *kcontrol, return 1; } -static struct snd_kcontrol_new headphone_detect_choice = { +static const struct snd_kcontrol_new headphone_detect_choice = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Detect Autoswitch", .info = control_info, @@ -717,7 +717,7 @@ static struct snd_kcontrol_new headphone_detect_choice = { .private_value = 0, }; -static struct snd_kcontrol_new lineout_detect_choice = { +static const struct snd_kcontrol_new lineout_detect_choice = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line-Out Detect Autoswitch", .info = control_info, @@ -749,7 +749,7 @@ static int detected_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new headphone_detected = { +static const struct snd_kcontrol_new headphone_detected = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Detected", .info = control_info, @@ -758,7 +758,7 @@ static struct snd_kcontrol_new headphone_detected = { .private_value = 0, }; -static struct snd_kcontrol_new lineout_detected = { +static const struct snd_kcontrol_new lineout_detected = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line-Out Detected", .info = control_info, diff --git a/sound/core/ctljack.c b/sound/core/ctljack.c index 84a3cd683068..0249d5e6ac23 100644 --- a/sound/core/ctljack.c +++ b/sound/core/ctljack.c @@ -23,7 +23,7 @@ static int jack_detect_kctl_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new jack_detect_kctl = { +static const struct snd_kcontrol_new jack_detect_kctl = { /* name is filled later */ .iface = SNDRV_CTL_ELEM_IFACE_CARD, .access = SNDRV_CTL_ELEM_ACCESS_READ, diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c index be9477e30739..98a41ac40b60 100644 --- a/sound/drivers/vx/vx_mixer.c +++ b/sound/drivers/vx/vx_mixer.c @@ -455,7 +455,7 @@ static int vx_output_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele return 0; } -static struct snd_kcontrol_new vx_control_output_level = { +static const struct snd_kcontrol_new vx_control_output_level = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), @@ -514,7 +514,7 @@ static int vx_audio_src_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v return 0; } -static struct snd_kcontrol_new vx_control_audio_src = { +static const struct snd_kcontrol_new vx_control_audio_src = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", .info = vx_audio_src_info, @@ -558,7 +558,7 @@ static int vx_clock_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ return 0; } -static struct snd_kcontrol_new vx_control_clock_mode = { +static const struct snd_kcontrol_new vx_control_clock_mode = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Clock Mode", .info = vx_clock_mode_info, @@ -717,7 +717,7 @@ static int vx_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ static const DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0); -static struct snd_kcontrol_new vx_control_audio_gain = { +static const struct snd_kcontrol_new vx_control_audio_gain = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), @@ -727,14 +727,14 @@ static struct snd_kcontrol_new vx_control_audio_gain = { .put = vx_audio_gain_put, .tlv = { .p = db_scale_audio_gain }, }; -static struct snd_kcontrol_new vx_control_output_switch = { +static const struct snd_kcontrol_new vx_control_output_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Switch", .info = vx_audio_sw_info, .get = vx_audio_sw_get, .put = vx_audio_sw_put }; -static struct snd_kcontrol_new vx_control_monitor_gain = { +static const struct snd_kcontrol_new vx_control_monitor_gain = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Monitoring Volume", .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -744,7 +744,7 @@ static struct snd_kcontrol_new vx_control_monitor_gain = { .put = vx_audio_monitor_put, .tlv = { .p = db_scale_audio_gain }, }; -static struct snd_kcontrol_new vx_control_monitor_switch = { +static const struct snd_kcontrol_new vx_control_monitor_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Monitoring Switch", .info = vx_audio_sw_info, /* shared */ @@ -805,7 +805,7 @@ static int vx_iec958_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu return 0; } -static struct snd_kcontrol_new vx_control_iec958_mask = { +static const struct snd_kcontrol_new vx_control_iec958_mask = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), @@ -813,7 +813,7 @@ static struct snd_kcontrol_new vx_control_iec958_mask = { .get = vx_iec958_mask_get, }; -static struct snd_kcontrol_new vx_control_iec958 = { +static const struct snd_kcontrol_new vx_control_iec958 = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), .info = vx_iec958_info, @@ -878,7 +878,7 @@ static int vx_saturation_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ return 0; } -static struct snd_kcontrol_new vx_control_vu_meter = { +static const struct snd_kcontrol_new vx_control_vu_meter = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, /* name will be filled later */ @@ -886,7 +886,7 @@ static struct snd_kcontrol_new vx_control_vu_meter = { .get = vx_vu_meter_get, }; -static struct snd_kcontrol_new vx_control_peak_meter = { +static const struct snd_kcontrol_new vx_control_peak_meter = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, /* name will be filled later */ @@ -894,7 +894,7 @@ static struct snd_kcontrol_new vx_control_peak_meter = { .get = vx_peak_meter_get, }; -static struct snd_kcontrol_new vx_control_saturation = { +static const struct snd_kcontrol_new vx_control_saturation = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Input Saturation", .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, diff --git a/sound/firewire/bebob/bebob_maudio.c b/sound/firewire/bebob/bebob_maudio.c index 07e5abdbceb5..d10208f92edf 100644 --- a/sound/firewire/bebob/bebob_maudio.c +++ b/sound/firewire/bebob/bebob_maudio.c @@ -396,7 +396,7 @@ static int special_clk_ctl_put(struct snd_kcontrol *kctl, return err; } -static struct snd_kcontrol_new special_clk_ctl = { +static const struct snd_kcontrol_new special_clk_ctl = { .name = "Clock Source", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -429,7 +429,7 @@ static int special_sync_ctl_get(struct snd_kcontrol *kctl, return 0; } -static struct snd_kcontrol_new special_sync_ctl = { +static const struct snd_kcontrol_new special_sync_ctl = { .name = "Sync Status", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READ, @@ -521,7 +521,7 @@ end: mutex_unlock(&bebob->mutex); return err; } -static struct snd_kcontrol_new special_dig_in_iface_ctl = { +static const struct snd_kcontrol_new special_dig_in_iface_ctl = { .name = "Digital Input Interface", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -577,7 +577,7 @@ static int special_dig_out_iface_ctl_set(struct snd_kcontrol *kctl, mutex_unlock(&bebob->mutex); return err; } -static struct snd_kcontrol_new special_dig_out_iface_ctl = { +static const struct snd_kcontrol_new special_dig_out_iface_ctl = { .name = "Digital Output Interface", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c index 684dc4ddef41..6505deb8c06b 100644 --- a/sound/mips/hal2.c +++ b/sound/mips/hal2.c @@ -264,7 +264,7 @@ static int hal2_gain_put(struct snd_kcontrol *kcontrol, return old != new; } -static struct snd_kcontrol_new hal2_ctrl_headphone = { +static const struct snd_kcontrol_new hal2_ctrl_headphone = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Playback Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -274,7 +274,7 @@ static struct snd_kcontrol_new hal2_ctrl_headphone = { .put = hal2_gain_put, }; -static struct snd_kcontrol_new hal2_ctrl_mic = { +static const struct snd_kcontrol_new hal2_ctrl_mic = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Mic Capture Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index f07aa3993f83..0ebc1c3727df 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -230,7 +230,7 @@ static int sgio2audio_source_put(struct snd_kcontrol *kcontrol, } /* dac1/pcm0 mixer control */ -static struct snd_kcontrol_new sgio2audio_ctrl_pcm0 = { +static const struct snd_kcontrol_new sgio2audio_ctrl_pcm0 = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Volume", .index = 0, @@ -242,7 +242,7 @@ static struct snd_kcontrol_new sgio2audio_ctrl_pcm0 = { }; /* dac2/pcm1 mixer control */ -static struct snd_kcontrol_new sgio2audio_ctrl_pcm1 = { +static const struct snd_kcontrol_new sgio2audio_ctrl_pcm1 = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Volume", .index = 1, @@ -254,7 +254,7 @@ static struct snd_kcontrol_new sgio2audio_ctrl_pcm1 = { }; /* record level mixer control */ -static struct snd_kcontrol_new sgio2audio_ctrl_reclevel = { +static const struct snd_kcontrol_new sgio2audio_ctrl_reclevel = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -265,7 +265,7 @@ static struct snd_kcontrol_new sgio2audio_ctrl_reclevel = { }; /* record level source control */ -static struct snd_kcontrol_new sgio2audio_ctrl_recsource = { +static const struct snd_kcontrol_new sgio2audio_ctrl_recsource = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -275,7 +275,7 @@ static struct snd_kcontrol_new sgio2audio_ctrl_recsource = { }; /* line mixer control */ -static struct snd_kcontrol_new sgio2audio_ctrl_line = { +static const struct snd_kcontrol_new sgio2audio_ctrl_line = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line Playback Volume", .index = 0, @@ -287,7 +287,7 @@ static struct snd_kcontrol_new sgio2audio_ctrl_line = { }; /* cd mixer control */ -static struct snd_kcontrol_new sgio2audio_ctrl_cd = { +static const struct snd_kcontrol_new sgio2audio_ctrl_cd = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line Playback Volume", .index = 1, @@ -299,7 +299,7 @@ static struct snd_kcontrol_new sgio2audio_ctrl_cd = { }; /* mic mixer control */ -static struct snd_kcontrol_new sgio2audio_ctrl_mic = { +static const struct snd_kcontrol_new sgio2audio_ctrl_mic = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Mic Playback Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, diff --git a/sound/pcmcia/vx/vxp_mixer.c b/sound/pcmcia/vx/vxp_mixer.c index 1ca3eef9e305..304b153005a5 100644 --- a/sound/pcmcia/vx/vxp_mixer.c +++ b/sound/pcmcia/vx/vxp_mixer.c @@ -69,7 +69,7 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v static const DECLARE_TLV_DB_SCALE(db_scale_mic, -21, 3, 0); -static struct snd_kcontrol_new vx_control_mic_level = { +static const struct snd_kcontrol_new vx_control_mic_level = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), @@ -109,7 +109,7 @@ static int vx_mic_boost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v return 0; } -static struct snd_kcontrol_new vx_control_mic_boost = { +static const struct snd_kcontrol_new vx_control_mic_boost = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Mic Boost", .info = vx_mic_boost_info, diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c index 1468e4b7bf93..d1e4ef1c5c30 100644 --- a/sound/ppc/awacs.c +++ b/sound/ppc/awacs.c @@ -514,7 +514,7 @@ static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] = { }, }; -static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw = { +static const struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Playback Switch", .info = snd_pmac_boolean_stereo_info, @@ -523,7 +523,7 @@ static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw = { .private_value = AMP_CH_HD, }; -static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw = { +static const struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Speaker Playback Switch", .info = snd_pmac_boolean_stereo_info, diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c index d3524f9fa05d..f19eb3e39937 100644 --- a/sound/ppc/beep.c +++ b/sound/ppc/beep.c @@ -206,7 +206,7 @@ static int snd_pmac_put_beep(struct snd_kcontrol *kcontrol, return oval != chip->beep->volume; } -static struct snd_kcontrol_new snd_pmac_beep_mixer = { +static const struct snd_kcontrol_new snd_pmac_beep_mixer = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Beep Playback Volume", .info = snd_pmac_info_beep, diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 58ee8089bbf9..0779a2912237 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -897,7 +897,7 @@ static struct snd_kcontrol_new snapper_mixers[] = { }, }; -static struct snd_kcontrol_new tumbler_hp_sw = { +static const struct snd_kcontrol_new tumbler_hp_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Playback Switch", .info = snd_pmac_boolean_mono_info, @@ -905,7 +905,7 @@ static struct snd_kcontrol_new tumbler_hp_sw = { .put = tumbler_put_mute_switch, .private_value = TUMBLER_MUTE_HP, }; -static struct snd_kcontrol_new tumbler_speaker_sw = { +static const struct snd_kcontrol_new tumbler_speaker_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Speaker Playback Switch", .info = snd_pmac_boolean_mono_info, @@ -913,7 +913,7 @@ static struct snd_kcontrol_new tumbler_speaker_sw = { .put = tumbler_put_mute_switch, .private_value = TUMBLER_MUTE_AMP, }; -static struct snd_kcontrol_new tumbler_lineout_sw = { +static const struct snd_kcontrol_new tumbler_lineout_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line Out Playback Switch", .info = snd_pmac_boolean_mono_info, @@ -921,7 +921,7 @@ static struct snd_kcontrol_new tumbler_lineout_sw = { .put = tumbler_put_mute_switch, .private_value = TUMBLER_MUTE_LINE, }; -static struct snd_kcontrol_new tumbler_drc_sw = { +static const struct snd_kcontrol_new tumbler_drc_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DRC Switch", .info = snd_pmac_boolean_mono_info, diff --git a/sound/sh/aica.c b/sound/sh/aica.c index fbbc25279559..ab4802df62e1 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -535,7 +535,7 @@ static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol, return 1; } -static struct snd_kcontrol_new snd_aica_pcmswitch_control = { +static const struct snd_kcontrol_new snd_aica_pcmswitch_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Switch", .index = 0, @@ -544,7 +544,7 @@ static struct snd_kcontrol_new snd_aica_pcmswitch_control = { .put = aica_pcmswitch_put }; -static struct snd_kcontrol_new snd_aica_pcmvolume_control = { +static const struct snd_kcontrol_new snd_aica_pcmvolume_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Volume", .index = 0, diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c index 76b2ab8c2b4a..4a22aadac294 100644 --- a/sound/soc/sh/siu_dai.c +++ b/sound/soc/sh/siu_dai.c @@ -441,7 +441,7 @@ static int siu_dai_put_volume(struct snd_kcontrol *kctrl, return 0; } -static struct snd_kcontrol_new playback_controls = { +static const struct snd_kcontrol_new playback_controls = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Volume", .index = 0, @@ -451,7 +451,7 @@ static struct snd_kcontrol_new playback_controls = { .private_value = VOLUME_PLAYBACK, }; -static struct snd_kcontrol_new capture_controls = { +static const struct snd_kcontrol_new capture_controls = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Capture Volume", .index = 0, diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 4fa0053a40af..e3d1dec48ee4 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -362,7 +362,7 @@ static int snd_audigy2nx_led_resume(struct usb_mixer_elem_list *list) } /* name and private_value are set dynamically */ -static struct snd_kcontrol_new snd_audigy2nx_control = { +static const struct snd_kcontrol_new snd_audigy2nx_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = snd_audigy2nx_led_info, .get = snd_audigy2nx_led_get, From 7421a1671abe5bc07cc7a09f5a1be45acc403db7 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 30 May 2017 11:39:45 +0100 Subject: [PATCH 129/418] ALSA: pcm: include pcm_local.h and remove some extraneous tabs We need to include pcm_local.h to clean up some smatch warnings: symbol 'snd_pcm_timer_done' was not declared. Should it be static? symbol 'snd_pcm_timer_init' was not declared. Should it be static? symbol 'snd_pcm_timer_resolution_change' was not declared. Should it be static? Also remove some extraneous tabs on empty lines and replace space intentation with a tab. Signed-off-by: Colin Ian King Signed-off-by: Takashi Iwai --- sound/core/pcm_timer.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c index 20ecd8f18080..11389f13de73 100644 --- a/sound/core/pcm_timer.c +++ b/sound/core/pcm_timer.c @@ -25,6 +25,8 @@ #include #include +#include "pcm_local.h" + /* * Timer functions */ @@ -33,8 +35,8 @@ void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream) { unsigned long rate, mult, fsize, l, post; struct snd_pcm_runtime *runtime = substream->runtime; - - mult = 1000000000; + + mult = 1000000000; rate = runtime->rate; if (snd_BUG_ON(!rate)) return; @@ -65,7 +67,7 @@ void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream) static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer) { struct snd_pcm_substream *substream; - + substream = timer->private_data; return substream->runtime ? substream->runtime->timer_resolution : 0; } @@ -73,7 +75,7 @@ static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer) static int snd_pcm_timer_start(struct snd_timer * timer) { struct snd_pcm_substream *substream; - + substream = snd_timer_chip(timer); substream->timer_running = 1; return 0; @@ -82,7 +84,7 @@ static int snd_pcm_timer_start(struct snd_timer * timer) static int snd_pcm_timer_stop(struct snd_timer * timer) { struct snd_pcm_substream *substream; - + substream = snd_timer_chip(timer); substream->timer_running = 0; return 0; @@ -112,7 +114,7 @@ void snd_pcm_timer_init(struct snd_pcm_substream *substream) { struct snd_timer_id tid; struct snd_timer *timer; - + tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; tid.dev_class = SNDRV_TIMER_CLASS_PCM; tid.card = substream->pcm->card->number; From 29d1a873de542cbb46d0641037d2601cb76be5b1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 20:02:35 +0200 Subject: [PATCH 130/418] ALSA: pcm: Introduce copy_user, copy_kernel and fill_silence ops For supporting the explicit in-kernel copy of PCM buffer data, and also for further code refactoring, three new PCM ops, copy_user, copy_kernel and fill_silence, are introduced. The old copy and silence ops will be deprecated and removed later once when all callers are converted. The copy_kernel ops is the new one, and it's supposed to transfer the PCM data from the given kernel buffer to the hardware ring-buffer (or vice-versa depending on the stream direction), while the copy_user ops is equivalent with the former copy ops, to transfer the data from the user-space buffer. The major difference of the new copy_* and fill_silence ops from the previous ops is that the new ops take bytes instead of frames for size and position arguments. It has two merits: first, it allows the callback implementation often simpler (just call directly memcpy() & co), and second, it may unify the implementations of both interleaved and non-interleaved cases, as we'll see in the later patch. As of this stage, copy_kernel ops isn't referred yet, but only copy_user is used. Reviewed-by: Takashi Sakamoto Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 7 ++++ sound/core/pcm_lib.c | 89 ++++++++++++++++++++++++++++++++++++-------- sound/soc/soc-pcm.c | 3 ++ 3 files changed, 84 insertions(+), 15 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 79fedf517070..86b126be49a2 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -83,6 +83,13 @@ struct snd_pcm_ops { void __user *buf, snd_pcm_uframes_t count); int (*silence)(struct snd_pcm_substream *substream, int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count); + int (*fill_silence)(struct snd_pcm_substream *substream, int channel, + unsigned long pos, unsigned long bytes); + int (*copy_user)(struct snd_pcm_substream *substream, int channel, + unsigned long pos, void __user *buf, + unsigned long bytes); + int (*copy_kernel)(struct snd_pcm_substream *substream, int channel, + unsigned long pos, void *buf, unsigned long bytes); struct page *(*page)(struct snd_pcm_substream *substream, unsigned long offset); int (*mmap)(struct snd_pcm_substream *substream, struct vm_area_struct *vma); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index e50548af4004..1fca1ffd235e 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -57,6 +57,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t frames, ofs, transfer; + char *hwbuf; + int err; if (runtime->silence_size < runtime->boundary) { snd_pcm_sframes_t noise_dist, n; @@ -111,27 +113,37 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames; if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) { - if (substream->ops->silence) { - int err; + if (substream->ops->fill_silence) { + err = substream->ops->fill_silence(substream, 0, + frames_to_bytes(runtime, ofs), + frames_to_bytes(runtime, transfer)); + snd_BUG_ON(err < 0); + } else if (substream->ops->silence) { err = substream->ops->silence(substream, -1, ofs, transfer); snd_BUG_ON(err < 0); } else { - char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs); + hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs); snd_pcm_format_set_silence(runtime->format, hwbuf, transfer * runtime->channels); } } else { unsigned int c; unsigned int channels = runtime->channels; - if (substream->ops->silence) { + if (substream->ops->fill_silence) { + for (c = 0; c < channels; ++c) { + err = substream->ops->fill_silence(substream, c, + samples_to_bytes(runtime, ofs), + samples_to_bytes(runtime, transfer)); + snd_BUG_ON(err < 0); + } + } else if (substream->ops->silence) { for (c = 0; c < channels; ++c) { - int err; err = substream->ops->silence(substream, c, ofs, transfer); snd_BUG_ON(err < 0); } } else { size_t dma_csize = runtime->dma_bytes / channels; for (c = 0; c < channels; ++c) { - char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, ofs); + hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, ofs); snd_pcm_format_set_silence(runtime->format, hwbuf, transfer); } } @@ -1997,7 +2009,13 @@ static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; int err; char __user *buf = (char __user *) data + frames_to_bytes(runtime, off); - if (substream->ops->copy) { + if (substream->ops->copy_user) { + hwoff = frames_to_bytes(runtime, hwoff); + frames = frames_to_bytes(runtime, frames); + err = substream->ops->copy_user(substream, 0, hwoff, buf, frames); + if (err < 0) + return err; + } else if (substream->ops->copy) { if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0) return err; } else { @@ -2121,7 +2139,8 @@ static int pcm_sanity_check(struct snd_pcm_substream *substream) if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; - if (snd_BUG_ON(!substream->ops->copy && !runtime->dma_area)) + if (snd_BUG_ON(!substream->ops->copy_user && !substream->ops->copy + && !runtime->dma_area)) return -EINVAL; if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; @@ -2158,8 +2177,30 @@ static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream, int err; void __user **bufs = (void __user **)data; int channels = runtime->channels; + char __user *buf; int c; - if (substream->ops->copy) { + + if (substream->ops->copy_user) { + hwoff = samples_to_bytes(runtime, hwoff); + off = samples_to_bytes(runtime, off); + frames = samples_to_bytes(runtime, frames); + for (c = 0; c < channels; ++c, ++bufs) { + buf = *bufs + off; + if (!*bufs) { + if (snd_BUG_ON(!substream->ops->fill_silence)) + return -EINVAL; + err = substream->ops->fill_silence(substream, c, + hwoff, + frames); + } else { + err = substream->ops->copy_user(substream, c, + hwoff, buf, + frames); + } + if (err < 0) + return err; + } + } else if (substream->ops->copy) { if (snd_BUG_ON(!substream->ops->silence)) return -EINVAL; for (c = 0; c < channels; ++c, ++bufs) { @@ -2167,7 +2208,7 @@ static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream, if ((err = substream->ops->silence(substream, c, hwoff, frames)) < 0) return err; } else { - char __user *buf = *bufs + samples_to_bytes(runtime, off); + buf = *bufs + samples_to_bytes(runtime, off); if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0) return err; } @@ -2219,7 +2260,13 @@ static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; int err; char __user *buf = (char __user *) data + frames_to_bytes(runtime, off); - if (substream->ops->copy) { + if (substream->ops->copy_user) { + hwoff = frames_to_bytes(runtime, hwoff); + frames = frames_to_bytes(runtime, frames); + err = substream->ops->copy_user(substream, 0, hwoff, buf, frames); + if (err < 0) + return err; + } else if (substream->ops->copy) { if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0) return err; } else { @@ -2367,10 +2414,24 @@ static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream, int err; void __user **bufs = (void __user **)data; int channels = runtime->channels; + char __user *buf; + char *hwbuf; int c; - if (substream->ops->copy) { + + if (substream->ops->copy_user) { + hwoff = samples_to_bytes(runtime, hwoff); + off = samples_to_bytes(runtime, off); + frames = samples_to_bytes(runtime, frames); + for (c = 0; c < channels; ++c, ++bufs) { + if (!*bufs) + continue; + err = substream->ops->copy_user(substream, c, hwoff, + *bufs + off, frames); + if (err < 0) + return err; + } + } else if (substream->ops->copy) { for (c = 0; c < channels; ++c, ++bufs) { - char __user *buf; if (*bufs == NULL) continue; buf = *bufs + samples_to_bytes(runtime, off); @@ -2380,8 +2441,6 @@ static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream, } else { snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels; for (c = 0; c < channels; ++c, ++bufs) { - char *hwbuf; - char __user *buf; if (*bufs == NULL) continue; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index efc5831f205d..8867ed9e5f56 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2743,6 +2743,9 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (platform->driver->ops) { rtd->ops.ack = platform->driver->ops->ack; + rtd->ops.copy_user = platform->driver->ops->copy_user; + rtd->ops.copy_kernel = platform->driver->ops->copy_kernel; + rtd->ops.fill_silence = platform->driver->ops->fill_silence; rtd->ops.copy = platform->driver->ops->copy; rtd->ops.silence = platform->driver->ops->silence; rtd->ops.page = platform->driver->ops->page; From d53611d21ef6000619e87f6cfc1f6d870c10cd93 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 20:15:40 +0200 Subject: [PATCH 131/418] ALSA: dummy: Convert to new PCM copy ops It's a dummy ops, so just replacing it. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/drivers/dummy.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 172dacd925f5..dd5ed037adf2 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -644,15 +644,22 @@ static int alloc_fake_buffer(void) } static int dummy_pcm_copy(struct snd_pcm_substream *substream, - int channel, snd_pcm_uframes_t pos, - void __user *dst, snd_pcm_uframes_t count) + int channel, unsigned long pos, + void __user *dst, unsigned long bytes) +{ + return 0; /* do nothing */ +} + +static int dummy_pcm_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *dst, unsigned long bytes) { return 0; /* do nothing */ } static int dummy_pcm_silence(struct snd_pcm_substream *substream, - int channel, snd_pcm_uframes_t pos, - snd_pcm_uframes_t count) + int channel, unsigned long pos, + unsigned long bytes) { return 0; /* do nothing */ } @@ -683,8 +690,9 @@ static struct snd_pcm_ops dummy_pcm_ops_no_buf = { .prepare = dummy_pcm_prepare, .trigger = dummy_pcm_trigger, .pointer = dummy_pcm_pointer, - .copy = dummy_pcm_copy, - .silence = dummy_pcm_silence, + .copy_user = dummy_pcm_copy, + .copy_kernel = dummy_pcm_copy_kernel, + .fill_silence = dummy_pcm_silence, .page = dummy_pcm_page, }; From b96c3a155696eae0a3c08b71f7642ccb1437ac75 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 20:16:36 +0200 Subject: [PATCH 132/418] ALSA: es1938: Convert to the new PCM copy ops Replace the copy ops with the new copy_user and copy_kernel ops. It's used only for a capture stream (for some hardware workaround), thus we need no silence operation. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/es1938.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index e8d943071a8c..a544cd52f73a 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -839,15 +839,12 @@ static snd_pcm_uframes_t snd_es1938_playback_pointer(struct snd_pcm_substream *s } static int snd_es1938_capture_copy(struct snd_pcm_substream *substream, - int channel, - snd_pcm_uframes_t pos, - void __user *dst, - snd_pcm_uframes_t count) + int channel, unsigned long pos, + void __user *dst, unsigned long count) { struct snd_pcm_runtime *runtime = substream->runtime; struct es1938 *chip = snd_pcm_substream_chip(substream); - pos <<= chip->dma1_shift; - count <<= chip->dma1_shift; + if (snd_BUG_ON(pos + count > chip->dma1_size)) return -EINVAL; if (pos + count < chip->dma1_size) { @@ -856,12 +853,31 @@ static int snd_es1938_capture_copy(struct snd_pcm_substream *substream, } else { if (copy_to_user(dst, runtime->dma_area + pos + 1, count - 1)) return -EFAULT; - if (put_user(runtime->dma_area[0], ((unsigned char __user *)dst) + count - 1)) + if (put_user(runtime->dma_area[0], + ((unsigned char __user *)dst) + count - 1)) return -EFAULT; } return 0; } +static int snd_es1938_capture_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *dst, unsigned long count) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct es1938 *chip = snd_pcm_substream_chip(substream); + + if (snd_BUG_ON(pos + count > chip->dma1_size)) + return -EINVAL; + if (pos + count < chip->dma1_size) { + memcpy(dst, runtime->dma_area + pos + 1, count); + } else { + memcpy(dst, runtime->dma_area + pos + 1, count - 1); + runtime->dma_area[0] = *((unsigned char *)dst + count - 1); + } + return 0; +} + /* * buffer management */ @@ -1012,7 +1028,8 @@ static const struct snd_pcm_ops snd_es1938_capture_ops = { .prepare = snd_es1938_capture_prepare, .trigger = snd_es1938_capture_trigger, .pointer = snd_es1938_capture_pointer, - .copy = snd_es1938_capture_copy, + .copy_user = snd_es1938_capture_copy, + .copy_kernel = snd_es1938_capture_copy_kernel, }; static int snd_es1938_new_pcm(struct es1938 *chip, int device) From 21de5673663f2620fa2838e4e2ea5db9c91fad4d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 20:25:17 +0200 Subject: [PATCH 133/418] ALSA: nm256: Convert to new PCM copy ops Replace the copy and the silence ops with the new ops. The conversion is straightforward with standard helper functions, and now we can drop the bytes <-> frames conversions in callbacks. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/nm256/nm256.c | 57 ++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 103fe311e5a9..63f0985dae27 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -695,53 +695,68 @@ snd_nm256_capture_pointer(struct snd_pcm_substream *substream) */ static int snd_nm256_playback_silence(struct snd_pcm_substream *substream, - int channel, /* not used (interleaved data) */ - snd_pcm_uframes_t pos, - snd_pcm_uframes_t count) + int channel, unsigned long pos, unsigned long count) { struct snd_pcm_runtime *runtime = substream->runtime; struct nm256_stream *s = runtime->private_data; - count = frames_to_bytes(runtime, count); - pos = frames_to_bytes(runtime, pos); + memset_io(s->bufptr + pos, 0, count); return 0; } static int snd_nm256_playback_copy(struct snd_pcm_substream *substream, - int channel, /* not used (interleaved data) */ - snd_pcm_uframes_t pos, - void __user *src, - snd_pcm_uframes_t count) + int channel, unsigned long pos, + void __user *src, unsigned long count) { struct snd_pcm_runtime *runtime = substream->runtime; struct nm256_stream *s = runtime->private_data; - count = frames_to_bytes(runtime, count); - pos = frames_to_bytes(runtime, pos); + if (copy_from_user_toio(s->bufptr + pos, src, count)) return -EFAULT; return 0; } +static int +snd_nm256_playback_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *src, unsigned long count) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct nm256_stream *s = runtime->private_data; + + memcpy_toio(s->bufptr + pos, src, count); + return 0; +} + /* * copy to user */ static int snd_nm256_capture_copy(struct snd_pcm_substream *substream, - int channel, /* not used (interleaved data) */ - snd_pcm_uframes_t pos, - void __user *dst, - snd_pcm_uframes_t count) + int channel, unsigned long pos, + void __user *dst, unsigned long count) { struct snd_pcm_runtime *runtime = substream->runtime; struct nm256_stream *s = runtime->private_data; - count = frames_to_bytes(runtime, count); - pos = frames_to_bytes(runtime, pos); + if (copy_to_user_fromio(dst, s->bufptr + pos, count)) return -EFAULT; return 0; } +static int +snd_nm256_capture_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *dst, unsigned long count) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct nm256_stream *s = runtime->private_data; + + memcpy_fromio(dst, s->bufptr + pos, count); + return 0; +} + #endif /* !__i386__ */ @@ -911,8 +926,9 @@ static const struct snd_pcm_ops snd_nm256_playback_ops = { .trigger = snd_nm256_playback_trigger, .pointer = snd_nm256_playback_pointer, #ifndef __i386__ - .copy = snd_nm256_playback_copy, - .silence = snd_nm256_playback_silence, + .copy_user = snd_nm256_playback_copy, + .copy_kernel = snd_nm256_playback_copy_kernel, + .fill_silence = snd_nm256_playback_silence, #endif .mmap = snd_pcm_lib_mmap_iomem, }; @@ -926,7 +942,8 @@ static const struct snd_pcm_ops snd_nm256_capture_ops = { .trigger = snd_nm256_capture_trigger, .pointer = snd_nm256_capture_pointer, #ifndef __i386__ - .copy = snd_nm256_capture_copy, + .copy_user = snd_nm256_capture_copy, + .copy_kernel = snd_nm256_capture_copy_kernel, #endif .mmap = snd_pcm_lib_mmap_iomem, }; From 6c6ba11fad0b01356f53a37a1d776dd45c6875ae Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 20:19:17 +0200 Subject: [PATCH 134/418] ALSA: korg1212: Convert to the new PCM ops Replace the copy and the silence ops with the new PCM ops. Although we can refactor this messy code, at this time, the changes are kept as small as possible. Let's clean up later. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/korg1212/korg1212.c | 110 ++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 46 deletions(-) diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 1e25095fd144..b28fe4914d6b 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -1299,13 +1299,21 @@ static int snd_korg1212_silence(struct snd_korg1212 *korg1212, int pos, int coun return 0; } -static int snd_korg1212_copy_to(struct snd_korg1212 *korg1212, void __user *dst, int pos, int count, int offset, int size) +static int snd_korg1212_copy_to(struct snd_pcm_substream *substream, + void __user *dst, int pos, int count, + bool in_kernel) { - struct KorgAudioFrame * src = korg1212->recordDataBufsPtr[0].bufferData + pos; - int i, rc; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream); + struct KorgAudioFrame *src; + int i, size; - K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: snd_korg1212_copy_to pos=%d offset=%d size=%d\n", - pos, offset, size); + pos = bytes_to_frames(runtime, pos); + count = bytes_to_frames(runtime, count); + size = korg1212->channels * 2; + src = korg1212->recordDataBufsPtr[0].bufferData + pos; + K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: snd_korg1212_copy_to pos=%d size=%d count=%d\n", + pos, size, count); if (snd_BUG_ON(pos + count > K1212_MAX_SAMPLES)) return -EINVAL; @@ -1317,11 +1325,10 @@ static int snd_korg1212_copy_to(struct snd_korg1212 *korg1212, void __user *dst, return -EFAULT; } #endif - rc = copy_to_user(dst + offset, src, size); - if (rc) { - K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_copy_to USER EFAULT src=%p dst=%p iter=%d\n", src, dst, i); + if (in_kernel) + memcpy((void *)dst, src, size); + else if (copy_to_user(dst, src, size)) return -EFAULT; - } src++; dst += size; } @@ -1329,13 +1336,22 @@ static int snd_korg1212_copy_to(struct snd_korg1212 *korg1212, void __user *dst, return 0; } -static int snd_korg1212_copy_from(struct snd_korg1212 *korg1212, void __user *src, int pos, int count, int offset, int size) +static int snd_korg1212_copy_from(struct snd_pcm_substream *substream, + void __user *src, int pos, int count, + bool in_kernel) { - struct KorgAudioFrame * dst = korg1212->playDataBufsPtr[0].bufferData + pos; - int i, rc; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream); + struct KorgAudioFrame *dst; + int i, size; - K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: snd_korg1212_copy_from pos=%d offset=%d size=%d count=%d\n", - pos, offset, size, count); + pos = bytes_to_frames(runtime, pos); + count = bytes_to_frames(runtime, count); + size = korg1212->channels * 2; + dst = korg1212->playDataBufsPtr[0].bufferData + pos; + + K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: snd_korg1212_copy_from pos=%d size=%d count=%d\n", + pos, size, count); if (snd_BUG_ON(pos + count > K1212_MAX_SAMPLES)) return -EINVAL; @@ -1348,11 +1364,10 @@ static int snd_korg1212_copy_from(struct snd_korg1212 *korg1212, void __user *sr return -EFAULT; } #endif - rc = copy_from_user((void*) dst + offset, src, size); - if (rc) { - K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_copy_from USER EFAULT src=%p dst=%p iter=%d\n", src, dst, i); + if (in_kernel) + memcpy((void *)dst, src, size); + else if (copy_from_user(dst, src, size)) return -EFAULT; - } dst++; src += size; } @@ -1640,45 +1655,46 @@ static snd_pcm_uframes_t snd_korg1212_capture_pointer(struct snd_pcm_substream * } static int snd_korg1212_playback_copy(struct snd_pcm_substream *substream, - int channel, /* not used (interleaved data) */ - snd_pcm_uframes_t pos, - void __user *src, - snd_pcm_uframes_t count) + int channel, unsigned long pos, + void __user *src, unsigned long count) { - struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream); - - K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: snd_korg1212_playback_copy [%s] %ld %ld\n", - stateName[korg1212->cardState], pos, count); - - return snd_korg1212_copy_from(korg1212, src, pos, count, 0, korg1212->channels * 2); + return snd_korg1212_copy_from(substream, src, pos, count, false); +} +static int snd_korg1212_playback_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *src, unsigned long count) +{ + return snd_korg1212_copy_from(substream, (void __user *)src, + pos, count, true); } static int snd_korg1212_playback_silence(struct snd_pcm_substream *substream, int channel, /* not used (interleaved data) */ - snd_pcm_uframes_t pos, - snd_pcm_uframes_t count) + unsigned long pos, + unsigned long count) { + struct snd_pcm_runtime *runtime = substream->runtime; struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream); - K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: snd_korg1212_playback_silence [%s]\n", - stateName[korg1212->cardState]); - - return snd_korg1212_silence(korg1212, pos, count, 0, korg1212->channels * 2); + return snd_korg1212_silence(korg1212, bytes_to_frames(runtime, pos), + bytes_to_frames(runtime, count), + 0, korg1212->channels * 2); } static int snd_korg1212_capture_copy(struct snd_pcm_substream *substream, - int channel, /* not used (interleaved data) */ - snd_pcm_uframes_t pos, - void __user *dst, - snd_pcm_uframes_t count) + int channel, unsigned long pos, + void __user *dst, unsigned long count) { - struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream); + return snd_korg1212_copy_to(substream, dst, pos, count, false); +} - K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: snd_korg1212_capture_copy [%s] %ld %ld\n", - stateName[korg1212->cardState], pos, count); - - return snd_korg1212_copy_to(korg1212, dst, pos, count, 0, korg1212->channels * 2); +static int snd_korg1212_capture_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *dst, unsigned long count) +{ + return snd_korg1212_copy_to(substream, (void __user *)dst, + pos, count, true); } static const struct snd_pcm_ops snd_korg1212_playback_ops = { @@ -1689,8 +1705,9 @@ static const struct snd_pcm_ops snd_korg1212_playback_ops = { .prepare = snd_korg1212_prepare, .trigger = snd_korg1212_trigger, .pointer = snd_korg1212_playback_pointer, - .copy = snd_korg1212_playback_copy, - .silence = snd_korg1212_playback_silence, + .copy_user = snd_korg1212_playback_copy, + .copy_kernel = snd_korg1212_playback_copy_kernel, + .fill_silence = snd_korg1212_playback_silence, }; static const struct snd_pcm_ops snd_korg1212_capture_ops = { @@ -1701,7 +1718,8 @@ static const struct snd_pcm_ops snd_korg1212_capture_ops = { .prepare = snd_korg1212_prepare, .trigger = snd_korg1212_trigger, .pointer = snd_korg1212_capture_pointer, - .copy = snd_korg1212_capture_copy, + .copy_user = snd_korg1212_capture_copy, + .copy_kernel = snd_korg1212_capture_copy_kernel, }; /* From 032db751efa7d3eb80a3f4b3fde51eb4f6c24308 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 20:29:25 +0200 Subject: [PATCH 135/418] ALSA: rme32: Convert to the new PCM copy ops Replace the copy and the silence ops with the new ops. The conversion is straightforward with standard helper functions, and now we can drop the bytes <-> frames conversions in callbacks. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/rme32.c | 67 +++++++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index f9b424056d0f..67d48c8869e9 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -254,39 +254,46 @@ static inline unsigned int snd_rme32_pcm_byteptr(struct rme32 * rme32) } /* silence callback for halfduplex mode */ -static int snd_rme32_playback_silence(struct snd_pcm_substream *substream, int channel, /* not used (interleaved data) */ - snd_pcm_uframes_t pos, - snd_pcm_uframes_t count) +static int snd_rme32_playback_silence(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + unsigned long count) { struct rme32 *rme32 = snd_pcm_substream_chip(substream); - count <<= rme32->playback_frlog; - pos <<= rme32->playback_frlog; + memset_io(rme32->iobase + RME32_IO_DATA_BUFFER + pos, 0, count); return 0; } /* copy callback for halfduplex mode */ -static int snd_rme32_playback_copy(struct snd_pcm_substream *substream, int channel, /* not used (interleaved data) */ - snd_pcm_uframes_t pos, - void __user *src, snd_pcm_uframes_t count) +static int snd_rme32_playback_copy(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void __user *src, unsigned long count) { struct rme32 *rme32 = snd_pcm_substream_chip(substream); - count <<= rme32->playback_frlog; - pos <<= rme32->playback_frlog; + if (copy_from_user_toio(rme32->iobase + RME32_IO_DATA_BUFFER + pos, - src, count)) + src, count)) return -EFAULT; return 0; } -/* copy callback for halfduplex mode */ -static int snd_rme32_capture_copy(struct snd_pcm_substream *substream, int channel, /* not used (interleaved data) */ - snd_pcm_uframes_t pos, - void __user *dst, snd_pcm_uframes_t count) +static int snd_rme32_playback_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *src, unsigned long count) { struct rme32 *rme32 = snd_pcm_substream_chip(substream); - count <<= rme32->capture_frlog; - pos <<= rme32->capture_frlog; + + memcpy_toio(rme32->iobase + RME32_IO_DATA_BUFFER + pos, src, count); + return 0; +} + +/* copy callback for halfduplex mode */ +static int snd_rme32_capture_copy(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void __user *dst, unsigned long count) +{ + struct rme32 *rme32 = snd_pcm_substream_chip(substream); + if (copy_to_user_fromio(dst, rme32->iobase + RME32_IO_DATA_BUFFER + pos, count)) @@ -294,6 +301,16 @@ static int snd_rme32_capture_copy(struct snd_pcm_substream *substream, int chann return 0; } +static int snd_rme32_capture_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *dst, unsigned long count) +{ + struct rme32 *rme32 = snd_pcm_substream_chip(substream); + + memcpy_fromio(dst, rme32->iobase + RME32_IO_DATA_BUFFER + pos, count); + return 0; +} + /* * SPDIF I/O capabilities (half-duplex mode) */ @@ -1203,8 +1220,9 @@ static const struct snd_pcm_ops snd_rme32_playback_spdif_ops = { .prepare = snd_rme32_playback_prepare, .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_playback_pointer, - .copy = snd_rme32_playback_copy, - .silence = snd_rme32_playback_silence, + .copy_user = snd_rme32_playback_copy, + .copy_kernel = snd_rme32_playback_copy_kernel, + .fill_silence = snd_rme32_playback_silence, .mmap = snd_pcm_lib_mmap_iomem, }; @@ -1217,7 +1235,8 @@ static const struct snd_pcm_ops snd_rme32_capture_spdif_ops = { .prepare = snd_rme32_capture_prepare, .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_capture_pointer, - .copy = snd_rme32_capture_copy, + .copy_user = snd_rme32_capture_copy, + .copy_kernel = snd_rme32_capture_copy_kernel, .mmap = snd_pcm_lib_mmap_iomem, }; @@ -1229,8 +1248,9 @@ static const struct snd_pcm_ops snd_rme32_playback_adat_ops = { .prepare = snd_rme32_playback_prepare, .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_playback_pointer, - .copy = snd_rme32_playback_copy, - .silence = snd_rme32_playback_silence, + .copy_user = snd_rme32_playback_copy, + .copy_kernel = snd_rme32_playback_copy_kernel, + .fill_silence = snd_rme32_playback_silence, .mmap = snd_pcm_lib_mmap_iomem, }; @@ -1242,7 +1262,8 @@ static const struct snd_pcm_ops snd_rme32_capture_adat_ops = { .prepare = snd_rme32_capture_prepare, .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_capture_pointer, - .copy = snd_rme32_capture_copy, + .copy_user = snd_rme32_capture_copy, + .copy_kernel = snd_rme32_capture_copy_kernel, .mmap = snd_pcm_lib_mmap_iomem, }; From 53945f5b8ae550d8c6f7ac8ed9b1e496778fad45 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 20:30:34 +0200 Subject: [PATCH 136/418] ALSA: rme96: Convert to the new PCM ops Replace the copy and the silence ops with the new PCM ops. The conversion is straightforward with standard helper functions, and now we can drop the bytes <-> frames conversions in callbacks. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/rme96.c | 70 +++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 05b9da30990d..24f1349a8e1b 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -327,13 +327,10 @@ snd_rme96_capture_ptr(struct rme96 *rme96) static int snd_rme96_playback_silence(struct snd_pcm_substream *substream, - int channel, /* not used (interleaved data) */ - snd_pcm_uframes_t pos, - snd_pcm_uframes_t count) + int channel, unsigned long pos, unsigned long count) { struct rme96 *rme96 = snd_pcm_substream_chip(substream); - count <<= rme96->playback_frlog; - pos <<= rme96->playback_frlog; + memset_io(rme96->iobase + RME96_IO_PLAY_BUFFER + pos, 0, count); return 0; @@ -341,32 +338,49 @@ snd_rme96_playback_silence(struct snd_pcm_substream *substream, static int snd_rme96_playback_copy(struct snd_pcm_substream *substream, - int channel, /* not used (interleaved data) */ - snd_pcm_uframes_t pos, - void __user *src, - snd_pcm_uframes_t count) + int channel, unsigned long pos, + void __user *src, unsigned long count) { struct rme96 *rme96 = snd_pcm_substream_chip(substream); - count <<= rme96->playback_frlog; - pos <<= rme96->playback_frlog; - return copy_from_user_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + pos, src, - count); + + return copy_from_user_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + pos, + src, count); +} + +static int +snd_rme96_playback_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *src, unsigned long count) +{ + struct rme96 *rme96 = snd_pcm_substream_chip(substream); + + memcpy_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + pos, src, count); + return 0; } static int snd_rme96_capture_copy(struct snd_pcm_substream *substream, - int channel, /* not used (interleaved data) */ - snd_pcm_uframes_t pos, - void __user *dst, - snd_pcm_uframes_t count) + int channel, unsigned long pos, + void __user *dst, unsigned long count) { struct rme96 *rme96 = snd_pcm_substream_chip(substream); - count <<= rme96->capture_frlog; - pos <<= rme96->capture_frlog; - return copy_to_user_fromio(dst, rme96->iobase + RME96_IO_REC_BUFFER + pos, + + return copy_to_user_fromio(dst, + rme96->iobase + RME96_IO_REC_BUFFER + pos, count); } +static int +snd_rme96_capture_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *dst, unsigned long count) +{ + struct rme96 *rme96 = snd_pcm_substream_chip(substream); + + memcpy_fromio(dst, rme96->iobase + RME96_IO_REC_BUFFER + pos, count); + return 0; +} + /* * Digital output capabilities (S/PDIF) */ @@ -1513,8 +1527,9 @@ static const struct snd_pcm_ops snd_rme96_playback_spdif_ops = { .prepare = snd_rme96_playback_prepare, .trigger = snd_rme96_playback_trigger, .pointer = snd_rme96_playback_pointer, - .copy = snd_rme96_playback_copy, - .silence = snd_rme96_playback_silence, + .copy_user = snd_rme96_playback_copy, + .copy_kernel = snd_rme96_playback_copy_kernel, + .fill_silence = snd_rme96_playback_silence, .mmap = snd_pcm_lib_mmap_iomem, }; @@ -1526,7 +1541,8 @@ static const struct snd_pcm_ops snd_rme96_capture_spdif_ops = { .prepare = snd_rme96_capture_prepare, .trigger = snd_rme96_capture_trigger, .pointer = snd_rme96_capture_pointer, - .copy = snd_rme96_capture_copy, + .copy_user = snd_rme96_capture_copy, + .copy_kernel = snd_rme96_capture_copy_kernel, .mmap = snd_pcm_lib_mmap_iomem, }; @@ -1538,8 +1554,9 @@ static const struct snd_pcm_ops snd_rme96_playback_adat_ops = { .prepare = snd_rme96_playback_prepare, .trigger = snd_rme96_playback_trigger, .pointer = snd_rme96_playback_pointer, - .copy = snd_rme96_playback_copy, - .silence = snd_rme96_playback_silence, + .copy_user = snd_rme96_playback_copy, + .copy_kernel = snd_rme96_playback_copy_kernel, + .fill_silence = snd_rme96_playback_silence, .mmap = snd_pcm_lib_mmap_iomem, }; @@ -1551,7 +1568,8 @@ static const struct snd_pcm_ops snd_rme96_capture_adat_ops = { .prepare = snd_rme96_capture_prepare, .trigger = snd_rme96_capture_trigger, .pointer = snd_rme96_capture_pointer, - .copy = snd_rme96_capture_copy, + .copy_user = snd_rme96_capture_copy, + .copy_kernel = snd_rme96_capture_copy_kernel, .mmap = snd_pcm_lib_mmap_iomem, }; From 7b6ae34da6302ea1b64b45c957c1a323e1fb2e08 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 20:31:41 +0200 Subject: [PATCH 137/418] ALSA: rme9652: Convert to the new PCM ops Replace the copy and the silence ops with the new PCM ops. The conversion is straightforward with standard helper functions. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/rme9652/rme9652.c | 71 ++++++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 17 deletions(-) diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 55172c689991..59684bf5cac0 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -1883,13 +1883,14 @@ static char *rme9652_channel_buffer_location(struct snd_rme9652 *rme9652, } } -static int snd_rme9652_playback_copy(struct snd_pcm_substream *substream, int channel, - snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count) +static int snd_rme9652_playback_copy(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void __user *src, unsigned long count) { struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); char *channel_buf; - if (snd_BUG_ON(pos + count > RME9652_CHANNEL_BUFFER_BYTES / 4)) + if (snd_BUG_ON(pos + count > RME9652_CHANNEL_BUFFER_BYTES)) return -EINVAL; channel_buf = rme9652_channel_buffer_location (rme9652, @@ -1897,18 +1898,35 @@ static int snd_rme9652_playback_copy(struct snd_pcm_substream *substream, int ch channel); if (snd_BUG_ON(!channel_buf)) return -EIO; - if (copy_from_user(channel_buf + pos * 4, src, count * 4)) + if (copy_from_user(channel_buf + pos, src, count)) return -EFAULT; - return count; + return 0; } -static int snd_rme9652_capture_copy(struct snd_pcm_substream *substream, int channel, - snd_pcm_uframes_t pos, void __user *dst, snd_pcm_uframes_t count) +static int snd_rme9652_playback_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *src, unsigned long count) { struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); char *channel_buf; - if (snd_BUG_ON(pos + count > RME9652_CHANNEL_BUFFER_BYTES / 4)) + channel_buf = rme9652_channel_buffer_location(rme9652, + substream->pstr->stream, + channel); + if (snd_BUG_ON(!channel_buf)) + return -EIO; + memcpy(channel_buf + pos, src, count); + return 0; +} + +static int snd_rme9652_capture_copy(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void __user *dst, unsigned long count) +{ + struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); + char *channel_buf; + + if (snd_BUG_ON(pos + count > RME9652_CHANNEL_BUFFER_BYTES)) return -EINVAL; channel_buf = rme9652_channel_buffer_location (rme9652, @@ -1916,13 +1934,30 @@ static int snd_rme9652_capture_copy(struct snd_pcm_substream *substream, int cha channel); if (snd_BUG_ON(!channel_buf)) return -EIO; - if (copy_to_user(dst, channel_buf + pos * 4, count * 4)) + if (copy_to_user(dst, channel_buf + pos, count)) return -EFAULT; - return count; + return 0; } -static int snd_rme9652_hw_silence(struct snd_pcm_substream *substream, int channel, - snd_pcm_uframes_t pos, snd_pcm_uframes_t count) +static int snd_rme9652_capture_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *dst, unsigned long count) +{ + struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); + char *channel_buf; + + channel_buf = rme9652_channel_buffer_location(rme9652, + substream->pstr->stream, + channel); + if (snd_BUG_ON(!channel_buf)) + return -EIO; + memcpy(dst, channel_buf + pos, count); + return 0; +} + +static int snd_rme9652_hw_silence(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + unsigned long count) { struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); char *channel_buf; @@ -1932,8 +1967,8 @@ static int snd_rme9652_hw_silence(struct snd_pcm_substream *substream, int chann channel); if (snd_BUG_ON(!channel_buf)) return -EIO; - memset(channel_buf + pos * 4, 0, count * 4); - return count; + memset(channel_buf + pos, 0, count); + return 0; } static int snd_rme9652_reset(struct snd_pcm_substream *substream) @@ -2376,8 +2411,9 @@ static const struct snd_pcm_ops snd_rme9652_playback_ops = { .prepare = snd_rme9652_prepare, .trigger = snd_rme9652_trigger, .pointer = snd_rme9652_hw_pointer, - .copy = snd_rme9652_playback_copy, - .silence = snd_rme9652_hw_silence, + .copy_user = snd_rme9652_playback_copy, + .copy_kernel = snd_rme9652_playback_copy_kernel, + .fill_silence = snd_rme9652_hw_silence, }; static const struct snd_pcm_ops snd_rme9652_capture_ops = { @@ -2388,7 +2424,8 @@ static const struct snd_pcm_ops snd_rme9652_capture_ops = { .prepare = snd_rme9652_prepare, .trigger = snd_rme9652_trigger, .pointer = snd_rme9652_hw_pointer, - .copy = snd_rme9652_capture_copy, + .copy_user = snd_rme9652_capture_copy, + .copy_kernel = snd_rme9652_capture_copy_kernel, }; static int snd_rme9652_create_pcm(struct snd_card *card, From 0925e6b26fcb52808145fbbb6d769485cb46f47b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 20:32:25 +0200 Subject: [PATCH 138/418] ALSA: hdsp: Convert to the new PCM ops Replace the copy and the silence ops with the new PCM ops. The conversion is straightforward with standard helper functions. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdsp.c | 67 ++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index fc0face6cdc6..b00009644e0e 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -3913,42 +3913,73 @@ static char *hdsp_channel_buffer_location(struct hdsp *hdsp, return hdsp->playback_buffer + (mapped_channel * HDSP_CHANNEL_BUFFER_BYTES); } -static int snd_hdsp_playback_copy(struct snd_pcm_substream *substream, int channel, - snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count) +static int snd_hdsp_playback_copy(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void __user *src, unsigned long count) { struct hdsp *hdsp = snd_pcm_substream_chip(substream); char *channel_buf; - if (snd_BUG_ON(pos + count > HDSP_CHANNEL_BUFFER_BYTES / 4)) + if (snd_BUG_ON(pos + count > HDSP_CHANNEL_BUFFER_BYTES)) return -EINVAL; channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel); if (snd_BUG_ON(!channel_buf)) return -EIO; - if (copy_from_user(channel_buf + pos * 4, src, count * 4)) + if (copy_from_user(channel_buf + pos, src, count)) return -EFAULT; - return count; + return 0; } -static int snd_hdsp_capture_copy(struct snd_pcm_substream *substream, int channel, - snd_pcm_uframes_t pos, void __user *dst, snd_pcm_uframes_t count) +static int snd_hdsp_playback_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *src, unsigned long count) { struct hdsp *hdsp = snd_pcm_substream_chip(substream); char *channel_buf; - if (snd_BUG_ON(pos + count > HDSP_CHANNEL_BUFFER_BYTES / 4)) + channel_buf = hdsp_channel_buffer_location(hdsp, substream->pstr->stream, channel); + if (snd_BUG_ON(!channel_buf)) + return -EIO; + memcpy(channel_buf + pos, src, count); + return 0; +} + +static int snd_hdsp_capture_copy(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void __user *dst, unsigned long count) +{ + struct hdsp *hdsp = snd_pcm_substream_chip(substream); + char *channel_buf; + + if (snd_BUG_ON(pos + count > HDSP_CHANNEL_BUFFER_BYTES)) return -EINVAL; channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel); if (snd_BUG_ON(!channel_buf)) return -EIO; - if (copy_to_user(dst, channel_buf + pos * 4, count * 4)) + if (copy_to_user(dst, channel_buf + pos, count)) return -EFAULT; - return count; + return 0; } -static int snd_hdsp_hw_silence(struct snd_pcm_substream *substream, int channel, - snd_pcm_uframes_t pos, snd_pcm_uframes_t count) +static int snd_hdsp_capture_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *dst, unsigned long count) +{ + struct hdsp *hdsp = snd_pcm_substream_chip(substream); + char *channel_buf; + + channel_buf = hdsp_channel_buffer_location(hdsp, substream->pstr->stream, channel); + if (snd_BUG_ON(!channel_buf)) + return -EIO; + memcpy(dst, channel_buf + pos, count); + return 0; +} + +static int snd_hdsp_hw_silence(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + unsigned long count) { struct hdsp *hdsp = snd_pcm_substream_chip(substream); char *channel_buf; @@ -3956,8 +3987,8 @@ static int snd_hdsp_hw_silence(struct snd_pcm_substream *substream, int channel, channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel); if (snd_BUG_ON(!channel_buf)) return -EIO; - memset(channel_buf + pos * 4, 0, count * 4); - return count; + memset(channel_buf + pos, 0, count); + return 0; } static int snd_hdsp_reset(struct snd_pcm_substream *substream) @@ -4869,8 +4900,9 @@ static const struct snd_pcm_ops snd_hdsp_playback_ops = { .prepare = snd_hdsp_prepare, .trigger = snd_hdsp_trigger, .pointer = snd_hdsp_hw_pointer, - .copy = snd_hdsp_playback_copy, - .silence = snd_hdsp_hw_silence, + .copy_user = snd_hdsp_playback_copy, + .copy_kernel = snd_hdsp_playback_copy_kernel, + .fill_silence = snd_hdsp_hw_silence, }; static const struct snd_pcm_ops snd_hdsp_capture_ops = { @@ -4881,7 +4913,8 @@ static const struct snd_pcm_ops snd_hdsp_capture_ops = { .prepare = snd_hdsp_prepare, .trigger = snd_hdsp_trigger, .pointer = snd_hdsp_hw_pointer, - .copy = snd_hdsp_capture_copy, + .copy_user = snd_hdsp_capture_copy, + .copy_kernel = snd_hdsp_capture_copy_kernel, }; static int snd_hdsp_create_hwdep(struct snd_card *card, struct hdsp *hdsp) From a6970bb1dd996943fce8c975282c7146fd69f560 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 20:33:05 +0200 Subject: [PATCH 139/418] ALSA: gus: Convert to the new PCM ops Replace the copy and the silence ops with the new PCM ops. For simplifying the code a bit, two local helpers are introduced here: get_bpos() and playback_copy_ack(). Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/isa/gus/gus_pcm.c | 101 ++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 40 deletions(-) diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index 0cc3f272edf1..b9f6dcbef889 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c @@ -353,26 +353,25 @@ static int snd_gf1_pcm_poke_block(struct snd_gus_card *gus, unsigned char *buf, return 0; } -static int snd_gf1_pcm_playback_copy(struct snd_pcm_substream *substream, - int voice, - snd_pcm_uframes_t pos, - void __user *src, - snd_pcm_uframes_t count) +static int get_bpos(struct gus_pcm_private *pcmp, int voice, unsigned int pos, + unsigned int len) { - struct snd_pcm_runtime *runtime = substream->runtime; - struct gus_pcm_private *pcmp = runtime->private_data; - struct snd_gus_card *gus = pcmp->gus; - unsigned int bpos, len; - int w16, invert; - - bpos = samples_to_bytes(runtime, pos) + (voice * (pcmp->dma_size / 2)); - len = samples_to_bytes(runtime, count); + unsigned int bpos = pos + (voice * (pcmp->dma_size / 2)); if (snd_BUG_ON(bpos > pcmp->dma_size)) return -EIO; if (snd_BUG_ON(bpos + len > pcmp->dma_size)) return -EIO; - if (copy_from_user(runtime->dma_area + bpos, src, len)) - return -EFAULT; + return bpos; +} + +static int playback_copy_ack(struct snd_pcm_substream *substream, + unsigned int bpos, unsigned int len) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct gus_pcm_private *pcmp = runtime->private_data; + struct snd_gus_card *gus = pcmp->gus; + int w16, invert; + if (len > 32) return snd_gf1_pcm_block_change(substream, bpos, pcmp->memory + bpos, len); @@ -383,33 +382,54 @@ static int snd_gf1_pcm_playback_copy(struct snd_pcm_substream *substream, pcmp->memory + bpos, len, w16, invert); } -static int snd_gf1_pcm_playback_silence(struct snd_pcm_substream *substream, - int voice, - snd_pcm_uframes_t pos, - snd_pcm_uframes_t count) +static int snd_gf1_pcm_playback_copy(struct snd_pcm_substream *substream, + int voice, unsigned long pos, + void __user *src, unsigned long count) { struct snd_pcm_runtime *runtime = substream->runtime; struct gus_pcm_private *pcmp = runtime->private_data; - struct snd_gus_card *gus = pcmp->gus; - unsigned int bpos, len; - int w16, invert; - - bpos = samples_to_bytes(runtime, pos) + (voice * (pcmp->dma_size / 2)); - len = samples_to_bytes(runtime, count); - if (snd_BUG_ON(bpos > pcmp->dma_size)) - return -EIO; - if (snd_BUG_ON(bpos + len > pcmp->dma_size)) - return -EIO; - snd_pcm_format_set_silence(runtime->format, runtime->dma_area + bpos, - count); - if (len > 32) - return snd_gf1_pcm_block_change(substream, bpos, - pcmp->memory + bpos, len); + unsigned int len = count; + int bpos; - w16 = (snd_pcm_format_width(runtime->format) == 16); - invert = snd_pcm_format_unsigned(runtime->format); - return snd_gf1_pcm_poke_block(gus, runtime->dma_area + bpos, - pcmp->memory + bpos, len, w16, invert); + bpos = get_bpos(pcmp, voice, pos, len); + if (bpos < 0) + return pos; + if (copy_from_user(runtime->dma_area + bpos, src, len)) + return -EFAULT; + return playback_copy_ack(substream, bpos, len); +} + +static int snd_gf1_pcm_playback_copy_kernel(struct snd_pcm_substream *substream, + int voice, unsigned long pos, + void *src, unsigned long count) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct gus_pcm_private *pcmp = runtime->private_data; + unsigned int len = count; + int bpos; + + bpos = get_bpos(pcmp, voice, pos, len); + if (bpos < 0) + return pos; + memcpy(runtime->dma_area + bpos, src, len); + return playback_copy_ack(substream, bpos, len); +} + +static int snd_gf1_pcm_playback_silence(struct snd_pcm_substream *substream, + int voice, unsigned long pos, + unsigned long count) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct gus_pcm_private *pcmp = runtime->private_data; + unsigned int len = count; + int bpos; + + bpos = get_bpos(pcmp, voice, pos, len); + if (bpos < 0) + return pos; + snd_pcm_format_set_silence(runtime->format, runtime->dma_area + bpos, + bytes_to_samples(runtime, count)); + return playback_copy_ack(substream, bpos, len); } static int snd_gf1_pcm_playback_hw_params(struct snd_pcm_substream *substream, @@ -831,8 +851,9 @@ static struct snd_pcm_ops snd_gf1_pcm_playback_ops = { .prepare = snd_gf1_pcm_playback_prepare, .trigger = snd_gf1_pcm_playback_trigger, .pointer = snd_gf1_pcm_playback_pointer, - .copy = snd_gf1_pcm_playback_copy, - .silence = snd_gf1_pcm_playback_silence, + .copy_user = snd_gf1_pcm_playback_copy, + .copy_kernel = snd_gf1_pcm_playback_copy_kernel, + .fill_silence = snd_gf1_pcm_playback_silence, }; static struct snd_pcm_ops snd_gf1_pcm_capture_ops = { From 4b83eff81c817d7e4c75605670320722611315b9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 20:34:45 +0200 Subject: [PATCH 140/418] ALSA: sb: Convert to the new PCM ops Replace the copy and the silence ops with the new PCM ops. For avoiding the code redundancy, slightly hackish macros are introduced. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/isa/sb/emu8000_pcm.c | 192 +++++++++++++++++++++---------------- 1 file changed, 110 insertions(+), 82 deletions(-) diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c index c480024422af..2ee8d67871ec 100644 --- a/sound/isa/sb/emu8000_pcm.c +++ b/sound/isa/sb/emu8000_pcm.c @@ -422,121 +422,148 @@ do { \ return -EAGAIN;\ } while (0) +enum { + COPY_USER, COPY_KERNEL, FILL_SILENCE, +}; + +#define GET_VAL(sval, buf, mode) \ + do { \ + switch (mode) { \ + case FILL_SILENCE: \ + sval = 0; \ + break; \ + case COPY_KERNEL: \ + sval = *buf++; \ + break; \ + default: \ + if (get_user(sval, (unsigned short __user *)buf)) \ + return -EFAULT; \ + buf++; \ + break; \ + } \ + } while (0) #ifdef USE_NONINTERLEAVE + +#define LOOP_WRITE(rec, offset, _buf, count, mode) \ + do { \ + struct snd_emu8000 *emu = (rec)->emu; \ + unsigned short *buf = (unsigned short *)(_buf); \ + snd_emu8000_write_wait(emu, 1); \ + EMU8000_SMALW_WRITE(emu, offset); \ + while (count > 0) { \ + unsigned short sval; \ + CHECK_SCHEDULER(); \ + GET_VAL(sval, buf, mode); \ + EMU8000_SMLD_WRITE(emu, sval); \ + count--; \ + } \ + } while (0) + /* copy one channel block */ -static int emu8k_transfer_block(struct snd_emu8000 *emu, int offset, unsigned short *buf, int count) +static int emu8k_pcm_copy(struct snd_pcm_substream *subs, + int voice, unsigned long pos, + void __user *src, unsigned long count) { - EMU8000_SMALW_WRITE(emu, offset); - while (count > 0) { - unsigned short sval; - CHECK_SCHEDULER(); - if (get_user(sval, buf)) - return -EFAULT; - EMU8000_SMLD_WRITE(emu, sval); - buf++; - count--; - } + struct snd_emu8k_pcm *rec = subs->runtime->private_data; + + /* convert to word unit */ + pos = (pos << 1) + rec->loop_start[voice]; + count <<= 1; + LOOP_WRITE(rec, pos, src, count, COPY_UESR); return 0; } -static int emu8k_pcm_copy(struct snd_pcm_substream *subs, - int voice, - snd_pcm_uframes_t pos, - void *src, - snd_pcm_uframes_t count) +static int emu8k_pcm_copy_kernel(struct snd_pcm_substream *subs, + int voice, unsigned long pos, + void *src, unsigned long count) { struct snd_emu8k_pcm *rec = subs->runtime->private_data; - struct snd_emu8000 *emu = rec->emu; - snd_emu8000_write_wait(emu, 1); - return emu8k_transfer_block(emu, pos + rec->loop_start[voice], src, - count); + /* convert to word unit */ + pos = (pos << 1) + rec->loop_start[voice]; + count <<= 1; + LOOP_WRITE(rec, pos, src, count, COPY_KERNEL); + return 0; } /* make a channel block silence */ -static int emu8k_silence_block(struct snd_emu8000 *emu, int offset, int count) +static int emu8k_pcm_silence(struct snd_pcm_substream *subs, + int voice, unsigned long pos, unsigned long count) { - EMU8000_SMALW_WRITE(emu, offset); - while (count > 0) { - CHECK_SCHEDULER(); - EMU8000_SMLD_WRITE(emu, 0); - count--; - } + struct snd_emu8k_pcm *rec = subs->runtime->private_data; + + /* convert to word unit */ + pos = (pos << 1) + rec->loop_start[voice]; + count <<= 1; + LOOP_WRITE(rec, pos, NULL, count, FILL_SILENCE); return 0; } -static int emu8k_pcm_silence(struct snd_pcm_substream *subs, - int voice, - snd_pcm_uframes_t pos, - snd_pcm_uframes_t count) -{ - struct snd_emu8k_pcm *rec = subs->runtime->private_data; - struct snd_emu8000 *emu = rec->emu; - - snd_emu8000_write_wait(emu, 1); - return emu8k_silence_block(emu, pos + rec->loop_start[voice], count); -} - #else /* interleave */ +#define LOOP_WRITE(rec, pos, _buf, count, mode) \ + do { \ + struct snd_emu8000 *emu = rec->emu; \ + unsigned short *buf = (unsigned short *)(_buf); \ + snd_emu8000_write_wait(emu, 1); \ + EMU8000_SMALW_WRITE(emu, pos + rec->loop_start[0]); \ + if (rec->voices > 1) \ + EMU8000_SMARW_WRITE(emu, pos + rec->loop_start[1]); \ + while (count > 0) { \ + unsigned short sval; \ + CHECK_SCHEDULER(); \ + GET_VAL(sval, buf, mode); \ + EMU8000_SMLD_WRITE(emu, sval); \ + if (rec->voices > 1) { \ + CHECK_SCHEDULER(); \ + GET_VAL(sval, buf, mode); \ + EMU8000_SMRD_WRITE(emu, sval); \ + } \ + count--; \ + } \ + } while (0) + + /* * copy the interleaved data can be done easily by using * DMA "left" and "right" channels on emu8k engine. */ static int emu8k_pcm_copy(struct snd_pcm_substream *subs, - int voice, - snd_pcm_uframes_t pos, - void __user *src, - snd_pcm_uframes_t count) + int voice, unsigned long pos, + void __user *src, unsigned long count) { struct snd_emu8k_pcm *rec = subs->runtime->private_data; - struct snd_emu8000 *emu = rec->emu; - unsigned short __user *buf = src; - snd_emu8000_write_wait(emu, 1); - EMU8000_SMALW_WRITE(emu, pos + rec->loop_start[0]); - if (rec->voices > 1) - EMU8000_SMARW_WRITE(emu, pos + rec->loop_start[1]); + /* convert to frames */ + pos = bytes_to_frames(subs->runtime, pos); + count = bytes_to_frames(subs->runtime, count); + LOOP_WRITE(rec, pos, src, count, COPY_USER); + return 0; +} - while (count-- > 0) { - unsigned short sval; - CHECK_SCHEDULER(); - if (get_user(sval, buf)) - return -EFAULT; - EMU8000_SMLD_WRITE(emu, sval); - buf++; - if (rec->voices > 1) { - CHECK_SCHEDULER(); - if (get_user(sval, buf)) - return -EFAULT; - EMU8000_SMRD_WRITE(emu, sval); - buf++; - } - } +static int emu8k_pcm_copy_kernel(struct snd_pcm_substream *subs, + int voice, unsigned long pos, + void *src, unsigned long count) +{ + struct snd_emu8k_pcm *rec = subs->runtime->private_data; + + /* convert to frames */ + pos = bytes_to_frames(subs->runtime, pos); + count = bytes_to_frames(subs->runtime, count); + LOOP_WRITE(rec, pos, src, count, COPY_KERNEL); return 0; } static int emu8k_pcm_silence(struct snd_pcm_substream *subs, - int voice, - snd_pcm_uframes_t pos, - snd_pcm_uframes_t count) + int voice, unsigned long pos, unsigned long count) { struct snd_emu8k_pcm *rec = subs->runtime->private_data; - struct snd_emu8000 *emu = rec->emu; - snd_emu8000_write_wait(emu, 1); - EMU8000_SMALW_WRITE(emu, rec->loop_start[0] + pos); - if (rec->voices > 1) - EMU8000_SMARW_WRITE(emu, rec->loop_start[1] + pos); - while (count-- > 0) { - CHECK_SCHEDULER(); - EMU8000_SMLD_WRITE(emu, 0); - if (rec->voices > 1) { - CHECK_SCHEDULER(); - EMU8000_SMRD_WRITE(emu, 0); - } - } + /* convert to frames */ + pos = bytes_to_frames(subs->runtime, pos); + count = bytes_to_frames(subs->runtime, count); + LOOP_WRITE(rec, pos, NULL, count, FILL_SILENCE); return 0; } #endif @@ -652,8 +679,9 @@ static struct snd_pcm_ops emu8k_pcm_ops = { .prepare = emu8k_pcm_prepare, .trigger = emu8k_pcm_trigger, .pointer = emu8k_pcm_pointer, - .copy = emu8k_pcm_copy, - .silence = emu8k_pcm_silence, + .copy_user = emu8k_pcm_copy, + .copy_kernel = emu8k_pcm_copy_kernel, + .fill_silence = emu8k_pcm_silence, }; From 1cc2f8ba0b3e63e0c8977cbad89e90352251c518 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 21:57:16 +0200 Subject: [PATCH 141/418] ALSA: sh: Convert to the new PCM ops Replace the copy and the silence ops with the new PCM ops. Fixed also the user-space buffer copy with the proper copy_from_user*() variant. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/sh/sh_dac_audio.c | 54 +++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c index 461b310c7872..c1e00ed715ee 100644 --- a/sound/sh/sh_dac_audio.c +++ b/sound/sh/sh_dac_audio.c @@ -184,23 +184,36 @@ static int snd_sh_dac_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return 0; } -static int snd_sh_dac_pcm_copy(struct snd_pcm_substream *substream, int channel, - snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count) +static int snd_sh_dac_pcm_copy(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void __user *src, unsigned long count) { /* channel is not used (interleaved data) */ struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - ssize_t b_count = frames_to_bytes(runtime , count); - ssize_t b_pos = frames_to_bytes(runtime , pos); - if (count < 0) - return -EINVAL; + if (copy_from_user_toio(chip->data_buffer + pos, src, count)) + return -EFAULT; + chip->buffer_end = chip->data_buffer + pos + count; - if (!count) - return 0; + if (chip->empty) { + chip->empty = 0; + dac_audio_start_timer(chip); + } - memcpy_toio(chip->data_buffer + b_pos, src, b_count); - chip->buffer_end = chip->data_buffer + b_pos + b_count; + return 0; +} + +static int snd_sh_dac_pcm_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *src, unsigned long count) +{ + /* channel is not used (interleaved data) */ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + + memcpy_toio(chip->data_buffer + pos, src, count); + chip->buffer_end = chip->data_buffer + pos + count; if (chip->empty) { chip->empty = 0; @@ -211,23 +224,15 @@ static int snd_sh_dac_pcm_copy(struct snd_pcm_substream *substream, int channel, } static int snd_sh_dac_pcm_silence(struct snd_pcm_substream *substream, - int channel, snd_pcm_uframes_t pos, - snd_pcm_uframes_t count) + int channel, unsigned long pos, + unsigned long count) { /* channel is not used (interleaved data) */ struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - ssize_t b_count = frames_to_bytes(runtime , count); - ssize_t b_pos = frames_to_bytes(runtime , pos); - if (count < 0) - return -EINVAL; - - if (!count) - return 0; - - memset_io(chip->data_buffer + b_pos, 0, b_count); - chip->buffer_end = chip->data_buffer + b_pos + b_count; + memset_io(chip->data_buffer + pos, 0, count); + chip->buffer_end = chip->data_buffer + pos + count; if (chip->empty) { chip->empty = 0; @@ -256,8 +261,9 @@ static struct snd_pcm_ops snd_sh_dac_pcm_ops = { .prepare = snd_sh_dac_pcm_prepare, .trigger = snd_sh_dac_pcm_trigger, .pointer = snd_sh_dac_pcm_pointer, - .copy = snd_sh_dac_pcm_copy, - .silence = snd_sh_dac_pcm_silence, + .copy_user = snd_sh_dac_pcm_copy, + .copy_kernel = snd_sh_dac_pcm_copy_kernel, + .fill_silence = snd_sh_dac_pcm_silence, .mmap = snd_pcm_lib_mmap_iomem, }; From aa708c613b96c9c3a00a5ba78a203616cab27f86 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 21:59:12 +0200 Subject: [PATCH 142/418] ASoC: blackfin: Convert to the new PCM ops Replace the copy and the silence ops with the new PCM ops. In AC97 and I2S-TDM mode, we need to convert back to frames, but otherwise the conversion is pretty straightforward. Reviewed-by: Takashi Sakamoto Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/blackfin/bf5xx-ac97-pcm.c | 27 +++++++++++++++------- sound/soc/blackfin/bf5xx-i2s-pcm.c | 36 +++++++++++++++++++---------- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 02ad2606fa19..913e29275f4e 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -279,23 +279,33 @@ static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, return 0 ; } #else -static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, - snd_pcm_uframes_t pos, - void __user *buf, snd_pcm_uframes_t count) +static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *buf, unsigned long count) { struct snd_pcm_runtime *runtime = substream->runtime; unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1]; + struct ac97_frame *dst; + pr_debug("%s copy pos:0x%lx count:0x%lx\n", substream->stream ? "Capture" : "Playback", pos, count); + dst = (struct ac97_frame *)runtime->dma_area + + bytes_to_frames(runtime, pos); + count = bytes_to_frames(runtime, count); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - bf5xx_pcm_to_ac97((struct ac97_frame *)runtime->dma_area + pos, - (__u16 *)buf, count, chan_mask); + bf5xx_pcm_to_ac97(dst, buf, count, chan_mask); else - bf5xx_ac97_to_pcm((struct ac97_frame *)runtime->dma_area + pos, - (__u16 *)buf, count); + bf5xx_ac97_to_pcm(dst, buf, count); return 0; } + +static int bf5xx_pcm_copy_user(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void __user *buf, unsigned long count) +{ + return bf5xx_pcm_copy(substream, channel, pos, (void *)buf, count); +} #endif static struct snd_pcm_ops bf5xx_pcm_ac97_ops = { @@ -309,7 +319,8 @@ static struct snd_pcm_ops bf5xx_pcm_ac97_ops = { #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) .mmap = bf5xx_pcm_mmap, #else - .copy = bf5xx_pcm_copy, + .copy_user = bf5xx_pcm_copy_user, + .copy_kernel = bf5xx_pcm_copy, #endif }; diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index 6cba211da32e..470d99abf6f6 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -225,8 +225,9 @@ static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, return 0 ; } -static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, - snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count) +static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *buf, unsigned long count) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; @@ -238,6 +239,8 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if (dma_data->tdm_mode) { + pos = bytes_to_frames(runtime, pos); + count = bytes_to_frames(runtime, count); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { src = buf; dst = runtime->dma_area; @@ -269,21 +272,29 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { src = buf; dst = runtime->dma_area; - dst += frames_to_bytes(runtime, pos); + dst += pos; } else { src = runtime->dma_area; - src += frames_to_bytes(runtime, pos); + src += pos; dst = buf; } - memcpy(dst, src, frames_to_bytes(runtime, count)); + memcpy(dst, src, count); } return 0; } +static int bf5xx_pcm_copy_user(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void __user *buf, unsigned long count) +{ + return bf5xx_pcm_copy(substream, channel, pos, (void *)buf, count); +} + static int bf5xx_pcm_silence(struct snd_pcm_substream *substream, - int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count) + int channel, unsigned long pos, + unsigned long count) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; @@ -295,11 +306,11 @@ static int bf5xx_pcm_silence(struct snd_pcm_substream *substream, dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if (dma_data->tdm_mode) { - offset = pos * 8 * sample_size; - samples = count * 8; + offset = bytes_to_frames(runtime, pos) * 8 * sample_size; + samples = bytes_to_frames(runtime, count) * 8; } else { - offset = frames_to_bytes(runtime, pos); - samples = count * runtime->channels; + offset = pos; + samples = bytes_to_samples(runtime, count); } snd_pcm_format_set_silence(runtime->format, buf + offset, samples); @@ -316,8 +327,9 @@ static struct snd_pcm_ops bf5xx_pcm_i2s_ops = { .trigger = bf5xx_pcm_trigger, .pointer = bf5xx_pcm_pointer, .mmap = bf5xx_pcm_mmap, - .copy = bf5xx_pcm_copy, - .silence = bf5xx_pcm_silence, + .copy_user = bf5xx_pcm_copy_user, + .copy_kernel = bf5xx_pcm_copy, + .fill_silence = bf5xx_pcm_silence, }; static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd) From 1facf21e8b903524b34f09c39a7d27b4b71a07f7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 22:20:10 +0200 Subject: [PATCH 143/418] [media] solo6x10: Convert to the new PCM ops Replace the copy and the silence ops with the new PCM ops. The device supports only 1 channel and 8bit sample, so it's always bytes=frames, and we need no conversion of unit in the callback. Also, it's a capture stream, thus no silence is needed. Acked-by: Hans Verkuil Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- drivers/media/pci/solo6x10/solo6x10-g723.c | 32 ++++++++++++++++------ 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c index 36e93540bb49..3ca947092775 100644 --- a/drivers/media/pci/solo6x10/solo6x10-g723.c +++ b/drivers/media/pci/solo6x10/solo6x10-g723.c @@ -223,9 +223,9 @@ static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss) return idx * G723_FRAMES_PER_PAGE; } -static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel, - snd_pcm_uframes_t pos, void __user *dst, - snd_pcm_uframes_t count) +static int __snd_solo_pcm_copy(struct snd_pcm_substream *ss, + unsigned long pos, void *dst, + unsigned long count, bool in_kernel) { struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); struct solo_dev *solo_dev = solo_pcm->solo_dev; @@ -242,16 +242,31 @@ static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel, if (err) return err; - err = copy_to_user(dst + (i * G723_PERIOD_BYTES), - solo_pcm->g723_buf, G723_PERIOD_BYTES); - - if (err) + if (in_kernel) + memcpy(dst, solo_pcm->g723_buf, G723_PERIOD_BYTES); + else if (copy_to_user((void __user *)dst, + solo_pcm->g723_buf, G723_PERIOD_BYTES)) return -EFAULT; + dst += G723_PERIOD_BYTES; } return 0; } +static int snd_solo_pcm_copy_user(struct snd_pcm_substream *ss, int channel, + unsigned long pos, void __user *dst, + unsigned long count) +{ + return __snd_solo_pcm_copy(ss, pos, (void *)dst, count, false); +} + +static int snd_solo_pcm_copy_kernel(struct snd_pcm_substream *ss, int channel, + unsigned long pos, void *dst, + unsigned long count) +{ + return __snd_solo_pcm_copy(ss, pos, dst, count, true); +} + static const struct snd_pcm_ops snd_solo_pcm_ops = { .open = snd_solo_pcm_open, .close = snd_solo_pcm_close, @@ -261,7 +276,8 @@ static const struct snd_pcm_ops snd_solo_pcm_ops = { .prepare = snd_solo_pcm_prepare, .trigger = snd_solo_pcm_trigger, .pointer = snd_solo_pcm_pointer, - .copy = snd_solo_pcm_copy, + .copy_user = snd_solo_pcm_copy_user, + .copy_kernel = snd_solo_pcm_copy_kernel, }; static int snd_solo_capture_volume_info(struct snd_kcontrol *kcontrol, From 2ae48354a1a7afbec0c61280e6410a90894a21e7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 May 2017 22:21:52 +0200 Subject: [PATCH 144/418] ALSA: pcm: Drop the old copy and silence ops Now that all users of old copy and silence ops have been converted to the new PCM ops, the old stuff can be retired and go away. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 5 ----- sound/core/pcm_lib.c | 38 +------------------------------------- sound/soc/soc-pcm.c | 2 -- 3 files changed, 1 insertion(+), 44 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 86b126be49a2..0da5117636ec 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -78,11 +78,6 @@ struct snd_pcm_ops { struct timespec *system_ts, struct timespec *audio_ts, struct snd_pcm_audio_tstamp_config *audio_tstamp_config, struct snd_pcm_audio_tstamp_report *audio_tstamp_report); - int (*copy)(struct snd_pcm_substream *substream, int channel, - snd_pcm_uframes_t pos, - void __user *buf, snd_pcm_uframes_t count); - int (*silence)(struct snd_pcm_substream *substream, int channel, - snd_pcm_uframes_t pos, snd_pcm_uframes_t count); int (*fill_silence)(struct snd_pcm_substream *substream, int channel, unsigned long pos, unsigned long bytes); int (*copy_user)(struct snd_pcm_substream *substream, int channel, diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 1fca1ffd235e..9c5fe62e2c51 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -118,9 +118,6 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram frames_to_bytes(runtime, ofs), frames_to_bytes(runtime, transfer)); snd_BUG_ON(err < 0); - } else if (substream->ops->silence) { - err = substream->ops->silence(substream, -1, ofs, transfer); - snd_BUG_ON(err < 0); } else { hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs); snd_pcm_format_set_silence(runtime->format, hwbuf, transfer * runtime->channels); @@ -135,11 +132,6 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram samples_to_bytes(runtime, transfer)); snd_BUG_ON(err < 0); } - } else if (substream->ops->silence) { - for (c = 0; c < channels; ++c) { - err = substream->ops->silence(substream, c, ofs, transfer); - snd_BUG_ON(err < 0); - } } else { size_t dma_csize = runtime->dma_bytes / channels; for (c = 0; c < channels; ++c) { @@ -2015,9 +2007,6 @@ static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, err = substream->ops->copy_user(substream, 0, hwoff, buf, frames); if (err < 0) return err; - } else if (substream->ops->copy) { - if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0) - return err; } else { char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames))) @@ -2139,8 +2128,7 @@ static int pcm_sanity_check(struct snd_pcm_substream *substream) if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; - if (snd_BUG_ON(!substream->ops->copy_user && !substream->ops->copy - && !runtime->dma_area)) + if (snd_BUG_ON(!substream->ops->copy_user && !runtime->dma_area)) return -EINVAL; if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; @@ -2200,19 +2188,6 @@ static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream, if (err < 0) return err; } - } else if (substream->ops->copy) { - if (snd_BUG_ON(!substream->ops->silence)) - return -EINVAL; - for (c = 0; c < channels; ++c, ++bufs) { - if (*bufs == NULL) { - if ((err = substream->ops->silence(substream, c, hwoff, frames)) < 0) - return err; - } else { - buf = *bufs + samples_to_bytes(runtime, off); - if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0) - return err; - } - } } else { /* default transfer behaviour */ size_t dma_csize = runtime->dma_bytes / channels; @@ -2266,9 +2241,6 @@ static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream, err = substream->ops->copy_user(substream, 0, hwoff, buf, frames); if (err < 0) return err; - } else if (substream->ops->copy) { - if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0) - return err; } else { char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames))) @@ -2430,14 +2402,6 @@ static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream, if (err < 0) return err; } - } else if (substream->ops->copy) { - for (c = 0; c < channels; ++c, ++bufs) { - if (*bufs == NULL) - continue; - buf = *bufs + samples_to_bytes(runtime, off); - if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0) - return err; - } } else { snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels; for (c = 0; c < channels; ++c, ++bufs) { diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 8867ed9e5f56..dcc5ece08668 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2746,8 +2746,6 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->ops.copy_user = platform->driver->ops->copy_user; rtd->ops.copy_kernel = platform->driver->ops->copy_kernel; rtd->ops.fill_silence = platform->driver->ops->fill_silence; - rtd->ops.copy = platform->driver->ops->copy; - rtd->ops.silence = platform->driver->ops->silence; rtd->ops.page = platform->driver->ops->page; rtd->ops.mmap = platform->driver->ops->mmap; } From 6ba63929ae76e5aaafa14021517fab41cfcd5c83 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 24 May 2017 17:51:30 +0200 Subject: [PATCH 145/418] ALSA: pcm: Check PCM state by a common helper function Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 81 ++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 52 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 9c5fe62e2c51..5fcd798672b4 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2019,6 +2019,22 @@ typedef int (*transfer_f)(struct snd_pcm_substream *substream, unsigned int hwof unsigned long data, unsigned int off, snd_pcm_uframes_t size); +static int pcm_accessible_state(struct snd_pcm_runtime *runtime) +{ + switch (runtime->status->state) { + case SNDRV_PCM_STATE_PREPARED: + case SNDRV_PCM_STATE_RUNNING: + case SNDRV_PCM_STATE_PAUSED: + return 0; + case SNDRV_PCM_STATE_XRUN: + return -EPIPE; + case SNDRV_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + default: + return -EBADFD; + } +} + static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, unsigned long data, snd_pcm_uframes_t size, @@ -2035,21 +2051,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, return 0; snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_PREPARED: - case SNDRV_PCM_STATE_RUNNING: - case SNDRV_PCM_STATE_PAUSED: - break; - case SNDRV_PCM_STATE_XRUN: - err = -EPIPE; + err = pcm_accessible_state(runtime); + if (err < 0) goto _end_unlock; - case SNDRV_PCM_STATE_SUSPENDED: - err = -ESTRPIPE; - goto _end_unlock; - default: - err = -EBADFD; - goto _end_unlock; - } runtime->twake = runtime->control->avail_min ? : 1; if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) @@ -2085,16 +2089,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, snd_pcm_stream_lock_irq(substream); if (err < 0) goto _end_unlock; - switch (runtime->status->state) { - case SNDRV_PCM_STATE_XRUN: - err = -EPIPE; + err = pcm_accessible_state(runtime); + if (err < 0) goto _end_unlock; - case SNDRV_PCM_STATE_SUSPENDED: - err = -ESTRPIPE; - goto _end_unlock; - default: - break; - } appl_ptr += frames; if (appl_ptr >= runtime->boundary) appl_ptr -= runtime->boundary; @@ -2265,27 +2262,14 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, return 0; snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_PREPARED: - if (size >= runtime->start_threshold) { - err = snd_pcm_start(substream); - if (err < 0) - goto _end_unlock; - } - break; - case SNDRV_PCM_STATE_DRAINING: - case SNDRV_PCM_STATE_RUNNING: - case SNDRV_PCM_STATE_PAUSED: - break; - case SNDRV_PCM_STATE_XRUN: - err = -EPIPE; - goto _end_unlock; - case SNDRV_PCM_STATE_SUSPENDED: - err = -ESTRPIPE; - goto _end_unlock; - default: - err = -EBADFD; + err = pcm_accessible_state(runtime); + if (err < 0) goto _end_unlock; + if (runtime->status->state == SNDRV_PCM_STATE_PREPARED && + size >= runtime->start_threshold) { + err = snd_pcm_start(substream); + if (err < 0) + goto _end_unlock; } runtime->twake = runtime->control->avail_min ? : 1; @@ -2329,16 +2313,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, snd_pcm_stream_lock_irq(substream); if (err < 0) goto _end_unlock; - switch (runtime->status->state) { - case SNDRV_PCM_STATE_XRUN: - err = -EPIPE; + err = pcm_accessible_state(runtime); + if (err < 0) goto _end_unlock; - case SNDRV_PCM_STATE_SUSPENDED: - err = -ESTRPIPE; - goto _end_unlock; - default: - break; - } appl_ptr += frames; if (appl_ptr >= runtime->boundary) appl_ptr -= runtime->boundary; From bdc4acf7f6eb14a64c549c04c741b18e3afb350e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 24 May 2017 17:59:17 +0200 Subject: [PATCH 146/418] ALSA: pcm: Shuffle codes Just shuffle the codes, without any change otherwise. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 212 +++++++++++++++++++++---------------------- 1 file changed, 106 insertions(+), 106 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 5fcd798672b4..51eeea9088de 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1993,6 +1993,10 @@ static int wait_for_avail(struct snd_pcm_substream *substream, return err; } +typedef int (*transfer_f)(struct snd_pcm_substream *substream, unsigned int hwoff, + unsigned long data, unsigned int off, + snd_pcm_uframes_t size); + static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, unsigned int hwoff, unsigned long data, unsigned int off, @@ -2015,9 +2019,68 @@ static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, return 0; } -typedef int (*transfer_f)(struct snd_pcm_substream *substream, unsigned int hwoff, - unsigned long data, unsigned int off, - snd_pcm_uframes_t size); +static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream, + unsigned int hwoff, + unsigned long data, unsigned int off, + snd_pcm_uframes_t frames) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + int err; + void __user **bufs = (void __user **)data; + int channels = runtime->channels; + char __user *buf; + int c; + + if (substream->ops->copy_user) { + hwoff = samples_to_bytes(runtime, hwoff); + off = samples_to_bytes(runtime, off); + frames = samples_to_bytes(runtime, frames); + for (c = 0; c < channels; ++c, ++bufs) { + buf = *bufs + off; + if (!*bufs) { + if (snd_BUG_ON(!substream->ops->fill_silence)) + return -EINVAL; + err = substream->ops->fill_silence(substream, c, + hwoff, + frames); + } else { + err = substream->ops->copy_user(substream, c, + hwoff, buf, + frames); + } + if (err < 0) + return err; + } + } else { + /* default transfer behaviour */ + size_t dma_csize = runtime->dma_bytes / channels; + for (c = 0; c < channels; ++c, ++bufs) { + char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff); + if (*bufs == NULL) { + snd_pcm_format_set_silence(runtime->format, hwbuf, frames); + } else { + char __user *buf = *bufs + samples_to_bytes(runtime, off); + if (copy_from_user(hwbuf, buf, samples_to_bytes(runtime, frames))) + return -EFAULT; + } + } + } + return 0; +} + +/* sanity-check for read/write methods */ +static int pcm_sanity_check(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime; + if (PCM_RUNTIME_CHECK(substream)) + return -ENXIO; + runtime = substream->runtime; + if (snd_BUG_ON(!substream->ops->copy_user && !runtime->dma_area)) + return -EINVAL; + if (runtime->status->state == SNDRV_PCM_STATE_OPEN) + return -EBADFD; + return 0; +} static int pcm_accessible_state(struct snd_pcm_runtime *runtime) { @@ -2118,20 +2181,6 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; } -/* sanity-check for read/write methods */ -static int pcm_sanity_check(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime; - if (PCM_RUNTIME_CHECK(substream)) - return -ENXIO; - runtime = substream->runtime; - if (snd_BUG_ON(!substream->ops->copy_user && !runtime->dma_area)) - return -EINVAL; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) - return -EBADFD; - return 0; -} - snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, snd_pcm_uframes_t size) { struct snd_pcm_runtime *runtime; @@ -2153,55 +2202,6 @@ snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const v EXPORT_SYMBOL(snd_pcm_lib_write); -static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream, - unsigned int hwoff, - unsigned long data, unsigned int off, - snd_pcm_uframes_t frames) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - void __user **bufs = (void __user **)data; - int channels = runtime->channels; - char __user *buf; - int c; - - if (substream->ops->copy_user) { - hwoff = samples_to_bytes(runtime, hwoff); - off = samples_to_bytes(runtime, off); - frames = samples_to_bytes(runtime, frames); - for (c = 0; c < channels; ++c, ++bufs) { - buf = *bufs + off; - if (!*bufs) { - if (snd_BUG_ON(!substream->ops->fill_silence)) - return -EINVAL; - err = substream->ops->fill_silence(substream, c, - hwoff, - frames); - } else { - err = substream->ops->copy_user(substream, c, - hwoff, buf, - frames); - } - if (err < 0) - return err; - } - } else { - /* default transfer behaviour */ - size_t dma_csize = runtime->dma_bytes / channels; - for (c = 0; c < channels; ++c, ++bufs) { - char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff); - if (*bufs == NULL) { - snd_pcm_format_set_silence(runtime->format, hwbuf, frames); - } else { - char __user *buf = *bufs + samples_to_bytes(runtime, off); - if (copy_from_user(hwbuf, buf, samples_to_bytes(runtime, frames))) - return -EFAULT; - } - } - } - return 0; -} - snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream, void __user **bufs, snd_pcm_uframes_t frames) @@ -2246,6 +2246,46 @@ static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream, return 0; } +static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream, + unsigned int hwoff, + unsigned long data, unsigned int off, + snd_pcm_uframes_t frames) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + int err; + void __user **bufs = (void __user **)data; + int channels = runtime->channels; + char __user *buf; + char *hwbuf; + int c; + + if (substream->ops->copy_user) { + hwoff = samples_to_bytes(runtime, hwoff); + off = samples_to_bytes(runtime, off); + frames = samples_to_bytes(runtime, frames); + for (c = 0; c < channels; ++c, ++bufs) { + if (!*bufs) + continue; + err = substream->ops->copy_user(substream, c, hwoff, + *bufs + off, frames); + if (err < 0) + return err; + } + } else { + snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels; + for (c = 0; c < channels; ++c, ++bufs) { + if (*bufs == NULL) + continue; + + hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff); + buf = *bufs + samples_to_bytes(runtime, off); + if (copy_to_user(buf, hwbuf, samples_to_bytes(runtime, frames))) + return -EFAULT; + } + } + return 0; +} + static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, unsigned long data, snd_pcm_uframes_t size, @@ -2354,46 +2394,6 @@ snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __u EXPORT_SYMBOL(snd_pcm_lib_read); -static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream, - unsigned int hwoff, - unsigned long data, unsigned int off, - snd_pcm_uframes_t frames) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - void __user **bufs = (void __user **)data; - int channels = runtime->channels; - char __user *buf; - char *hwbuf; - int c; - - if (substream->ops->copy_user) { - hwoff = samples_to_bytes(runtime, hwoff); - off = samples_to_bytes(runtime, off); - frames = samples_to_bytes(runtime, frames); - for (c = 0; c < channels; ++c, ++bufs) { - if (!*bufs) - continue; - err = substream->ops->copy_user(substream, c, hwoff, - *bufs + off, frames); - if (err < 0) - return err; - } - } else { - snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels; - for (c = 0; c < channels; ++c, ++bufs) { - if (*bufs == NULL) - continue; - - hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff); - buf = *bufs + samples_to_bytes(runtime, off); - if (copy_to_user(buf, hwbuf, samples_to_bytes(runtime, frames))) - return -EFAULT; - } - } - return 0; -} - snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream, void __user **bufs, snd_pcm_uframes_t frames) From c48f12ee0acbd431d6c3ed249f79a6d68b757058 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 21 May 2017 09:35:21 +0200 Subject: [PATCH 147/418] ALSA: pcm: Call directly the common read/write helpers Make snd_pcm_lib_read() and *_write() static inline functions that call the common helper functions directly. This reduces a slight amount of codes, and at the same time, it's a preparation for the further cleanups / fixes. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 43 +++++++++--- sound/core/pcm_lib.c | 156 +++++++++++++++---------------------------- 2 files changed, 89 insertions(+), 110 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 0da5117636ec..0fac948bb053 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -1072,15 +1072,40 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream); int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg); void snd_pcm_period_elapsed(struct snd_pcm_substream *substream); -snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, - const void __user *buf, - snd_pcm_uframes_t frames); -snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, - void __user *buf, snd_pcm_uframes_t frames); -snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream, - void __user **bufs, snd_pcm_uframes_t frames); -snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream, - void __user **bufs, snd_pcm_uframes_t frames); +snd_pcm_sframes_t __snd_pcm_lib_write(struct snd_pcm_substream *substream, + void *buf, bool interleaved, + snd_pcm_uframes_t frames); +snd_pcm_sframes_t __snd_pcm_lib_read(struct snd_pcm_substream *substream, + void *buf, bool interleaved, + snd_pcm_uframes_t frames); + +static inline snd_pcm_sframes_t +snd_pcm_lib_write(struct snd_pcm_substream *substream, + const void __user *buf, snd_pcm_uframes_t frames) +{ + return __snd_pcm_lib_write(substream, (void *)buf, true, frames); +} + +static inline snd_pcm_sframes_t +snd_pcm_lib_read(struct snd_pcm_substream *substream, + void __user *buf, snd_pcm_uframes_t frames) +{ + return __snd_pcm_lib_read(substream, (void *)buf, true, frames); +} + +static inline snd_pcm_sframes_t +snd_pcm_lib_writev(struct snd_pcm_substream *substream, + void __user **bufs, snd_pcm_uframes_t frames) +{ + return __snd_pcm_lib_write(substream, (void *)bufs, false, frames); +} + +static inline snd_pcm_sframes_t +snd_pcm_lib_readv(struct snd_pcm_substream *substream, + void __user **bufs, snd_pcm_uframes_t frames) +{ + return __snd_pcm_lib_read(substream, (void *)bufs, false, frames); +} int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime); unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 51eeea9088de..ae030c5eb7c6 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1994,12 +1994,12 @@ static int wait_for_avail(struct snd_pcm_substream *substream, } typedef int (*transfer_f)(struct snd_pcm_substream *substream, unsigned int hwoff, - unsigned long data, unsigned int off, + void *data, unsigned int off, snd_pcm_uframes_t size); static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, unsigned int hwoff, - unsigned long data, unsigned int off, + void *data, unsigned int off, snd_pcm_uframes_t frames) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -2021,7 +2021,7 @@ static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream, unsigned int hwoff, - unsigned long data, unsigned int off, + void *data, unsigned int off, snd_pcm_uframes_t frames) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -2098,21 +2098,39 @@ static int pcm_accessible_state(struct snd_pcm_runtime *runtime) } } -static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, - unsigned long data, - snd_pcm_uframes_t size, - int nonblock, - transfer_f transfer) +snd_pcm_sframes_t __snd_pcm_lib_write(struct snd_pcm_substream *substream, + void *data, bool interleaved, + snd_pcm_uframes_t size) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t xfer = 0; snd_pcm_uframes_t offset = 0; snd_pcm_uframes_t avail; - int err = 0; + transfer_f transfer; + bool nonblock; + int err; + + err = pcm_sanity_check(substream); + if (err < 0) + return err; + runtime = substream->runtime; + + if (interleaved) { + if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && + runtime->channels > 1) + return -EINVAL; + transfer = snd_pcm_lib_write_transfer; + } else { + if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) + return -EINVAL; + transfer = snd_pcm_lib_writev_transfer; + } if (size == 0) return 0; + nonblock = !!(substream->f_flags & O_NONBLOCK); + snd_pcm_stream_lock_irq(substream); err = pcm_accessible_state(runtime); if (err < 0) @@ -2180,53 +2198,11 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, snd_pcm_stream_unlock_irq(substream); return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; } - -snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, snd_pcm_uframes_t size) -{ - struct snd_pcm_runtime *runtime; - int nonblock; - int err; - - err = pcm_sanity_check(substream); - if (err < 0) - return err; - runtime = substream->runtime; - nonblock = !!(substream->f_flags & O_NONBLOCK); - - if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && - runtime->channels > 1) - return -EINVAL; - return snd_pcm_lib_write1(substream, (unsigned long)buf, size, nonblock, - snd_pcm_lib_write_transfer); -} - -EXPORT_SYMBOL(snd_pcm_lib_write); - -snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream, - void __user **bufs, - snd_pcm_uframes_t frames) -{ - struct snd_pcm_runtime *runtime; - int nonblock; - int err; - - err = pcm_sanity_check(substream); - if (err < 0) - return err; - runtime = substream->runtime; - nonblock = !!(substream->f_flags & O_NONBLOCK); - - if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) - return -EINVAL; - return snd_pcm_lib_write1(substream, (unsigned long)bufs, frames, - nonblock, snd_pcm_lib_writev_transfer); -} - -EXPORT_SYMBOL(snd_pcm_lib_writev); +EXPORT_SYMBOL(__snd_pcm_lib_write); static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream, unsigned int hwoff, - unsigned long data, unsigned int off, + void *data, unsigned int off, snd_pcm_uframes_t frames) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -2248,7 +2224,7 @@ static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream, static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream, unsigned int hwoff, - unsigned long data, unsigned int off, + void *data, unsigned int off, snd_pcm_uframes_t frames) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -2286,21 +2262,39 @@ static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream, return 0; } -static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, - unsigned long data, - snd_pcm_uframes_t size, - int nonblock, - transfer_f transfer) +snd_pcm_sframes_t __snd_pcm_lib_read(struct snd_pcm_substream *substream, + void *data, bool interleaved, + snd_pcm_uframes_t size) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t xfer = 0; snd_pcm_uframes_t offset = 0; snd_pcm_uframes_t avail; - int err = 0; + transfer_f transfer; + bool nonblock; + int err; + + err = pcm_sanity_check(substream); + if (err < 0) + return err; + runtime = substream->runtime; + + if (interleaved) { + if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && + runtime->channels > 1) + return -EINVAL; + transfer = snd_pcm_lib_read_transfer; + } else { + if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) + return -EINVAL; + transfer = snd_pcm_lib_readv_transfer; + } if (size == 0) return 0; + nonblock = !!(substream->f_flags & O_NONBLOCK); + snd_pcm_stream_lock_irq(substream); err = pcm_accessible_state(runtime); if (err < 0) @@ -2375,47 +2369,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, snd_pcm_stream_unlock_irq(substream); return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; } - -snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __user *buf, snd_pcm_uframes_t size) -{ - struct snd_pcm_runtime *runtime; - int nonblock; - int err; - - err = pcm_sanity_check(substream); - if (err < 0) - return err; - runtime = substream->runtime; - nonblock = !!(substream->f_flags & O_NONBLOCK); - if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED) - return -EINVAL; - return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer); -} - -EXPORT_SYMBOL(snd_pcm_lib_read); - -snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream, - void __user **bufs, - snd_pcm_uframes_t frames) -{ - struct snd_pcm_runtime *runtime; - int nonblock; - int err; - - err = pcm_sanity_check(substream); - if (err < 0) - return err; - runtime = substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) - return -EBADFD; - - nonblock = !!(substream->f_flags & O_NONBLOCK); - if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) - return -EINVAL; - return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer); -} - -EXPORT_SYMBOL(snd_pcm_lib_readv); +EXPORT_SYMBOL(__snd_pcm_lib_read); /* * standard channel mapping helpers From 9f60063094ba72e2767be18289baf5151f1f1c2f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 24 May 2017 18:15:26 +0200 Subject: [PATCH 148/418] ALSA: pcm: More unification of PCM transfer codes This patch proceeds more abstraction of PCM read/write loop codes. For both interleaved and non-interleaved transfers, the same copy or silence transfer code (which is defined as pcm_transfer_f) is used now. This became possible since we switched to byte size to copy_* and fill_silence ops argument instead of frames. And, for both read and write, we can use the same copy function (which is defined as pcm_copy_f), just depending on whether interleaved or non-interleaved mode. The transfer function is determined at the beginning of the loop, depending on whether the driver gives the specific copy ops or it's the standard read/write. Another bonus by this change is that we now guarantee the silencing behavior when NULL buffer is passed to write helpers. It'll simplify some codes later. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 256 +++++++++++++++++++++---------------------- 1 file changed, 124 insertions(+), 132 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index ae030c5eb7c6..0c53a34201c1 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1993,77 +1993,100 @@ static int wait_for_avail(struct snd_pcm_substream *substream, return err; } -typedef int (*transfer_f)(struct snd_pcm_substream *substream, unsigned int hwoff, - void *data, unsigned int off, - snd_pcm_uframes_t size); +typedef int (*pcm_transfer_f)(struct snd_pcm_substream *substream, + int channel, unsigned long hwoff, + void *buf, unsigned long bytes); -static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, - unsigned int hwoff, - void *data, unsigned int off, - snd_pcm_uframes_t frames) +typedef int (*pcm_copy_f)(struct snd_pcm_substream *, snd_pcm_uframes_t, void *, + snd_pcm_uframes_t, snd_pcm_uframes_t, pcm_transfer_f); + +/* calculate the target DMA-buffer position to be written/read */ +static void *get_dma_ptr(struct snd_pcm_runtime *runtime, + int channel, unsigned long hwoff) { - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - char __user *buf = (char __user *) data + frames_to_bytes(runtime, off); - if (substream->ops->copy_user) { - hwoff = frames_to_bytes(runtime, hwoff); - frames = frames_to_bytes(runtime, frames); - err = substream->ops->copy_user(substream, 0, hwoff, buf, frames); - if (err < 0) - return err; - } else { - char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); - if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames))) - return -EFAULT; - } + return runtime->dma_area + hwoff + + channel * (runtime->dma_bytes / runtime->channels); +} + +/* default copy_user ops for write */ +static int default_write_copy_user(struct snd_pcm_substream *substream, + int channel, unsigned long hwoff, + void __user *buf, unsigned long bytes) +{ + if (copy_from_user(get_dma_ptr(substream->runtime, channel, hwoff), + buf, bytes)) + return -EFAULT; return 0; } - -static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream, - unsigned int hwoff, - void *data, unsigned int off, - snd_pcm_uframes_t frames) + +/* fill silence instead of copy data; called as a transfer helper + * from __snd_pcm_lib_write() or directly from noninterleaved_copy() when + * a NULL buffer is passed + */ +static int fill_silence(struct snd_pcm_substream *substream, int channel, + unsigned long hwoff, void *buf, unsigned long bytes) { struct snd_pcm_runtime *runtime = substream->runtime; - int err; - void __user **bufs = (void __user **)data; - int channels = runtime->channels; - char __user *buf; - int c; - if (substream->ops->copy_user) { - hwoff = samples_to_bytes(runtime, hwoff); - off = samples_to_bytes(runtime, off); - frames = samples_to_bytes(runtime, frames); - for (c = 0; c < channels; ++c, ++bufs) { - buf = *bufs + off; - if (!*bufs) { - if (snd_BUG_ON(!substream->ops->fill_silence)) - return -EINVAL; - err = substream->ops->fill_silence(substream, c, - hwoff, - frames); - } else { - err = substream->ops->copy_user(substream, c, - hwoff, buf, - frames); - } - if (err < 0) - return err; - } - } else { - /* default transfer behaviour */ - size_t dma_csize = runtime->dma_bytes / channels; - for (c = 0; c < channels; ++c, ++bufs) { - char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff); - if (*bufs == NULL) { - snd_pcm_format_set_silence(runtime->format, hwbuf, frames); - } else { - char __user *buf = *bufs + samples_to_bytes(runtime, off); - if (copy_from_user(hwbuf, buf, samples_to_bytes(runtime, frames))) - return -EFAULT; - } - } + if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) + return 0; + if (substream->ops->fill_silence) + return substream->ops->fill_silence(substream, channel, + hwoff, bytes); + + snd_pcm_format_set_silence(runtime->format, + get_dma_ptr(runtime, channel, hwoff), + bytes_to_samples(runtime, bytes)); + return 0; +} + +/* call transfer function with the converted pointers and sizes; + * for interleaved mode, it's one shot for all samples + */ +static int interleaved_copy(struct snd_pcm_substream *substream, + snd_pcm_uframes_t hwoff, void *data, + snd_pcm_uframes_t off, + snd_pcm_uframes_t frames, + pcm_transfer_f transfer) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + /* convert to bytes */ + hwoff = frames_to_bytes(runtime, hwoff); + off = frames_to_bytes(runtime, off); + frames = frames_to_bytes(runtime, frames); + return transfer(substream, 0, hwoff, data + off, frames); +} + +/* call transfer function with the converted pointers and sizes for each + * non-interleaved channel; when buffer is NULL, silencing instead of copying + */ +static int noninterleaved_copy(struct snd_pcm_substream *substream, + snd_pcm_uframes_t hwoff, void *data, + snd_pcm_uframes_t off, + snd_pcm_uframes_t frames, + pcm_transfer_f transfer) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + int channels = runtime->channels; + void **bufs = data; + int c, err; + + /* convert to bytes; note that it's not frames_to_bytes() here. + * in non-interleaved mode, we copy for each channel, thus + * each copy is n_samples bytes x channels = whole frames. + */ + off = samples_to_bytes(runtime, off); + frames = samples_to_bytes(runtime, frames); + hwoff = samples_to_bytes(runtime, hwoff); + for (c = 0; c < channels; ++c, ++bufs) { + if (!data || !*bufs) + err = fill_silence(substream, c, hwoff, NULL, frames); + else + err = transfer(substream, c, hwoff, *bufs + off, + frames); + if (err < 0) + return err; } return 0; } @@ -2106,24 +2129,33 @@ snd_pcm_sframes_t __snd_pcm_lib_write(struct snd_pcm_substream *substream, snd_pcm_uframes_t xfer = 0; snd_pcm_uframes_t offset = 0; snd_pcm_uframes_t avail; - transfer_f transfer; + pcm_copy_f writer; + pcm_transfer_f transfer; bool nonblock; int err; err = pcm_sanity_check(substream); if (err < 0) return err; - runtime = substream->runtime; if (interleaved) { if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && runtime->channels > 1) return -EINVAL; - transfer = snd_pcm_lib_write_transfer; + writer = interleaved_copy; } else { if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) return -EINVAL; - transfer = snd_pcm_lib_writev_transfer; + writer = noninterleaved_copy; + } + + if (!data) { + transfer = fill_silence; + } else { + if (substream->ops->copy_user) + transfer = (pcm_transfer_f)substream->ops->copy_user; + else + transfer = default_write_copy_user; } if (size == 0) @@ -2166,7 +2198,8 @@ snd_pcm_sframes_t __snd_pcm_lib_write(struct snd_pcm_substream *substream, appl_ptr = runtime->control->appl_ptr; appl_ofs = appl_ptr % runtime->buffer_size; snd_pcm_stream_unlock_irq(substream); - err = transfer(substream, appl_ofs, data, offset, frames); + err = writer(substream, appl_ofs, data, offset, frames, + transfer); snd_pcm_stream_lock_irq(substream); if (err < 0) goto _end_unlock; @@ -2200,65 +2233,15 @@ snd_pcm_sframes_t __snd_pcm_lib_write(struct snd_pcm_substream *substream, } EXPORT_SYMBOL(__snd_pcm_lib_write); -static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream, - unsigned int hwoff, - void *data, unsigned int off, - snd_pcm_uframes_t frames) +/* default copy_user ops for read */ +static int default_read_copy_user(struct snd_pcm_substream *substream, + int channel, unsigned long hwoff, + void *buf, unsigned long bytes) { - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - char __user *buf = (char __user *) data + frames_to_bytes(runtime, off); - if (substream->ops->copy_user) { - hwoff = frames_to_bytes(runtime, hwoff); - frames = frames_to_bytes(runtime, frames); - err = substream->ops->copy_user(substream, 0, hwoff, buf, frames); - if (err < 0) - return err; - } else { - char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); - if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames))) - return -EFAULT; - } - return 0; -} - -static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream, - unsigned int hwoff, - void *data, unsigned int off, - snd_pcm_uframes_t frames) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - void __user **bufs = (void __user **)data; - int channels = runtime->channels; - char __user *buf; - char *hwbuf; - int c; - - if (substream->ops->copy_user) { - hwoff = samples_to_bytes(runtime, hwoff); - off = samples_to_bytes(runtime, off); - frames = samples_to_bytes(runtime, frames); - for (c = 0; c < channels; ++c, ++bufs) { - if (!*bufs) - continue; - err = substream->ops->copy_user(substream, c, hwoff, - *bufs + off, frames); - if (err < 0) - return err; - } - } else { - snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels; - for (c = 0; c < channels; ++c, ++bufs) { - if (*bufs == NULL) - continue; - - hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff); - buf = *bufs + samples_to_bytes(runtime, off); - if (copy_to_user(buf, hwbuf, samples_to_bytes(runtime, frames))) - return -EFAULT; - } - } + if (copy_to_user((void __user *)buf, + get_dma_ptr(substream->runtime, channel, hwoff), + bytes)) + return -EFAULT; return 0; } @@ -2270,26 +2253,34 @@ snd_pcm_sframes_t __snd_pcm_lib_read(struct snd_pcm_substream *substream, snd_pcm_uframes_t xfer = 0; snd_pcm_uframes_t offset = 0; snd_pcm_uframes_t avail; - transfer_f transfer; + pcm_copy_f reader; + pcm_transfer_f transfer; bool nonblock; int err; err = pcm_sanity_check(substream); if (err < 0) return err; - runtime = substream->runtime; + + if (!data) + return -EINVAL; if (interleaved) { if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && runtime->channels > 1) return -EINVAL; - transfer = snd_pcm_lib_read_transfer; + reader = interleaved_copy; } else { if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) return -EINVAL; - transfer = snd_pcm_lib_readv_transfer; + reader = noninterleaved_copy; } + if (substream->ops->copy_user) + transfer = (pcm_transfer_f)substream->ops->copy_user; + else + transfer = default_read_copy_user; + if (size == 0) return 0; @@ -2343,7 +2334,8 @@ snd_pcm_sframes_t __snd_pcm_lib_read(struct snd_pcm_substream *substream, appl_ptr = runtime->control->appl_ptr; appl_ofs = appl_ptr % runtime->buffer_size; snd_pcm_stream_unlock_irq(substream); - err = transfer(substream, appl_ofs, data, offset, frames); + err = reader(substream, appl_ofs, data, offset, frames, + transfer); snd_pcm_stream_lock_irq(substream); if (err < 0) goto _end_unlock; From 5c7264cfbb209efea04bbbd69b8b4f5f2fc5f86d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 24 May 2017 22:36:23 +0200 Subject: [PATCH 149/418] ALSA: pcm: Unify read/write loop Both __snd_pcm_lib_read() and __snd_pcm_write() functions have almost the same code to loop over samples. For simplification, this patch unifies both as the single helper, __snd_pcm_lib_xfer(). Other than that, there should be no functional change by this patch. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 13 ++- sound/core/pcm_lib.c | 194 ++++++++++++------------------------------- 2 files changed, 56 insertions(+), 151 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 0fac948bb053..db649083c76d 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -1072,10 +1072,7 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream); int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg); void snd_pcm_period_elapsed(struct snd_pcm_substream *substream); -snd_pcm_sframes_t __snd_pcm_lib_write(struct snd_pcm_substream *substream, - void *buf, bool interleaved, - snd_pcm_uframes_t frames); -snd_pcm_sframes_t __snd_pcm_lib_read(struct snd_pcm_substream *substream, +snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, void *buf, bool interleaved, snd_pcm_uframes_t frames); @@ -1083,28 +1080,28 @@ static inline snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, snd_pcm_uframes_t frames) { - return __snd_pcm_lib_write(substream, (void *)buf, true, frames); + return __snd_pcm_lib_xfer(substream, (void *)buf, true, frames); } static inline snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __user *buf, snd_pcm_uframes_t frames) { - return __snd_pcm_lib_read(substream, (void *)buf, true, frames); + return __snd_pcm_lib_xfer(substream, (void *)buf, true, frames); } static inline snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream, void __user **bufs, snd_pcm_uframes_t frames) { - return __snd_pcm_lib_write(substream, (void *)bufs, false, frames); + return __snd_pcm_lib_xfer(substream, (void *)bufs, false, frames); } static inline snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream, void __user **bufs, snd_pcm_uframes_t frames) { - return __snd_pcm_lib_read(substream, (void *)bufs, false, frames); + return __snd_pcm_lib_xfer(substream, (void *)bufs, false, frames); } int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 0c53a34201c1..af73c629a6b2 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2008,13 +2008,13 @@ static void *get_dma_ptr(struct snd_pcm_runtime *runtime, channel * (runtime->dma_bytes / runtime->channels); } -/* default copy_user ops for write */ -static int default_write_copy_user(struct snd_pcm_substream *substream, - int channel, unsigned long hwoff, - void __user *buf, unsigned long bytes) +/* default copy_user ops for write; used for both interleaved and non- modes */ +static int default_write_copy(struct snd_pcm_substream *substream, + int channel, unsigned long hwoff, + void *buf, unsigned long bytes) { if (copy_from_user(get_dma_ptr(substream->runtime, channel, hwoff), - buf, bytes)) + (void __user *)buf, bytes)) return -EFAULT; return 0; } @@ -2040,6 +2040,18 @@ static int fill_silence(struct snd_pcm_substream *substream, int channel, return 0; } +/* default copy_user ops for read; used for both interleaved and non- modes */ +static int default_read_copy(struct snd_pcm_substream *substream, + int channel, unsigned long hwoff, + void *buf, unsigned long bytes) +{ + if (copy_to_user((void __user *)buf, + get_dma_ptr(substream->runtime, channel, hwoff), + bytes)) + return -EFAULT; + return 0; +} + /* call transfer function with the converted pointers and sizes; * for interleaved mode, it's one shot for all samples */ @@ -2121,9 +2133,10 @@ static int pcm_accessible_state(struct snd_pcm_runtime *runtime) } } -snd_pcm_sframes_t __snd_pcm_lib_write(struct snd_pcm_substream *substream, - void *data, bool interleaved, - snd_pcm_uframes_t size) +/* the common loop for read/write data */ +snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, + void *data, bool interleaved, + snd_pcm_uframes_t size) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t xfer = 0; @@ -2132,12 +2145,14 @@ snd_pcm_sframes_t __snd_pcm_lib_write(struct snd_pcm_substream *substream, pcm_copy_f writer; pcm_transfer_f transfer; bool nonblock; + bool is_playback; int err; err = pcm_sanity_check(substream); if (err < 0) return err; + is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; if (interleaved) { if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && runtime->channels > 1) @@ -2150,12 +2165,16 @@ snd_pcm_sframes_t __snd_pcm_lib_write(struct snd_pcm_substream *substream, } if (!data) { - transfer = fill_silence; + if (is_playback) + transfer = fill_silence; + else + return -EINVAL; } else { if (substream->ops->copy_user) transfer = (pcm_transfer_f)substream->ops->copy_user; else - transfer = default_write_copy_user; + transfer = is_playback ? + default_write_copy : default_read_copy; } if (size == 0) @@ -2168,14 +2187,30 @@ snd_pcm_sframes_t __snd_pcm_lib_write(struct snd_pcm_substream *substream, if (err < 0) goto _end_unlock; + if (!is_playback && + runtime->status->state == SNDRV_PCM_STATE_PREPARED && + size >= runtime->start_threshold) { + err = snd_pcm_start(substream); + if (err < 0) + goto _end_unlock; + } + runtime->twake = runtime->control->avail_min ? : 1; if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) snd_pcm_update_hw_ptr(substream); - avail = snd_pcm_playback_avail(runtime); + if (is_playback) + avail = snd_pcm_playback_avail(runtime); + else + avail = snd_pcm_capture_avail(runtime); while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t cont; if (!avail) { + if (!is_playback && + runtime->status->state == SNDRV_PCM_STATE_DRAINING) { + snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); + goto _end_unlock; + } if (nonblock) { err = -EAGAIN; goto _end_unlock; @@ -2185,6 +2220,8 @@ snd_pcm_sframes_t __snd_pcm_lib_write(struct snd_pcm_substream *substream, err = wait_for_avail(substream, &avail); if (err < 0) goto _end_unlock; + if (!avail) + continue; /* draining */ } frames = size > avail ? avail : size; cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; @@ -2217,7 +2254,8 @@ snd_pcm_sframes_t __snd_pcm_lib_write(struct snd_pcm_substream *substream, size -= frames; xfer += frames; avail -= frames; - if (runtime->status->state == SNDRV_PCM_STATE_PREPARED && + if (is_playback && + runtime->status->state == SNDRV_PCM_STATE_PREPARED && snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) { err = snd_pcm_start(substream); if (err < 0) @@ -2231,137 +2269,7 @@ snd_pcm_sframes_t __snd_pcm_lib_write(struct snd_pcm_substream *substream, snd_pcm_stream_unlock_irq(substream); return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; } -EXPORT_SYMBOL(__snd_pcm_lib_write); - -/* default copy_user ops for read */ -static int default_read_copy_user(struct snd_pcm_substream *substream, - int channel, unsigned long hwoff, - void *buf, unsigned long bytes) -{ - if (copy_to_user((void __user *)buf, - get_dma_ptr(substream->runtime, channel, hwoff), - bytes)) - return -EFAULT; - return 0; -} - -snd_pcm_sframes_t __snd_pcm_lib_read(struct snd_pcm_substream *substream, - void *data, bool interleaved, - snd_pcm_uframes_t size) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_uframes_t xfer = 0; - snd_pcm_uframes_t offset = 0; - snd_pcm_uframes_t avail; - pcm_copy_f reader; - pcm_transfer_f transfer; - bool nonblock; - int err; - - err = pcm_sanity_check(substream); - if (err < 0) - return err; - - if (!data) - return -EINVAL; - - if (interleaved) { - if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && - runtime->channels > 1) - return -EINVAL; - reader = interleaved_copy; - } else { - if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) - return -EINVAL; - reader = noninterleaved_copy; - } - - if (substream->ops->copy_user) - transfer = (pcm_transfer_f)substream->ops->copy_user; - else - transfer = default_read_copy_user; - - if (size == 0) - return 0; - - nonblock = !!(substream->f_flags & O_NONBLOCK); - - snd_pcm_stream_lock_irq(substream); - err = pcm_accessible_state(runtime); - if (err < 0) - goto _end_unlock; - if (runtime->status->state == SNDRV_PCM_STATE_PREPARED && - size >= runtime->start_threshold) { - err = snd_pcm_start(substream); - if (err < 0) - goto _end_unlock; - } - - runtime->twake = runtime->control->avail_min ? : 1; - if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) - snd_pcm_update_hw_ptr(substream); - avail = snd_pcm_capture_avail(runtime); - while (size > 0) { - snd_pcm_uframes_t frames, appl_ptr, appl_ofs; - snd_pcm_uframes_t cont; - if (!avail) { - if (runtime->status->state == - SNDRV_PCM_STATE_DRAINING) { - snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); - goto _end_unlock; - } - if (nonblock) { - err = -EAGAIN; - goto _end_unlock; - } - runtime->twake = min_t(snd_pcm_uframes_t, size, - runtime->control->avail_min ? : 1); - err = wait_for_avail(substream, &avail); - if (err < 0) - goto _end_unlock; - if (!avail) - continue; /* draining */ - } - frames = size > avail ? avail : size; - cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; - if (frames > cont) - frames = cont; - if (snd_BUG_ON(!frames)) { - runtime->twake = 0; - snd_pcm_stream_unlock_irq(substream); - return -EINVAL; - } - appl_ptr = runtime->control->appl_ptr; - appl_ofs = appl_ptr % runtime->buffer_size; - snd_pcm_stream_unlock_irq(substream); - err = reader(substream, appl_ofs, data, offset, frames, - transfer); - snd_pcm_stream_lock_irq(substream); - if (err < 0) - goto _end_unlock; - err = pcm_accessible_state(runtime); - if (err < 0) - goto _end_unlock; - appl_ptr += frames; - if (appl_ptr >= runtime->boundary) - appl_ptr -= runtime->boundary; - runtime->control->appl_ptr = appl_ptr; - if (substream->ops->ack) - substream->ops->ack(substream); - - offset += frames; - size -= frames; - xfer += frames; - avail -= frames; - } - _end_unlock: - runtime->twake = 0; - if (xfer > 0 && err >= 0) - snd_pcm_update_state(substream, runtime); - snd_pcm_stream_unlock_irq(substream); - return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; -} -EXPORT_SYMBOL(__snd_pcm_lib_read); +EXPORT_SYMBOL(__snd_pcm_lib_xfer); /* * standard channel mapping helpers From a9cd29e79965f0f769d13edcf2e9adb389698e7b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 24 May 2017 18:18:15 +0200 Subject: [PATCH 150/418] ALSA: pcm: Simplify snd_pcm_playback_silence() Use the existing silence helper codes for simplification. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 50 ++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index af73c629a6b2..f31949b20c0d 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -44,6 +44,9 @@ #define trace_hw_ptr_error(substream, reason) #endif +static int fill_silence_frames(struct snd_pcm_substream *substream, + snd_pcm_uframes_t off, snd_pcm_uframes_t frames); + /* * fill ring buffer with silence * runtime->silence_start: starting pointer to silence area @@ -57,7 +60,6 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t frames, ofs, transfer; - char *hwbuf; int err; if (runtime->silence_size < runtime->boundary) { @@ -111,35 +113,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram ofs = runtime->silence_start % runtime->buffer_size; while (frames > 0) { transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames; - if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || - runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) { - if (substream->ops->fill_silence) { - err = substream->ops->fill_silence(substream, 0, - frames_to_bytes(runtime, ofs), - frames_to_bytes(runtime, transfer)); - snd_BUG_ON(err < 0); - } else { - hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs); - snd_pcm_format_set_silence(runtime->format, hwbuf, transfer * runtime->channels); - } - } else { - unsigned int c; - unsigned int channels = runtime->channels; - if (substream->ops->fill_silence) { - for (c = 0; c < channels; ++c) { - err = substream->ops->fill_silence(substream, c, - samples_to_bytes(runtime, ofs), - samples_to_bytes(runtime, transfer)); - snd_BUG_ON(err < 0); - } - } else { - size_t dma_csize = runtime->dma_bytes / channels; - for (c = 0; c < channels; ++c) { - hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, ofs); - snd_pcm_format_set_silence(runtime->format, hwbuf, transfer); - } - } - } + err = fill_silence_frames(substream, ofs, transfer); + snd_BUG_ON(err < 0); runtime->silence_filled += transfer; frames -= transfer; ofs = 0; @@ -2103,6 +2078,21 @@ static int noninterleaved_copy(struct snd_pcm_substream *substream, return 0; } +/* fill silence on the given buffer position; + * called from snd_pcm_playback_silence() + */ +static int fill_silence_frames(struct snd_pcm_substream *substream, + snd_pcm_uframes_t off, snd_pcm_uframes_t frames) +{ + if (substream->runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || + substream->runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) + return interleaved_copy(substream, off, NULL, 0, frames, + fill_silence); + else + return noninterleaved_copy(substream, off, NULL, 0, frames, + fill_silence); +} + /* sanity-check for read/write methods */ static int pcm_sanity_check(struct snd_pcm_substream *substream) { From 68541213720df9bb7904cc1fecab563d424849ae Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 24 May 2017 18:23:20 +0200 Subject: [PATCH 151/418] ALSA: pcm: Direct in-kernel read/write support Now all materials are ready, let's allow the direct in-kernel read/write, i.e. a kernel-space buffer is passed for read or write, instead of the normal user-space buffer. This feature is used by OSS layer and UAC1 driver, for example. The __snd_pcm_lib_xfer() takes in_kernel argument that indicates the in-kernel buffer copy. When this flag is set, another transfer code is used. It's either via copy_kernel PCM ops or the normal memcpy(), depending on the driver setup. As external API, snd_pcm_kernel_read(), *_write() and other variants are provided. That's all. This support is really simple because of the code refactoring until now. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 38 +++++++++++++++++++++++++++++++++----- sound/core/pcm_lib.c | 26 +++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index db649083c76d..c24f85f12b71 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -1074,34 +1074,62 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, void snd_pcm_period_elapsed(struct snd_pcm_substream *substream); snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, void *buf, bool interleaved, - snd_pcm_uframes_t frames); + snd_pcm_uframes_t frames, bool in_kernel); static inline snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, snd_pcm_uframes_t frames) { - return __snd_pcm_lib_xfer(substream, (void *)buf, true, frames); + return __snd_pcm_lib_xfer(substream, (void *)buf, true, frames, false); } static inline snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __user *buf, snd_pcm_uframes_t frames) { - return __snd_pcm_lib_xfer(substream, (void *)buf, true, frames); + return __snd_pcm_lib_xfer(substream, (void *)buf, true, frames, false); } static inline snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream, void __user **bufs, snd_pcm_uframes_t frames) { - return __snd_pcm_lib_xfer(substream, (void *)bufs, false, frames); + return __snd_pcm_lib_xfer(substream, (void *)bufs, false, frames, false); } static inline snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream, void __user **bufs, snd_pcm_uframes_t frames) { - return __snd_pcm_lib_xfer(substream, (void *)bufs, false, frames); + return __snd_pcm_lib_xfer(substream, (void *)bufs, false, frames, false); +} + +static inline snd_pcm_sframes_t +snd_pcm_kernel_write(struct snd_pcm_substream *substream, + const void *buf, snd_pcm_uframes_t frames) +{ + return __snd_pcm_lib_xfer(substream, (void *)buf, true, frames, true); +} + +static inline snd_pcm_sframes_t +snd_pcm_kernel_read(struct snd_pcm_substream *substream, + void *buf, snd_pcm_uframes_t frames) +{ + return __snd_pcm_lib_xfer(substream, buf, true, frames, true); +} + +static inline snd_pcm_sframes_t +snd_pcm_kernel_writev(struct snd_pcm_substream *substream, + void **bufs, snd_pcm_uframes_t frames) +{ + return __snd_pcm_lib_xfer(substream, bufs, false, frames, true); +} + +static inline snd_pcm_sframes_t +snd_pcm_kernel_readv(struct snd_pcm_substream *substream, + void **bufs, snd_pcm_uframes_t frames) +{ + return __snd_pcm_lib_xfer(substream, bufs, false, frames, true); } int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index f31949b20c0d..95b8ef15029f 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1994,6 +1994,15 @@ static int default_write_copy(struct snd_pcm_substream *substream, return 0; } +/* default copy_kernel ops for write */ +static int default_write_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long hwoff, + void *buf, unsigned long bytes) +{ + memcpy(get_dma_ptr(substream->runtime, channel, hwoff), buf, bytes); + return 0; +} + /* fill silence instead of copy data; called as a transfer helper * from __snd_pcm_lib_write() or directly from noninterleaved_copy() when * a NULL buffer is passed @@ -2027,6 +2036,15 @@ static int default_read_copy(struct snd_pcm_substream *substream, return 0; } +/* default copy_kernel ops for read */ +static int default_read_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long hwoff, + void *buf, unsigned long bytes) +{ + memcpy(buf, get_dma_ptr(substream->runtime, channel, hwoff), bytes); + return 0; +} + /* call transfer function with the converted pointers and sizes; * for interleaved mode, it's one shot for all samples */ @@ -2126,7 +2144,7 @@ static int pcm_accessible_state(struct snd_pcm_runtime *runtime) /* the common loop for read/write data */ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, void *data, bool interleaved, - snd_pcm_uframes_t size) + snd_pcm_uframes_t size, bool in_kernel) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t xfer = 0; @@ -2159,6 +2177,12 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, transfer = fill_silence; else return -EINVAL; + } else if (in_kernel) { + if (substream->ops->copy_kernel) + transfer = substream->ops->copy_kernel; + else + transfer = is_playback ? + default_write_copy_kernel : default_read_copy_kernel; } else { if (substream->ops->copy_user) transfer = (pcm_transfer_f)substream->ops->copy_user; From 66b5542e3a781091920430da42640bdf40499dea Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 21 May 2017 10:19:16 +0200 Subject: [PATCH 152/418] usb: gadget: u_uac1: Kill set_fs() usage With the new API to perform the in-kernel buffer copy, we can get rid of set_fs() usage in this driver, finally. Acked-by: Greg Kroah-Hartman Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- drivers/usb/gadget/function/u_uac1.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/usb/gadget/function/u_uac1.c b/drivers/usb/gadget/function/u_uac1.c index c78c84138a28..ca88e4c0fd1e 100644 --- a/drivers/usb/gadget/function/u_uac1.c +++ b/drivers/usb/gadget/function/u_uac1.c @@ -157,7 +157,6 @@ size_t u_audio_playback(struct gaudio *card, void *buf, size_t count) struct gaudio_snd_dev *snd = &card->playback; struct snd_pcm_substream *substream = snd->substream; struct snd_pcm_runtime *runtime = substream->runtime; - mm_segment_t old_fs; ssize_t result; snd_pcm_sframes_t frames; @@ -174,15 +173,11 @@ try_again: } frames = bytes_to_frames(runtime, count); - old_fs = get_fs(); - set_fs(KERNEL_DS); - result = snd_pcm_lib_write(snd->substream, (void __user *)buf, frames); + result = snd_pcm_kernel_write(snd->substream, buf, frames); if (result != frames) { ERROR(card, "Playback error: %d\n", (int)result); - set_fs(old_fs); goto try_again; } - set_fs(old_fs); return 0; } From 13f72c8c28fc4b2d5329c940086c8939756600c2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 21 May 2017 10:14:42 +0200 Subject: [PATCH 153/418] ALSA: pcm: Kill set_fs() in PCM OSS layer This is the last-standing one: kill the set_fs() usage in PCM OSS layer by replacing with the new API functions to deal with the direct in-kernel buffer copying. The code to fill the silence can be replaced even to a one-liner to pass NULL buffer instead of the manual copying. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_oss.c | 77 +++++++--------------------------------- 1 file changed, 12 insertions(+), 65 deletions(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index e306f05ce51d..2d6a825cfe88 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -67,18 +67,6 @@ static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file); static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file); static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file); -static inline mm_segment_t snd_enter_user(void) -{ - mm_segment_t fs = get_fs(); - set_fs(get_ds()); - return fs; -} - -static inline void snd_leave_user(mm_segment_t fs) -{ - set_fs(fs); -} - /* * helper functions to process hw_params */ @@ -1191,14 +1179,8 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const if (ret < 0) break; } - if (in_kernel) { - mm_segment_t fs; - fs = snd_enter_user(); - ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames); - snd_leave_user(fs); - } else { - ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames); - } + ret = __snd_pcm_lib_xfer(substream, (void *)ptr, true, + frames, in_kernel); if (ret != -EPIPE && ret != -ESTRPIPE) break; /* test, if we can't store new data, because the stream */ @@ -1234,14 +1216,8 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p ret = snd_pcm_oss_capture_position_fixup(substream, &delay); if (ret < 0) break; - if (in_kernel) { - mm_segment_t fs; - fs = snd_enter_user(); - ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames); - snd_leave_user(fs); - } else { - ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames); - } + ret = __snd_pcm_lib_xfer(substream, (void *)ptr, true, + frames, in_kernel); if (ret == -EPIPE) { if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); @@ -1273,14 +1249,8 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void if (ret < 0) break; } - if (in_kernel) { - mm_segment_t fs; - fs = snd_enter_user(); - ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames); - snd_leave_user(fs); - } else { - ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames); - } + ret = __snd_pcm_lib_xfer(substream, bufs, false, frames, + in_kernel); if (ret != -EPIPE && ret != -ESTRPIPE) break; @@ -1313,14 +1283,8 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void * if (ret < 0) break; } - if (in_kernel) { - mm_segment_t fs; - fs = snd_enter_user(); - ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames); - snd_leave_user(fs); - } else { - ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames); - } + ret = __snd_pcm_lib_xfer(substream, bufs, false, frames, + in_kernel); if (ret != -EPIPE && ret != -ESTRPIPE) break; } @@ -1650,27 +1614,10 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) size = runtime->control->appl_ptr % runtime->period_size; if (size > 0) { size = runtime->period_size - size; - if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) { - size = (runtime->frame_bits * size) / 8; - while (size > 0) { - mm_segment_t fs; - size_t size1 = size < runtime->oss.period_bytes ? size : runtime->oss.period_bytes; - size -= size1; - size1 *= 8; - size1 /= runtime->sample_bits; - snd_pcm_format_set_silence(runtime->format, - runtime->oss.buffer, - size1); - size1 /= runtime->channels; /* frames */ - fs = snd_enter_user(); - snd_pcm_lib_write(substream, (void __force __user *)runtime->oss.buffer, size1); - snd_leave_user(fs); - } - } else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) { - void __user *buffers[runtime->channels]; - memset(buffers, 0, runtime->channels * sizeof(void *)); - snd_pcm_lib_writev(substream, buffers, size); - } + if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) + snd_pcm_lib_write(substream, NULL, size); + else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) + snd_pcm_lib_writev(substream, NULL, size); } mutex_unlock(&runtime->oss.params_lock); /* From fed5794fccf40297f17e0032cc8211cdad0ba6df Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 21 May 2017 19:08:57 +0200 Subject: [PATCH 154/418] ALSA: pcm: Build OSS writev/readv helpers conditionally The snd_pcm_oss_writev3() and snd_pcm_oss_readv3() are used only in io.c with CONFIG_SND_PCM_OSS_PLUGINS=y. Add an ifdef to reduce the build of these functions. Along with it, since they are called always for in-kernel copy, reduce the argument and call snd_pcm_kernel_writev() and *_readv() directly instead. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/oss/io.c | 4 ++-- sound/core/oss/pcm_oss.c | 12 ++++++------ sound/core/oss/pcm_plugin.h | 6 ++---- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/sound/core/oss/io.c b/sound/core/oss/io.c index 6faa1d719206..d870b2d93135 100644 --- a/sound/core/oss/io.c +++ b/sound/core/oss/io.c @@ -26,9 +26,9 @@ #include "pcm_plugin.h" #define pcm_write(plug,buf,count) snd_pcm_oss_write3(plug,buf,count,1) -#define pcm_writev(plug,vec,count) snd_pcm_oss_writev3(plug,vec,count,1) +#define pcm_writev(plug,vec,count) snd_pcm_oss_writev3(plug,vec,count) #define pcm_read(plug,buf,count) snd_pcm_oss_read3(plug,buf,count,1) -#define pcm_readv(plug,vec,count) snd_pcm_oss_readv3(plug,vec,count,1) +#define pcm_readv(plug,vec,count) snd_pcm_oss_readv3(plug,vec,count) /* * Basic io plugin diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 2d6a825cfe88..5e1009d959a8 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1232,7 +1232,8 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p return ret; } -snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel) +#ifdef CONFIG_SND_PCM_OSS_PLUGINS +snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames) { struct snd_pcm_runtime *runtime = substream->runtime; int ret; @@ -1249,8 +1250,7 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void if (ret < 0) break; } - ret = __snd_pcm_lib_xfer(substream, bufs, false, frames, - in_kernel); + ret = snd_pcm_kernel_writev(substream, bufs, frames); if (ret != -EPIPE && ret != -ESTRPIPE) break; @@ -1262,7 +1262,7 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void return ret; } -snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel) +snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames) { struct snd_pcm_runtime *runtime = substream->runtime; int ret; @@ -1283,13 +1283,13 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void * if (ret < 0) break; } - ret = __snd_pcm_lib_xfer(substream, bufs, false, frames, - in_kernel); + ret = snd_pcm_kernel_readv(substream, bufs, frames); if (ret != -EPIPE && ret != -ESTRPIPE) break; } return ret; } +#endif /* CONFIG_SND_PCM_OSS_PLUGINS */ static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const char *buf, size_t bytes, int in_kernel) { diff --git a/sound/core/oss/pcm_plugin.h b/sound/core/oss/pcm_plugin.h index 73c068abaca5..c9cd29d86efd 100644 --- a/sound/core/oss/pcm_plugin.h +++ b/sound/core/oss/pcm_plugin.h @@ -162,11 +162,9 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *ptr, snd_pcm_uframes_t size, int in_kernel); snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, - void **bufs, snd_pcm_uframes_t frames, - int in_kernel); + void **bufs, snd_pcm_uframes_t frames); snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, - void **bufs, snd_pcm_uframes_t frames, - int in_kernel); + void **bufs, snd_pcm_uframes_t frames); #else From f7a478178a8ea970abd34f7ab73e66c9119b1606 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 1 Jun 2017 22:36:02 +0200 Subject: [PATCH 155/418] ALSA: doc: Update copy_user, copy_kernel and fill_silence PCM ops Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- .../kernel-api/writing-an-alsa-driver.rst | 111 ++++++++++++------ 1 file changed, 76 insertions(+), 35 deletions(-) diff --git a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst index 95c5443eff38..58ffa3f5bda7 100644 --- a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst +++ b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst @@ -2080,8 +2080,8 @@ sleeping poll threads, etc. This callback is also atomic as default. -copy and silence callbacks -~~~~~~~~~~~~~~~~~~~~~~~~~~ +copy_user, copy_kernel and fill_silence ops +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ These callbacks are not mandatory, and can be omitted in most cases. These callbacks are used when the hardware buffer cannot be in the @@ -3532,8 +3532,9 @@ external hardware buffer in interrupts (or in tasklets, preferably). The first case works fine if the external hardware buffer is large enough. This method doesn't need any extra buffers and thus is more -effective. You need to define the ``copy`` and ``silence`` callbacks -for the data transfer. However, there is a drawback: it cannot be +effective. You need to define the ``copy_user`` and ``copy_kernel`` +callbacks for the data transfer, in addition to ``fill_silence`` +callback for playback. However, there is a drawback: it cannot be mmapped. The examples are GUS's GF1 PCM or emu8000's wavetable PCM. The second case allows for mmap on the buffer, although you have to @@ -3545,30 +3546,34 @@ Another case is when the chip uses a PCI memory-map region for the buffer instead of the host memory. In this case, mmap is available only on certain architectures like the Intel one. In non-mmap mode, the data cannot be transferred as in the normal way. Thus you need to define the -``copy`` and ``silence`` callbacks as well, as in the cases above. The -examples are found in ``rme32.c`` and ``rme96.c``. +``copy_user``, ``copy_kernel`` and ``fill_silence`` callbacks as well, +as in the cases above. The examples are found in ``rme32.c`` and +``rme96.c``. -The implementation of the ``copy`` and ``silence`` callbacks depends -upon whether the hardware supports interleaved or non-interleaved -samples. The ``copy`` callback is defined like below, a bit -differently depending whether the direction is playback or capture: +The implementation of the ``copy_user``, ``copy_kernel`` and +``silence`` callbacks depends upon whether the hardware supports +interleaved or non-interleaved samples. The ``copy_user`` callback is +defined like below, a bit differently depending whether the direction +is playback or capture: :: - static int playback_copy(struct snd_pcm_substream *substream, int channel, - snd_pcm_uframes_t pos, void *src, snd_pcm_uframes_t count); - static int capture_copy(struct snd_pcm_substream *substream, int channel, - snd_pcm_uframes_t pos, void *dst, snd_pcm_uframes_t count); + static int playback_copy_user(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void __user *src, unsigned long count); + static int capture_copy_user(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void __user *dst, unsigned long count); In the case of interleaved samples, the second argument (``channel``) is not used. The third argument (``pos``) points the current position -offset in frames. +offset in bytes. The meaning of the fourth argument is different between playback and capture. For playback, it holds the source data pointer, and for capture, it's the destination data pointer. -The last argument is the number of frames to be copied. +The last argument is the number of bytes to be copied. What you have to do in this callback is again different between playback and capture directions. In the playback case, you copy the given amount @@ -3578,8 +3583,7 @@ way, the copy would be like: :: - my_memcpy(my_buffer + frames_to_bytes(runtime, pos), src, - frames_to_bytes(runtime, count)); + my_memcpy_from_user(my_buffer + pos, src, count); For the capture direction, you copy the given amount of data (``count``) at the specified offset (``pos``) on the hardware buffer to the @@ -3587,31 +3591,68 @@ specified pointer (``dst``). :: - my_memcpy(dst, my_buffer + frames_to_bytes(runtime, pos), - frames_to_bytes(runtime, count)); + my_memcpy_to_user(dst, my_buffer + pos, count); -Note that both the position and the amount of data are given in frames. +Here the functions are named as ``from_user`` and ``to_user`` because +it's the user-space buffer that is passed to these callbacks. That +is, the callback is supposed to copy from/to the user-space data +directly to/from the hardware buffer. + +Careful readers might notice that these callbacks receive the +arguments in bytes, not in frames like other callbacks. It's because +it would make coding easier like the examples above, and also it makes +easier to unify both the interleaved and non-interleaved cases, as +explained in the following. In the case of non-interleaved samples, the implementation will be a bit -more complicated. +more complicated. The callback is called for each channel, passed by +the second argument, so totally it's called for N-channels times per +transfer. -You need to check the channel argument, and if it's -1, copy the whole -channels. Otherwise, you have to copy only the specified channel. Please -check ``isa/gus/gus_pcm.c`` as an example. +The meaning of other arguments are almost same as the interleaved +case. The callback is supposed to copy the data from/to the given +user-space buffer, but only for the given channel. For the detailed +implementations, please check ``isa/gus/gus_pcm.c`` or +"pci/rme9652/rme9652.c" as examples. -The ``silence`` callback is also implemented in a similar way +The above callbacks are the copy from/to the user-space buffer. There +are some cases where we want copy from/to the kernel-space buffer +instead. In such a case, ``copy_kernel`` callback is called. It'd +look like: + +:: + + static int playback_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *src, unsigned long count); + static int capture_copy_kernel(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void *dst, unsigned long count); + +As found easily, the only difference is that the buffer pointer is +without ``__user`` prefix; that is, a kernel-buffer pointer is passed +in the fourth argument. Correspondingly, the implementation would be +a version without the user-copy, such as: + +:: + + my_memcpy(my_buffer + pos, src, count); + +Usually for the playback, another callback ``fill_silence`` is +defined. It's implemented in a similar way as the copy callbacks +above: :: static int silence(struct snd_pcm_substream *substream, int channel, - snd_pcm_uframes_t pos, snd_pcm_uframes_t count); + unsigned long pos, unsigned long count); -The meanings of arguments are the same as in the ``copy`` callback, -although there is no ``src/dst`` argument. In the case of interleaved -samples, the channel argument has no meaning, as well as on ``copy`` -callback. +The meanings of arguments are the same as in the ``copy_user`` and +``copy_kernel`` callbacks, although there is no buffer pointer +argument. In the case of interleaved samples, the channel argument has +no meaning, as well as on ``copy_*`` callbacks. -The role of ``silence`` callback is to set the given amount +The role of ``fill_silence`` callback is to set the given amount (``count``) of silence data at the specified offset (``pos``) on the hardware buffer. Suppose that the data format is signed (that is, the silent-data is 0), and the implementation using a memset-like function @@ -3619,11 +3660,11 @@ would be like: :: - my_memcpy(my_buffer + frames_to_bytes(runtime, pos), 0, - frames_to_bytes(runtime, count)); + my_memset(my_buffer + pos, 0, count); In the case of non-interleaved samples, again, the implementation -becomes a bit more complicated. See, for example, ``isa/gus/gus_pcm.c``. +becomes a bit more complicated, as it's called N-times per transfer +for each channel. See, for example, ``isa/gus/gus_pcm.c``. Non-Contiguous Buffers ---------------------- From f07b38e53b71aeb62f865632d31d3f579a77ffc0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 6 Jun 2017 02:34:42 +0000 Subject: [PATCH 156/418] ASoC: rsnd: remove unused rsnd_ssi_non_ops rsnd_ssi_non_ops is never used. Let's remove it Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index d0602c189736..eddd8afa0825 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -791,13 +791,6 @@ int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) } -/* - * Non SSI - */ -static struct rsnd_mod_ops rsnd_ssi_non_ops = { - .name = SSI_NAME, -}; - /* * ssi mod function */ @@ -998,7 +991,6 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) goto rsnd_ssi_probe_done; } - ops = &rsnd_ssi_non_ops; if (of_property_read_bool(np, "pio-transfer")) ops = &rsnd_ssi_pio_ops; else From d70c34db3357cedf8735ebad0b0fa5fed7b54b35 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 6 Jun 2017 02:35:10 +0000 Subject: [PATCH 157/418] ASoC: rsnd: remove unused rsnd_dai_path_info commit 2ea2cc86db7c ("ASoC: rsnd: remove struct rcar_snd_info") removed all struct rsnd_dai_path_info related code. This patch removes unused rsnd_dai_path_info. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsnd.h | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 037e33ffa69d..96a567de5f14 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -421,7 +421,6 @@ struct rsnd_dai_stream { char name[RSND_DAI_NAME_SIZE]; struct snd_pcm_substream *substream; struct rsnd_mod *mod[RSND_MOD_MAX]; - struct rsnd_dai_path_info *info; /* rcar_snd.h */ struct rsnd_dai *rdai; u32 parent_ssi_status; int byte_pos; From 010f21b2ba0cd546d7489ca536a156b281faa3fb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 6 Jun 2017 02:35:43 +0000 Subject: [PATCH 158/418] ASoC: simple-scu-card: tidyup "Sampling Rate Conversion" "Sampling Rate Conversion" is better than "Sampling Rate Convert" Reported-by: James Cameron Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/simple-scu-card.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/simple-scu-card.txt b/Documentation/devicetree/bindings/sound/simple-scu-card.txt index e894cef1d314..327d229a51b2 100644 --- a/Documentation/devicetree/bindings/sound/simple-scu-card.txt +++ b/Documentation/devicetree/bindings/sound/simple-scu-card.txt @@ -38,7 +38,7 @@ Optional CPU/CODEC subnodes properties: - clocks / system-clock-frequency : see simple-audio-card.txt -Example 1. Sampling Rate Covert +Example 1. Sampling Rate Conversion sound { compatible = "simple-scu-audio-card"; From 08862251476f899c4c4528e922df5854076b8661 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 6 Jun 2017 02:37:07 +0000 Subject: [PATCH 159/418] ASoC: audio-graph-scu-card: add missing MIX binding example Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../bindings/sound/audio-graph-scu-card.txt | 47 ++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt b/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt index b2dd23fd2135..b63c5594bbb3 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt +++ b/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt @@ -35,7 +35,7 @@ Required properties: - compatible : "audio-graph-scu-card"; - dais : list of CPU DAI port{s} -Example +Example 1. Sampling Rate Conversion sound_card { compatible = "audio-graph-scu-card"; @@ -70,3 +70,48 @@ Example }; }; }; + +Example 2. 2 CPU 1 Codec (Mixing) + + sound_card { + compatible = "audio-graph-scu-card"; + + label = "sound-card"; + prefix = "codec"; + routing = "codec Playback", "DAI0 Playback", + "codec Playback", "DAI1 Playback"; + convert-rate = <48000>; + + dais = <&cpu_port0 + &cpu_port1>; + }; + + audio-codec { + ... + + port { + codec_endpoint: endpoint { + remote-endpoint = <&cpu_endpoint0>; + }; + }; + }; + + dai-controller { + ... + ports { + cpu_port0: port { + cpu_endpoint0: endpoint { + remote-endpoint = <&codec_endpoint>; + + dai-format = "left_j"; + ... + }; + }; + cpu_port1: port { + cpu_endpoint1: endpoint { + dai-format = "left_j"; + ... + }; + }; + }; + }; From af2728e4deb9f08721374f3adc06b1d3e7d133ec Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Tue, 6 Jun 2017 14:59:54 +0800 Subject: [PATCH 160/418] ASoC: rt5663: Fix the IRQ issue The patch fixed the IRQ issue. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 2 +- sound/soc/codecs/rt5663.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index a32508d7dcfd..8569e8c7d894 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -3141,7 +3141,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5663->regmap, RT5663_DIG_MISC, RT5663_DIG_GATE_CTRL_MASK, RT5663_DIG_GATE_CTRL_EN); regmap_update_bits(rt5663->regmap, RT5663_AUTO_1MRC_CLK, - RT5663_IRQ_POW_SAV_MASK, RT5663_IRQ_POW_SAV_EN); + RT5663_IRQ_MANUAL_MASK, RT5663_IRQ_MANUAL_EN); regmap_update_bits(rt5663->regmap, RT5663_IRQ_1, RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN); regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, diff --git a/sound/soc/codecs/rt5663.h b/sound/soc/codecs/rt5663.h index d77fae619f2f..4621812c94d8 100644 --- a/sound/soc/codecs/rt5663.h +++ b/sound/soc/codecs/rt5663.h @@ -590,6 +590,10 @@ #define RT5663_IRQ_POW_SAV_JD1_SHIFT 14 #define RT5663_IRQ_POW_SAV_JD1_DIS (0x0 << 14) #define RT5663_IRQ_POW_SAV_JD1_EN (0x1 << 14) +#define RT5663_IRQ_MANUAL_MASK (0x1 << 8) +#define RT5663_IRQ_MANUAL_SHIFT 8 +#define RT5663_IRQ_MANUAL_DIS (0x0 << 8) +#define RT5663_IRQ_MANUAL_EN (0x1 << 8) /* IRQ Control 1 (0x00b6) */ #define RT5663_EN_CB_JD_MASK (0x1 << 3) From 50aadc14cee74009c72e7d66954b15f27d45c02f Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Mon, 5 Jun 2017 21:27:20 +0800 Subject: [PATCH 161/418] ASoC: sun8i-codec-analog: prepare a mixer control/widget/route set for V3s Allwinner V3s has an analog codec without MIC2 and Line In, which will need a special set of mixer controls/widgets/routes, otherwise meaningless controls will be exported to userspace and confuse the user. Add the special set, and use it when the SoC has no MIC2 and Line In. Signed-off-by: Icenowy Zheng Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec-analog.c | 101 ++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c index edcc3eb7cd9a..29c446068151 100644 --- a/sound/soc/sunxi/sun8i-codec-analog.c +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -219,6 +219,22 @@ static const struct snd_kcontrol_new sun8i_codec_mixer_controls[] = { SUN8I_ADDA_LOMIXSC_MIC2, 1, 0), }; +/* mixer controls */ +static const struct snd_kcontrol_new sun8i_v3s_codec_mixer_controls[] = { + SOC_DAPM_DOUBLE_R("DAC Playback Switch", + SUN8I_ADDA_LOMIXSC, + SUN8I_ADDA_ROMIXSC, + SUN8I_ADDA_LOMIXSC_DACL, 1, 0), + SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch", + SUN8I_ADDA_LOMIXSC, + SUN8I_ADDA_ROMIXSC, + SUN8I_ADDA_LOMIXSC_DACR, 1, 0), + SOC_DAPM_DOUBLE_R("Mic1 Playback Switch", + SUN8I_ADDA_LOMIXSC, + SUN8I_ADDA_ROMIXSC, + SUN8I_ADDA_LOMIXSC_MIC1, 1, 0), +}; + /* ADC mixer controls */ static const struct snd_kcontrol_new sun8i_codec_adc_mixer_controls[] = { SOC_DAPM_DOUBLE_R("Mixer Capture Switch", @@ -243,6 +259,22 @@ static const struct snd_kcontrol_new sun8i_codec_adc_mixer_controls[] = { SUN8I_ADDA_LADCMIXSC_MIC2, 1, 0), }; +/* ADC mixer controls */ +static const struct snd_kcontrol_new sun8i_v3s_codec_adc_mixer_controls[] = { + SOC_DAPM_DOUBLE_R("Mixer Capture Switch", + SUN8I_ADDA_LADCMIXSC, + SUN8I_ADDA_RADCMIXSC, + SUN8I_ADDA_LADCMIXSC_OMIXRL, 1, 0), + SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch", + SUN8I_ADDA_LADCMIXSC, + SUN8I_ADDA_RADCMIXSC, + SUN8I_ADDA_LADCMIXSC_OMIXRR, 1, 0), + SOC_DAPM_DOUBLE_R("Mic1 Capture Switch", + SUN8I_ADDA_LADCMIXSC, + SUN8I_ADDA_RADCMIXSC, + SUN8I_ADDA_LADCMIXSC_MIC1, 1, 0), +}; + /* volume / mute controls */ static const DECLARE_TLV_DB_SCALE(sun8i_codec_out_mixer_pregain_scale, -450, 150, 0); @@ -292,8 +324,9 @@ static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = { /* Mic input path */ SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN, 0, NULL, 0), +}; - /* Mixers */ +static const struct snd_soc_dapm_widget sun8i_codec_mixer_widgets[] = { SND_SOC_DAPM_MIXER("Left Mixer", SUN8I_ADDA_DAC_PA_SRC, SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0, sun8i_codec_mixer_controls, @@ -312,10 +345,31 @@ static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = { ARRAY_SIZE(sun8i_codec_adc_mixer_controls)), }; +static const struct snd_soc_dapm_widget sun8i_v3s_codec_mixer_widgets[] = { + SND_SOC_DAPM_MIXER("Left Mixer", SUN8I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0, + sun8i_v3s_codec_mixer_controls, + ARRAY_SIZE(sun8i_v3s_codec_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Mixer", SUN8I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_RMIXEN, 0, + sun8i_v3s_codec_mixer_controls, + ARRAY_SIZE(sun8i_v3s_codec_mixer_controls)), + SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0, + sun8i_v3s_codec_adc_mixer_controls, + ARRAY_SIZE(sun8i_v3s_codec_adc_mixer_controls)), + SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCREN, 0, + sun8i_v3s_codec_adc_mixer_controls, + ARRAY_SIZE(sun8i_v3s_codec_adc_mixer_controls)), +}; + static const struct snd_soc_dapm_route sun8i_codec_common_routes[] = { /* Microphone Routes */ { "Mic1 Amplifier", NULL, "MIC1"}, +}; +static const struct snd_soc_dapm_route sun8i_codec_mixer_routes[] = { /* Left Mixer Routes */ { "Left Mixer", "DAC Playback Switch", "Left DAC" }, { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, @@ -714,6 +768,48 @@ static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = { .has_mic2 = true, }; +static int sun8i_codec_analog_add_mixer(struct snd_soc_component *cmpnt, + const struct sun8i_codec_analog_quirks *quirks) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); + struct device *dev = cmpnt->dev; + int ret; + + if (!quirks->has_mic2 && !quirks->has_linein) { + /* + * Apply the special widget set which has uses a control + * without MIC2 and Line In, for SoCs without these. + * TODO: not all special cases are supported now, this case + * is present because it's the case of V3s. + */ + ret = snd_soc_dapm_new_controls(dapm, + sun8i_v3s_codec_mixer_widgets, + ARRAY_SIZE(sun8i_v3s_codec_mixer_widgets)); + if (ret) { + dev_err(dev, "Failed to add V3s Mixer DAPM widgets: %d\n", ret); + return ret; + } + } else { + /* Apply the generic mixer widget set. */ + ret = snd_soc_dapm_new_controls(dapm, + sun8i_codec_mixer_widgets, + ARRAY_SIZE(sun8i_codec_mixer_widgets)); + if (ret) { + dev_err(dev, "Failed to add Mixer DAPM widgets: %d\n", ret); + return ret; + } + } + + ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_mixer_routes, + ARRAY_SIZE(sun8i_codec_mixer_routes)); + if (ret) { + dev_err(dev, "Failed to add Mixer DAPM routes: %d\n", ret); + return ret; + } + + return 0; +} + static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt) { struct device *dev = cmpnt->dev; @@ -728,6 +824,9 @@ static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt) quirks = of_device_get_match_data(dev); /* Add controls, widgets, and routes for individual features */ + ret = sun8i_codec_analog_add_mixer(cmpnt, quirks); + if (ret) + return ret; if (quirks->has_headphone) { ret = sun8i_codec_add_headphone(cmpnt); From 2cfeaec0ec896bc0b8aad2de28a3de4572c7e4a1 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Mon, 5 Jun 2017 21:27:21 +0800 Subject: [PATCH 162/418] ASoC: sun8i-codec-analog: add support for V3s SoC The V3s SoC features an analog codec with headphone support but without mic2 and linein. Add support for it. Signed-off-by: Icenowy Zheng Reviewed-by: Chen-Yu Tsai Acked-by: Rob Herring Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/sun8i-codec-analog.txt | 1 + sound/soc/sunxi/sun8i-codec-analog.c | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt b/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt index 779b735781ba..1b6e7c4e50ab 100644 --- a/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt +++ b/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt @@ -4,6 +4,7 @@ Required properties: - compatible: must be one of the following compatibles: - "allwinner,sun8i-a23-codec-analog" - "allwinner,sun8i-h3-codec-analog" + - "allwinner,sun8i-v3s-codec-analog" Required properties if not a sub-node of the PRCM node: - reg: must contain the registers location and length diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c index 29c446068151..485e79f292c4 100644 --- a/sound/soc/sunxi/sun8i-codec-analog.c +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -810,6 +810,11 @@ static int sun8i_codec_analog_add_mixer(struct snd_soc_component *cmpnt, return 0; } +static const struct sun8i_codec_analog_quirks sun8i_v3s_quirks = { + .has_headphone = true, + .has_hmic = true, +}; + static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt) { struct device *dev = cmpnt->dev; @@ -886,6 +891,10 @@ static const struct of_device_id sun8i_codec_analog_of_match[] = { .compatible = "allwinner,sun8i-h3-codec-analog", .data = &sun8i_h3_quirks, }, + { + .compatible = "allwinner,sun8i-v3s-codec-analog", + .data = &sun8i_v3s_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match); From 8b2840b6daca728cecfa925b50bf638189e2fbca Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Mon, 5 Jun 2017 21:27:22 +0800 Subject: [PATCH 163/418] ASoC: sun4i-codec: Add support for V3s codec The codec in the V3s is similar to the one found on the A31. One key difference is the analog path controls are routed through the PRCM block. This is supported by the sun8i-codec-analog driver, and tied into this codec driver with the audio card's aux_dev. In addition, the V3s does not have LINEIN, LINEOUT, MBIAS and MIC2, MIC3, and the FIFO related registers are like H3. Signed-off-by: Icenowy Zheng Reviewed-by: Chen-Yu Tsai Acked-by: Rob Herring Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/sun4i-codec.txt | 11 ++-- sound/soc/sunxi/sun4i-codec.c | 63 +++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt index 3863531d1e6d..2d4e10deb6f4 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt @@ -7,6 +7,7 @@ Required properties: - "allwinner,sun7i-a20-codec" - "allwinner,sun8i-a23-codec" - "allwinner,sun8i-h3-codec" + - "allwinner,sun8i-v3s-codec" - reg: must contain the registers location and length - interrupts: must contain the codec interrupt - dmas: DMA channels for tx and rx dma. See the DMA client binding, @@ -25,6 +26,7 @@ Required properties for the following compatibles: - "allwinner,sun6i-a31-codec" - "allwinner,sun8i-a23-codec" - "allwinner,sun8i-h3-codec" + - "allwinner,sun8i-v3s-codec" - resets: phandle to the reset control for this device - allwinner,audio-routing: A list of the connections between audio components. Each entry is a pair of strings, the first being the @@ -34,15 +36,15 @@ Required properties for the following compatibles: Audio pins on the SoC: "HP" "HPCOM" - "LINEIN" - "LINEOUT" (not on sun8i-a23) + "LINEIN" (not on sun8i-v3s) + "LINEOUT" (not on sun8i-a23 or sun8i-v3s) "MIC1" - "MIC2" + "MIC2" (not on sun8i-v3s) "MIC3" (sun6i-a31 only) Microphone biases from the SoC: "HBIAS" - "MBIAS" + "MBIAS" (not on sun8i-v3s) Board connectors: "Headphone" @@ -55,6 +57,7 @@ Required properties for the following compatibles: Required properties for the following compatibles: - "allwinner,sun8i-a23-codec" - "allwinner,sun8i-h3-codec" + - "allwinner,sun8i-v3s-codec" - allwinner,codec-analog-controls: A phandle to the codec analog controls block in the PRCM. diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index c3aab10fa085..150069987c0c 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -1339,6 +1339,44 @@ static struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev) return card; }; +static struct snd_soc_card *sun8i_v3s_codec_create_card(struct device *dev) +{ + struct snd_soc_card *card; + int ret; + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return ERR_PTR(-ENOMEM); + + aux_dev.codec_of_node = of_parse_phandle(dev->of_node, + "allwinner,codec-analog-controls", + 0); + if (!aux_dev.codec_of_node) { + dev_err(dev, "Can't find analog controls for codec.\n"); + return ERR_PTR(-EINVAL); + }; + + card->dai_link = sun4i_codec_create_link(dev, &card->num_links); + if (!card->dai_link) + return ERR_PTR(-ENOMEM); + + card->dev = dev; + card->name = "V3s Audio Codec"; + card->dapm_widgets = sun6i_codec_card_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets); + card->dapm_routes = sun8i_codec_card_routes; + card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes); + card->aux_dev = &aux_dev; + card->num_aux_devs = 1; + card->fully_routed = true; + + ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); + if (ret) + dev_warn(dev, "failed to parse audio-routing: %d\n", ret); + + return card; +}; + static const struct regmap_config sun4i_codec_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -1374,6 +1412,13 @@ static const struct regmap_config sun8i_h3_codec_regmap_config = { .max_register = SUN8I_H3_CODEC_ADC_DBG, }; +static const struct regmap_config sun8i_v3s_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN8I_H3_CODEC_ADC_DBG, +}; + struct sun4i_codec_quirks { const struct regmap_config *regmap_config; const struct snd_soc_codec_driver *codec; @@ -1437,6 +1482,20 @@ static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = { .has_reset = true, }; +static const struct sun4i_codec_quirks sun8i_v3s_codec_quirks = { + .regmap_config = &sun8i_v3s_codec_regmap_config, + /* + * TODO The codec structure should be split out, like + * H3, when adding digital audio processing support. + */ + .codec = &sun8i_a23_codec_codec, + .create_card = sun8i_v3s_codec_create_card, + .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA, + .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, + .has_reset = true, +}; + static const struct of_device_id sun4i_codec_of_match[] = { { .compatible = "allwinner,sun4i-a10-codec", @@ -1458,6 +1517,10 @@ static const struct of_device_id sun4i_codec_of_match[] = { .compatible = "allwinner,sun8i-h3-codec", .data = &sun8i_h3_codec_quirks, }, + { + .compatible = "allwinner,sun8i-v3s-codec", + .data = &sun8i_v3s_codec_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun4i_codec_of_match); From d4dbcb63c8bde48741468cf7c711b76ed3e7fce5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 5 Jun 2017 04:27:56 +0000 Subject: [PATCH 164/418] ASoC: simple-card-utils: share same dev_dbg() for Card Name Let's share same debug message for Card Name Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-scu-card.c | 2 -- sound/soc/generic/simple-card-utils.c | 2 ++ sound/soc/generic/simple-scu-card.c | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c index c5c52d1f500c..1ce727b6bc21 100644 --- a/sound/soc/generic/audio-graph-scu-card.c +++ b/sound/soc/generic/audio-graph-scu-card.c @@ -295,8 +295,6 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) if (ret) goto parse_of_err; - dev_dbg(dev, "New card: %s\n", - card->name ? card->name : ""); dev_dbg(dev, "convert_rate %d\n", priv->convert_rate); dev_dbg(dev, "convert_channels %d\n", priv->convert_channels); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 9c7f5b91b90a..da24ac171aec 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -100,6 +100,8 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card, if (!card->name && card->dai_link) card->name = card->dai_link->name; + dev_dbg(card->dev, "Card Name: %s\n", card->name ? card->name : ""); + return 0; } EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name); diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index 9b9b01e12149..5f4384f322c1 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -246,8 +246,6 @@ static int asoc_simple_card_parse_of(struct device_node *node, if (ret < 0) return ret; - dev_dbg(dev, "New card: %s\n", - card->name ? card->name : ""); dev_dbg(dev, "convert_rate %d\n", priv->convert_rate); dev_dbg(dev, "convert_channels %d\n", priv->convert_channels); From aaad9c131b8fcdb493ed64e56cea8ea52977e091 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 5 Jun 2017 04:28:12 +0000 Subject: [PATCH 165/418] ASoC: simple-card-utils: share same dev_dbg() for DAI format Let's share same debug message for DAI format Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 1 - sound/soc/generic/simple-card-utils.c | 2 ++ sound/soc/generic/simple-card.c | 1 - 3 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 93c167a91d2d..1769a39a22c4 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -170,7 +170,6 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, dai_link->init = asoc_graph_card_dai_init; dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); - dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt); dev_dbg(dev, "\tcpu : %s / %d\n", dai_link->cpu_dai_name, cpu_dai->sysclk); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index da24ac171aec..59e770125596 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -51,6 +51,8 @@ int asoc_simple_card_parse_daifmt(struct device *dev, *retfmt = daifmt; + dev_dbg(dev, "format : %04x\n", daifmt); + return 0; } EXPORT_SYMBOL_GPL(asoc_simple_card_parse_daifmt); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 4dacaf78a0de..d364f08a7182 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -302,7 +302,6 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, dai_link->init = asoc_simple_card_dai_init; dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); - dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt); dev_dbg(dev, "\tcpu : %s / %d\n", dai_link->cpu_dai_name, dai_props->cpu_dai.sysclk); From 4579771ebb78aa26831ee3d9617690da5198072c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 5 Jun 2017 04:28:29 +0000 Subject: [PATCH 166/418] ASoC: simple-card-utils: share same dev_dbg() for Dai Name Let's share same debug message for DAI Name Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 1 - sound/soc/generic/simple-card-utils.c | 2 ++ sound/soc/generic/simple-card.c | 1 - 3 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 1769a39a22c4..2c3a1cc01442 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -169,7 +169,6 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, dai_link->ops = &asoc_graph_card_ops; dai_link->init = asoc_graph_card_dai_init; - dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); dev_dbg(dev, "\tcpu : %s / %d\n", dai_link->cpu_dai_name, cpu_dai->sysclk); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 59e770125596..1f08064f65b1 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -74,6 +74,8 @@ int asoc_simple_card_set_dailink_name(struct device *dev, dai_link->name = name; dai_link->stream_name = name; + + dev_dbg(dev, "name : %s\n", name); } return ret; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index d364f08a7182..1da0e2b068c3 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -301,7 +301,6 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, dai_link->ops = &asoc_simple_card_ops; dai_link->init = asoc_simple_card_dai_init; - dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); dev_dbg(dev, "\tcpu : %s / %d\n", dai_link->cpu_dai_name, dai_props->cpu_dai.sysclk); From 8e16638256425faf74c5b9ffa40e5f0d9aa4413b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 5 Jun 2017 04:28:45 +0000 Subject: [PATCH 167/418] ASoC: simple-card-utils: share same dev_dbg() for sysclk Let's share same debug message for sysclk Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 9 ++++++--- sound/soc/generic/audio-graph-card.c | 7 ------- sound/soc/generic/audio-graph-scu-card.c | 5 ----- sound/soc/generic/simple-card-utils.c | 5 ++++- sound/soc/generic/simple-card.c | 7 ------- sound/soc/generic/simple-scu-card.c | 5 ----- 6 files changed, 10 insertions(+), 28 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index efab584af11b..108cae459ed0 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -35,13 +35,16 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card, char *prefix); #define asoc_simple_card_parse_clk_cpu(dev, node, dai_link, simple_dai) \ - asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai) + asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai, \ + dai_link->cpu_dai_name) #define asoc_simple_card_parse_clk_codec(dev, node, dai_link, simple_dai) \ - asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai) + asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai,\ + dai_link->codec_dai_name) int asoc_simple_card_parse_clk(struct device *dev, struct device_node *node, struct device_node *dai_of_node, - struct asoc_simple_dai *simple_dai); + struct asoc_simple_dai *simple_dai, + const char *name); #define asoc_simple_card_parse_cpu(node, dai_link, \ list_name, cells_name, is_single_link) \ diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 2c3a1cc01442..0180b286bee3 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -169,13 +169,6 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, dai_link->ops = &asoc_graph_card_ops; dai_link->init = asoc_graph_card_dai_init; - dev_dbg(dev, "\tcpu : %s / %d\n", - dai_link->cpu_dai_name, - cpu_dai->sysclk); - dev_dbg(dev, "\tcodec : %s / %d\n", - dai_link->codec_dai_name, - codec_dai->sysclk); - asoc_simple_card_canonicalize_cpu(dai_link, card->num_links == 1); diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c index 1ce727b6bc21..0066102f5bc4 100644 --- a/sound/soc/generic/audio-graph-scu-card.c +++ b/sound/soc/generic/audio-graph-scu-card.c @@ -185,11 +185,6 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, dai_link->ops = &asoc_graph_card_ops; dai_link->init = asoc_graph_card_dai_init; - dev_dbg(dev, "\t%s / %04x / %d\n", - dai_link->name, - dai_link->dai_fmt, - dai_props->sysclk); - return 0; } diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 1f08064f65b1..d9d8b8a58348 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -113,7 +113,8 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name); int asoc_simple_card_parse_clk(struct device *dev, struct device_node *node, struct device_node *dai_of_node, - struct asoc_simple_dai *simple_dai) + struct asoc_simple_dai *simple_dai, + const char *name) { struct clk *clk; u32 val; @@ -136,6 +137,8 @@ int asoc_simple_card_parse_clk(struct device *dev, simple_dai->sysclk = clk_get_rate(clk); } + dev_dbg(dev, "%s : sysclk = %d\n", name, simple_dai->sysclk); + return 0; } EXPORT_SYMBOL_GPL(asoc_simple_card_parse_clk); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 1da0e2b068c3..e86c6e16146b 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -301,13 +301,6 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, dai_link->ops = &asoc_simple_card_ops; dai_link->init = asoc_simple_card_dai_init; - dev_dbg(dev, "\tcpu : %s / %d\n", - dai_link->cpu_dai_name, - dai_props->cpu_dai.sysclk); - dev_dbg(dev, "\tcodec : %s / %d\n", - dai_link->codec_dai_name, - dai_props->codec_dai.sysclk); - asoc_simple_card_canonicalize_cpu(dai_link, single_cpu); dai_link_of_err: diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index 5f4384f322c1..9a251400685e 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -189,11 +189,6 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, dai_link->ops = &asoc_simple_card_ops; dai_link->init = asoc_simple_card_dai_init; - dev_dbg(dev, "\t%s / %04x / %d\n", - dai_link->name, - dai_link->dai_fmt, - dai_props->sysclk); - return 0; } From 5f440c48c5d5a11f1892819c409e183b2056e4ba Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 1 Jun 2017 12:36:15 +0200 Subject: [PATCH 168/418] ASoC: rsnd: Document optional reset properties Document the optional properties for describing module resets, to support resetting these modules on R-Car Gen2 and Gen3. Note that the audio module has resets for the Serial Sound Interfaces only. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/renesas,rsnd.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 13cb21d53b8b..7246bb268bf9 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -379,6 +379,9 @@ Optional properties: - clock-frequency : for all audio_clkout0/1/2/3 - clkout-lr-asynchronous : boolean property. it indicates that audio_clkoutn is asynchronizes with lr-clock. +- resets : References to SSI resets. +- reset-names : List of valid reset names. + "ssi-all", "ssi.X" SSI subnode properties: - interrupts : Should contain SSI interrupt for PIO transfer From a00cebf51d5ceed8ba9f6fac5fb189b38cd5a7c2 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Wed, 31 May 2017 14:32:33 +0200 Subject: [PATCH 169/418] ASoC: atmel: tse850: fix off-by-one in the "ANA" enumeration count At some point I added the "Low" entry at the beginning of the array without bumping the enumeration count from 9 to 10. Fix this. While at it, fix the anti-pattern for the other enumeration (used by MUX{1,2}). Fixes: aa43112445f0 ("ASoC: atmel: tse850: add ASoC driver for the Axentia TSE-850") Signed-off-by: Peter Rosin Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/atmel/tse850-pcm5142.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c index a72c7d642026..3a1393283156 100644 --- a/sound/soc/atmel/tse850-pcm5142.c +++ b/sound/soc/atmel/tse850-pcm5142.c @@ -227,7 +227,7 @@ int tse850_put_ana(struct snd_kcontrol *kctrl, static const char * const mux_text[] = { "Mixer", "Loop" }; static const struct soc_enum mux_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, mux_text); + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(mux_text), mux_text); static const struct snd_kcontrol_new mux1 = SOC_DAPM_ENUM_EXT("MUX1", mux_enum, tse850_get_mux1, tse850_put_mux1); @@ -252,7 +252,7 @@ static const char * const ana_text[] = { }; static const struct soc_enum ana_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 9, ana_text); + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(ana_text), ana_text); static const struct snd_kcontrol_new out = SOC_DAPM_ENUM_EXT("ANA", ana_enum, tse850_get_ana, tse850_put_ana); From dc43f46a9b6988a40d4e11d05b8107d4546c61b9 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 31 May 2017 16:51:13 +0100 Subject: [PATCH 170/418] ASoC: cs35l35: Add additional delay for reset Very fast systems may violate the minimum constraints for time the reset line needs to remain low, or communicate with the device too soon after releasing the reset. Fix this by adding some delays in to allow the chip to properly reset, also factor out the reset into a function as it is likely it will be re-used in later additions to the driver. Signed-off-by: Charles Keepax Acked-by: Paul Handrigan Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index f8aef5869b03..5ff12e4116e5 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -162,6 +162,14 @@ static bool cs35l35_precious_register(struct device *dev, unsigned int reg) } } +static void cs35l35_reset(struct cs35l35_private *cs35l35) +{ + gpiod_set_value_cansleep(cs35l35->reset_gpio, 0); + usleep_range(2000, 2100); + gpiod_set_value_cansleep(cs35l35->reset_gpio, 1); + usleep_range(1000, 1100); +} + static int cs35l35_wait_for_pdn(struct cs35l35_private *cs35l35) { int ret; @@ -1454,7 +1462,7 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, } } - gpiod_set_value_cansleep(cs35l35->reset_gpio, 1); + cs35l35_reset(cs35l35); init_completion(&cs35l35->pdn_done); From 98cf2c03b467fa67df58cb52adeb85b425cabcb2 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 30 May 2017 09:51:30 -0700 Subject: [PATCH 171/418] ASoC: Intel: sst: Delete sst_shim_regs64; saved regs are never used In commit 9a075265c6dc ("ASoC: Intel: sst: Remove unused function sst_restore_shim64()"), we deleted the sst_restore_shim64() since it was never used. ...but a quick look at the code shows that we should also be able to remove the sst_save_shim64() function and the structure members we were storing data in. Once we delete sst_save_shim64() there are no longer any users of the 'sst_shim_regs64' structure. That means we can delete it completely and also avoid allocating memory for it. This saves a whopping 136 bytes of devm allocated memory. We also get the nice benefit of avoiding an error path in the init code. Note that the saving code that we're removing (and the comments talking about how important it is to do the save) has been around since commit 336cfbb05edf ("ASoC: Intel: mrfld- add ACPI module"). Signed-off-by: Douglas Anderson Reviewed-by: Andy Shevchenko Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst.c | 19 ------------------- sound/soc/intel/atom/sst/sst.h | 22 ---------------------- sound/soc/intel/atom/sst/sst_acpi.c | 14 -------------- 3 files changed, 55 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index 2d43b8693c0c..5ee92257ca85 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -382,21 +382,6 @@ void sst_context_cleanup(struct intel_sst_drv *ctx) } EXPORT_SYMBOL_GPL(sst_context_cleanup); -static inline void sst_save_shim64(struct intel_sst_drv *ctx, - void __iomem *shim, - struct sst_shim_regs64 *shim_regs) -{ - unsigned long irq_flags; - - spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags); - - shim_regs->imrx = sst_shim_read64(shim, SST_IMRX); - shim_regs->csr = sst_shim_read64(shim, SST_CSR); - - - spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags); -} - void sst_configure_runtime_pm(struct intel_sst_drv *ctx) { pm_runtime_set_autosuspend_delay(ctx->dev, SST_SUSPEND_DELAY); @@ -416,8 +401,6 @@ void sst_configure_runtime_pm(struct intel_sst_drv *ctx) pm_runtime_set_active(ctx->dev); else pm_runtime_put_noidle(ctx->dev); - - sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64); } EXPORT_SYMBOL_GPL(sst_configure_runtime_pm); @@ -441,8 +424,6 @@ static int intel_sst_runtime_suspend(struct device *dev) flush_workqueue(ctx->post_msg_wq); ctx->ops->reset(ctx); - /* save the shim registers because PMC doesn't save state */ - sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64); return ret; } diff --git a/sound/soc/intel/atom/sst/sst.h b/sound/soc/intel/atom/sst/sst.h index 5c9a51cc77aa..1693befa455a 100644 --- a/sound/soc/intel/atom/sst/sst.h +++ b/sound/soc/intel/atom/sst/sst.h @@ -317,26 +317,6 @@ struct sst_ipc_reg { int ipcd; }; -struct sst_shim_regs64 { - u64 csr; - u64 pisr; - u64 pimr; - u64 isrx; - u64 isrd; - u64 imrx; - u64 imrd; - u64 ipcx; - u64 ipcd; - u64 isrsc; - u64 isrlpesc; - u64 imrsc; - u64 imrlpesc; - u64 ipcsc; - u64 ipclpesc; - u64 clkctl; - u64 csr2; -}; - struct sst_fw_save { void *iram; void *dram; @@ -356,7 +336,6 @@ struct sst_fw_save { * @dram : SST DRAM pointer * @pdata : SST info passed as a part of pci platform data * @shim_phy_add : SST shim phy addr - * @shim_regs64: Struct to save shim registers * @ipc_dispatch_list : ipc messages dispatched * @rx_list : to copy the process_reply/process_msg from DSP * @ipc_post_msg_wq : wq to post IPC messages context @@ -398,7 +377,6 @@ struct intel_sst_drv { unsigned int ddr_end; unsigned int ddr_base; unsigned int mailbox_recv_offset; - struct sst_shim_regs64 *shim_regs64; struct list_head block_list; struct list_head ipc_dispatch_list; struct sst_platform_info *pdata; diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 592f6afaf2a5..cf88cd1865fb 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -358,23 +358,9 @@ static int sst_acpi_probe(struct platform_device *pdev) if (ret < 0) return ret; - /* need to save shim registers in BYT */ - ctx->shim_regs64 = devm_kzalloc(ctx->dev, sizeof(*ctx->shim_regs64), - GFP_KERNEL); - if (!ctx->shim_regs64) { - ret = -ENOMEM; - goto do_sst_cleanup; - } - sst_configure_runtime_pm(ctx); platform_set_drvdata(pdev, ctx); return ret; - -do_sst_cleanup: - sst_context_cleanup(ctx); - platform_set_drvdata(pdev, NULL); - dev_err(ctx->dev, "failed with %d\n", ret); - return ret; } /** From db6879efb9d1d48ff9c2bd49dde05ecf757d73cf Mon Sep 17 00:00:00 2001 From: Dharageswari R Date: Wed, 31 May 2017 10:30:24 +0530 Subject: [PATCH 172/418] ASoC: Intel: Skylake: Add mic-select module type mic-select module is a DSP module, which is used to select one or more input channels. This patch adds mic-select module type. Signed-off-by: Dharageswari R Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 2 ++ sound/soc/intel/skylake/skl-tplg-interface.h | 1 + 2 files changed, 3 insertions(+) diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index ab1adc0c9cc3..5a465020ebd8 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -707,6 +707,7 @@ static u16 skl_get_module_param_size(struct skl_sst *ctx, return param_size; case SKL_MODULE_TYPE_BASE_OUTFMT: + case SKL_MODULE_TYPE_MIC_SELECT: case SKL_MODULE_TYPE_KPB: return sizeof(struct skl_base_outfmt_cfg); @@ -761,6 +762,7 @@ static int skl_set_module_format(struct skl_sst *ctx, break; case SKL_MODULE_TYPE_BASE_OUTFMT: + case SKL_MODULE_TYPE_MIC_SELECT: case SKL_MODULE_TYPE_KPB: skl_set_base_outfmt_format(ctx, module_config, *param_data); break; diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h index 7a2febf99019..c22517bd2161 100644 --- a/sound/soc/intel/skylake/skl-tplg-interface.h +++ b/sound/soc/intel/skylake/skl-tplg-interface.h @@ -82,6 +82,7 @@ enum skl_module_type { SKL_MODULE_TYPE_ALGO, SKL_MODULE_TYPE_BASE_OUTFMT, SKL_MODULE_TYPE_KPB, + SKL_MODULE_TYPE_MIC_SELECT, }; enum skl_core_affinity { From 7a1b749b34e8238acae8a039a8f6822f4f4e2061 Mon Sep 17 00:00:00 2001 From: Dharageswari R Date: Wed, 31 May 2017 10:30:25 +0530 Subject: [PATCH 173/418] ASoC: Intel: Skylake: Add enum control for mic selection User may prefer to select data from particular mics. A mic-select module in DSP allows this selection. Create possible enum controls to allow user to select a combination of mics to capture data from. Based on the user selection, parameters are generated and passed to mic-select module during init. Signed-off-by: Dharageswari R Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 159 +++++++++++++++++++ sound/soc/intel/skylake/skl-topology.h | 20 +++ sound/soc/intel/skylake/skl-tplg-interface.h | 1 + 3 files changed, 180 insertions(+) diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 4c3bdff092bd..212cee71d586 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -36,6 +36,19 @@ #define SKL_IN_DIR_BIT_MASK BIT(0) #define SKL_PIN_COUNT_MASK GENMASK(7, 4) +static const int mic_mono_list[] = { +0, 1, 2, 3, +}; +static const int mic_stereo_list[][SKL_CH_STEREO] = { +{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}, +}; +static const int mic_trio_list[][SKL_CH_TRIO] = { +{0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3}, +}; +static const int mic_quatro_list[][SKL_CH_QUATRO] = { +{0, 1, 2, 3}, +}; + void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps) { struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3; @@ -1314,6 +1327,111 @@ static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, return 0; } +static int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); + struct skl_module_cfg *mconfig = w->priv; + struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; + u32 ch_type = *((u32 *)ec->dobj.private); + + if (mconfig->dmic_ch_type == ch_type) + ucontrol->value.enumerated.item[0] = + mconfig->dmic_ch_combo_index; + else + ucontrol->value.enumerated.item[0] = 0; + + return 0; +} + +static int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig, + struct skl_mic_sel_config *mic_cfg, struct device *dev) +{ + struct skl_specific_cfg *sp_cfg = &mconfig->formats_config; + + sp_cfg->caps_size = sizeof(struct skl_mic_sel_config); + sp_cfg->set_params = SKL_PARAM_SET; + sp_cfg->param_id = 0x00; + if (!sp_cfg->caps) { + sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL); + if (!sp_cfg->caps) + return -ENOMEM; + } + + mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH; + mic_cfg->flags = 0; + memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size); + + return 0; +} + +static int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); + struct skl_module_cfg *mconfig = w->priv; + struct skl_mic_sel_config mic_cfg = {0}; + struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; + u32 ch_type = *((u32 *)ec->dobj.private); + const int *list; + u8 in_ch, out_ch, index; + + mconfig->dmic_ch_type = ch_type; + mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0]; + + /* enum control index 0 is INVALID, so no channels to be set */ + if (mconfig->dmic_ch_combo_index == 0) + return 0; + + /* No valid channel selection map for index 0, so offset by 1 */ + index = mconfig->dmic_ch_combo_index - 1; + + switch (ch_type) { + case SKL_CH_MONO: + if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list)) + return -EINVAL; + + list = &mic_mono_list[index]; + break; + + case SKL_CH_STEREO: + if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list)) + return -EINVAL; + + list = mic_stereo_list[index]; + break; + + case SKL_CH_TRIO: + if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list)) + return -EINVAL; + + list = mic_trio_list[index]; + break; + + case SKL_CH_QUATRO: + if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list)) + return -EINVAL; + + list = mic_quatro_list[index]; + break; + + default: + dev_err(w->dapm->dev, + "Invalid channel %d for mic_select module\n", + ch_type); + return -EINVAL; + + } + + /* channel type enum map to number of chanels for that type */ + for (out_ch = 0; out_ch < ch_type; out_ch++) { + in_ch = list[out_ch]; + mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN; + } + + return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev); +} + /* * Fill the dma id for host and link. In case of passthrough * pipeline, this will both host and link in the same @@ -1666,6 +1784,14 @@ static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = { skl_tplg_tlv_control_set}, }; +static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = { + { + .id = SKL_CONTROL_TYPE_MIC_SELECT, + .get = skl_tplg_mic_control_get, + .put = skl_tplg_mic_control_set, + }, +}; + static int skl_tplg_fill_pipe_tkn(struct device *dev, struct skl_pipe *pipe, u32 tkn, u32 tkn_val) @@ -2390,14 +2516,34 @@ static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, return 0; } +static int skl_init_enum_data(struct device *dev, struct soc_enum *se, + struct snd_soc_tplg_enum_control *ec) +{ + + void *data; + + if (ec->priv.size) { + data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL); + if (!data) + return -ENOMEM; + memcpy(data, ec->priv.data, ec->priv.size); + se->dobj.private = data; + } + + return 0; + +} + static int skl_tplg_control_load(struct snd_soc_component *cmpnt, struct snd_kcontrol_new *kctl, struct snd_soc_tplg_ctl_hdr *hdr) { struct soc_bytes_ext *sb; struct snd_soc_tplg_bytes_control *tplg_bc; + struct snd_soc_tplg_enum_control *tplg_ec; struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); struct hdac_bus *bus = ebus_to_hbus(ebus); + struct soc_enum *se; switch (hdr->ops.info) { case SND_SOC_TPLG_CTL_BYTES: @@ -2411,6 +2557,17 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt, } break; + case SND_SOC_TPLG_CTL_ENUM: + tplg_ec = container_of(hdr, + struct snd_soc_tplg_enum_control, hdr); + if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READWRITE) { + se = (struct soc_enum *)kctl->private_value; + if (tplg_ec->priv.size) + return skl_init_enum_data(bus->dev, se, + tplg_ec); + } + break; + default: dev_warn(bus->dev, "Control load not supported %d:%d:%d\n", hdr->ops.get, hdr->ops.put, hdr->ops.info); @@ -2639,6 +2796,8 @@ static struct snd_soc_tplg_ops skl_tplg_ops = { .control_load = skl_tplg_control_load, .bytes_ext_ops = skl_tlv_ops, .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops), + .io_ops = skl_tplg_kcontrol_ops, + .io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops), .manifest = skl_manifest_load, }; diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index cc64d6bdb4f6..3f51a0a00093 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -39,6 +39,11 @@ #define MODULE_MAX_IN_PINS 8 #define MODULE_MAX_OUT_PINS 8 +#define SKL_MIC_CH_SUPPORT 4 +#define SKL_MIC_MAX_CH_SUPPORT 8 +#define SKL_DEFAULT_MIC_SEL_GAIN 0x3FF +#define SKL_MIC_SEL_SWITCH 0x3 + enum skl_channel_index { SKL_CHANNEL_LEFT = 0, SKL_CHANNEL_RIGHT = 1, @@ -309,6 +314,8 @@ struct skl_module_cfg { u8 dev_type; u8 dma_id; u8 time_slot; + u8 dmic_ch_combo_index; + u32 dmic_ch_type; u32 params_fixup; u32 converter; u32 vbus_id; @@ -342,6 +349,19 @@ struct skl_module_deferred_bind { struct list_head node; }; +struct skl_mic_sel_config { + u16 mic_switch; + u16 flags; + u16 blob[SKL_MIC_MAX_CH_SUPPORT][SKL_MIC_MAX_CH_SUPPORT]; +} __packed; + +enum skl_channel { + SKL_CH_MONO = 1, + SKL_CH_STEREO = 2, + SKL_CH_TRIO = 3, + SKL_CH_QUATRO = 4, +}; + static inline struct skl *get_skl_ctx(struct device *dev) { struct hdac_ext_bus *ebus = dev_get_drvdata(dev); diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h index c22517bd2161..f8d1749a2e0c 100644 --- a/sound/soc/intel/skylake/skl-tplg-interface.h +++ b/sound/soc/intel/skylake/skl-tplg-interface.h @@ -24,6 +24,7 @@ * SST types start at higher to avoid any overlapping in future */ #define SKL_CONTROL_TYPE_BYTE_TLV 0x100 +#define SKL_CONTROL_TYPE_MIC_SELECT 0x102 #define HDA_SST_CFG_MAX 900 /* size of copier cfg*/ #define MAX_IN_QUEUE 8 From e8883cb61aa0a91980222e5e9d114100783eb7e2 Mon Sep 17 00:00:00 2001 From: Dharageswari R Date: Wed, 31 May 2017 10:30:26 +0530 Subject: [PATCH 174/418] ASoC: Intel: Boards: Add 4-channel DMIC fixup. This patch adds a 4-channel dmic fixup so that DMIC copier will receive 4 channel data and further selection will be done by mic-select module. Signed-off-by: Dharageswari R Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_rt298.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 1a68d043c803..36ee7480e9f1 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -222,16 +222,13 @@ static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd, { struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - if (params_channels(params) == 2) - channels->min = channels->max = 2; - else - channels->min = channels->max = 4; + channels->min = channels->max = 4; return 0; } static unsigned int channels_dmic[] = { - 2, 4, + 1, 2, 3, 4, }; static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { From 875becf8412c60ffae93c5f69e95a4d023f0e8ee Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 7 Jun 2017 09:38:05 +0900 Subject: [PATCH 175/418] ALSA: firewire: process packets in 'struct snd_pcm_ops.ack' callback In recent commit for ALSA PCM core, some arrangement is done for 'struct snd_pcm_ops.ack' callback. This is called when appl_ptr is explicitly moved in intermediate buffer for PCM frames, except for some cases described later. For drivers in ALSA firewire stack, usage of this callback has a merit to reduce latency between time of PCM frame queueing and handling actual packets in recent isochronous cycle, because no need to wait for software IRQ context from isochronous context of OHCI 1394. If this works well in a case that mapped page frame is used for the intermediate buffer, user process should execute some commands for ioctl(2) to tell the number of handled PCM frames in the intermediate buffer just after handling them. Therefore, at present, with a combination of below conditions, this doesn't work as expected and user process should wait for the software IRQ context as usual: - when ALSA PCM core judges page frame mapping is available for status data (struct snd_pcm_mmap_status) and control data (struct snd_pcm_mmap_control). - user process handles PCM frames by loop just with 'snd_pcm_mmap_begin()' and 'snd_pcm_mmap_commit()'. - user process uses PCM hw plugin in alsa-lib to operate I/O without 'sync_ptr_ioctl' option. Unfortunately, major use case include these three conditions. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 19 +++++++++++++++++++ sound/firewire/amdtp-stream.h | 1 + sound/firewire/bebob/bebob_pcm.c | 16 ++++++++++++++++ sound/firewire/dice/dice-pcm.c | 18 ++++++++++++++++++ sound/firewire/digi00x/digi00x-pcm.c | 16 ++++++++++++++++ sound/firewire/fireface/ff-pcm.c | 16 ++++++++++++++++ sound/firewire/fireworks/fireworks_pcm.c | 16 ++++++++++++++++ sound/firewire/motu/motu-pcm.c | 16 ++++++++++++++++ sound/firewire/oxfw/oxfw-pcm.c | 16 ++++++++++++++++ sound/firewire/tascam/tascam-pcm.c | 16 ++++++++++++++++ 10 files changed, 150 insertions(+) diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 9e6f54f8c45d..4316d9db404d 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -928,6 +928,25 @@ unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s) } EXPORT_SYMBOL(amdtp_stream_pcm_pointer); +/** + * amdtp_stream_pcm_ack - acknowledge queued PCM frames + * @s: the AMDTP stream that transfers the PCM frames + * + * Returns zero always. + */ +int amdtp_stream_pcm_ack(struct amdtp_stream *s) +{ + /* + * Process isochronous packets for recent isochronous cycle to handle + * queued PCM frames. + */ + if (amdtp_stream_running(s)) + fw_iso_context_flush_completions(s->context); + + return 0; +} +EXPORT_SYMBOL(amdtp_stream_pcm_ack); + /** * amdtp_stream_update - update the stream after a bus reset * @s: the AMDTP stream diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 7e8831722821..6d613f2eb612 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -168,6 +168,7 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s, void amdtp_stream_pcm_prepare(struct amdtp_stream *s); unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s); +int amdtp_stream_pcm_ack(struct amdtp_stream *s); void amdtp_stream_pcm_abort(struct amdtp_stream *s); extern const unsigned int amdtp_syt_intervals[CIP_SFC_COUNT]; diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index e2f023f3cd9f..657e15a27e5c 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -355,6 +355,20 @@ pcm_playback_pointer(struct snd_pcm_substream *sbstrm) return amdtp_stream_pcm_pointer(&bebob->rx_stream); } +static int pcm_capture_ack(struct snd_pcm_substream *substream) +{ + struct snd_bebob *bebob = substream->private_data; + + return amdtp_stream_pcm_ack(&bebob->tx_stream); +} + +static int pcm_playback_ack(struct snd_pcm_substream *substream) +{ + struct snd_bebob *bebob = substream->private_data; + + return amdtp_stream_pcm_ack(&bebob->rx_stream); +} + int snd_bebob_create_pcm_devices(struct snd_bebob *bebob) { static const struct snd_pcm_ops capture_ops = { @@ -366,6 +380,7 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob) .prepare = pcm_capture_prepare, .trigger = pcm_capture_trigger, .pointer = pcm_capture_pointer, + .ack = pcm_capture_ack, .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops playback_ops = { @@ -377,6 +392,7 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob) .prepare = pcm_playback_prepare, .trigger = pcm_playback_trigger, .pointer = pcm_playback_pointer, + .ack = pcm_playback_ack, .page = snd_pcm_lib_get_vmalloc_page, .mmap = snd_pcm_lib_mmap_vmalloc, }; diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index b633805a885f..2dda74695069 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -294,6 +294,22 @@ static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream) return amdtp_stream_pcm_pointer(stream); } +static int capture_ack(struct snd_pcm_substream *substream) +{ + struct snd_dice *dice = substream->private_data; + struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; + + return amdtp_stream_pcm_ack(stream); +} + +static int playback_ack(struct snd_pcm_substream *substream) +{ + struct snd_dice *dice = substream->private_data; + struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; + + return amdtp_stream_pcm_ack(stream); +} + int snd_dice_create_pcm(struct snd_dice *dice) { static const struct snd_pcm_ops capture_ops = { @@ -305,6 +321,7 @@ int snd_dice_create_pcm(struct snd_dice *dice) .prepare = capture_prepare, .trigger = capture_trigger, .pointer = capture_pointer, + .ack = capture_ack, .page = snd_pcm_lib_get_vmalloc_page, .mmap = snd_pcm_lib_mmap_vmalloc, }; @@ -317,6 +334,7 @@ int snd_dice_create_pcm(struct snd_dice *dice) .prepare = playback_prepare, .trigger = playback_trigger, .pointer = playback_pointer, + .ack = playback_ack, .page = snd_pcm_lib_get_vmalloc_page, .mmap = snd_pcm_lib_mmap_vmalloc, }; diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c index 6379f67416d7..f76cf5e383db 100644 --- a/sound/firewire/digi00x/digi00x-pcm.c +++ b/sound/firewire/digi00x/digi00x-pcm.c @@ -324,6 +324,20 @@ static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) return amdtp_stream_pcm_pointer(&dg00x->rx_stream); } +static int pcm_capture_ack(struct snd_pcm_substream *substream) +{ + struct snd_dg00x *dg00x = substream->private_data; + + return amdtp_stream_pcm_ack(&dg00x->tx_stream); +} + +static int pcm_playback_ack(struct snd_pcm_substream *substream) +{ + struct snd_dg00x *dg00x = substream->private_data; + + return amdtp_stream_pcm_ack(&dg00x->rx_stream); +} + int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x) { static const struct snd_pcm_ops capture_ops = { @@ -335,6 +349,7 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x) .prepare = pcm_capture_prepare, .trigger = pcm_capture_trigger, .pointer = pcm_capture_pointer, + .ack = pcm_capture_ack, .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops playback_ops = { @@ -346,6 +361,7 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x) .prepare = pcm_playback_prepare, .trigger = pcm_playback_trigger, .pointer = pcm_playback_pointer, + .ack = pcm_playback_ack, .page = snd_pcm_lib_get_vmalloc_page, .mmap = snd_pcm_lib_mmap_vmalloc, }; diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c index 93cee1978e8e..adb5c87f492f 100644 --- a/sound/firewire/fireface/ff-pcm.c +++ b/sound/firewire/fireface/ff-pcm.c @@ -365,6 +365,20 @@ static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) return amdtp_stream_pcm_pointer(&ff->rx_stream); } +static int pcm_capture_ack(struct snd_pcm_substream *substream) +{ + struct snd_ff *ff = substream->private_data; + + return amdtp_stream_pcm_ack(&ff->tx_stream); +} + +static int pcm_playback_ack(struct snd_pcm_substream *substream) +{ + struct snd_ff *ff = substream->private_data; + + return amdtp_stream_pcm_ack(&ff->rx_stream); +} + static struct snd_pcm_ops pcm_capture_ops = { .open = pcm_open, .close = pcm_close, @@ -374,6 +388,7 @@ static struct snd_pcm_ops pcm_capture_ops = { .prepare = pcm_capture_prepare, .trigger = pcm_capture_trigger, .pointer = pcm_capture_pointer, + .ack = pcm_capture_ack, .page = snd_pcm_lib_get_vmalloc_page, }; @@ -386,6 +401,7 @@ static struct snd_pcm_ops pcm_playback_ops = { .prepare = pcm_playback_prepare, .trigger = pcm_playback_trigger, .pointer = pcm_playback_pointer, + .ack = pcm_playback_ack, .page = snd_pcm_lib_get_vmalloc_page, .mmap = snd_pcm_lib_mmap_vmalloc, }; diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index f10aec117998..346e2647ed1f 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -379,6 +379,20 @@ static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) return amdtp_stream_pcm_pointer(&efw->rx_stream); } +static int pcm_capture_ack(struct snd_pcm_substream *substream) +{ + struct snd_efw *efw = substream->private_data; + + return amdtp_stream_pcm_ack(&efw->tx_stream); +} + +static int pcm_playback_ack(struct snd_pcm_substream *substream) +{ + struct snd_efw *efw = substream->private_data; + + return amdtp_stream_pcm_ack(&efw->rx_stream); +} + int snd_efw_create_pcm_devices(struct snd_efw *efw) { static const struct snd_pcm_ops capture_ops = { @@ -390,6 +404,7 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw) .prepare = pcm_capture_prepare, .trigger = pcm_capture_trigger, .pointer = pcm_capture_pointer, + .ack = pcm_capture_ack, .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops playback_ops = { @@ -401,6 +416,7 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw) .prepare = pcm_playback_prepare, .trigger = pcm_playback_trigger, .pointer = pcm_playback_pointer, + .ack = pcm_playback_ack, .page = snd_pcm_lib_get_vmalloc_page, .mmap = snd_pcm_lib_mmap_vmalloc, }; diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c index 94558f3d218b..e3ef89cee565 100644 --- a/sound/firewire/motu/motu-pcm.c +++ b/sound/firewire/motu/motu-pcm.c @@ -356,6 +356,20 @@ static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream) return amdtp_stream_pcm_pointer(&motu->rx_stream); } +static int capture_ack(struct snd_pcm_substream *substream) +{ + struct snd_motu *motu = substream->private_data; + + return amdtp_stream_pcm_ack(&motu->tx_stream); +} + +static int playback_ack(struct snd_pcm_substream *substream) +{ + struct snd_motu *motu = substream->private_data; + + return amdtp_stream_pcm_ack(&motu->rx_stream); +} + int snd_motu_create_pcm_devices(struct snd_motu *motu) { static struct snd_pcm_ops capture_ops = { @@ -367,6 +381,7 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu) .prepare = capture_prepare, .trigger = capture_trigger, .pointer = capture_pointer, + .ack = capture_ack, .page = snd_pcm_lib_get_vmalloc_page, .mmap = snd_pcm_lib_mmap_vmalloc, }; @@ -379,6 +394,7 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu) .prepare = playback_prepare, .trigger = playback_trigger, .pointer = playback_pointer, + .ack = playback_ack, .page = snd_pcm_lib_get_vmalloc_page, .mmap = snd_pcm_lib_mmap_vmalloc, }; diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index d4594f7115ae..bc1a3a36ab06 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -382,6 +382,20 @@ static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstm) return amdtp_stream_pcm_pointer(&oxfw->rx_stream); } +static int pcm_capture_ack(struct snd_pcm_substream *substream) +{ + struct snd_oxfw *oxfw = substream->private_data; + + return amdtp_stream_pcm_ack(&oxfw->tx_stream); +} + +static int pcm_playback_ack(struct snd_pcm_substream *substream) +{ + struct snd_oxfw *oxfw = substream->private_data; + + return amdtp_stream_pcm_ack(&oxfw->rx_stream); +} + int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) { static const struct snd_pcm_ops capture_ops = { @@ -393,6 +407,7 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) .prepare = pcm_capture_prepare, .trigger = pcm_capture_trigger, .pointer = pcm_capture_pointer, + .ack = pcm_capture_ack, .page = snd_pcm_lib_get_vmalloc_page, .mmap = snd_pcm_lib_mmap_vmalloc, }; @@ -405,6 +420,7 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) .prepare = pcm_playback_prepare, .trigger = pcm_playback_trigger, .pointer = pcm_playback_pointer, + .ack = pcm_playback_ack, .page = snd_pcm_lib_get_vmalloc_page, .mmap = snd_pcm_lib_mmap_vmalloc, }; diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c index 6207588d7c73..3c4482aa7231 100644 --- a/sound/firewire/tascam/tascam-pcm.c +++ b/sound/firewire/tascam/tascam-pcm.c @@ -263,6 +263,20 @@ static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) return amdtp_stream_pcm_pointer(&tscm->rx_stream); } +static int pcm_capture_ack(struct snd_pcm_substream *substream) +{ + struct snd_tscm *tscm = substream->private_data; + + return amdtp_stream_pcm_ack(&tscm->tx_stream); +} + +static int pcm_playback_ack(struct snd_pcm_substream *substream) +{ + struct snd_tscm *tscm = substream->private_data; + + return amdtp_stream_pcm_ack(&tscm->rx_stream); +} + int snd_tscm_create_pcm_devices(struct snd_tscm *tscm) { static const struct snd_pcm_ops capture_ops = { @@ -274,6 +288,7 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm) .prepare = pcm_capture_prepare, .trigger = pcm_capture_trigger, .pointer = pcm_capture_pointer, + .ack = pcm_capture_ack, .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops playback_ops = { @@ -285,6 +300,7 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm) .prepare = pcm_playback_prepare, .trigger = pcm_playback_trigger, .pointer = pcm_playback_pointer, + .ack = pcm_playback_ack, .page = snd_pcm_lib_get_vmalloc_page, .mmap = snd_pcm_lib_mmap_vmalloc, }; From d2dc2a96de9d58038ac1f9ee432e88a70958d59b Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 7 Jun 2017 09:38:06 +0900 Subject: [PATCH 176/418] ALSA: fireface: constify ALSA specific operations ALSA fireface driver has ALSA specific operations for MIDI/PCM data. Structured data for the operations can be constified. Additionally, The structured data can be function local. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-midi.c | 22 ++++++------- sound/firewire/fireface/ff-pcm.c | 52 +++++++++++++++---------------- 2 files changed, 35 insertions(+), 39 deletions(-) diff --git a/sound/firewire/fireface/ff-midi.c b/sound/firewire/fireface/ff-midi.c index 29ee0a7365c3..949ee56b4e0e 100644 --- a/sound/firewire/fireface/ff-midi.c +++ b/sound/firewire/fireface/ff-midi.c @@ -74,18 +74,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substream, spin_unlock_irqrestore(&ff->lock, flags); } -static struct snd_rawmidi_ops midi_capture_ops = { - .open = midi_capture_open, - .close = midi_capture_close, - .trigger = midi_capture_trigger, -}; - -static struct snd_rawmidi_ops midi_playback_ops = { - .open = midi_playback_open, - .close = midi_playback_close, - .trigger = midi_playback_trigger, -}; - static void set_midi_substream_names(struct snd_rawmidi_str *stream, const char *const name) { @@ -99,6 +87,16 @@ static void set_midi_substream_names(struct snd_rawmidi_str *stream, int snd_ff_create_midi_devices(struct snd_ff *ff) { + static const struct snd_rawmidi_ops midi_capture_ops = { + .open = midi_capture_open, + .close = midi_capture_close, + .trigger = midi_capture_trigger, + }; + static const struct snd_rawmidi_ops midi_playback_ops = { + .open = midi_playback_open, + .close = midi_playback_close, + .trigger = midi_playback_trigger, + }; struct snd_rawmidi *rmidi; struct snd_rawmidi_str *stream; int err; diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c index adb5c87f492f..ad974b5a2561 100644 --- a/sound/firewire/fireface/ff-pcm.c +++ b/sound/firewire/fireface/ff-pcm.c @@ -379,35 +379,33 @@ static int pcm_playback_ack(struct snd_pcm_substream *substream) return amdtp_stream_pcm_ack(&ff->rx_stream); } -static struct snd_pcm_ops pcm_capture_ops = { - .open = pcm_open, - .close = pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = pcm_capture_hw_params, - .hw_free = pcm_capture_hw_free, - .prepare = pcm_capture_prepare, - .trigger = pcm_capture_trigger, - .pointer = pcm_capture_pointer, - .ack = pcm_capture_ack, - .page = snd_pcm_lib_get_vmalloc_page, -}; - -static struct snd_pcm_ops pcm_playback_ops = { - .open = pcm_open, - .close = pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = pcm_playback_hw_params, - .hw_free = pcm_playback_hw_free, - .prepare = pcm_playback_prepare, - .trigger = pcm_playback_trigger, - .pointer = pcm_playback_pointer, - .ack = pcm_playback_ack, - .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, -}; - int snd_ff_create_pcm_devices(struct snd_ff *ff) { + static const struct snd_pcm_ops pcm_capture_ops = { + .open = pcm_open, + .close = pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = pcm_capture_hw_params, + .hw_free = pcm_capture_hw_free, + .prepare = pcm_capture_prepare, + .trigger = pcm_capture_trigger, + .pointer = pcm_capture_pointer, + .ack = pcm_capture_ack, + .page = snd_pcm_lib_get_vmalloc_page, + }; + static const struct snd_pcm_ops pcm_playback_ops = { + .open = pcm_open, + .close = pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = pcm_playback_hw_params, + .hw_free = pcm_playback_hw_free, + .prepare = pcm_playback_prepare, + .trigger = pcm_playback_trigger, + .pointer = pcm_playback_pointer, + .ack = pcm_playback_ack, + .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, + }; struct snd_pcm *pcm; int err; From 890e2cb5d184629702a2c1a1e9631f9f64523c65 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 2 Jun 2017 17:16:59 +0200 Subject: [PATCH 177/418] ALSA: timer: Improve user queue reallocation ALSA timer may reallocate the user queue upon request, and it happens at three places for now: at opening, at SNDRV_TIMER_IOCTL_PARAMS, and at SNDRV_TIMER_IOCTL_SELECT. However, the last one, snd_timer_user_tselect(), doesn't need to reallocate the buffer since it doesn't change the queue size. It does just because tu->tread might have been changed before starting the timer. Instead of *_SELECT ioctl, we should reallocate the queue at SNDRV_TIMER_IOCTL_TREAD; then the timer is guaranteed to be stopped, thus we can reassign the buffer more safely. This patch implements that with a slight code refactoring. Essentially, the patch achieves: - Introduce realloc_user_queue() for (re-)allocating the ring buffer, and call it from all places. Also, realloc_user_queue() uses kcalloc() for avoiding possible leaks. - Add the buffer reallocation at SNDRV_TIMER_IOCTL_TREAD. When it fails, tu->tread is restored to the old value, too. - Drop the buffer reallocation at snd_timer_user_tselect(). Tested-by: Alexander Potapenko Signed-off-by: Takashi Iwai --- sound/core/timer.c | 94 +++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 51 deletions(-) diff --git a/sound/core/timer.c b/sound/core/timer.c index cd67d1c12cf1..96cffb1be57f 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1327,6 +1327,33 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, wake_up(&tu->qchange_sleep); } +static int realloc_user_queue(struct snd_timer_user *tu, int size) +{ + struct snd_timer_read *queue = NULL; + struct snd_timer_tread *tqueue = NULL; + + if (tu->tread) { + tqueue = kcalloc(size, sizeof(*tqueue), GFP_KERNEL); + if (!tqueue) + return -ENOMEM; + } else { + queue = kcalloc(size, sizeof(*queue), GFP_KERNEL); + if (!queue) + return -ENOMEM; + } + + spin_lock_irq(&tu->qlock); + kfree(tu->queue); + kfree(tu->tqueue); + tu->queue_size = size; + tu->queue = queue; + tu->tqueue = tqueue; + tu->qhead = tu->qtail = tu->qused = 0; + spin_unlock_irq(&tu->qlock); + + return 0; +} + static int snd_timer_user_open(struct inode *inode, struct file *file) { struct snd_timer_user *tu; @@ -1343,10 +1370,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file) init_waitqueue_head(&tu->qchange_sleep); mutex_init(&tu->ioctl_lock); tu->ticks = 1; - tu->queue_size = 128; - tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), - GFP_KERNEL); - if (tu->queue == NULL) { + if (realloc_user_queue(tu, 128) < 0) { kfree(tu); return -ENOMEM; } @@ -1618,34 +1642,12 @@ static int snd_timer_user_tselect(struct file *file, if (err < 0) goto __err; - tu->qhead = tu->qtail = tu->qused = 0; - kfree(tu->queue); - tu->queue = NULL; - kfree(tu->tqueue); - tu->tqueue = NULL; - if (tu->tread) { - tu->tqueue = kmalloc(tu->queue_size * sizeof(struct snd_timer_tread), - GFP_KERNEL); - if (tu->tqueue == NULL) - err = -ENOMEM; - } else { - tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), - GFP_KERNEL); - if (tu->queue == NULL) - err = -ENOMEM; - } - - if (err < 0) { - snd_timer_close(tu->timeri); - tu->timeri = NULL; - } else { - tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; - tu->timeri->callback = tu->tread + tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; + tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt; - tu->timeri->ccallback = snd_timer_user_ccallback; - tu->timeri->callback_data = (void *)tu; - tu->timeri->disconnect = snd_timer_user_disconnect; - } + tu->timeri->ccallback = snd_timer_user_ccallback; + tu->timeri->callback_data = (void *)tu; + tu->timeri->disconnect = snd_timer_user_disconnect; __err: return err; @@ -1687,8 +1689,6 @@ static int snd_timer_user_params(struct file *file, struct snd_timer_user *tu; struct snd_timer_params params; struct snd_timer *t; - struct snd_timer_read *tr; - struct snd_timer_tread *ttr; int err; tu = file->private_data; @@ -1751,23 +1751,9 @@ static int snd_timer_user_params(struct file *file, spin_unlock_irq(&t->lock); if (params.queue_size > 0 && (unsigned int)tu->queue_size != params.queue_size) { - if (tu->tread) { - ttr = kmalloc(params.queue_size * sizeof(*ttr), - GFP_KERNEL); - if (ttr) { - kfree(tu->tqueue); - tu->queue_size = params.queue_size; - tu->tqueue = ttr; - } - } else { - tr = kmalloc(params.queue_size * sizeof(*tr), - GFP_KERNEL); - if (tr) { - kfree(tu->queue); - tu->queue_size = params.queue_size; - tu->queue = tr; - } - } + err = realloc_user_queue(tu, params.queue_size); + if (err < 0) + goto _end; } tu->qhead = tu->qtail = tu->qused = 0; if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) { @@ -1891,13 +1877,19 @@ static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd, return snd_timer_user_next_device(argp); case SNDRV_TIMER_IOCTL_TREAD: { - int xarg; + int xarg, old_tread; if (tu->timeri) /* too late */ return -EBUSY; if (get_user(xarg, p)) return -EFAULT; + old_tread = tu->tread; tu->tread = xarg ? 1 : 0; + if (tu->tread != old_tread && + realloc_user_queue(tu, tu->queue_size) < 0) { + tu->tread = old_tread; + return -ENOMEM; + } return 0; } case SNDRV_TIMER_IOCTL_GINFO: From d7f910bfedd863d13ea320030fe98e42d0938ed5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 2 Jun 2017 17:35:30 +0200 Subject: [PATCH 178/418] ALSA: timer: Wrap with spinlock for queue access For accessing the snd_timer_user queue indices, we take tu->qlock. But it's forgotten in a couple of places. The one in snd_timer_user_params() should be safe without the spinlock as the timer is already stopped. But it's better for consistency. The one in poll is just a read-out, so it's not inevitably needed, but it'd be good to make the result consistent, too. Tested-by: Alexander Potapenko Signed-off-by: Takashi Iwai --- sound/core/timer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/core/timer.c b/sound/core/timer.c index 96cffb1be57f..148290ace756 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1755,6 +1755,7 @@ static int snd_timer_user_params(struct file *file, if (err < 0) goto _end; } + spin_lock_irq(&tu->qlock); tu->qhead = tu->qtail = tu->qused = 0; if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) { if (tu->tread) { @@ -1775,6 +1776,7 @@ static int snd_timer_user_params(struct file *file, } tu->filter = params.filter; tu->ticks = params.ticks; + spin_unlock_irq(&tu->qlock); err = 0; _end: if (copy_to_user(_params, ¶ms, sizeof(params))) @@ -2022,10 +2024,12 @@ static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait) poll_wait(file, &tu->qchange_sleep, wait); mask = 0; + spin_lock_irq(&tu->qlock); if (tu->qused) mask |= POLLIN | POLLRDNORM; if (tu->disconnected) mask |= POLLERR; + spin_unlock_irq(&tu->qlock); return mask; } From be4e31dab0e14c1f6fa5c03b33056058b93316e2 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 7 Jun 2017 08:46:43 +0900 Subject: [PATCH 179/418] ALSA: pcm: tracepoints for refining PCM parameters When working for devices which support configurable modes for its data transmission or which consists of several components, developers are likely to use rules of parameters of PCM substream. However, there's no infrastructure to assist their work. In old days, ALSA PCM core got a local 'RULES_DEBUG' macro to debug refinement of parameters for PCM substream. Although this is merely a makeshift. With some modifications, we get the infrastructure. This commit is for the purpose. Refinement of mask/interval type of PCM parameters is probed as tracepoint events as 'hw_mask_param' and 'hw_interval_param' on existent 'snd_pcm' subsystem. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/Makefile | 1 + sound/core/pcm_native.c | 33 ++++++++ sound/core/pcm_param_trace.h | 142 +++++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 sound/core/pcm_param_trace.h diff --git a/sound/core/Makefile b/sound/core/Makefile index e85d9dd12c2d..a8514b313a89 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -22,6 +22,7 @@ snd-pcm-$(CONFIG_SND_PCM_IEC958) += pcm_iec958.o # for trace-points CFLAGS_pcm_lib.o := -I$(src) +CFLAGS_pcm_native.o := -I$(src) snd-pcm-dmaengine-objs := pcm_dmaengine.o diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index bf5d0f2acfb9..b98b3ccde4f0 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -39,6 +39,9 @@ #include "pcm_local.h" +#define CREATE_TRACE_POINTS +#include "pcm_param_trace.h" + /* * Compatibility */ @@ -279,6 +282,9 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, unsigned int stamp = 2; int changed, again; + struct snd_mask __maybe_unused old_mask; + struct snd_interval __maybe_unused old_interval; + params->info = 0; params->fifo_size = 0; if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS)) @@ -294,6 +300,9 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, return -EINVAL; if (!(params->rmask & (1 << k))) continue; + + if (trace_hw_mask_param_enabled()) + old_mask = *m; #ifdef RULES_DEBUG pr_debug("%s = ", snd_pcm_hw_param_names[k]); pr_cont("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]); @@ -302,6 +311,8 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, #ifdef RULES_DEBUG pr_cont("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]); #endif + trace_hw_mask_param(substream, k, 0, &old_mask, m); + if (changed) params->cmask |= 1 << k; if (changed < 0) @@ -314,6 +325,9 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, return -EINVAL; if (!(params->rmask & (1 << k))) continue; + + if (trace_hw_interval_param_enabled()) + old_interval = *i; #ifdef RULES_DEBUG pr_debug("%s = ", snd_pcm_hw_param_names[k]); if (i->empty) @@ -333,6 +347,8 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, i->openmin ? '(' : '[', i->min, i->max, i->openmax ? ')' : ']'); #endif + trace_hw_interval_param(substream, k, 0, &old_interval, i); + if (changed) params->cmask |= 1 << k; if (changed < 0) @@ -359,6 +375,15 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, } if (!doit) continue; + + if (trace_hw_mask_param_enabled()) { + if (hw_is_mask(r->var)) + old_mask = *hw_param_mask(params, r->var); + } + if (trace_hw_interval_param_enabled()) { + if (hw_is_interval(r->var)) + old_interval = *hw_param_interval(params, r->var); + } #ifdef RULES_DEBUG pr_debug("Rule %d [%p]: ", k, r->func); if (r->var >= 0) { @@ -394,6 +419,14 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, } pr_cont("\n"); #endif + if (hw_is_mask(r->var)) { + trace_hw_mask_param(substream, r->var, k + 1, + &old_mask, hw_param_mask(params, r->var)); + } + if (hw_is_interval(r->var)) { + trace_hw_interval_param(substream, r->var, k + 1, + &old_interval, hw_param_interval(params, r->var)); + } rstamps[k] = stamp; if (changed && r->var >= 0) { params->cmask |= (1 << r->var); diff --git a/sound/core/pcm_param_trace.h b/sound/core/pcm_param_trace.h new file mode 100644 index 000000000000..872922326b38 --- /dev/null +++ b/sound/core/pcm_param_trace.h @@ -0,0 +1,142 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM snd_pcm + +#if !defined(_PCM_PARAMS_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _PCM_PARAMS_TRACE_H + +#include + +#define HW_PARAM_ENTRY(param) {SNDRV_PCM_HW_PARAM_##param, #param} +#define hw_param_labels \ + HW_PARAM_ENTRY(ACCESS), \ + HW_PARAM_ENTRY(FORMAT), \ + HW_PARAM_ENTRY(SUBFORMAT), \ + HW_PARAM_ENTRY(SAMPLE_BITS), \ + HW_PARAM_ENTRY(FRAME_BITS), \ + HW_PARAM_ENTRY(CHANNELS), \ + HW_PARAM_ENTRY(RATE), \ + HW_PARAM_ENTRY(PERIOD_TIME), \ + HW_PARAM_ENTRY(PERIOD_SIZE), \ + HW_PARAM_ENTRY(PERIOD_BYTES), \ + HW_PARAM_ENTRY(PERIODS), \ + HW_PARAM_ENTRY(BUFFER_TIME), \ + HW_PARAM_ENTRY(BUFFER_SIZE), \ + HW_PARAM_ENTRY(BUFFER_BYTES), \ + HW_PARAM_ENTRY(TICK_TIME) + +TRACE_EVENT(hw_mask_param, + TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_hw_param_t type, int index, const struct snd_mask *prev, const struct snd_mask *curr), + TP_ARGS(substream, type, index, prev, curr), + TP_STRUCT__entry( + __field(int, card) + __field(int, device) + __field(int, subdevice) + __field(int, direction) + __field(snd_pcm_hw_param_t, type) + __field(int, index) + __field(int, total) + __array(__u32, prev_bits, 8) + __array(__u32, curr_bits, 8) + ), + TP_fast_assign( + __entry->card = substream->pcm->card->number; + __entry->device = substream->pcm->device; + __entry->subdevice = substream->number; + __entry->direction = substream->stream; + __entry->type = type; + __entry->index = index; + __entry->total = substream->runtime->hw_constraints.rules_num; + memcpy(__entry->prev_bits, prev->bits, sizeof(__u32) * 8); + memcpy(__entry->curr_bits, curr->bits, sizeof(__u32) * 8); + ), + TP_printk("%d,%d,%d,%d %03d/%03d %s %08x%08x%08x%08x %08x%08x%08x%08x", + __entry->card, + __entry->device, + __entry->subdevice, + __entry->direction, + __entry->index, + __entry->total, + __print_symbolic(__entry->type, hw_param_labels), + __entry->prev_bits[3], __entry->prev_bits[2], + __entry->prev_bits[1], __entry->prev_bits[0], + __entry->curr_bits[3], __entry->curr_bits[2], + __entry->curr_bits[1], __entry->curr_bits[0] + ) +); + +TRACE_EVENT(hw_interval_param, + TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_hw_param_t type, int index, const struct snd_interval *prev, const struct snd_interval *curr), + TP_ARGS(substream, type, index, prev, curr), + TP_STRUCT__entry( + __field(int, card) + __field(int, device) + __field(int, subdevice) + __field(int, direction) + __field(snd_pcm_hw_param_t, type) + __field(int, index) + __field(int, total) + __field(unsigned int, prev_min) + __field(unsigned int, prev_max) + __field(unsigned int, prev_openmin) + __field(unsigned int, prev_openmax) + __field(unsigned int, prev_integer) + __field(unsigned int, prev_empty) + __field(unsigned int, curr_min) + __field(unsigned int, curr_max) + __field(unsigned int, curr_openmin) + __field(unsigned int, curr_openmax) + __field(unsigned int, curr_integer) + __field(unsigned int, curr_empty) + ), + TP_fast_assign( + __entry->card = substream->pcm->card->number; + __entry->device = substream->pcm->device; + __entry->subdevice = substream->number; + __entry->direction = substream->stream; + __entry->type = type; + __entry->index = index; + __entry->total = substream->runtime->hw_constraints.rules_num; + __entry->prev_min = prev->min; + __entry->prev_max = prev->max; + __entry->prev_openmin = prev->openmin; + __entry->prev_openmax = prev->openmax; + __entry->prev_integer = prev->integer; + __entry->prev_empty = prev->empty; + __entry->curr_min = curr->min; + __entry->curr_max = curr->max; + __entry->curr_openmin = curr->openmin; + __entry->curr_openmax = curr->openmax; + __entry->curr_integer = curr->integer; + __entry->curr_empty = curr->empty; + ), + TP_printk("%d,%d,%d,%d %03d/%03d %s %d %d %s%u %u%s %d %d %s%u %u%s", + __entry->card, + __entry->device, + __entry->subdevice, + __entry->direction, + __entry->index, + __entry->total, + __print_symbolic(__entry->type, hw_param_labels), + __entry->prev_empty, + __entry->prev_integer, + __entry->prev_openmin ? "(" : "[", + __entry->prev_min, + __entry->prev_max, + __entry->prev_openmax ? ")" : "]", + __entry->curr_empty, + __entry->curr_integer, + __entry->curr_openmin ? "(" : "[", + __entry->curr_min, + __entry->curr_max, + __entry->curr_openmax ? ")" : "]" + ) +); + +#endif /* _PCM_PARAMS_TRACE_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE pcm_param_trace +#include From 37567c55035a3a6c6cdf060301a7d8e514627afa Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 7 Jun 2017 08:46:44 +0900 Subject: [PATCH 180/418] ALSA: pcm: enable parameter tracepoints only when CONFIG_SND_DEBUG is enabled In a previous commit, tracepoints are added for PCM parameter processing. As long as I know, this implementation increases size of relocatable object by 35%. For vendors who are conscious of memory footprint, it brings apparent disadvantage. This commit utilizes CONFIG_SND_DEBUG configuration to enable/disable the tracepoints. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index b98b3ccde4f0..2ce3c98a1418 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -39,8 +39,15 @@ #include "pcm_local.h" +#ifdef CONFIG_SND_DEBUG #define CREATE_TRACE_POINTS #include "pcm_param_trace.h" +#else +#define trace_hw_mask_param_enabled() 0 +#define trace_hw_interval_param_enabled() 0 +#define trace_hw_mask_param(substream, type, index, prev, curr) +#define trace_hw_interval_param(substream, type, index, prev, curr) +#endif /* * Compatibility From c6706de0ce8bc8cd1e336b8cf0acabf1adedba6c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 7 Jun 2017 08:46:45 +0900 Subject: [PATCH 181/418] ALSA: pcm: obsolete RULES_DEBUG local macro Added tracepoints obsoleted RULES_DEBUG local macro and relevant codes. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 89 ++++------------------------------------- 1 file changed, 7 insertions(+), 82 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 2ce3c98a1418..2bde07a4a87f 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -253,29 +253,6 @@ static bool hw_support_mmap(struct snd_pcm_substream *substream) return true; } -#undef RULES_DEBUG - -#ifdef RULES_DEBUG -#define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v -static const char * const snd_pcm_hw_param_names[] = { - HW_PARAM(ACCESS), - HW_PARAM(FORMAT), - HW_PARAM(SUBFORMAT), - HW_PARAM(SAMPLE_BITS), - HW_PARAM(FRAME_BITS), - HW_PARAM(CHANNELS), - HW_PARAM(RATE), - HW_PARAM(PERIOD_TIME), - HW_PARAM(PERIOD_SIZE), - HW_PARAM(PERIOD_BYTES), - HW_PARAM(PERIODS), - HW_PARAM(BUFFER_TIME), - HW_PARAM(BUFFER_SIZE), - HW_PARAM(BUFFER_BYTES), - HW_PARAM(TICK_TIME), -}; -#endif - int snd_pcm_hw_refine(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -310,14 +287,9 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, if (trace_hw_mask_param_enabled()) old_mask = *m; -#ifdef RULES_DEBUG - pr_debug("%s = ", snd_pcm_hw_param_names[k]); - pr_cont("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]); -#endif + changed = snd_mask_refine(m, constrs_mask(constrs, k)); -#ifdef RULES_DEBUG - pr_cont("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]); -#endif + trace_hw_mask_param(substream, k, 0, &old_mask, m); if (changed) @@ -335,25 +307,9 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, if (trace_hw_interval_param_enabled()) old_interval = *i; -#ifdef RULES_DEBUG - pr_debug("%s = ", snd_pcm_hw_param_names[k]); - if (i->empty) - pr_cont("empty"); - else - pr_cont("%c%u %u%c", - i->openmin ? '(' : '[', i->min, - i->max, i->openmax ? ')' : ']'); - pr_cont(" -> "); -#endif + changed = snd_interval_refine(i, constrs_interval(constrs, k)); -#ifdef RULES_DEBUG - if (i->empty) - pr_cont("empty\n"); - else - pr_cont("%c%u %u%c\n", - i->openmin ? '(' : '[', i->min, - i->max, i->openmax ? ')' : ']'); -#endif + trace_hw_interval_param(substream, k, 0, &old_interval, i); if (changed) @@ -391,41 +347,9 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, if (hw_is_interval(r->var)) old_interval = *hw_param_interval(params, r->var); } -#ifdef RULES_DEBUG - pr_debug("Rule %d [%p]: ", k, r->func); - if (r->var >= 0) { - pr_cont("%s = ", snd_pcm_hw_param_names[r->var]); - if (hw_is_mask(r->var)) { - m = hw_param_mask(params, r->var); - pr_cont("%x", *m->bits); - } else { - i = hw_param_interval(params, r->var); - if (i->empty) - pr_cont("empty"); - else - pr_cont("%c%u %u%c", - i->openmin ? '(' : '[', i->min, - i->max, i->openmax ? ')' : ']'); - } - } -#endif + changed = r->func(params, r); -#ifdef RULES_DEBUG - if (r->var >= 0) { - pr_cont(" -> "); - if (hw_is_mask(r->var)) - pr_cont("%x", *m->bits); - else { - if (i->empty) - pr_cont("empty"); - else - pr_cont("%c%u %u%c", - i->openmin ? '(' : '[', i->min, - i->max, i->openmax ? ')' : ']'); - } - } - pr_cont("\n"); -#endif + if (hw_is_mask(r->var)) { trace_hw_mask_param(substream, r->var, k + 1, &old_mask, hw_param_mask(params, r->var)); @@ -434,6 +358,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, trace_hw_interval_param(substream, r->var, k + 1, &old_interval, hw_param_interval(params, r->var)); } + rstamps[k] = stamp; if (changed && r->var >= 0) { params->cmask |= (1 << r->var); From c8597af855f3e34aaebaff0e5c3dbd07611c87f1 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 6 Jun 2017 15:45:07 +0100 Subject: [PATCH 182/418] ASoC: topology: Allow bespoke configuration post widget creation Current topology only allows for widget configuration before the widget is registered. This patch also allows further configuration and usage after registration is complete. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 002772e3ba2c..273a374e741c 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -344,12 +344,24 @@ static int soc_tplg_widget_load(struct soc_tplg *tplg, return 0; } +/* optionally pass new dynamic widget to component driver. This is mainly for + * external widgets where we can assign private data/ops */ +static int soc_tplg_widget_ready(struct soc_tplg *tplg, + struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w) +{ + if (tplg->comp && tplg->ops && tplg->ops->widget_ready) + return tplg->ops->widget_ready(tplg->comp, w, tplg_w); + + return 0; +} + /* pass DAI configurations to component driver for extra initialization */ static int soc_tplg_dai_load(struct soc_tplg *tplg, - struct snd_soc_dai_driver *dai_drv) + struct snd_soc_dai_driver *dai_drv, + struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai) { if (tplg->comp && tplg->ops && tplg->ops->dai_load) - return tplg->ops->dai_load(tplg->comp, dai_drv); + return tplg->ops->dai_load(tplg->comp, dai_drv, pcm, dai); return 0; } @@ -1580,8 +1592,16 @@ widget: kfree(template.sname); kfree(template.name); list_add(&widget->dobj.list, &tplg->comp->dobj_list); + + ret = soc_tplg_widget_ready(tplg, widget, w); + if (ret < 0) + goto ready_err; + return 0; +ready_err: + snd_soc_tplg_widget_remove(widget); + snd_soc_dapm_free_widget(widget); hdr_err: kfree(template.sname); err: From cc9d4714a8da98f905c63d74e9897fc6f4563fca Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 6 Jun 2017 15:45:08 +0100 Subject: [PATCH 183/418] ASoC: topology: rephrase deferred binding warning. Rewrite the message to be more meaningful. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 273a374e741c..f24d1f2e82a0 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1648,7 +1648,7 @@ static int soc_tplg_dapm_complete(struct soc_tplg *tplg) */ if (!card || !card->instantiated) { dev_warn(tplg->dev, "ASoC: Parent card not yet available," - "Do not add new widgets now\n"); + " widget card binding deferred\n"); return 0; } From c3421a6a65abc636b067eb15a4c5e9cb59e91c95 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 6 Jun 2017 15:45:09 +0100 Subject: [PATCH 184/418] ASoC: topology: Dont free template strings whilst they are in use. Template name pointers are copied when creating new widgets and are freed in widget destroy. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index f24d1f2e82a0..7006cf3007b5 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1477,6 +1477,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, if (template.id < 0) return template.id; + /* strings are allocated here, but used and freed by the widget */ template.name = kstrdup(w->name, GFP_KERNEL); if (!template.name) return -ENOMEM; @@ -1589,8 +1590,6 @@ widget: widget->dobj.widget.kcontrol_type = kcontrol_type; widget->dobj.ops = tplg->ops; widget->dobj.index = tplg->index; - kfree(template.sname); - kfree(template.name); list_add(&widget->dobj.list, &tplg->comp->dobj_list); ret = soc_tplg_widget_ready(tplg, widget, w); From 294de6e372673229432dc8bcd80964223bc1589d Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 6 Jun 2017 15:55:04 +0100 Subject: [PATCH 185/418] ASoC: topology: Fix potential build issues with undeclared structs We should be declaring snd_kcontrol_new and soc_dai_link as both are used within this header so need to be declared. [Reworded commit message to indicate this wasn't an immediate build failure -- broonie] Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/soc-topology.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index f9cc7b9271ac..b8da221615e0 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -28,6 +28,8 @@ struct snd_soc_component; struct snd_soc_tplg_pcm_fe; struct snd_soc_dapm_context; struct snd_soc_card; +struct snd_kcontrol_new; +struct snd_soc_dai_link; /* object scan be loaded and unloaded in groups with identfying indexes */ #define SND_SOC_TPLG_INDEX_ALL 0 /* ID that matches all FW objects */ From ca3b5ad30c0b32f8d12ddb307b698ff56d56c2aa Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 6 Jun 2017 23:16:01 +0000 Subject: [PATCH 186/418] ASoC: hdmi-codec: remove unused ratec struct snd_pcm_hw_constraint_list ratec is not used. Let's remove it Signed-off-by: Kuninori Morimoto 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 6d05161b625d..22ed0dc88f0a 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -282,7 +282,6 @@ struct hdmi_codec_priv { struct hdmi_codec_daifmt daifmt[2]; struct mutex current_stream_lock; struct snd_pcm_substream *current_stream; - struct snd_pcm_hw_constraint_list ratec; uint8_t eld[MAX_ELD_BYTES]; struct snd_pcm_chmap *chmap_info; unsigned int chmap_idx; From 411652982a20ab60957283e9084c81d791cb69f9 Mon Sep 17 00:00:00 2001 From: Ryo Kodama Date: Wed, 7 Jun 2017 14:39:00 +0900 Subject: [PATCH 187/418] ASoC: ak4613: Improve counting DAI number Add the startup function to count DAI instead of hw_params. This change matches the number of opened DAIs. If this change isn't applied, you may get unexpected error due to mismatching of count. Since the excution number of hw_params and shutdown may be different, the mismatching happens. Signed-off-by: Kuninori Morimoto Signed-off-by: Ryo Kodama Signed-off-by: Mark Brown --- sound/soc/codecs/ak4613.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index 557ac16d43e2..e3121ca3d1a2 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -252,6 +252,17 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream, mutex_unlock(&priv->lock); } +static int ak4613_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec); + + priv->cnt++; + + return 0; +} + static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_codec *codec = dai->codec; @@ -349,7 +360,6 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, if ((priv->iface == NULL) || (priv->iface == iface)) { priv->iface = iface; - priv->cnt++; ret = 0; } mutex_unlock(&priv->lock); @@ -398,6 +408,7 @@ static int ak4613_set_bias_level(struct snd_soc_codec *codec, } static const struct snd_soc_dai_ops ak4613_dai_ops = { + .startup = ak4613_dai_startup, .shutdown = ak4613_dai_shutdown, .set_fmt = ak4613_dai_set_fmt, .hw_params = ak4613_dai_hw_params, From d2fdcc285f8c79ab1a6d20e5196eb173a105b365 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Jun 2017 00:37:05 +0000 Subject: [PATCH 188/418] ASoC: simple-card: remove duplicate parameter from asoc_simple_card_parse_of() Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 565d057f0d14..33ff487193f9 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -356,12 +356,12 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node, return 0; } -static int asoc_simple_card_parse_of(struct device_node *node, - struct simple_card_data *priv) +static int asoc_simple_card_parse_of(struct simple_card_data *priv) { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_card *card = simple_priv_to_card(priv); struct device_node *dai_link; + struct device_node *node = dev->of_node; int ret; if (!node) @@ -460,7 +460,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (np && of_device_is_available(np)) { - ret = asoc_simple_card_parse_of(np, priv); + ret = asoc_simple_card_parse_of(priv); if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(dev, "parse error %d\n", ret); From 0d6b35212b451d4ac0c07c7b2b15b20ea763df5c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Jun 2017 00:37:30 +0000 Subject: [PATCH 189/418] ASoC: simple-scu-card: remove duplicate paramera from asoc_simple_card_parse_of Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-scu-card.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index 9a251400685e..5faf5d6c48a2 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -192,13 +192,13 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, return 0; } -static int asoc_simple_card_parse_of(struct device_node *node, - struct simple_card_data *priv) +static int asoc_simple_card_parse_of(struct simple_card_data *priv) { struct device *dev = simple_priv_to_dev(priv); struct device_node *np; struct snd_soc_card *card = simple_priv_to_card(priv); + struct device_node *node = dev->of_node; unsigned int daifmt = 0; bool is_fe; int ret, i; @@ -281,7 +281,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) card->codec_conf = &priv->codec_conf; card->num_configs = 1; - ret = asoc_simple_card_parse_of(np, priv); + ret = asoc_simple_card_parse_of(priv); if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(dev, "parse error %d\n", ret); From 07b7acb51d283d8469696c906b91f1882696a4d4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Jun 2017 00:20:01 +0000 Subject: [PATCH 190/418] ASoC: rsnd: update pointer more accurate Current rsnd driver updates pointer when DMA transfer was finished in DMA transfer mode. But PulseAudio requests more accurate pointer update when timer mode. This patch consider about DMA transfer residue and update more accurate pointer. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 6 ++++-- sound/soc/sh/rcar/dma.c | 26 +++++++++++++++++++++++++- sound/soc/sh/rcar/rsnd.h | 7 +++++++ sound/soc/sh/rcar/ssi.c | 12 ++++++++++++ 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 080431543141..bc12c449857a 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -968,12 +968,14 @@ static int rsnd_hw_params(struct snd_pcm_substream *substream, static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + snd_pcm_uframes_t pointer = 0; - return bytes_to_frames(runtime, io->byte_pos); + rsnd_dai_call(pointer, io, &pointer); + + return pointer; } static struct snd_pcm_ops rsnd_pcm_ops = { diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 241cb3b08a07..05e538f4c8d5 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -25,6 +25,7 @@ struct rsnd_dmaen { struct dma_chan *chan; + dma_cookie_t cookie; dma_addr_t dma_buf; unsigned int dma_len; unsigned int dma_period; @@ -292,7 +293,8 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, for (i = 0; i < 2; i++) rsnd_dmaen_sync(dmaen, io, i); - if (dmaengine_submit(desc) < 0) { + dmaen->cookie = dmaengine_submit(desc); + if (dmaen->cookie < 0) { dev_err(dev, "dmaengine_submit() fail\n"); return -EIO; } @@ -348,12 +350,34 @@ static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, return 0; } +static int rsnd_dmaen_pointer(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + snd_pcm_uframes_t *pointer) +{ + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); + struct dma_tx_state state; + enum dma_status status; + unsigned int pos = 0; + + status = dmaengine_tx_status(dmaen->chan, dmaen->cookie, &state); + if (status == DMA_IN_PROGRESS || status == DMA_PAUSED) { + if (state.residue > 0 && state.residue <= dmaen->dma_len) + pos = dmaen->dma_len - state.residue; + } + *pointer = bytes_to_frames(runtime, pos); + + return 0; +} + static struct rsnd_mod_ops rsnd_dmaen_ops = { .name = "audmac", .nolock_start = rsnd_dmaen_nolock_start, .nolock_stop = rsnd_dmaen_nolock_stop, .start = rsnd_dmaen_start, .stop = rsnd_dmaen_stop, + .pointer= rsnd_dmaen_pointer, }; /* diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 96a567de5f14..d4f89d5e6994 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -269,6 +269,9 @@ struct rsnd_mod_ops { struct rsnd_dai_stream *io, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params); + int (*pointer)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + snd_pcm_uframes_t *pointer); int (*fallback)(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv); @@ -306,6 +309,7 @@ struct rsnd_mod { * H 0: pcm_new * H 0: fallback * H 0: hw_params + * H 0: pointer */ #define __rsnd_mod_shift_nolock_start 0 #define __rsnd_mod_shift_nolock_stop 0 @@ -319,6 +323,7 @@ struct rsnd_mod { #define __rsnd_mod_shift_pcm_new 28 /* always called */ #define __rsnd_mod_shift_fallback 28 /* always called */ #define __rsnd_mod_shift_hw_params 28 /* always called */ +#define __rsnd_mod_shift_pointer 28 /* always called */ #define __rsnd_mod_add_probe 0 #define __rsnd_mod_add_remove 0 @@ -332,6 +337,7 @@ struct rsnd_mod { #define __rsnd_mod_add_pcm_new 0 #define __rsnd_mod_add_fallback 0 #define __rsnd_mod_add_hw_params 0 +#define __rsnd_mod_add_pointer 0 #define __rsnd_mod_call_probe 0 #define __rsnd_mod_call_remove 0 @@ -343,6 +349,7 @@ struct rsnd_mod { #define __rsnd_mod_call_pcm_new 0 #define __rsnd_mod_call_fallback 0 #define __rsnd_mod_call_hw_params 0 +#define __rsnd_mod_call_pointer 0 #define __rsnd_mod_call_nolock_start 0 #define __rsnd_mod_call_nolock_stop 1 diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index eddd8afa0825..2363d0beeafd 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -685,6 +685,17 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, return ret; } +static int rsnd_ssi_pointer(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + snd_pcm_uframes_t *pointer) +{ + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + + *pointer = bytes_to_frames(runtime, io->byte_pos); + + return 0; +} + static struct rsnd_mod_ops rsnd_ssi_pio_ops = { .name = SSI_NAME, .probe = rsnd_ssi_common_probe, @@ -693,6 +704,7 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = { .start = rsnd_ssi_start, .stop = rsnd_ssi_stop, .irq = rsnd_ssi_irq, + .pointer= rsnd_ssi_pointer, .pcm_new = rsnd_ssi_pcm_new, .hw_params = rsnd_ssi_hw_params, }; From a97a06c7efc1ee34f500171f1c4e9608295bb79a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Jun 2017 00:20:47 +0000 Subject: [PATCH 191/418] ASoC: rsnd: cleanup pointer related code Current rsnd driver is sharing pointer related code between PIO / DMA. But, it is used only PIO mode now, no longer needed. This patch cleanup these. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 42 ------------------------- sound/soc/sh/rcar/dma.c | 6 +--- sound/soc/sh/rcar/rsnd.h | 6 ---- sound/soc/sh/rcar/ssi.c | 67 ++++++++++++++++++++++++++++++++++++++-- 4 files changed, 65 insertions(+), 56 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 7a8c08933503..7c68f9d4a0ed 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -551,40 +551,6 @@ static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai) /* * rsnd_soc_dai functions */ -int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional) -{ - struct snd_pcm_substream *substream = io->substream; - struct snd_pcm_runtime *runtime = substream->runtime; - int pos = io->byte_pos + additional; - - pos %= (runtime->periods * io->byte_per_period); - - return pos; -} - -bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte) -{ - io->byte_pos += byte; - - if (io->byte_pos >= io->next_period_byte) { - struct snd_pcm_substream *substream = io->substream; - struct snd_pcm_runtime *runtime = substream->runtime; - - io->period_pos++; - io->next_period_byte += io->byte_per_period; - - if (io->period_pos >= runtime->periods) { - io->byte_pos = 0; - io->period_pos = 0; - io->next_period_byte = io->byte_per_period; - } - - return true; - } - - return false; -} - void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io) { struct snd_pcm_substream *substream = io->substream; @@ -602,15 +568,7 @@ void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io) static void rsnd_dai_stream_init(struct rsnd_dai_stream *io, struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; - io->substream = substream; - io->byte_pos = 0; - io->period_pos = 0; - io->byte_per_period = runtime->period_size * - runtime->channels * - samples_to_bytes(runtime, 1); - io->next_period_byte = io->byte_per_period; } static void rsnd_dai_stream_quit(struct rsnd_dai_stream *io) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 05e538f4c8d5..60aa5e96a49f 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -104,10 +104,6 @@ static void __rsnd_dmaen_complete(struct rsnd_mod *mod, * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri. * But, Audio-DMAC-peri-peri doesn't have interrupt, * and this driver is assuming that here. - * - * If Audio-DMAC-peri-peri has interrpt, - * rsnd_dai_pointer_update() will be called twice, - * ant it will breaks io->byte_pos */ spin_lock_irqsave(&priv->lock, flags); @@ -122,7 +118,7 @@ static void __rsnd_dmaen_complete(struct rsnd_mod *mod, */ rsnd_dmaen_sync(dmaen, io, dmaen->dma_cnt + 2); - elapsed = rsnd_dai_pointer_update(io, io->byte_per_period); + elapsed = true; dmaen->dma_cnt++; } diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index bd8def0bc212..6de5f7ec6464 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -432,10 +432,6 @@ struct rsnd_dai_stream { struct rsnd_mod *mod[RSND_MOD_MAX]; struct rsnd_dai *rdai; u32 parent_ssi_status; - int byte_pos; - int period_pos; - int byte_per_period; - int next_period_byte; }; #define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) @@ -480,9 +476,7 @@ struct rsnd_dai { struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id); -bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io); -int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); int rsnd_dai_connect(struct rsnd_mod *mod, struct rsnd_dai_stream *io, enum rsnd_mod_type type); diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 59ca6e3f46bc..f7df3b5e2985 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -77,6 +77,11 @@ struct rsnd_ssi { int rate; int irq; unsigned int usrcnt; + + int byte_pos; + int period_pos; + int byte_per_period; + int next_period_byte; }; /* flags */ @@ -374,6 +379,59 @@ static void rsnd_ssi_register_setup(struct rsnd_mod *mod) ssi->cr_mode); /* without EN */ } +static void rsnd_ssi_pointer_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + + ssi->byte_pos = 0; + ssi->period_pos = 0; + ssi->byte_per_period = runtime->period_size * + runtime->channels * + samples_to_bytes(runtime, 1); + ssi->next_period_byte = ssi->byte_per_period; +} + +static int rsnd_ssi_pointer_offset(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + int additional) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + int pos = ssi->byte_pos + additional; + + pos %= (runtime->periods * ssi->byte_per_period); + + return pos; +} + +static bool rsnd_ssi_pointer_update(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + int byte) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + + ssi->byte_pos += byte; + + if (ssi->byte_pos >= ssi->next_period_byte) { + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + + ssi->period_pos++; + ssi->next_period_byte += ssi->byte_per_period; + + if (ssi->period_pos >= runtime->periods) { + ssi->byte_pos = 0; + ssi->period_pos = 0; + ssi->next_period_byte = ssi->byte_per_period; + } + + return true; + } + + return false; +} + /* * SSI mod common functions */ @@ -387,6 +445,8 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, if (!rsnd_ssi_is_run_mods(mod, io)) return 0; + rsnd_ssi_pointer_init(mod, io); + ssi->usrcnt++; rsnd_mod_power_on(mod); @@ -566,7 +626,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, if (!is_dma && (status & DIRQ)) { struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); u32 *buf = (u32 *)(runtime->dma_area + - rsnd_dai_pointer_offset(io, 0)); + rsnd_ssi_pointer_offset(mod, io, 0)); int shift = 0; switch (runtime->sample_bits) { @@ -585,7 +645,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, else *buf = (rsnd_mod_read(mod, SSIRDR) >> shift); - elapsed = rsnd_dai_pointer_update(io, sizeof(*buf)); + elapsed = rsnd_ssi_pointer_update(mod, io, sizeof(*buf)); } /* DMA only */ @@ -696,9 +756,10 @@ static int rsnd_ssi_pointer(struct rsnd_mod *mod, struct rsnd_dai_stream *io, snd_pcm_uframes_t *pointer) { + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - *pointer = bytes_to_frames(runtime, io->byte_pos); + *pointer = bytes_to_frames(runtime, ssi->byte_pos); return 0; } From 55799c5ab99e8762e58c387e39f9fa36e8f14158 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 8 Jun 2017 09:11:03 +0900 Subject: [PATCH 192/418] ALSA: firewire: arrange common PCM info/constraints for AMDTP engine applications In ALSA firewire stack, 8 drivers uses IEC 61883-1/6 engine for data transmission. They have common PCM info/constraints and duplicated codes. This commit unifies the codes into fireiwre-lib. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 19 +++++++++++++ sound/firewire/bebob/bebob_pcm.c | 21 -------------- sound/firewire/dice/dice-pcm.c | 20 -------------- sound/firewire/digi00x/digi00x-pcm.c | 33 ++++++++-------------- sound/firewire/fireface/ff-pcm.c | 21 -------------- sound/firewire/fireworks/fireworks_pcm.c | 21 -------------- sound/firewire/motu/motu-pcm.c | 20 -------------- sound/firewire/oxfw/oxfw-pcm.c | 20 -------------- sound/firewire/tascam/tascam-pcm.c | 35 ++++-------------------- 9 files changed, 36 insertions(+), 174 deletions(-) diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 4316d9db404d..9678bc75dc5b 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -148,8 +148,27 @@ EXPORT_SYMBOL(amdtp_rate_table); int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s, struct snd_pcm_runtime *runtime) { + struct snd_pcm_hardware *hw = &runtime->hw; int err; + hw->info = SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_JOINT_DUPLEX | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID; + + /* SNDRV_PCM_INFO_BATCH */ + hw->periods_min = 2; + hw->periods_max = UINT_MAX; + + /* bytes for a frame */ + hw->period_bytes_min = 4 * hw->channels_max; + + /* Just to prevent from allocating much pages. */ + hw->period_bytes_max = hw->period_bytes_min * 2048; + hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min; + /* * Currently firewire-lib processes 16 packets in one software * interrupt callback. This equals to 2msec but actually the diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index 657e15a27e5c..e6adab3ef42e 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -92,19 +92,6 @@ limit_channels_and_rates(struct snd_pcm_hardware *hw, } } -static void -limit_period_and_buffer(struct snd_pcm_hardware *hw) -{ - hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */ - hw->periods_max = UINT_MAX; - - hw->period_bytes_min = 4 * hw->channels_max; /* bytes for a frame */ - - /* Just to prevent from allocating much pages. */ - hw->period_bytes_max = hw->period_bytes_min * 2048; - hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min; -} - static int pcm_init_hw_params(struct snd_bebob *bebob, struct snd_pcm_substream *substream) @@ -114,13 +101,6 @@ pcm_init_hw_params(struct snd_bebob *bebob, struct snd_bebob_stream_formation *formations; int err; - runtime->hw.info = SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_JOINT_DUPLEX | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID; - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS; s = &bebob->tx_stream; @@ -132,7 +112,6 @@ pcm_init_hw_params(struct snd_bebob *bebob, } limit_channels_and_rates(&runtime->hw, formations); - limit_period_and_buffer(&runtime->hw); err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, hw_rule_channels, formations, diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 2dda74695069..7cb9e9713ac3 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -51,18 +51,6 @@ static int limit_channels_and_rates(struct snd_dice *dice, return 0; } -static void limit_period_and_buffer(struct snd_pcm_hardware *hw) -{ - hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */ - hw->periods_max = UINT_MAX; - - hw->period_bytes_min = 4 * hw->channels_max; /* byte for a frame */ - - /* Just to prevent from allocating much pages. */ - hw->period_bytes_max = hw->period_bytes_min * 2048; - hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min; -} - static int init_hw_info(struct snd_dice *dice, struct snd_pcm_substream *substream) { @@ -74,13 +62,6 @@ static int init_hw_info(struct snd_dice *dice, unsigned int count, size; int err; - hw->info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_JOINT_DUPLEX | - SNDRV_PCM_INFO_BLOCK_TRANSFER; - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { hw->formats = AM824_IN_PCM_FORMAT_BITS; dir = AMDTP_IN_STREAM; @@ -107,7 +88,6 @@ static int init_hw_info(struct snd_dice *dice, substream->pcm->device, size); if (err < 0) return err; - limit_period_and_buffer(hw); return amdtp_am824_add_pcm_hw_constraints(stream, runtime); } diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c index f76cf5e383db..796f4b4645f5 100644 --- a/sound/firewire/digi00x/digi00x-pcm.c +++ b/sound/firewire/digi00x/digi00x-pcm.c @@ -58,31 +58,11 @@ static int hw_rule_channels(struct snd_pcm_hw_params *params, static int pcm_init_hw_params(struct snd_dg00x *dg00x, struct snd_pcm_substream *substream) { - static const struct snd_pcm_hardware hardware = { - .info = SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_JOINT_DUPLEX | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID, - .rates = SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000, - .rate_min = 44100, - .rate_max = 96000, - .channels_min = 10, - .channels_max = 18, - .period_bytes_min = 4 * 18, - .period_bytes_max = 4 * 18 * 2048, - .buffer_bytes_max = 4 * 18 * 2048 * 2, - .periods_min = 2, - .periods_max = UINT_MAX, - }; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_pcm_hardware *hw = &runtime->hw; struct amdtp_stream *s; int err; - substream->runtime->hw = hardware; if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S32; @@ -92,6 +72,15 @@ static int pcm_init_hw_params(struct snd_dg00x *dg00x, s = &dg00x->rx_stream; } + hw->channels_min = 10; + hw->channels_max = 18; + + hw->rates = SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000; + snd_pcm_limit_hw_rates(runtime); + err = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, hw_rule_channels, NULL, diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c index ad974b5a2561..d12a0e3a4219 100644 --- a/sound/firewire/fireface/ff-pcm.c +++ b/sound/firewire/fireface/ff-pcm.c @@ -91,18 +91,6 @@ static void limit_channels_and_rates(struct snd_pcm_hardware *hw, } } -static void limit_period_and_buffer(struct snd_pcm_hardware *hw) -{ - hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */ - hw->periods_max = UINT_MAX; - - hw->period_bytes_min = 4 * hw->channels_max; /* bytes for a frame */ - - /* Just to prevent from allocating much pages. */ - hw->period_bytes_max = hw->period_bytes_min * 2048; - hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min; -} - static int pcm_init_hw_params(struct snd_ff *ff, struct snd_pcm_substream *substream) { @@ -111,13 +99,6 @@ static int pcm_init_hw_params(struct snd_ff *ff, const unsigned int *pcm_channels; int err; - runtime->hw.info = SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_JOINT_DUPLEX | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID; - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { runtime->hw.formats = SNDRV_PCM_FMTBIT_S32; s = &ff->tx_stream; @@ -128,9 +109,7 @@ static int pcm_init_hw_params(struct snd_ff *ff, pcm_channels = ff->spec->pcm_playback_channels; } - /* limit rates */ limit_channels_and_rates(&runtime->hw, pcm_channels); - limit_period_and_buffer(&runtime->hw); err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, hw_rule_channels, (void *)pcm_channels, diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index 346e2647ed1f..40faed5e6968 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -129,19 +129,6 @@ limit_channels(struct snd_pcm_hardware *hw, unsigned int *pcm_channels) } } -static void -limit_period_and_buffer(struct snd_pcm_hardware *hw) -{ - hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */ - hw->periods_max = UINT_MAX; - - hw->period_bytes_min = 4 * hw->channels_max; /* bytes for a frame */ - - /* Just to prevent from allocating much pages. */ - hw->period_bytes_max = hw->period_bytes_min * 2048; - hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min; -} - static int pcm_init_hw_params(struct snd_efw *efw, struct snd_pcm_substream *substream) @@ -151,13 +138,6 @@ pcm_init_hw_params(struct snd_efw *efw, unsigned int *pcm_channels; int err; - runtime->hw.info = SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_JOINT_DUPLEX | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID; - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS; s = &efw->tx_stream; @@ -173,7 +153,6 @@ pcm_init_hw_params(struct snd_efw *efw, snd_pcm_limit_hw_rates(runtime); limit_channels(&runtime->hw, pcm_channels); - limit_period_and_buffer(&runtime->hw); err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, hw_rule_channels, pcm_channels, diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c index e3ef89cee565..a2b50df70874 100644 --- a/sound/firewire/motu/motu-pcm.c +++ b/sound/firewire/motu/motu-pcm.c @@ -96,18 +96,6 @@ static void limit_channels_and_rates(struct snd_motu *motu, snd_pcm_limit_hw_rates(runtime); } -static void limit_period_and_buffer(struct snd_pcm_hardware *hw) -{ - hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */ - hw->periods_max = UINT_MAX; - - hw->period_bytes_min = 4 * hw->channels_max; /* byte for a frame */ - - /* Just to prevent from allocating much pages. */ - hw->period_bytes_max = hw->period_bytes_min * 2048; - hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min; -} - static int init_hw_info(struct snd_motu *motu, struct snd_pcm_substream *substream) { @@ -117,13 +105,6 @@ static int init_hw_info(struct snd_motu *motu, struct snd_motu_packet_format *formats; int err; - hw->info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_JOINT_DUPLEX | - SNDRV_PCM_INFO_BLOCK_TRANSFER; - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { hw->formats = SNDRV_PCM_FMTBIT_S32; stream = &motu->tx_stream; @@ -135,7 +116,6 @@ static int init_hw_info(struct snd_motu *motu, } limit_channels_and_rates(motu, runtime, formats); - limit_period_and_buffer(hw); err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, motu_rate_constraint, formats, diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index bc1a3a36ab06..3dd46285c0e2 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -106,18 +106,6 @@ static void limit_channels_and_rates(struct snd_pcm_hardware *hw, u8 **formats) } } -static void limit_period_and_buffer(struct snd_pcm_hardware *hw) -{ - hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */ - hw->periods_max = UINT_MAX; - - hw->period_bytes_min = 4 * hw->channels_max; /* bytes for a frame */ - - /* Just to prevent from allocating much pages. */ - hw->period_bytes_max = hw->period_bytes_min * 2048; - hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min; -} - static int init_hw_params(struct snd_oxfw *oxfw, struct snd_pcm_substream *substream) { @@ -126,13 +114,6 @@ static int init_hw_params(struct snd_oxfw *oxfw, struct amdtp_stream *stream; int err; - runtime->hw.info = SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_JOINT_DUPLEX | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID; - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS; stream = &oxfw->tx_stream; @@ -144,7 +125,6 @@ static int init_hw_params(struct snd_oxfw *oxfw, } limit_channels_and_rates(&runtime->hw, formats); - limit_period_and_buffer(&runtime->hw); err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, hw_rule_channels, formats, diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c index 3c4482aa7231..6ec8ec634d4d 100644 --- a/sound/firewire/tascam/tascam-pcm.c +++ b/sound/firewire/tascam/tascam-pcm.c @@ -8,41 +8,14 @@ #include "tascam.h" -static void set_buffer_params(struct snd_pcm_hardware *hw) -{ - hw->period_bytes_min = 4 * hw->channels_min; - hw->period_bytes_max = hw->period_bytes_min * 2048; - hw->buffer_bytes_max = hw->period_bytes_max * 2; - - hw->periods_min = 2; - hw->periods_max = UINT_MAX; -} - static int pcm_init_hw_params(struct snd_tscm *tscm, struct snd_pcm_substream *substream) { - static const struct snd_pcm_hardware hardware = { - .info = SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_JOINT_DUPLEX | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID, - .rates = SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000, - .rate_min = 44100, - .rate_max = 96000, - .channels_min = 10, - .channels_max = 18, - }; struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_pcm_hardware *hw = &runtime->hw; struct amdtp_stream *stream; unsigned int pcm_channels; - runtime->hw = hardware; - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { runtime->hw.formats = SNDRV_PCM_FMTBIT_S32; stream = &tscm->tx_stream; @@ -59,7 +32,11 @@ static int pcm_init_hw_params(struct snd_tscm *tscm, pcm_channels += 2; runtime->hw.channels_min = runtime->hw.channels_max = pcm_channels; - set_buffer_params(&runtime->hw); + hw->rates = SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000; + snd_pcm_limit_hw_rates(runtime); return amdtp_tscm_add_pcm_hw_constraints(stream, runtime); } From 102ebe266c317da59471e2cde0dce603de031482 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 8 Jun 2017 17:02:02 +0100 Subject: [PATCH 193/418] ASoC: Back out post commit widget creation changes Due to build errors revert commit c8597af855f3 (ASoC: topology: Allow bespoke configuration post widget creation) until they can be fixed. Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 7006cf3007b5..f4ec236a418e 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -344,24 +344,12 @@ static int soc_tplg_widget_load(struct soc_tplg *tplg, return 0; } -/* optionally pass new dynamic widget to component driver. This is mainly for - * external widgets where we can assign private data/ops */ -static int soc_tplg_widget_ready(struct soc_tplg *tplg, - struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w) -{ - if (tplg->comp && tplg->ops && tplg->ops->widget_ready) - return tplg->ops->widget_ready(tplg->comp, w, tplg_w); - - return 0; -} - /* pass DAI configurations to component driver for extra initialization */ static int soc_tplg_dai_load(struct soc_tplg *tplg, - struct snd_soc_dai_driver *dai_drv, - struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai) + struct snd_soc_dai_driver *dai_drv) { if (tplg->comp && tplg->ops && tplg->ops->dai_load) - return tplg->ops->dai_load(tplg->comp, dai_drv, pcm, dai); + return tplg->ops->dai_load(tplg->comp, dai_drv); return 0; } @@ -1591,16 +1579,8 @@ widget: widget->dobj.ops = tplg->ops; widget->dobj.index = tplg->index; list_add(&widget->dobj.list, &tplg->comp->dobj_list); - - ret = soc_tplg_widget_ready(tplg, widget, w); - if (ret < 0) - goto ready_err; - return 0; -ready_err: - snd_soc_tplg_widget_remove(widget); - snd_soc_dapm_free_widget(widget); hdr_err: kfree(template.sname); err: From 561e1cadb4dca3783de82cfa453a142129953e4d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 9 Jun 2017 06:36:59 +0900 Subject: [PATCH 194/418] ALSA: pcm: add a helper function to constrain mask-type parameters Application of constraints to mask-type parameters for PCM substream is done in a call of snd_pcm_hw_refine(), while the function includes much codes and is not enough friendly to readers. This commit splits the codes to a separated function so that readers can get it easily. I leave desicion into compilers to merge the function into its callee. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 62 ++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 2bde07a4a87f..1dee5f960fbe 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -253,30 +253,15 @@ static bool hw_support_mmap(struct snd_pcm_substream *substream) return true; } -int snd_pcm_hw_refine(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int constrain_mask_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { + struct snd_pcm_hw_constraints *constrs = + &substream->runtime->hw_constraints; + struct snd_mask *m; unsigned int k; - struct snd_pcm_hardware *hw; - struct snd_interval *i = NULL; - struct snd_mask *m = NULL; - struct snd_pcm_hw_constraints *constrs = &substream->runtime->hw_constraints; - unsigned int rstamps[constrs->rules_num]; - unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; - unsigned int stamp = 2; - int changed, again; - - struct snd_mask __maybe_unused old_mask; - struct snd_interval __maybe_unused old_interval; - - params->info = 0; - params->fifo_size = 0; - if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS)) - params->msbits = 0; - if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) { - params->rate_num = 0; - params->rate_den = 0; - } + struct snd_mask old_mask; + int changed; for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) { m = hw_param_mask(params, k); @@ -298,6 +283,39 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, return changed; } + return 0; +} + +int snd_pcm_hw_refine(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + unsigned int k; + struct snd_pcm_hardware *hw; + struct snd_interval *i = NULL; + struct snd_mask *m = NULL; + struct snd_pcm_hw_constraints *constrs = &substream->runtime->hw_constraints; + unsigned int rstamps[constrs->rules_num]; + unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; + unsigned int stamp = 2; + int changed, again; + int err; + + struct snd_mask __maybe_unused old_mask; + struct snd_interval __maybe_unused old_interval; + + params->info = 0; + params->fifo_size = 0; + if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS)) + params->msbits = 0; + if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) { + params->rate_num = 0; + params->rate_den = 0; + } + + err = constrain_mask_params(substream, params); + if (err < 0) + return err; + for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) { i = hw_param_interval(params, k); if (snd_interval_empty(i)) From 3432fa040211660989844209b67b414185003004 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 9 Jun 2017 06:37:00 +0900 Subject: [PATCH 195/418] ALSA: pcm: add a helper function to constrain interval-type parameters Application of constraints to interval-type parameters for PCM substream is done in a call of snd_pcm_hw_refine(), while the function includes much codes and is not enough friendly to readers. This commit splits the codes to a separated function so that readers can get it easily. I leave desicion into compilers to merge the function into its callee. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 55 +++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 1dee5f960fbe..7e811ace6bf2 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -286,6 +286,39 @@ static int constrain_mask_params(struct snd_pcm_substream *substream, return 0; } +static int constrain_interval_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_hw_constraints *constrs = + &substream->runtime->hw_constraints; + struct snd_interval *i; + unsigned int k; + struct snd_interval old_interval; + int changed; + + for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) { + i = hw_param_interval(params, k); + if (snd_interval_empty(i)) + return -EINVAL; + if (!(params->rmask & (1 << k))) + continue; + + if (trace_hw_interval_param_enabled()) + old_interval = *i; + + changed = snd_interval_refine(i, constrs_interval(constrs, k)); + + trace_hw_interval_param(substream, k, 0, &old_interval, i); + + if (changed) + params->cmask |= 1 << k; + if (changed < 0) + return changed; + } + + return 0; +} + int snd_pcm_hw_refine(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -316,25 +349,9 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, if (err < 0) return err; - for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) { - i = hw_param_interval(params, k); - if (snd_interval_empty(i)) - return -EINVAL; - if (!(params->rmask & (1 << k))) - continue; - - if (trace_hw_interval_param_enabled()) - old_interval = *i; - - changed = snd_interval_refine(i, constrs_interval(constrs, k)); - - trace_hw_interval_param(substream, k, 0, &old_interval, i); - - if (changed) - params->cmask |= 1 << k; - if (changed < 0) - return changed; - } + err = constrain_interval_params(substream, params); + if (err < 0) + return err; for (k = 0; k < constrs->rules_num; k++) rstamps[k] = 0; From 9cc07f55d42be47ad2b06dae9541d9fd964c3287 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 9 Jun 2017 06:37:01 +0900 Subject: [PATCH 196/418] ALSA: pcm: add a helper function to apply parameter rules Application of rules to parameters of PCM substream is done in a call of snd_pcm_hw_refine(), while the function includes much codes and is not enough friendly to readers. This commit splits the codes to a separated function so that readers can get it easily. I leave desicion into compilers to merge the function into its callee. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 77 ++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 7e811ace6bf2..000e6e9a0c2b 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -319,43 +319,23 @@ static int constrain_interval_params(struct snd_pcm_substream *substream, return 0; } -int snd_pcm_hw_refine(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int constrain_params_by_rules(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { + struct snd_pcm_hw_constraints *constrs = + &substream->runtime->hw_constraints; unsigned int k; - struct snd_pcm_hardware *hw; - struct snd_interval *i = NULL; - struct snd_mask *m = NULL; - struct snd_pcm_hw_constraints *constrs = &substream->runtime->hw_constraints; unsigned int rstamps[constrs->rules_num]; unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; unsigned int stamp = 2; - int changed, again; - int err; - - struct snd_mask __maybe_unused old_mask; - struct snd_interval __maybe_unused old_interval; - - params->info = 0; - params->fifo_size = 0; - if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS)) - params->msbits = 0; - if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) { - params->rate_num = 0; - params->rate_den = 0; - } - - err = constrain_mask_params(substream, params); - if (err < 0) - return err; - - err = constrain_interval_params(substream, params); - if (err < 0) - return err; + struct snd_mask old_mask; + struct snd_interval old_interval; + int again; + int changed; for (k = 0; k < constrs->rules_num; k++) rstamps[k] = 0; - for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) + for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0; do { again = 0; @@ -405,6 +385,39 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, stamp++; } } while (again); + + return 0; +} + +int snd_pcm_hw_refine(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_hardware *hw; + struct snd_interval *i = NULL; + struct snd_mask *m = NULL; + int err; + + params->info = 0; + params->fifo_size = 0; + if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS)) + params->msbits = 0; + if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) { + params->rate_num = 0; + params->rate_den = 0; + } + + err = constrain_mask_params(substream, params); + if (err < 0) + return err; + + err = constrain_interval_params(substream, params); + if (err < 0) + return err; + + err = constrain_params_by_rules(substream, params); + if (err < 0) + return err; + if (!params->msbits) { i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); if (snd_interval_single(i)) @@ -432,10 +445,10 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); if (snd_mask_min(m) == snd_mask_max(m) && snd_interval_min(i) == snd_interval_max(i)) { - changed = substream->ops->ioctl(substream, + err = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_FIFO_SIZE, params); - if (changed < 0) - return changed; + if (err < 0) + return err; } } params->rmask = 0; From 0d4e399965738bb90dcee2fd5aeb15c1ccc81b42 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 9 Jun 2017 06:37:02 +0900 Subject: [PATCH 197/418] ALSA: pcm: use goto statement instead of while statement to reduce indentation In a process to calculate parameters of PCM substream, application of all rules is iterated several times till parameter dependencies are satisfied. In current implementation, two loops are used for the design, however this brings two-level indentation and decline readability. This commit attempts to reduce the indentation by using goto statement, instead of outer while loop. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 94 +++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 000e6e9a0c2b..41aeb6facdec 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -337,54 +337,56 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream, rstamps[k] = 0; for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0; - do { - again = 0; - for (k = 0; k < constrs->rules_num; k++) { - struct snd_pcm_hw_rule *r = &constrs->rules[k]; - unsigned int d; - int doit = 0; - if (r->cond && !(r->cond & params->flags)) - continue; - for (d = 0; r->deps[d] >= 0; d++) { - if (vstamps[r->deps[d]] > rstamps[k]) { - doit = 1; - break; - } +retry: + again = 0; + for (k = 0; k < constrs->rules_num; k++) { + struct snd_pcm_hw_rule *r = &constrs->rules[k]; + unsigned int d; + int doit = 0; + if (r->cond && !(r->cond & params->flags)) + continue; + for (d = 0; r->deps[d] >= 0; d++) { + if (vstamps[r->deps[d]] > rstamps[k]) { + doit = 1; + break; } - if (!doit) - continue; - - if (trace_hw_mask_param_enabled()) { - if (hw_is_mask(r->var)) - old_mask = *hw_param_mask(params, r->var); - } - if (trace_hw_interval_param_enabled()) { - if (hw_is_interval(r->var)) - old_interval = *hw_param_interval(params, r->var); - } - - changed = r->func(params, r); - - if (hw_is_mask(r->var)) { - trace_hw_mask_param(substream, r->var, k + 1, - &old_mask, hw_param_mask(params, r->var)); - } - if (hw_is_interval(r->var)) { - trace_hw_interval_param(substream, r->var, k + 1, - &old_interval, hw_param_interval(params, r->var)); - } - - rstamps[k] = stamp; - if (changed && r->var >= 0) { - params->cmask |= (1 << r->var); - vstamps[r->var] = stamp; - again = 1; - } - if (changed < 0) - return changed; - stamp++; } - } while (again); + if (!doit) + continue; + + if (trace_hw_mask_param_enabled()) { + if (hw_is_mask(r->var)) + old_mask = *hw_param_mask(params, r->var); + } + if (trace_hw_interval_param_enabled()) { + if (hw_is_interval(r->var)) + old_interval = *hw_param_interval(params, r->var); + } + + changed = r->func(params, r); + + if (hw_is_mask(r->var)) { + trace_hw_mask_param(substream, r->var, k + 1, + &old_mask, hw_param_mask(params, r->var)); + } + if (hw_is_interval(r->var)) { + trace_hw_interval_param(substream, r->var, k + 1, + &old_interval, hw_param_interval(params, r->var)); + } + + rstamps[k] = stamp; + if (changed && r->var >= 0) { + params->cmask |= (1 << r->var); + vstamps[r->var] = stamp; + again = 1; + } + if (changed < 0) + return changed; + stamp++; + } + + if (again) + goto retry; return 0; } From d656b4a6549f0f5863b7888b25a7b20d03ecbce7 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 9 Jun 2017 06:37:03 +0900 Subject: [PATCH 198/418] ALSA: pcm: remove function local variable with alternative evaluation A local variable is used to judge whether a parameter should be handled due to reverse dependency of the other rules. However, this can be obsoleted by check of a sentinel in dependency array. This commit removes the local variable and check the sentinel to reduce stack usage. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 41aeb6facdec..db4cdd114ed4 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -342,16 +342,13 @@ retry: for (k = 0; k < constrs->rules_num; k++) { struct snd_pcm_hw_rule *r = &constrs->rules[k]; unsigned int d; - int doit = 0; if (r->cond && !(r->cond & params->flags)) continue; for (d = 0; r->deps[d] >= 0; d++) { - if (vstamps[r->deps[d]] > rstamps[k]) { - doit = 1; + if (vstamps[r->deps[d]] > rstamps[k]) break; - } } - if (!doit) + if (r->deps[d] < 0) continue; if (trace_hw_mask_param_enabled()) { From a1c06e39a9373501b4f28caf37fbccba52532f79 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 9 Jun 2017 06:37:04 +0900 Subject: [PATCH 199/418] ALSA: pcm: adaption of code formatting This commit modifies current for readability in below aspects: - use bool type variable instead of int type variable assigned to 0/1 - move variable definition from loop to top of the function definition Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index db4cdd114ed4..40560e579d33 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -328,9 +328,11 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream, unsigned int rstamps[constrs->rules_num]; unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; unsigned int stamp = 2; + struct snd_pcm_hw_rule *r; + unsigned int d; struct snd_mask old_mask; struct snd_interval old_interval; - int again; + bool again; int changed; for (k = 0; k < constrs->rules_num; k++) @@ -338,10 +340,9 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream, for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0; retry: - again = 0; + again = false; for (k = 0; k < constrs->rules_num; k++) { - struct snd_pcm_hw_rule *r = &constrs->rules[k]; - unsigned int d; + r = &constrs->rules[k]; if (r->cond && !(r->cond & params->flags)) continue; for (d = 0; r->deps[d] >= 0; d++) { @@ -375,7 +376,7 @@ retry: if (changed && r->var >= 0) { params->cmask |= (1 << r->var); vstamps[r->var] = stamp; - again = 1; + again = true; } if (changed < 0) return changed; @@ -453,7 +454,6 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, params->rmask = 0; return 0; } - EXPORT_SYMBOL(snd_pcm_hw_refine); static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, From b81e5ddb159490270fa2cca4f6682c4452035203 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 9 Jun 2017 06:37:05 +0900 Subject: [PATCH 200/418] ALSA: pcm: use helper functions to check whether parameters are determined A commit 8bea869c5e56 ("ALSA: PCM midlevel: improve fifo_size handling") allows drivers to implement calculation of fifo size in parameter structure. This calculation runs only when two of the other parameters have single value. In ALSA PCM core, there're some helper functions for the case. This commit applies the functions instead of value comparison. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 40560e579d33..80275aa0bcca 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -443,8 +443,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, if (!params->fifo_size) { m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - if (snd_mask_min(m) == snd_mask_max(m) && - snd_interval_min(i) == snd_interval_max(i)) { + if (snd_mask_single(m) && snd_interval_single(i)) { err = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_FIFO_SIZE, params); if (err < 0) From d81052f92c3d018ade20ecbf461004566428d9a5 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 9 Jun 2017 06:37:06 +0900 Subject: [PATCH 201/418] ALSA: pcm: add comment about application of rule to PCM parameters Drivers add rules of parameters to runtime of PCM substream, when applications open ALSA PCM character device. When applications call ioctl(2) with SNDRV_PCM_IOCTL_HW_REFINE or SNDRV_PCM_IOCTL_HW_PARAMS, the rules are applied to the parameters and return the result to user space. The rule can have dependency between parameters. Additionally, it can have condition flags about application of rules. Userspace applications can indicate the flags to suppress change of parameters. This commit attempts to describe the mechanism. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 53 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 80275aa0bcca..422ee4629698 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -267,6 +267,8 @@ static int constrain_mask_params(struct snd_pcm_substream *substream, m = hw_param_mask(params, k); if (snd_mask_empty(m)) return -EINVAL; + + /* This parameter is not requested to change by a caller. */ if (!(params->rmask & (1 << k))) continue; @@ -277,6 +279,7 @@ static int constrain_mask_params(struct snd_pcm_substream *substream, trace_hw_mask_param(substream, k, 0, &old_mask, m); + /* Set corresponding flag so that the caller gets it. */ if (changed) params->cmask |= 1 << k; if (changed < 0) @@ -300,6 +303,8 @@ static int constrain_interval_params(struct snd_pcm_substream *substream, i = hw_param_interval(params, k); if (snd_interval_empty(i)) return -EINVAL; + + /* This parameter is not requested to change by a caller. */ if (!(params->rmask & (1 << k))) continue; @@ -310,6 +315,7 @@ static int constrain_interval_params(struct snd_pcm_substream *substream, trace_hw_interval_param(substream, k, 0, &old_interval, i); + /* Set corresponding flag so that the caller gets it. */ if (changed) params->cmask |= 1 << k; if (changed < 0) @@ -327,7 +333,7 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream, unsigned int k; unsigned int rstamps[constrs->rules_num]; unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; - unsigned int stamp = 2; + unsigned int stamp; struct snd_pcm_hw_rule *r; unsigned int d; struct snd_mask old_mask; @@ -335,16 +341,54 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream, bool again; int changed; + /* + * Each application of rule has own sequence number. + * + * Each member of 'rstamps' array represents the sequence number of + * recent application of corresponding rule. + */ for (k = 0; k < constrs->rules_num; k++) rstamps[k] = 0; + + /* + * Each member of 'vstamps' array represents the sequence number of + * recent application of rule in which corresponding parameters were + * changed. + * + * In initial state, elements corresponding to parameters requested by + * a caller is 1. For unrequested parameters, corresponding members + * have 0 so that the parameters are never changed anymore. + */ for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0; + + /* Due to the above design, actual sequence number starts at 2. */ + stamp = 2; retry: + /* Apply all rules in order. */ again = false; for (k = 0; k < constrs->rules_num; k++) { r = &constrs->rules[k]; + + /* + * Check condition bits of this rule. When the rule has + * some condition bits, parameter without the bits is + * never processed. SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP + * is an example of the condition bits. + */ if (r->cond && !(r->cond & params->flags)) continue; + + /* + * The 'deps' array includes maximum three dependencies + * to SNDRV_PCM_HW_PARAM_XXXs for this rule. The fourth + * member of this array is a sentinel and should be + * negative value. + * + * This rule should be processed in this time when dependent + * parameters were changed at former applications of the other + * rules. + */ for (d = 0; r->deps[d] >= 0; d++) { if (vstamps[r->deps[d]] > rstamps[k]) break; @@ -373,6 +417,12 @@ retry: } rstamps[k] = stamp; + + /* + * When the parameters is changed, notify it to the caller + * by corresponding returned bit, then preparing for next + * iteration. + */ if (changed && r->var >= 0) { params->cmask |= (1 << r->var); vstamps[r->var] = stamp; @@ -383,6 +433,7 @@ retry: stamp++; } + /* Iterate to evaluate all rules till no parameters are changed. */ if (again) goto retry; From e02de47e3c020c7bc8ce587b1b98cfc817e7db8e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 9 Jun 2017 09:34:38 +0900 Subject: [PATCH 202/418] ALSA: pcm: use helper functions to refer parameters as constants To fixup some parameters, ALSA PCM core refers the other parameters as constants. There're some macros for this purpose. This commit replaces codes with them. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 422ee4629698..87a507f12f2f 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -444,8 +444,8 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_hardware *hw; - struct snd_interval *i = NULL; - struct snd_mask *m = NULL; + const struct snd_interval *i; + const struct snd_mask *m; int err; params->info = 0; @@ -470,13 +470,13 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, return err; if (!params->msbits) { - i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); + i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); if (snd_interval_single(i)) params->msbits = snd_interval_value(i); } if (!params->rate_den) { - i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); if (snd_interval_single(i)) { params->rate_num = snd_interval_value(i); params->rate_den = 1; @@ -492,8 +492,8 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, SNDRV_PCM_INFO_MMAP_VALID); } if (!params->fifo_size) { - m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); + i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); if (snd_mask_single(m) && snd_interval_single(i)) { err = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_FIFO_SIZE, params); From f9a076bff053100c9c3d1d5cca33ca856688b782 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 9 Jun 2017 09:34:39 +0900 Subject: [PATCH 203/418] ALSA: pcm: calculate non-mask/non-interval parameters always when possible A structure for parameters of PCM runtime has parameters which are not classified as mask/interval type. They are decided only when corresponding normal parameters have unique values. * struct snd_pcm_hw_params.msbits * struct snd_pcm_hw_params.rate_num * struct snd_pcm_hw_params.rate_den * struct snd_pcm_hw_params.fifo_size Current implementation of hw_params ioctl sometimes doesn't decide these parameters even if corresponding parameters are fixed, because these parameters are evaluated before a call of snd_pcm_hw_params_choose(). This commit adds a helper function to process the parameters and call it in proper positions. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 70 ++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 87a507f12f2f..dfe6113a6a60 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -440,12 +440,45 @@ retry: return 0; } +static int fixup_unreferenced_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + const struct snd_interval *i; + const struct snd_mask *m; + int err; + + if (!params->msbits) { + i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); + if (snd_interval_single(i)) + params->msbits = snd_interval_value(i); + } + + if (!params->rate_den) { + i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); + if (snd_interval_single(i)) { + params->rate_num = snd_interval_value(i); + params->rate_den = 1; + } + } + + if (!params->fifo_size) { + m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); + i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); + if (snd_mask_single(m) && snd_interval_single(i)) { + err = substream->ops->ioctl(substream, + SNDRV_PCM_IOCTL1_FIFO_SIZE, params); + if (err < 0) + return err; + } + } + + return 0; +} + int snd_pcm_hw_refine(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_hardware *hw; - const struct snd_interval *i; - const struct snd_mask *m; int err; params->info = 0; @@ -469,20 +502,6 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, if (err < 0) return err; - if (!params->msbits) { - i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); - if (snd_interval_single(i)) - params->msbits = snd_interval_value(i); - } - - if (!params->rate_den) { - i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); - if (snd_interval_single(i)) { - params->rate_num = snd_interval_value(i); - params->rate_den = 1; - } - } - hw = &substream->runtime->hw; if (!params->info) { params->info = hw->info & ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES | @@ -491,16 +510,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, params->info &= ~(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID); } - if (!params->fifo_size) { - m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); - i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); - if (snd_mask_single(m) && snd_interval_single(i)) { - err = substream->ops->ioctl(substream, - SNDRV_PCM_IOCTL1_FIFO_SIZE, params); - if (err < 0) - return err; - } - } + params->rmask = 0; return 0; } @@ -517,6 +527,8 @@ static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, return PTR_ERR(params); err = snd_pcm_hw_refine(substream, params); + if (err >= 0) + err = fixup_unreferenced_params(substream, params); if (copy_to_user(_params, params, sizeof(*params))) { if (!err) err = -EFAULT; @@ -596,6 +608,10 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, if (err < 0) goto _error; + err = fixup_unreferenced_params(substream, params); + if (err < 0) + goto _error; + if (substream->ops->hw_params != NULL) { err = substream->ops->hw_params(substream, params); if (err < 0) @@ -3621,6 +3637,8 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, } snd_pcm_hw_convert_from_old_params(params, oparams); err = snd_pcm_hw_refine(substream, params); + if (err >= 0) + err = fixup_unreferenced_params(substream, params); snd_pcm_hw_convert_to_old_params(oparams, params); if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { if (!err) From 7802fb52564b5d6b4fdcf25a08d487897f9e4a8b Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 9 Jun 2017 09:34:40 +0900 Subject: [PATCH 204/418] ALSA: pcm: move fixup of info flag after selecting single parameters When drivers register no flags about information of PCM hardware, ALSA PCM core fixups it roughly. Currently, this operation places in a function snd_pcm_hw_refine(). It can be moved to a function fixup_unreferenced_params() because it doesn't affects operations between these two functions. This idea is better to bundle codes with similar purposes and this commit achieves it. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index dfe6113a6a60..3293db0172db 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -472,13 +472,21 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream, } } + if (!params->info) { + params->info = substream->runtime->hw.info; + params->info &= ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES | + SNDRV_PCM_INFO_DRAIN_TRIGGER); + if (!hw_support_mmap(substream)) + params->info &= ~(SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID); + } + return 0; } int snd_pcm_hw_refine(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_pcm_hardware *hw; int err; params->info = 0; @@ -502,16 +510,8 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, if (err < 0) return err; - hw = &substream->runtime->hw; - if (!params->info) { - params->info = hw->info & ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES | - SNDRV_PCM_INFO_DRAIN_TRIGGER); - if (!hw_support_mmap(substream)) - params->info &= ~(SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID); - } - params->rmask = 0; + return 0; } EXPORT_SYMBOL(snd_pcm_hw_refine); From 642b7589da26d59ce36f9a4b1b5188f95e514de9 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Fri, 9 Jun 2017 11:39:56 +0530 Subject: [PATCH 205/418] ALSA : pcsp: pcsp_lib: constify snd_pcsp_playback_ops File size before: text data bss dec hex filename 2027 168 1 2196 894 sound/drivers/pcsp/pcsp_lib.o File size After: text data bss dec hex filename 2155 40 1 2196 894 sound/drivers/pcsp/pcsp_lib.o Signed-off-by: Arvind Yadav Signed-off-by: Takashi Iwai --- sound/drivers/pcsp/pcsp_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c index aca2d7d5f059..44b3632f6940 100644 --- a/sound/drivers/pcsp/pcsp_lib.c +++ b/sound/drivers/pcsp/pcsp_lib.c @@ -323,7 +323,7 @@ static int snd_pcsp_playback_open(struct snd_pcm_substream *substream) return 0; } -static struct snd_pcm_ops snd_pcsp_playback_ops = { +static const struct snd_pcm_ops snd_pcsp_playback_ops = { .open = snd_pcsp_playback_open, .close = snd_pcsp_playback_close, .ioctl = snd_pcm_lib_ioctl, From bf8334845598a172b42ee487b05eb4394c86bce8 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Fri, 9 Jun 2017 12:35:43 +0530 Subject: [PATCH 206/418] ALSA: vx: vx_pcm: constify vx_pcm_playback_ops and vx_pcm_capture_ops. File size before: text data bss dec hex filename 7126 240 0 7366 1cc6 sound/drivers/vx/vx_pcm.o File size After adding 'const': text data bss dec hex filename 7382 0 0 7382 1cd6 sound/drivers/vx/vx_pcm.o Signed-off-by: Arvind Yadav Signed-off-by: Takashi Iwai --- sound/drivers/vx/vx_pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index ea7b377f0378..d318a33b6cfb 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -873,7 +873,7 @@ static int vx_pcm_prepare(struct snd_pcm_substream *subs) /* * operators for PCM playback */ -static struct snd_pcm_ops vx_pcm_playback_ops = { +static const struct snd_pcm_ops vx_pcm_playback_ops = { .open = vx_pcm_playback_open, .close = vx_pcm_playback_close, .ioctl = snd_pcm_lib_ioctl, @@ -1095,7 +1095,7 @@ static snd_pcm_uframes_t vx_pcm_capture_pointer(struct snd_pcm_substream *subs) /* * operators for PCM capture */ -static struct snd_pcm_ops vx_pcm_capture_ops = { +static const struct snd_pcm_ops vx_pcm_capture_ops = { .open = vx_pcm_capture_open, .close = vx_pcm_capture_close, .ioctl = snd_pcm_lib_ioctl, From 0adaf3bea166d21dfd420b8628ca74adf15d75f8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:12:16 +0200 Subject: [PATCH 207/418] ALSA: cs423x: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/isa/cs423x/cs4236_lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index 2b7cc596f4c6..2012936f6756 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c @@ -138,7 +138,7 @@ static unsigned char snd_cs4236_ctrl_in(struct snd_wss *chip, unsigned char reg) #define CLOCKS 8 -static struct snd_ratnum clocks[CLOCKS] = { +static const struct snd_ratnum clocks[CLOCKS] = { { .num = 16934400, .den_min = 353, .den_max = 353, .den_step = 1 }, { .num = 16934400, .den_min = 529, .den_max = 529, .den_step = 1 }, { .num = 16934400, .den_min = 617, .den_max = 617, .den_step = 1 }, @@ -149,7 +149,7 @@ static struct snd_ratnum clocks[CLOCKS] = { { .num = 16934400/16, .den_min = 21, .den_max = 192, .den_step = 1 } }; -static struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks = { +static const struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks = { .nrats = CLOCKS, .rats = clocks, }; From 4ea2bb7311deab401d01877f15c75e0803ac6257 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:15:49 +0200 Subject: [PATCH 208/418] ALSA: es1688: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/isa/es1688/es1688_lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index 81cf26fa28d6..5d3df96c5e5b 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c @@ -290,7 +290,7 @@ static int snd_es1688_init(struct snd_es1688 * chip, int enable) */ -static struct snd_ratnum clocks[2] = { +static const struct snd_ratnum clocks[2] = { { .num = 795444, .den_min = 1, @@ -305,7 +305,7 @@ static struct snd_ratnum clocks[2] = { } }; -static struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks = { +static const struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks = { .nrats = 2, .rats = clocks, }; From 21709121fb734715b4c4819aae36aad50cc88fd7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:16:10 +0200 Subject: [PATCH 209/418] ALSA: es18xx: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/isa/es18xx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 0cabe2b8974f..ae17a6584061 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -369,7 +369,7 @@ static int snd_es18xx_reset_fifo(struct snd_es18xx *chip) return 0; } -static struct snd_ratnum new_clocks[2] = { +static const struct snd_ratnum new_clocks[2] = { { .num = 793800, .den_min = 1, @@ -384,12 +384,12 @@ static struct snd_ratnum new_clocks[2] = { } }; -static struct snd_pcm_hw_constraint_ratnums new_hw_constraints_clocks = { +static const struct snd_pcm_hw_constraint_ratnums new_hw_constraints_clocks = { .nrats = 2, .rats = new_clocks, }; -static struct snd_ratnum old_clocks[2] = { +static const struct snd_ratnum old_clocks[2] = { { .num = 795444, .den_min = 1, @@ -404,7 +404,7 @@ static struct snd_ratnum old_clocks[2] = { } }; -static struct snd_pcm_hw_constraint_ratnums old_hw_constraints_clocks = { +static const struct snd_pcm_hw_constraint_ratnums old_hw_constraints_clocks = { .nrats = 2, .rats = old_clocks, }; From bfa516a109ae77dae34b69f36d09b8f9d329384b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:16:25 +0200 Subject: [PATCH 210/418] ALSA: gus: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/isa/gus/gus_pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index b9f6dcbef889..6b3da01a93b7 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c @@ -562,14 +562,14 @@ static snd_pcm_uframes_t snd_gf1_pcm_playback_pointer(struct snd_pcm_substream * return pos; } -static struct snd_ratnum clock = { +static const struct snd_ratnum clock = { .num = 9878400/16, .den_min = 2, .den_max = 257, .den_step = 1, }; -static struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks = { +static const struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks = { .nrats = 1, .rats = &clock, }; From b078bbfbb1a1083a69117bc894107cad6920a2ed Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:16:34 +0200 Subject: [PATCH 211/418] ALSA: sb: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/isa/sb/sb8_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index 9043397fe62f..0f302be4fb6d 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c @@ -46,19 +46,19 @@ MODULE_LICENSE("GPL"); #define SB8_DEN(v) ((SB8_CLOCK + (v) / 2) / (v)) #define SB8_RATE(v) (SB8_CLOCK / SB8_DEN(v)) -static struct snd_ratnum clock = { +static const struct snd_ratnum clock = { .num = SB8_CLOCK, .den_min = 1, .den_max = 256, .den_step = 1, }; -static struct snd_pcm_hw_constraint_ratnums hw_constraints_clock = { +static const struct snd_pcm_hw_constraint_ratnums hw_constraints_clock = { .nrats = 1, .rats = &clock, }; -static struct snd_ratnum stereo_clocks[] = { +static const struct snd_ratnum stereo_clocks[] = { { .num = SB8_CLOCK, .den_min = SB8_DEN(22050), From 7b3f477636eddcaa137b96e6c847fb466fadb19a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:16:43 +0200 Subject: [PATCH 212/418] ALSA: wss: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/isa/wss/wss_lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 913b731d2236..9f4e2e34cbe1 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -69,12 +69,12 @@ static unsigned char freq_bits[14] = { /* 48000 */ 0x0C | CS4231_XTAL1 }; -static unsigned int rates[14] = { +static const unsigned int rates[14] = { 5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050, 27042, 32000, 33075, 37800, 44100, 48000 }; -static struct snd_pcm_hw_constraint_list hw_constraints_rates = { +static const struct snd_pcm_hw_constraint_list hw_constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, From d236d36107dec03a7755ee9a6dfc2961f269aa43 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:17:04 +0200 Subject: [PATCH 213/418] ALSA: parisc: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/parisc/harmony.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c index 99b64cb3cef8..5911eb35c2a3 100644 --- a/sound/parisc/harmony.c +++ b/sound/parisc/harmony.c @@ -83,14 +83,14 @@ MODULE_DEVICE_TABLE(parisc, snd_harmony_devtable); #define NAME "harmony" #define PFX NAME ": " -static unsigned int snd_harmony_rates[] = { +static const unsigned int snd_harmony_rates[] = { 5512, 6615, 8000, 9600, 11025, 16000, 18900, 22050, 27428, 32000, 33075, 37800, 44100, 48000 }; -static unsigned int rate_bits[14] = { +static const unsigned int rate_bits[14] = { HARMONY_SR_5KHZ, HARMONY_SR_6KHZ, HARMONY_SR_8KHZ, HARMONY_SR_9KHZ, HARMONY_SR_11KHZ, HARMONY_SR_16KHZ, HARMONY_SR_18KHZ, HARMONY_SR_22KHZ, HARMONY_SR_27KHZ, @@ -98,7 +98,7 @@ static unsigned int rate_bits[14] = { HARMONY_SR_44KHZ, HARMONY_SR_48KHZ }; -static struct snd_pcm_hw_constraint_list hw_constraint_rates = { +static const struct snd_pcm_hw_constraint_list hw_constraint_rates = { .count = ARRAY_SIZE(snd_harmony_rates), .list = snd_harmony_rates, .mask = 0, From 8eba3b30a239807f8d3b185befd9e9fef92cb5e9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:17:23 +0200 Subject: [PATCH 214/418] ALSA: ali5451: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/ali5451/ali5451.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 34bbc2e730a6..8567f1e5b9cf 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -1602,8 +1602,8 @@ static struct snd_pcm_hardware snd_ali_modem = static int snd_ali_modem_open(struct snd_pcm_substream *substream, int rec, int channel) { - static unsigned int rates[] = {8000, 9600, 12000, 16000}; - static struct snd_pcm_hw_constraint_list hw_constraint_rates = { + static const unsigned int rates[] = {8000, 9600, 12000, 16000}; + static const struct snd_pcm_hw_constraint_list hw_constraint_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, From c15ec07bafbe00b82b7a2e26102c8e41e9b4626d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:17:39 +0200 Subject: [PATCH 215/418] ALSA: atiixp: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/atiixp_modem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 40152feef1e7..52e0ea7b9b80 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -860,8 +860,8 @@ static int snd_atiixp_pcm_open(struct snd_pcm_substream *substream, struct atiixp_modem *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err; - static unsigned int rates[] = { 8000, 9600, 12000, 16000 }; - static struct snd_pcm_hw_constraint_list hw_constraints_rates = { + static const unsigned int rates[] = { 8000, 9600, 12000, 16000 }; + static const struct snd_pcm_hw_constraint_list hw_constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, From 2e5eb6b745315c2c12f970929d410be920ae18bb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:18:01 +0200 Subject: [PATCH 216/418] ALSA: au88x0: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/au88x0/au88x0_pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index 335979a753fe..1aa97012451d 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c @@ -112,11 +112,11 @@ static struct snd_pcm_hardware snd_vortex_playback_hw_wt = { }; #endif #ifdef CHIP_AU8830 -static unsigned int au8830_channels[3] = { +static const unsigned int au8830_channels[3] = { 1, 2, 4, }; -static struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = { +static const struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = { .count = ARRAY_SIZE(au8830_channels), .list = au8830_channels, .mask = 0, From 3e2fd04f89e5d38c8df3c4b6dba771f2c46a8f44 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:18:16 +0200 Subject: [PATCH 217/418] ALSA: azt3328: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/azt3328.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 79b2e6b7d88b..fc18c29a8173 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -2014,7 +2014,7 @@ static const struct snd_pcm_hardware snd_azf3328_hardware = }; -static unsigned int snd_azf3328_fixed_rates[] = { +static const unsigned int snd_azf3328_fixed_rates[] = { AZF_FREQ_4000, AZF_FREQ_4800, AZF_FREQ_5512, @@ -2031,7 +2031,7 @@ static unsigned int snd_azf3328_fixed_rates[] = { AZF_FREQ_66200 }; -static struct snd_pcm_hw_constraint_list snd_azf3328_hw_constraints_rates = { +static const struct snd_pcm_hw_constraint_list snd_azf3328_hw_constraints_rates = { .count = ARRAY_SIZE(snd_azf3328_fixed_rates), .list = snd_azf3328_fixed_rates, .mask = 0, From 934cd5b76d6fb5bbdefd37815a2b9441eb09d02f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:18:33 +0200 Subject: [PATCH 218/418] ALSA: bt87x: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/bt87x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 099efb046b1c..de0234294c25 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -401,13 +401,13 @@ static int snd_bt87x_set_digital_hw(struct snd_bt87x *chip, struct snd_pcm_runti static int snd_bt87x_set_analog_hw(struct snd_bt87x *chip, struct snd_pcm_runtime *runtime) { - static struct snd_ratnum analog_clock = { + static const struct snd_ratnum analog_clock = { .num = ANALOG_CLOCK, .den_min = CLOCK_DIV_MIN, .den_max = CLOCK_DIV_MAX, .den_step = 1 }; - static struct snd_pcm_hw_constraint_ratnums constraint_rates = { + static const struct snd_pcm_hw_constraint_ratnums constraint_rates = { .nrats = 1, .rats = &analog_clock }; From 0fac3195a8b8677199404a62c7c5e74daaa942dd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:18:47 +0200 Subject: [PATCH 219/418] ALSA: cmipci: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/cmipci.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 745a0a3743b4..a460cb63e971 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -719,18 +719,18 @@ static int snd_cmipci_hw_free(struct snd_pcm_substream *substream) /* */ -static unsigned int hw_channels[] = {1, 2, 4, 6, 8}; -static struct snd_pcm_hw_constraint_list hw_constraints_channels_4 = { +static const unsigned int hw_channels[] = {1, 2, 4, 6, 8}; +static const struct snd_pcm_hw_constraint_list hw_constraints_channels_4 = { .count = 3, .list = hw_channels, .mask = 0, }; -static struct snd_pcm_hw_constraint_list hw_constraints_channels_6 = { +static const struct snd_pcm_hw_constraint_list hw_constraints_channels_6 = { .count = 4, .list = hw_channels, .mask = 0, }; -static struct snd_pcm_hw_constraint_list hw_constraints_channels_8 = { +static const struct snd_pcm_hw_constraint_list hw_constraints_channels_8 = { .count = 5, .list = hw_channels, .mask = 0, @@ -1597,9 +1597,9 @@ static struct snd_pcm_hardware snd_cmipci_capture_spdif = .fifo_size = 0, }; -static unsigned int rate_constraints[] = { 5512, 8000, 11025, 16000, 22050, +static const unsigned int rate_constraints[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 128000 }; -static struct snd_pcm_hw_constraint_list hw_constraints_rates = { +static const struct snd_pcm_hw_constraint_list hw_constraints_rates = { .count = ARRAY_SIZE(rate_constraints), .list = rate_constraints, .mask = 0, From 54e848ceb736d21cd754b90f7a884ae9acf483f3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:19:05 +0200 Subject: [PATCH 220/418] ALSA: cs46xx: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/cs46xx/cs46xx_lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index ae2aad52ea6f..709fb1a503b7 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -1482,9 +1482,9 @@ static struct snd_pcm_hardware snd_cs46xx_capture = #ifdef CONFIG_SND_CS46XX_NEW_DSP -static unsigned int period_sizes[] = { 32, 64, 128, 256, 512, 1024, 2048 }; +static const unsigned int period_sizes[] = { 32, 64, 128, 256, 512, 1024, 2048 }; -static struct snd_pcm_hw_constraint_list hw_constraints_period_sizes = { +static const struct snd_pcm_hw_constraint_list hw_constraints_period_sizes = { .count = ARRAY_SIZE(period_sizes), .list = period_sizes, .mask = 0 From 973f1d6c9467e5f0e3988d1449abc4191090798f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:19:20 +0200 Subject: [PATCH 221/418] ALSA: emu10k1: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emupcm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index bdda29f335f6..5c9054a9f69e 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -164,7 +164,7 @@ static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm * epcm, int voic return 0; } -static unsigned int capture_period_sizes[31] = { +static const unsigned int capture_period_sizes[31] = { 384, 448, 512, 640, 384*2, 448*2, 512*2, 640*2, 384*4, 448*4, 512*4, 640*4, @@ -175,17 +175,17 @@ static unsigned int capture_period_sizes[31] = { 384*128,448*128,512*128 }; -static struct snd_pcm_hw_constraint_list hw_constraints_capture_period_sizes = { +static const struct snd_pcm_hw_constraint_list hw_constraints_capture_period_sizes = { .count = 31, .list = capture_period_sizes, .mask = 0 }; -static unsigned int capture_rates[8] = { +static const unsigned int capture_rates[8] = { 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000 }; -static struct snd_pcm_hw_constraint_list hw_constraints_capture_rates = { +static const struct snd_pcm_hw_constraint_list hw_constraints_capture_rates = { .count = 8, .list = capture_rates, .mask = 0 From d71a13f4c0e659c7ce7bef872c2e6a2287868e0e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:19:28 +0200 Subject: [PATCH 222/418] ALSA: fm801: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/fm801.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index c47287d79306..2e402ece4c86 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -334,23 +334,23 @@ static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short return fm801_readw(chip, AC97_DATA); } -static unsigned int rates[] = { +static const unsigned int rates[] = { 5500, 8000, 9600, 11025, 16000, 19200, 22050, 32000, 38400, 44100, 48000 }; -static struct snd_pcm_hw_constraint_list hw_constraints_rates = { +static const struct snd_pcm_hw_constraint_list hw_constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, }; -static unsigned int channels[] = { +static const unsigned int channels[] = { 2, 4, 6 }; -static struct snd_pcm_hw_constraint_list hw_constraints_channels = { +static const struct snd_pcm_hw_constraint_list hw_constraints_channels = { .count = ARRAY_SIZE(channels), .list = channels, .mask = 0, From 8130829a9b73dca2bd9cc7ce8ea031405cb1757f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:19:39 +0200 Subject: [PATCH 223/418] ALSA: ens137x: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/ens1370.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 09a63ef41ef2..f0d978e3b274 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -467,41 +467,41 @@ MODULE_DEVICE_TABLE(pci, snd_audiopci_ids); #define POLL_COUNT 0xa000 #ifdef CHIP1370 -static unsigned int snd_es1370_fixed_rates[] = +static const unsigned int snd_es1370_fixed_rates[] = {5512, 11025, 22050, 44100}; -static struct snd_pcm_hw_constraint_list snd_es1370_hw_constraints_rates = { +static const struct snd_pcm_hw_constraint_list snd_es1370_hw_constraints_rates = { .count = 4, .list = snd_es1370_fixed_rates, .mask = 0, }; -static struct snd_ratnum es1370_clock = { +static const struct snd_ratnum es1370_clock = { .num = ES_1370_SRCLOCK, .den_min = 29, .den_max = 353, .den_step = 1, }; -static struct snd_pcm_hw_constraint_ratnums snd_es1370_hw_constraints_clock = { +static const struct snd_pcm_hw_constraint_ratnums snd_es1370_hw_constraints_clock = { .nrats = 1, .rats = &es1370_clock, }; #else -static struct snd_ratden es1371_dac_clock = { +static const struct snd_ratden es1371_dac_clock = { .num_min = 3000 * (1 << 15), .num_max = 48000 * (1 << 15), .num_step = 3000, .den = 1 << 15, }; -static struct snd_pcm_hw_constraint_ratdens snd_es1371_hw_constraints_dac_clock = { +static const struct snd_pcm_hw_constraint_ratdens snd_es1371_hw_constraints_dac_clock = { .nrats = 1, .rats = &es1371_dac_clock, }; -static struct snd_ratnum es1371_adc_clock = { +static const struct snd_ratnum es1371_adc_clock = { .num = 48000 << 15, .den_min = 32768, .den_max = 393216, .den_step = 1, }; -static struct snd_pcm_hw_constraint_ratnums snd_es1371_hw_constraints_adc_clock = { +static const struct snd_pcm_hw_constraint_ratnums snd_es1371_hw_constraints_adc_clock = { .nrats = 1, .rats = &es1371_adc_clock, }; From 44d715074d4006d30d3eaa35412f2d31896245ad Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:19:56 +0200 Subject: [PATCH 224/418] ALSA: es1938: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/es1938.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index a544cd52f73a..069902a06f00 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -436,7 +436,7 @@ static void snd_es1938_reset_fifo(struct es1938 *chip) outb(0, SLSB_REG(chip, RESET)); } -static struct snd_ratnum clocks[2] = { +static const struct snd_ratnum clocks[2] = { { .num = 793800, .den_min = 1, @@ -451,7 +451,7 @@ static struct snd_ratnum clocks[2] = { } }; -static struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks = { +static const struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks = { .nrats = 2, .rats = clocks, }; From 50c697adfb7770a28081f73e7f9f6ddc5b55cfc5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:20:07 +0200 Subject: [PATCH 225/418] ALSA: hda: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 10 +++++----- sound/pci/hda/patch_si3054.c | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 90e4ff87445e..0d7955eec201 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2782,21 +2782,21 @@ static int nvhdmi_7x_init_8ch(struct hda_codec *codec) return 0; } -static unsigned int channels_2_6_8[] = { +static const unsigned int channels_2_6_8[] = { 2, 6, 8 }; -static unsigned int channels_2_8[] = { +static const unsigned int channels_2_8[] = { 2, 8 }; -static struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = { +static const struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = { .count = ARRAY_SIZE(channels_2_6_8), .list = channels_2_6_8, .mask = 0, }; -static struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = { +static const struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = { .count = ARRAY_SIZE(channels_2_8), .list = channels_2_8, .mask = 0, @@ -2807,7 +2807,7 @@ static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct hdmi_spec *spec = codec->spec; - struct snd_pcm_hw_constraint_list *hw_constraints_channels = NULL; + const struct snd_pcm_hw_constraint_list *hw_constraints_channels = NULL; switch (codec->preset->vendor_id) { case 0x10de0002: diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index ffda38c45509..f63acb1b965c 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -169,8 +169,8 @@ static int si3054_pcm_open(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) { - static unsigned int rates[] = { 8000, 9600, 16000 }; - static struct snd_pcm_hw_constraint_list hw_constraints_rates = { + static const unsigned int rates[] = { 8000, 9600, 16000 }; + static const struct snd_pcm_hw_constraint_list hw_constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, From 5cf30ddf81bd0074eb0d867fc99a6f52997db71b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:20:40 +0200 Subject: [PATCH 226/418] ALSA: ice1712: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1712.c | 4 ++-- sound/pci/ice1712/ice1712.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 6b650ab2a084..0e66afa403a3 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -932,10 +932,10 @@ static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device) * PCM code - professional part (multitrack) */ -static unsigned int rates[] = { 8000, 9600, 11025, 12000, 16000, 22050, 24000, +static const unsigned int rates[] = { 8000, 9600, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000 }; -static struct snd_pcm_hw_constraint_list hw_constraints_rates = { +static const struct snd_pcm_hw_constraint_list hw_constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 58f8f2ae758d..5cfba09c9761 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -348,7 +348,7 @@ struct snd_ice1712 { struct mutex open_mutex; struct snd_pcm_substream *pcm_reserved[4]; - struct snd_pcm_hw_constraint_list *hw_rates; /* card-specific rate constraints */ + const struct snd_pcm_hw_constraint_list *hw_rates; /* card-specific rate constraints */ unsigned int akm_codecs; struct snd_akm4xxx *akm; From 965f19bed24d240c845401015e42ad5cb0cca00c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:20:52 +0200 Subject: [PATCH 227/418] ALSA: ice1724: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1724.c | 8 ++++---- sound/pci/ice1712/juli.c | 6 +++--- sound/pci/ice1712/maya44.c | 4 ++-- sound/pci/ice1712/quartet.c | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 785188140f6b..057c2f394ea7 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -521,25 +521,25 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) * PCM code - professional part (multitrack) */ -static unsigned int rates[] = { +static const unsigned int rates[] = { 8000, 9600, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000, }; -static struct snd_pcm_hw_constraint_list hw_constraints_rates_96 = { +static const struct snd_pcm_hw_constraint_list hw_constraints_rates_96 = { .count = ARRAY_SIZE(rates) - 2, /* up to 96000 */ .list = rates, .mask = 0, }; -static struct snd_pcm_hw_constraint_list hw_constraints_rates_48 = { +static const struct snd_pcm_hw_constraint_list hw_constraints_rates_48 = { .count = ARRAY_SIZE(rates) - 5, /* up to 48000 */ .list = rates, .mask = 0, }; -static struct snd_pcm_hw_constraint_list hw_constraints_rates_192 = { +static const struct snd_pcm_hw_constraint_list hw_constraints_rates_192 = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index 4f0213427152..5bb146703738 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -133,19 +133,19 @@ struct juli_spec { /* * Initial setup of the conversion array GPIO <-> rate */ -static unsigned int juli_rates[] = { +static const unsigned int juli_rates[] = { 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000, }; -static unsigned int gpio_vals[] = { +static const unsigned int gpio_vals[] = { GPIO_RATE_16000, GPIO_RATE_22050, GPIO_RATE_24000, GPIO_RATE_32000, GPIO_RATE_44100, GPIO_RATE_48000, GPIO_RATE_64000, GPIO_RATE_88200, GPIO_RATE_96000, GPIO_RATE_176400, GPIO_RATE_192000, }; -static struct snd_pcm_hw_constraint_list juli_rates_info = { +static const struct snd_pcm_hw_constraint_list juli_rates_info = { .count = ARRAY_SIZE(juli_rates), .list = juli_rates, .mask = 0, diff --git a/sound/pci/ice1712/maya44.c b/sound/pci/ice1712/maya44.c index 7de25c4807fd..0e30419f6bbd 100644 --- a/sound/pci/ice1712/maya44.c +++ b/sound/pci/ice1712/maya44.c @@ -661,12 +661,12 @@ static void set_rate(struct snd_ice1712 *ice, unsigned int rate) * supported sample rates (to override the default one) */ -static unsigned int rates[] = { +static const unsigned int rates[] = { 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000 }; /* playback rates: 32..192 kHz */ -static struct snd_pcm_hw_constraint_list dac_rates = { +static const struct snd_pcm_hw_constraint_list dac_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0 diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c index 7c387b04067e..f1b3732cc6d2 100644 --- a/sound/pci/ice1712/quartet.c +++ b/sound/pci/ice1712/quartet.c @@ -231,17 +231,17 @@ static char *get_binary(char *buffer, int value) /* * Initial setup of the conversion array GPIO <-> rate */ -static unsigned int qtet_rates[] = { +static const unsigned int qtet_rates[] = { 44100, 48000, 88200, 96000, 176400, 192000, }; -static unsigned int cks_vals[] = { +static const unsigned int cks_vals[] = { CPLD_CKS_44100HZ, CPLD_CKS_48000HZ, CPLD_CKS_88200HZ, CPLD_CKS_96000HZ, CPLD_CKS_176400HZ, CPLD_CKS_192000HZ, }; -static struct snd_pcm_hw_constraint_list qtet_rates_info = { +static const struct snd_pcm_hw_constraint_list qtet_rates_info = { .count = ARRAY_SIZE(qtet_rates), .list = qtet_rates, .mask = 0, From 0f470ce622230b7ebfb88ec8db8676e278867046 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:21:31 +0200 Subject: [PATCH 228/418] ALSA: intel8x0: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 12 ++++++------ sound/pci/intel8x0m.c | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 6d17b171c17b..a8d7092e93dd 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1136,31 +1136,31 @@ static struct snd_pcm_hardware snd_intel8x0_stream = .fifo_size = 0, }; -static unsigned int channels4[] = { +static const unsigned int channels4[] = { 2, 4, }; -static struct snd_pcm_hw_constraint_list hw_constraints_channels4 = { +static const struct snd_pcm_hw_constraint_list hw_constraints_channels4 = { .count = ARRAY_SIZE(channels4), .list = channels4, .mask = 0, }; -static unsigned int channels6[] = { +static const unsigned int channels6[] = { 2, 4, 6, }; -static struct snd_pcm_hw_constraint_list hw_constraints_channels6 = { +static const struct snd_pcm_hw_constraint_list hw_constraints_channels6 = { .count = ARRAY_SIZE(channels6), .list = channels6, .mask = 0, }; -static unsigned int channels8[] = { +static const unsigned int channels8[] = { 2, 4, 6, 8, }; -static struct snd_pcm_hw_constraint_list hw_constraints_channels8 = { +static const struct snd_pcm_hw_constraint_list hw_constraints_channels8 = { .count = ARRAY_SIZE(channels8), .list = channels8, .mask = 0, diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 1bc98c867133..18ff668ce7a5 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -635,8 +635,8 @@ static struct snd_pcm_hardware snd_intel8x0m_stream = static int snd_intel8x0m_pcm_open(struct snd_pcm_substream *substream, struct ichdev *ichdev) { - static unsigned int rates[] = { 8000, 9600, 12000, 16000 }; - static struct snd_pcm_hw_constraint_list hw_constraints_rates = { + static const unsigned int rates[] = { 8000, 9600, 12000, 16000 }; + static const struct snd_pcm_hw_constraint_list hw_constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, From 3f2bdc45f36df349d9f9984252b612c57a8b1a73 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:21:49 +0200 Subject: [PATCH 229/418] ALSA: nm256: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/nm256/nm256.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 63f0985dae27..0ef8054c3936 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -398,10 +398,10 @@ snd_nm256_load_coefficient(struct nm256 *chip, int stream, int number) /* The actual rates supported by the card. */ -static unsigned int samplerates[8] = { +static const unsigned int samplerates[8] = { 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, }; -static struct snd_pcm_hw_constraint_list constraints_rates = { +static const struct snd_pcm_hw_constraint_list constraints_rates = { .count = ARRAY_SIZE(samplerates), .list = samplerates, .mask = 0, From a7f8009df4078fa28eb26f6caac89da60fd94a16 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:22:02 +0200 Subject: [PATCH 230/418] ALSA: rme32: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/rme32.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 67d48c8869e9..e4cdef94e4a2 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -836,10 +836,9 @@ static irqreturn_t snd_rme32_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static unsigned int period_bytes[] = { RME32_BLOCK_SIZE }; +static const unsigned int period_bytes[] = { RME32_BLOCK_SIZE }; - -static struct snd_pcm_hw_constraint_list hw_constraints_period_bytes = { +static const struct snd_pcm_hw_constraint_list hw_constraints_period_bytes = { .count = ARRAY_SIZE(period_bytes), .list = period_bytes, .mask = 0 From 84e7b99865329394177db0d2a506c22b1c02dea1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:22:10 +0200 Subject: [PATCH 231/418] ALSA: rme96: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/rme96.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 24f1349a8e1b..2e19ba55e754 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -1163,9 +1163,9 @@ snd_rme96_interrupt(int irq, return IRQ_HANDLED; } -static unsigned int period_bytes[] = { RME96_SMALL_BLOCK_SIZE, RME96_LARGE_BLOCK_SIZE }; +static const unsigned int period_bytes[] = { RME96_SMALL_BLOCK_SIZE, RME96_LARGE_BLOCK_SIZE }; -static struct snd_pcm_hw_constraint_list hw_constraints_period_bytes = { +static const struct snd_pcm_hw_constraint_list hw_constraints_period_bytes = { .count = ARRAY_SIZE(period_bytes), .list = period_bytes, .mask = 0 From 4640c034ebf59f7188dd1fb661e6be80e5598d0d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:22:26 +0200 Subject: [PATCH 232/418] ALSA: hdsp: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdsp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index b00009644e0e..fe36d44d16c6 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -4270,17 +4270,17 @@ static struct snd_pcm_hardware snd_hdsp_capture_subinfo = .fifo_size = 0 }; -static unsigned int hdsp_period_sizes[] = { 64, 128, 256, 512, 1024, 2048, 4096, 8192 }; +static const unsigned int hdsp_period_sizes[] = { 64, 128, 256, 512, 1024, 2048, 4096, 8192 }; -static struct snd_pcm_hw_constraint_list hdsp_hw_constraints_period_sizes = { +static const struct snd_pcm_hw_constraint_list hdsp_hw_constraints_period_sizes = { .count = ARRAY_SIZE(hdsp_period_sizes), .list = hdsp_period_sizes, .mask = 0 }; -static unsigned int hdsp_9632_sample_rates[] = { 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 }; +static const unsigned int hdsp_9632_sample_rates[] = { 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 }; -static struct snd_pcm_hw_constraint_list hdsp_hw_constraints_9632_sample_rates = { +static const struct snd_pcm_hw_constraint_list hdsp_hw_constraints_9632_sample_rates = { .count = ARRAY_SIZE(hdsp_9632_sample_rates), .list = hdsp_9632_sample_rates, .mask = 0 From bdf84db72fe78a411aacd1a93375978c2941945f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:22:35 +0200 Subject: [PATCH 233/418] ALSA: hdspm: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index c48acdb0e186..254c3d040118 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -6040,11 +6040,11 @@ static int snd_hdspm_hw_rule_out_channels(struct snd_pcm_hw_params *params, } -static unsigned int hdspm_aes32_sample_rates[] = { +static const unsigned int hdspm_aes32_sample_rates[] = { 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 }; -static struct snd_pcm_hw_constraint_list +static const struct snd_pcm_hw_constraint_list hdspm_hw_constraints_aes32_sample_rates = { .count = ARRAY_SIZE(hdspm_aes32_sample_rates), .list = hdspm_aes32_sample_rates, From f9fee5534dedd15e69572d2fc2f050e4be3b1d6a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:22:43 +0200 Subject: [PATCH 234/418] ALSA: rme9652: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/rme9652/rme9652.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 59684bf5cac0..150d08898db8 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -2228,9 +2228,9 @@ static struct snd_pcm_hardware snd_rme9652_capture_subinfo = .fifo_size = 0, }; -static unsigned int period_sizes[] = { 64, 128, 256, 512, 1024, 2048, 4096, 8192 }; +static const unsigned int period_sizes[] = { 64, 128, 256, 512, 1024, 2048, 4096, 8192 }; -static struct snd_pcm_hw_constraint_list hw_constraints_period_sizes = { +static const struct snd_pcm_hw_constraint_list hw_constraints_period_sizes = { .count = ARRAY_SIZE(period_sizes), .list = period_sizes, .mask = 0 From de900b182ef1826e887c4458d7af0696f08fcc4b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:22:55 +0200 Subject: [PATCH 235/418] ALSA: sonicvibes: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/sonicvibes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 8e3d4ec39c35..784d762f18a7 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -248,13 +248,13 @@ static const struct pci_device_id snd_sonic_ids[] = { MODULE_DEVICE_TABLE(pci, snd_sonic_ids); -static struct snd_ratden sonicvibes_adc_clock = { +static const struct snd_ratden sonicvibes_adc_clock = { .num_min = 4000 * 65536, .num_max = 48000UL * 65536, .num_step = 1, .den = 65536, }; -static struct snd_pcm_hw_constraint_ratdens snd_sonicvibes_hw_constraints_adc_clock = { +static const struct snd_pcm_hw_constraint_ratdens snd_sonicvibes_hw_constraints_adc_clock = { .nrats = 1, .rats = &sonicvibes_adc_clock, }; From fbc57b2a3e74fd56581bc2acacade9eac22544bd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:23:13 +0200 Subject: [PATCH 236/418] ALSA: via82xx: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/pci/via82xx.c | 4 ++-- sound/pci/via82xx_modem.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index b6c84d15b10b..c767b8664359 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -1286,10 +1286,10 @@ static int snd_via8233_multi_open(struct snd_pcm_substream *substream) /* channels constraint for VIA8233A * 3 and 5 channels are not supported */ - static unsigned int channels[] = { + static const unsigned int channels[] = { 1, 2, 4, 6 }; - static struct snd_pcm_hw_constraint_list hw_constraints_channels = { + static const struct snd_pcm_hw_constraint_list hw_constraints_channels = { .count = ARRAY_SIZE(channels), .list = channels, .mask = 0, diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 2f6d40f10618..55f79b2599e7 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -744,8 +744,8 @@ static int snd_via82xx_modem_pcm_open(struct via82xx_modem *chip, struct viadev { struct snd_pcm_runtime *runtime = substream->runtime; int err; - static unsigned int rates[] = { 8000, 9600, 12000, 16000 }; - static struct snd_pcm_hw_constraint_list hw_constraints_rates = { + static const unsigned int rates[] = { 8000, 9600, 12000, 16000 }; + static const struct snd_pcm_hw_constraint_list hw_constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, From 4e4b7eaa624d08433ab571920d50b6e14a70ab90 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jun 2017 14:23:22 +0200 Subject: [PATCH 237/418] ALSA: sparc: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai --- sound/sparc/cs4231.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index 30bdc971883b..3d7d425fbd24 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -200,12 +200,12 @@ static unsigned char freq_bits[14] = { /* 48000 */ 0x0C | CS4231_XTAL1 }; -static unsigned int rates[14] = { +static const unsigned int rates[14] = { 5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050, 27042, 32000, 33075, 37800, 44100, 48000 }; -static struct snd_pcm_hw_constraint_list hw_constraints_rates = { +static const struct snd_pcm_hw_constraint_list hw_constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, }; From 60f96aaecb19ca294addfff0d2d0335293f3c379 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 9 Jun 2017 21:46:48 +0900 Subject: [PATCH 238/418] ALSA: pcm: localize snd_pcm_hw_params_choose() As of v4.12, snd_pcm_hw_params_choose() is just called in a process context of ioctl(2) with SNDRV_PCM_IOCTL_HW_PARAMS. The function locates in a different file, which has no tracepoints. This commit moves the function to a file with the tracepoints for later commit. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 40 ---------------------------------------- sound/core/pcm_local.h | 3 --- sound/core/pcm_native.c | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 43 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 95b8ef15029f..9dc7bbfe8853 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1700,46 +1700,6 @@ int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, EXPORT_SYMBOL(snd_pcm_hw_param_last); -/** - * snd_pcm_hw_param_choose - choose a configuration defined by @params - * @pcm: PCM instance - * @params: the hw_params instance - * - * Choose one configuration from configuration space defined by @params. - * The configuration chosen is that obtained fixing in this order: - * first access, first format, first subformat, min channels, - * min rate, min period time, max buffer size, min tick time - * - * Return: Zero if successful, or a negative error code on failure. - */ -int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, - struct snd_pcm_hw_params *params) -{ - static const int vars[] = { - SNDRV_PCM_HW_PARAM_ACCESS, - SNDRV_PCM_HW_PARAM_FORMAT, - SNDRV_PCM_HW_PARAM_SUBFORMAT, - SNDRV_PCM_HW_PARAM_CHANNELS, - SNDRV_PCM_HW_PARAM_RATE, - SNDRV_PCM_HW_PARAM_PERIOD_TIME, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - SNDRV_PCM_HW_PARAM_TICK_TIME, - -1 - }; - const int *v; - int err; - - for (v = vars; *v != -1; v++) { - if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE) - err = snd_pcm_hw_param_first(pcm, params, *v, NULL); - else - err = snd_pcm_hw_param_last(pcm, params, *v, NULL); - if (snd_BUG_ON(err < 0)) - return err; - } - return 0; -} - static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream, void *arg) { diff --git a/sound/core/pcm_local.h b/sound/core/pcm_local.h index 34c66decaaf2..e4bf2af62b02 100644 --- a/sound/core/pcm_local.h +++ b/sound/core/pcm_local.h @@ -24,9 +24,6 @@ void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k, int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream); int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream); -int snd_pcm_hw_params_choose(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params); - int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var, u_int32_t mask); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 3293db0172db..8d9d181b1c03 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -571,6 +571,46 @@ static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream, #endif } +/** + * snd_pcm_hw_param_choose - choose a configuration defined by @params + * @pcm: PCM instance + * @params: the hw_params instance + * + * Choose one configuration from configuration space defined by @params. + * The configuration chosen is that obtained fixing in this order: + * first access, first format, first subformat, min channels, + * min rate, min period time, max buffer size, min tick time + * + * Return: Zero if successful, or a negative error code on failure. + */ +static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, + struct snd_pcm_hw_params *params) +{ + static const int vars[] = { + SNDRV_PCM_HW_PARAM_ACCESS, + SNDRV_PCM_HW_PARAM_FORMAT, + SNDRV_PCM_HW_PARAM_SUBFORMAT, + SNDRV_PCM_HW_PARAM_CHANNELS, + SNDRV_PCM_HW_PARAM_RATE, + SNDRV_PCM_HW_PARAM_PERIOD_TIME, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + SNDRV_PCM_HW_PARAM_TICK_TIME, + -1 + }; + const int *v; + int err; + + for (v = vars; *v != -1; v++) { + if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE) + err = snd_pcm_hw_param_first(pcm, params, *v, NULL); + else + err = snd_pcm_hw_param_last(pcm, params, *v, NULL); + if (snd_BUG_ON(err < 0)) + return err; + } + return 0; +} + static int snd_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { From 7b8a54aff30e96b980aa65b0b2e4ebdffcd57196 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 9 Jun 2017 21:46:49 +0900 Subject: [PATCH 239/418] ALSA: pcm: add tracepoints for final selection process of hardware parameters Results of ioctl(2) with SNDRV_PCM_IOCTL_HW_REFINE and SNDRV_PCM_IOCTL_HW_PARAMS are different, because the latter has single value for several parameters; e.g. channels of PCM substream. Selection of the single value is done independently of application of constraints. It's helpful for developers to trace the selection process. This commit adds tracepoints to snd_pcm_hw_params_choose() for the purpose. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 8d9d181b1c03..076187ae8859 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -598,16 +598,38 @@ static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, -1 }; const int *v; + struct snd_mask old_mask; + struct snd_interval old_interval; int err; for (v = vars; *v != -1; v++) { + /* Keep old parameter to trace. */ + if (trace_hw_mask_param_enabled()) { + if (hw_is_mask(*v)) + old_mask = *hw_param_mask(params, *v); + } + if (trace_hw_interval_param_enabled()) { + if (hw_is_interval(*v)) + old_interval = *hw_param_interval(params, *v); + } if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE) err = snd_pcm_hw_param_first(pcm, params, *v, NULL); else err = snd_pcm_hw_param_last(pcm, params, *v, NULL); if (snd_BUG_ON(err < 0)) return err; + + /* Trace the parameter. */ + if (hw_is_mask(*v)) { + trace_hw_mask_param(pcm, *v, 0, &old_mask, + hw_param_mask(params, *v)); + } + if (hw_is_interval(*v)) { + trace_hw_interval_param(pcm, *v, 0, &old_interval, + hw_param_interval(params, *v)); + } } + return 0; } From 6baca010c71176f406299ea1949e721ab995ff01 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 9 Jun 2017 21:46:50 +0900 Subject: [PATCH 240/418] ALSA: pcm: use friendly name for id of PCM substream in trace print Use the same print format of snd_pcm_debug_name() for userspace tracing program. Suggested-by: Takashi Iwai Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_param_trace.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/core/pcm_param_trace.h b/sound/core/pcm_param_trace.h index 872922326b38..86c8d658a25c 100644 --- a/sound/core/pcm_param_trace.h +++ b/sound/core/pcm_param_trace.h @@ -49,11 +49,11 @@ TRACE_EVENT(hw_mask_param, memcpy(__entry->prev_bits, prev->bits, sizeof(__u32) * 8); memcpy(__entry->curr_bits, curr->bits, sizeof(__u32) * 8); ), - TP_printk("%d,%d,%d,%d %03d/%03d %s %08x%08x%08x%08x %08x%08x%08x%08x", + TP_printk("pcmC%dD%d%s:%d %03d/%03d %s %08x%08x%08x%08x %08x%08x%08x%08x", __entry->card, __entry->device, + __entry->direction ? "c" : "p", __entry->subdevice, - __entry->direction, __entry->index, __entry->total, __print_symbolic(__entry->type, hw_param_labels), @@ -109,11 +109,11 @@ TRACE_EVENT(hw_interval_param, __entry->curr_integer = curr->integer; __entry->curr_empty = curr->empty; ), - TP_printk("%d,%d,%d,%d %03d/%03d %s %d %d %s%u %u%s %d %d %s%u %u%s", + TP_printk("pcmC%dD%d%s:%d %03d/%03d %s %d %d %s%u %u%s %d %d %s%u %u%s", __entry->card, __entry->device, + __entry->direction ? "c" : "p", __entry->subdevice, - __entry->direction, __entry->index, __entry->total, __print_symbolic(__entry->type, hw_param_labels), From eb3b705aaed9cab7efef8c905eda919b5fd902b9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 9 Jun 2017 13:56:05 +0200 Subject: [PATCH 241/418] ALSA: Make CONFIG_SND_OSSEMUL user-selectable Currently CONFIG_SND_OSSEMUL is selected by each config like CONFIG_SND_PCM_OSS. But, as see in the raw MIDI code that is built conditionally with CONFIG_SND_OSSEMUL, we should rather make CONFIG_SND_OSSEMUL user-selectable as the top kconfig item, and leave the rest depending on it. Signed-off-by: Takashi Iwai --- sound/core/Kconfig | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 9749f9e8b45c..3a9afc520d4e 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -59,12 +59,14 @@ config SND_SEQ_DUMMY will be called snd-seq-dummy. config SND_OSSEMUL + bool "Enable OSS Emulation" select SOUND_OSS_CORE - bool + help + This option enables the build of OSS emulation layer. config SND_MIXER_OSS tristate "OSS Mixer API" - select SND_OSSEMUL + depends on SND_OSSEMUL help To enable OSS mixer API emulation (/dev/mixer*), say Y here and read . @@ -76,7 +78,7 @@ config SND_MIXER_OSS config SND_PCM_OSS tristate "OSS PCM (digital audio) API" - select SND_OSSEMUL + depends on SND_OSSEMUL select SND_PCM help To enable OSS digital audio (PCM) emulation (/dev/dsp*), say Y @@ -110,7 +112,7 @@ config SND_PCM_TIMER config SND_SEQUENCER_OSS bool "OSS Sequencer API" depends on SND_SEQUENCER - select SND_OSSEMUL + depends on SND_OSSEMUL help Say Y here to enable OSS sequencer emulation (both /dev/sequencer and /dev/music interfaces). From 69beca69d68b69b38c2610b8b5fd2e27a40d441b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 9 Jun 2017 15:06:54 +0300 Subject: [PATCH 242/418] ASoC: omap-mcbsp: Use sysfs_match_string() helper Use sysfs_match_string() helper instead of open coded variant. Cc: Peter Ujfalusi Cc: Jarkko Nikula Cc: Mark Brown Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- sound/soc/omap/mcbsp.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c index 06fec5699cc8..7a54e3083203 100644 --- a/sound/soc/omap/mcbsp.c +++ b/sound/soc/omap/mcbsp.c @@ -835,15 +835,11 @@ static ssize_t dma_op_mode_store(struct device *dev, const char *buf, size_t size) { struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); - const char * const *s; - int i = 0; + int i; - for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) - if (sysfs_streq(buf, *s)) - break; - - if (i == ARRAY_SIZE(dma_op_modes)) - return -EINVAL; + i = sysfs_match_string(dma_op_modes, buf); + if (i < 0) + return i; spin_lock_irq(&mcbsp->lock); if (!mcbsp->free) { From b5f2a487f524e6eeeec38651e7b58760ebfd843e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 9 Jun 2017 15:01:21 +0800 Subject: [PATCH 243/418] ASoC: ak4613: Fix out of bounds array access for ak4613_iface Signed-off-by: Axel Lin Acked-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/ak4613.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index b2dfddead227..987918628d5b 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -345,7 +345,7 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, if (ak4613_dai_fmt_matching(priv->iface, is_play, fmt, width)) iface = priv->iface; } else { - for (i = ARRAY_SIZE(ak4613_iface); i >= 0; i--) { + for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) { if (!ak4613_dai_fmt_matching(ak4613_iface + i, is_play, fmt, width)) From ebd259d33a900b28ef774c4c26e8ce6e2baea7e5 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 9 Jun 2017 15:43:23 +0100 Subject: [PATCH 244/418] ASoC: topology: Allow bespoke configuration post widget creation Current topology only allows for widget configuration before the widget is registered. This patch also allows further configuration and usage after registration is complete. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/soc-topology.h | 3 +++ sound/soc/soc-topology.c | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index b8da221615e0..f552c3f56368 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -118,6 +118,9 @@ struct snd_soc_tplg_ops { int (*widget_load)(struct snd_soc_component *, struct snd_soc_dapm_widget *, struct snd_soc_tplg_dapm_widget *); + int (*widget_ready)(struct snd_soc_component *, + struct snd_soc_dapm_widget *, + struct snd_soc_tplg_dapm_widget *); int (*widget_unload)(struct snd_soc_component *, struct snd_soc_dobj *); diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index f4ec236a418e..12e189701924 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -344,6 +344,17 @@ static int soc_tplg_widget_load(struct soc_tplg *tplg, return 0; } +/* optionally pass new dynamic widget to component driver. This is mainly for + * external widgets where we can assign private data/ops */ +static int soc_tplg_widget_ready(struct soc_tplg *tplg, + struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w) +{ + if (tplg->comp && tplg->ops && tplg->ops->widget_ready) + return tplg->ops->widget_ready(tplg->comp, w, tplg_w); + + return 0; +} + /* pass DAI configurations to component driver for extra initialization */ static int soc_tplg_dai_load(struct soc_tplg *tplg, struct snd_soc_dai_driver *dai_drv) @@ -1579,8 +1590,16 @@ widget: widget->dobj.ops = tplg->ops; widget->dobj.index = tplg->index; list_add(&widget->dobj.list, &tplg->comp->dobj_list); + + ret = soc_tplg_widget_ready(tplg, widget, w); + if (ret < 0) + goto ready_err; + return 0; +ready_err: + snd_soc_tplg_widget_remove(widget); + snd_soc_dapm_free_widget(widget); hdr_err: kfree(template.sname); err: From 63ddf5dc9cc77963a993921995d9e390095dc3d4 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 9 Jun 2017 19:09:44 +0200 Subject: [PATCH 245/418] ASoC: samsung: Odroid DT binding documentation corrections This patch removes unused and undocumented samsung,cpu-dai, samsung,codec-dai properties from the dts example and moves sub-nodes' description to a separate section. Suggested-by: Rob Herring Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/samsung,odroid.txt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/samsung,odroid.txt b/Documentation/devicetree/bindings/sound/samsung,odroid.txt index c1ac70cb0afb..c30934dd975b 100644 --- a/Documentation/devicetree/bindings/sound/samsung,odroid.txt +++ b/Documentation/devicetree/bindings/sound/samsung,odroid.txt @@ -5,11 +5,6 @@ Required properties: - compatible - "samsung,odroidxu3-audio" - for Odroid XU3 board, "samsung,odroidxu4-audio" - for Odroid XU4 board - model - the user-visible name of this sound complex - - 'cpu' subnode with a 'sound-dai' property containing the phandle of the I2S - controller - - 'codec' subnode with a 'sound-dai' property containing list of phandles - to the CODEC nodes, first entry must be corresponding to the MAX98090 - CODEC and the second entry must be the phandle of the HDMI IP block node - clocks - should contain entries matching clock names in the clock-names property - clock-names - should contain following entries: @@ -32,12 +27,18 @@ Required properties: For Odroid XU4: no entries +Required sub-nodes: + + - 'cpu' subnode with a 'sound-dai' property containing the phandle of the I2S + controller + - 'codec' subnode with a 'sound-dai' property containing list of phandles + to the CODEC nodes, first entry must be corresponding to the MAX98090 + CODEC and the second entry must be the phandle of the HDMI IP block node + Example: sound { compatible = "samsung,odroidxu3-audio"; - samsung,cpu-dai = <&i2s0>; - samsung,codec-dai = <&max98090>; model = "Odroid-XU3"; samsung,audio-routing = "Headphone Jack", "HPL", From 3d774d5ef066971aee1839150bf47d100d8e43d3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 9 Jun 2017 14:06:46 +0200 Subject: [PATCH 246/418] ALSA: seq: Allow the tristate build of OSS emulation Currently OSS sequencer emulation is tied with ALSA sequencer core, both are built in the same level; i.e. when CONFIG_SND_SEQUENCER=y, the OSS sequencer emulation is also always built-in, even though the functionality can be built as an individual module. This patch changes the rule and allows users to build snd-seq-oss module while others are built-in. Essentially, it's just a few simple changes in Kconfig and Makefile. Some driver codes like opl3 need to convert from the simple ifdef to IS_ENABLED(). But that's all. You might wonder how about the dependency: right, it can be messy, but it still works. Since we rewrote the sequencer binding with the standard bus, the driver can be bound at any time on demand. So, the synthesizer driver module can be loaded individually from the OSS emulation core before/after it. Signed-off-by: Takashi Iwai --- include/sound/emux_synth.h | 8 +++----- include/sound/opl3.h | 4 +--- sound/core/Kconfig | 2 +- sound/core/seq/Makefile | 7 +++---- sound/core/seq/oss/Makefile | 2 +- sound/drivers/opl3/opl3_seq.c | 4 ++-- sound/drivers/opl3/opl3_voice.h | 5 ++++- sound/isa/sb/emu8000_callback.c | 6 +++--- sound/synth/emux/emux.c | 6 +++--- sound/synth/emux/emux_effect.c | 2 +- sound/synth/emux/emux_oss.c | 4 ---- 11 files changed, 22 insertions(+), 28 deletions(-) diff --git a/include/sound/emux_synth.h b/include/sound/emux_synth.h index a0a40b74bf13..19a0cb561ffc 100644 --- a/include/sound/emux_synth.h +++ b/include/sound/emux_synth.h @@ -25,9 +25,7 @@ #include #include #include -#ifdef CONFIG_SND_SEQUENCER_OSS #include -#endif #include #include @@ -66,7 +64,7 @@ struct snd_emux_operators { const void __user *data, long count); void (*sysex)(struct snd_emux *emu, char *buf, int len, int parsed, struct snd_midi_channel_set *chset); -#ifdef CONFIG_SND_SEQUENCER_OSS +#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) int (*oss_ioctl)(struct snd_emux *emu, int cmd, int p1, int p2); #endif }; @@ -129,7 +127,7 @@ struct snd_emux { struct snd_info_entry *proc; #endif -#ifdef CONFIG_SND_SEQUENCER_OSS +#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) struct snd_seq_device *oss_synth; #endif }; @@ -150,7 +148,7 @@ struct snd_emux_port { #ifdef SNDRV_EMUX_USE_RAW_EFFECT struct snd_emux_effect_table *effect; #endif -#ifdef CONFIG_SND_SEQUENCER_OSS +#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) struct snd_seq_oss_arg *oss_arg; #endif }; diff --git a/include/sound/opl3.h b/include/sound/opl3.h index 5a87641c6ae4..a4a593590cff 100644 --- a/include/sound/opl3.h +++ b/include/sound/opl3.h @@ -55,10 +55,8 @@ #include #include #include -#ifdef CONFIG_SND_SEQUENCER_OSS #include #include -#endif #include #include @@ -330,7 +328,7 @@ struct snd_opl3 { struct snd_seq_device *seq_dev; /* sequencer device */ struct snd_midi_channel_set * chset; -#ifdef CONFIG_SND_SEQUENCER_OSS +#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) struct snd_seq_device *oss_seq_dev; /* OSS sequencer device */ struct snd_midi_channel_set * oss_chset; #endif diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 3a9afc520d4e..d64dbee36986 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -110,7 +110,7 @@ config SND_PCM_TIMER footprint, about 20KB on x86_64 platform. config SND_SEQUENCER_OSS - bool "OSS Sequencer API" + tristate "OSS Sequencer API" depends on SND_SEQUENCER depends on SND_OSSEMUL help diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile index b65fa5a1943b..3283b055e5ff 100644 --- a/sound/core/seq/Makefile +++ b/sound/core/seq/Makefile @@ -15,10 +15,9 @@ snd-seq-dummy-objs := seq_dummy.o snd-seq-virmidi-objs := seq_virmidi.o obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o snd-seq-device.o -ifeq ($(CONFIG_SND_SEQUENCER_OSS),y) - obj-$(CONFIG_SND_SEQUENCER) += snd-seq-midi-event.o - obj-$(CONFIG_SND_SEQUENCER) += oss/ -endif +obj-$(CONFIG_SND_SEQUENCER_OSS) += snd-seq-midi-event.o +obj-$(CONFIG_SND_SEQUENCER_OSS) += oss/ + obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o # Toplevel Module Dependency diff --git a/sound/core/seq/oss/Makefile b/sound/core/seq/oss/Makefile index b38406b8463c..4ea4e3eea6b7 100644 --- a/sound/core/seq/oss/Makefile +++ b/sound/core/seq/oss/Makefile @@ -7,4 +7,4 @@ snd-seq-oss-objs := seq_oss.o seq_oss_init.o seq_oss_timer.o seq_oss_ioctl.o \ seq_oss_event.o seq_oss_rw.o seq_oss_synth.o \ seq_oss_midi.o seq_oss_readq.o seq_oss_writeq.o -obj-$(CONFIG_SND_SEQUENCER) += snd-seq-oss.o +obj-$(CONFIG_SND_SEQUENCER_OSS) += snd-seq-oss.o diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c index fdae5d7f421f..d3e91be8b23a 100644 --- a/sound/drivers/opl3/opl3_seq.c +++ b/sound/drivers/opl3/opl3_seq.c @@ -252,7 +252,7 @@ static int snd_opl3_seq_probe(struct device *_dev) spin_lock_init(&opl3->sys_timer_lock); opl3->sys_timer_status = 0; -#ifdef CONFIG_SND_SEQUENCER_OSS +#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) snd_opl3_init_seq_oss(opl3, name); #endif return 0; @@ -267,7 +267,7 @@ static int snd_opl3_seq_remove(struct device *_dev) if (opl3 == NULL) return -EINVAL; -#ifdef CONFIG_SND_SEQUENCER_OSS +#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) snd_opl3_free_seq_oss(opl3); #endif if (opl3->seq_client >= 0) { diff --git a/sound/drivers/opl3/opl3_voice.h b/sound/drivers/opl3/opl3_voice.h index a371c075ac87..eaef435e0528 100644 --- a/sound/drivers/opl3/opl3_voice.h +++ b/sound/drivers/opl3/opl3_voice.h @@ -44,9 +44,12 @@ void snd_opl3_load_drums(struct snd_opl3 *opl3); void snd_opl3_drum_switch(struct snd_opl3 *opl3, int note, int on_off, int vel, struct snd_midi_channel *chan); /* Prototypes for opl3_oss.c */ -#ifdef CONFIG_SND_SEQUENCER_OSS +#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) void snd_opl3_init_seq_oss(struct snd_opl3 *opl3, char *name); void snd_opl3_free_seq_oss(struct snd_opl3 *opl3); +#else +#define snd_opl3_init_seq_oss(opl3, name) /* NOP */ +#define snd_opl3_free_seq_oss(opl3) /* NOP */ #endif #endif diff --git a/sound/isa/sb/emu8000_callback.c b/sound/isa/sb/emu8000_callback.c index 72a9ac5efb40..d28d712f99f4 100644 --- a/sound/isa/sb/emu8000_callback.c +++ b/sound/isa/sb/emu8000_callback.c @@ -36,7 +36,7 @@ static void reset_voice(struct snd_emux *emu, int ch); static void terminate_voice(struct snd_emux_voice *vp); static void sysex(struct snd_emux *emu, char *buf, int len, int parsed, struct snd_midi_channel_set *chset); -#ifdef CONFIG_SND_SEQUENCER_OSS +#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) static int oss_ioctl(struct snd_emux *emu, int cmd, int p1, int p2); #endif static int load_fx(struct snd_emux *emu, int type, int mode, @@ -76,7 +76,7 @@ static struct snd_emux_operators emu8000_ops = { .sample_reset = snd_emu8000_sample_reset, .load_fx = load_fx, .sysex = sysex, -#ifdef CONFIG_SND_SEQUENCER_OSS +#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) .oss_ioctl = oss_ioctl, #endif }; @@ -477,7 +477,7 @@ sysex(struct snd_emux *emu, char *buf, int len, int parsed, struct snd_midi_chan } -#ifdef CONFIG_SND_SEQUENCER_OSS +#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) /* * OSS ioctl callback */ diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c index 9312cd8a6fdd..b9981e8c0027 100644 --- a/sound/synth/emux/emux.c +++ b/sound/synth/emux/emux.c @@ -47,7 +47,7 @@ int snd_emux_new(struct snd_emux **remu) mutex_init(&emu->register_mutex); emu->client = -1; -#ifdef CONFIG_SND_SEQUENCER_OSS +#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) emu->oss_synth = NULL; #endif emu->max_voices = 0; @@ -123,7 +123,7 @@ int snd_emux_register(struct snd_emux *emu, struct snd_card *card, int index, ch snd_emux_init_voices(emu); snd_emux_init_seq(emu, card, index); -#ifdef CONFIG_SND_SEQUENCER_OSS +#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) snd_emux_init_seq_oss(emu); #endif snd_emux_init_virmidi(emu, card); @@ -150,7 +150,7 @@ int snd_emux_free(struct snd_emux *emu) snd_emux_proc_free(emu); snd_emux_delete_virmidi(emu); -#ifdef CONFIG_SND_SEQUENCER_OSS +#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) snd_emux_detach_seq_oss(emu); #endif snd_emux_detach_seq(emu); diff --git a/sound/synth/emux/emux_effect.c b/sound/synth/emux/emux_effect.c index a447218b6160..9ac0bf531b4b 100644 --- a/sound/synth/emux/emux_effect.c +++ b/sound/synth/emux/emux_effect.c @@ -150,7 +150,7 @@ effect_get_offset(struct snd_midi_channel *chan, int lo, int hi, int mode) return addr; } -#ifdef CONFIG_SND_SEQUENCER_OSS +#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) /* change effects - for OSS sequencer compatibility */ void snd_emux_send_effect_oss(struct snd_emux_port *port, diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c index 850fab4a8f3b..de19e108974a 100644 --- a/sound/synth/emux/emux_oss.c +++ b/sound/synth/emux/emux_oss.c @@ -23,8 +23,6 @@ */ -#ifdef CONFIG_SND_SEQUENCER_OSS - #include #include #include @@ -505,5 +503,3 @@ fake_event(struct snd_emux *emu, struct snd_emux_port *port, int ch, int param, ev.data.control.value = val; snd_emux_event_input(&ev, 0, port, atomic, hop); } - -#endif /* CONFIG_SND_SEQUENCER_OSS */ From 0181307abc1d2eb2a0dead93870bcffadddb827c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 9 Jun 2017 14:40:18 +0200 Subject: [PATCH 247/418] ALSA: seq: Reorganize kconfig and build This is a slightly intensive rewrite of Kconfig and Makefile about ALSA sequencer stuff. The first major change is that the kconfig items for the sequencer are moved to sound/core/seq/Kconfig. OK, that's easy. The substantial change is that, instead of hackish top-level module selection in Makefile, we define a Kconfig item for each sequencer module. The driver that requires such sequencer components select exclusively the kconfig items. This is more straightforward and standard way. Signed-off-by: Takashi Iwai --- sound/core/Kconfig | 47 ---------------------------- sound/core/seq/Kconfig | 68 ++++++++++++++++++++++++++++++++++------- sound/core/seq/Makefile | 13 +++----- sound/drivers/Kconfig | 13 ++++++++ sound/isa/Kconfig | 6 ++++ sound/pci/Kconfig | 6 ++++ 6 files changed, 86 insertions(+), 67 deletions(-) diff --git a/sound/core/Kconfig b/sound/core/Kconfig index d64dbee36986..90990eb1d250 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -33,31 +33,6 @@ config SND_JACK_INPUT_DEV depends on SND_JACK default y if INPUT=y || INPUT=SND -config SND_SEQUENCER - tristate "Sequencer support" - select SND_TIMER - help - Say Y or M to enable MIDI sequencer and router support. This - feature allows routing and enqueueing of MIDI events. Events - can be processed at a given time. - - Many programs require this feature, so you should enable it - unless you know what you're doing. - -config SND_SEQ_DUMMY - tristate "Sequencer dummy client" - depends on SND_SEQUENCER - help - Say Y here to enable the dummy sequencer client. This client - is a simple MIDI-through client: all normal input events are - redirected to the output port immediately. - - You don't need this unless you want to connect many MIDI - devices or applications together. - - To compile this driver as a module, choose M here: the module - will be called snd-seq-dummy. - config SND_OSSEMUL bool "Enable OSS Emulation" select SOUND_OSS_CORE @@ -109,20 +84,6 @@ config SND_PCM_TIMER For some embedded devices, we may disable it to reduce memory footprint, about 20KB on x86_64 platform. -config SND_SEQUENCER_OSS - tristate "OSS Sequencer API" - depends on SND_SEQUENCER - depends on SND_OSSEMUL - help - Say Y here to enable OSS sequencer emulation (both - /dev/sequencer and /dev/music interfaces). - - Many programs still use the OSS API, so say Y. - - If you choose M in "Sequencer support" (SND_SEQUENCER), - this will be compiled as a module. The module will be called - snd-seq-oss. - config SND_HRTIMER tristate "HR-timer backend support" depends on HIGH_RES_TIMERS @@ -135,14 +96,6 @@ config SND_HRTIMER To compile this driver as a module, choose M here: the module will be called snd-hrtimer. -config SND_SEQ_HRTIMER_DEFAULT - bool "Use HR-timer as default sequencer timer" - depends on SND_HRTIMER && SND_SEQUENCER - default y - help - Say Y here to use the HR-timer backend as the default sequencer - timer. - config SND_DYNAMIC_MINORS bool "Dynamic device file minor numbers" help diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig index b851fd890a89..140e640e62a6 100644 --- a/sound/core/seq/Kconfig +++ b/sound/core/seq/Kconfig @@ -1,16 +1,62 @@ -# define SND_XXX_SEQ to min(SND_SEQUENCER,SND_XXX) +config SND_SEQUENCER + tristate "Sequencer support" + select SND_TIMER + help + Say Y or M to enable MIDI sequencer and router support. This + feature allows routing and enqueueing of MIDI events. Events + can be processed at a given time. -config SND_RAWMIDI_SEQ - def_tristate SND_SEQUENCER && SND_RAWMIDI + Many programs require this feature, so you should enable it + unless you know what you're doing. -config SND_OPL3_LIB_SEQ - def_tristate SND_SEQUENCER && SND_OPL3_LIB +if SND_SEQUENCER -config SND_OPL4_LIB_SEQ - def_tristate SND_SEQUENCER && SND_OPL4_LIB +config SND_SEQ_DUMMY + tristate "Sequencer dummy client" + help + Say Y here to enable the dummy sequencer client. This client + is a simple MIDI-through client: all normal input events are + redirected to the output port immediately. -config SND_SBAWE_SEQ - def_tristate SND_SEQUENCER && SND_SBAWE + You don't need this unless you want to connect many MIDI + devices or applications together. + + To compile this driver as a module, choose M here: the module + will be called snd-seq-dummy. + +config SND_SEQUENCER_OSS + tristate "OSS Sequencer API" + depends on SND_OSSEMUL + select SND_SEQ_MIDI_EVENT + help + Say Y here to enable OSS sequencer emulation (both + /dev/sequencer and /dev/music interfaces). + + Many programs still use the OSS API, so say Y. + + To compile this driver as a module, choose M here: the module + will be called snd-seq-oss. + +config SND_SEQ_HRTIMER_DEFAULT + bool "Use HR-timer as default sequencer timer" + depends on SND_HRTIMER + default y + help + Say Y here to use the HR-timer backend as the default sequencer + timer. + +config SND_SEQ_MIDI_EVENT + def_tristate SND_RAWMIDI + +config SND_SEQ_MIDI + tristate + select SND_SEQ_MIDI_EVENT + +config SND_SEQ_MIDI_EMUL + tristate + +config SND_SEQ_VIRMIDI + tristate + +endif # SND_SEQUENCER -config SND_EMU10K1_SEQ - def_tristate SND_SEQUENCER && SND_EMU10K1 diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile index 3283b055e5ff..81a8ea537209 100644 --- a/sound/core/seq/Makefile +++ b/sound/core/seq/Makefile @@ -15,15 +15,10 @@ snd-seq-dummy-objs := seq_dummy.o snd-seq-virmidi-objs := seq_virmidi.o obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o snd-seq-device.o -obj-$(CONFIG_SND_SEQUENCER_OSS) += snd-seq-midi-event.o obj-$(CONFIG_SND_SEQUENCER_OSS) += oss/ obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o - -# Toplevel Module Dependency -obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o -obj-$(CONFIG_SND_RAWMIDI_SEQ) += snd-seq-midi.o snd-seq-midi-event.o -obj-$(CONFIG_SND_OPL3_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o -obj-$(CONFIG_SND_OPL4_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o -obj-$(CONFIG_SND_SBAWE_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o -obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o +obj-$(CONFIG_SND_SEQ_MIDI) += snd-seq-midi.o +obj-$(CONFIG_SND_SEQ_MIDI_EMUL) += snd-seq-midi-emul.o +obj-$(CONFIG_SND_SEQ_MIDI_EVENT) += snd-seq-midi-event.o +obj-$(CONFIG_SND_SEQ_VIRMIDI) += snd-seq-virmidi.o diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 8545da99b183..0e3dc80a7262 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -12,6 +12,17 @@ config SND_OPL4_LIB select SND_TIMER select SND_HWDEP +# select SEQ stuff to min(SND_SEQUENCER,SND_XXX) +config SND_OPL3_LIB_SEQ + def_tristate SND_SEQUENCER && SND_OPL3_LIB + select SND_SEQ_MIDI_EMUL + select SND_SEQ_MIDI_EVENT + +config SND_OPL4_LIB_SEQ + def_tristate SND_SEQUENCER && SND_OPL4_LIB + select SND_SEQ_MIDI_EMUL + select SND_SEQ_MIDI_EVENT + config SND_VX_LIB tristate select FW_LOADER @@ -99,6 +110,8 @@ config SND_VIRMIDI depends on SND_SEQUENCER select SND_TIMER select SND_RAWMIDI + select SND_SEQ_VIRMIDI + select SND_SEQ_MIDI_EVENT help Say Y here to include the virtual MIDI driver. This driver allows to connect applications using raw MIDI devices to diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 37adcc6cbe6b..bf1ab340e2a7 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -384,6 +384,12 @@ config SND_SBAWE To compile this driver as a module, choose M here: the module will be called snd-sbawe. +# select SEQ stuff to min(SND_SEQUENCER,SND_XXX) +config SND_SBAWE_SEQ + def_tristate SND_SEQUENCER && SND_SBAWE + select SND_SEQ_MIDI_EMUL + select SND_SEQ_VIRMIDI + config SND_SB16_CSP bool "Sound Blaster 16/AWE CSP support" depends on (SND_SB16 || SND_SBAWE) && (BROKEN || !PPC) diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 32151d8c6bb8..bc7acb489a43 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -477,6 +477,12 @@ config SND_EMU10K1 To compile this driver as a module, choose M here: the module will be called snd-emu10k1. +# select SEQ stuff to min(SND_SEQUENCER,SND_XXX) +config SND_EMU10K1_SEQ + def_tristate SND_SEQUENCER && SND_EMU10K1 + select SND_SEQ_MIDI_EMUL + select SND_SEQ_VIRMIDI + config SND_EMU10K1X tristate "Emu10k1X (Dell OEM Version)" select SND_AC97_CODEC From 8272115578ce02566b4c6bbe45f09d0d55f4a1c6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 9 Jun 2017 14:57:51 +0200 Subject: [PATCH 248/418] ALSA: synth: Select snd-emux-synth explicitly Instead of the non-standard way to enable the build of snd-emux-synth module inside Makefile, rewrite Kconfig to select the item explicitly from each driver (sbawe and emu10k1). This is the standard way. Signed-off-by: Takashi Iwai --- sound/Kconfig | 2 ++ sound/isa/Kconfig | 1 + sound/pci/Kconfig | 1 + sound/synth/Kconfig | 2 ++ sound/synth/emux/Makefile | 4 +--- 5 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 sound/synth/Kconfig diff --git a/sound/Kconfig b/sound/Kconfig index d2fadbec8d51..d7d2aac9542e 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -110,6 +110,8 @@ source "sound/soc/Kconfig" source "sound/x86/Kconfig" +source "sound/synth/Kconfig" + endif # SND menuconfig SOUND_PRIME diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index bf1ab340e2a7..ea8ecc5bb826 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -389,6 +389,7 @@ config SND_SBAWE_SEQ def_tristate SND_SEQUENCER && SND_SBAWE select SND_SEQ_MIDI_EMUL select SND_SEQ_VIRMIDI + select SND_SYNTH_EMUX config SND_SB16_CSP bool "Sound Blaster 16/AWE CSP support" diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index bc7acb489a43..9ac9326f28d6 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -482,6 +482,7 @@ config SND_EMU10K1_SEQ def_tristate SND_SEQUENCER && SND_EMU10K1 select SND_SEQ_MIDI_EMUL select SND_SEQ_VIRMIDI + select SND_SYNTH_EMUX config SND_EMU10K1X tristate "Emu10k1X (Dell OEM Version)" diff --git a/sound/synth/Kconfig b/sound/synth/Kconfig new file mode 100644 index 000000000000..dfe8950e0556 --- /dev/null +++ b/sound/synth/Kconfig @@ -0,0 +1,2 @@ +config SND_SYNTH_EMUX + tristate diff --git a/sound/synth/emux/Makefile b/sound/synth/emux/Makefile index fb761c2c2b50..4599108452fd 100644 --- a/sound/synth/emux/Makefile +++ b/sound/synth/emux/Makefile @@ -8,6 +8,4 @@ snd-emux-synth-objs := emux.o emux_synth.o emux_seq.o emux_nrpn.o \ snd-emux-synth-$(CONFIG_SND_PROC_FS) += emux_proc.o snd-emux-synth-$(CONFIG_SND_SEQUENCER_OSS) += emux_oss.o -# Toplevel Module Dependencies -obj-$(CONFIG_SND_SBAWE_SEQ) += snd-emux-synth.o -obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-emux-synth.o +obj-$(CONFIG_SND_SYNTH_EMUX) += snd-emux-synth.o From f74ae15fe3da7905b78e986ad906a333587cf160 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 11 Jun 2017 23:56:12 +0900 Subject: [PATCH 249/418] ALSA: pcm: return error immediately for parameters handling When refining mask/interval parameters, helper functions can return error code. This error is not handled immediately. This seems to return parameters to userspace applications in its meddle of processing. However, in general, when receiving error from system calls, the application might not handle argument buffer. It's reasonable to judge the above design as superfluity. This commit handles the error immediately. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 66 ++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 076187ae8859..425f54827e78 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -276,14 +276,14 @@ static int constrain_mask_params(struct snd_pcm_substream *substream, old_mask = *m; changed = snd_mask_refine(m, constrs_mask(constrs, k)); + if (changed < 0) + return changed; trace_hw_mask_param(substream, k, 0, &old_mask, m); /* Set corresponding flag so that the caller gets it. */ if (changed) params->cmask |= 1 << k; - if (changed < 0) - return changed; } return 0; @@ -312,14 +312,14 @@ static int constrain_interval_params(struct snd_pcm_substream *substream, old_interval = *i; changed = snd_interval_refine(i, constrs_interval(constrs, k)); + if (changed < 0) + return changed; trace_hw_interval_param(substream, k, 0, &old_interval, i); /* Set corresponding flag so that the caller gets it. */ if (changed) params->cmask |= 1 << k; - if (changed < 0) - return changed; } return 0; @@ -406,6 +406,8 @@ retry: } changed = r->func(params, r); + if (changed < 0) + return changed; if (hw_is_mask(r->var)) { trace_hw_mask_param(substream, r->var, k + 1, @@ -428,8 +430,7 @@ retry: vstamps[r->var] = stamp; again = true; } - if (changed < 0) - return changed; + stamp++; } @@ -527,13 +528,16 @@ static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, return PTR_ERR(params); err = snd_pcm_hw_refine(substream, params); - if (err >= 0) - err = fixup_unreferenced_params(substream, params); - if (copy_to_user(_params, params, sizeof(*params))) { - if (!err) - err = -EFAULT; - } + if (err < 0) + goto end; + err = fixup_unreferenced_params(substream, params); + if (err < 0) + goto end; + + if (copy_to_user(_params, params, sizeof(*params))) + err = -EFAULT; +end: kfree(params); return err; } @@ -749,11 +753,12 @@ static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream, return PTR_ERR(params); err = snd_pcm_hw_params(substream, params); - if (copy_to_user(_params, params, sizeof(*params))) { - if (!err) - err = -EFAULT; - } + if (err < 0) + goto end; + if (copy_to_user(_params, params, sizeof(*params))) + err = -EFAULT; +end: kfree(params); return err; } @@ -3699,14 +3704,17 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, } snd_pcm_hw_convert_from_old_params(params, oparams); err = snd_pcm_hw_refine(substream, params); - if (err >= 0) - err = fixup_unreferenced_params(substream, params); - snd_pcm_hw_convert_to_old_params(oparams, params); - if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { - if (!err) - err = -EFAULT; - } + if (err < 0) + goto out_old; + err = fixup_unreferenced_params(substream, params); + if (err < 0) + goto out_old; + + snd_pcm_hw_convert_to_old_params(oparams, params); + if (copy_to_user(_oparams, oparams, sizeof(*oparams))) + err = -EFAULT; +out_old: kfree(oparams); out: kfree(params); @@ -3729,14 +3737,16 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream, err = PTR_ERR(oparams); goto out; } + snd_pcm_hw_convert_from_old_params(params, oparams); err = snd_pcm_hw_params(substream, params); - snd_pcm_hw_convert_to_old_params(oparams, params); - if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { - if (!err) - err = -EFAULT; - } + if (err < 0) + goto out_old; + snd_pcm_hw_convert_to_old_params(oparams, params); + if (copy_to_user(_oparams, oparams, sizeof(*oparams))) + err = -EFAULT; +out_old: kfree(oparams); out: kfree(params); From 82e7d5012f73e51209305876bed2aac53b62cde3 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 11 Jun 2017 23:56:13 +0900 Subject: [PATCH 250/418] ALSA: pcm: probe events when parameters are changed actually At present, trace events are probed even if corresponding parameter is not actually changed. This is inconvenient. This commit improves the behaviour. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 56 +++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 425f54827e78..5099078dde93 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -278,12 +278,12 @@ static int constrain_mask_params(struct snd_pcm_substream *substream, changed = snd_mask_refine(m, constrs_mask(constrs, k)); if (changed < 0) return changed; - - trace_hw_mask_param(substream, k, 0, &old_mask, m); + if (changed == 0) + continue; /* Set corresponding flag so that the caller gets it. */ - if (changed) - params->cmask |= 1 << k; + trace_hw_mask_param(substream, k, 0, &old_mask, m); + params->cmask |= 1 << k; } return 0; @@ -314,12 +314,12 @@ static int constrain_interval_params(struct snd_pcm_substream *substream, changed = snd_interval_refine(i, constrs_interval(constrs, k)); if (changed < 0) return changed; - - trace_hw_interval_param(substream, k, 0, &old_interval, i); + if (changed == 0) + continue; /* Set corresponding flag so that the caller gets it. */ - if (changed) - params->cmask |= 1 << k; + trace_hw_interval_param(substream, k, 0, &old_interval, i); + params->cmask |= 1 << k; } return 0; @@ -409,29 +409,29 @@ retry: if (changed < 0) return changed; - if (hw_is_mask(r->var)) { - trace_hw_mask_param(substream, r->var, k + 1, - &old_mask, hw_param_mask(params, r->var)); - } - if (hw_is_interval(r->var)) { - trace_hw_interval_param(substream, r->var, k + 1, - &old_interval, hw_param_interval(params, r->var)); - } - - rstamps[k] = stamp; - /* - * When the parameters is changed, notify it to the caller + * When the parameter is changed, notify it to the caller * by corresponding returned bit, then preparing for next * iteration. */ if (changed && r->var >= 0) { + if (hw_is_mask(r->var)) { + trace_hw_mask_param(substream, r->var, + k + 1, &old_mask, + hw_param_mask(params, r->var)); + } + if (hw_is_interval(r->var)) { + trace_hw_interval_param(substream, r->var, + k + 1, &old_interval, + hw_param_interval(params, r->var)); + } + params->cmask |= (1 << r->var); vstamps[r->var] = stamp; again = true; } - stamp++; + rstamps[k] = stamp++; } /* Iterate to evaluate all rules till no parameters are changed. */ @@ -604,7 +604,7 @@ static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, const int *v; struct snd_mask old_mask; struct snd_interval old_interval; - int err; + int changed; for (v = vars; *v != -1; v++) { /* Keep old parameter to trace. */ @@ -617,13 +617,15 @@ static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, old_interval = *hw_param_interval(params, *v); } if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE) - err = snd_pcm_hw_param_first(pcm, params, *v, NULL); + changed = snd_pcm_hw_param_first(pcm, params, *v, NULL); else - err = snd_pcm_hw_param_last(pcm, params, *v, NULL); - if (snd_BUG_ON(err < 0)) - return err; + changed = snd_pcm_hw_param_last(pcm, params, *v, NULL); + if (snd_BUG_ON(changed < 0)) + return changed; + if (changed == 0) + continue; - /* Trace the parameter. */ + /* Trace the changed parameter. */ if (hw_is_mask(*v)) { trace_hw_mask_param(pcm, *v, 0, &old_mask, hw_param_mask(params, *v)); From 111b0cdb97d44cfe5dec1338a78ba8aff65c32e2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 9 Jun 2017 15:11:58 +0200 Subject: [PATCH 251/418] ALSA: seq: Allow the modular sequencer registration Many drivers bind the sequencer stuff in off-load by another driver module, so that it's loaded only on demand. In the current code, this mechanism doesn't work when the driver is built-in while the sequencer is module. We check with IS_REACHABLE() and enable only when the sequencer is in the same level of build. However, this is basically a overshoot. The binder code (snd-seq-device) is an individual module from the sequencer core (snd-seq), and we just have to make the former a built-in while keeping the latter a module for allowing the scenario like the above. This patch achieves that by rewriting Kconfig slightly. Now, a driver that provides the manual sequencer device binding should select CONFIG_SND_SEQ_DEVICE in a way as select SND_SEQ_DEVICE if SND_SEQUENCER != n Note that the "!=n" is needed here to avoid the influence of the sequencer core is module while the driver is built-in. Also, since rawmidi.o may be linked with snd_seq_device.o when built-in, we have to shuffle the code to make the linker happy. (the kernel linker isn't smart enough yet to handle such a case.) That is, snd_seq_device.c is moved to sound/core from sound/core/seq, as well as Makefile. Last but not least, the patch replaces the code using IS_REACHABLE() with IS_ENABLED(), since now the condition meets always when enabled. Signed-off-by: Takashi Iwai --- sound/core/Kconfig | 4 ++++ sound/core/Makefile | 2 ++ sound/core/rawmidi.c | 4 ++-- sound/core/seq/Kconfig | 2 +- sound/core/seq/Makefile | 3 +-- sound/core/{seq => }/seq_device.c | 0 sound/drivers/Kconfig | 2 ++ sound/drivers/opl3/opl3_lib.c | 2 +- sound/drivers/opl4/opl4_lib.c | 4 ++-- sound/drivers/opl4/opl4_local.h | 2 +- sound/isa/Kconfig | 1 + sound/isa/sb/emu8000.c | 2 +- sound/isa/sb/sb16.c | 2 +- sound/pci/Kconfig | 1 + sound/pci/emu10k1/emu10k1.c | 2 +- 15 files changed, 21 insertions(+), 12 deletions(-) rename sound/core/{seq => }/seq_device.c (100%) diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 90990eb1d250..6e937a8146a1 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -18,8 +18,12 @@ config SND_DMAENGINE_PCM config SND_HWDEP tristate +config SND_SEQ_DEVICE + tristate + config SND_RAWMIDI tristate + select SND_SEQ_DEVICE if SND_SEQUENCER != n config SND_COMPRESS_OFFLOAD tristate diff --git a/sound/core/Makefile b/sound/core/Makefile index a8514b313a89..e2066e2ef9f8 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -31,6 +31,7 @@ snd-timer-objs := timer.o snd-hrtimer-objs := hrtimer.o snd-rtctimer-objs := rtctimer.o snd-hwdep-objs := hwdep.o +snd-seq-device-objs := seq_device.o snd-compress-objs := compress_offload.o @@ -40,6 +41,7 @@ obj-$(CONFIG_SND_TIMER) += snd-timer.o obj-$(CONFIG_SND_HRTIMER) += snd-hrtimer.o obj-$(CONFIG_SND_PCM) += snd-pcm.o obj-$(CONFIG_SND_DMAENGINE_PCM) += snd-pcm-dmaengine.o +obj-$(CONFIG_SND_SEQ_DEVICE) += snd-seq-device.o obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o obj-$(CONFIG_SND_OSSEMUL) += oss/ diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index ab890336175f..153d78bc79c0 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1610,7 +1610,7 @@ static int snd_rawmidi_dev_free(struct snd_device *device) return snd_rawmidi_free(rmidi); } -#if IS_REACHABLE(CONFIG_SND_SEQUENCER) +#if IS_ENABLED(CONFIG_SND_SEQUENCER) static void snd_rawmidi_dev_seq_free(struct snd_seq_device *device) { struct snd_rawmidi *rmidi = device->private_data; @@ -1691,7 +1691,7 @@ static int snd_rawmidi_dev_register(struct snd_device *device) } } rmidi->proc_entry = entry; -#if IS_REACHABLE(CONFIG_SND_SEQUENCER) +#if IS_ENABLED(CONFIG_SND_SEQUENCER) if (!rmidi->ops || !rmidi->ops->dev_register) { /* own registration mechanism */ if (snd_seq_device_new(rmidi->card, rmidi->device, SNDRV_SEQ_DEV_ID_MIDISYNTH, 0, &rmidi->seq_dev) >= 0) { rmidi->seq_dev->private_data = rmidi; diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig index 140e640e62a6..a536760a94c2 100644 --- a/sound/core/seq/Kconfig +++ b/sound/core/seq/Kconfig @@ -1,6 +1,7 @@ config SND_SEQUENCER tristate "Sequencer support" select SND_TIMER + select SND_SEQ_DEVICE help Say Y or M to enable MIDI sequencer and router support. This feature allows routing and enqueueing of MIDI events. Events @@ -59,4 +60,3 @@ config SND_SEQ_VIRMIDI tristate endif # SND_SEQUENCER - diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile index 81a8ea537209..68fd367ac39c 100644 --- a/sound/core/seq/Makefile +++ b/sound/core/seq/Makefile @@ -3,7 +3,6 @@ # Copyright (c) 1999 by Jaroslav Kysela # -snd-seq-device-objs := seq_device.o snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \ seq_fifo.o seq_prioq.o seq_timer.o \ seq_system.o seq_ports.o @@ -14,7 +13,7 @@ snd-seq-midi-event-objs := seq_midi_event.o snd-seq-dummy-objs := seq_dummy.o snd-seq-virmidi-objs := seq_virmidi.o -obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o snd-seq-device.o +obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o obj-$(CONFIG_SND_SEQUENCER_OSS) += oss/ obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o diff --git a/sound/core/seq/seq_device.c b/sound/core/seq_device.c similarity index 100% rename from sound/core/seq/seq_device.c rename to sound/core/seq_device.c diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 0e3dc80a7262..7144cc36e8ae 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -6,11 +6,13 @@ config SND_OPL3_LIB tristate select SND_TIMER select SND_HWDEP + select SND_SEQ_DEVICE if SND_SEQUENCER != n config SND_OPL4_LIB tristate select SND_TIMER select SND_HWDEP + select SND_SEQ_DEVICE if SND_SEQUENCER != n # select SEQ stuff to min(SND_SEQUENCER,SND_XXX) config SND_OPL3_LIB_SEQ diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c index cd9e9f31720f..d5e5b4657b4b 100644 --- a/sound/drivers/opl3/opl3_lib.c +++ b/sound/drivers/opl3/opl3_lib.c @@ -528,7 +528,7 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3, opl3->hwdep = hw; opl3->seq_dev_num = seq_device; -#if IS_REACHABLE(CONFIG_SND_SEQUENCER) +#if IS_ENABLED(CONFIG_SND_SEQUENCER) if (snd_seq_device_new(card, seq_device, SNDRV_SEQ_DEV_ID_OPL3, sizeof(struct snd_opl3 *), &opl3->seq_dev) >= 0) { strcpy(opl3->seq_dev->name, hw->name); diff --git a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c index 240656e54400..bc345d564f8d 100644 --- a/sound/drivers/opl4/opl4_lib.c +++ b/sound/drivers/opl4/opl4_lib.c @@ -153,7 +153,7 @@ static int snd_opl4_detect(struct snd_opl4 *opl4) return 0; } -#if IS_REACHABLE(CONFIG_SND_SEQUENCER) +#if IS_ENABLED(CONFIG_SND_SEQUENCER) static void snd_opl4_seq_dev_free(struct snd_seq_device *seq_dev) { struct snd_opl4 *opl4 = seq_dev->private_data; @@ -249,7 +249,7 @@ int snd_opl4_create(struct snd_card *card, snd_opl4_create_mixer(opl4); snd_opl4_create_proc(opl4); -#if IS_REACHABLE(CONFIG_SND_SEQUENCER) +#if IS_ENABLED(CONFIG_SND_SEQUENCER) opl4->seq_client = -1; if (opl4->hardware < OPL3_HW_OPL4_ML) snd_opl4_create_seq_dev(opl4, seq_device); diff --git a/sound/drivers/opl4/opl4_local.h b/sound/drivers/opl4/opl4_local.h index d5bac93f8245..a16b4677c1e9 100644 --- a/sound/drivers/opl4/opl4_local.h +++ b/sound/drivers/opl4/opl4_local.h @@ -184,7 +184,7 @@ struct snd_opl4 { #endif struct mutex access_mutex; -#if IS_REACHABLE(CONFIG_SND_SEQUENCER) +#if IS_ENABLED(CONFIG_SND_SEQUENCER) int used; int seq_dev_num; diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index ea8ecc5bb826..cb54d9c0a77f 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -377,6 +377,7 @@ config SND_SBAWE select SND_OPL3_LIB select SND_MPU401_UART select SND_SB16_DSP + select SND_SEQ_DEVICE if SND_SEQUENCER != n help Say Y here to include support for Sound Blaster AWE soundcards (including the Plug and Play version). diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index 0b5c4cf3abfa..d56973b770c7 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -1138,7 +1138,7 @@ snd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports, snd_emu8000_free(hw); return err; } -#if IS_REACHABLE(CONFIG_SND_SEQUENCER) +#if IS_ENABLED(CONFIG_SND_SEQUENCER) if (snd_seq_device_new(card, index, SNDRV_SEQ_DEV_ID_EMU8000, sizeof(struct snd_emu8000*), &awe) >= 0) { strcpy(awe->name, "EMU-8000"); diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c index 31ab09b3b049..917a93d696c3 100644 --- a/sound/isa/sb/sb16.c +++ b/sound/isa/sb/sb16.c @@ -62,7 +62,7 @@ MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB AWE 32}," #define SNDRV_DEBUG_IRQ #endif -#if defined(SNDRV_SBAWE) && IS_REACHABLE(CONFIG_SND_SEQUENCER) +#if defined(SNDRV_SBAWE) && IS_ENABLED(CONFIG_SND_SEQUENCER) #define SNDRV_SBAWE_EMU8000 #endif diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 9ac9326f28d6..d9f3fdb777e4 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -465,6 +465,7 @@ config SND_EMU10K1 select SND_RAWMIDI select SND_AC97_CODEC select SND_TIMER + select SND_SEQ_DEVICE if SND_SEQUENCER != n depends on ZONE_DMA help Say Y to include support for Sound Blaster PCI 512, Live!, diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 6a0e49ac5273..d3203df50a1a 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -37,7 +37,7 @@ MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB Live!/PCI512/E-mu APS}," "{Creative Labs,SB Audigy}}"); -#if IS_REACHABLE(CONFIG_SND_SEQUENCER) +#if IS_ENABLED(CONFIG_SND_SEQUENCER) #define ENABLE_SYNTH #include #endif From 66e01a5cf63f2b132059d0d3d78ed737207489f2 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 12 Jun 2017 09:41:44 +0900 Subject: [PATCH 252/418] ALSA: pcm: unify codes to operate application-side position on PCM buffer In a series of recent work, ALSA PCM core got some arrangements to handle application-side position on PCM buffer. However, relevant codes still disperse to two translation units This commit unifies these codes into a helper function. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 27 ++++++++++++++++++++++++--- sound/core/pcm_local.h | 2 ++ sound/core/pcm_native.c | 28 ++++------------------------ 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 9dc7bbfe8853..d82f1437667f 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2101,6 +2101,27 @@ static int pcm_accessible_state(struct snd_pcm_runtime *runtime) } } +/* update to the given appl_ptr and call ack callback if needed; + * when an error is returned, take back to the original value + */ +int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream, + snd_pcm_uframes_t appl_ptr) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_uframes_t old_appl_ptr = runtime->control->appl_ptr; + int ret; + + runtime->control->appl_ptr = appl_ptr; + if (substream->ops->ack) { + ret = substream->ops->ack(substream); + if (ret < 0) { + runtime->control->appl_ptr = old_appl_ptr; + return ret; + } + } + return 0; +} + /* the common loop for read/write data */ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, void *data, bool interleaved, @@ -2220,9 +2241,9 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, appl_ptr += frames; if (appl_ptr >= runtime->boundary) appl_ptr -= runtime->boundary; - runtime->control->appl_ptr = appl_ptr; - if (substream->ops->ack) - substream->ops->ack(substream); + err = pcm_lib_apply_appl_ptr(substream, appl_ptr); + if (err < 0) + goto _end_unlock; offset += frames; size -= frames; diff --git a/sound/core/pcm_local.h b/sound/core/pcm_local.h index e4bf2af62b02..16f254732b2a 100644 --- a/sound/core/pcm_local.h +++ b/sound/core/pcm_local.h @@ -27,6 +27,8 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream); int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var, u_int32_t mask); +int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream, + snd_pcm_uframes_t appl_ptr); int snd_pcm_update_state(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime); int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 5099078dde93..07995e645327 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2598,27 +2598,6 @@ static int do_pcm_hwsync(struct snd_pcm_substream *substream) } } -/* update to the given appl_ptr and call ack callback if needed; - * when an error is returned, take back to the original value - */ -static int apply_appl_ptr(struct snd_pcm_substream *substream, - snd_pcm_uframes_t appl_ptr) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_uframes_t old_appl_ptr = runtime->control->appl_ptr; - int ret; - - runtime->control->appl_ptr = appl_ptr; - if (substream->ops->ack) { - ret = substream->ops->ack(substream); - if (ret < 0) { - runtime->control->appl_ptr = old_appl_ptr; - return ret; - } - } - return 0; -} - /* increase the appl_ptr; returns the processed frames or a negative error */ static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream, snd_pcm_uframes_t frames, @@ -2635,7 +2614,7 @@ static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream, appl_ptr = runtime->control->appl_ptr + frames; if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) appl_ptr -= runtime->boundary; - ret = apply_appl_ptr(substream, appl_ptr); + ret = pcm_lib_apply_appl_ptr(substream, appl_ptr); return ret < 0 ? ret : frames; } @@ -2655,7 +2634,7 @@ static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream, appl_ptr = runtime->control->appl_ptr - frames; if (appl_ptr < 0) appl_ptr += runtime->boundary; - ret = apply_appl_ptr(substream, appl_ptr); + ret = pcm_lib_apply_appl_ptr(substream, appl_ptr); return ret < 0 ? ret : frames; } @@ -2783,7 +2762,8 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, } snd_pcm_stream_lock_irq(substream); if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) { - err = apply_appl_ptr(substream, sync_ptr.c.control.appl_ptr); + err = pcm_lib_apply_appl_ptr(substream, + sync_ptr.c.control.appl_ptr); if (err < 0) { snd_pcm_stream_unlock_irq(substream); return err; From fccf53881e9b564321326f62ed5f85130fa6e569 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 12 Jun 2017 09:41:45 +0900 Subject: [PATCH 253/418] ALSA: pcm: add 'applptr' event of tracepoint In design of ALSA PCM core, status and control data for runtime of ALSA PCM substream are shared between kernel/user spaces by page frame mapping with read-only attribute. Both of hardware-side and application-side position on PCM buffer are maintained as a part of the status data. In a view of ALSA PCM application, these two positions can be updated by executing ioctl(2) with some commands. There's an event of tracepoint for hardware-side position; 'hwptr'. On the other hand, no events for application-side position. This commit adds a new event for this purpose; 'applptr'. When the application-side position is changed in kernel space, this event is probed with useful information for developers. I note that the event is not probed for all of ALSA PCM applications, When applications are written by read/write programming scenario, the event is surely probed. The applications execute ioctl(2) with SNDRV_PCM_IOCTL_[READ|WRITE][N/I]_FRAMES to read/write any PCM frame, then ALSA PCM core updates the application-side position in kernel land. However, when applications are written by mmap programming scenario, if maintaining the application side position in kernel space accurately, applications should voluntarily execute ioctl(2) with SNDRV_PCM_IOCTL_SYNC_PTR to commit the number of handled PCM frames. If not voluntarily, the application-side position is not changed, thus the added event is not probed. There's a loophole, using architectures to which ALSA PCM core judges non cache coherent. In this case, the status and control data is not mapped into processe's VMA for any applications. Userland library, alsa-lib, is programmed for this case. It executes ioctl(2) with SNDRV_PCM_IOCTL_SYNC_PTR command every time to requiring the status and control data. ARM is such an architecture. Below is an example with serial sound interface (ssi) on i.mx6 quad core SoC. I use v4.1 kernel released by fsl-community with patches from VIA Tech. Inc. for VAB820, and my backport patches for relevant features for this patchset. I use Ubuntu 17.04 from ports.ubuntu.com as user land for armhf architecture. $ aplay -v -M -D hw:imx6vab820sgtl5,0 /dev/urandom -f S16_LE -r 48000 --period-size=128 --buffer-size=256 Playing raw data '/dev/urandom' : Signed 16 bit Little Endian, Rate 48000 Hz, Mono Hardware PCM card 0 'imx6-vab820-sgtl5000' device 0 subdevice 0 Its setup is: stream : PLAYBACK access : MMAP_INTERLEAVED format : S16_LE subformat : STD channels : 1 rate : 48000 exact rate : 48000 (48000/1) msbits : 16 buffer_size : 256 period_size : 128 period_time : 2666 tstamp_mode : NONE tstamp_type : MONOTONIC period_step : 1 avail_min : 128 period_event : 0 start_threshold : 256 stop_threshold : 256 silence_threshold: 0 silence_size : 0 boundary : 1073741824 appl_ptr : 0 hw_ptr : 0 mmap_area[0] = 0x76f98000,0,16 (16) $ trace-cmd record -e snd_pcm:hwptr -e snd_pcm:applptr $ trace-cmd report ... 60.208495: applptr: pcmC0D0p/sub0: prev=1792, curr=1792, avail=0, period=128, buf=256 60.208633: applptr: pcmC0D0p/sub0: prev=1792, curr=1792, avail=0, period=128, buf=256 60.210022: hwptr: pcmC0D0p/sub0: IRQ: pos=128, old=1536, base=1536, period=128, buf=256 60.210202: applptr: pcmC0D0p/sub0: prev=1792, curr=1792, avail=128, period=128, buf=256 60.210344: hwptr: pcmC0D0p/sub0: POS: pos=128, old=1664, base=1536, period=128, buf=256 60.210348: applptr: pcmC0D0p/sub0: prev=1792, curr=1792, avail=128, period=128, buf=256 60.210486: applptr: pcmC0D0p/sub0: prev=1792, curr=1792, avail=128, period=128, buf=256 60.210626: applptr: pcmC0D0p/sub0: prev=1792, curr=1920, avail=0, period=128, buf=256 60.211002: applptr: pcmC0D0p/sub0: prev=1920, curr=1920, avail=0, period=128, buf=256 60.211142: hwptr: pcmC0D0p/sub0: POS: pos=128, old=1664, base=1536, period=128, buf=256 60.211146: applptr: pcmC0D0p/sub0: prev=1920, curr=1920, avail=0, period=128, buf=256 60.211287: applptr: pcmC0D0p/sub0: prev=1920, curr=1920, avail=0, period=128, buf=256 60.212690: hwptr: pcmC0D0p/sub0: IRQ: pos=0, old=1664, base=1536, period=128, buf=256 60.212866: applptr: pcmC0D0p/sub0: prev=1920, curr=1920, avail=128, period=128, buf=256 60.212999: hwptr: pcmC0D0p/sub0: POS: pos=0, old=1792, base=1792, period=128, buf=256 60.213003: applptr: pcmC0D0p/sub0: prev=1920, curr=1920, avail=128, period=128, buf=256 60.213135: applptr: pcmC0D0p/sub0: prev=1920, curr=1920, avail=128, period=128, buf=256 60.213276: applptr: pcmC0D0p/sub0: prev=1920, curr=2048, avail=0, period=128, buf=256 60.213654: applptr: pcmC0D0p/sub0: prev=2048, curr=2048, avail=0, period=128, buf=256 60.213796: hwptr: pcmC0D0p/sub0: POS: pos=0, old=1792, base=1792, period=128, buf=256 60.213800: applptr: pcmC0D0p/sub0: prev=2048, curr=2048, avail=0, period=128, buf=256 60.213937: applptr: pcmC0D0p/sub0: prev=2048, curr=2048, avail=0, period=128, buf=256 60.215356: hwptr: pcmC0D0p/sub0: IRQ: pos=128, old=1792, base=1792, period=128, buf=256 60.215542: applptr: pcmC0D0p/sub0: prev=2048, curr=2048, avail=128, period=128, buf=256 60.215679: hwptr: pcmC0D0p/sub0: POS: pos=128, old=1920, base=1792, period=128, buf=256 60.215683: applptr: pcmC0D0p/sub0: prev=2048, curr=2048, avail=128, period=128, buf=256 60.215813: applptr: pcmC0D0p/sub0: prev=2048, curr=2048, avail=128, period=128, buf=256 60.215947: applptr: pcmC0D0p/sub0: prev=2048, curr=2176, avail=0, period=128, buf=256 ... We can surely see 'applptr' event is probed even if the application run for mmap programming scenario ('-M' option and 'hw' plugin). Below is a result of strace: 02:44:15.886382 ioctl(4, SNDRV_PCM_IOCTL_SYNC_PTR, 0x56a32b30) = 0 02:44:15.887203 poll([{fd=4, events=POLLOUT|POLLERR|POLLNVAL}], 1, -1) = 1 ([{fd=4, revents=POLLOUT}]) 02:44:15.887471 ioctl(4, SNDRV_PCM_IOCTL_SYNC_PTR, 0x56a32b30) = 0 02:44:15.887637 ioctl(4, SNDRV_PCM_IOCTL_SYNC_PTR, 0x56a32b30) = 0 02:44:15.887805 ioctl(4, SNDRV_PCM_IOCTL_SYNC_PTR, 0x56a32b30) = 0 02:44:15.887969 ioctl(4, SNDRV_PCM_IOCTL_SYNC_PTR, 0x56a32b30) = 0 02:44:15.888132 read(3, "..."..., 256) = 256 02:44:15.889040 ioctl(4, SNDRV_PCM_IOCTL_SYNC_PTR, 0x56a32b30) = 0 02:44:15.889221 ioctl(4, SNDRV_PCM_IOCTL_SYNC_PTR, 0x56a32b30) = 0 02:44:15.889431 ioctl(4, SNDRV_PCM_IOCTL_SYNC_PTR, 0x56a32b30) = 0 02:44:15.889606 poll([{fd=4, events=POLLOUT|POLLERR|POLLNVAL}], 1, -1) = 1 ([{fd=4, revents=POLLOUT}]) 02:44:15.889833 ioctl(4, SNDRV_PCM_IOCTL_SYNC_PTR, 0x56a32b30) = 0 02:44:15.889998 ioctl(4, SNDRV_PCM_IOCTL_SYNC_PTR, 0x56a32b30) = 0 02:44:15.890164 ioctl(4, SNDRV_PCM_IOCTL_SYNC_PTR, 0x56a32b30) = 0 02:44:15.891048 ioctl(4, SNDRV_PCM_IOCTL_SYNC_PTR, 0x56a32b30) = 0 02:44:15.891228 read(3, "..."..., 256) = 256 02:44:15.891497 ioctl(4, SNDRV_PCM_IOCTL_SYNC_PTR, 0x56a32b30) = 0 02:44:15.891661 ioctl(4, SNDRV_PCM_IOCTL_SYNC_PTR, 0x56a32b30) = 0 02:44:15.891829 ioctl(4, SNDRV_PCM_IOCTL_SYNC_PTR, 0x56a32b30) = 0 02:44:15.891991 poll([{fd=4, events=POLLOUT|POLLERR|POLLNVAL}], 1, -1) = 1 ([{fd=4, revents=POLLOUT}]) 02:44:15.893007 ioctl(4, SNDRV_PCM_IOCTL_SYNC_PTR, 0x56a32b30) = 0 We can see 7 calls of ioctl(2) with SNDRV_PCM_IOCTL_SYNC_PTR per loop with call of poll(2). 128 PCM frames are transferred per loop of one poll(2), because the PCM substream is configured with S16_LE format and 1 channel (2 byte * 1 * 128 = 256 bytes). This equals to the size of period of PCM buffer. Comparing to the probed data, one of the 7 calls of ioctl(2) is actually used to commit the number of copied PCM frames to kernel space. The other calls are just used to check runtime status of PCM substream; e.g. XRUN. The tracepoint event is useful to investigate this case. I note that below modules are related to the above sample. * snd-soc-dummy.ko * snd-soc-imx-sgtl5000.ko * snd-soc-fsl-ssi.ko * snd-soc-imx-pcm-dma.ko * snd-soc-sgtl5000.ko My additional note is lock acquisition. The event is probed under acquiring PCM stream lock. This means that calculation in the event is free from any hardware events. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 4 ++++ sound/core/pcm_trace.h | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index d82f1437667f..e73b6e4135f6 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -42,6 +42,7 @@ #define trace_hwptr(substream, pos, in_interrupt) #define trace_xrun(substream) #define trace_hw_ptr_error(substream, reason) +#define trace_applptr(substream, prev, curr) #endif static int fill_silence_frames(struct snd_pcm_substream *substream, @@ -2119,6 +2120,9 @@ int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream, return ret; } } + + trace_applptr(substream, old_appl_ptr, appl_ptr); + return 0; } diff --git a/sound/core/pcm_trace.h b/sound/core/pcm_trace.h index b63b654da5ff..e672368ab878 100644 --- a/sound/core/pcm_trace.h +++ b/sound/core/pcm_trace.h @@ -102,6 +102,44 @@ TRACE_EVENT(hw_ptr_error, __entry->number, __entry->reason) ); +TRACE_EVENT(applptr, + TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_uframes_t prev, snd_pcm_uframes_t curr), + TP_ARGS(substream, prev, curr), + TP_STRUCT__entry( + __field( unsigned int, card ) + __field( unsigned int, device ) + __field( unsigned int, number ) + __field( unsigned int, stream ) + __field( snd_pcm_uframes_t, prev ) + __field( snd_pcm_uframes_t, curr ) + __field( snd_pcm_uframes_t, avail ) + __field( snd_pcm_uframes_t, period_size ) + __field( snd_pcm_uframes_t, buffer_size ) + ), + TP_fast_assign( + __entry->card = (substream)->pcm->card->number; + __entry->device = (substream)->pcm->device; + __entry->number = (substream)->number; + __entry->stream = (substream)->stream; + __entry->prev = (prev); + __entry->curr = (curr); + __entry->avail = (substream)->stream ? snd_pcm_capture_avail(substream->runtime) : snd_pcm_playback_avail(substream->runtime); + __entry->period_size = (substream)->runtime->period_size; + __entry->buffer_size = (substream)->runtime->buffer_size; + ), + TP_printk("pcmC%dD%d%s/sub%d: prev=%lu, curr=%lu, avail=%lu, period=%lu, buf=%lu", + __entry->card, + __entry->device, + __entry->stream ? "c" : "p", + __entry->number, + __entry->prev, + __entry->curr, + __entry->avail, + __entry->period_size, + __entry->buffer_size + ) +); + #endif /* _PCM_TRACE_H */ /* This part must be outside protection */ From f5abd532227affc2129586f74d28d28c316ae1e3 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 12 Jun 2017 09:41:46 +0900 Subject: [PATCH 254/418] ALSA: pcm: use %s instead of %c for format of PCM buffer tracepoints As long as I know, in userspace, '%c' format on printing format for tracepoint is replaced with '>c<' by existent tracing program; i.g. 'perf-trace' and 'trace-cmd'. This is inconvenient. This commit replaces the format with '%s'. The length of letters in the format string is not changed, thus this commit doesn't increase object size. In theory, I should work for improvements of these tracing programs, but here I'd like to save my time to work for the other projects. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_trace.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/core/pcm_trace.h b/sound/core/pcm_trace.h index e672368ab878..3ddec1b8ae46 100644 --- a/sound/core/pcm_trace.h +++ b/sound/core/pcm_trace.h @@ -34,9 +34,9 @@ TRACE_EVENT(hwptr, __entry->old_hw_ptr = (substream)->runtime->status->hw_ptr; __entry->hw_ptr_base = (substream)->runtime->hw_ptr_base; ), - TP_printk("pcmC%dD%d%c/sub%d: %s: pos=%lu, old=%lu, base=%lu, period=%lu, buf=%lu", + TP_printk("pcmC%dD%d%s/sub%d: %s: pos=%lu, old=%lu, base=%lu, period=%lu, buf=%lu", __entry->card, __entry->device, - __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', + __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c", __entry->number, __entry->in_interrupt ? "IRQ" : "POS", (unsigned long)__entry->pos, @@ -69,9 +69,9 @@ TRACE_EVENT(xrun, __entry->old_hw_ptr = (substream)->runtime->status->hw_ptr; __entry->hw_ptr_base = (substream)->runtime->hw_ptr_base; ), - TP_printk("pcmC%dD%d%c/sub%d: XRUN: old=%lu, base=%lu, period=%lu, buf=%lu", + TP_printk("pcmC%dD%d%s/sub%d: XRUN: old=%lu, base=%lu, period=%lu, buf=%lu", __entry->card, __entry->device, - __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', + __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c", __entry->number, (unsigned long)__entry->old_hw_ptr, (unsigned long)__entry->hw_ptr_base, @@ -96,9 +96,9 @@ TRACE_EVENT(hw_ptr_error, __entry->stream = (substream)->stream; __entry->reason = (why); ), - TP_printk("pcmC%dD%d%c/sub%d: ERROR: %s", + TP_printk("pcmC%dD%d%s/sub%d: ERROR: %s", __entry->card, __entry->device, - __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', + __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c", __entry->number, __entry->reason) ); From fc05a5b222530617d99d0e803abb262130fdb0c4 Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Tue, 13 Jun 2017 15:27:46 +0800 Subject: [PATCH 255/418] ASoC: rockchip: add support for pdm controller The Pulse Density Modulation Interface Controller (PDMC) is a PDM interface controller and decoder that support PDM format. It integrates a clock generator driving the PDM microphone and embeds filters which decimate the incoming bit stream to obtain most common audio rates. Signed-off-by: Sugar Zhang Signed-off-by: Mark Brown --- .../bindings/sound/rockchip,pdm.txt | 39 ++ sound/soc/rockchip/Kconfig | 9 + sound/soc/rockchip/Makefile | 2 + sound/soc/rockchip/rockchip_pdm.c | 516 ++++++++++++++++++ sound/soc/rockchip/rockchip_pdm.h | 83 +++ 5 files changed, 649 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/rockchip,pdm.txt create mode 100644 sound/soc/rockchip/rockchip_pdm.c create mode 100644 sound/soc/rockchip/rockchip_pdm.h diff --git a/Documentation/devicetree/bindings/sound/rockchip,pdm.txt b/Documentation/devicetree/bindings/sound/rockchip,pdm.txt new file mode 100644 index 000000000000..921729de7346 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rockchip,pdm.txt @@ -0,0 +1,39 @@ +* Rockchip PDM controller + +Required properties: + +- compatible: "rockchip,pdm" +- reg: physical base address of the controller and length of memory mapped + region. +- dmas: DMA specifiers for rx dma. See the DMA client binding, + Documentation/devicetree/bindings/dma/dma.txt +- dma-names: should include "rx". +- clocks: a list of phandle + clock-specifer pairs, one for each entry in clock-names. +- clock-names: should contain following: + - "pdm_hclk": clock for PDM BUS + - "pdm_clk" : clock for PDM controller +- pinctrl-names: Must contain a "default" entry. +- pinctrl-N: One property must exist for each entry in + pinctrl-names. See ../pinctrl/pinctrl-bindings.txt + for details of the property values. + +Example for rk3328 PDM controller: + +pdm: pdm@ff040000 { + compatible = "rockchip,pdm"; + reg = <0x0 0xff040000 0x0 0x1000>; + clocks = <&clk_pdm>, <&clk_gates28 0>; + clock-names = "pdm_clk", "pdm_hclk"; + dmas = <&pdma 16>; + #dma-cells = <1>; + dma-names = "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pdmm0_clk + &pdmm0_fsync + &pdmm0_sdi0 + &pdmm0_sdi1 + &pdmm0_sdi2 + &pdmm0_sdi3>; + pinctrl-1 = <&pdmm0_sleep>; + status = "disabled"; +}; diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig index e3ca1e973de5..c84487805876 100644 --- a/sound/soc/rockchip/Kconfig +++ b/sound/soc/rockchip/Kconfig @@ -15,6 +15,15 @@ config SND_SOC_ROCKCHIP_I2S Rockchip I2S device. The device supports upto maximum of 8 channels each for play and record. +config SND_SOC_ROCKCHIP_PDM + tristate "Rockchip PDM Controller Driver" + depends on CLKDEV_LOOKUP && SND_SOC_ROCKCHIP + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y or M if you want to add support for PDM driver for + Rockchip PDM Controller. The Controller supports up to maximum of + 8 channels record. + config SND_SOC_ROCKCHIP_SPDIF tristate "Rockchip SPDIF Device Driver" depends on CLKDEV_LOOKUP && SND_SOC_ROCKCHIP diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile index 991f91bea9f9..105f0e14a4ab 100644 --- a/sound/soc/rockchip/Makefile +++ b/sound/soc/rockchip/Makefile @@ -1,8 +1,10 @@ # ROCKCHIP Platform Support snd-soc-rockchip-i2s-objs := rockchip_i2s.o +snd-soc-rockchip-pdm-objs := rockchip_pdm.o snd-soc-rockchip-spdif-objs := rockchip_spdif.o obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-rockchip-i2s.o +obj-$(CONFIG_SND_SOC_ROCKCHIP_PDM) += snd-soc-rockchip-pdm.o obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o snd-soc-rockchip-max98090-objs := rockchip_max98090.o diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c new file mode 100644 index 000000000000..c5ddeed97260 --- /dev/null +++ b/sound/soc/rockchip/rockchip_pdm.c @@ -0,0 +1,516 @@ +/* + * Rockchip PDM ALSA SoC Digital Audio Interface(DAI) driver + * + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "rockchip_pdm.h" + +#define PDM_DMA_BURST_SIZE (16) /* size * width: 16*4 = 64 bytes */ + +struct rk_pdm_dev { + struct device *dev; + struct clk *clk; + struct clk *hclk; + struct regmap *regmap; + struct snd_dmaengine_dai_dma_data capture_dma_data; +}; + +struct rk_pdm_clkref { + unsigned int sr; + unsigned int clk; +}; + +static struct rk_pdm_clkref clkref[] = { + { 8000, 40960000 }, + { 11025, 56448000 }, + { 12000, 61440000 }, +}; + +static unsigned int get_pdm_clk(unsigned int sr) +{ + unsigned int i, count, clk, div; + + clk = 0; + if (!sr) + return clk; + + count = ARRAY_SIZE(clkref); + for (i = 0; i < count; i++) { + if (sr % clkref[i].sr) + continue; + div = sr / clkref[i].sr; + if ((div & (div - 1)) == 0) { + clk = clkref[i].clk; + break; + } + } + + return clk; +} + +static inline struct rk_pdm_dev *to_info(struct snd_soc_dai *dai) +{ + return snd_soc_dai_get_drvdata(dai); +} + +static void rockchip_pdm_rxctrl(struct rk_pdm_dev *pdm, int on) +{ + if (on) { + regmap_update_bits(pdm->regmap, PDM_DMA_CTRL, + PDM_DMA_RD_MSK, PDM_DMA_RD_EN); + regmap_update_bits(pdm->regmap, PDM_SYSCONFIG, + PDM_RX_MASK, PDM_RX_START); + } else { + regmap_update_bits(pdm->regmap, PDM_DMA_CTRL, + PDM_DMA_RD_MSK, PDM_DMA_RD_DIS); + regmap_update_bits(pdm->regmap, PDM_SYSCONFIG, + PDM_RX_MASK | PDM_RX_CLR_MASK, + PDM_RX_STOP | PDM_RX_CLR_WR); + } +} + +static int rockchip_pdm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct rk_pdm_dev *pdm = to_info(dai); + unsigned int val = 0; + unsigned int clk_rate, clk_div, samplerate; + int ret; + + samplerate = params_rate(params); + clk_rate = get_pdm_clk(samplerate); + if (!clk_rate) + return -EINVAL; + + ret = clk_set_rate(pdm->clk, clk_rate); + if (ret) + return -EINVAL; + + clk_div = DIV_ROUND_CLOSEST(clk_rate, samplerate); + + switch (clk_div) { + case 320: + val = PDM_CLK_320FS; + break; + case 640: + val = PDM_CLK_640FS; + break; + case 1280: + val = PDM_CLK_1280FS; + break; + case 2560: + val = PDM_CLK_2560FS; + break; + case 5120: + val = PDM_CLK_5120FS; + break; + default: + dev_err(pdm->dev, "unsupported div: %d\n", clk_div); + return -EINVAL; + } + + regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, PDM_DS_RATIO_MSK, val); + regmap_update_bits(pdm->regmap, PDM_HPF_CTRL, + PDM_HPF_CF_MSK, PDM_HPF_60HZ); + regmap_update_bits(pdm->regmap, PDM_HPF_CTRL, + PDM_HPF_LE | PDM_HPF_RE, PDM_HPF_LE | PDM_HPF_RE); + regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, PDM_CLK_EN, PDM_CLK_EN); + + val = 0; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + val |= PDM_VDW(8); + break; + case SNDRV_PCM_FORMAT_S16_LE: + val |= PDM_VDW(16); + break; + case SNDRV_PCM_FORMAT_S20_3LE: + val |= PDM_VDW(20); + break; + case SNDRV_PCM_FORMAT_S24_LE: + val |= PDM_VDW(24); + break; + case SNDRV_PCM_FORMAT_S32_LE: + val |= PDM_VDW(32); + break; + default: + return -EINVAL; + } + + switch (params_channels(params)) { + case 8: + val |= PDM_PATH3_EN; + /* fallthrough */ + case 6: + val |= PDM_PATH2_EN; + /* fallthrough */ + case 4: + val |= PDM_PATH1_EN; + /* fallthrough */ + case 2: + val |= PDM_PATH0_EN; + break; + default: + dev_err(pdm->dev, "invalid channel: %d\n", + params_channels(params)); + return -EINVAL; + } + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + regmap_update_bits(pdm->regmap, PDM_CTRL0, + PDM_PATH_MSK | PDM_VDW_MSK, + val); + regmap_update_bits(pdm->regmap, PDM_DMA_CTRL, PDM_DMA_RDL_MSK, + PDM_DMA_RDL(16)); + regmap_update_bits(pdm->regmap, PDM_SYSCONFIG, + PDM_RX_MASK | PDM_RX_CLR_MASK, + PDM_RX_STOP | PDM_RX_CLR_WR); + } + + return 0; +} + +static int rockchip_pdm_set_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + struct rk_pdm_dev *pdm = to_info(cpu_dai); + unsigned int mask = 0, val = 0; + + mask = PDM_CKP_MSK; + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + val = PDM_CKP_NORMAL; + break; + case SND_SOC_DAIFMT_IB_NF: + val = PDM_CKP_INVERTED; + break; + default: + return -EINVAL; + } + + regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, mask, val); + + return 0; +} + +static int rockchip_pdm_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct rk_pdm_dev *pdm = to_info(dai); + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + rockchip_pdm_rxctrl(pdm, 1); + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + rockchip_pdm_rxctrl(pdm, 0); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int rockchip_pdm_dai_probe(struct snd_soc_dai *dai) +{ + struct rk_pdm_dev *pdm = to_info(dai); + + dai->capture_dma_data = &pdm->capture_dma_data; + + return 0; +} + +static struct snd_soc_dai_ops rockchip_pdm_dai_ops = { + .set_fmt = rockchip_pdm_set_fmt, + .trigger = rockchip_pdm_trigger, + .hw_params = rockchip_pdm_hw_params, +}; + +#define ROCKCHIP_PDM_RATES SNDRV_PCM_RATE_8000_192000 +#define ROCKCHIP_PDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver rockchip_pdm_dai = { + .probe = rockchip_pdm_dai_probe, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 8, + .rates = ROCKCHIP_PDM_RATES, + .formats = ROCKCHIP_PDM_FORMATS, + }, + .ops = &rockchip_pdm_dai_ops, + .symmetric_rates = 1, +}; + +static const struct snd_soc_component_driver rockchip_pdm_component = { + .name = "rockchip-pdm", +}; + +static int rockchip_pdm_runtime_suspend(struct device *dev) +{ + struct rk_pdm_dev *pdm = dev_get_drvdata(dev); + + clk_disable_unprepare(pdm->clk); + clk_disable_unprepare(pdm->hclk); + + return 0; +} + +static int rockchip_pdm_runtime_resume(struct device *dev) +{ + struct rk_pdm_dev *pdm = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(pdm->clk); + if (ret) { + dev_err(pdm->dev, "clock enable failed %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(pdm->hclk); + if (ret) { + dev_err(pdm->dev, "hclock enable failed %d\n", ret); + return ret; + } + + return 0; +} + +static bool rockchip_pdm_wr_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case PDM_SYSCONFIG: + case PDM_CTRL0: + case PDM_CTRL1: + case PDM_CLK_CTRL: + case PDM_HPF_CTRL: + case PDM_FIFO_CTRL: + case PDM_DMA_CTRL: + case PDM_INT_EN: + case PDM_INT_CLR: + case PDM_DATA_VALID: + return true; + default: + return false; + } +} + +static bool rockchip_pdm_rd_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case PDM_SYSCONFIG: + case PDM_CTRL0: + case PDM_CTRL1: + case PDM_CLK_CTRL: + case PDM_HPF_CTRL: + case PDM_FIFO_CTRL: + case PDM_DMA_CTRL: + case PDM_INT_EN: + case PDM_INT_CLR: + case PDM_INT_ST: + case PDM_DATA_VALID: + case PDM_VERSION: + return true; + default: + return false; + } +} + +static bool rockchip_pdm_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case PDM_SYSCONFIG: + case PDM_INT_CLR: + case PDM_INT_ST: + return true; + default: + return false; + } +} + +static const struct regmap_config rockchip_pdm_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = PDM_VERSION, + .writeable_reg = rockchip_pdm_wr_reg, + .readable_reg = rockchip_pdm_rd_reg, + .volatile_reg = rockchip_pdm_volatile_reg, + .cache_type = REGCACHE_FLAT, +}; + +static int rockchip_pdm_probe(struct platform_device *pdev) +{ + struct rk_pdm_dev *pdm; + struct resource *res; + void __iomem *regs; + int ret; + + pdm = devm_kzalloc(&pdev->dev, sizeof(*pdm), GFP_KERNEL); + if (!pdm) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + pdm->regmap = devm_regmap_init_mmio(&pdev->dev, regs, + &rockchip_pdm_regmap_config); + if (IS_ERR(pdm->regmap)) + return PTR_ERR(pdm->regmap); + + pdm->capture_dma_data.addr = res->start + PDM_RXFIFO_DATA; + pdm->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + pdm->capture_dma_data.maxburst = PDM_DMA_BURST_SIZE; + + pdm->dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, pdm); + + pdm->clk = devm_clk_get(&pdev->dev, "pdm_clk"); + if (IS_ERR(pdm->clk)) + return PTR_ERR(pdm->clk); + + pdm->hclk = devm_clk_get(&pdev->dev, "pdm_hclk"); + if (IS_ERR(pdm->hclk)) + return PTR_ERR(pdm->hclk); + + ret = clk_prepare_enable(pdm->hclk); + if (ret) + return ret; + + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = rockchip_pdm_runtime_resume(&pdev->dev); + if (ret) + goto err_pm_disable; + } + + ret = devm_snd_soc_register_component(&pdev->dev, + &rockchip_pdm_component, + &rockchip_pdm_dai, 1); + + if (ret) { + dev_err(&pdev->dev, "could not register dai: %d\n", ret); + goto err_suspend; + } + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) { + dev_err(&pdev->dev, "could not register pcm: %d\n", ret); + goto err_suspend; + } + + return 0; + +err_suspend: + if (!pm_runtime_status_suspended(&pdev->dev)) + rockchip_pdm_runtime_suspend(&pdev->dev); +err_pm_disable: + pm_runtime_disable(&pdev->dev); + + clk_disable_unprepare(pdm->hclk); + + return ret; +} + +static int rockchip_pdm_remove(struct platform_device *pdev) +{ + struct rk_pdm_dev *pdm = dev_get_drvdata(&pdev->dev); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + rockchip_pdm_runtime_suspend(&pdev->dev); + + clk_disable_unprepare(pdm->clk); + clk_disable_unprepare(pdm->hclk); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int rockchip_pdm_suspend(struct device *dev) +{ + struct rk_pdm_dev *pdm = dev_get_drvdata(dev); + + regcache_mark_dirty(pdm->regmap); + + return 0; +} + +static int rockchip_pdm_resume(struct device *dev) +{ + struct rk_pdm_dev *pdm = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_get_sync(dev); + if (ret < 0) + return ret; + + ret = regcache_sync(pdm->regmap); + + pm_runtime_put(dev); + + return ret; +} +#endif + +static const struct dev_pm_ops rockchip_pdm_pm_ops = { + SET_RUNTIME_PM_OPS(rockchip_pdm_runtime_suspend, + rockchip_pdm_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(rockchip_pdm_suspend, rockchip_pdm_resume) +}; + +static const struct of_device_id rockchip_pdm_match[] = { + { .compatible = "rockchip,pdm", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rockchip_pdm_match); + +static struct platform_driver rockchip_pdm_driver = { + .probe = rockchip_pdm_probe, + .remove = rockchip_pdm_remove, + .driver = { + .name = "rockchip-pdm", + .of_match_table = of_match_ptr(rockchip_pdm_match), + .pm = &rockchip_pdm_pm_ops, + }, +}; + +module_platform_driver(rockchip_pdm_driver); + +MODULE_AUTHOR("Sugar "); +MODULE_DESCRIPTION("Rockchip PDM Controller Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/rockchip/rockchip_pdm.h b/sound/soc/rockchip/rockchip_pdm.h new file mode 100644 index 000000000000..886b48d128fd --- /dev/null +++ b/sound/soc/rockchip/rockchip_pdm.h @@ -0,0 +1,83 @@ +/* + * Rockchip PDM ALSA SoC Digital Audio Interface(DAI) driver + * + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _ROCKCHIP_PDM_H +#define _ROCKCHIP_PDM_H + +/* PDM REGS */ +#define PDM_SYSCONFIG (0x0000) +#define PDM_CTRL0 (0x0004) +#define PDM_CTRL1 (0x0008) +#define PDM_CLK_CTRL (0x000c) +#define PDM_HPF_CTRL (0x0010) +#define PDM_FIFO_CTRL (0x0014) +#define PDM_DMA_CTRL (0x0018) +#define PDM_INT_EN (0x001c) +#define PDM_INT_CLR (0x0020) +#define PDM_INT_ST (0x0024) +#define PDM_RXFIFO_DATA (0x0030) +#define PDM_DATA_VALID (0x0054) +#define PDM_VERSION (0x0058) + +/* PDM_SYSCONFIG */ +#define PDM_RX_MASK (0x1 << 2) +#define PDM_RX_START (0x1 << 2) +#define PDM_RX_STOP (0x0 << 2) +#define PDM_RX_CLR_MASK (0x1 << 0) +#define PDM_RX_CLR_WR (0x1 << 0) +#define PDM_RX_CLR_DONE (0x0 << 0) + +/* PDM CTRL0 */ +#define PDM_PATH_MSK (0xf << 27) +#define PDM_PATH3_EN BIT(30) +#define PDM_PATH2_EN BIT(29) +#define PDM_PATH1_EN BIT(28) +#define PDM_PATH0_EN BIT(27) +#define PDM_HWT_EN BIT(26) +#define PDM_VDW_MSK (0x1f << 0) +#define PDM_VDW(X) ((X - 1) << 0) + +/* PDM CLK CTRL */ +#define PDM_CLK_MSK BIT(5) +#define PDM_CLK_EN BIT(5) +#define PDM_CLK_DIS (0x0 << 5) +#define PDM_CKP_MSK BIT(3) +#define PDM_CKP_NORMAL (0x0 << 3) +#define PDM_CKP_INVERTED BIT(3) +#define PDM_DS_RATIO_MSK (0x7 << 0) +#define PDM_CLK_320FS (0x0 << 0) +#define PDM_CLK_640FS (0x1 << 0) +#define PDM_CLK_1280FS (0x2 << 0) +#define PDM_CLK_2560FS (0x3 << 0) +#define PDM_CLK_5120FS (0x4 << 0) + +/* PDM HPF CTRL */ +#define PDM_HPF_LE BIT(3) +#define PDM_HPF_RE BIT(2) +#define PDM_HPF_CF_MSK (0x3 << 0) +#define PDM_HPF_3P79HZ (0x0 << 0) +#define PDM_HPF_60HZ (0x1 << 0) +#define PDM_HPF_243HZ (0x2 << 0) +#define PDM_HPF_493HZ (0x3 << 0) + +/* PDM DMA CTRL */ +#define PDM_DMA_RD_MSK BIT(8) +#define PDM_DMA_RD_EN BIT(8) +#define PDM_DMA_RD_DIS (0x0 << 8) +#define PDM_DMA_RDL_MSK (0x7f << 0) +#define PDM_DMA_RDL(X) ((X - 1) << 0) + +#endif /* _ROCKCHIP_PDM_H */ From b8b88b70875af786d9f346d766fa2b0630e2cf41 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Mon, 12 Jun 2017 11:01:45 -0600 Subject: [PATCH 256/418] ASoC: add es8316 codec driver Add a codec driver for the Everest ES8316, based on code provided by David Yang from Everest Semi. I limited the functionality to items where the vendor code was clear, and things that can be tested on the Weibu F3C (Intel Cherry Trail). As a result the initial implementation only supports running in slave mode at single speed (up to 48kHz sample rate) using I2S. HPD is not supported. Signed-off-by: David Yang [drake@endlessm.com: significant cleanups and simplifications, remove dead/unclear code] Signed-off-by: Daniel Drake Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/es8316.c | 637 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/es8316.h | 129 ++++++++ 4 files changed, 772 insertions(+) create mode 100644 sound/soc/codecs/es8316.c create mode 100644 sound/soc/codecs/es8316.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 883ed4c8a551..c6286e5ba511 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -72,6 +72,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_DA9055 if I2C select SND_SOC_DIO2125 select SND_SOC_DMIC + select SND_SOC_ES8316 if I2C select SND_SOC_ES8328_SPI if SPI_MASTER select SND_SOC_ES8328_I2C if I2C select SND_SOC_ES7134 @@ -543,6 +544,9 @@ config SND_SOC_HDMI_CODEC config SND_SOC_ES7134 tristate "Everest Semi ES7134 CODEC" +config SND_SOC_ES8316 + tristate "Everest Semi ES8316 CODEC" + config SND_SOC_ES8328 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 28a63fdaf982..e878306ce46e 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -65,6 +65,7 @@ snd-soc-da732x-objs := da732x.o snd-soc-da9055-objs := da9055.o snd-soc-dmic-objs := dmic.o snd-soc-es7134-objs := es7134.o +snd-soc-es8316-objs := es8316.o snd-soc-es8328-objs := es8328.o snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o @@ -300,6 +301,7 @@ obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o obj-$(CONFIG_SND_SOC_ES7134) += snd-soc-es7134.o +obj-$(CONFIG_SND_SOC_ES8316) += snd-soc-es8316.o obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c new file mode 100644 index 000000000000..ecc02449c569 --- /dev/null +++ b/sound/soc/codecs/es8316.c @@ -0,0 +1,637 @@ +/* + * es8316.c -- es8316 ALSA SoC audio driver + * Copyright Everest Semiconductor Co.,Ltd + * + * Authors: David Yang , + * Daniel Drake + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "es8316.h" + +/* In slave mode at single speed, the codec is documented as accepting 5 + * MCLK/LRCK ratios, but we also add ratio 400, which is commonly used on + * Intel Cherry Trail platforms (19.2MHz MCLK, 48kHz LRCK). + */ +#define NR_SUPPORTED_MCLK_LRCK_RATIOS 6 +static const unsigned int supported_mclk_lrck_ratios[] = { + 256, 384, 400, 512, 768, 1024 +}; + +struct es8316_priv { + unsigned int sysclk; + unsigned int allowed_rates[NR_SUPPORTED_MCLK_LRCK_RATIOS]; + struct snd_pcm_hw_constraint_list sysclk_constraints; +}; + +/* + * ES8316 controls + */ +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9600, 50, 1); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_vol_tlv, -9600, 50, 1); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_max_gain_tlv, -650, 150, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_min_gain_tlv, -1200, 150, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_target_tlv, -1650, 150, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(hpmixer_gain_tlv, -1200, 150, 0); + +static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(adc_pga_gain_tlv, + 0, 0, TLV_DB_SCALE_ITEM(-350, 0, 0), + 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), +); + +static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(hpout_vol_tlv, + 0, 0, TLV_DB_SCALE_ITEM(-4800, 0, 0), + 1, 3, TLV_DB_SCALE_ITEM(-2400, 1200, 0), +); + +static const char * const ng_type_txt[] = + { "Constant PGA Gain", "Mute ADC Output" }; +static const struct soc_enum ng_type = + SOC_ENUM_SINGLE(ES8316_ADC_ALC_NG, 6, 2, ng_type_txt); + +static const char * const adcpol_txt[] = { "Normal", "Invert" }; +static const struct soc_enum adcpol = + SOC_ENUM_SINGLE(ES8316_ADC_MUTE, 1, 2, adcpol_txt); +static const char *const dacpol_txt[] = + { "Normal", "R Invert", "L Invert", "L + R Invert" }; +static const struct soc_enum dacpol = + SOC_ENUM_SINGLE(ES8316_DAC_SET1, 0, 4, dacpol_txt); + +static const struct snd_kcontrol_new es8316_snd_controls[] = { + SOC_DOUBLE_TLV("Headphone Playback Volume", ES8316_CPHP_ICAL_VOL, + 4, 0, 3, 1, hpout_vol_tlv), + SOC_DOUBLE_TLV("Headphone Mixer Volume", ES8316_HPMIX_VOL, + 0, 4, 7, 0, hpmixer_gain_tlv), + + SOC_ENUM("Playback Polarity", dacpol), + SOC_DOUBLE_R_TLV("DAC Playback Volume", ES8316_DAC_VOLL, + ES8316_DAC_VOLR, 0, 0xc0, 1, dac_vol_tlv), + SOC_SINGLE("DAC Soft Ramp Switch", ES8316_DAC_SET1, 4, 1, 1), + SOC_SINGLE("DAC Soft Ramp Rate", ES8316_DAC_SET1, 2, 4, 0), + SOC_SINGLE("DAC Notch Filter Switch", ES8316_DAC_SET2, 6, 1, 0), + SOC_SINGLE("DAC Double Fs Switch", ES8316_DAC_SET2, 7, 1, 0), + SOC_SINGLE("DAC Stereo Enhancement", ES8316_DAC_SET3, 0, 7, 0), + + SOC_ENUM("Capture Polarity", adcpol), + SOC_SINGLE("Mic Boost Switch", ES8316_ADC_D2SEPGA, 0, 1, 0), + SOC_SINGLE_TLV("ADC Capture Volume", ES8316_ADC_VOLUME, + 0, 0xc0, 1, adc_vol_tlv), + SOC_SINGLE_TLV("ADC PGA Gain Volume", ES8316_ADC_PGAGAIN, + 4, 10, 0, adc_pga_gain_tlv), + SOC_SINGLE("ADC Soft Ramp Switch", ES8316_ADC_MUTE, 4, 1, 0), + SOC_SINGLE("ADC Double Fs Switch", ES8316_ADC_DMIC, 4, 1, 0), + + SOC_SINGLE("ALC Capture Switch", ES8316_ADC_ALC1, 6, 1, 0), + SOC_SINGLE_TLV("ALC Capture Max Volume", ES8316_ADC_ALC1, 0, 28, 0, + alc_max_gain_tlv), + SOC_SINGLE_TLV("ALC Capture Min Volume", ES8316_ADC_ALC2, 0, 28, 0, + alc_min_gain_tlv), + SOC_SINGLE_TLV("ALC Capture Target Volume", ES8316_ADC_ALC3, 4, 10, 0, + alc_target_tlv), + SOC_SINGLE("ALC Capture Hold Time", ES8316_ADC_ALC3, 0, 10, 0), + SOC_SINGLE("ALC Capture Decay Time", ES8316_ADC_ALC4, 4, 10, 0), + SOC_SINGLE("ALC Capture Attack Time", ES8316_ADC_ALC4, 0, 10, 0), + SOC_SINGLE("ALC Capture Noise Gate Switch", ES8316_ADC_ALC_NG, + 5, 1, 0), + SOC_SINGLE("ALC Capture Noise Gate Threshold", ES8316_ADC_ALC_NG, + 0, 31, 0), + SOC_ENUM("ALC Capture Noise Gate Type", ng_type), +}; + +/* Analog Input Mux */ +static const char * const es8316_analog_in_txt[] = { + "lin1-rin1", + "lin2-rin2", + "lin1-rin1 with 20db Boost", + "lin2-rin2 with 20db Boost" +}; +static const unsigned int es8316_analog_in_values[] = { 0, 1, 2, 3 }; +static const struct soc_enum es8316_analog_input_enum = + SOC_VALUE_ENUM_SINGLE(ES8316_ADC_PDN_LINSEL, 4, 3, + ARRAY_SIZE(es8316_analog_in_txt), + es8316_analog_in_txt, + es8316_analog_in_values); +static const struct snd_kcontrol_new es8316_analog_in_mux_controls = + SOC_DAPM_ENUM("Route", es8316_analog_input_enum); + +static const char * const es8316_dmic_txt[] = { + "dmic disable", + "dmic data at high level", + "dmic data at low level", +}; +static const unsigned int es8316_dmic_values[] = { 0, 1, 2 }; +static const struct soc_enum es8316_dmic_src_enum = + SOC_VALUE_ENUM_SINGLE(ES8316_ADC_DMIC, 0, 3, + ARRAY_SIZE(es8316_dmic_txt), + es8316_dmic_txt, + es8316_dmic_values); +static const struct snd_kcontrol_new es8316_dmic_src_controls = + SOC_DAPM_ENUM("Route", es8316_dmic_src_enum); + +/* hp mixer mux */ +static const char * const es8316_hpmux_texts[] = { + "lin1-rin1", + "lin2-rin2", + "lin-rin with Boost", + "lin-rin with Boost and PGA" +}; + +static const unsigned int es8316_hpmux_values[] = { 0, 1, 2, 3 }; + +static SOC_ENUM_SINGLE_DECL(es8316_left_hpmux_enum, ES8316_HPMIX_SEL, + 4, es8316_hpmux_texts); + +static const struct snd_kcontrol_new es8316_left_hpmux_controls = + SOC_DAPM_ENUM("Route", es8316_left_hpmux_enum); + +static SOC_ENUM_SINGLE_DECL(es8316_right_hpmux_enum, ES8316_HPMIX_SEL, + 0, es8316_hpmux_texts); + +static const struct snd_kcontrol_new es8316_right_hpmux_controls = + SOC_DAPM_ENUM("Route", es8316_right_hpmux_enum); + +/* headphone Output Mixer */ +static const struct snd_kcontrol_new es8316_out_left_mix[] = { + SOC_DAPM_SINGLE("LLIN Switch", ES8316_HPMIX_SWITCH, 6, 1, 0), + SOC_DAPM_SINGLE("Left DAC Switch", ES8316_HPMIX_SWITCH, 7, 1, 0), +}; +static const struct snd_kcontrol_new es8316_out_right_mix[] = { + SOC_DAPM_SINGLE("RLIN Switch", ES8316_HPMIX_SWITCH, 2, 1, 0), + SOC_DAPM_SINGLE("Right DAC Switch", ES8316_HPMIX_SWITCH, 3, 1, 0), +}; + +/* DAC data source mux */ +static const char * const es8316_dacsrc_texts[] = { + "LDATA TO LDAC, RDATA TO RDAC", + "LDATA TO LDAC, LDATA TO RDAC", + "RDATA TO LDAC, RDATA TO RDAC", + "RDATA TO LDAC, LDATA TO RDAC", +}; + +static const unsigned int es8316_dacsrc_values[] = { 0, 1, 2, 3 }; + +static SOC_ENUM_SINGLE_DECL(es8316_dacsrc_mux_enum, ES8316_DAC_SET1, + 6, es8316_dacsrc_texts); + +static const struct snd_kcontrol_new es8316_dacsrc_mux_controls = + SOC_DAPM_ENUM("Route", es8316_dacsrc_mux_enum); + +static const struct snd_soc_dapm_widget es8316_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("Bias", ES8316_SYS_PDN, 3, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Analog power", ES8316_SYS_PDN, 4, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Bias", ES8316_SYS_PDN, 5, 1, NULL, 0), + + SND_SOC_DAPM_INPUT("DMIC"), + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + + /* Input Mux */ + SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, + &es8316_analog_in_mux_controls), + + SND_SOC_DAPM_SUPPLY("ADC Vref", ES8316_SYS_PDN, 1, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC bias", ES8316_SYS_PDN, 2, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC Clock", ES8316_CLKMGR_CLKSW, 3, 0, NULL, 0), + SND_SOC_DAPM_PGA("Line input PGA", ES8316_ADC_PDN_LINSEL, + 7, 1, NULL, 0), + SND_SOC_DAPM_ADC("Mono ADC", NULL, ES8316_ADC_PDN_LINSEL, 6, 1), + SND_SOC_DAPM_MUX("Digital Mic Mux", SND_SOC_NOPM, 0, 0, + &es8316_dmic_src_controls), + + /* Digital Interface */ + SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture", 1, + ES8316_SERDATA_ADC, 6, 1), + SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_MUX("DAC Source Mux", SND_SOC_NOPM, 0, 0, + &es8316_dacsrc_mux_controls), + + SND_SOC_DAPM_SUPPLY("DAC Vref", ES8316_SYS_PDN, 0, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Clock", ES8316_CLKMGR_CLKSW, 2, 0, NULL, 0), + SND_SOC_DAPM_DAC("Right DAC", NULL, ES8316_DAC_PDN, 0, 1), + SND_SOC_DAPM_DAC("Left DAC", NULL, ES8316_DAC_PDN, 4, 1), + + /* Headphone Output Side */ + SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, + &es8316_left_hpmux_controls), + SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, + &es8316_right_hpmux_controls), + SND_SOC_DAPM_MIXER("Left Headphone Mixer", ES8316_HPMIX_PDN, + 5, 1, &es8316_out_left_mix[0], + ARRAY_SIZE(es8316_out_left_mix)), + SND_SOC_DAPM_MIXER("Right Headphone Mixer", ES8316_HPMIX_PDN, + 1, 1, &es8316_out_right_mix[0], + ARRAY_SIZE(es8316_out_right_mix)), + SND_SOC_DAPM_PGA("Left Headphone Mixer Out", ES8316_HPMIX_PDN, + 4, 1, NULL, 0), + SND_SOC_DAPM_PGA("Right Headphone Mixer Out", ES8316_HPMIX_PDN, + 0, 1, NULL, 0), + + SND_SOC_DAPM_OUT_DRV("Left Headphone Charge Pump", ES8316_CPHP_OUTEN, + 6, 0, NULL, 0), + SND_SOC_DAPM_OUT_DRV("Right Headphone Charge Pump", ES8316_CPHP_OUTEN, + 2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", ES8316_CPHP_PDN2, + 5, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Headphone Charge Pump Clock", ES8316_CLKMGR_CLKSW, + 4, 0, NULL, 0), + + SND_SOC_DAPM_OUT_DRV("Left Headphone Driver", ES8316_CPHP_OUTEN, + 5, 0, NULL, 0), + SND_SOC_DAPM_OUT_DRV("Right Headphone Driver", ES8316_CPHP_OUTEN, + 1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Headphone Out", ES8316_CPHP_PDN1, 2, 1, NULL, 0), + + /* pdn_Lical and pdn_Rical bits are documented as Reserved, but must + * be explicitly unset in order to enable HP output + */ + SND_SOC_DAPM_SUPPLY("Left Headphone ical", ES8316_CPHP_ICAL_VOL, + 7, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Right Headphone ical", ES8316_CPHP_ICAL_VOL, + 3, 1, NULL, 0), + + SND_SOC_DAPM_OUTPUT("HPOL"), + SND_SOC_DAPM_OUTPUT("HPOR"), +}; + +static const struct snd_soc_dapm_route es8316_dapm_routes[] = { + /* Recording */ + {"MIC1", NULL, "Mic Bias"}, + {"MIC2", NULL, "Mic Bias"}, + {"MIC1", NULL, "Bias"}, + {"MIC2", NULL, "Bias"}, + {"MIC1", NULL, "Analog power"}, + {"MIC2", NULL, "Analog power"}, + + {"Differential Mux", "lin1-rin1", "MIC1"}, + {"Differential Mux", "lin2-rin2", "MIC2"}, + {"Line input PGA", NULL, "Differential Mux"}, + + {"Mono ADC", NULL, "ADC Clock"}, + {"Mono ADC", NULL, "ADC Vref"}, + {"Mono ADC", NULL, "ADC bias"}, + {"Mono ADC", NULL, "Line input PGA"}, + + /* It's not clear why, but to avoid recording only silence, + * the DAC clock must be running for the ADC to work. + */ + {"Mono ADC", NULL, "DAC Clock"}, + + {"Digital Mic Mux", "dmic disable", "Mono ADC"}, + + {"I2S OUT", NULL, "Digital Mic Mux"}, + + /* Playback */ + {"DAC Source Mux", "LDATA TO LDAC, RDATA TO RDAC", "I2S IN"}, + + {"Left DAC", NULL, "DAC Clock"}, + {"Right DAC", NULL, "DAC Clock"}, + + {"Left DAC", NULL, "DAC Vref"}, + {"Right DAC", NULL, "DAC Vref"}, + + {"Left DAC", NULL, "DAC Source Mux"}, + {"Right DAC", NULL, "DAC Source Mux"}, + + {"Left Headphone Mux", "lin-rin with Boost and PGA", "Line input PGA"}, + {"Right Headphone Mux", "lin-rin with Boost and PGA", "Line input PGA"}, + + {"Left Headphone Mixer", "LLIN Switch", "Left Headphone Mux"}, + {"Left Headphone Mixer", "Left DAC Switch", "Left DAC"}, + + {"Right Headphone Mixer", "RLIN Switch", "Right Headphone Mux"}, + {"Right Headphone Mixer", "Right DAC Switch", "Right DAC"}, + + {"Left Headphone Mixer Out", NULL, "Left Headphone Mixer"}, + {"Right Headphone Mixer Out", NULL, "Right Headphone Mixer"}, + + {"Left Headphone Charge Pump", NULL, "Left Headphone Mixer Out"}, + {"Right Headphone Charge Pump", NULL, "Right Headphone Mixer Out"}, + + {"Left Headphone Charge Pump", NULL, "Headphone Charge Pump"}, + {"Right Headphone Charge Pump", NULL, "Headphone Charge Pump"}, + + {"Left Headphone Charge Pump", NULL, "Headphone Charge Pump Clock"}, + {"Right Headphone Charge Pump", NULL, "Headphone Charge Pump Clock"}, + + {"Left Headphone Driver", NULL, "Left Headphone Charge Pump"}, + {"Right Headphone Driver", NULL, "Right Headphone Charge Pump"}, + + {"HPOL", NULL, "Left Headphone Driver"}, + {"HPOR", NULL, "Right Headphone Driver"}, + + {"HPOL", NULL, "Left Headphone ical"}, + {"HPOR", NULL, "Right Headphone ical"}, + + {"Headphone Out", NULL, "Bias"}, + {"Headphone Out", NULL, "Analog power"}, + {"HPOL", NULL, "Headphone Out"}, + {"HPOR", NULL, "Headphone Out"}, +}; + +static int es8316_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec); + int i; + int count = 0; + + es8316->sysclk = freq; + + if (freq == 0) + return 0; + + /* Limit supported sample rates to ones that can be autodetected + * by the codec running in slave mode. + */ + for (i = 0; i < NR_SUPPORTED_MCLK_LRCK_RATIOS; i++) { + const unsigned int ratio = supported_mclk_lrck_ratios[i]; + + if (freq % ratio == 0) + es8316->allowed_rates[count++] = freq / ratio; + } + + es8316->sysclk_constraints.list = es8316->allowed_rates; + es8316->sysclk_constraints.count = count; + + return 0; +} + +static int es8316_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u8 serdata1 = 0; + u8 serdata2 = 0; + u8 clksw; + u8 mask; + + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + dev_err(codec->dev, "Codec driver only supports slave mode\n"); + return -EINVAL; + } + + if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) { + dev_err(codec->dev, "Codec driver only supports I2S format\n"); + return -EINVAL; + } + + /* Clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + serdata1 |= ES8316_SERDATA1_BCLK_INV; + serdata2 |= ES8316_SERDATA2_ADCLRP; + break; + case SND_SOC_DAIFMT_IB_NF: + serdata1 |= ES8316_SERDATA1_BCLK_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + serdata2 |= ES8316_SERDATA2_ADCLRP; + break; + default: + return -EINVAL; + } + + mask = ES8316_SERDATA1_MASTER | ES8316_SERDATA1_BCLK_INV; + snd_soc_update_bits(codec, ES8316_SERDATA1, mask, serdata1); + + mask = ES8316_SERDATA2_FMT_MASK | ES8316_SERDATA2_ADCLRP; + snd_soc_update_bits(codec, ES8316_SERDATA_ADC, mask, serdata2); + snd_soc_update_bits(codec, ES8316_SERDATA_DAC, mask, serdata2); + + /* Enable BCLK and MCLK inputs in slave mode */ + clksw = ES8316_CLKMGR_CLKSW_MCLK_ON | ES8316_CLKMGR_CLKSW_BCLK_ON; + snd_soc_update_bits(codec, ES8316_CLKMGR_CLKSW, clksw, clksw); + + return 0; +} + +static int es8316_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec); + + if (es8316->sysclk == 0) { + dev_err(codec->dev, "No sysclk provided\n"); + return -EINVAL; + } + + /* The set of sample rates that can be supported depends on the + * MCLK supplied to the CODEC. + */ + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &es8316->sysclk_constraints); + + return 0; +} + +static int es8316_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec); + u8 wordlen = 0; + + if (!es8316->sysclk) { + dev_err(codec->dev, "No MCLK configured\n"); + return -EINVAL; + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + wordlen = ES8316_SERDATA2_LEN_16; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + wordlen = ES8316_SERDATA2_LEN_20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + wordlen = ES8316_SERDATA2_LEN_24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + wordlen = ES8316_SERDATA2_LEN_32; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, ES8316_SERDATA_DAC, + ES8316_SERDATA2_LEN_MASK, wordlen); + snd_soc_update_bits(codec, ES8316_SERDATA_ADC, + ES8316_SERDATA2_LEN_MASK, wordlen); + return 0; +} + +static int es8316_mute(struct snd_soc_dai *dai, int mute) +{ + snd_soc_update_bits(dai->codec, ES8316_DAC_SET1, 0x20, + mute ? 0x20 : 0); + return 0; +} + +#define ES8316_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_ops es8316_ops = { + .startup = es8316_pcm_startup, + .hw_params = es8316_pcm_hw_params, + .set_fmt = es8316_set_dai_fmt, + .set_sysclk = es8316_set_dai_sysclk, + .digital_mute = es8316_mute, +}; + +static struct snd_soc_dai_driver es8316_dai = { + .name = "ES8316 HiFi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = ES8316_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = ES8316_FORMATS, + }, + .ops = &es8316_ops, + .symmetric_rates = 1, +}; + +static int es8316_probe(struct snd_soc_codec *codec) +{ + /* Reset codec and enable current state machine */ + snd_soc_write(codec, ES8316_RESET, 0x3f); + usleep_range(5000, 5500); + snd_soc_write(codec, ES8316_RESET, ES8316_RESET_CSM_ON); + msleep(30); + + /* + * Documentation is unclear, but this value from the vendor driver is + * needed otherwise audio output is silent. + */ + snd_soc_write(codec, ES8316_SYS_VMIDSEL, 0xff); + + /* + * Documentation for this register is unclear and incomplete, + * but here is a vendor-provided value that improves volume + * and quality for Intel CHT platforms. + */ + snd_soc_write(codec, ES8316_CLKMGR_ADCOSR, 0x32); + + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_es8316 = { + .probe = es8316_probe, + .idle_bias_off = true, + + .component_driver = { + .controls = es8316_snd_controls, + .num_controls = ARRAY_SIZE(es8316_snd_controls), + .dapm_widgets = es8316_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(es8316_dapm_widgets), + .dapm_routes = es8316_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(es8316_dapm_routes), + }, +}; + +static const struct regmap_config es8316_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x53, + .cache_type = REGCACHE_RBTREE, +}; + +static int es8316_i2c_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id) +{ + struct es8316_priv *es8316; + struct regmap *regmap; + + es8316 = devm_kzalloc(&i2c_client->dev, sizeof(struct es8316_priv), + GFP_KERNEL); + if (es8316 == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c_client, es8316); + + regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return snd_soc_register_codec(&i2c_client->dev, &soc_codec_dev_es8316, + &es8316_dai, 1); +} + +static int es8316_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id es8316_i2c_id[] = { + {"es8316", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, es8316_i2c_id); + +static const struct of_device_id es8316_of_match[] = { + { .compatible = "everest,es8316", }, + {}, +}; +MODULE_DEVICE_TABLE(of, es8316_of_match); + +static const struct acpi_device_id es8316_acpi_match[] = { + {"ESSX8316", 0}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, es8316_acpi_match); + +static struct i2c_driver es8316_i2c_driver = { + .driver = { + .name = "es8316", + .acpi_match_table = ACPI_PTR(es8316_acpi_match), + .of_match_table = of_match_ptr(es8316_of_match), + }, + .probe = es8316_i2c_probe, + .remove = es8316_i2c_remove, + .id_table = es8316_i2c_id, +}; +module_i2c_driver(es8316_i2c_driver); + +MODULE_DESCRIPTION("Everest Semi ES8316 ALSA SoC Codec Driver"); +MODULE_AUTHOR("David Yang "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/es8316.h b/sound/soc/codecs/es8316.h new file mode 100644 index 000000000000..6bcdd63ea459 --- /dev/null +++ b/sound/soc/codecs/es8316.h @@ -0,0 +1,129 @@ +/* + * Copyright Everest Semiconductor Co.,Ltd + * + * Author: David Yang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef _ES8316_H +#define _ES8316_H + +/* + * ES8316 register space + */ + +/* Reset Control */ +#define ES8316_RESET 0x00 + +/* Clock Management */ +#define ES8316_CLKMGR_CLKSW 0x01 +#define ES8316_CLKMGR_CLKSEL 0x02 +#define ES8316_CLKMGR_ADCOSR 0x03 +#define ES8316_CLKMGR_ADCDIV1 0x04 +#define ES8316_CLKMGR_ADCDIV2 0x05 +#define ES8316_CLKMGR_DACDIV1 0x06 +#define ES8316_CLKMGR_DACDIV2 0x07 +#define ES8316_CLKMGR_CPDIV 0x08 + +/* Serial Data Port Control */ +#define ES8316_SERDATA1 0x09 +#define ES8316_SERDATA_ADC 0x0a +#define ES8316_SERDATA_DAC 0x0b + +/* System Control */ +#define ES8316_SYS_VMIDSEL 0x0c +#define ES8316_SYS_PDN 0x0d +#define ES8316_SYS_LP1 0x0e +#define ES8316_SYS_LP2 0x0f +#define ES8316_SYS_VMIDLOW 0x10 +#define ES8316_SYS_VSEL 0x11 +#define ES8316_SYS_REF 0x12 + +/* Headphone Mixer */ +#define ES8316_HPMIX_SEL 0x13 +#define ES8316_HPMIX_SWITCH 0x14 +#define ES8316_HPMIX_PDN 0x15 +#define ES8316_HPMIX_VOL 0x16 + +/* Charge Pump Headphone driver */ +#define ES8316_CPHP_OUTEN 0x17 +#define ES8316_CPHP_ICAL_VOL 0x18 +#define ES8316_CPHP_PDN1 0x19 +#define ES8316_CPHP_PDN2 0x1a +#define ES8316_CPHP_LDOCTL 0x1b + +/* Calibration */ +#define ES8316_CAL_TYPE 0x1c +#define ES8316_CAL_SET 0x1d +#define ES8316_CAL_HPLIV 0x1e +#define ES8316_CAL_HPRIV 0x1f +#define ES8316_CAL_HPLMV 0x20 +#define ES8316_CAL_HPRMV 0x21 + +/* ADC Control */ +#define ES8316_ADC_PDN_LINSEL 0x22 +#define ES8316_ADC_PGAGAIN 0x23 +#define ES8316_ADC_D2SEPGA 0x24 +#define ES8316_ADC_DMIC 0x25 +#define ES8316_ADC_MUTE 0x26 +#define ES8316_ADC_VOLUME 0x27 +#define ES8316_ADC_ALC1 0x29 +#define ES8316_ADC_ALC2 0x2a +#define ES8316_ADC_ALC3 0x2b +#define ES8316_ADC_ALC4 0x2c +#define ES8316_ADC_ALC5 0x2d +#define ES8316_ADC_ALC_NG 0x2e + +/* DAC Control */ +#define ES8316_DAC_PDN 0x2f +#define ES8316_DAC_SET1 0x30 +#define ES8316_DAC_SET2 0x31 +#define ES8316_DAC_SET3 0x32 +#define ES8316_DAC_VOLL 0x33 +#define ES8316_DAC_VOLR 0x34 + +/* GPIO */ +#define ES8316_GPIO_SEL 0x4d +#define ES8316_GPIO_DEBOUNCE 0x4e +#define ES8316_GPIO_FLAG 0x4f + +/* Test mode */ +#define ES8316_TESTMODE 0x50 +#define ES8316_TEST1 0x51 +#define ES8316_TEST2 0x52 +#define ES8316_TEST3 0x53 + +/* + * Field definitions + */ + +/* ES8316_RESET */ +#define ES8316_RESET_CSM_ON 0x80 + +/* ES8316_CLKMGR_CLKSW */ +#define ES8316_CLKMGR_CLKSW_MCLK_ON 0x40 +#define ES8316_CLKMGR_CLKSW_BCLK_ON 0x20 + +/* ES8316_SERDATA1 */ +#define ES8316_SERDATA1_MASTER 0x80 +#define ES8316_SERDATA1_BCLK_INV 0x20 + +/* ES8316_SERDATA_ADC and _DAC */ +#define ES8316_SERDATA2_FMT_MASK 0x3 +#define ES8316_SERDATA2_FMT_I2S 0x00 +#define ES8316_SERDATA2_FMT_LEFTJ 0x01 +#define ES8316_SERDATA2_FMT_RIGHTJ 0x02 +#define ES8316_SERDATA2_FMT_PCM 0x03 +#define ES8316_SERDATA2_ADCLRP 0x20 +#define ES8316_SERDATA2_LEN_MASK 0x1c +#define ES8316_SERDATA2_LEN_24 0x00 +#define ES8316_SERDATA2_LEN_20 0x04 +#define ES8316_SERDATA2_LEN_18 0x08 +#define ES8316_SERDATA2_LEN_16 0x0c +#define ES8316_SERDATA2_LEN_32 0x10 + +#endif From a03bdaa565cbf23fa86697727a7d2bf1465e7a03 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Mon, 12 Jun 2017 11:01:46 -0600 Subject: [PATCH 257/418] ASoC: Intel: add machine driver for BYT/CHT + ES8316 Add new machine driver, tested with Weibu F3C MiniPC. Based heavily on code provided by David Yang @ Everest, and other machine drivers in the same directory. Signed-off-by: David Yang [drake@endlessm.com: cleanups and modernization] Signed-off-by: Daniel Drake Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 12 + sound/soc/intel/atom/sst/sst_acpi.c | 7 + sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/bytcht_es8316.c | 300 +++++++++++++++++++++++++ 4 files changed, 321 insertions(+) create mode 100644 sound/soc/intel/boards/bytcht_es8316.c diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index a9c50d022e73..35a6a5c55914 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -214,6 +214,18 @@ config SND_SOC_INTEL_BYT_CHT_DA7213_MACH platforms with DA7212/7213 audio codec. If unsure select "N". +config SND_SOC_INTEL_BYT_CHT_ES8316_MACH + tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with ES8316 codec" + depends on X86_INTEL_LPSS && I2C && ACPI + select SND_SOC_ES8316 + select SND_SST_ATOM_HIFI2_PLATFORM + select SND_SST_IPC_ACPI + select SND_SOC_INTEL_SST_MATCH if ACPI + help + This adds support for ASoC machine driver for Intel(R) Baytrail & + Cherrytrail platforms with ES8316 audio codec. + If unsure select "N". + config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)" depends on X86_INTEL_LPSS && I2C && ACPI diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index cf88cd1865fb..0e928d54305d 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -611,6 +611,13 @@ static struct sst_acpi_mach sst_acpi_chv[] = { .board = "bytcht_da7213", .pdata = &chv_platform_data }, + { + .id = "ESSX8316", + .drv_name = "bytcht_es8316", + .fw_filename = "intel/fw_sst_22a8.bin", + .board = "bytcht_es8316", + .pdata = &chv_platform_data + }, /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ { .id = "10EC5640", diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index c92ebcac0222..c4e986f03ec9 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -11,6 +11,7 @@ snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o +snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o snd-soc-skl_rt286-objs := skl_rt286.o @@ -30,6 +31,7 @@ obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o +obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c new file mode 100644 index 000000000000..52635462dac6 --- /dev/null +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -0,0 +1,300 @@ +/* + * bytcht_es8316.c - ASoc Machine driver for Intel Baytrail/Cherrytrail + * platforms with Everest ES8316 SoC + * + * Copyright (C) 2017 Endless Mobile, Inc. + * Authors: David Yang , + * Daniel Drake + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../atom/sst-atom-controls.h" +#include "../common/sst-acpi.h" +#include "../common/sst-dsp.h" + +struct byt_cht_es8316_private { + struct clk *mclk; +}; + +#define CODEC_DAI1 "ES8316 HiFi" + +static inline struct snd_soc_dai *get_codec_dai(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + + list_for_each_entry(rtd, &card->rtd_list, list) { + if (!strncmp(rtd->codec_dai->name, CODEC_DAI1, + strlen(CODEC_DAI1))) + return rtd->codec_dai; + } + return NULL; +} + +static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + + /* + * The codec supports two analog microphone inputs. I have only + * tested MIC1. A DMIC route could also potentially be added + * if such functionality is found on another platform. + */ + SND_SOC_DAPM_MIC("Microphone 1", NULL), + SND_SOC_DAPM_MIC("Microphone 2", NULL), +}; + +static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { + {"MIC1", NULL, "Microphone 1"}, + {"MIC2", NULL, "Microphone 2"}, + + {"Headphone", NULL, "HPOL"}, + {"Headphone", NULL, "HPOR"}, + + {"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, "Capture"}, +}; + +static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Microphone 1"), + SOC_DAPM_PIN_SWITCH("Microphone 2"), +}; + +static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_card *card = runtime->card; + struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); + int ret; + + card->dapm.idle_bias_off = true; + + /* + * 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(priv->mclk); + if (!ret) + clk_disable_unprepare(priv->mclk); + + ret = clk_set_rate(priv->mclk, 19200000); + if (ret) + dev_err(card->dev, "unable to set MCLK rate\n"); + + ret = clk_prepare_enable(priv->mclk); + if (ret) + dev_err(card->dev, "unable to enable MCLK\n"); + + ret = snd_soc_dai_set_sysclk(runtime->codec_dai, 0, 19200000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec clock %d\n", ret); + return ret; + } + + return 0; +} + +static const struct snd_soc_pcm_stream byt_cht_es8316_dai_params = { + .formats = SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, +}; + +static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + 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; + + /* The DSP will covert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP2 to 24-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + + /* + * Default mode for SSP configuration is TDM 4 slot, override config + * with explicit setting to I2S 2ch 24-bit. The word length is set with + * dai_set_tdm_slot() since there is no other API exposed + */ + ret = snd_soc_dai_set_fmt(rtd->cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS + ); + if (ret < 0) { + dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); + if (ret < 0) { + dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); + return ret; + } + + return 0; +} + +static int byt_cht_es8316_aif1_startup(struct snd_pcm_substream *substream) +{ + return snd_pcm_hw_constraint_single(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, 48000); +} + +static const struct snd_soc_ops byt_cht_es8316_aif1_ops = { + .startup = byt_cht_es8316_aif1_startup, +}; + +static struct snd_soc_dai_link byt_cht_es8316_dais[] = { + [MERR_DPCM_AUDIO] = { + .name = "Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "media-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ops = &byt_cht_es8316_aif1_ops, + }, + + [MERR_DPCM_DEEP_BUFFER] = { + .name = "Deep-Buffer Audio Port", + .stream_name = "Deep-Buffer Audio", + .cpu_dai_name = "deepbuffer-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .ops = &byt_cht_es8316_aif1_ops, + }, + + [MERR_DPCM_COMPR] = { + .name = "Compressed Port", + .stream_name = "Compress", + .cpu_dai_name = "compress-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + }, + + /* back ends */ + { + /* Only SSP2 has been tested here, so BYT-CR platforms that + * require SSP0 will not work. + */ + .name = "SSP2-Codec", + .id = 1, + .cpu_dai_name = "ssp2-port", + .platform_name = "sst-mfld-platform", + .no_pcm = 1, + .codec_dai_name = "ES8316 HiFi", + .codec_name = "i2c-ESSX8316:00", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .be_hw_params_fixup = byt_cht_es8316_codec_fixup, + .nonatomic = true, + .dpcm_playback = 1, + .dpcm_capture = 1, + .init = byt_cht_es8316_init, + }, +}; + + +/* SoC card */ +static struct snd_soc_card byt_cht_es8316_card = { + .name = "bytcht-es8316", + .owner = THIS_MODULE, + .dai_link = byt_cht_es8316_dais, + .num_links = ARRAY_SIZE(byt_cht_es8316_dais), + .dapm_widgets = byt_cht_es8316_widgets, + .num_dapm_widgets = ARRAY_SIZE(byt_cht_es8316_widgets), + .dapm_routes = byt_cht_es8316_audio_map, + .num_dapm_routes = ARRAY_SIZE(byt_cht_es8316_audio_map), + .controls = byt_cht_es8316_controls, + .num_controls = ARRAY_SIZE(byt_cht_es8316_controls), + .fully_routed = true, +}; + +static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) +{ + int ret = 0; + struct byt_cht_es8316_private *priv; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); + if (!priv) + return -ENOMEM; + + /* register the soc card */ + byt_cht_es8316_card.dev = &pdev->dev; + snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); + + priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + if (IS_ERR(priv->mclk)) { + ret = PTR_ERR(priv->mclk); + dev_err(&pdev->dev, + "Failed to get MCLK from pmc_plt_clk_3: %d\n", + ret); + return ret; + } + + ret = devm_snd_soc_register_card(&pdev->dev, &byt_cht_es8316_card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret); + return ret; + } + platform_set_drvdata(pdev, &byt_cht_es8316_card); + return ret; +} + +static struct platform_driver snd_byt_cht_es8316_mc_driver = { + .driver = { + .name = "bytcht_es8316", + }, + .probe = snd_byt_cht_es8316_mc_probe, +}; + +module_platform_driver(snd_byt_cht_es8316_mc_driver); +MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail Machine driver"); +MODULE_AUTHOR("David Yang "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:bytcht_es8316"); From 17616ce62c84c94e9519574e9d2df6f20e80a285 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Mon, 12 Jun 2017 11:02:17 +0800 Subject: [PATCH 258/418] ASoC: rt5663: Check the JD status in the resume function In the suspend, the IRQ function will not work in some machines. So the JD status should be checked in the resume function. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 8569e8c7d894..a33202affeb1 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -2847,6 +2847,8 @@ static int rt5663_resume(struct snd_soc_codec *codec) regcache_cache_only(rt5663->regmap, false); regcache_sync(rt5663->regmap); + rt5663_irq(0, rt5663); + return 0; } #else From 8cd8a186eb30c87e0b855cf4823034472413914e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 May 2017 01:48:24 +0000 Subject: [PATCH 259/418] ASoC: rsnd: don't call free_irq() on Parent SSI If SSI uses shared pin, some SSI will be used as parent SSI. Then, normal SSI's remove and Parent SSI's remove (these are same SSI) will be called when unbind or remove timing. In this case, free_irq() will be called twice. This patch solve this issue. Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Reported-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 135c5669f796..03867353d10c 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -709,6 +709,11 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); + + /* Do nothing for SSI parent mod */ + if (ssi_parent_mod == mod) + return 0; /* PIO will request IRQ again */ free_irq(ssi->irq, mod); From 1ebb4d9dbf8f7a429abff359fa1d779b639da76f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jun 2017 23:37:22 +0200 Subject: [PATCH 260/418] ASoC: intel: byt: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_nocodec.c | 4 ++-- sound/soc/intel/boards/bytcr_rt5651.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_nocodec.c b/sound/soc/intel/boards/bytcht_nocodec.c index 89853eeaaf9d..1dd9441806fa 100644 --- a/sound/soc/intel/boards/bytcht_nocodec.c +++ b/sound/soc/intel/boards/bytcht_nocodec.c @@ -85,11 +85,11 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static unsigned int rates_48000[] = { +static const unsigned int rates_48000[] = { 48000, }; -static struct snd_pcm_hw_constraint_list constraints_48000 = { +static const struct snd_pcm_hw_constraint_list constraints_48000 = { .count = ARRAY_SIZE(rates_48000), .list = rates_48000, }; diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 8164bec63bf1..4a3516b38c2c 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -203,11 +203,11 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static unsigned int rates_48000[] = { +static const unsigned int rates_48000[] = { 48000, }; -static struct snd_pcm_hw_constraint_list constraints_48000 = { +static const struct snd_pcm_hw_constraint_list constraints_48000 = { .count = ARRAY_SIZE(rates_48000), .list = rates_48000, }; From 617647ae2880cf291293048f8cfd54f8111acb1c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jun 2017 23:37:23 +0200 Subject: [PATCH 261/418] ASoC: intel: skl: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 16 ++++++++-------- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 16 ++++++++-------- sound/soc/intel/boards/skl_rt286.c | 12 ++++++------ 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 3b12bc1fa518..5ed0aa27b467 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -266,21 +266,21 @@ static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static unsigned int rates[] = { +static const unsigned int rates[] = { 48000, }; -static struct snd_pcm_hw_constraint_list constraints_rates = { +static const struct snd_pcm_hw_constraint_list constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, }; -static unsigned int channels[] = { +static const unsigned int channels[] = { 2, }; -static struct snd_pcm_hw_constraint_list constraints_channels = { +static const struct snd_pcm_hw_constraint_list constraints_channels = { .count = ARRAY_SIZE(channels), .list = channels, .mask = 0, @@ -348,11 +348,11 @@ static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static unsigned int channels_dmic[] = { +static const unsigned int channels_dmic[] = { 2, 4, }; -static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { +static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { .count = ARRAY_SIZE(channels_dmic), .list = channels_dmic, .mask = 0, @@ -384,11 +384,11 @@ static const struct snd_soc_ops skylake_dmic_ops = { .startup = skylake_dmic_startup, }; -static unsigned int rates_16000[] = { +static const unsigned int rates_16000[] = { 16000, }; -static struct snd_pcm_hw_constraint_list constraints_16000 = { +static const struct snd_pcm_hw_constraint_list constraints_16000 = { .count = ARRAY_SIZE(rates_16000), .list = rates_16000, }; diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index eb7751b0599b..01b8b140bb08 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -297,21 +297,21 @@ static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static unsigned int rates[] = { +static const unsigned int rates[] = { 48000, }; -static struct snd_pcm_hw_constraint_list constraints_rates = { +static const struct snd_pcm_hw_constraint_list constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, }; -static unsigned int channels[] = { +static const unsigned int channels[] = { 2, }; -static struct snd_pcm_hw_constraint_list constraints_channels = { +static const struct snd_pcm_hw_constraint_list constraints_channels = { .count = ARRAY_SIZE(channels), .list = channels, .mask = 0, @@ -397,11 +397,11 @@ static const struct snd_soc_ops skylake_nau8825_ops = { .hw_params = skylake_nau8825_hw_params, }; -static unsigned int channels_dmic[] = { +static const unsigned int channels_dmic[] = { 2, 4, }; -static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { +static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { .count = ARRAY_SIZE(channels_dmic), .list = channels_dmic, .mask = 0, @@ -433,11 +433,11 @@ static const struct snd_soc_ops skylake_dmic_ops = { .startup = skylake_dmic_startup, }; -static unsigned int rates_16000[] = { +static const unsigned int rates_16000[] = { 16000, }; -static struct snd_pcm_hw_constraint_list constraints_16000 = { +static const struct snd_pcm_hw_constraint_list constraints_16000 = { .count = ARRAY_SIZE(rates_16000), .list = rates_16000, }; diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index f5ab7b8d51d1..e08c71625fd0 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -165,21 +165,21 @@ static int skylake_hdmi_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static unsigned int rates[] = { +static const unsigned int rates[] = { 48000, }; -static struct snd_pcm_hw_constraint_list constraints_rates = { +static const struct snd_pcm_hw_constraint_list constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, }; -static unsigned int channels[] = { +static const unsigned int channels[] = { 2, }; -static struct snd_pcm_hw_constraint_list constraints_channels = { +static const struct snd_pcm_hw_constraint_list constraints_channels = { .count = ARRAY_SIZE(channels), .list = channels, .mask = 0, @@ -264,11 +264,11 @@ static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static unsigned int channels_dmic[] = { +static const unsigned int channels_dmic[] = { 2, 4, }; -static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { +static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { .count = ARRAY_SIZE(channels_dmic), .list = channels_dmic, .mask = 0, From e8fa1a4929849b71936f30e88c0b17c3a641509d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jun 2017 23:37:19 +0200 Subject: [PATCH 262/418] ASoC: cs35l34: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l34.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c index 7c5d1510cf2c..0a747c66cc6c 100644 --- a/sound/soc/codecs/cs35l34.c +++ b/sound/soc/codecs/cs35l34.c @@ -567,12 +567,12 @@ static int cs35l34_pcm_hw_params(struct snd_pcm_substream *substream, return ret; } -static unsigned int cs35l34_src_rates[] = { +static const unsigned int cs35l34_src_rates[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }; -static struct snd_pcm_hw_constraint_list cs35l34_constraints = { +static const struct snd_pcm_hw_constraint_list cs35l34_constraints = { .count = ARRAY_SIZE(cs35l34_src_rates), .list = cs35l34_src_rates, }; From 92f468d2c587e3cea32032df064d06c96637f295 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jun 2017 23:37:20 +0200 Subject: [PATCH 263/418] ASoC: cs53l30: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/cs53l30.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c index 1e0d5973b758..06933a5d0a75 100644 --- a/sound/soc/codecs/cs53l30.c +++ b/sound/soc/codecs/cs53l30.c @@ -747,7 +747,7 @@ static unsigned int const cs53l30_src_rates[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }; -static struct snd_pcm_hw_constraint_list src_constraints = { +static const struct snd_pcm_hw_constraint_list src_constraints = { .count = ARRAY_SIZE(cs53l30_src_rates), .list = cs53l30_src_rates, }; From b02ee56087adae4819ce4d91c08d57403f71fd34 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jun 2017 23:37:24 +0200 Subject: [PATCH 264/418] ASoC: mediatek: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai Acked-By: Matthias Brugger Signed-off-by: Mark Brown --- sound/soc/mediatek/mt2701/mt2701-cs42448.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c index aa5b31b121e3..70f61d53fe05 100644 --- a/sound/soc/mediatek/mt2701/mt2701-cs42448.c +++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c @@ -107,7 +107,7 @@ static const struct snd_kcontrol_new mt2701_cs42448_controls[] = { static const unsigned int mt2701_cs42448_sampling_rates[] = {48000}; -static struct snd_pcm_hw_constraint_list mt2701_cs42448_constraints_rates = { +static const struct snd_pcm_hw_constraint_list mt2701_cs42448_constraints_rates = { .count = ARRAY_SIZE(mt2701_cs42448_sampling_rates), .list = mt2701_cs42448_sampling_rates, .mask = 0, From 0994c030443b50089b8ac74bc863d71238739f2e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jun 2017 23:37:25 +0200 Subject: [PATCH 265/418] ASoC: samsung: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/s3c24xx_uda134x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c index 81a78940967c..55538e333cc8 100644 --- a/sound/soc/samsung/s3c24xx_uda134x.c +++ b/sound/soc/samsung/s3c24xx_uda134x.c @@ -44,7 +44,7 @@ struct s3c24xx_uda134x { static unsigned int rates[33 * 2]; #ifdef ENFORCE_RATES -static struct snd_pcm_hw_constraint_list hw_constraints_rates = { +static const struct snd_pcm_hw_constraint_list hw_constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, From 8cce431aa26ef24a4d4b820301ac73bf55df7a5e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 9 Jun 2017 00:34:09 +0000 Subject: [PATCH 266/418] ASoC: rsnd: add detail explanation of L/R conversion timing Renesas Sound device *Hardware* L/R and Linux *Software* L/R are inverted. Because of this background, it needs to convert L/R. Then, DVC needs *Hardware* L/R, and Linux needs *Software* L/R. Because Playback/Capture needs different timing, and there is no explanation about it on source code / git log, this patch adds it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 7c68f9d4a0ed..1bf261d677b7 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -310,6 +310,24 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) u32 val = 0x76543210; u32 mask = ~0; + /* + * *Hardware* L/R and *Software* L/R are inverted. + * We need to care about inversion timing to control + * Playback/Capture correctly. + * The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R + * + * sL/R : software L/R + * hL/R : hardware L/R + * (*) : conversion timing + * + * Playback + * sL/R (*) hL/R hL/R hL/R hL/R hL/R + * [MEM] -> [SRC] -> [DVC] -> [CMD] -> [SSIU] -> [SSI] -> codec + * + * Capture + * hL/R hL/R hL/R hL/R hL/R (*) sL/R + * codec -> [SSI] -> [SSIU] -> [SRC] -> [DVC] -> [CMD] -> [MEM] + */ if (rsnd_io_is_play(io)) { struct rsnd_mod *src = rsnd_io_to_mod_src(io); From f0b04d8b442757f7bcad2cd07b54f63910253ebc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Jun 2017 00:11:48 +0000 Subject: [PATCH 267/418] ASoC: rsnd: control kctrl items acceptance anytime/runtime Current SRC/DVC/CTU adds kctrl for each device, and SRC can adjust its sampling rate during playback, thus, this feature should be enabled only *during* playback. This patch controls it more clearly Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 17 +++++++++++++++++ sound/soc/sh/rcar/ctu.c | 6 ++++++ sound/soc/sh/rcar/dvc.c | 5 +++++ sound/soc/sh/rcar/rsnd.h | 16 ++++++++++------ sound/soc/sh/rcar/src.c | 2 ++ 5 files changed, 40 insertions(+), 6 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 1bf261d677b7..0bb99aa70e29 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1065,6 +1065,9 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl, struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl); int i, change = 0; + if (!cfg->accept(cfg->io)) + return 0; + for (i = 0; i < cfg->size; i++) { if (cfg->texts) { change |= (uc->value.enumerated.item[i] != cfg->val[i]); @@ -1081,6 +1084,18 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl, return change; } +int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io) +{ + return 1; +} + +int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io) +{ + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + + return !!runtime; +} + struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg) { cfg->cfg.val = cfg->val; @@ -1099,6 +1114,7 @@ int rsnd_kctrl_new(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct snd_soc_pcm_runtime *rtd, const unsigned char *name, + int (*accept)(struct rsnd_dai_stream *io), void (*update)(struct rsnd_dai_stream *io, struct rsnd_mod *mod), struct rsnd_kctrl_cfg *cfg, @@ -1133,6 +1149,7 @@ int rsnd_kctrl_new(struct rsnd_mod *mod, cfg->texts = texts; cfg->max = max; cfg->size = size; + cfg->accept = accept; cfg->update = update; cfg->card = card; cfg->kctrl = kctrl; diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 9dcc1f9db026..4ba8f2fe7a4c 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -279,12 +279,14 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, /* CTU Pass */ ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass", + rsnd_kctrl_accept_anytime, NULL, &ctu->pass, RSND_MAX_CHANNELS, 0xC); /* ROW0 */ ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0", + rsnd_kctrl_accept_anytime, NULL, &ctu->sv0, RSND_MAX_CHANNELS, 0x00FFFFFF); @@ -293,6 +295,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, /* ROW1 */ ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1", + rsnd_kctrl_accept_anytime, NULL, &ctu->sv1, RSND_MAX_CHANNELS, 0x00FFFFFF); @@ -301,6 +304,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, /* ROW2 */ ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2", + rsnd_kctrl_accept_anytime, NULL, &ctu->sv2, RSND_MAX_CHANNELS, 0x00FFFFFF); @@ -309,6 +313,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, /* ROW3 */ ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3", + rsnd_kctrl_accept_anytime, NULL, &ctu->sv3, RSND_MAX_CHANNELS, 0x00FFFFFF); @@ -317,6 +322,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, /* Reset */ ret = rsnd_kctrl_new_s(mod, io, rtd, "CTU Reset", + rsnd_kctrl_accept_anytime, rsnd_ctu_value_reset, &ctu->reset, 1); diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 463de8360985..75af6e742328 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -257,6 +257,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, ret = rsnd_kctrl_new_m(mod, io, rtd, is_play ? "DVC Out Playback Volume" : "DVC In Capture Volume", + rsnd_kctrl_accept_anytime, rsnd_dvc_volume_update, &dvc->volume, slots, 0x00800000 - 1); @@ -267,6 +268,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, ret = rsnd_kctrl_new_m(mod, io, rtd, is_play ? "DVC Out Mute Switch" : "DVC In Mute Switch", + rsnd_kctrl_accept_anytime, rsnd_dvc_volume_update, &dvc->mute, slots, 1); @@ -277,6 +279,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, ret = rsnd_kctrl_new_s(mod, io, rtd, is_play ? "DVC Out Ramp Switch" : "DVC In Ramp Switch", + rsnd_kctrl_accept_anytime, rsnd_dvc_volume_update, &dvc->ren, 1); if (ret < 0) @@ -285,6 +288,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, ret = rsnd_kctrl_new_e(mod, io, rtd, is_play ? "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate", + rsnd_kctrl_accept_anytime, rsnd_dvc_volume_update, &dvc->rup, dvc_ramp_rate); @@ -294,6 +298,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, ret = rsnd_kctrl_new_e(mod, io, rtd, is_play ? "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate", + rsnd_kctrl_accept_anytime, rsnd_dvc_volume_update, &dvc->rdown, dvc_ramp_rate); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 6de5f7ec6464..ac4d50d118d1 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -598,6 +598,7 @@ struct rsnd_kctrl_cfg { unsigned int size; u32 *val; const char * const *texts; + int (*accept)(struct rsnd_dai_stream *io); void (*update)(struct rsnd_dai_stream *io, struct rsnd_mod *mod); struct rsnd_dai_stream *io; struct snd_card *card; @@ -615,12 +616,15 @@ struct rsnd_kctrl_cfg_s { u32 val; }; +int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io); +int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io); struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg); struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg); int rsnd_kctrl_new(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct snd_soc_pcm_runtime *rtd, const unsigned char *name, + int (*accept)(struct rsnd_dai_stream *io), void (*update)(struct rsnd_dai_stream *io, struct rsnd_mod *mod), struct rsnd_kctrl_cfg *cfg, @@ -628,16 +632,16 @@ int rsnd_kctrl_new(struct rsnd_mod *mod, int size, u32 max); -#define rsnd_kctrl_new_m(mod, io, rtd, name, update, cfg, size, max) \ - rsnd_kctrl_new(mod, io, rtd, name, update, rsnd_kctrl_init_m(cfg), \ +#define rsnd_kctrl_new_m(mod, io, rtd, name, accept, update, cfg, size, max) \ + rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_m(cfg), \ NULL, size, max) -#define rsnd_kctrl_new_s(mod, io, rtd, name, update, cfg, max) \ - rsnd_kctrl_new(mod, io, rtd, name, update, rsnd_kctrl_init_s(cfg), \ +#define rsnd_kctrl_new_s(mod, io, rtd, name, accept, update, cfg, max) \ + rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \ NULL, 1, max) -#define rsnd_kctrl_new_e(mod, io, rtd, name, update, cfg, texts) \ - rsnd_kctrl_new(mod, io, rtd, name, update, rsnd_kctrl_init_s(cfg), \ +#define rsnd_kctrl_new_e(mod, io, rtd, name, accept, update, cfg, texts) \ + rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \ texts, 1, ARRAY_SIZE(texts)) /* diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 8dbe9ebcbff1..7aa239e28491 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -497,6 +497,7 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod, rsnd_io_is_play(io) ? "SRC Out Rate Switch" : "SRC In Rate Switch", + rsnd_kctrl_accept_anytime, rsnd_src_set_convert_rate, &src->sen, 1); if (ret < 0) @@ -506,6 +507,7 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod, rsnd_io_is_play(io) ? "SRC Out Rate" : "SRC In Rate", + rsnd_kctrl_accept_runtime, rsnd_src_set_convert_rate, &src->sync, 192000); From 7c197881e163f34679b941c75500a6c85560b7c9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sat, 10 Jun 2017 19:37:41 +0300 Subject: [PATCH 268/418] ASoC: Intel: byt-max98090: Add GPIO ACPI mapping table In order to make GPIO ACPI library stricter prepare users of gpiod_get_index() to correctly behave when there no mapping is provided by firmware. Here we add explicit mapping between _CRS GpioIo() resources and their names used in the driver. Reviewed-by: Dmitry Torokhov Tested-by: Nicolas Porcel Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- sound/soc/intel/boards/byt-max98090.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/boards/byt-max98090.c b/sound/soc/intel/boards/byt-max98090.c index d9f81b8d915d..047be7fa0ce9 100644 --- a/sound/soc/intel/boards/byt-max98090.c +++ b/sound/soc/intel/boards/byt-max98090.c @@ -67,20 +67,27 @@ static struct snd_soc_jack_pin hs_jack_pins[] = { static struct snd_soc_jack_gpio hs_jack_gpios[] = { { - .name = "hp-gpio", - .idx = 0, + .name = "hp", .report = SND_JACK_HEADPHONE | SND_JACK_LINEOUT, .debounce_time = 200, }, { - .name = "mic-gpio", - .idx = 1, + .name = "mic", .invert = 1, .report = SND_JACK_MICROPHONE, .debounce_time = 200, }, }; +static const struct acpi_gpio_params hp_gpios = { 0, 0, false }; +static const struct acpi_gpio_params mic_gpios = { 1, 0, false }; + +static const struct acpi_gpio_mapping acpi_byt_max98090_gpios[] = { + { "hp-gpios", &hp_gpios, 1 }, + { "mic-gpios", &mic_gpios, 1 }, + {}, +}; + static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime) { int ret; @@ -140,8 +147,9 @@ static struct snd_soc_card byt_max98090_card = { static int byt_max98090_probe(struct platform_device *pdev) { - int ret_val = 0; + struct device *dev = &pdev->dev; struct byt_max98090_private *priv; + int ret_val; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); if (!priv) { @@ -149,6 +157,10 @@ static int byt_max98090_probe(struct platform_device *pdev) return -ENOMEM; } + ret_val = devm_acpi_dev_add_driver_gpios(dev->parent, acpi_byt_max98090_gpios); + if (ret_val) + dev_dbg(dev, "Unable to add GPIO mapping table\n"); + byt_max98090_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&byt_max98090_card, priv); ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_max98090_card); @@ -158,7 +170,7 @@ static int byt_max98090_probe(struct platform_device *pdev) return ret_val; } - return ret_val; + return 0; } static int byt_max98090_remove(struct platform_device *pdev) From 55f42d2e28a42b06907c916c3c71ceb6dfb5afc4 Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Fri, 9 Jun 2017 15:59:32 +0800 Subject: [PATCH 269/418] ASoC: rockchip: add bindings for spdif controller this patch add compatible for rk3228/rk3328 spdif, Signed-off-by: Sugar Zhang Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rockchip-spdif.txt | 2 ++ sound/soc/rockchip/rockchip_spdif.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/rockchip-spdif.txt b/Documentation/devicetree/bindings/sound/rockchip-spdif.txt index 11046429a118..4706b96d450b 100644 --- a/Documentation/devicetree/bindings/sound/rockchip-spdif.txt +++ b/Documentation/devicetree/bindings/sound/rockchip-spdif.txt @@ -9,7 +9,9 @@ Required properties: - compatible: should be one of the following: - "rockchip,rk3066-spdif" - "rockchip,rk3188-spdif" + - "rockchip,rk3228-spdif" - "rockchip,rk3288-spdif" + - "rockchip,rk3328-spdif" - "rockchip,rk3366-spdif" - "rockchip,rk3368-spdif" - "rockchip,rk3399-spdif" diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c index fa8101d1e16f..ee5055d47d13 100644 --- a/sound/soc/rockchip/rockchip_spdif.c +++ b/sound/soc/rockchip/rockchip_spdif.c @@ -49,8 +49,12 @@ static const struct of_device_id rk_spdif_match[] = { .data = (void *)RK_SPDIF_RK3066 }, { .compatible = "rockchip,rk3188-spdif", .data = (void *)RK_SPDIF_RK3188 }, + { .compatible = "rockchip,rk3228-spdif", + .data = (void *)RK_SPDIF_RK3366 }, { .compatible = "rockchip,rk3288-spdif", .data = (void *)RK_SPDIF_RK3288 }, + { .compatible = "rockchip,rk3328-spdif", + .data = (void *)RK_SPDIF_RK3366 }, { .compatible = "rockchip,rk3366-spdif", .data = (void *)RK_SPDIF_RK3366 }, { .compatible = "rockchip,rk3368-spdif", From ec2212c4af20d84841ae288a397d8ee9ecec72a0 Mon Sep 17 00:00:00 2001 From: zhangjun Date: Fri, 9 Jun 2017 16:52:48 +0800 Subject: [PATCH 270/418] ASoC: rockchip: i2s: add other configurable formats simple-audio-card,bitclock-inversion = <1> : bclk falling edge taken simple-audio-card,format = "dsp_a" : pcm no delay mode simple-audio-card,format = "dsp_b" : pcm late 1 mode Signed-off-by: zhangjun Signed-off-by: Sugar Zhang Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 30 ++++++++++++++++++++++++++++-- sound/soc/rockchip/rockchip_i2s.h | 3 +++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 974915cb4c4f..66a26c56c658 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -204,7 +204,21 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai, regmap_update_bits(i2s->regmap, I2S_CKR, mask, val); - mask = I2S_TXCR_IBM_MASK; + mask = I2S_CKR_CKP_MASK; + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + val = I2S_CKR_CKP_NEG; + break; + case SND_SOC_DAIFMT_IB_NF: + val = I2S_CKR_CKP_POS; + break; + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, I2S_CKR, mask, val); + + mask = I2S_TXCR_IBM_MASK | I2S_TXCR_TFS_MASK | I2S_TXCR_PBM_MASK; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_RIGHT_J: val = I2S_TXCR_IBM_RSJM; @@ -215,13 +229,19 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai, case SND_SOC_DAIFMT_I2S: val = I2S_TXCR_IBM_NORMAL; break; + case SND_SOC_DAIFMT_DSP_A: /* PCM no delay mode */ + val = I2S_TXCR_TFS_PCM; + break; + case SND_SOC_DAIFMT_DSP_B: /* PCM delay 1 mode */ + val = I2S_TXCR_TFS_PCM | I2S_TXCR_PBM_MODE(1); + break; default: return -EINVAL; } regmap_update_bits(i2s->regmap, I2S_TXCR, mask, val); - mask = I2S_RXCR_IBM_MASK; + mask = I2S_RXCR_IBM_MASK | I2S_RXCR_TFS_MASK | I2S_RXCR_PBM_MASK; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_RIGHT_J: val = I2S_RXCR_IBM_RSJM; @@ -232,6 +252,12 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai, case SND_SOC_DAIFMT_I2S: val = I2S_RXCR_IBM_NORMAL; break; + case SND_SOC_DAIFMT_DSP_A: /* PCM no delay mode */ + val = I2S_RXCR_TFS_PCM; + break; + case SND_SOC_DAIFMT_DSP_B: /* PCM delay 1 mode */ + val = I2S_RXCR_TFS_PCM | I2S_RXCR_PBM_MODE(1); + break; default: return -EINVAL; } diff --git a/sound/soc/rockchip/rockchip_i2s.h b/sound/soc/rockchip/rockchip_i2s.h index 31f11fd25393..a7b8527d8a73 100644 --- a/sound/soc/rockchip/rockchip_i2s.h +++ b/sound/soc/rockchip/rockchip_i2s.h @@ -41,6 +41,7 @@ #define I2S_TXCR_TFS_SHIFT 5 #define I2S_TXCR_TFS_I2S (0 << I2S_TXCR_TFS_SHIFT) #define I2S_TXCR_TFS_PCM (1 << I2S_TXCR_TFS_SHIFT) +#define I2S_TXCR_TFS_MASK (1 << I2S_TXCR_TFS_SHIFT) #define I2S_TXCR_VDW_SHIFT 0 #define I2S_TXCR_VDW(x) ((x - 1) << I2S_TXCR_VDW_SHIFT) #define I2S_TXCR_VDW_MASK (0x1f << I2S_TXCR_VDW_SHIFT) @@ -70,6 +71,7 @@ #define I2S_RXCR_TFS_SHIFT 5 #define I2S_RXCR_TFS_I2S (0 << I2S_RXCR_TFS_SHIFT) #define I2S_RXCR_TFS_PCM (1 << I2S_RXCR_TFS_SHIFT) +#define I2S_RXCR_TFS_MASK (1 << I2S_RXCR_TFS_SHIFT) #define I2S_RXCR_VDW_SHIFT 0 #define I2S_RXCR_VDW(x) ((x - 1) << I2S_RXCR_VDW_SHIFT) #define I2S_RXCR_VDW_MASK (0x1f << I2S_RXCR_VDW_SHIFT) @@ -91,6 +93,7 @@ #define I2S_CKR_CKP_SHIFT 26 #define I2S_CKR_CKP_NEG (0 << I2S_CKR_CKP_SHIFT) #define I2S_CKR_CKP_POS (1 << I2S_CKR_CKP_SHIFT) +#define I2S_CKR_CKP_MASK (1 << I2S_CKR_CKP_SHIFT) #define I2S_CKR_RLP_SHIFT 25 #define I2S_CKR_RLP_NORMAL (0 << I2S_CKR_RLP_SHIFT) #define I2S_CKR_RLP_OPPSITE (1 << I2S_CKR_RLP_SHIFT) From 5894b91d1e700f38b4157df143be1502cf08daa8 Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Fri, 9 Jun 2017 16:52:46 +0800 Subject: [PATCH 271/418] ASoC: rockchip: i2s: add a delay before i2s clear in order to guarantee i2s lrck signal integrity, when i2s stop, need at least one lrck cycle to ensure signal integrity. the max delay time is when lrck is 8khz, the delay time is 125us(1/8khz), using udelay(150) with a 25us margin. Signed-off-by: Sugar Zhang Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 974915cb4c4f..f54843342ee2 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -116,6 +116,7 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on) I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP); + udelay(150); regmap_update_bits(i2s->regmap, I2S_CLR, I2S_CLR_TXC | I2S_CLR_RXC, I2S_CLR_TXC | I2S_CLR_RXC); @@ -162,6 +163,7 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on) I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP); + udelay(150); regmap_update_bits(i2s->regmap, I2S_CLR, I2S_CLR_TXC | I2S_CLR_RXC, I2S_CLR_TXC | I2S_CLR_RXC); From 891caea417469b4efdf506b6be1ef461b759c999 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 9 Jun 2017 00:43:18 +0000 Subject: [PATCH 272/418] ASoC: simple_card_utils: add asoc_simple_card_clk_xxx() Current simple-card-utils sets asoc_simple_dai::clk via asoc_simple_card_parse_clk(). Current simple card drivers are using it directly for clk_enable/disable. Encapsulation is one of simple card util's purpose. Let's encapsulate it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 2 ++ sound/soc/generic/simple-card-utils.c | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 108cae459ed0..840d624148df 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -45,6 +45,8 @@ int asoc_simple_card_parse_clk(struct device *dev, struct device_node *dai_of_node, struct asoc_simple_dai *simple_dai, const char *name); +int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai); +void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai); #define asoc_simple_card_parse_cpu(node, dai_link, \ list_name, cells_name, is_single_link) \ diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index d9d8b8a58348..beb4e3817d22 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -110,6 +110,22 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name); +static void asoc_simple_card_clk_register(struct asoc_simple_dai *dai, + struct clk *clk) +{ + dai->clk = clk; +} + +int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai) +{ + return clk_prepare_enable(dai->clk); +} + +void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai) +{ + clk_disable_unprepare(dai->clk); +} + int asoc_simple_card_parse_clk(struct device *dev, struct device_node *node, struct device_node *dai_of_node, @@ -128,7 +144,8 @@ int asoc_simple_card_parse_clk(struct device *dev, clk = devm_get_clk_from_child(dev, node, NULL); if (!IS_ERR(clk)) { simple_dai->sysclk = clk_get_rate(clk); - simple_dai->clk = clk; + + asoc_simple_card_clk_register(simple_dai, clk); } else if (!of_property_read_u32(node, "system-clock-frequency", &val)) { simple_dai->sysclk = val; } else { From 3ab50c4f98434080c1f73fc56d8d8b38364c6cd8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 9 Jun 2017 00:44:16 +0000 Subject: [PATCH 273/418] ASoC: simple-card: use asoc_simple_card_clk_xxx() Current simple-card-utils sets asoc_simple_dai::clk via asoc_simple_card_parse_clk(). Current simple card drivers are using it directly for clk_enable/disable. Encapsulation is one of simple card util's purpose. Let's use asoc_simple_card_clk_enable/disable. Signed-off-by: Kuninori Morimoto 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 e26bd14ba70f..8828b91867b8 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -118,13 +118,13 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream) simple_priv_to_props(priv, rtd->num); int ret; - ret = clk_prepare_enable(dai_props->cpu_dai.clk); + ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai); if (ret) return ret; - ret = clk_prepare_enable(dai_props->codec_dai.clk); + ret = asoc_simple_card_clk_enable(&dai_props->codec_dai); if (ret) - clk_disable_unprepare(dai_props->cpu_dai.clk); + asoc_simple_card_clk_disable(&dai_props->cpu_dai); return ret; } @@ -136,9 +136,9 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); - clk_disable_unprepare(dai_props->cpu_dai.clk); + asoc_simple_card_clk_disable(&dai_props->cpu_dai); - clk_disable_unprepare(dai_props->codec_dai.clk); + asoc_simple_card_clk_disable(&dai_props->codec_dai); } static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, From bb24a3ba3f52942b5f3eb6c10288da830ec9ef70 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 9 Jun 2017 00:44:40 +0000 Subject: [PATCH 274/418] ASoC: simple-scu-card: use asoc_simple_card_clk_xxx() Current simple-card-utils sets asoc_simple_dai::clk via asoc_simple_card_parse_clk(). Current simple card drivers are using it directly for clk_enable/disable. Encapsulation is one of simple card util's purpose. Let's use asoc_simple_card_clk_enable/disable. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-scu-card.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index 5faf5d6c48a2..f203783b2fad 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -47,7 +47,7 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream) struct asoc_simple_dai *dai_props = simple_priv_to_props(priv, rtd->num); - return clk_prepare_enable(dai_props->clk); + return asoc_simple_card_clk_enable(dai_props); } static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) @@ -57,7 +57,7 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) struct asoc_simple_dai *dai_props = simple_priv_to_props(priv, rtd->num); - clk_disable_unprepare(dai_props->clk); + asoc_simple_card_clk_disable(dai_props); } static const struct snd_soc_ops asoc_simple_card_ops = { From 6654fc77797e306a3b67b3cdf0b6121294893dba Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 9 Jun 2017 00:45:01 +0000 Subject: [PATCH 275/418] ASoC: audio-graph-scu-card: use asoc_simple_card_clk_xxx() Current simple-card-utils sets asoc_simple_dai::clk via asoc_simple_card_parse_clk(). Current simple card drivers are using it directly for clk_enable/disable. Encapsulation is one of simple card util's purpose. Let's use asoc_simple_card_clk_enable/disable. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-scu-card.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c index 0066102f5bc4..27a261ee7302 100644 --- a/sound/soc/generic/audio-graph-scu-card.c +++ b/sound/soc/generic/audio-graph-scu-card.c @@ -45,7 +45,7 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream) struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num); - return clk_prepare_enable(dai_props->clk); + return asoc_simple_card_clk_enable(dai_props); } static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) @@ -54,7 +54,7 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num); - clk_disable_unprepare(dai_props->clk); + asoc_simple_card_clk_disable(dai_props); } static struct snd_soc_ops asoc_graph_card_ops = { From d471d55934ca8b4f38535207589df4e3cc8b1484 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 9 Jun 2017 00:45:23 +0000 Subject: [PATCH 276/418] ASoC: audio-graph-card: use asoc_simple_card_clk_xxx() Current simple-card-utils sets asoc_simple_dai::clk via asoc_simple_card_parse_clk(). Current simple card drivers are using it directly for clk_enable/disable. Encapsulation is one of simple card util's purpose. Let's use asoc_simple_card_clk_enable/disable. Signed-off-by: Kuninori Morimoto 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 0180b286bee3..b5bb791a6e61 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -44,13 +44,13 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream) struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); int ret; - ret = clk_prepare_enable(dai_props->cpu_dai.clk); + ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai); if (ret) return ret; - ret = clk_prepare_enable(dai_props->codec_dai.clk); + ret = asoc_simple_card_clk_enable(&dai_props->codec_dai); if (ret) - clk_disable_unprepare(dai_props->cpu_dai.clk); + asoc_simple_card_clk_disable(&dai_props->cpu_dai); return ret; } @@ -61,9 +61,9 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - clk_disable_unprepare(dai_props->cpu_dai.clk); + asoc_simple_card_clk_disable(&dai_props->cpu_dai); - clk_disable_unprepare(dai_props->codec_dai.clk); + asoc_simple_card_clk_disable(&dai_props->codec_dai); } static struct snd_soc_ops asoc_graph_card_ops = { From 34bcc44abb302d1586bf1eb7548be75d0f56babc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 May 2016 14:58:04 +0200 Subject: [PATCH 277/418] ALSA: pcm: Clean up SNDRV_PCM_IOCTL_PAUSE code Use snd_pcm_action_lock_irq() helper instead of open coding. No functional change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 07995e645327..798bca967c0e 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2865,13 +2865,9 @@ static int snd_pcm_common_ioctl1(struct file *file, case SNDRV_PCM_IOCTL_DROP: return snd_pcm_drop(substream); case SNDRV_PCM_IOCTL_PAUSE: - { - int res; - snd_pcm_stream_lock_irq(substream); - res = snd_pcm_pause(substream, (int)(unsigned long)arg); - snd_pcm_stream_unlock_irq(substream); - return res; - } + return snd_pcm_action_lock_irq(&snd_pcm_action_pause, + substream, + (int)(unsigned long)arg); } pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd); return -ENOTTY; From 68b4acd322494444803a3f49884ae889c8ec6689 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 May 2016 15:07:39 +0200 Subject: [PATCH 278/418] ALSA: pcm: Apply power lock globally to common ioctls All PCM common ioctls should run only in the powered up state, but currently only a few ioctls do the proper snd_power_lock() and snd_power_wait() invocations. Instead of adding to each place, do it commonly in the caller side, so that all these ioctls are assured to be operated at the power up state. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 56 ++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 37 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 798bca967c0e..bd1b74aa2068 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1540,14 +1540,7 @@ static const struct action_ops snd_pcm_action_resume = { static int snd_pcm_resume(struct snd_pcm_substream *substream) { - struct snd_card *card = substream->pcm->card; - int res; - - snd_power_lock(card); - if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) - res = snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0); - snd_power_unlock(card); - return res; + return snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0); } #else @@ -1566,17 +1559,9 @@ static int snd_pcm_resume(struct snd_pcm_substream *substream) */ static int snd_pcm_xrun(struct snd_pcm_substream *substream) { - struct snd_card *card = substream->pcm->card; struct snd_pcm_runtime *runtime = substream->runtime; int result; - snd_power_lock(card); - if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { - result = snd_power_wait(card, SNDRV_CTL_POWER_D0); - if (result < 0) - goto _unlock; - } - snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_XRUN: @@ -1589,8 +1574,6 @@ static int snd_pcm_xrun(struct snd_pcm_substream *substream) result = -EBADFD; } snd_pcm_stream_unlock_irq(substream); - _unlock: - snd_power_unlock(card); return result; } @@ -1694,8 +1677,6 @@ static const struct action_ops snd_pcm_action_prepare = { static int snd_pcm_prepare(struct snd_pcm_substream *substream, struct file *file) { - int res; - struct snd_card *card = substream->pcm->card; int f_flags; if (file) @@ -1703,12 +1684,8 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream, else f_flags = substream->f_flags; - snd_power_lock(card); - if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) - res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, - substream, f_flags); - snd_power_unlock(card); - return res; + return snd_pcm_action_nonatomic(&snd_pcm_action_prepare, + substream, f_flags); } /* @@ -1805,15 +1782,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; - snd_power_lock(card); - if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { - result = snd_power_wait(card, SNDRV_CTL_POWER_D0); - if (result < 0) { - snd_power_unlock(card); - return result; - } - } - if (file) { if (file->f_flags & O_NONBLOCK) nonblock = 1; @@ -1896,7 +1864,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, unlock: snd_pcm_stream_unlock_irq(substream); up_read(&snd_pcm_link_rwsem); - snd_power_unlock(card); return result; } @@ -2798,7 +2765,7 @@ static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg) return 0; } -static int snd_pcm_common_ioctl1(struct file *file, +static int snd_pcm_common_ioctl(struct file *file, struct snd_pcm_substream *substream, unsigned int cmd, void __user *arg) { @@ -2873,6 +2840,21 @@ static int snd_pcm_common_ioctl1(struct file *file, return -ENOTTY; } +static int snd_pcm_common_ioctl1(struct file *file, + struct snd_pcm_substream *substream, + unsigned int cmd, void __user *arg) +{ + struct snd_card *card = substream->pcm->card; + int res; + + snd_power_lock(card); + res = snd_power_wait(card, SNDRV_CTL_POWER_D0); + if (res >= 0) + res = snd_pcm_common_ioctl(file, substream, cmd, arg); + snd_power_unlock(card); + return res; +} + static int snd_pcm_playback_ioctl1(struct file *file, struct snd_pcm_substream *substream, unsigned int cmd, void __user *arg) From 4b95ff781e30c50298257d22a2c3743b2e5739be Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 May 2016 15:08:31 +0200 Subject: [PATCH 279/418] ALSA: pcm: Allow dropping stream directly after resume So far, the PCM core refuses DROP ioctl when the stream in the suspended state. This was basically to avoid the invalid state change *during* the suspend. But since we protect the power change globally in the common PCM ioctl caller side, it's guaranteed that snd_pcm_drop() is called at the right power state. So we can assume that the drop of stream is safe immediately after SUSPENDED state. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index bd1b74aa2068..69cf9b02ac70 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1883,8 +1883,7 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream) runtime = substream->runtime; if (runtime->status->state == SNDRV_PCM_STATE_OPEN || - runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED || - runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) + runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) return -EBADFD; snd_pcm_stream_lock_irq(substream); From 1b745cd97425f7b0b9d0c87c1b9766c31b7d0a7e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 May 2016 15:40:03 +0200 Subject: [PATCH 280/418] ALSA: pcm: Preprocess PAUSED or SUSPENDED stream before PREPARE Calling PREPARE ioctl to the stream in either PAUSED or SUSPENDED state may confuse some drivers that don't handle the state properly. Instead of fixing each driver, PCM core should take care of the proper state change before actually trying to (re-)prepare the stream. Namely, when the stream is in PAUSED state, it triggers PAUSE_RELEASE, and when in SUSPENDED state, it triggers STOP, before calling prepare callbacks. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 69cf9b02ac70..0941b9c92b3f 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1684,6 +1684,17 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream, else f_flags = substream->f_flags; + snd_pcm_stream_lock_irq(substream); + switch (substream->runtime->status->state) { + case SNDRV_PCM_STATE_PAUSED: + snd_pcm_pause(substream, 0); + /* fallthru */ + case SNDRV_PCM_STATE_SUSPENDED: + snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); + break; + } + snd_pcm_stream_unlock_irq(substream); + return snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, f_flags); } From 4e99151435cb2e88b6d0d49939bf836c35e555a3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 May 2016 15:53:36 +0200 Subject: [PATCH 281/418] ALSA: pcm: Use common PCM_RUNTIME_CHECK() for sanity checks Just a code cleanup. Reviewed-by: Takashi Sakamoto 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 0941b9c92b3f..05858c91c0ea 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2869,7 +2869,7 @@ static int snd_pcm_playback_ioctl1(struct file *file, struct snd_pcm_substream *substream, unsigned int cmd, void __user *arg) { - if (snd_BUG_ON(!substream)) + if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_PLAYBACK)) return -EINVAL; @@ -2949,7 +2949,7 @@ static int snd_pcm_capture_ioctl1(struct file *file, struct snd_pcm_substream *substream, unsigned int cmd, void __user *arg) { - if (snd_BUG_ON(!substream)) + if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_CAPTURE)) return -EINVAL; From f8ff2f28ba49fa41a06215ac3187dede347bc9a7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 13 Jun 2017 15:57:28 +0200 Subject: [PATCH 282/418] ALSA: pcm: Skip ack callback without actual appl_ptr update We call ack callback whenever appl_ptr gets updated via pcm_lib_apply_appl_ptr(). There are various code paths to call this function. A part of them are for read/write/forward/rewind, where the appl_ptr is always changed and thus the call of ack is mandatory. OTOH, another part of code paths are from the explicit user call, e.g. via SYNC_PTR ioctl. There, we may receive the same appl_ptr value, and in such a case, calling ack is obviously superfluous. This patch adds the check of the given appl_ptr value, and returns immediately if it's no real update. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index e73b6e4135f6..75308ddc54ca 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2112,6 +2112,9 @@ int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream, snd_pcm_uframes_t old_appl_ptr = runtime->control->appl_ptr; int ret; + if (old_appl_ptr == appl_ptr) + return 0; + runtime->control->appl_ptr = appl_ptr; if (substream->ops->ack) { ret = substream->ops->ack(substream); From 63a5f59208bce7110596b09950f48bf07b8baeb9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 14 Jun 2017 01:04:11 +0000 Subject: [PATCH 283/418] ASoC: simple_card_utils: add EXPORT_SYMBOL_GPL() for asoc_simple_card_clk_xxx() commit 891caea41746 ("ASoC: simple_card_utils: add asoc_simple_card_clk_xxx()") added new asoc_simple_card_clk_xxx(), but, it didn't have EXPORT_SYMBOL_GPL(). This patch adds it. Otherwise, we will get below error ERROR: "asoc_simple_card_clk_enable" [sound/soc/generic/snd-soc-simple-scu-card.ko] undefined! ERROR: "asoc_simple_card_clk_disable" [sound/soc/generic/snd-soc-simple-scu-card.ko] undefined! ERROR: "asoc_simple_card_clk_enable" [sound/soc/generic/snd-soc-simple-card.ko] undefined! ERROR: "asoc_simple_card_clk_disable" [sound/soc/generic/snd-soc-simple-card.ko] undefined! ERROR: "asoc_simple_card_clk_enable" [sound/soc/generic/snd-soc-audio-graph-scu-card.ko] undefined! ERROR: "asoc_simple_card_clk_disable" [sound/soc/generic/snd-soc-audio-graph-scu-card.ko] undefined! ERROR: "asoc_simple_card_clk_enable" [sound/soc/generic/snd-soc-audio-graph-card.ko] undefined! ERROR: "asoc_simple_card_clk_disable" [sound/soc/generic/snd-soc-audio-graph-card.ko] undefined! Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card-utils.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index beb4e3817d22..2ad7633292bf 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -120,11 +120,13 @@ int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai) { return clk_prepare_enable(dai->clk); } +EXPORT_SYMBOL_GPL(asoc_simple_card_clk_enable); void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai) { clk_disable_unprepare(dai->clk); } +EXPORT_SYMBOL_GPL(asoc_simple_card_clk_disable); int asoc_simple_card_parse_clk(struct device *dev, struct device_node *node, From a729526720059ae019803acc953f07d9c17ae234 Mon Sep 17 00:00:00 2001 From: Richard Leitner Date: Wed, 14 Jun 2017 10:36:12 +0200 Subject: [PATCH 284/418] ASoC: sgtl5000: add avc support The sgtl5000 features an automatic volume control block (AVC), which reduces loud signals and amplifies low level signals for easier listening. This patch adds support for this AVC block to the driver. Apart from the "AVC Switch" control which enables the block following controls for the configuration of AVC are added: + AVC Threshold Volume: threshold where audio is compressed when the measured level is above or expanded when below + AVC Max Gain Volume: maximum gain which can be applied when the measured audio level is below threshold + AVC Hard Limiter Switch: when enabled the signal is limited to the programmed threshold. + AVC Integrator Response: response time of the integrator The AVC block is enabled and configured using the DAP_AVC_CTRL and DAP_AVC_THRESHOLD registers. Following 2 checkpatch.pl strict checks are ignored because the indentation style is different for the struct snd_kcontrol_new definition: patch:147: CHECK: Alignment should match open parenthesis patch:150: CHECK: Alignment should match open parenthesis Signed-off-by: Richard Leitner Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 89 +++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 5a2702edeb77..8f6814c1eb6b 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -74,6 +74,20 @@ static const struct reg_default sgtl5000_reg_defaults[] = { { SGTL5000_DAP_AVC_DECAY, 0x0050 }, }; +/* AVC: Threshold dB -> register: pre-calculated values */ +static const u16 avc_thr_db2reg[97] = { + 0x5168, 0x488E, 0x40AA, 0x39A1, 0x335D, 0x2DC7, 0x28CC, 0x245D, 0x2068, + 0x1CE2, 0x19BE, 0x16F1, 0x1472, 0x1239, 0x103E, 0x0E7A, 0x0CE6, 0x0B7F, + 0x0A3F, 0x0922, 0x0824, 0x0741, 0x0677, 0x05C3, 0x0522, 0x0493, 0x0414, + 0x03A2, 0x033D, 0x02E3, 0x0293, 0x024B, 0x020B, 0x01D2, 0x019F, 0x0172, + 0x014A, 0x0126, 0x0106, 0x00E9, 0x00D0, 0x00B9, 0x00A5, 0x0093, 0x0083, + 0x0075, 0x0068, 0x005D, 0x0052, 0x0049, 0x0041, 0x003A, 0x0034, 0x002E, + 0x0029, 0x0025, 0x0021, 0x001D, 0x001A, 0x0017, 0x0014, 0x0012, 0x0010, + 0x000E, 0x000D, 0x000B, 0x000A, 0x0009, 0x0008, 0x0007, 0x0006, 0x0005, + 0x0005, 0x0004, 0x0004, 0x0003, 0x0003, 0x0002, 0x0002, 0x0002, 0x0002, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}; + /* regulator supplies for sgtl5000, VDDD is an optional external supply */ enum sgtl5000_regulator_supplies { VDDA, @@ -382,6 +396,65 @@ static int dac_put_volsw(struct snd_kcontrol *kcontrol, return 0; } +/* + * custom function to get AVC threshold + * + * The threshold dB is calculated by rearranging the calculation from the + * avc_put_threshold function: register_value = 10^(dB/20) * 0.636 * 2^15 ==> + * dB = ( fls(register_value) - 14.347 ) * 6.02 + * + * As this calculation is expensive and the threshold dB values may not exeed + * 0 to 96 we use pre-calculated values. + */ +static int avc_get_threshold(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int db, i; + u16 reg = snd_soc_read(codec, SGTL5000_DAP_AVC_THRESHOLD); + + /* register value 0 => -96dB */ + if (!reg) { + ucontrol->value.integer.value[0] = 96; + ucontrol->value.integer.value[1] = 96; + return 0; + } + + /* get dB from register value (rounded down) */ + for (i = 0; avc_thr_db2reg[i] > reg; i++) + ; + db = i; + + ucontrol->value.integer.value[0] = db; + ucontrol->value.integer.value[1] = db; + + return 0; +} + +/* + * custom function to put AVC threshold + * + * The register value is calculated by following formula: + * register_value = 10^(dB/20) * 0.636 * 2^15 + * As this calculation is expensive and the threshold dB values may not exeed + * 0 to 96 we use pre-calculated values. + */ +static int avc_put_threshold(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int db; + u16 reg; + + db = (int)ucontrol->value.integer.value[0]; + if (db < 0 || db > 96) + return -EINVAL; + reg = avc_thr_db2reg[db]; + snd_soc_write(codec, SGTL5000_DAP_AVC_THRESHOLD, reg); + + return 0; +} + static const DECLARE_TLV_DB_SCALE(capture_6db_attenuate, -600, 600, 0); /* tlv for mic gain, 0db 20db 30db 40db */ @@ -396,6 +469,12 @@ static const DECLARE_TLV_DB_SCALE(headphone_volume, -5150, 50, 0); /* tlv for lineout volume, 31 steps of .5db each */ static const DECLARE_TLV_DB_SCALE(lineout_volume, -1550, 50, 0); +/* tlv for dap avc max gain, 0db, 6db, 12db */ +static const DECLARE_TLV_DB_SCALE(avc_max_gain, 0, 600, 0); + +/* tlv for dap avc threshold, */ +static const DECLARE_TLV_DB_MINMAX(avc_threshold, 0, 9600); + static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { /* SOC_DOUBLE_S8_TLV with invert */ { @@ -434,6 +513,16 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { 0x1f, 1, lineout_volume), SOC_SINGLE("Lineout Playback Switch", SGTL5000_CHIP_ANA_CTRL, 8, 1, 1), + + /* Automatic Volume Control (DAP AVC) */ + SOC_SINGLE("AVC Switch", SGTL5000_DAP_AVC_CTRL, 0, 1, 0), + SOC_SINGLE("AVC Hard Limiter Switch", SGTL5000_DAP_AVC_CTRL, 5, 1, 0), + SOC_SINGLE_TLV("AVC Max Gain Volume", SGTL5000_DAP_AVC_CTRL, 12, 2, 0, + avc_max_gain), + SOC_SINGLE("AVC Integrator Response", SGTL5000_DAP_AVC_CTRL, 8, 3, 0), + SOC_SINGLE_EXT_TLV("AVC Threshold Volume", SGTL5000_DAP_AVC_THRESHOLD, + 0, 96, 0, avc_get_threshold, avc_put_threshold, + avc_threshold), }; /* mute the codec used by alsa core */ From 21031d531eb33a6ad0251ff661a539802700c6e5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 14 Jun 2017 09:33:06 +0200 Subject: [PATCH 285/418] ASoC: intel: bxt: Constify hw_constraints snd_pcm_hw_constraint_list(), *_ratnums() and *_ratdens() receive the const pointers. Constify the corresponding static objects for better hardening. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 12 ++++++------ sound/soc/intel/boards/bxt_rt298.c | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 3a8c4d954a91..1429eb391da8 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -238,31 +238,31 @@ static int broxton_da7219_fe_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static unsigned int rates[] = { +static const unsigned int rates[] = { 48000, }; -static struct snd_pcm_hw_constraint_list constraints_rates = { +static const struct snd_pcm_hw_constraint_list constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, }; -static unsigned int channels[] = { +static const unsigned int channels[] = { DUAL_CHANNEL, }; -static struct snd_pcm_hw_constraint_list constraints_channels = { +static const struct snd_pcm_hw_constraint_list constraints_channels = { .count = ARRAY_SIZE(channels), .list = channels, .mask = 0, }; -static unsigned int channels_quad[] = { +static const unsigned int channels_quad[] = { QUAD_CHANNEL, }; -static struct snd_pcm_hw_constraint_list constraints_channels_quad = { +static const struct snd_pcm_hw_constraint_list constraints_channels_quad = { .count = ARRAY_SIZE(channels_quad), .list = channels_quad, .mask = 0, diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 36ee7480e9f1..0c3a3cbcb884 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -207,11 +207,11 @@ static const struct snd_soc_ops broxton_rt298_ops = { .hw_params = broxton_rt298_hw_params, }; -static unsigned int rates[] = { +static const unsigned int rates[] = { 48000, }; -static struct snd_pcm_hw_constraint_list constraints_rates = { +static const struct snd_pcm_hw_constraint_list constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, @@ -227,11 +227,11 @@ static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static unsigned int channels_dmic[] = { +static const unsigned int channels_dmic[] = { 1, 2, 3, 4, }; -static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { +static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { .count = ARRAY_SIZE(channels_dmic), .list = channels_dmic, .mask = 0, @@ -253,11 +253,11 @@ static const struct snd_soc_ops broxton_dmic_ops = { .startup = broxton_dmic_startup, }; -static unsigned int channels[] = { +static const unsigned int channels[] = { 2, }; -static struct snd_pcm_hw_constraint_list constraints_channels = { +static const struct snd_pcm_hw_constraint_list constraints_channels = { .count = ARRAY_SIZE(channels), .list = channels, .mask = 0, From f30b4ca4447095f6923b59ffaa25ca6a54daffac Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 14 Jun 2017 07:41:43 +0000 Subject: [PATCH 286/418] ASoC: rsnd: reduce confusable macro parameter magic rsnd_dai_call() macro is using "priv" inside. Thus, if caller function doesn't have "priv" related operation, strange phenomenon occur which code is using "priv", but compiler indicates "unused variable 'priv'". >From code point of view, it is not problem, but it is very confusable. This patch removes "priv" from rsnd_dai_call() macro, and adds "priv" on caller function. Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 0bb99aa70e29..1b536d140e49 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -488,8 +488,7 @@ static int rsnd_status_update(u32 *status, #define rsnd_dai_call(fn, io, param...) \ ({ \ - struct rsnd_priv *priv = rsnd_io_to_priv(io); \ - struct device *dev = rsnd_priv_to_dev(priv); \ + struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); \ struct rsnd_mod *mod; \ int is_play = rsnd_io_is_play(io); \ int ret = 0, i; \ @@ -741,6 +740,7 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); int ret; @@ -758,6 +758,7 @@ static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); /* From a83ac4860925e1d0a7e38e7bea331fd2f2e0460d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 14 Jun 2017 00:31:06 +0000 Subject: [PATCH 287/418] ASoC: ak4613: add missing 64000 in ak4613_dai_hw_params() Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/ak4613.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index e3121ca3d1a2..d5beca008dea 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -321,6 +321,7 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, case 48000: ctrl2 = DFS_NORMAL_SPEED; break; + case 64000: case 88200: case 96000: ctrl2 = DFS_DOUBLE_SPEED; From e68ba207444354ddf295de2e7fbcc97c06cccc8b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 14 Jun 2017 00:34:35 +0000 Subject: [PATCH 288/418] ASoC: simple-card-utils: add asoc_simple_card_of_parse_tdm() Current simple card drivers are using asoc_simple_dai's tx_slot_mask, rx_slot_mask, slots, slot_width directly to parse TDM. Encapsulation is one of simple card util's purpose. Let's add asoc_simple_card_of_parse_tdm for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 840d624148df..2679312228b3 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -75,6 +75,12 @@ int asoc_simple_card_parse_graph_dai(struct device_node *ep, struct device_node **endpoint_np, const char **dai_name); +#define asoc_simple_card_of_parse_tdm(np, dai) \ + snd_soc_of_parse_tdm_slot(np, &(dai)->tx_slot_mask, \ + &(dai)->rx_slot_mask, \ + &(dai)->slots, \ + &(dai)->slot_width); + int asoc_simple_card_init_dai(struct snd_soc_dai *dai, struct asoc_simple_dai *simple_dai); From b93d2cf8c0facb593d6f008af30ae0fcd1d49ede Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 14 Jun 2017 00:34:53 +0000 Subject: [PATCH 289/418] ASoC: simple-card: use asoc_simple_card_of_parse_tdm() Current simple card drivers are using asoc_simple_dai's tx_slot_mask, rx_slot_mask, slots, slot_width directly to parse TDM. Encapsulation is one of simple card util's purpose. Let's use asoc_simple_card_of_parse_tdm for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 8828b91867b8..8b414af966ee 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -271,17 +271,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, if (ret < 0) goto dai_link_of_err; - ret = snd_soc_of_parse_tdm_slot(cpu, &cpu_dai->tx_slot_mask, - &cpu_dai->rx_slot_mask, - &cpu_dai->slots, - &cpu_dai->slot_width); + ret = asoc_simple_card_of_parse_tdm(cpu, cpu_dai); if (ret < 0) goto dai_link_of_err; - ret = snd_soc_of_parse_tdm_slot(codec, &codec_dai->tx_slot_mask, - &codec_dai->rx_slot_mask, - &codec_dai->slots, - &codec_dai->slot_width); + ret = asoc_simple_card_of_parse_tdm(codec, codec_dai); if (ret < 0) goto dai_link_of_err; From 77b713b52878fbe21d9d5339cc42fbec3202392e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 14 Jun 2017 00:35:13 +0000 Subject: [PATCH 290/418] ASoC: simple-scu-card: use asoc_simple_card_of_parse_tdm() Current simple card drivers are using asoc_simple_dai's tx_slot_mask, rx_slot_mask, slots, slot_width directly to parse TDM. Encapsulation is one of simple card util's purpose. Let's use asoc_simple_card_of_parse_tdm for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-scu-card.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index f203783b2fad..938f3f30eef1 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -171,11 +171,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, PREFIX "prefix"); } - ret = snd_soc_of_parse_tdm_slot(np, - &dai_props->tx_slot_mask, - &dai_props->rx_slot_mask, - &dai_props->slots, - &dai_props->slot_width); + ret = asoc_simple_card_of_parse_tdm(np, dai_props); if (ret) return ret; From c98907d59594827535b492309a145ac9c758fb4c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 14 Jun 2017 00:35:30 +0000 Subject: [PATCH 291/418] ASoC: audio-graph-card: use asoc_simple_card_of_parse_tdm() Current simple card drivers are using asoc_simple_dai's tx_slot_mask, rx_slot_mask, slots, slot_width directly to parse TDM. Encapsulation is one of simple card util's purpose. Let's use asoc_simple_card_of_parse_tdm for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index b5bb791a6e61..885b405d7844 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -131,19 +131,11 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, if (ret < 0) goto dai_link_of_err; - ret = snd_soc_of_parse_tdm_slot(cpu_ep, - &cpu_dai->tx_slot_mask, - &cpu_dai->rx_slot_mask, - &cpu_dai->slots, - &cpu_dai->slot_width); + ret = asoc_simple_card_of_parse_tdm(cpu_ep, cpu_dai); if (ret < 0) goto dai_link_of_err; - ret = snd_soc_of_parse_tdm_slot(codec_ep, - &codec_dai->tx_slot_mask, - &codec_dai->rx_slot_mask, - &codec_dai->slots, - &codec_dai->slot_width); + ret = asoc_simple_card_of_parse_tdm(codec_ep, codec_dai); if (ret < 0) goto dai_link_of_err; From 616c3b15f596e1f1e6c2537a1ad3492052eecba6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 14 Jun 2017 00:35:47 +0000 Subject: [PATCH 292/418] ASoC: audio-graph-scu-card: use asoc_simple_card_of_parse_tdm() Current simple card drivers are using asoc_simple_dai's tx_slot_mask, rx_slot_mask, slots, slot_width directly to parse TDM. Encapsulation is one of simple card util's purpose. Let's use asoc_simple_card_of_parse_tdm for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-scu-card.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c index 27a261ee7302..4d295d07858a 100644 --- a/sound/soc/generic/audio-graph-scu-card.c +++ b/sound/soc/generic/audio-graph-scu-card.c @@ -167,11 +167,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, "prefix"); } - ret = snd_soc_of_parse_tdm_slot(ep, - &dai_props->tx_slot_mask, - &dai_props->rx_slot_mask, - &dai_props->slots, - &dai_props->slot_width); + ret = asoc_simple_card_of_parse_tdm(ep, dai_props); if (ret) return ret; From e11f0f90a626f93899687b1cc909ee37dd6c5809 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 14 Jun 2017 19:30:03 +0900 Subject: [PATCH 293/418] ALSA: pcm: remove SNDRV_PCM_IOCTL1_INFO internal command Drivers can implement 'struct snd_pcm_ops.ioctl' to handle some requests from ALSA PCM core. These requests are internal purpose in kernel land. Usually common set of operations are used for it. SNDRV_PCM_IOCTL1_INFO is one of the requests. According to code comment, it has been obsoleted in the old days. We can see old releases in ftp.alsa-project.org. The command was firstly introduced in v0.5.0 release as SND_PCM_IOCTL1_INFO, to allow drivers to fill data of 'struct snd_pcm_channel_info' type. In v0.9.0 release, this was obsoleted by the other commands for ioctl(2) such as SNDRV_PCM_IOCTL_CHANNEL_INFO. This commit removes the long-abandoned command, bye. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 2 +- sound/core/pcm_lib.c | 2 -- sound/core/pcm_native.c | 6 +----- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index c24f85f12b71..48e3eecac86d 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -102,7 +102,7 @@ struct snd_pcm_ops { #endif #define SNDRV_PCM_IOCTL1_RESET 0 -#define SNDRV_PCM_IOCTL1_INFO 1 +/* 1 is absent slot. */ #define SNDRV_PCM_IOCTL1_CHANNEL_INFO 2 #define SNDRV_PCM_IOCTL1_GSTATE 3 #define SNDRV_PCM_IOCTL1_FIFO_SIZE 4 diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 75308ddc54ca..631cd598ba6c 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1787,8 +1787,6 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg) { switch (cmd) { - case SNDRV_PCM_IOCTL1_INFO: - return 0; case SNDRV_PCM_IOCTL1_RESET: return snd_pcm_lib_ioctl_reset(substream, arg); case SNDRV_PCM_IOCTL1_CHANNEL_INFO: diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 05858c91c0ea..7e8f3656b695 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -212,11 +212,7 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) info->subdevices_avail = pstr->substream_count - pstr->substream_opened; strlcpy(info->subname, substream->name, sizeof(info->subname)); runtime = substream->runtime; - /* AB: FIXME!!! This is definitely nonsense */ - if (runtime) { - info->sync = runtime->sync; - substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_INFO, info); - } + return 0; } From ba61faf0d75df9537393b2b796df41c30dcfcce7 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 14 Jun 2017 19:30:04 +0900 Subject: [PATCH 294/418] ALSA: pcm: remove SNDRV_PCM_IOCTL1_GSTATE internal command SNDRV_PCM_IOCTL1_GSTATE was firstly introduced in v0.9.0, however never be used and the purpose is missing. This commit removes the long-abandoned command, bye. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 48e3eecac86d..5a22075c5fcf 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -104,7 +104,7 @@ struct snd_pcm_ops { #define SNDRV_PCM_IOCTL1_RESET 0 /* 1 is absent slot. */ #define SNDRV_PCM_IOCTL1_CHANNEL_INFO 2 -#define SNDRV_PCM_IOCTL1_GSTATE 3 +/* 3 is absent slot. */ #define SNDRV_PCM_IOCTL1_FIFO_SIZE 4 #define SNDRV_PCM_TRIGGER_STOP 0 From 2a18483a7fb415c0c978f15cc690793b0f7d73e2 Mon Sep 17 00:00:00 2001 From: Harsha Priya N Date: Wed, 14 Jun 2017 10:32:17 -0700 Subject: [PATCH 295/418] ASoC: Intel: Add Kabylake machine driver for RT5514, RT5663 and MAX98927 This patch adds Kabylake I2S machine driver which uses codecs MAX98927 as speakers and RT5514 as dmic on ssp0 and RT5663 as headset on ssp1. Signed-off-by: Harsha Priya Signed-off-by: Hsin-yu Chao Signed-off-by: Naveen M Acked-By: Vinod Koul --- sound/soc/intel/Kconfig | 15 + sound/soc/intel/boards/Makefile | 2 + .../intel/boards/kbl_rt5663_rt5514_max98927.c | 640 ++++++++++++++++++ 3 files changed, 657 insertions(+) create mode 100644 sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 35a6a5c55914..b301bfff1c09 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -253,6 +253,21 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH Say Y if you have such a device. If unsure select "N". +config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH + tristate "ASoC Audio driver for KBL with RT5663, RT5514 and MAX98927 in I2S Mode" + depends on X86_INTEL_LPSS && I2C + select SND_SOC_INTEL_SST + select SND_SOC_INTEL_SKYLAKE + select SND_SOC_RT5663 + select SND_SOC_RT5514 + select SND_SOC_MAX98927 + select SND_SOC_HDAC_HDMI + help + This adds support for ASoC Onboard Codec I2S machine driver. This will + create an alsa sound card for RT5663 + RT5514 + MAX98927. + Say Y if you have such a device. + If unsure select "N". + config SND_SOC_INTEL_SKYLAKE tristate select SND_HDA_EXT_CORE diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index c4e986f03ec9..a5c5bc5732a2 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -14,6 +14,7 @@ snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o +snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o snd-soc-skl_rt286-objs := skl_rt286.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o @@ -34,6 +35,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o +obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c new file mode 100644 index 000000000000..3fe4a0807095 --- /dev/null +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -0,0 +1,640 @@ +/* + * Intel Kabylake I2S Machine Driver with MAXIM98927 + * RT5514 and RT5663 Codecs + * + * Copyright (C) 2017, Intel Corporation. All rights reserved. + * + * Modified from: + * Intel Kabylake I2S Machine driver supporting MAXIM98927 and + * RT5663 codecs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/rt5514.h" +#include "../../codecs/rt5663.h" +#include "../../codecs/hdac_hdmi.h" +#include "../skylake/skl.h" + +#define KBL_REALTEK_CODEC_DAI "rt5663-aif" +#define KBL_REALTEK_DMIC_CODEC_DAI "rt5514-aif1" +#define KBL_MAXIM_CODEC_DAI "max98927-aif1" +#define MAXIM_DEV0_NAME "i2c-MX98927:00" +#define MAXIM_DEV1_NAME "i2c-MX98927:01" +#define RT5514_DEV_NAME "i2c-10EC5514:00" +#define RT5663_DEV_NAME "i2c-10EC5663:00" +#define RT5514_AIF1_BCLK_FREQ (48000 * 8 * 16) +#define RT5514_AIF1_SYSCLK_FREQ 12288000 +#define NAME_SIZE 32 + +#define DMIC_CH(p) p->list[p->count-1] + + +static struct snd_soc_card kabylake_audio_card; +static const struct snd_pcm_hw_constraint_list *dmic_constraints; + +struct kbl_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct kbl_codec_private { + struct snd_soc_jack kabylake_headset; + struct list_head hdmi_pcm_list; + struct snd_soc_jack kabylake_hdmi[2]; +}; + +enum { + KBL_DPCM_AUDIO_PB = 0, + KBL_DPCM_AUDIO_CP, + KBL_DPCM_AUDIO_DMIC_CP, + KBL_DPCM_AUDIO_HDMI1_PB, + KBL_DPCM_AUDIO_HDMI2_PB, +}; + +static const struct snd_kcontrol_new kabylake_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), + SOC_DAPM_PIN_SWITCH("DMIC"), +}; + +static const struct snd_soc_dapm_widget kabylake_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), + SND_SOC_DAPM_MIC("DMIC", NULL), + SND_SOC_DAPM_SPK("DP", NULL), + SND_SOC_DAPM_SPK("HDMI", NULL), + +}; + +static const struct snd_soc_dapm_route kabylake_map[] = { + /* Headphones */ + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + + /* speaker */ + { "Left Spk", NULL, "Left BE_OUT" }, + { "Right Spk", NULL, "Right BE_OUT" }, + + /* other jacks */ + { "IN1P", NULL, "Headset Mic" }, + { "IN1N", NULL, "Headset Mic" }, + + { "HDMI", NULL, "hif5 Output" }, + { "DP", NULL, "hif6 Output" }, + + /* CODEC BE connections */ + { "Left HiFi Playback", NULL, "ssp0 Tx" }, + { "Right HiFi Playback", NULL, "ssp0 Tx" }, + { "ssp0 Tx", NULL, "codec0_out" }, + + { "AIF Playback", NULL, "ssp1 Tx" }, + { "ssp1 Tx", NULL, "codec1_out" }, + + { "codec0_in", NULL, "ssp1 Rx" }, + { "ssp1 Rx", NULL, "AIF Capture" }, + + { "codec1_in", NULL, "ssp0 Rx" }, + { "ssp0 Rx", NULL, "AIF1 Capture" }, + + /* DMIC */ + { "DMIC1L", NULL, "DMIC" }, + { "DMIC1R", NULL, "DMIC" }, + { "DMIC2L", NULL, "DMIC" }, + { "DMIC2R", NULL, "DMIC" }, + + { "hifi2", NULL, "iDisp2 Tx" }, + { "iDisp2 Tx", NULL, "iDisp2_out" }, + { "hifi1", NULL, "iDisp1 Tx" }, + { "iDisp1 Tx", NULL, "iDisp1_out" }, +}; + +static struct snd_soc_codec_conf max98927_codec_conf[] = { + { + .dev_name = MAXIM_DEV0_NAME, + .name_prefix = "Right", + }, + { + .dev_name = MAXIM_DEV1_NAME, + .name_prefix = "Left", + }, +}; + +static struct snd_soc_dai_link_component ssp0_codec_components[] = { + { /* Left */ + .name = MAXIM_DEV0_NAME, + .dai_name = KBL_MAXIM_CODEC_DAI, + }, + { /* Right */ + .name = MAXIM_DEV1_NAME, + .dai_name = KBL_MAXIM_CODEC_DAI, + }, + { /*dmic */ + .name = RT5514_DEV_NAME, + .dai_name = KBL_REALTEK_DMIC_CODEC_DAI, + }, +}; + +static int kabylake_rt5663_fe_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dapm_context *dapm; + struct snd_soc_component *component = rtd->cpu_dai->component; + int ret; + + dapm = snd_soc_component_get_dapm(component); + ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); + if (ret) + dev_err(rtd->dev, "Ref Cap -Ignore suspend failed = %d\n", ret); + + return ret; +} + +static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_codec *codec = rtd->codec; + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new(&kabylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, &ctx->kabylake_headset, + NULL, 0); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); + return ret; + } + + rt5663_set_jack_detect(codec, &ctx->kabylake_headset); + + ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "DMIC"); + if (ret) + dev_err(rtd->dev, "DMIC - Ignore suspend failed = %d\n", ret); + + return ret; +} + +static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) +{ + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct kbl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = device; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); +} + +static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); +} + +static const unsigned int rates[] = { + 48000, +}; + +static const struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, +}; + +static const unsigned int channels[] = { + 2, +}; + +static const struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, +}; + +static int kbl_fe_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + /* + * On this platform for PCM device we support, + * 48Khz + * stereo + * 16 bit audio + */ + + runtime->hw.channels_max = 2; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); + + return 0; +} + +static const struct snd_soc_ops kabylake_rt5663_fe_ops = { + .startup = kbl_fe_startup, +}; + +static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + 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); + 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; + + /* + * 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 Capture Port")) { + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + snd_mask_none(fmt); + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + } else if (!strcmp(fe_dai_link->name, "Kbl Audio DMIC cap")) { + if (params_channels(params) == 2 || + DMIC_CH(dmic_constraints) == 2) + channels->min = channels->max = 2; + else + channels->min = channels->max = 4; + } + /* + * 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")) + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S16_LE); + + return 0; +} + +static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */ + rt5663_sel_asrc_clk_src(codec_dai->codec, RT5663_DA_STEREO_FILTER, 1); + + ret = snd_soc_dai_set_sysclk(codec_dai, + RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + + return ret; +} + +static struct snd_soc_ops kabylake_rt5663_ops = { + .hw_params = kabylake_rt5663_hw_params, +}; + +static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int ret = 0, j; + + for (j = 0; j < rtd->num_codecs; j++) { + struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; + + if (!strcmp(codec_dai->component->name, RT5514_DEV_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0, 8, 16); + if (ret < 0) { + dev_err(rtd->dev, "set TDM slot err:%d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_pll(codec_dai, 0, + RT5514_PLL1_S_BCLK, RT5514_AIF1_BCLK_FREQ, + RT5514_AIF1_SYSCLK_FREQ); + if (ret < 0) { + dev_err(rtd->dev, "set bclk err: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, + RT5514_SCLK_S_PLL1, RT5514_AIF1_SYSCLK_FREQ, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(rtd->dev, "set sclk err: %d\n", ret); + return ret; + } + } + if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME) || + !strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF0, 3, 8, 16); + if (ret < 0) { + dev_err(rtd->dev, "set TDM slot err:%d\n", ret); + return ret; + } + } + } + return ret; +} + +static struct snd_soc_ops kabylake_ssp0_ops = { + .hw_params = kabylake_ssp0_hw_params, +}; + +static const unsigned int channels_dmic[] = { + 4, +}; + +static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { + .count = ARRAY_SIZE(channels_dmic), + .list = channels_dmic, + .mask = 0, +}; + +static const unsigned int dmic_2ch[] = { + 4, +}; + +static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { + .count = ARRAY_SIZE(dmic_2ch), + .list = dmic_2ch, + .mask = 0, +}; + +static int kabylake_dmic_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_max = DMIC_CH(dmic_constraints); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + dmic_constraints); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); +} + +static struct snd_soc_ops kabylake_dmic_ops = { + .startup = kabylake_dmic_startup, +}; + +/* kabylake digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link kabylake_dais[] = { + /* Front End DAI links */ + [KBL_DPCM_AUDIO_PB] = { + .name = "Kbl Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .init = kabylake_rt5663_fe_init, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .ops = &kabylake_rt5663_fe_ops, + }, + [KBL_DPCM_AUDIO_CP] = { + .name = "Kbl Audio Capture Port", + .stream_name = "Audio Record", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_capture = 1, + .ops = &kabylake_rt5663_fe_ops, + }, + [KBL_DPCM_AUDIO_DMIC_CP] = { + .name = "Kbl Audio DMIC cap", + .stream_name = "dmiccap", + .cpu_dai_name = "DMIC Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &kabylake_dmic_ops, + }, + [KBL_DPCM_AUDIO_HDMI1_PB] = { + .name = "Kbl HDMI Port1", + .stream_name = "Hdmi1", + .cpu_dai_name = "HDMI1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI2_PB] = { + .name = "Kbl HDMI Port2", + .stream_name = "Hdmi2", + .cpu_dai_name = "HDMI2 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + /* Back End DAI links */ + /* single Back end dai for both max speakers and dmic */ + { + /* SSP0 - Codec */ + .name = "SSP0-Codec", + .id = 0, + .cpu_dai_name = "SSP0 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codecs = ssp0_codec_components, + .num_codecs = ARRAY_SIZE(ssp0_codec_components), + .dai_fmt = SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp_fixup, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ops = &kabylake_ssp0_ops, + }, + { + .name = "SSP1-Codec", + .id = 1, + .cpu_dai_name = "SSP1 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codec_name = RT5663_DEV_NAME, + .codec_dai_name = KBL_REALTEK_CODEC_DAI, + .init = kabylake_rt5663_codec_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp_fixup, + .ops = &kabylake_rt5663_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + { + .name = "iDisp1", + .id = 3, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = kabylake_hdmi1_init, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .id = 4, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi2_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + +static int kabylake_card_late_probe(struct snd_soc_card *card) +{ + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); + struct kbl_hdmi_pcm *pcm; + int err, i = 0; + char jack_name[NAME_SIZE]; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &ctx->kabylake_hdmi[i], + NULL, 0); + + if (err) + return err; + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &ctx->kabylake_hdmi[i]); + if (err < 0) + return err; + i++; + } + + return 0; +} + +/* + * kabylake audio machine driver for MAX98927 + RT5514 + RT5663 + */ +static struct snd_soc_card kabylake_audio_card = { + .name = "kbl_r5514_5663_max", + .owner = THIS_MODULE, + .dai_link = kabylake_dais, + .num_links = ARRAY_SIZE(kabylake_dais), + .controls = kabylake_controls, + .num_controls = ARRAY_SIZE(kabylake_controls), + .dapm_widgets = kabylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), + .dapm_routes = kabylake_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_map), + .codec_conf = max98927_codec_conf, + .num_configs = ARRAY_SIZE(max98927_codec_conf), + .fully_routed = true, + .late_probe = kabylake_card_late_probe, +}; + +static int kabylake_audio_probe(struct platform_device *pdev) +{ + struct kbl_codec_private *ctx; + struct skl_machine_pdata *pdata; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + kabylake_audio_card.dev = &pdev->dev; + snd_soc_card_set_drvdata(&kabylake_audio_card, ctx); + + pdata = dev_get_drvdata(&pdev->dev); + if (pdata) + dmic_constraints = pdata->dmic_num == 2 ? + &constraints_dmic_2ch : &constraints_dmic_channels; + + return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card); +} + +static const struct platform_device_id kbl_board_ids[] = { + { .name = "kbl_r5514_5663_max" }, + { } +}; + +static struct platform_driver kabylake_audio = { + .probe = kabylake_audio_probe, + .driver = { + .name = "kbl_r5514_5663_max", + .pm = &snd_soc_pm_ops, + }, + .id_table = kbl_board_ids, +}; + +module_platform_driver(kabylake_audio) + +/* Module information */ +MODULE_DESCRIPTION("Audio Machine driver-RT5663 RT5514 & MAX98927"); +MODULE_AUTHOR("Harsha Priya "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:kbl_r5514_5663_max"); From 9a90c972b6e5814a5f928f8d5a3d145fa50988b0 Mon Sep 17 00:00:00 2001 From: Harsha Priya N Date: Wed, 14 Jun 2017 10:32:18 -0700 Subject: [PATCH 296/418] ASoC: Intel: Convert all sst_codecs data definition to c99 style C99 style struct initialization helps in readability as well as initialization of variables not specified as NULL. This patch changes the struct data definitions in skl.c that were not in c99 style. Signed-off-by: Harsha Priya Signed-off-by: Naveen M Acked-By: Vinod Koul --- sound/soc/intel/skylake/skl.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 4ebae850c559..6a79fc759fb4 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -876,10 +876,25 @@ static void skl_remove(struct pci_dev *pci) dev_set_drvdata(&pci->dev, NULL); } -static struct sst_codecs skl_codecs = { 1, {"NAU88L25"} }; -static struct sst_codecs kbl_codecs = { 1, {"NAU88L25"} }; -static struct sst_codecs bxt_codecs = { 1, {"MX98357A"} }; -static struct sst_codecs kbl_poppy_codecs = { 1, {"10EC5663"} }; +static struct sst_codecs skl_codecs = { + .num_codecs = 1, + .codecs = {"NAU88L25"} +}; + +static struct sst_codecs kbl_codecs = { + .num_codecs = 1, + .codecs = {"NAU88L25"} +}; + +static struct sst_codecs bxt_codecs = { + .num_codecs = 1, + .codecs = {"MX98357A"} +}; + +static struct sst_codecs kbl_poppy_codecs = { + .num_codecs = 1, + .codecs = {"10EC5663"} +}; static struct sst_acpi_mach sst_skl_devdata[] = { { From ad7fb5a3b89a7a11d3306948c6954de7a999be40 Mon Sep 17 00:00:00 2001 From: Harsha Priya N Date: Wed, 14 Jun 2017 10:32:19 -0700 Subject: [PATCH 297/418] ASoC: Intel: Add Kabylake RT5663+RT5514+MAX98927 machine driver entry This patch adds Kabylake I2S machine driver which uses codecs MAX98927 as speakers and RT5514 as dmic on ssp0 and RT5663 as headset on ssp1. Signed-off-by: Harsha Priya Signed-off-by: Naveen M Acked-By: Vinod Koul --- sound/soc/intel/skylake/skl.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 6a79fc759fb4..e761550c6dad 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -896,6 +896,12 @@ static struct sst_codecs kbl_poppy_codecs = { .codecs = {"10EC5663"} }; +static struct sst_codecs kbl_5663_5514_codecs = { + .num_codecs = 2, + .codecs = {"10EC5663", "10EC5514"} +}; + + static struct sst_acpi_mach sst_skl_devdata[] = { { .id = "INT343A", @@ -958,6 +964,14 @@ static struct sst_acpi_mach sst_kbl_devdata[] = { .quirk_data = &kbl_codecs, .pdata = &skl_dmic_data }, + { + .id = "MX98927", + .drv_name = "kbl_r5514_5663_max", + .fw_filename = "intel/dsp_fw_kbl.bin", + .machine_quirk = sst_acpi_codec_list, + .quirk_data = &kbl_5663_5514_codecs, + .pdata = &skl_dmic_data + }, { .id = "MX98927", .drv_name = "kbl_rt5663_m98927", From c3a3d3c41b74b05267bab6173f2a8224a1443ba6 Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Thu, 15 Jun 2017 07:53:11 +0200 Subject: [PATCH 298/418] ASoC: rockchip: Fix an error handling in 'rockchip_i2s_probe' If this memory allocation fail, we must disable what has been enabled. Do not return immediately but go thrue the error handling path instead. Also use 'devm_kmemdup' instead of 'devm_kzalloc+memcpy' to simplify code. Signed-off-by: Christophe JAILLET Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 66a26c56c658..ce09dee2202e 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -641,12 +641,13 @@ static int rockchip_i2s_probe(struct platform_device *pdev) goto err_pm_disable; } - soc_dai = devm_kzalloc(&pdev->dev, + soc_dai = devm_kmemdup(&pdev->dev, &rockchip_i2s_dai sizeof(*soc_dai), GFP_KERNEL); - if (!soc_dai) - return -ENOMEM; + if (!soc_dai) { + err = -ENOMEM; + goto err_pm_disable; + } - memcpy(soc_dai, &rockchip_i2s_dai, sizeof(*soc_dai)); if (!of_property_read_u32(node, "rockchip,playback-channels", &val)) { if (val >= 2 && val <= 8) soc_dai->playback.channels_max = val; From 13bb1cc0ad205b2aeeb8d2ea5c790a396135283d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 15 Jun 2017 00:24:09 +0000 Subject: [PATCH 299/418] ASoC: simple-card-utils: add asoc_simple_card_convert_fixup() Current simple/audio scu card drivers are supporting same convert-rate/convert-channels on DT, but doesn't use same function for it. Encapsulation is one of simple card util's purpose. Let's add asoc_simple_card_parse_convert/asoc_simple_card_convert_fixup Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 10 +++++++ sound/soc/generic/simple-card-utils.c | 40 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 2679312228b3..cc318ccd6a2d 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -22,6 +22,11 @@ struct asoc_simple_dai { struct clk *clk; }; +struct asoc_simple_card_data { + u32 convert_rate; + u32 convert_channels; +}; + int asoc_simple_card_parse_daifmt(struct device *dev, struct device_node *node, struct device_node *codec, @@ -90,4 +95,9 @@ void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link, int asoc_simple_card_clean_reference(struct snd_soc_card *card); +void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data, + struct snd_pcm_hw_params *params); +void asoc_simple_card_parse_convert(struct device *dev, char *prefix, + struct asoc_simple_card_data *data); + #endif /* __SIMPLE_CARD_UTILS_H */ diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 2ad7633292bf..948a18842e64 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -13,6 +13,46 @@ #include #include +void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data, + struct snd_pcm_hw_params *params) +{ + 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); + + if (data->convert_rate) + rate->min = + rate->max = data->convert_rate; + + if (data->convert_channels) + channels->min = + channels->max = data->convert_channels; +} +EXPORT_SYMBOL_GPL(asoc_simple_card_convert_fixup); + +void asoc_simple_card_parse_convert(struct device *dev, char *prefix, + struct asoc_simple_card_data *data) +{ + struct device_node *np = dev->of_node; + char prop[128]; + + if (!prefix) + prefix = ""; + + /* sampling rate convert */ + snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-rate"); + of_property_read_u32(np, prop, &data->convert_rate); + + /* channels transfer */ + snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-channels"); + of_property_read_u32(np, prop, &data->convert_channels); + + dev_dbg(dev, "convert_rate %d\n", data->convert_rate); + dev_dbg(dev, "convert_channels %d\n", data->convert_channels); +} +EXPORT_SYMBOL_GPL(asoc_simple_card_parse_convert); + int asoc_simple_card_parse_daifmt(struct device *dev, struct device_node *node, struct device_node *codec, From cd8957f588397498c12b258da9044b52598c9527 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 15 Jun 2017 00:24:28 +0000 Subject: [PATCH 300/418] ASoC: simple-scu-card: use asoc_simple_card_convert_fixup() Current simple/audio scu card drivers are supporting same convert-rate/convert-channels on DT, but, doesn't use same function for it. Encapsulation is one of simple card util's purpose. Let's use asoc_simple_card_parse_convert/asoc_simple_card_convert_fixup Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-scu-card.c | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index 938f3f30eef1..44da69101097 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -27,8 +27,7 @@ struct simple_card_data { struct snd_soc_codec_conf codec_conf; struct asoc_simple_dai *dai_props; struct snd_soc_dai_link *dai_link; - u32 convert_rate; - u32 convert_channels; + struct asoc_simple_card_data adata; }; #define simple_priv_to_card(priv) (&(priv)->snd_card) @@ -86,18 +85,8 @@ static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { struct simple_card_data *priv = 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); - if (priv->convert_rate) - rate->min = - rate->max = priv->convert_rate; - - if (priv->convert_channels) - channels->min = - channels->max = priv->convert_channels; + asoc_simple_card_convert_fixup(&priv->adata, params); return 0; } @@ -206,11 +195,7 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) if (ret < 0) return ret; - /* sampling rate convert */ - of_property_read_u32(node, PREFIX "convert-rate", &priv->convert_rate); - - /* channels transfer */ - of_property_read_u32(node, PREFIX "convert-channels", &priv->convert_channels); + asoc_simple_card_parse_convert(dev, PREFIX, &priv->adata); /* find 1st codec */ np = of_get_child_by_name(node, PREFIX "codec"); @@ -237,9 +222,6 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) if (ret < 0) return ret; - dev_dbg(dev, "convert_rate %d\n", priv->convert_rate); - dev_dbg(dev, "convert_channels %d\n", priv->convert_channels); - return 0; } From c564a5b18710f76da222ad9f14a4c0ebc2c4c74c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 15 Jun 2017 00:24:43 +0000 Subject: [PATCH 301/418] ASoC: audio-graph-scu-card: use asoc_simple_card_convert_fixup() Current simple/audio scu card drivers are supporting same convert-rate/convert-channels on DT, but, doesn't use same function for it. Encapsulation is one of simple card util's purpose. Let's use asoc_simple_card_parse_convert/asoc_simple_card_convert_fixup Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-scu-card.c | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c index 4d295d07858a..9502f6ed14b8 100644 --- a/sound/soc/generic/audio-graph-scu-card.c +++ b/sound/soc/generic/audio-graph-scu-card.c @@ -30,8 +30,7 @@ struct graph_card_data { struct snd_soc_codec_conf codec_conf; struct asoc_simple_dai *dai_props; struct snd_soc_dai_link *dai_link; - u32 convert_rate; - u32 convert_channels; + struct asoc_simple_card_data adata; }; #define graph_priv_to_card(priv) (&(priv)->snd_card) @@ -83,18 +82,8 @@ static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { struct graph_card_data *priv = 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); - if (priv->convert_rate) - rate->min = - rate->max = priv->convert_rate; - - if (priv->convert_channels) - channels->min = - channels->max = priv->convert_channels; + asoc_simple_card_convert_fixup(&priv->adata, params); return 0; } @@ -210,11 +199,7 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) if (ret) return ret; - /* sampling rate convert */ - of_property_read_u32(node, "convert-rate", &priv->convert_rate); - - /* channels transfer */ - of_property_read_u32(node, "convert-channels", &priv->convert_channels); + asoc_simple_card_parse_convert(dev, NULL, &priv->adata); /* * it supports multi CPU, single CODEC only here @@ -286,9 +271,6 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) if (ret) goto parse_of_err; - dev_dbg(dev, "convert_rate %d\n", priv->convert_rate); - dev_dbg(dev, "convert_channels %d\n", priv->convert_channels); - ret = 0; parse_of_err: From 3296d07826ebc698113832acb426f037e9b3b253 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 15 Jun 2017 00:25:02 +0000 Subject: [PATCH 302/418] ASoC: simple-card-utils: add asoc_simple_card_of_parse_routing() Current simple card drivers are parsing routing on each own driver. Encapsulation is one of simple card util's purpose. Let's add asoc_simple_card_of_parse_routing for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 4 ++++ sound/soc/generic/simple-card-utils.c | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index cc318ccd6a2d..889c8ff86369 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -100,4 +100,8 @@ void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data, void asoc_simple_card_parse_convert(struct device *dev, char *prefix, struct asoc_simple_card_data *data); +int asoc_simple_card_of_parse_routing(struct snd_soc_card *card, + char *prefix, + int optional); + #endif /* __SIMPLE_CARD_UTILS_H */ diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 948a18842e64..a2b6d95bc2f9 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -375,6 +375,28 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card) } EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference); +int asoc_simple_card_of_parse_routing(struct snd_soc_card *card, + char *prefix, + int optional) +{ + struct device_node *node = card->dev->of_node; + char prop[128]; + + if (!prefix) + prefix = ""; + + snprintf(prop, sizeof(prop), "%s%s", prefix, "routing"); + + if (!of_property_read_bool(node, prop)) { + if (optional) + return 0; + return -EINVAL; + } + + return snd_soc_of_parse_audio_routing(card, prop); +} +EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_routing); + /* Module information */ MODULE_AUTHOR("Kuninori Morimoto "); MODULE_DESCRIPTION("ALSA SoC Simple Card Utils"); From 1fdb5d258e28de85263a34aab57f0a70b1715342 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 15 Jun 2017 00:25:17 +0000 Subject: [PATCH 303/418] ASoC: simple-card: use asoc_simple_card_of_parse_routing() Current simple/audio scu card drivers are supporting same routing on DT, but, doesn't use same function for it. Encapsulation is one of simple card util's purpose. Let's use asoc_simple_card_of_parse_routing Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 8b414af966ee..7b2533c7f82e 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -362,13 +362,9 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) goto card_parse_end; } - /* DAPM routes */ - if (of_property_read_bool(node, PREFIX "routing")) { - ret = snd_soc_of_parse_audio_routing(card, - PREFIX "routing"); - if (ret) - goto card_parse_end; - } + ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1); + if (ret < 0) + goto card_parse_end; /* Factor to mclk, used in hw_params() */ of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs); From bfe6b5898269b92571e502b4d706c815dd6bf53b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 15 Jun 2017 00:25:33 +0000 Subject: [PATCH 304/418] ASoC: simple-scu-card: use asoc_simple_card_of_parse_routing() Current simple/audio scu card drivers are supporting same routing on DT, but, doesn't use same function for it. Encapsulation is one of simple card util's purpose. Let's use asoc_simple_card_of_parse_routing Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-scu-card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index 44da69101097..a75b385455c4 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -191,7 +191,7 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) if (!node) return -EINVAL; - ret = snd_soc_of_parse_audio_routing(card, PREFIX "routing"); + ret = asoc_simple_card_of_parse_routing(card, PREFIX, 0); if (ret < 0) return ret; From 9fb9b2f236f05168a6138e62c82124a2f5eaf320 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 15 Jun 2017 00:25:51 +0000 Subject: [PATCH 305/418] ASoC: audio-graph-scu-card: use asoc_simple_card_of_parse_routing() Current simple/audio scu card drivers are supporting same routing on DT, but, doesn't use same function for it. Encapsulation is one of simple card util's purpose. Let's use asoc_simple_card_of_parse_routing Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-scu-card.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c index 9502f6ed14b8..05934b24627b 100644 --- a/sound/soc/generic/audio-graph-scu-card.c +++ b/sound/soc/generic/audio-graph-scu-card.c @@ -195,8 +195,8 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) * see simple-card */ - ret = snd_soc_of_parse_audio_routing(card, "routing"); - if (ret) + ret = asoc_simple_card_of_parse_routing(card, NULL, 0); + if (ret < 0) return ret; asoc_simple_card_parse_convert(dev, NULL, &priv->adata); From 1ff9593d2f27a48fbeeccd7fc253eed2a7102d16 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 15 Jun 2017 00:49:27 +0000 Subject: [PATCH 306/418] ASoC: rsnd: rename "slots" related variable Current Renesas sound driver has slots and slots_num in struct rsnd_dai, but these are very un-understandable naming (It had named from TDM slots). In this driver, the "slots" means total usable channels, and "stot_num" means SSI lane number if Multi SSI was used. To more understandable code, this patch renames "slots" to "max_channels", and "slots_num" to "ssi_lane", and replaces related functions name. Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 53 ++++++++++++++++++++-------------------- sound/soc/sh/rcar/dvc.c | 7 +++--- sound/soc/sh/rcar/rsnd.h | 23 +++++++++++------ sound/soc/sh/rcar/ssi.c | 3 ++- 4 files changed, 49 insertions(+), 37 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 1b536d140e49..9b9e898d0df3 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -203,27 +203,6 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io) return !!io->substream; } -void rsnd_set_slot(struct rsnd_dai *rdai, - int slots, int num) -{ - rdai->slots = slots; - rdai->slots_num = num; -} - -int rsnd_get_slot(struct rsnd_dai_stream *io) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - - return rdai->slots; -} - -int rsnd_get_slot_num(struct rsnd_dai_stream *io) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - - return rdai->slots_num; -} - int rsnd_runtime_channel_original(struct rsnd_dai_stream *io) { struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); @@ -248,13 +227,14 @@ int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io) int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io) { + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); int chan = rsnd_io_is_play(io) ? rsnd_runtime_channel_after_ctu(io) : rsnd_runtime_channel_original(io); /* Use Multi SSI */ if (rsnd_runtime_is_ssi_multi(io)) - chan /= rsnd_get_slot_num(io); + chan /= rsnd_rdai_ssi_lane_get(rdai); /* TDM Extend Mode needs 8ch */ if (chan == 6) @@ -265,12 +245,13 @@ int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io) int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io) { - int slots = rsnd_get_slot_num(io); + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + int lane = rsnd_rdai_ssi_lane_get(rdai); int chan = rsnd_io_is_play(io) ? rsnd_runtime_channel_after_ctu(io) : rsnd_runtime_channel_original(io); - return (chan >= 6) && (slots > 1); + return (chan > 2) && (lane > 1); } int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io) @@ -549,6 +530,24 @@ static void rsnd_dai_disconnect(struct rsnd_mod *mod, io->mod[type] = NULL; } +int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai, + int max_channels) +{ + if (max_channels > 0) + rdai->max_channels = max_channels; + + return rdai->max_channels; +} + +int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, + int ssi_lane) +{ + if (ssi_lane > 0) + rdai->ssi_lane = ssi_lane; + + return rdai->ssi_lane; +} + struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id) { if ((id < 0) || (id >= rsnd_rdai_nr(priv))) @@ -726,7 +725,8 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, switch (slots) { case 6: /* TDM Extend Mode */ - rsnd_set_slot(rdai, slots, 1); + rsnd_rdai_channels_set(rdai, slots); + rsnd_rdai_ssi_lane_set(rdai, 1); break; default: dev_err(dev, "unsupported TDM slots (%d)\n", slots); @@ -879,7 +879,8 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, rdai->playback.rdai = rdai; rdai->capture.rdai = rdai; - rsnd_set_slot(rdai, 2, 1); /* default */ + rsnd_rdai_channels_set(rdai, 2); /* default 2ch */ + rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */ for (io_i = 0;; io_i++) { playback = of_parse_phandle(dai_np, "playback", io_i); diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 75af6e742328..99d2d9459e75 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -249,8 +249,9 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, struct snd_soc_pcm_runtime *rtd) { struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); int is_play = rsnd_io_is_play(io); - int slots = rsnd_get_slot(io); + int channels = rsnd_rdai_channels_get(rdai); int ret; /* Volume */ @@ -259,7 +260,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, "DVC Out Playback Volume" : "DVC In Capture Volume", rsnd_kctrl_accept_anytime, rsnd_dvc_volume_update, - &dvc->volume, slots, + &dvc->volume, channels, 0x00800000 - 1); if (ret < 0) return ret; @@ -270,7 +271,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, "DVC Out Mute Switch" : "DVC In Mute Switch", rsnd_kctrl_accept_anytime, rsnd_dvc_volume_update, - &dvc->mute, slots, + &dvc->mute, channels, 1); if (ret < 0) return ret; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index ac4d50d118d1..47162bdf1abc 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -399,11 +399,6 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, struct device_node *playback, struct device_node *capture); -void rsnd_set_slot(struct rsnd_dai *rdai, - int slots, int slots_total); -int rsnd_get_slot(struct rsnd_dai_stream *io); -int rsnd_get_slot_num(struct rsnd_dai_stream *io); - int rsnd_runtime_channel_original(struct rsnd_dai_stream *io); int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io); int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io); @@ -455,8 +450,8 @@ struct rsnd_dai { struct rsnd_dai_stream capture; struct rsnd_priv *priv; - int slots; - int slots_num; + int max_channels; /* 2ch - 16ch */ + int ssi_lane; /* 1lane - 4lane */ unsigned int clk_master:1; unsigned int bit_clk_inv:1; @@ -476,6 +471,20 @@ struct rsnd_dai { struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id); +#define rsnd_rdai_channels_set(rdai, max_channels) \ + rsnd_rdai_channels_ctrl(rdai, max_channels) +#define rsnd_rdai_channels_get(rdai) \ + rsnd_rdai_channels_ctrl(rdai, 0) +int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai, + int max_channels); + +#define rsnd_rdai_ssi_lane_set(rdai, ssi_lane) \ + rsnd_rdai_ssi_lane_ctrl(rdai, ssi_lane) +#define rsnd_rdai_ssi_lane_get(rdai) \ + rsnd_rdai_ssi_lane_ctrl(rdai, 0) +int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, + int ssi_lane); + void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io); int rsnd_dai_connect(struct rsnd_mod *mod, struct rsnd_dai_stream *io, diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index f7df3b5e2985..6450095eb547 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -897,7 +897,8 @@ static void rsnd_ssi_connect(struct rsnd_mod *mod, type = types[i]; if (!rsnd_io_to_mod(io, type)) { rsnd_dai_connect(mod, io, type); - rsnd_set_slot(rdai, 2 * (i + 1), (i + 1)); + rsnd_rdai_channels_set(rdai, (i + 1) * 2); + rsnd_rdai_ssi_lane_set(rdai, (i + 1)); return; } } From 1dfdc6501a4a140cfbfc6be8dbb1da3a6f726c15 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 15 Jun 2017 00:49:43 +0000 Subject: [PATCH 307/418] ASoC: rsnd: add rsnd_adg_clk_query() Current Renesas sound driver is assuming that all Sampling rate and channles are possible to use, but these are depends on inputed clock and SSI connection situation. For example, if it is using 1 SSI, enabled TDM mode and has 12288000 input clock, 2ch output can support until 192000Hz, but 6ch output can support until 64000Hz, 8ch can support 48000Hz. To control these situation correctly, it needs to support hw_constraints / refine feature. To support such feature, it needs SSI clock query feature, and it needs ADG clock query feature. Current ADG has rsnd_adg_ssi_clk_try_start() and it is doing similar things, but it try to setup ADG register in same time. This is not needed. This patch adds new rsnd_adg_clk_query() and separates query feature and register setting feature in adg.c Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 53 ++++++++++++++++++++-------------------- sound/soc/sh/rcar/rsnd.h | 1 + 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 4a72fd74ddc2..197cb3ec075f 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -308,23 +308,12 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) } } -int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod) +int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate) { - rsnd_adg_set_ssi_clk(ssi_mod, 0); - - return 0; -} - -int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_mod *adg_mod = rsnd_mod_get(adg); struct clk *clk; int i; - u32 data; - u32 ckr = 0; int sel_table[] = { [CLKA] = 0x1, [CLKB] = 0x2, @@ -338,30 +327,42 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) * find suitable clock from * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI. */ - data = 0; for_each_rsnd_clk(clk, adg, i) { - if (rate == clk_get_rate(clk)) { - data = sel_table[i]; - goto found_clock; - } + if (rate == clk_get_rate(clk)) + return sel_table[i]; } /* * find divided clock from BRGA/BRGB */ - if (rate == adg->rbga_rate_for_441khz) { - data = 0x10; - goto found_clock; - } + if (rate == adg->rbga_rate_for_441khz) + return 0x10; - if (rate == adg->rbgb_rate_for_48khz) { - data = 0x20; - goto found_clock; - } + if (rate == adg->rbgb_rate_for_48khz) + return 0x20; return -EIO; +} -found_clock: +int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod) +{ + rsnd_adg_set_ssi_clk(ssi_mod, 0); + + return 0; +} + +int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); + struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_mod *adg_mod = rsnd_mod_get(adg); + int data; + u32 ckr = 0; + + data = rsnd_adg_clk_query(priv, rate); + if (data < 0) + return data; rsnd_adg_set_ssi_clk(ssi_mod, data); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 47162bdf1abc..7b76f3998fd7 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -502,6 +502,7 @@ 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_probe(struct rsnd_priv *priv); From ef4cf5d6a143e04e149ad81fc491fe10855544fe Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 15 Jun 2017 00:50:02 +0000 Subject: [PATCH 308/418] ASoC: rsnd: add rsnd_ssi_clk_query() Current Renesas sound driver is assuming that all Sampling rate and channles are possible to use, but these are depends on inputed clock and SSI connection situation. For example, if it is using 1 SSI, enabled TDM mode and has 12288000 input clock, 2ch output can support until 192000Hz, but 6ch output can support until 64000Hz, 8ch can support 48000Hz. To control these situation correctly, it needs to support hw_constraints / refine feature. To support such feature, this patch adds new rsnd_ssi_clk_query(). Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsnd.h | 2 + sound/soc/sh/rcar/ssi.c | 99 +++++++++++++++++++++++----------------- 2 files changed, 60 insertions(+), 41 deletions(-) diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 7b76f3998fd7..3aa07a07bbcb 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -679,6 +679,8 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, struct device_node *playback, struct device_node *capture); +int rsnd_ssi_clk_query(struct rsnd_priv *priv, + int param1, int param2, int *idx); /* * R-Car SSIU diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 6450095eb547..c8956c3484dd 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -208,6 +208,46 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io) return 0; } +int rsnd_ssi_clk_query(struct rsnd_priv *priv, + int param1, int param2, int *idx) +{ + int ssi_clk_mul_table[] = { + 1, 2, 4, 8, 16, 6, 12, + }; + int j, ret; + int main_rate; + + for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) { + + /* + * It will set SSIWSR.CONT here, but SSICR.CKDV = 000 + * with it is not allowed. (SSIWSR.WS_MODE with + * SSICR.CKDV = 000 is not allowed either). + * Skip it. See SSICR.CKDV + */ + if (j == 0) + continue; + + /* + * this driver is assuming that + * system word is 32bit x chan + * see rsnd_ssi_init() + */ + main_rate = 32 * param1 * param2 * ssi_clk_mul_table[j]; + + ret = rsnd_adg_clk_query(priv, main_rate); + if (ret < 0) + continue; + + if (idx) + *idx = j; + + return main_rate; + } + + return -EINVAL; +} + static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { @@ -217,10 +257,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); int chan = rsnd_runtime_channel_for_ssi(io); - int j, ret; - int ssi_clk_mul_table[] = { - 1, 2, 4, 8, 16, 6, 12, - }; + int idx, ret; unsigned int main_rate; unsigned int rate = rsnd_io_is_play(io) ? rsnd_src_get_out_rate(priv, io) : @@ -244,45 +281,25 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, return 0; } - /* - * Find best clock, and try to start ADG - */ - for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) { - - /* - * It will set SSIWSR.CONT here, but SSICR.CKDV = 000 - * with it is not allowed. (SSIWSR.WS_MODE with - * SSICR.CKDV = 000 is not allowed either). - * Skip it. See SSICR.CKDV - */ - if (j == 0) - continue; - - /* - * this driver is assuming that - * system word is 32bit x chan - * see rsnd_ssi_init() - */ - main_rate = rate * 32 * chan * ssi_clk_mul_table[j]; - - ret = rsnd_adg_ssi_clk_try_start(mod, main_rate); - if (0 == ret) { - ssi->cr_clk = FORCE | SWL_32 | - SCKD | SWSD | CKDV(j); - ssi->wsr = CONT; - - ssi->rate = rate; - - dev_dbg(dev, "%s[%d] outputs %u Hz\n", - rsnd_mod_name(mod), - rsnd_mod_id(mod), rate); - - return 0; - } + main_rate = rsnd_ssi_clk_query(priv, rate, chan, &idx); + if (main_rate < 0) { + dev_err(dev, "unsupported clock rate\n"); + return -EIO; } - dev_err(dev, "unsupported clock rate\n"); - return -EIO; + ret = rsnd_adg_ssi_clk_try_start(mod, main_rate); + if (ret < 0) + return ret; + + ssi->cr_clk = FORCE | SWL_32 | SCKD | SWSD | CKDV(idx); + ssi->wsr = CONT; + ssi->rate = rate; + + dev_dbg(dev, "%s[%d] outputs %u Hz\n", + rsnd_mod_name(mod), + rsnd_mod_id(mod), rate); + + return 0; } static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod, From 8cc03722403a5153054993388857e4e565dcdfb1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 15 Jun 2017 00:50:19 +0000 Subject: [PATCH 309/418] ASoC: rsnd: add rsnd_soc_hw_rule/constraint() Current Renesas sound driver is assuming that all Sampling rate and channles are possible to use, but these are depends on inputed clock and SSI connection situation. For example, if it is using 1 SSI, enabled TDM mode and has 12288000 input clock, 2ch output can support until 192000Hz, but 6ch output can support until 64000Hz, 8ch can support 48000Hz. To control these situation correctly, it needs to support hw_constraints / refine feature. To support such feature, this patch adds new rsnd_soc_hw_rule/constraint() which adds hw rule of Channel and Sampling Rate. Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 155 ++++++++++++++++++++++++++++++++++++++- sound/soc/sh/rcar/rsnd.h | 1 + 2 files changed, 154 insertions(+), 2 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 9b9e898d0df3..4892c0a4b613 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -723,7 +723,10 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, struct device *dev = rsnd_priv_to_dev(priv); switch (slots) { + case 2: case 6: + case 8: + case 16: /* TDM Extend Mode */ rsnd_rdai_channels_set(rdai, slots); rsnd_rdai_ssi_lane_set(rdai, 1); @@ -736,6 +739,151 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, return 0; } +static unsigned int rsnd_soc_hw_channels_list[] = { + 2, 6, 8, 16, +}; + +static unsigned int rsnd_soc_hw_rate_list[] = { + 8000, + 11025, + 16000, + 22050, + 32000, + 44100, + 48000, + 64000, + 88200, + 96000, + 176400, + 192000, +}; + +static int rsnd_soc_hw_rule(struct rsnd_priv *priv, + unsigned int *list, int list_num, + struct snd_interval *baseline, struct snd_interval *iv) +{ + struct snd_interval p; + int rate; + int i; + + snd_interval_any(&p); + p.min = UINT_MAX; + p.max = 0; + + for (i = 0; i < list_num; i++) { + + if (!snd_interval_test(iv, list[i])) + continue; + + rate = rsnd_ssi_clk_query(priv, + baseline->min, list[i], NULL); + if (rate > 0) { + p.min = min(p.min, list[i]); + p.max = max(p.max, list[i]); + } + + rate = rsnd_ssi_clk_query(priv, + baseline->max, list[i], NULL); + if (rate > 0) { + p.min = min(p.min, list[i]); + p.max = max(p.max, list[i]); + } + } + + return snd_interval_refine(iv, &p); +} + +static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval ic; + struct snd_soc_dai *dai = rule->private; + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + + /* + * possible sampling rate limitation is same as + * 2ch if it supports multi ssi + */ + ic = *ic_; + if (1 < rsnd_rdai_ssi_lane_get(rdai)) { + ic.min = 2; + ic.max = 2; + } + + return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list, + ARRAY_SIZE(rsnd_soc_hw_rate_list), + &ic, ir); +} + + +static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval ic; + struct snd_soc_dai *dai = rule->private; + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + + /* + * possible sampling rate limitation is same as + * 2ch if it supports multi ssi + */ + ic = *ic_; + if (1 < rsnd_rdai_ssi_lane_get(rdai)) { + ic.min = 2; + ic.max = 2; + } + + return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list, + ARRAY_SIZE(rsnd_soc_hw_channels_list), + ir, &ic); +} + +static void rsnd_soc_hw_constraint(struct snd_pcm_runtime *runtime, + struct snd_soc_dai *dai) +{ + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint; + unsigned int max_channels = rsnd_rdai_channels_get(rdai); + int i; + + /* + * Channel Limitation + * It depends on Platform design + */ + constraint->list = rsnd_soc_hw_channels_list; + constraint->count = 0; + constraint->mask = 0; + + for (i = 0; i < ARRAY_SIZE(rsnd_soc_hw_channels_list); i++) { + if (rsnd_soc_hw_channels_list[i] > max_channels) + break; + constraint->count = i + 1; + } + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, constraint); + + /* + * Sampling Rate / Channel Limitation + * It depends on Clock Master Mode + */ + if (!rsnd_rdai_is_clk_master(rdai)) + return; + + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + rsnd_soc_hw_rule_rate, dai, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + rsnd_soc_hw_rule_channels, dai, + SNDRV_PCM_HW_PARAM_RATE, -1); +} + static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -744,6 +892,9 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); int ret; + /* rsnd_io_to_runtime() is not yet enabled here */ + rsnd_soc_hw_constraint(substream->runtime, dai); + /* * call rsnd_dai_call without spinlock */ @@ -866,7 +1017,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, drv->playback.rates = RSND_RATES; drv->playback.formats = RSND_FMTS; drv->playback.channels_min = 2; - drv->playback.channels_max = 6; + drv->playback.channels_max = 16; drv->playback.stream_name = rdai->playback.name; snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE, @@ -874,7 +1025,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, drv->capture.rates = RSND_RATES; drv->capture.formats = RSND_FMTS; drv->capture.channels_min = 2; - drv->capture.channels_max = 6; + drv->capture.channels_max = 16; drv->capture.stream_name = rdai->capture.name; rdai->playback.rdai = rdai; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 3aa07a07bbcb..9428d4e288dd 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -449,6 +449,7 @@ struct rsnd_dai { struct rsnd_dai_stream playback; struct rsnd_dai_stream capture; struct rsnd_priv *priv; + struct snd_pcm_hw_constraint_list constraint; int max_channels; /* 2ch - 16ch */ int ssi_lane; /* 1lane - 4lane */ From 15b5ef42904bdaf20f0145c3693a7d2f3c10ab44 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 16 Jun 2017 09:17:09 +0200 Subject: [PATCH 310/418] ALSA: hal2: switch to dma_alloc_attrs Use dma_alloc_attrs directly instead of the dma_alloc_noncoherent wrapper. Signed-off-by: Christoph Hellwig Signed-off-by: Takashi Iwai --- sound/mips/hal2.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c index 6505deb8c06b..3318c15e324a 100644 --- a/sound/mips/hal2.c +++ b/sound/mips/hal2.c @@ -461,15 +461,15 @@ static int hal2_alloc_dmabuf(struct hal2_codec *codec) int count = H2_BUF_SIZE / H2_BLOCK_SIZE; int i; - codec->buffer = dma_alloc_noncoherent(NULL, H2_BUF_SIZE, - &buffer_dma, GFP_KERNEL); + codec->buffer = dma_alloc_attrs(NULL, H2_BUF_SIZE, &buffer_dma, + GFP_KERNEL, DMA_ATTR_NON_CONSISTENT); if (!codec->buffer) return -ENOMEM; - desc = dma_alloc_noncoherent(NULL, count * sizeof(struct hal2_desc), - &desc_dma, GFP_KERNEL); + desc = dma_alloc_attrs(NULL, count * sizeof(struct hal2_desc), + &desc_dma, GFP_KERNEL, DMA_ATTR_NON_CONSISTENT); if (!desc) { - dma_free_noncoherent(NULL, H2_BUF_SIZE, - codec->buffer, buffer_dma); + dma_free_attrs(NULL, H2_BUF_SIZE, codec->buffer, buffer_dma, + DMA_ATTR_NON_CONSISTENT); return -ENOMEM; } codec->buffer_dma = buffer_dma; @@ -490,10 +490,10 @@ static int hal2_alloc_dmabuf(struct hal2_codec *codec) static void hal2_free_dmabuf(struct hal2_codec *codec) { - dma_free_noncoherent(NULL, codec->desc_count * sizeof(struct hal2_desc), - codec->desc, codec->desc_dma); - dma_free_noncoherent(NULL, H2_BUF_SIZE, codec->buffer, - codec->buffer_dma); + dma_free_attrs(NULL, codec->desc_count * sizeof(struct hal2_desc), + codec->desc, codec->desc_dma, DMA_ATTR_NON_CONSISTENT); + dma_free_attrs(NULL, H2_BUF_SIZE, codec->buffer, codec->buffer_dma, + DMA_ATTR_NON_CONSISTENT); } static struct snd_pcm_hardware hal2_pcm_hw = { From 4a219ef8f37071ce0993959fe52ffa5034689f42 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Fri, 16 Jun 2017 16:54:35 +0800 Subject: [PATCH 311/418] ALSA: hda/realtek - Add ALC256 HP depop function Add this functions, it could support ALC256 for HP depop functions. It also can solve some ALC256 machine plug headset cause power off issue. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 70 +++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5ef2413511c4..17fe05da0119 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3062,6 +3062,74 @@ static void alc283_shutup(struct hda_codec *codec) alc_write_coef_idx(codec, 0x43, 0x9614); } +static void alc256_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; + bool hp_pin_sense; + + if (!hp_pin) + return; + + msleep(30); + + hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); + + if (hp_pin_sense) + msleep(2); + + alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */ + + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + + if (hp_pin_sense) + msleep(85); + + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + + if (hp_pin_sense) + msleep(100); + + alc_update_coef_idx(codec, 0x46, 3 << 12, 0); + alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */ +} + +static void alc256_shutup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; + bool hp_pin_sense; + + if (!hp_pin) { + alc269_shutup(codec); + return; + } + + hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); + + if (hp_pin_sense) + msleep(2); + + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + + if (hp_pin_sense) + msleep(85); + + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + + alc_update_coef_idx(codec, 0x46, 0, 3 << 12); /* 3k pull low control for Headset jack. */ + + if (hp_pin_sense) + msleep(100); + + alc_auto_setup_eapd(codec, false); + snd_hda_shutup_pins(codec); +} + static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg, unsigned int val) { @@ -6483,6 +6551,8 @@ static int patch_alc269(struct hda_codec *codec) break; case 0x10ec0256: spec->codec_variant = ALC269_TYPE_ALC256; + spec->shutup = alc256_shutup; + spec->init_hook = alc256_init; spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */ alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/ break; From 75bd90860a1f6d4671403f5b7beb9c4430ca9750 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 16 Jun 2017 11:20:29 +0200 Subject: [PATCH 312/418] ASoC: intel: Use kvzalloc() for suspend buffers Intel SST driver allocates lots of pages at suspend for saving the firmware states, and this may occasionally lead to the allocation error due to the high order, ending up with the suspend failure. Use kvzalloc() so that it can fall back to vmalloc() gracefully. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst.c | 22 +++++++++++----------- sound/soc/intel/atom/sst/sst.h | 8 ++++---- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index 5ee92257ca85..8afdff457579 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -464,23 +464,23 @@ static int intel_sst_suspend(struct device *dev) fw_save = kzalloc(sizeof(*fw_save), GFP_KERNEL); if (!fw_save) return -ENOMEM; - fw_save->iram = kzalloc(ctx->iram_end - ctx->iram_base, GFP_KERNEL); + fw_save->iram = kvzalloc(ctx->iram_end - ctx->iram_base, GFP_KERNEL); if (!fw_save->iram) { ret = -ENOMEM; goto iram; } - fw_save->dram = kzalloc(ctx->dram_end - ctx->dram_base, GFP_KERNEL); + fw_save->dram = kvzalloc(ctx->dram_end - ctx->dram_base, GFP_KERNEL); if (!fw_save->dram) { ret = -ENOMEM; goto dram; } - fw_save->sram = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL); + fw_save->sram = kvzalloc(SST_MAILBOX_SIZE, GFP_KERNEL); if (!fw_save->sram) { ret = -ENOMEM; goto sram; } - fw_save->ddr = kzalloc(ctx->ddr_end - ctx->ddr_base, GFP_KERNEL); + fw_save->ddr = kvzalloc(ctx->ddr_end - ctx->ddr_base, GFP_KERNEL); if (!fw_save->ddr) { ret = -ENOMEM; goto ddr; @@ -495,11 +495,11 @@ static int intel_sst_suspend(struct device *dev) ctx->ops->reset(ctx); return 0; ddr: - kfree(fw_save->sram); + kvfree(fw_save->sram); sram: - kfree(fw_save->dram); + kvfree(fw_save->dram); dram: - kfree(fw_save->iram); + kvfree(fw_save->iram); iram: kfree(fw_save); return ret; @@ -527,10 +527,10 @@ static int intel_sst_resume(struct device *dev) memcpy32_toio(ctx->mailbox, fw_save->sram, SST_MAILBOX_SIZE); memcpy32_toio(ctx->ddr, fw_save->ddr, ctx->ddr_end - ctx->ddr_base); - kfree(fw_save->sram); - kfree(fw_save->dram); - kfree(fw_save->iram); - kfree(fw_save->ddr); + kvfree(fw_save->sram); + kvfree(fw_save->dram); + kvfree(fw_save->iram); + kvfree(fw_save->ddr); kfree(fw_save); block = sst_create_block(ctx, 0, FW_DWNL_ID); diff --git a/sound/soc/intel/atom/sst/sst.h b/sound/soc/intel/atom/sst/sst.h index 1693befa455a..e02e2b4cc08f 100644 --- a/sound/soc/intel/atom/sst/sst.h +++ b/sound/soc/intel/atom/sst/sst.h @@ -318,10 +318,10 @@ struct sst_ipc_reg { }; struct sst_fw_save { - void *iram; - void *dram; - void *sram; - void *ddr; + void *iram; /* allocated via kvmalloc() */ + void *dram; /* allocated via kvmalloc() */ + void *sram; /* allocated via kvmalloc() */ + void *ddr; /* allocated via kvmalloc() */ }; /** From 33c0f552c9f3721b1e9452b1c82a37992fa90bfd Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 15 Jun 2017 20:13:33 +0100 Subject: [PATCH 313/418] ASoC: rockchip: Fix build Reported-by: Christophe Jaillet Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index ce09dee2202e..b4a8aff69570 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -641,10 +641,10 @@ static int rockchip_i2s_probe(struct platform_device *pdev) goto err_pm_disable; } - soc_dai = devm_kmemdup(&pdev->dev, &rockchip_i2s_dai + soc_dai = devm_kmemdup(&pdev->dev, &rockchip_i2s_dai, sizeof(*soc_dai), GFP_KERNEL); if (!soc_dai) { - err = -ENOMEM; + ret = -ENOMEM; goto err_pm_disable; } From 602d7d72c8255f80898e94562f777635efd1ddaf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 16 Jun 2017 16:12:30 +0200 Subject: [PATCH 314/418] ALSA: pcm: Follow standard EXPORT_SYMBOL() declarations Just a tidy up to follow the standard EXPORT_SYMBOL*() declarations in order to improve grep-ability. - Remove superfluous blank line before EXPORT_SYMBOL*() lines Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 21 --------------------- sound/core/pcm_memory.c | 6 ------ sound/core/pcm_misc.c | 11 ----------- sound/core/pcm_native.c | 7 ------- 4 files changed, 45 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 631cd598ba6c..461c21f21caf 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -490,7 +490,6 @@ void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, for (substream = stream->substream; substream != NULL; substream = substream->next) substream->ops = ops; } - EXPORT_SYMBOL(snd_pcm_set_ops); /** @@ -508,7 +507,6 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream) runtime->sync.id32[2] = -1; runtime->sync.id32[3] = -1; } - EXPORT_SYMBOL(snd_pcm_set_sync); /* @@ -625,7 +623,6 @@ int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v) } return changed; } - EXPORT_SYMBOL(snd_interval_refine); static int snd_interval_refine_first(struct snd_interval *i) @@ -888,7 +885,6 @@ int snd_interval_ratnum(struct snd_interval *i, } return err; } - EXPORT_SYMBOL(snd_interval_ratnum); /** @@ -1026,7 +1022,6 @@ int snd_interval_list(struct snd_interval *i, unsigned int count, } return snd_interval_refine(i, &list_range); } - EXPORT_SYMBOL(snd_interval_list); /** @@ -1165,7 +1160,6 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond, va_end(args); return 0; } - EXPORT_SYMBOL(snd_pcm_hw_rule_add); /** @@ -1229,7 +1223,6 @@ int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_pa struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints; return snd_interval_setinteger(constrs_interval(constrs, var)); } - EXPORT_SYMBOL(snd_pcm_hw_constraint_integer); /** @@ -1255,7 +1248,6 @@ int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_par t.integer = 0; return snd_interval_refine(constrs_interval(constrs, var), &t); } - EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax); static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params, @@ -1286,7 +1278,6 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime, snd_pcm_hw_rule_list, (void *)l, var, -1); } - EXPORT_SYMBOL(snd_pcm_hw_constraint_list); static int snd_pcm_hw_rule_ranges(struct snd_pcm_hw_params *params, @@ -1353,7 +1344,6 @@ int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, snd_pcm_hw_rule_ratnums, (void *)r, var, -1); } - EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums); static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params, @@ -1388,7 +1378,6 @@ int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime, snd_pcm_hw_rule_ratdens, (void *)r, var, -1); } - EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens); static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, @@ -1435,7 +1424,6 @@ int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime, (void*) l, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); } - EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits); static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params, @@ -1463,7 +1451,6 @@ int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime, snd_pcm_hw_rule_step, (void *) step, var, -1); } - EXPORT_SYMBOL(snd_pcm_hw_constraint_step); static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) @@ -1494,7 +1481,6 @@ int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime, snd_pcm_hw_rule_pow2, NULL, var, -1); } - EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2); static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params, @@ -1553,7 +1539,6 @@ void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params) _snd_pcm_hw_param_any(params, k); params->info = ~0U; } - EXPORT_SYMBOL(_snd_pcm_hw_params_any); /** @@ -1586,7 +1571,6 @@ int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params, } return -EINVAL; } - EXPORT_SYMBOL(snd_pcm_hw_param_value); void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, @@ -1604,7 +1588,6 @@ void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, snd_BUG(); } } - EXPORT_SYMBOL(_snd_pcm_hw_param_setempty); static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params, @@ -1651,7 +1634,6 @@ int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, } return snd_pcm_hw_param_value(params, var, dir); } - EXPORT_SYMBOL(snd_pcm_hw_param_first); static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params, @@ -1698,7 +1680,6 @@ int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, } return snd_pcm_hw_param_value(params, var, dir); } - EXPORT_SYMBOL(snd_pcm_hw_param_last); static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream, @@ -1796,7 +1777,6 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, } return -ENXIO; } - EXPORT_SYMBOL(snd_pcm_lib_ioctl); /** @@ -1832,7 +1812,6 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) kill_fasync(&runtime->fasync, SIGIO, POLL_IN); snd_pcm_stream_unlock_irqrestore(substream, flags); } - EXPORT_SYMBOL(snd_pcm_period_elapsed); /* diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index b45f6aa32264..ae33e456708c 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -120,7 +120,6 @@ int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm) snd_pcm_lib_preallocate_free(substream); return 0; } - EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all); #ifdef CONFIG_SND_VERBOSE_PROCFS @@ -263,7 +262,6 @@ int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, substream->dma_buffer.dev.dev = data; return snd_pcm_lib_preallocate_pages1(substream, size, max); } - EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages); /** @@ -292,7 +290,6 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, return err; return 0; } - EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all); #ifdef CONFIG_SND_DMA_SGBUF @@ -314,7 +311,6 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne return NULL; return sgbuf->page_table[idx]; } - EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page); #endif /* CONFIG_SND_DMA_SGBUF */ @@ -370,7 +366,6 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size) runtime->dma_bytes = size; return 1; /* area was changed */ } - EXPORT_SYMBOL(snd_pcm_lib_malloc_pages); /** @@ -398,7 +393,6 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream) snd_pcm_set_runtime_buffer(substream, NULL); return 0; } - EXPORT_SYMBOL(snd_pcm_lib_free_pages); int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream, diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index dd8383e29315..9be81025372f 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -248,7 +248,6 @@ int snd_pcm_format_signed(snd_pcm_format_t format) return -EINVAL; return val; } - EXPORT_SYMBOL(snd_pcm_format_signed); /** @@ -267,7 +266,6 @@ int snd_pcm_format_unsigned(snd_pcm_format_t format) return val; return !val; } - EXPORT_SYMBOL(snd_pcm_format_unsigned); /** @@ -280,7 +278,6 @@ int snd_pcm_format_linear(snd_pcm_format_t format) { return snd_pcm_format_signed(format) >= 0; } - EXPORT_SYMBOL(snd_pcm_format_linear); /** @@ -299,7 +296,6 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format) return -EINVAL; return val; } - EXPORT_SYMBOL(snd_pcm_format_little_endian); /** @@ -318,7 +314,6 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format) return val; return !val; } - EXPORT_SYMBOL(snd_pcm_format_big_endian); /** @@ -337,7 +332,6 @@ int snd_pcm_format_width(snd_pcm_format_t format) return -EINVAL; return val; } - EXPORT_SYMBOL(snd_pcm_format_width); /** @@ -356,7 +350,6 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format) return -EINVAL; return val; } - EXPORT_SYMBOL(snd_pcm_format_physical_width); /** @@ -374,7 +367,6 @@ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples) return -EINVAL; return samples * phys_width / 8; } - EXPORT_SYMBOL(snd_pcm_format_size); /** @@ -391,7 +383,6 @@ const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format) return NULL; return pcm_formats[(INT)format].silence; } - EXPORT_SYMBOL(snd_pcm_format_silence_64); /** @@ -462,7 +453,6 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int #endif return 0; } - EXPORT_SYMBOL(snd_pcm_format_set_silence); /** @@ -491,7 +481,6 @@ int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime) } return 0; } - EXPORT_SYMBOL(snd_pcm_limit_hw_rates); /** diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 7e8f3656b695..d35c6614fdab 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1278,7 +1278,6 @@ int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state) { return snd_pcm_action(&snd_pcm_action_stop, substream, state); } - EXPORT_SYMBOL(snd_pcm_stop); /** @@ -1453,7 +1452,6 @@ int snd_pcm_suspend(struct snd_pcm_substream *substream) snd_pcm_stream_unlock_irqrestore(substream, flags); return err; } - EXPORT_SYMBOL(snd_pcm_suspend); /** @@ -1485,7 +1483,6 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm) } return 0; } - EXPORT_SYMBOL(snd_pcm_suspend_all); /* resume */ @@ -2369,7 +2366,6 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream) } snd_pcm_detach_substream(substream); } - EXPORT_SYMBOL(snd_pcm_release_substream); int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, @@ -2411,7 +2407,6 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, snd_pcm_release_substream(substream); return err; } - EXPORT_SYMBOL(snd_pcm_open_substream); static int snd_pcm_open_file(struct file *file, @@ -3504,7 +3499,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, area->vm_page_prot = pgprot_noncached(area->vm_page_prot); return vm_iomap_memory(area, runtime->dma_addr, runtime->dma_bytes); } - EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); #endif /* SNDRV_PCM_INFO_MMAP */ @@ -3553,7 +3547,6 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, atomic_inc(&substream->mmap_count); return err; } - EXPORT_SYMBOL(snd_pcm_mmap_data); static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) From 9c8ddd105e3a420b1fe2e0a4c4767b9dd67081a9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 16 Jun 2017 16:15:24 +0200 Subject: [PATCH 315/418] ALSA: seq: Follow standard EXPORT_SYMBOL() declarations Just a tidy up to follow the standard EXPORT_SYMBOL*() declarations in order to improve grep-ability. - Move EXPORT_SYMBOL*() to the position right after its definition - Remove superfluous blank line before EXPORT_SYMBOL*() lines Signed-off-by: Takashi Iwai --- sound/core/seq/seq_clientmgr.c | 8 -------- sound/core/seq/seq_lock.c | 1 - sound/core/seq/seq_memory.c | 2 -- sound/core/seq/seq_midi_emul.c | 9 ++++----- sound/core/seq/seq_midi_event.c | 21 ++++++++------------- sound/core/seq/seq_ports.c | 2 -- sound/core/seq/seq_virmidi.c | 3 +-- 7 files changed, 13 insertions(+), 33 deletions(-) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index f3b1d7f50b81..272c55fe17c8 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1668,7 +1668,6 @@ int snd_seq_set_queue_tempo(int client, struct snd_seq_queue_tempo *tempo) return -EPERM; return snd_seq_queue_timer_set_tempo(tempo->queue, client, tempo); } - EXPORT_SYMBOL(snd_seq_set_queue_tempo); static int snd_seq_ioctl_set_queue_tempo(struct snd_seq_client *client, @@ -2200,7 +2199,6 @@ int snd_seq_create_kernel_client(struct snd_card *card, int client_index, /* return client number to caller */ return client->number; } - EXPORT_SYMBOL(snd_seq_create_kernel_client); /* exported to kernel modules */ @@ -2219,7 +2217,6 @@ int snd_seq_delete_kernel_client(int client) kfree(ptr); return 0; } - EXPORT_SYMBOL(snd_seq_delete_kernel_client); /* skeleton to enqueue event, called from snd_seq_kernel_client_enqueue @@ -2269,7 +2266,6 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event * ev, { return kernel_client_enqueue(client, ev, NULL, 0, atomic, hop); } - EXPORT_SYMBOL(snd_seq_kernel_client_enqueue); /* @@ -2283,7 +2279,6 @@ int snd_seq_kernel_client_enqueue_blocking(int client, struct snd_seq_event * ev { return kernel_client_enqueue(client, ev, file, 1, atomic, hop); } - EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking); /* @@ -2321,7 +2316,6 @@ int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev, snd_seq_client_unlock(cptr); return result; } - EXPORT_SYMBOL(snd_seq_kernel_client_dispatch); /** @@ -2354,7 +2348,6 @@ int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg) cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); return -ENOTTY; } - EXPORT_SYMBOL(snd_seq_kernel_client_ctl); /* exported (for OSS emulator) */ @@ -2372,7 +2365,6 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table return 1; return 0; } - EXPORT_SYMBOL(snd_seq_kernel_client_write_poll); /*---------------------------------------------------------------------------*/ diff --git a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c index 12ba83367b1b..0ff7926a5a69 100644 --- a/sound/core/seq/seq_lock.c +++ b/sound/core/seq/seq_lock.c @@ -40,7 +40,6 @@ void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line) schedule_timeout_uninterruptible(1); } } - EXPORT_SYMBOL(snd_use_lock_sync_helper); #endif diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index d4c61ec9be13..512f78ea13da 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -118,7 +118,6 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event, } return 0; } - EXPORT_SYMBOL(snd_seq_dump_var_event); @@ -169,7 +168,6 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char &buf); return err < 0 ? err : newlen; } - EXPORT_SYMBOL(snd_seq_expand_var_event); /* diff --git a/sound/core/seq/seq_midi_emul.c b/sound/core/seq/seq_midi_emul.c index 7ba937399ac7..9e2912e3e80f 100644 --- a/sound/core/seq/seq_midi_emul.c +++ b/sound/core/seq/seq_midi_emul.c @@ -236,6 +236,7 @@ snd_midi_process_event(struct snd_midi_op *ops, break; } } +EXPORT_SYMBOL(snd_midi_process_event); /* @@ -409,6 +410,7 @@ snd_midi_channel_set_clear(struct snd_midi_channel_set *chset) chan->drum_channel = 0; } } +EXPORT_SYMBOL(snd_midi_channel_set_clear); /* * Process a rpn message. @@ -701,6 +703,7 @@ struct snd_midi_channel_set *snd_midi_channel_alloc_set(int n) } return chset; } +EXPORT_SYMBOL(snd_midi_channel_alloc_set); /* * Reset the midi controllers on a particular channel to default values. @@ -724,6 +727,7 @@ void snd_midi_channel_free_set(struct snd_midi_channel_set *chset) kfree(chset->channels); kfree(chset); } +EXPORT_SYMBOL(snd_midi_channel_free_set); static int __init alsa_seq_midi_emul_init(void) { @@ -736,8 +740,3 @@ static void __exit alsa_seq_midi_emul_exit(void) module_init(alsa_seq_midi_emul_init) module_exit(alsa_seq_midi_emul_exit) - -EXPORT_SYMBOL(snd_midi_process_event); -EXPORT_SYMBOL(snd_midi_channel_set_clear); -EXPORT_SYMBOL(snd_midi_channel_alloc_set); -EXPORT_SYMBOL(snd_midi_channel_free_set); diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c index 37db7ba492a6..90bbbdbeba03 100644 --- a/sound/core/seq/seq_midi_event.c +++ b/sound/core/seq/seq_midi_event.c @@ -134,6 +134,7 @@ int snd_midi_event_new(int bufsize, struct snd_midi_event **rdev) *rdev = dev; return 0; } +EXPORT_SYMBOL(snd_midi_event_new); void snd_midi_event_free(struct snd_midi_event *dev) { @@ -142,6 +143,7 @@ void snd_midi_event_free(struct snd_midi_event *dev) kfree(dev); } } +EXPORT_SYMBOL(snd_midi_event_free); /* * initialize record @@ -161,6 +163,7 @@ void snd_midi_event_reset_encode(struct snd_midi_event *dev) reset_encode(dev); spin_unlock_irqrestore(&dev->lock, flags); } +EXPORT_SYMBOL(snd_midi_event_reset_encode); void snd_midi_event_reset_decode(struct snd_midi_event *dev) { @@ -170,6 +173,7 @@ void snd_midi_event_reset_decode(struct snd_midi_event *dev) dev->lastcmd = 0xff; spin_unlock_irqrestore(&dev->lock, flags); } +EXPORT_SYMBOL(snd_midi_event_reset_decode); #if 0 void snd_midi_event_init(struct snd_midi_event *dev) @@ -183,6 +187,7 @@ void snd_midi_event_no_status(struct snd_midi_event *dev, int on) { dev->nostat = on ? 1 : 0; } +EXPORT_SYMBOL(snd_midi_event_no_status); /* * resize buffer @@ -232,6 +237,7 @@ long snd_midi_event_encode(struct snd_midi_event *dev, unsigned char *buf, long return result; } +EXPORT_SYMBOL(snd_midi_event_encode); /* * read one byte and encode to sequencer event: @@ -307,6 +313,7 @@ int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c, spin_unlock_irqrestore(&dev->lock, flags); return rc; } +EXPORT_SYMBOL(snd_midi_event_encode_byte); /* encode note event */ static void note_event(struct snd_midi_event *dev, struct snd_seq_event *ev) @@ -408,6 +415,7 @@ long snd_midi_event_decode(struct snd_midi_event *dev, unsigned char *buf, long return qlen; } } +EXPORT_SYMBOL(snd_midi_event_decode); /* decode note event */ @@ -524,19 +532,6 @@ static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf, return idx; } -/* - * exports - */ - -EXPORT_SYMBOL(snd_midi_event_new); -EXPORT_SYMBOL(snd_midi_event_free); -EXPORT_SYMBOL(snd_midi_event_reset_encode); -EXPORT_SYMBOL(snd_midi_event_reset_decode); -EXPORT_SYMBOL(snd_midi_event_no_status); -EXPORT_SYMBOL(snd_midi_event_encode); -EXPORT_SYMBOL(snd_midi_event_encode_byte); -EXPORT_SYMBOL(snd_midi_event_decode); - static int __init alsa_seq_midi_event_init(void) { return 0; diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index fe686ee41c6d..0a7020c82bfc 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -685,7 +685,6 @@ int snd_seq_event_port_attach(int client, return ret; } - EXPORT_SYMBOL(snd_seq_event_port_attach); /* @@ -706,5 +705,4 @@ int snd_seq_event_port_detach(int client, int port) return err; } - EXPORT_SYMBOL(snd_seq_event_port_detach); diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 52f31f1498f9..8d93a4021c78 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -534,6 +534,7 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi *rrmidi = rmidi; return 0; } +EXPORT_SYMBOL(snd_virmidi_new); /* * ENTRY functions @@ -550,5 +551,3 @@ static void __exit alsa_virmidi_exit(void) module_init(alsa_virmidi_init) module_exit(alsa_virmidi_exit) - -EXPORT_SYMBOL(snd_virmidi_new); From 988563929d5b65c021439880ac6bd1b207722f26 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 16 Jun 2017 16:16:05 +0200 Subject: [PATCH 316/418] ALSA: timer: Follow standard EXPORT_SYMBOL() declarations Just a tidy up to follow the standard EXPORT_SYMBOL*() declarations in order to improve grep-ability. - Move EXPORT_SYMBOL*() to the position right after its definition Signed-off-by: Takashi Iwai --- sound/core/timer.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/sound/core/timer.c b/sound/core/timer.c index 148290ace756..4888203b2dbc 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -319,6 +319,7 @@ int snd_timer_open(struct snd_timer_instance **ti, *ti = timeri; return 0; } +EXPORT_SYMBOL(snd_timer_open); /* * close a timer instance @@ -384,6 +385,7 @@ int snd_timer_close(struct snd_timer_instance *timeri) mutex_unlock(®ister_mutex); return 0; } +EXPORT_SYMBOL(snd_timer_close); unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) { @@ -398,6 +400,7 @@ unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) } return 0; } +EXPORT_SYMBOL(snd_timer_resolution); static void snd_timer_notify1(struct snd_timer_instance *ti, int event) { @@ -589,6 +592,7 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) else return snd_timer_start1(timeri, true, ticks); } +EXPORT_SYMBOL(snd_timer_start); /* * stop the timer instance. @@ -602,6 +606,7 @@ int snd_timer_stop(struct snd_timer_instance *timeri) else return snd_timer_stop1(timeri, true); } +EXPORT_SYMBOL(snd_timer_stop); /* * start again.. the tick is kept. @@ -617,6 +622,7 @@ int snd_timer_continue(struct snd_timer_instance *timeri) else return snd_timer_start1(timeri, false, 0); } +EXPORT_SYMBOL(snd_timer_continue); /* * pause.. remember the ticks left @@ -628,6 +634,7 @@ int snd_timer_pause(struct snd_timer_instance * timeri) else return snd_timer_stop1(timeri, false); } +EXPORT_SYMBOL(snd_timer_pause); /* * reschedule the timer @@ -809,6 +816,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) if (use_tasklet) tasklet_schedule(&timer->task_queue); } +EXPORT_SYMBOL(snd_timer_interrupt); /* @@ -859,6 +867,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, *rtimer = timer; return 0; } +EXPORT_SYMBOL(snd_timer_new); static int snd_timer_free(struct snd_timer *timer) { @@ -978,6 +987,7 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam } spin_unlock_irqrestore(&timer->lock, flags); } +EXPORT_SYMBOL(snd_timer_notify); /* * exported functions for global timers @@ -993,11 +1003,13 @@ int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer) tid.subdevice = 0; return snd_timer_new(NULL, id, &tid, rtimer); } +EXPORT_SYMBOL(snd_timer_global_new); int snd_timer_global_free(struct snd_timer *timer) { return snd_timer_free(timer); } +EXPORT_SYMBOL(snd_timer_global_free); int snd_timer_global_register(struct snd_timer *timer) { @@ -1007,6 +1019,7 @@ int snd_timer_global_register(struct snd_timer *timer) dev.device_data = timer; return snd_timer_dev_register(&dev); } +EXPORT_SYMBOL(snd_timer_global_register); /* * System timer @@ -2113,17 +2126,3 @@ static void __exit alsa_timer_exit(void) module_init(alsa_timer_init) module_exit(alsa_timer_exit) - -EXPORT_SYMBOL(snd_timer_open); -EXPORT_SYMBOL(snd_timer_close); -EXPORT_SYMBOL(snd_timer_resolution); -EXPORT_SYMBOL(snd_timer_start); -EXPORT_SYMBOL(snd_timer_stop); -EXPORT_SYMBOL(snd_timer_continue); -EXPORT_SYMBOL(snd_timer_pause); -EXPORT_SYMBOL(snd_timer_new); -EXPORT_SYMBOL(snd_timer_notify); -EXPORT_SYMBOL(snd_timer_global_new); -EXPORT_SYMBOL(snd_timer_global_free); -EXPORT_SYMBOL(snd_timer_global_register); -EXPORT_SYMBOL(snd_timer_interrupt); From 35f8001415d301ba47124f463f98eee0e7d0792c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 16 Jun 2017 16:16:33 +0200 Subject: [PATCH 317/418] ALSA: core: Follow standard EXPORT_SYMBOL() declarations Just a tidy up to follow the standard EXPORT_SYMBOL*() declarations in order to improve grep-ability. - Move EXPORT_SYMBOL*() to the position right after its definition - Remove superfluous blank line before EXPORT_SYMBOL*() lines Signed-off-by: Takashi Iwai --- sound/core/info.c | 6 ------ sound/core/info_oss.c | 1 - sound/core/init.c | 8 +------- sound/core/isadma.c | 3 --- sound/core/memalloc.c | 13 ++++--------- sound/core/memory.c | 2 -- sound/core/misc.c | 1 - sound/core/oss/mixer_oss.c | 3 +-- sound/core/sound.c | 2 -- sound/core/sound_oss.c | 3 --- 10 files changed, 6 insertions(+), 36 deletions(-) diff --git a/sound/core/info.c b/sound/core/info.c index fc14ebe751d8..bcf6a48cc70d 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -652,7 +652,6 @@ int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) *line = '\0'; return 0; } - EXPORT_SYMBOL(snd_info_get_line); /** @@ -690,7 +689,6 @@ const char *snd_info_get_str(char *dest, const char *src, int len) src++; return src; } - EXPORT_SYMBOL(snd_info_get_str); /* @@ -748,7 +746,6 @@ struct snd_info_entry *snd_info_create_module_entry(struct module * module, entry->module = module; return entry; } - EXPORT_SYMBOL(snd_info_create_module_entry); /** @@ -772,7 +769,6 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, } return entry; } - EXPORT_SYMBOL(snd_info_create_card_entry); static void snd_info_disconnect(struct snd_info_entry *entry) @@ -815,7 +811,6 @@ void snd_info_free_entry(struct snd_info_entry * entry) entry->private_free(entry); kfree(entry); } - EXPORT_SYMBOL(snd_info_free_entry); /** @@ -858,7 +853,6 @@ int snd_info_register(struct snd_info_entry * entry) mutex_unlock(&info_mutex); return 0; } - EXPORT_SYMBOL(snd_info_register); /* diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c index 1478c8dfd473..f479374b6bd8 100644 --- a/sound/core/info_oss.c +++ b/sound/core/info_oss.c @@ -61,7 +61,6 @@ int snd_oss_info_register(int dev, int num, char *string) mutex_unlock(&strings); return 0; } - EXPORT_SYMBOL(snd_oss_info_register); static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int dev) diff --git a/sound/core/init.c b/sound/core/init.c index 6bda8436d765..00f2cbb76e69 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -452,7 +452,6 @@ int snd_card_disconnect(struct snd_card *card) #endif return 0; } - EXPORT_SYMBOL(snd_card_disconnect); static int snd_card_do_free(struct snd_card *card) @@ -718,7 +717,7 @@ int snd_card_add_dev_attr(struct snd_card *card, dev_err(card->dev, "Too many groups assigned\n"); return -ENOSPC; -}; +} EXPORT_SYMBOL_GPL(snd_card_add_dev_attr); /** @@ -775,7 +774,6 @@ int snd_card_register(struct snd_card *card) #endif return 0; } - EXPORT_SYMBOL(snd_card_register); #ifdef CONFIG_SND_PROC_FS @@ -895,7 +893,6 @@ int snd_component_add(struct snd_card *card, const char *component) strcat(card->components, component); return 0; } - EXPORT_SYMBOL(snd_component_add); /** @@ -930,7 +927,6 @@ int snd_card_file_add(struct snd_card *card, struct file *file) spin_unlock(&card->files_lock); return 0; } - EXPORT_SYMBOL(snd_card_file_add); /** @@ -972,7 +968,6 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) put_device(&card->card_dev); return 0; } - EXPORT_SYMBOL(snd_card_file_remove); #ifdef CONFIG_PM @@ -1012,6 +1007,5 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state) remove_wait_queue(&card->power_sleep, &wait); return result; } - EXPORT_SYMBOL(snd_power_wait); #endif /* CONFIG_PM */ diff --git a/sound/core/isadma.c b/sound/core/isadma.c index 31e8544d7f2d..7a8515abb5f9 100644 --- a/sound/core/isadma.c +++ b/sound/core/isadma.c @@ -55,7 +55,6 @@ void snd_dma_program(unsigned long dma, enable_dma(dma); release_dma_lock(flags); } - EXPORT_SYMBOL(snd_dma_program); /** @@ -73,7 +72,6 @@ void snd_dma_disable(unsigned long dma) disable_dma(dma); release_dma_lock(flags); } - EXPORT_SYMBOL(snd_dma_disable); /** @@ -113,5 +111,4 @@ unsigned int snd_dma_pointer(unsigned long dma, unsigned int size) else return size - result; } - EXPORT_SYMBOL(snd_dma_pointer); diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index f05cb6a8cbe0..7f89d3c79a4b 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -54,6 +54,7 @@ void *snd_malloc_pages(size_t size, gfp_t gfp_flags) pg = get_order(size); return (void *) __get_free_pages(gfp_flags, pg); } +EXPORT_SYMBOL(snd_malloc_pages); /** * snd_free_pages - release the pages @@ -71,6 +72,7 @@ void snd_free_pages(void *ptr, size_t size) pg = get_order(size); free_pages((unsigned long) ptr, pg); } +EXPORT_SYMBOL(snd_free_pages); /* * @@ -217,6 +219,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, dmab->bytes = size; return 0; } +EXPORT_SYMBOL(snd_dma_alloc_pages); /** * snd_dma_alloc_pages_fallback - allocate the buffer area according to the given type with fallback @@ -254,6 +257,7 @@ int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size, return -ENOMEM; return 0; } +EXPORT_SYMBOL(snd_dma_alloc_pages_fallback); /** @@ -287,13 +291,4 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) pr_err("snd-malloc: invalid device type %d\n", dmab->dev.type); } } - -/* - * exports - */ -EXPORT_SYMBOL(snd_dma_alloc_pages); -EXPORT_SYMBOL(snd_dma_alloc_pages_fallback); EXPORT_SYMBOL(snd_dma_free_pages); - -EXPORT_SYMBOL(snd_malloc_pages); -EXPORT_SYMBOL(snd_free_pages); diff --git a/sound/core/memory.c b/sound/core/memory.c index 4cd664efad77..19c9ea90d9bf 100644 --- a/sound/core/memory.c +++ b/sound/core/memory.c @@ -55,7 +55,6 @@ int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size return 0; #endif } - EXPORT_SYMBOL(copy_to_user_fromio); /** @@ -88,5 +87,4 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size return 0; #endif } - EXPORT_SYMBOL(copy_from_user_toio); diff --git a/sound/core/misc.c b/sound/core/misc.c index 21b228046e88..0f818d593c9e 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -48,7 +48,6 @@ void release_and_free_resource(struct resource *res) kfree(res); } } - EXPORT_SYMBOL(release_and_free_resource); #ifdef CONFIG_SND_VERBOSE_PRINTK diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 2ff9c12d664a..379bf486ccc7 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -395,6 +395,7 @@ int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned l fmixer.mixer = card->mixer_oss; return snd_mixer_oss_ioctl1(&fmixer, cmd, arg); } +EXPORT_SYMBOL(snd_mixer_oss_ioctl_card); #ifdef CONFIG_COMPAT /* all compatible */ @@ -1425,5 +1426,3 @@ static void __exit alsa_mixer_oss_exit(void) module_init(alsa_mixer_oss_init) module_exit(alsa_mixer_oss_exit) - -EXPORT_SYMBOL(snd_mixer_oss_ioctl_card); diff --git a/sound/core/sound.c b/sound/core/sound.c index 175f9e4e01c8..b30f027eb0fe 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -74,7 +74,6 @@ void snd_request_card(int card) return; request_module("snd-card-%i", card); } - EXPORT_SYMBOL(snd_request_card); static void snd_request_other(int minor) @@ -124,7 +123,6 @@ void *snd_lookup_minor_data(unsigned int minor, int type) mutex_unlock(&sound_mutex); return private_data; } - EXPORT_SYMBOL(snd_lookup_minor_data); #ifdef CONFIG_MODULES diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c index 0ca9d72b2273..0a5c66229a22 100644 --- a/sound/core/sound_oss.c +++ b/sound/core/sound_oss.c @@ -55,7 +55,6 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type) mutex_unlock(&sound_oss_mutex); return private_data; } - EXPORT_SYMBOL(snd_lookup_oss_minor_data); static int snd_oss_kernel_minor(int type, struct snd_card *card, int dev) @@ -159,7 +158,6 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev, kfree(preg); return -EBUSY; } - EXPORT_SYMBOL(snd_register_oss_device); int snd_unregister_oss_device(int type, struct snd_card *card, int dev) @@ -200,7 +198,6 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev) kfree(mptr); return 0; } - EXPORT_SYMBOL(snd_unregister_oss_device); /* From a36afb0ab6488eaa2c9672d6c20a966a7c08ef65 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 15 Jun 2017 15:46:36 +0300 Subject: [PATCH 318/418] ASoC: rt5677: Introduce proper table for ACPI enumeration I2C devices are enumerated by IDs, and not by instances. Make it clear by using proper module device table for ACPI case. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 65ac4518ad06..64cf6cc41ad1 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5030,7 +5030,6 @@ static const struct regmap_config rt5677_regmap = { static const struct i2c_device_id rt5677_i2c_id[] = { { "rt5677", RT5677 }, { "rt5676", RT5676 }, - { "RT5677CE:00", RT5677 }, { } }; MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); @@ -5041,6 +5040,14 @@ static const struct of_device_id rt5677_of_match[] = { }; MODULE_DEVICE_TABLE(of, rt5677_of_match); +#ifdef CONFIG_ACPI +static const struct acpi_device_id rt5677_acpi_match[] = { + { "RT5677CE", RT5677 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, rt5677_acpi_match); +#endif + static const struct acpi_gpio_params plug_det_gpio = { RT5677_GPIO_PLUG_DET, 0, false }; static const struct acpi_gpio_params mic_present_gpio = { RT5677_GPIO_MIC_PRESENT_L, 0, false }; static const struct acpi_gpio_params headphone_enable_gpio = { RT5677_GPIO_HP_AMP_SHDN_L, 0, false }; @@ -5301,6 +5308,7 @@ static struct i2c_driver rt5677_i2c_driver = { .driver = { .name = "rt5677", .of_match_table = rt5677_of_match, + .acpi_match_table = ACPI_PTR(rt5677_acpi_match), }, .probe = rt5677_i2c_probe, .remove = rt5677_i2c_remove, From 55e59aa0525a461abcbc226ace7a7eb9d9a07a4a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 15 Jun 2017 15:46:37 +0300 Subject: [PATCH 319/418] ASoC: rt5677: Move platform code to board file GPIO ACPI mapping table is defined on platform basis. Codec driver shouldn't have known what platform is using it. Make codec driver more generic by moving platform code to where it belongs. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 26 -------------------------- sound/soc/intel/boards/bdw-rt5677.c | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 64cf6cc41ad1..36e530a36c82 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -41,15 +41,6 @@ #define RT5677_PR_BASE (RT5677_PR_RANGE_BASE + (0 * RT5677_PR_SPACING)) -/* GPIO indexes defined by ACPI */ -enum { - RT5677_GPIO_PLUG_DET = 0, - RT5677_GPIO_MIC_PRESENT_L = 1, - RT5677_GPIO_HOTWORD_DET_L = 2, - RT5677_GPIO_DSP_INT = 3, - RT5677_GPIO_HP_AMP_SHDN_L = 4, -}; - static const struct regmap_range_cfg rt5677_ranges[] = { { .name = "PR", @@ -5048,28 +5039,11 @@ static const struct acpi_device_id rt5677_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt5677_acpi_match); #endif -static const struct acpi_gpio_params plug_det_gpio = { RT5677_GPIO_PLUG_DET, 0, false }; -static const struct acpi_gpio_params mic_present_gpio = { RT5677_GPIO_MIC_PRESENT_L, 0, false }; -static const struct acpi_gpio_params headphone_enable_gpio = { RT5677_GPIO_HP_AMP_SHDN_L, 0, false }; - -static const struct acpi_gpio_mapping bdw_rt5677_gpios[] = { - { "plug-det-gpios", &plug_det_gpio, 1 }, - { "mic-present-gpios", &mic_present_gpio, 1 }, - { "headphone-enable-gpios", &headphone_enable_gpio, 1 }, - { NULL }, -}; - static void rt5677_read_acpi_properties(struct rt5677_priv *rt5677, struct device *dev) { - int ret; u32 val; - ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), - bdw_rt5677_gpios); - if (ret) - dev_warn(dev, "Failed to add driver gpios\n"); - if (!device_property_read_u32(dev, "DCLK", &val)) rt5677->pdata.dmic2_clk_pin = val; diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 14d9693c1641..bb98e94dd6f9 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +#include #include #include #include @@ -120,6 +121,26 @@ static struct snd_soc_jack_gpio mic_jack_gpio = { .invert = 1, }; +/* GPIO indexes defined by ACPI */ +enum { + RT5677_GPIO_PLUG_DET = 0, + RT5677_GPIO_MIC_PRESENT_L = 1, + RT5677_GPIO_HOTWORD_DET_L = 2, + RT5677_GPIO_DSP_INT = 3, + RT5677_GPIO_HP_AMP_SHDN_L = 4, +}; + +static const struct acpi_gpio_params plug_det_gpio = { RT5677_GPIO_PLUG_DET, 0, false }; +static const struct acpi_gpio_params mic_present_gpio = { RT5677_GPIO_MIC_PRESENT_L, 0, false }; +static const struct acpi_gpio_params headphone_enable_gpio = { RT5677_GPIO_HP_AMP_SHDN_L, 0, false }; + +static const struct acpi_gpio_mapping bdw_rt5677_gpios[] = { + { "plug-det-gpios", &plug_det_gpio, 1 }, + { "mic-present-gpios", &mic_present_gpio, 1 }, + { "headphone-enable-gpios", &headphone_enable_gpio, 1 }, + { NULL }, +}; + static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -184,6 +205,12 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) snd_soc_card_get_drvdata(rtd->card); struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + int ret; + + ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(codec->dev), + bdw_rt5677_gpios); + if (ret) + dev_warn(codec->dev, "Failed to add driver gpios\n"); /* Enable codec ASRC function for Stereo DAC/Stereo1 ADC/DMIC/I2S1. * The ASRC clock source is clk_i2s1_asrc. From 0931352dcb4d2019bf1ec2a5457a41d1d6566509 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 15 Jun 2017 15:46:38 +0300 Subject: [PATCH 320/418] ASoC: Intel: bdw-rt5677: Switch to devm_acpi_dev_add_driver_gpios() Switch to use managed variant of acpi_dev_add_driver_gpios() to simplify error path and fix potentially wrong assignment if ->probe() fails. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- sound/soc/intel/boards/bdw-rt5677.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index bb98e94dd6f9..058b8ccedf02 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -207,8 +207,7 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); int ret; - ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(codec->dev), - bdw_rt5677_gpios); + ret = devm_acpi_dev_add_driver_gpios(codec->dev, bdw_rt5677_gpios); if (ret) dev_warn(codec->dev, "Failed to add driver gpios\n"); From 907cd8809eebccc57a6a3ee9fa87b7602e72df38 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 16 Jun 2017 01:47:34 +0000 Subject: [PATCH 321/418] ASoC: ak4613: add hw_constraint rule for Sampling Rate Current ak4613 accepts all range of Sampling Rate, but it depends on inputed master clock. This patch adds hw constraint rule for it. Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/codecs/ak4613.c | 61 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index d5beca008dea..a4520a1f849d 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -94,6 +94,8 @@ struct ak4613_interface { struct ak4613_priv { struct mutex lock; const struct ak4613_interface *iface; + struct snd_pcm_hw_constraint_list constraint; + unsigned int sysclk; unsigned int fmt; u8 oc; @@ -252,6 +254,50 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream, mutex_unlock(&priv->lock); } +static void ak4613_hw_constraints(struct ak4613_priv *priv, + struct snd_pcm_runtime *runtime) +{ + static const unsigned int ak4613_rates[] = { + 32000, + 44100, + 48000, + 64000, + 88200, + 96000, + 176400, + 192000, + }; + struct snd_pcm_hw_constraint_list *constraint = &priv->constraint; + unsigned int fs; + int i; + + constraint->list = ak4613_rates; + constraint->mask = 0; + constraint->count = 0; + + /* + * Slave Mode + * Normal: [32kHz, 48kHz] : 256fs,384fs or 512fs + * Double: [64kHz, 96kHz] : 256fs + * Quad : [128kHz,192kHz]: 128fs + * + * Master mode + * Normal: [32kHz, 48kHz] : 256fs or 512fs + * Double: [64kHz, 96kHz] : 256fs + * Quad : [128kHz,192kHz]: 128fs + */ + for (i = 0; i < ARRAY_SIZE(ak4613_rates); i++) { + /* minimum fs on each range */ + fs = (ak4613_rates[i] <= 96000) ? 256 : 128; + + if (priv->sysclk >= ak4613_rates[i] * fs) + constraint->count = i + 1; + } + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, constraint); +} + static int ak4613_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -260,6 +306,19 @@ static int ak4613_dai_startup(struct snd_pcm_substream *substream, priv->cnt++; + ak4613_hw_constraints(priv, substream->runtime); + + return 0; +} + +static int ak4613_dai_set_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec); + + priv->sysclk = freq; + return 0; } @@ -411,6 +470,7 @@ static int ak4613_set_bias_level(struct snd_soc_codec *codec, static const struct snd_soc_dai_ops ak4613_dai_ops = { .startup = ak4613_dai_startup, .shutdown = ak4613_dai_shutdown, + .set_sysclk = ak4613_dai_set_sysclk, .set_fmt = ak4613_dai_set_fmt, .hw_params = ak4613_dai_hw_params, }; @@ -529,6 +589,7 @@ static int ak4613_i2c_probe(struct i2c_client *i2c, priv->iface = NULL; priv->cnt = 0; + priv->sysclk = 0; mutex_init(&priv->lock); From b31f11d036e689ba9e60d581ffe8e032a6305da9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 16 Jun 2017 01:38:50 +0000 Subject: [PATCH 322/418] ASoC: simple-card-utils: add asoc_simple_card_of_parse_widgets() Current simple card drivers are parsing widgets on each own driver (only simple-card at this point, but will be supported on all drivers) Encapsulation is one of simple card util's purpose. Let's add asoc_simple_card_of_parse_widgets for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 2 ++ sound/soc/generic/simple-card-utils.c | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 889c8ff86369..42c6a6ac3ce6 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -103,5 +103,7 @@ void asoc_simple_card_parse_convert(struct device *dev, char *prefix, int asoc_simple_card_of_parse_routing(struct snd_soc_card *card, char *prefix, int optional); +int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card, + char *prefix); #endif /* __SIMPLE_CARD_UTILS_H */ diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index a2b6d95bc2f9..26d64fa40c9c 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -397,6 +397,25 @@ int asoc_simple_card_of_parse_routing(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_routing); +int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card, + char *prefix) +{ + struct device_node *node = card->dev->of_node; + char prop[128]; + + if (!prefix) + prefix = ""; + + snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets"); + + if (of_property_read_bool(node, prop)) + return snd_soc_of_parse_audio_simple_widgets(card, prop); + + /* no widgets is not error */ + return 0; +} +EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_widgets); + /* Module information */ MODULE_AUTHOR("Kuninori Morimoto "); MODULE_DESCRIPTION("ALSA SoC Simple Card Utils"); From fa2760dd366c735637504d1d7efab7688391c6b4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 16 Jun 2017 01:39:11 +0000 Subject: [PATCH 323/418] ASoC: simple-card: use asoc_simple_card_of_parse_widgets() Current simple card driver is supporting widgets on DT, other simple/audio card drivers will support it. Encapsulation is one of simple card util's purpose. Let's use asoc_simple_card_of_parse_widgets Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 7b2533c7f82e..8b7b47251fe1 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -354,13 +354,9 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) dai_link = of_get_child_by_name(node, PREFIX "dai-link"); - /* The off-codec widgets */ - if (of_property_read_bool(node, PREFIX "widgets")) { - ret = snd_soc_of_parse_audio_simple_widgets(card, - PREFIX "widgets"); - if (ret) - goto card_parse_end; - } + ret = asoc_simple_card_of_parse_widgets(card, PREFIX); + if (ret < 0) + goto card_parse_end; ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1); if (ret < 0) From 5b16c8b1faf4bf77934c0a206cfbe77154c79fd7 Mon Sep 17 00:00:00 2001 From: olivier moysan Date: Fri, 16 Jun 2017 14:15:28 +0200 Subject: [PATCH 324/418] ASoC: stm32: sai: fix DT example Correct the device tree example. Signed-off-by: olivier moysan Signed-off-by: Mark Brown --- .../bindings/sound/st,stm32-sai.txt | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt index c59a3d779e06..a0feeed1710e 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt @@ -36,6 +36,10 @@ SAI subnodes required properties: - pinctrl-names: should contain only value "default" - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt +The device node should contain one 'port' child node with one child 'endpoint' +node, according to the bindings defined in Documentation/devicetree/bindings/ +graph.txt. + Example: sound_card { compatible = "audio-graph-card"; @@ -46,16 +50,15 @@ sai1: sai1@40015800 { compatible = "st,stm32f4-sai"; #address-cells = <1>; #size-cells = <1>; - ranges; + ranges = <0 0x40015800 0x400>; reg = <0x40015800 0x4>; clocks = <&rcc 1 CLK_SAIQ_PDIV>, <&rcc 1 CLK_I2SQ_PDIV>; clock-names = "x8k", "x11k"; interrupts = <87>; sai1b: audio-controller@40015824 { - #sound-dai-cells = <0>; compatible = "st,stm32-sai-sub-b"; - reg = <0x40015824 0x1C>; + reg = <0x24 0x1C>; clocks = <&rcc 1 CLK_SAI2>; clock-names = "sai_ck"; dmas = <&dma2 5 0 0x400 0x0>; @@ -63,18 +66,10 @@ sai1: sai1@40015800 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sai1b>; - ports { - #address-cells = <1>; - #size-cells = <0>; - - sai1b_port: port@0 { - reg = <0>; - cpu_endpoint: endpoint { - remote-endpoint = <&codec_endpoint>; - audio-graph-card,format = "i2s"; - audio-graph-card,bitclock-master = <&codec_endpoint>; - audio-graph-card,frame-master = <&codec_endpoint>; - }; + sai1b_port: port { + cpu_endpoint: endpoint { + remote-endpoint = <&codec_endpoint>; + format = "i2s"; }; }; }; From 602fdadc547f3e623db32409eeea8a59a1baaf24 Mon Sep 17 00:00:00 2001 From: olivier moysan Date: Fri, 16 Jun 2017 14:15:30 +0200 Subject: [PATCH 325/418] ASoC: stm32: sai: typo fixes Fix typos in sai driver. Signed-off-by: olivier moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai.c | 2 +- sound/soc/stm/stm32_sai.h | 1 - sound/soc/stm/stm32_sai_sub.c | 28 ++++++++++++++-------------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index 2a27a26bf7a1..6159d66c2c54 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -110,6 +110,6 @@ static struct platform_driver stm32_sai_driver = { module_platform_driver(stm32_sai_driver); MODULE_DESCRIPTION("STM32 Soc SAI Interface"); -MODULE_AUTHOR("Olivier Moysan, "); +MODULE_AUTHOR("Olivier Moysan "); MODULE_ALIAS("platform:st,stm32-sai"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h index a801fda5066f..270be93b845e 100644 --- a/sound/soc/stm/stm32_sai.h +++ b/sound/soc/stm/stm32_sai.h @@ -125,7 +125,6 @@ #define SAI_XFRCR_FSOFF BIT(SAI_XFRCR_FSOFF_SHIFT) /****************** Bit definition for SAI_XSLOTR register ******************/ - #define SAI_XSLOTR_FBOFF_SHIFT 0 #define SAI_XSLOTR_FBOFF_MASK GENMASK(4, SAI_XSLOTR_FBOFF_SHIFT) #define SAI_XSLOTR_FBOFF_SET(x) ((x) << SAI_XSLOTR_FBOFF_SHIFT) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index ae4706ca265b..d7aeed3ec3c8 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -181,29 +181,29 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid) SAI_XCLRFR_MASK); if (flags & SAI_XIMR_OVRUDRIE) { - dev_err(&pdev->dev, "IT %s\n", + dev_err(&pdev->dev, "IRQ %s\n", STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun"); status = SNDRV_PCM_STATE_XRUN; } if (flags & SAI_XIMR_MUTEDETIE) - dev_dbg(&pdev->dev, "IT mute detected\n"); + dev_dbg(&pdev->dev, "IRQ mute detected\n"); if (flags & SAI_XIMR_WCKCFGIE) { - dev_err(&pdev->dev, "IT wrong clock configuration\n"); + dev_err(&pdev->dev, "IRQ wrong clock configuration\n"); status = SNDRV_PCM_STATE_DISCONNECTED; } if (flags & SAI_XIMR_CNRDYIE) - dev_warn(&pdev->dev, "IT Codec not ready\n"); + dev_err(&pdev->dev, "IRQ Codec not ready\n"); if (flags & SAI_XIMR_AFSDETIE) { - dev_warn(&pdev->dev, "IT Anticipated frame synchro\n"); + dev_err(&pdev->dev, "IRQ Anticipated frame synchro\n"); status = SNDRV_PCM_STATE_XRUN; } if (flags & SAI_XIMR_LFSDETIE) { - dev_warn(&pdev->dev, "IT Late frame synchro\n"); + dev_err(&pdev->dev, "IRQ Late frame synchro\n"); status = SNDRV_PCM_STATE_XRUN; } @@ -235,7 +235,7 @@ static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); int slotr, slotr_mask, slot_size; - dev_dbg(cpu_dai->dev, "masks tx/rx:%#x/%#x, slots:%d, width:%d\n", + dev_dbg(cpu_dai->dev, "Masks tx/rx:%#x/%#x, slots:%d, width:%d\n", tx_mask, rx_mask, slots, slot_width); switch (slot_width) { @@ -377,7 +377,7 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream, ret = clk_prepare_enable(sai->sai_ck); if (ret < 0) { - dev_err(cpu_dai->dev, "failed to enable clock: %d\n", ret); + dev_err(cpu_dai->dev, "Failed to enable clock: %d\n", ret); return ret; } @@ -497,7 +497,7 @@ static int stm32_sai_set_slots(struct snd_soc_dai *cpu_dai) SAI_XSLOTR_SLOTEN_SET(sai->slot_mask)); } - dev_dbg(cpu_dai->dev, "slots %d, slot width %d\n", + dev_dbg(cpu_dai->dev, "Slots %d, slot width %d\n", sai->slots, sai->slot_width); return 0; @@ -521,7 +521,7 @@ static void stm32_sai_set_frame(struct snd_soc_dai *cpu_dai) frcr |= SAI_XFRCR_FSALL_SET((fs_active - 1)); frcr_mask = SAI_XFRCR_FRL_MASK | SAI_XFRCR_FSALL_MASK; - dev_dbg(cpu_dai->dev, "frame length %d, frame active %d\n", + dev_dbg(cpu_dai->dev, "Frame length %d, frame active %d\n", sai->fs_length, fs_active); regmap_update_bits(sai->regmap, STM_SAI_FRCR_REGX, frcr_mask, frcr); @@ -784,7 +784,7 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck"); if (IS_ERR(sai->sai_ck)) { - dev_err(&pdev->dev, "missing kernel clock sai_ck\n"); + dev_err(&pdev->dev, "Missing kernel clock sai_ck\n"); return PTR_ERR(sai->sai_ck); } @@ -849,7 +849,7 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, sai->pdata->irq, stm32_sai_isr, IRQF_SHARED, dev_name(&pdev->dev), sai); if (ret) { - dev_err(&pdev->dev, "irq request returned %d\n", ret); + dev_err(&pdev->dev, "IRQ request returned %d\n", ret); return ret; } @@ -861,7 +861,7 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) ret = devm_snd_dmaengine_pcm_register(&pdev->dev, &stm32_sai_pcm_config, 0); if (ret) { - dev_err(&pdev->dev, "could not register pcm dma\n"); + dev_err(&pdev->dev, "Could not register pcm dma\n"); return ret; } @@ -879,6 +879,6 @@ static struct platform_driver stm32_sai_sub_driver = { module_platform_driver(stm32_sai_sub_driver); MODULE_DESCRIPTION("STM32 Soc SAI sub-block Interface"); -MODULE_AUTHOR("Olivier Moysan, "); +MODULE_AUTHOR("Olivier Moysan "); MODULE_ALIAS("platform:st,stm32-sai-sub"); MODULE_LICENSE("GPL v2"); From 607c61d40b9c29ab0902541d0d372b18793d6831 Mon Sep 17 00:00:00 2001 From: olivier moysan Date: Fri, 16 Jun 2017 14:15:31 +0200 Subject: [PATCH 326/418] ASoC: stm32: sai: remove spurious trace Remove spurious trace in sai driver. Signed-off-by: olivier moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai_sub.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index d7aeed3ec3c8..24b8874cfe5f 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -761,9 +761,6 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, return -ENODEV; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - dev_err(&pdev->dev, "res %pr\n", res); - base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) return PTR_ERR(base); From 4fa17938ea400b6478b24565483f2ac54122316f Mon Sep 17 00:00:00 2001 From: olivier moysan Date: Fri, 16 Jun 2017 14:15:32 +0200 Subject: [PATCH 327/418] ASoC: stm32: sai: change stop sequence Disable SAI before stopping DMA data transfers. Signed-off-by: olivier moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai_sub.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 24b8874cfe5f..97b69a3ab46e 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -629,12 +629,12 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd, dev_dbg(cpu_dai->dev, "Disable DMA and SAI\n"); regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, - SAI_XCR1_DMAEN, - (unsigned int)~SAI_XCR1_DMAEN); + SAI_XCR1_SAIEN, + (unsigned int)~SAI_XCR1_SAIEN); ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, - SAI_XCR1_SAIEN, - (unsigned int)~SAI_XCR1_SAIEN); + SAI_XCR1_DMAEN, + (unsigned int)~SAI_XCR1_DMAEN); if (ret < 0) dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); break; From 1c77603136d00368b8cd7c10d1ca4bad5952a136 Mon Sep 17 00:00:00 2001 From: olivier moysan Date: Fri, 16 Jun 2017 14:15:33 +0200 Subject: [PATCH 328/418] ASoC: stm32: sai: fix clock management Allow peripheral clock enable/disable on regmap accesses. Signed-off-by: olivier moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai_sub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 97b69a3ab46e..2466af0343db 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -766,8 +766,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, return PTR_ERR(base); sai->phys_addr = res->start; - sai->regmap = devm_regmap_init_mmio(&pdev->dev, base, - &stm32_sai_sub_regmap_config); + sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "sai_ck", base, + &stm32_sai_sub_regmap_config); /* Get direction property */ if (of_property_match_string(np, "dma-names", "tx") >= 0) { From 701a6ec3a3f8d30bdb45ee025fb61f7a934b6cad Mon Sep 17 00:00:00 2001 From: olivier moysan Date: Fri, 16 Jun 2017 14:15:34 +0200 Subject: [PATCH 329/418] ASoC: stm32: sai: manage master clock Disable master clock by default, and activate it only when requested. Signed-off-by: olivier moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai_sub.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 2466af0343db..ce48c02db051 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -220,8 +220,15 @@ static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); + int ret; if ((dir == SND_SOC_CLOCK_OUT) && sai->master) { + ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, + SAI_XCR1_NODIV, + (unsigned int)~SAI_XCR1_NODIV); + if (ret < 0) + return ret; + sai->mclk_rate = freq; dev_dbg(cpu_dai->dev, "SAI MCLK frequency is %uHz\n", freq); } @@ -356,6 +363,10 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) } cr1_mask |= SAI_XCR1_SLAVE; + /* do not generate master by default */ + cr1 |= SAI_XCR1_NODIV; + cr1_mask |= SAI_XCR1_NODIV; + ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1); if (ret < 0) { dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); @@ -652,6 +663,9 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream, regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0); + regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_NODIV, + SAI_XCR1_NODIV); + clk_disable_unprepare(sai->sai_ck); sai->substream = NULL; } From 3861da5801f59f3e9252b6a5db92cfa71629995c Mon Sep 17 00:00:00 2001 From: olivier moysan Date: Fri, 16 Jun 2017 14:16:23 +0200 Subject: [PATCH 330/418] ASoC: stm32: add h7 support for sai Document device tree bindings for STM32H7 SAI. Signed-off-by: olivier moysan Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/st,stm32-sai.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt index a0feeed1710e..f1c5ae59e7c9 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt @@ -6,7 +6,7 @@ The SAI contains two independent audio sub-blocks. Each sub-block has its own clock generator and I/O lines controller. Required properties: - - compatible: Should be "st,stm32f4-sai" + - compatible: Should be "st,stm32f4-sai" or "st,stm32h7-sai" - reg: Base address and size of SAI common register set. - clocks: Must contain phandle and clock specifier pairs for each entry in clock-names. @@ -47,24 +47,24 @@ sound_card { }; sai1: sai1@40015800 { - compatible = "st,stm32f4-sai"; + compatible = "st,stm32h7-sai"; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x40015800 0x400>; reg = <0x40015800 0x4>; - clocks = <&rcc 1 CLK_SAIQ_PDIV>, <&rcc 1 CLK_I2SQ_PDIV>; + clocks = <&rcc PLL1_Q>, <&rcc PLL2_P>; clock-names = "x8k", "x11k"; interrupts = <87>; - sai1b: audio-controller@40015824 { - compatible = "st,stm32-sai-sub-b"; - reg = <0x24 0x1C>; - clocks = <&rcc 1 CLK_SAI2>; + sai1a: audio-controller@40015804 { + compatible = "st,stm32-sai-sub-a"; + reg = <0x4 0x1C>; + clocks = <&rcc SAI1_CK>; clock-names = "sai_ck"; - dmas = <&dma2 5 0 0x400 0x0>; + dmas = <&dmamux1 1 87 0x400 0x0>; dma-names = "tx"; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_sai1b>; + pinctrl-0 = <&pinctrl_sai1a>; sai1b_port: port { cpu_endpoint: endpoint { From 03e78a242a15eca68e5c7cb606c94959382e2b18 Mon Sep 17 00:00:00 2001 From: olivier moysan Date: Fri, 16 Jun 2017 14:16:24 +0200 Subject: [PATCH 331/418] ASoC: stm32: sai: add h7 support Add support of SAI on STM32H7 family. Signed-off-by: olivier moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai.c | 13 ++++- sound/soc/stm/stm32_sai.h | 72 ++++++++++++++++++++++++++-- sound/soc/stm/stm32_sai_sub.c | 90 +++++++++++++++++++++++++++++------ 3 files changed, 154 insertions(+), 21 deletions(-) diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index 6159d66c2c54..f7713314913b 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -27,8 +27,17 @@ #include "stm32_sai.h" +static const struct stm32_sai_conf stm32_sai_conf_f4 = { + .version = SAI_STM32F4, +}; + +static const struct stm32_sai_conf stm32_sai_conf_h7 = { + .version = SAI_STM32H7, +}; + static const struct of_device_id stm32_sai_ids[] = { - { .compatible = "st,stm32f4-sai", .data = (void *)SAI_STM32F4 }, + { .compatible = "st,stm32f4-sai", .data = (void *)&stm32_sai_conf_f4 }, + { .compatible = "st,stm32h7-sai", .data = (void *)&stm32_sai_conf_h7 }, {} }; @@ -52,7 +61,7 @@ static int stm32_sai_probe(struct platform_device *pdev) of_id = of_match_device(stm32_sai_ids, &pdev->dev); if (of_id) - sai->version = (enum stm32_sai_version)of_id->data; + sai->conf = (struct stm32_sai_conf *)of_id->data; else return -EINVAL; diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h index 270be93b845e..889974dc62d9 100644 --- a/sound/soc/stm/stm32_sai.h +++ b/sound/soc/stm/stm32_sai.h @@ -31,6 +31,10 @@ #define STM_SAI_CLRFR_REGX 0x18 #define STM_SAI_DR_REGX 0x1C +/* Sub-block A registers, relative to sub-block A address */ +#define STM_SAI_PDMCR_REGX 0x40 +#define STM_SAI_PDMLY_REGX 0x44 + /******************** Bit definition for SAI_GCR register *******************/ #define SAI_GCR_SYNCIN_SHIFT 0 #define SAI_GCR_SYNCIN_MASK GENMASK(1, SAI_GCR_SYNCIN_SHIFT) @@ -75,10 +79,11 @@ #define SAI_XCR1_NODIV BIT(SAI_XCR1_NODIV_SHIFT) #define SAI_XCR1_MCKDIV_SHIFT 20 -#define SAI_XCR1_MCKDIV_WIDTH 4 -#define SAI_XCR1_MCKDIV_MASK GENMASK(24, SAI_XCR1_MCKDIV_SHIFT) +#define SAI_XCR1_MCKDIV_WIDTH(x) (((x) == SAI_STM32F4) ? 4 : 6) +#define SAI_XCR1_MCKDIV_MASK(x) GENMASK((SAI_XCR1_MCKDIV_SHIFT + (x) - 1),\ + SAI_XCR1_MCKDIV_SHIFT) #define SAI_XCR1_MCKDIV_SET(x) ((x) << SAI_XCR1_MCKDIV_SHIFT) -#define SAI_XCR1_MCKDIV_MAX ((1 << SAI_XCR1_MCKDIV_WIDTH) - 1) +#define SAI_XCR1_MCKDIV_MAX(x) ((1 << SAI_XCR1_MCKDIV_WIDTH(x)) - 1) #define SAI_XCR1_OSR_SHIFT 26 #define SAI_XCR1_OSR BIT(SAI_XCR1_OSR_SHIFT) @@ -178,8 +183,65 @@ #define SAI_XCLRFR_SHIFT 0 #define SAI_XCLRFR_MASK GENMASK(6, SAI_XCLRFR_SHIFT) +/****************** Bit definition for SAI_PDMCR register ******************/ +#define SAI_PDMCR_PDMEN BIT(0) + +#define SAI_PDMCR_MICNBR_SHIFT 4 +#define SAI_PDMCR_MICNBR_MASK GENMASK(5, SAI_PDMCR_MICNBR_SHIFT) +#define SAI_PDMCR_MICNBR_SET(x) ((x) << SAI_PDMCR_MICNBR_SHIFT) + +#define SAI_PDMCR_CKEN1 BIT(8) +#define SAI_PDMCR_CKEN2 BIT(9) +#define SAI_PDMCR_CKEN3 BIT(10) +#define SAI_PDMCR_CKEN4 BIT(11) + +/****************** Bit definition for (SAI_PDMDLY register ****************/ +#define SAI_PDMDLY_1L_SHIFT 0 +#define SAI_PDMDLY_1L_MASK GENMASK(2, SAI_PDMDLY_1L_SHIFT) +#define SAI_PDMDLY_1L_WIDTH 3 + +#define SAI_PDMDLY_1R_SHIFT 4 +#define SAI_PDMDLY_1R_MASK GENMASK(6, SAI_PDMDLY_1R_SHIFT) +#define SAI_PDMDLY_1R_WIDTH 3 + +#define SAI_PDMDLY_2L_SHIFT 8 +#define SAI_PDMDLY_2L_MASK GENMASK(10, SAI_PDMDLY_2L_SHIFT) +#define SAI_PDMDLY_2L_WIDTH 3 + +#define SAI_PDMDLY_2R_SHIFT 12 +#define SAI_PDMDLY_2R_MASK GENMASK(14, SAI_PDMDLY_2R_SHIFT) +#define SAI_PDMDLY_2R_WIDTH 3 + +#define SAI_PDMDLY_3L_SHIFT 16 +#define SAI_PDMDLY_3L_MASK GENMASK(18, SAI_PDMDLY_3L_SHIFT) +#define SAI_PDMDLY_3L_WIDTH 3 + +#define SAI_PDMDLY_3R_SHIFT 20 +#define SAI_PDMDLY_3R_MASK GENMASK(22, SAI_PDMDLY_3R_SHIFT) +#define SAI_PDMDLY_3R_WIDTH 3 + +#define SAI_PDMDLY_4L_SHIFT 24 +#define SAI_PDMDLY_4L_MASK GENMASK(26, SAI_PDMDLY_4L_SHIFT) +#define SAI_PDMDLY_4L_WIDTH 3 + +#define SAI_PDMDLY_4R_SHIFT 28 +#define SAI_PDMDLY_4R_MASK GENMASK(30, SAI_PDMDLY_4R_SHIFT) +#define SAI_PDMDLY_4R_WIDTH 3 + +#define STM_SAI_IS_F4(ip) ((ip)->conf->version == SAI_STM32F4) +#define STM_SAI_IS_H7(ip) ((ip)->conf->version == SAI_STM32H7) + enum stm32_sai_version { - SAI_STM32F4 + SAI_STM32F4, + SAI_STM32H7 +}; + +/** + * struct stm32_sai_conf - SAI configuration + * @version: SAI version + */ +struct stm32_sai_conf { + int version; }; /** @@ -194,6 +256,6 @@ struct stm32_sai_data { struct platform_device *pdev; struct clk *clk_x8k; struct clk *clk_x11k; - int version; + struct stm32_sai_conf *conf; int irq; }; diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index ce48c02db051..ba3fdc777ed8 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -51,12 +51,15 @@ #define STM_SAI_A_ID 0x0 #define STM_SAI_B_ID 0x1 +#define STM_SAI_IS_SUB_A(x) ((x)->id == STM_SAI_A_ID) +#define STM_SAI_IS_SUB_B(x) ((x)->id == STM_SAI_B_ID) #define STM_SAI_BLOCK_NAME(x) (((x)->id == STM_SAI_A_ID) ? "A" : "B") /** * struct stm32_sai_sub_data - private data of SAI sub block (block A or B) * @pdev: device data pointer * @regmap: SAI register map pointer + * @regmap_config: SAI sub block register map configuration pointer * @dma_params: dma configuration data for rx or tx channel * @cpu_dai_drv: DAI driver data pointer * @cpu_dai: DAI runtime data pointer @@ -79,6 +82,7 @@ struct stm32_sai_sub_data { struct platform_device *pdev; struct regmap *regmap; + const struct regmap_config *regmap_config; struct snd_dmaengine_dai_dma_data dma_params; struct snd_soc_dai_driver *cpu_dai_drv; struct snd_soc_dai *cpu_dai; @@ -118,6 +122,8 @@ static bool stm32_sai_sub_readable_reg(struct device *dev, unsigned int reg) case STM_SAI_SR_REGX: case STM_SAI_CLRFR_REGX: case STM_SAI_DR_REGX: + case STM_SAI_PDMCR_REGX: + case STM_SAI_PDMLY_REGX: return true; default: return false; @@ -145,13 +151,15 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg) case STM_SAI_SR_REGX: case STM_SAI_CLRFR_REGX: case STM_SAI_DR_REGX: + case STM_SAI_PDMCR_REGX: + case STM_SAI_PDMLY_REGX: return true; default: return false; } } -static const struct regmap_config stm32_sai_sub_regmap_config = { +static const struct regmap_config stm32_sai_sub_regmap_config_f4 = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -162,6 +170,17 @@ static const struct regmap_config stm32_sai_sub_regmap_config = { .fast_io = true, }; +static const struct regmap_config stm32_sai_sub_regmap_config_h7 = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = STM_SAI_PDMLY_REGX, + .readable_reg = stm32_sai_sub_readable_reg, + .volatile_reg = stm32_sai_sub_volatile_reg, + .writeable_reg = stm32_sai_sub_writeable_reg, + .fast_io = true, +}; + static irqreturn_t stm32_sai_isr(int irq, void *devid) { struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid; @@ -551,7 +570,8 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, { struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); int cr1, mask, div = 0; - int sai_clk_rate, ret; + int sai_clk_rate, mclk_ratio, den, ret; + int version = sai->pdata->conf->version; if (!sai->mclk_rate) { dev_err(cpu_dai->dev, "Mclk rate is null\n"); @@ -564,22 +584,54 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, clk_set_parent(sai->sai_ck, sai->pdata->clk_x8k); sai_clk_rate = clk_get_rate(sai->sai_ck); - /* - * mclk_rate = 256 * fs - * MCKDIV = 0 if sai_ck < 3/2 * mclk_rate - * MCKDIV = sai_ck / (2 * mclk_rate) otherwise - */ - if (2 * sai_clk_rate >= 3 * sai->mclk_rate) - div = DIV_ROUND_CLOSEST(sai_clk_rate, 2 * sai->mclk_rate); + if (STM_SAI_IS_F4(sai->pdata)) { + /* + * mclk_rate = 256 * fs + * MCKDIV = 0 if sai_ck < 3/2 * mclk_rate + * MCKDIV = sai_ck / (2 * mclk_rate) otherwise + */ + if (2 * sai_clk_rate >= 3 * sai->mclk_rate) + div = DIV_ROUND_CLOSEST(sai_clk_rate, + 2 * sai->mclk_rate); + } else { + /* + * TDM mode : + * mclk on + * MCKDIV = sai_ck / (ws x 256) (NOMCK=0. OSR=0) + * MCKDIV = sai_ck / (ws x 512) (NOMCK=0. OSR=1) + * mclk off + * MCKDIV = sai_ck / (frl x ws) (NOMCK=1) + * Note: NOMCK/NODIV correspond to same bit. + */ + if (sai->mclk_rate) { + mclk_ratio = sai->mclk_rate / params_rate(params); + if (mclk_ratio != 256) { + if (mclk_ratio == 512) { + mask = SAI_XCR1_OSR; + cr1 = SAI_XCR1_OSR; + } else { + dev_err(cpu_dai->dev, + "Wrong mclk ratio %d\n", + mclk_ratio); + return -EINVAL; + } + } + div = DIV_ROUND_CLOSEST(sai_clk_rate, sai->mclk_rate); + } else { + /* mclk-fs not set, master clock not active. NOMCK=1 */ + den = sai->fs_length * params_rate(params); + div = DIV_ROUND_CLOSEST(sai_clk_rate, den); + } + } - if (div > SAI_XCR1_MCKDIV_MAX) { + if (div > SAI_XCR1_MCKDIV_MAX(version)) { dev_err(cpu_dai->dev, "Divider %d out of range\n", div); return -EINVAL; } dev_dbg(cpu_dai->dev, "SAI clock %d, divider %d\n", sai_clk_rate, div); - mask = SAI_XCR1_MCKDIV_MASK; - cr1 = SAI_XCR1_MCKDIV_SET(div); + mask = SAI_XCR1_MCKDIV_MASK(SAI_XCR1_MCKDIV_WIDTH(version)); + cr1 = SAI_XCR1_MCKDIV_SET(div); ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, mask, cr1); if (ret < 0) { dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); @@ -780,8 +832,18 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, return PTR_ERR(base); sai->phys_addr = res->start; - sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "sai_ck", base, - &stm32_sai_sub_regmap_config); + + sai->regmap_config = &stm32_sai_sub_regmap_config_f4; + /* Note: PDM registers not available for H7 sub-block B */ + if (STM_SAI_IS_H7(sai->pdata) && STM_SAI_IS_SUB_A(sai)) + sai->regmap_config = &stm32_sai_sub_regmap_config_h7; + + sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "sai_ck", + base, sai->regmap_config); + if (IS_ERR(sai->regmap)) { + dev_err(&pdev->dev, "Failed to initialize MMIO\n"); + return PTR_ERR(sai->regmap); + } /* Get direction property */ if (of_property_match_string(np, "dma-names", "tx") >= 0) { From 5561b66bd0297b029d2aba40b044ac191fcca98c Mon Sep 17 00:00:00 2001 From: olivier moysan Date: Mon, 19 Jun 2017 11:09:55 +0200 Subject: [PATCH 332/418] ASoC: stm32: change configuration flag Use a specific flag for SAI and I2S interfaces, instead of common flag. Signed-off-by: olivier moysan Signed-off-by: Mark Brown --- sound/soc/stm/Kconfig | 19 ++++++++++++++++--- sound/soc/stm/Makefile | 6 +++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index a6372de54042..23600a5dd46f 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -1,8 +1,21 @@ -menuconfig SND_SOC_STM32 - tristate "STMicroelectronics STM32 SOC audio support" +menu "STMicroelectronics STM32 SOC audio support" + +config SND_SOC_STM32_SAI + tristate "STM32 SAI interface (Serial Audio Interface) support" depends on ARCH_STM32 || COMPILE_TEST depends on SND_SOC select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO help - Say Y if you want to enable ASoC support for STM32 + Say Y if you want to enable SAI for STM32 + +config SND_SOC_STM32_I2S + tristate "STM32 I2S interface (SPI/I2S block) support" + depends on ARCH_STM32 || COMPILE_TEST + depends on SND_SOC + select SND_SOC_GENERIC_DMAENGINE_PCM + select REGMAP_MMIO + help + Say Y if you want to enable I2S for STM32 + +endmenu diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile index 82519313c0b4..4140c67fa47b 100644 --- a/sound/soc/stm/Makefile +++ b/sound/soc/stm/Makefile @@ -1,10 +1,10 @@ # SAI snd-soc-stm32-sai-sub-objs := stm32_sai_sub.o -obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai-sub.o +obj-$(CONFIG_SND_SOC_STM32_SAI) += snd-soc-stm32-sai-sub.o snd-soc-stm32-sai-objs := stm32_sai.o -obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai.o +obj-$(CONFIG_SND_SOC_STM32_SAI) += snd-soc-stm32-sai.o # I2S snd-soc-stm32-i2s-objs := stm32_i2s.o -obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-i2s.o +obj-$(CONFIG_SND_SOC_STM32_I2S) += snd-soc-stm32-i2s.o From 939df3ada789ccd61a01721df8fc7955aab3aad7 Mon Sep 17 00:00:00 2001 From: Ramesh Babu Date: Mon, 19 Jun 2017 11:59:19 +0530 Subject: [PATCH 333/418] ASoC: Intel: Skylake: Add deep buffer support With this patch, the dma buffer size is fetched from topology binary. This buffer size is applicable for gateway copier modules. Now that we can configure DSP dma buffer size, the device can support deep buffer playback. DSP fetches large buffer and can result fewer wakes, which helps in power reduction. Signed-off-by: Ramesh Babu Signed-off-by: Subhransu S. Prusty Acked-By: Vinod Koul Signed-off-by: Mark Brown --- include/uapi/sound/snd_sst_tokens.h | 5 ++++- sound/soc/intel/skylake/skl-topology.c | 4 ++++ sound/soc/intel/skylake/skl-topology.h | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/uapi/sound/snd_sst_tokens.h b/include/uapi/sound/snd_sst_tokens.h index 89b82f6256ad..dedb2056160d 100644 --- a/include/uapi/sound/snd_sst_tokens.h +++ b/include/uapi/sound/snd_sst_tokens.h @@ -161,6 +161,8 @@ * * %SKL_TKL_U32_D0I3_CAPS: Specifies the D0i3 capability for module * + * %SKL_TKN_U32_DMA_BUF_SIZE: DMA buffer size in millisec + * * module_id and loadable flags dont have tokens as these values will be * read from the DSP FW manifest */ @@ -215,7 +217,8 @@ enum SKL_TKNS { SKL_TKN_U32_PMODE, SKL_TKL_U32_D0I3_CAPS, /* Typo added at v4.10 */ SKL_TKN_U32_D0I3_CAPS = SKL_TKL_U32_D0I3_CAPS, - SKL_TKN_MAX = SKL_TKN_U32_D0I3_CAPS, + SKL_TKN_U32_DMA_BUF_SIZE, + SKL_TKN_MAX = SKL_TKN_U32_DMA_BUF_SIZE, }; #endif diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 212cee71d586..9569f118e97e 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -2212,6 +2212,10 @@ static int skl_tplg_get_token(struct device *dev, break; + case SKL_TKN_U32_DMA_BUF_SIZE: + mconfig->dma_buffer_size = tkn_elem->value; + break; + case SKL_TKN_U8_IN_PIN_TYPE: case SKL_TKN_U8_OUT_PIN_TYPE: case SKL_TKN_U8_CONN_TYPE: diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 3f51a0a00093..c25e8868b84e 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -321,6 +321,7 @@ struct skl_module_cfg { u32 vbus_id; u32 mem_pages; enum d0i3_capability d0i3_caps; + u32 dma_buffer_size; /* in milli seconds */ struct skl_module_pin *m_in_pin; struct skl_module_pin *m_out_pin; enum skl_module_type m_type; From f6e6ab1d16ec9dafa65557b5637f5217b32702ef Mon Sep 17 00:00:00 2001 From: Ramesh Babu Date: Mon, 19 Jun 2017 11:59:20 +0530 Subject: [PATCH 334/418] ASoC: Intel: Skylake: Fix dma buffer size calculation DMA buffer size for gateway copier will be calculated based on: For host DMA copier: Input buffer size (ibs) for output direction (playback) Output buffer size (obs) for input direction (capture) For link DMA copier: IBS for input direction (capture) OBS for output direction (playback) Update the driver to use the above. Signed-off-by: Ramesh Babu Signed-off-by: Subhransu S. Prusty Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 29 ++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 5a465020ebd8..eca85827dbd2 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -507,6 +507,8 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, struct skl_module_cfg *mconfig, struct skl_cpr_cfg *cpr_mconfig) { + u32 dma_io_buf; + cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(ctx, mconfig); if (cpr_mconfig->gtw_cfg.node_id == SKL_NON_GATEWAY_CPR_NODE_ID) { @@ -514,10 +516,29 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, return; } - if (SKL_CONN_SOURCE == mconfig->hw_conn_type) - cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->obs; - else - cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->ibs; + switch (mconfig->hw_conn_type) { + case SKL_CONN_SOURCE: + if (mconfig->dev_type == SKL_DEVICE_HDAHOST) + dma_io_buf = mconfig->ibs; + else + dma_io_buf = mconfig->obs; + break; + + case SKL_CONN_SINK: + if (mconfig->dev_type == SKL_DEVICE_HDAHOST) + dma_io_buf = mconfig->obs; + else + dma_io_buf = mconfig->ibs; + break; + + default: + dev_warn(ctx->dev, "wrong connection type: %d\n", + mconfig->hw_conn_type); + return; + } + + cpr_mconfig->gtw_cfg.dma_buffer_size = + mconfig->dma_buffer_size * dma_io_buf; cpr_mconfig->cpr_feature_mask = 0; cpr_mconfig->gtw_cfg.config_length = 0; From 1f0f8bde45a7ea843bb2e7a8f45f255b23cdc2e7 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Mon, 19 Jun 2017 11:59:21 +0530 Subject: [PATCH 335/418] ASoC: skl_rt286: Add deepbuffer dai link This patch adds the deepbuffer device which can be opened with a bigger buffer size. The application can disable interrupts and sleep for longer duration. Signed-off-by: Subhransu S. Prusty Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_rt286.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index e08c71625fd0..2bc4cfca594e 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -43,6 +43,7 @@ struct skl_rt286_private { enum { SKL_DPCM_AUDIO_PB = 0, + SKL_DPCM_AUDIO_DB_PB, SKL_DPCM_AUDIO_CP, SKL_DPCM_AUDIO_REF_CP, SKL_DPCM_AUDIO_DMIC_CP, @@ -310,6 +311,23 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { .dpcm_playback = 1, .ops = &skylake_rt286_fe_ops, }, + [SKL_DPCM_AUDIO_DB_PB] = { + .name = "Skl Deepbuffer Port", + .stream_name = "Deep Buffer Audio", + .cpu_dai_name = "Deepbuffer Pin", + .platform_name = "0000:00:1f.3", + .nonatomic = 1, + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST + }, + .dpcm_playback = 1, + .ops = &skylake_rt286_fe_ops, + + }, [SKL_DPCM_AUDIO_CP] = { .name = "Skl Audio Capture Port", .stream_name = "Audio Record", From 2a0c2189d8170d52da64543cbf955f0908c15e70 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Mon, 19 Jun 2017 10:56:33 +0100 Subject: [PATCH 336/418] ASoC: da7219: Fix HP detection procedure for all MCLK frequencies Currently when HP detection procedure runs for certain MCLK frequencies, when PLL is bypassed, the procedure will incorrectly report Lineout instead of Headphones due to timing incosistencies. To avoid this problem, the PLL is temporarily enabled (if currently bypassed and MCLK present) to provide consistent timings for the procedure, regardless of MCLK frequency. Signed-off-by: Adam Thomson Acked-by: Sathyanarayana Nujella Signed-off-by: Mark Brown --- sound/soc/codecs/da7219-aad.c | 31 +++++++++++++++----- sound/soc/codecs/da7219.c | 53 ++++++++++++++++++++++++----------- sound/soc/codecs/da7219.h | 5 +++- 3 files changed, 64 insertions(+), 25 deletions(-) diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index 6274d79c1353..1d1d10dd92ae 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -115,19 +115,21 @@ static void da7219_aad_hptest_work(struct work_struct *work) struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); u16 tonegen_freq_hptest; - u8 pll_srm_sts, gain_ramp_ctrl, accdet_cfg8; + u8 pll_srm_sts, pll_ctrl, gain_ramp_ctrl, accdet_cfg8; int report = 0, ret = 0; - /* Lock DAPM and any Kcontrols that are affected by this test */ + /* Lock DAPM, Kcontrols affected by this test and the PLL */ snd_soc_dapm_mutex_lock(dapm); - mutex_lock(&da7219->lock); + mutex_lock(&da7219->ctrl_lock); + mutex_lock(&da7219->pll_lock); /* Ensure MCLK is available for HP test procedure */ if (da7219->mclk) { ret = clk_prepare_enable(da7219->mclk); if (ret) { dev_err(codec->dev, "Failed to enable mclk - %d\n", ret); - mutex_unlock(&da7219->lock); + mutex_unlock(&da7219->pll_lock); + mutex_unlock(&da7219->ctrl_lock); snd_soc_dapm_mutex_unlock(dapm); return; } @@ -136,12 +138,21 @@ static void da7219_aad_hptest_work(struct work_struct *work) /* * If MCLK not present, then we're using the internal oscillator and * require different frequency settings to achieve the same result. + * + * If MCLK is present, but PLL is not enabled then we enable it here to + * ensure a consistent detection procedure. */ pll_srm_sts = snd_soc_read(codec, DA7219_PLL_SRM_STS); - if (pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) + if (pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) { tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ); - else + + pll_ctrl = snd_soc_read(codec, DA7219_PLL_CTRL); + if ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS) + da7219_set_pll(codec, DA7219_SYSCLK_PLL, + DA7219_PLL_FREQ_OUT_98304); + } else { tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC); + } /* Ensure gain ramping at fastest rate */ gain_ramp_ctrl = snd_soc_read(codec, DA7219_GAIN_RAMP_CTRL); @@ -302,11 +313,17 @@ static void da7219_aad_hptest_work(struct work_struct *work) snd_soc_update_bits(codec, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK, DA7219_HP_R_AMP_OE_MASK); + /* Restore PLL to previous configuration, if re-configured */ + if ((pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) && + ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS)) + da7219_set_pll(codec, DA7219_SYSCLK_MCLK, 0); + /* Remove MCLK, if previously enabled */ if (da7219->mclk) clk_disable_unprepare(da7219->mclk); - mutex_unlock(&da7219->lock); + mutex_unlock(&da7219->pll_lock); + mutex_unlock(&da7219->ctrl_lock); snd_soc_dapm_mutex_unlock(dapm); /* diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 99601627f83c..f71d72c22bfc 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -260,9 +260,9 @@ static int da7219_volsw_locked_get(struct snd_kcontrol *kcontrol, struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); int ret; - mutex_lock(&da7219->lock); + mutex_lock(&da7219->ctrl_lock); ret = snd_soc_get_volsw(kcontrol, ucontrol); - mutex_unlock(&da7219->lock); + mutex_unlock(&da7219->ctrl_lock); return ret; } @@ -274,9 +274,9 @@ static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol, struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); int ret; - mutex_lock(&da7219->lock); + mutex_lock(&da7219->ctrl_lock); ret = snd_soc_put_volsw(kcontrol, ucontrol); - mutex_unlock(&da7219->lock); + mutex_unlock(&da7219->ctrl_lock); return ret; } @@ -288,9 +288,9 @@ static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol, struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); int ret; - mutex_lock(&da7219->lock); + mutex_lock(&da7219->ctrl_lock); ret = snd_soc_get_enum_double(kcontrol, ucontrol); - mutex_unlock(&da7219->lock); + mutex_unlock(&da7219->ctrl_lock); return ret; } @@ -302,9 +302,9 @@ static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol, struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); int ret; - mutex_lock(&da7219->lock); + mutex_lock(&da7219->ctrl_lock); ret = snd_soc_put_enum_double(kcontrol, ucontrol); - mutex_unlock(&da7219->lock); + mutex_unlock(&da7219->ctrl_lock); return ret; } @@ -424,9 +424,9 @@ static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol, u16 val; int ret; - mutex_lock(&da7219->lock); + mutex_lock(&da7219->ctrl_lock); ret = regmap_raw_read(da7219->regmap, reg, &val, sizeof(val)); - mutex_unlock(&da7219->lock); + mutex_unlock(&da7219->ctrl_lock); if (ret) return ret; @@ -458,9 +458,9 @@ static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol, */ val = cpu_to_le16(ucontrol->value.integer.value[0]); - mutex_lock(&da7219->lock); + mutex_lock(&da7219->ctrl_lock); ret = regmap_raw_write(da7219->regmap, reg, &val, sizeof(val)); - mutex_unlock(&da7219->lock); + mutex_unlock(&da7219->ctrl_lock); return ret; } @@ -801,7 +801,7 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w, ++i; msleep(50); } - } while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock)); + } while ((i < DA7219_SRM_CHECK_RETRIES) & (!srm_lock)); if (!srm_lock) dev_warn(codec->dev, "SRM failed to lock\n"); @@ -1129,6 +1129,8 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, return -EINVAL; } + mutex_lock(&da7219->pll_lock); + switch (clk_id) { case DA7219_CLKSRC_MCLK_SQR: snd_soc_update_bits(codec, DA7219_PLL_CTRL, @@ -1141,6 +1143,7 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, break; default: dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id); + mutex_unlock(&da7219->pll_lock); return -EINVAL; } @@ -1152,19 +1155,20 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, if (ret) { dev_err(codec_dai->dev, "Failed to set clock rate %d\n", freq); + mutex_unlock(&da7219->pll_lock); return ret; } } da7219->mclk_rate = freq; + mutex_unlock(&da7219->pll_lock); + return 0; } -static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, - int source, unsigned int fref, unsigned int fout) +int da7219_set_pll(struct snd_soc_codec *codec, int source, unsigned int fout) { - struct snd_soc_codec *codec = codec_dai->codec; struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); u8 pll_ctrl, indiv_bits, indiv; @@ -1237,6 +1241,20 @@ static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, return 0; } +static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int fref, unsigned int fout) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); + int ret; + + mutex_lock(&da7219->pll_lock); + ret = da7219_set_pll(codec, source, fout); + mutex_unlock(&da7219->pll_lock); + + return ret; +} + static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; @@ -1741,7 +1759,8 @@ static int da7219_probe(struct snd_soc_codec *codec) unsigned int rev; int ret; - mutex_init(&da7219->lock); + mutex_init(&da7219->ctrl_lock); + mutex_init(&da7219->pll_lock); /* Regulator configuration */ ret = da7219_handle_supplies(codec); diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index 6baba7455fa1..8d6c3c8c8026 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -810,7 +810,8 @@ struct da7219_priv { bool wakeup_source; struct regulator_bulk_data supplies[DA7219_NUM_SUPPLIES]; struct regmap *regmap; - struct mutex lock; + struct mutex ctrl_lock; + struct mutex pll_lock; struct clk *mclk; unsigned int mclk_rate; @@ -821,4 +822,6 @@ struct da7219_priv { u8 gain_ramp_ctrl; }; +int da7219_set_pll(struct snd_soc_codec *codec, int source, unsigned int fout); + #endif /* __DA7219_H */ From fd0f237572ada2b18fe1e8684ae9fa131b577a17 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Mon, 19 Jun 2017 10:56:34 +0100 Subject: [PATCH 337/418] ASoC: Intel: bxt: Move codec sysclk config to codec_init function The MCLK for DA7219 does not change in this platform, but is currently being configured everytime as part of the platform_clock event handler for DAPM. The upshot of this is that we have unnecessary calls to this function, and it also means that if a stream hasn't yet been started, DA7219 driver does not have the correct MCLK rates programmed and so the HP detection feature does not operate as expected. This patch rectifies this issue by moving the sysclk call to codec_init function so it's only called once at initialisation. Signed-off-by: Adam Thomson Acked-by: Sathyanarayana Nujella Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 3a8c4d954a91..1866e31b6c29 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -89,11 +89,6 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, if (ret) dev_err(card->dev, "failed to stop PLL: %d\n", ret); } else if(SND_SOC_DAPM_EVENT_ON(event)) { - ret = snd_soc_dai_set_sysclk(codec_dai, - DA7219_CLKSRC_MCLK, 19200000, SND_SOC_CLOCK_IN); - if (ret) - dev_err(card->dev, "can't set codec sysclk configuration\n"); - ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM, 0, DA7219_PLL_FREQ_OUT_98304); if (ret) @@ -187,8 +182,17 @@ static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd, static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) { int ret; + struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_codec *codec = rtd->codec; + /* Configure sysclk for codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 19200000, + SND_SOC_CLOCK_IN); + if (ret) { + dev_err(rtd->dev, "can't set codec sysclk configuration\n"); + return ret; + } + /* * Headset buttons map to the google Reference headset. * These can be configured by userspace. From 01b8cedfd0422326caae308641dcadaa85e0ca72 Mon Sep 17 00:00:00 2001 From: Satish Babu Patakokila Date: Fri, 16 Jun 2017 17:33:40 -0700 Subject: [PATCH 338/418] ASoC: compress: Derive substream from stream based on direction Currently compress driver hardcodes direction as playback to get substream from the stream. This results in getting the incorrect substream for compressed capture usecase. To fix this, remove the hardcoding and derive substream based on the stream direction. Signed-off-by: Satish Babu Patakokila Signed-off-by: Banajit Goswami Acked-By: Vinod Koul Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/soc-compress.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index bfd71b873ca2..206f36bf43e8 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -81,7 +81,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_dai *cpu_dai = fe->cpu_dai; struct snd_soc_dpcm *dpcm; @@ -467,7 +468,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; struct snd_soc_dai *cpu_dai = fe->cpu_dai; int ret = 0, stream; From a205c159f9e2db586a5ea475f4d22fa22e78fed8 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 17 Jun 2017 22:25:28 +0800 Subject: [PATCH 339/418] ASoC: zx-i2s: flip I2S master/slave mode The SND_SOC_DAIFMT_MASTER bits are defined to specify the master/slave mode for Codec, not I2S. So the I2S master/slave mode should be flipped according to SND_SOC_DAIFMT_MASTER bits. Signed-off-by: Shawn Guo Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/zte/zx-i2s.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/zte/zx-i2s.c b/sound/soc/zte/zx-i2s.c index a7f7a56e0a2d..8bbad1d72bc5 100644 --- a/sound/soc/zte/zx-i2s.c +++ b/sound/soc/zte/zx-i2s.c @@ -203,13 +203,15 @@ static int zx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: - i2s->master = 1; - val |= ZX_I2S_TIMING_MAST; - break; - case SND_SOC_DAIFMT_CBS_CFS: + /* Codec is master, and I2S is slave. */ i2s->master = 0; val |= ZX_I2S_TIMING_SLAVE; break; + case SND_SOC_DAIFMT_CBS_CFS: + /* Codec is slave, and I2S is master. */ + i2s->master = 1; + val |= ZX_I2S_TIMING_MAST; + break; default: dev_err(cpu_dai->dev, "Unknown master/slave format\n"); return -EINVAL; From c1d25075f4684a3a9a74e1668bdf147f879c5c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20P=2E=20M=C3=B6ller=20Ebner?= Date: Fri, 16 Jun 2017 14:14:16 -0400 Subject: [PATCH 340/418] ALSA: line6: add support for POD HD500X Add support for the Line6 POD HD500X multi effect processor for playback and capture (in/out audio) through USB. Signed-off-by: Hans P. Moller Signed-off-by: Takashi Iwai --- sound/usb/line6/podhd.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c index 6ab23e5aee71..e9b8122c4fe5 100644 --- a/sound/usb/line6/podhd.c +++ b/sound/usb/line6/podhd.c @@ -3,6 +3,7 @@ * * Copyright (C) 2011 Stefan Hajnoczi * Copyright (C) 2015 Andrej Krutak + * Copyright (C) 2017 Hans P. Moller * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -37,7 +38,8 @@ enum { LINE6_PODHD500_0, LINE6_PODHD500_1, LINE6_PODX3, - LINE6_PODX3LIVE + LINE6_PODX3LIVE, + LINE6_PODHD500X }; struct usb_line6_podhd { @@ -372,6 +374,7 @@ static const struct usb_device_id podhd_id_table[] = { { LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 }, { LINE6_IF_NUM(0x414A, 0), .driver_info = LINE6_PODX3 }, { LINE6_IF_NUM(0x414B, 0), .driver_info = LINE6_PODX3LIVE }, + { LINE6_IF_NUM(0x4159, 0), .driver_info = LINE6_PODHD500X }, {} }; @@ -446,6 +449,18 @@ static const struct line6_properties podhd_properties_table[] = { .ep_audio_r = 0x86, .ep_audio_w = 0x02, }, + [LINE6_PODHD500X] = { + .id = "PODHD500X", + .name = "POD HD500X", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM | LINE6_CAP_HWMON, + .altsetting = 1, + .ep_ctrl_r = 0x81, + .ep_ctrl_w = 0x01, + .ctrl_if = 1, + .ep_audio_r = 0x86, + .ep_audio_w = 0x02, + }, }; /* From 8cad7a3db658a0652e4ced46dc44fbc7872f0823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20P=2E=20M=C3=B6ller=20Ebner?= Date: Fri, 16 Jun 2017 14:14:17 -0400 Subject: [PATCH 341/418] ALSA: line6: remove unnecessary initialization to PODHD500X Remove Initialization from POD HD500X because it's not needed. Every time the device is connected dmesg gives the following output: "receive length failed (error -11)". To solve this problem, another flags is introduced (LINE6_CAP_CONTROL_INFO) and it is only used for PODX3 in: sysfs entries, call podhd_startup_finalize(pod) and disconnection. With this patch the error disappear. Signed-off-by: Hans P. Moller Signed-off-by: Takashi Iwai --- sound/usb/line6/driver.h | 2 ++ sound/usb/line6/podhd.c | 10 ++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h index a5c2e9ae5f17..dc97895547be 100644 --- a/sound/usb/line6/driver.h +++ b/sound/usb/line6/driver.h @@ -117,6 +117,8 @@ enum { LINE6_CAP_IN_NEEDS_OUT = 1 << 3, /* device uses raw MIDI via USB (data endpoints) */ LINE6_CAP_CONTROL_MIDI = 1 << 4, + /* device provides low-level information */ + LINE6_CAP_CONTROL_INFO = 1 << 5, }; /* diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c index e9b8122c4fe5..956f847a96e4 100644 --- a/sound/usb/line6/podhd.c +++ b/sound/usb/line6/podhd.c @@ -293,7 +293,7 @@ static void podhd_disconnect(struct usb_line6 *line6) { struct usb_line6_podhd *pod = (struct usb_line6_podhd *)line6; - if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) { + if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO) { struct usb_interface *intf; del_timer_sync(&pod->startup_timer); @@ -333,7 +333,9 @@ static int podhd_init(struct usb_line6 *line6, pod->line6.properties->ctrl_if, err); return err; } + } + if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO) { /* create sysfs entries: */ err = snd_card_add_dev_attr(line6->card, &podhd_dev_attr_group); if (err < 0) @@ -350,7 +352,7 @@ static int podhd_init(struct usb_line6 *line6, return err; } - if (!(pod->line6.properties->capabilities & LINE6_CAP_CONTROL)) { + if (!(pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO)) { /* register USB audio system directly */ return podhd_startup_finalize(pod); } @@ -428,7 +430,7 @@ static const struct line6_properties podhd_properties_table[] = { [LINE6_PODX3] = { .id = "PODX3", .name = "POD X3", - .capabilities = LINE6_CAP_CONTROL + .capabilities = LINE6_CAP_CONTROL | LINE6_CAP_CONTROL_INFO | LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT, .altsetting = 1, .ep_ctrl_r = 0x81, @@ -440,7 +442,7 @@ static const struct line6_properties podhd_properties_table[] = { [LINE6_PODX3LIVE] = { .id = "PODX3LIVE", .name = "POD X3 LIVE", - .capabilities = LINE6_CAP_CONTROL + .capabilities = LINE6_CAP_CONTROL | LINE6_CAP_CONTROL_INFO | LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT, .altsetting = 1, .ep_ctrl_r = 0x81, From a4b4793f640b72af3e2bb2a1ad79725c103d5e40 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 14 Jun 2017 07:26:00 +0200 Subject: [PATCH 342/418] ALSA: hda - Add AZX_DRIVER_SKL for simplification We checked the quirks specific to the recent Intel chips by checking the PCI IDs manually, but it's becoming messy with lots of IS_SKL() and other macros, as the amount accumulated. For simplification, here the new AZX_DRIVER_SKL type is introduced, and check chip->driver_type instead of the manual PCI ID. The short name for this is still "HDA Intel PCH", so that it doesn't break the existing user-space unnecessarily. Suggested-by: Vinod Koul Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 47 +++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 01eb1dc7b5b3..07ea7f48aa01 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -263,6 +263,7 @@ enum { AZX_DRIVER_ICH, AZX_DRIVER_PCH, AZX_DRIVER_SCH, + AZX_DRIVER_SKL, AZX_DRIVER_HDMI, AZX_DRIVER_ATI, AZX_DRIVER_ATIHDMI, @@ -364,23 +365,13 @@ enum { ((pci)->device == 0x0d0c) || \ ((pci)->device == 0x160c)) -#define IS_SKL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa170) -#define IS_SKL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d70) -#define IS_KBL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa171) -#define IS_KBL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d71) -#define IS_KBL_H(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa2f0) #define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) -#define IS_BXT_T(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x1a98) -#define IS_GLK(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x3198) -#define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348) -#define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci) || \ - IS_BXT_T(pci) || IS_KBL(pci) || IS_KBL_LP(pci) || \ - IS_KBL_H(pci) || IS_GLK(pci) || IS_CFL(pci)) static char *driver_short_names[] = { [AZX_DRIVER_ICH] = "HDA Intel", [AZX_DRIVER_PCH] = "HDA Intel PCH", [AZX_DRIVER_SCH] = "HDA Intel MID", + [AZX_DRIVER_SKL] = "HDA Intel PCH", /* kept old name for compatibility */ [AZX_DRIVER_HDMI] = "HDA Intel HDMI", [AZX_DRIVER_ATI] = "HDA ATI SB", [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI", @@ -644,13 +635,13 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) snd_hdac_set_codec_wakeup(bus, true); - if (IS_SKL_PLUS(pci)) { + if (chip->driver_type == AZX_DRIVER_SKL) { pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val); val = val & ~INTEL_HDA_CGCTL_MISCBDCGE; pci_write_config_dword(pci, INTEL_HDA_CGCTL, val); } azx_init_chip(chip, full_reset); - if (IS_SKL_PLUS(pci)) { + if (chip->driver_type == AZX_DRIVER_SKL) { pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val); val = val | INTEL_HDA_CGCTL_MISCBDCGE; pci_write_config_dword(pci, INTEL_HDA_CGCTL, val); @@ -1075,9 +1066,11 @@ static int azx_resume(struct device *dev) */ static int azx_freeze_noirq(struct device *dev) { + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip = card->private_data; struct pci_dev *pci = to_pci_dev(dev); - if (IS_SKL_PLUS(pci)) + if (chip->driver_type == AZX_DRIVER_SKL) pci_set_power_state(pci, PCI_D3hot); return 0; @@ -1085,9 +1078,11 @@ static int azx_freeze_noirq(struct device *dev) static int azx_thaw_noirq(struct device *dev) { + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip = card->private_data; struct pci_dev *pci = to_pci_dev(dev); - if (IS_SKL_PLUS(pci)) + if (chip->driver_type == AZX_DRIVER_SKL) pci_set_power_state(pci, PCI_D0); return 0; @@ -1497,7 +1492,7 @@ static int check_position_fix(struct azx *chip, int fix) dev_dbg(chip->card->dev, "Using LPIB position fix\n"); return POS_FIX_LPIB; } - if (IS_SKL_PLUS(chip->pci)) { + if (chip->driver_type == AZX_DRIVER_SKL) { dev_dbg(chip->card->dev, "Using SKL position fix\n"); return POS_FIX_SKL; } @@ -1798,7 +1793,7 @@ static int azx_first_init(struct azx *chip) return -ENXIO; } - if (IS_SKL_PLUS(pci)) + if (chip->driver_type == AZX_DRIVER_SKL) snd_hdac_bus_parse_capabilities(bus); /* @@ -2367,31 +2362,31 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Sunrise Point */ { PCI_DEVICE(0x8086, 0xa170), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, /* Sunrise Point-LP */ { PCI_DEVICE(0x8086, 0x9d70), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, /* Kabylake */ { PCI_DEVICE(0x8086, 0xa171), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, /* Kabylake-LP */ { PCI_DEVICE(0x8086, 0x9d71), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, /* Kabylake-H */ { PCI_DEVICE(0x8086, 0xa2f0), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, /* Coffelake */ { PCI_DEVICE(0x8086, 0xa348), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE}, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, /* Broxton-P(Apollolake) */ { PCI_DEVICE(0x8086, 0x5a98), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, /* Broxton-T */ { PCI_DEVICE(0x8086, 0x1a98), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, /* Gemini-Lake */ { PCI_DEVICE(0x8086, 0x3198), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, /* Haswell */ { PCI_DEVICE(0x8086, 0x0a0c), .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, From eb8d0eaaf84b0398533a7c091a0b65663f2fd7ea Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 19 Jun 2017 17:49:48 +0200 Subject: [PATCH 343/418] ALSA: hda: Fix potential race at unregistration and unsol events When the codec device is unregistered / freed, it may release the resource while being used in an unsolicited event like the jack detection work. This leads to use-after-free. The fix here is to unregister the device at first, i.e. removing the codec from the list, then flushing the pending works to assure that all unsol events are gone. After this point, we're free from accessing the codec via unsol events, thus can release the resources gracefully. The issue was spotted originally by Intel CI, but it couldn't be reproduced reliably by its nature. So let's hope this fix really addresses the whole issues. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=196045 Reported-by: Martin Peres Signed-off-by: Takashi Iwai --- sound/hda/hdac_bus.c | 1 + sound/hda/hdac_device.c | 1 + 2 files changed, 2 insertions(+) diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c index 0e81ea89a596..714a51721a31 100644 --- a/sound/hda/hdac_bus.c +++ b/sound/hda/hdac_bus.c @@ -212,5 +212,6 @@ void snd_hdac_bus_remove_device(struct hdac_bus *bus, bus->caddr_tbl[codec->addr] = NULL; clear_bit(codec->addr, &bus->codec_powered); bus->num_codecs--; + flush_work(&bus->unsol_work); } EXPORT_SYMBOL_GPL(snd_hdac_bus_remove_device); diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index 03c9872c31cf..19deb306facb 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -159,6 +159,7 @@ void snd_hdac_device_unregister(struct hdac_device *codec) if (device_is_registered(&codec->dev)) { hda_widget_sysfs_exit(codec); device_del(&codec->dev); + snd_hdac_bus_remove_device(codec->bus, codec); } } EXPORT_SYMBOL_GPL(snd_hdac_device_unregister); From aa30db060121f688d01f74f8d3fe603f7c4c731c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 16 Jun 2017 22:29:55 +0200 Subject: [PATCH 344/418] ALSA: pcm: Fix possible inconsistent appl_ptr update via mmap The ALSA PCM core refers to the appl_ptr value stored on the mmapped page that is shared between kernel and user-space. Although the reference is performed in the PCM stream lock, it doesn't guarantee the atomic access when the value gets updated concurrently from the user-space on another CPU. In most of codes, this is no big problem, but still there are a few places that may result in slight inconsistencies because they access runtime->control->appl_ptr multiple times; that is, the second read might be a different value from the first value. It can be even backward or jumping, as we have no control for it. Hence, the calculation may give an unexpected value. Luckily, there is no security vulnerability by that, as far as I've checked. But still we should address it. This patch tries to reduce such possible cases. The fix is simple -- we just read once, store it to a local variable and use it for the rest calculations. The READ_ONCE() macro is used for it in order to avoid the ill-effect by possible compiler optimizations. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index e8131c060c86..e76d55a4d1b2 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -65,15 +65,16 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram if (runtime->silence_size < runtime->boundary) { snd_pcm_sframes_t noise_dist, n; - if (runtime->silence_start != runtime->control->appl_ptr) { - n = runtime->control->appl_ptr - runtime->silence_start; + snd_pcm_uframes_t appl_ptr = READ_ONCE(runtime->control->appl_ptr); + if (runtime->silence_start != appl_ptr) { + n = appl_ptr - runtime->silence_start; if (n < 0) n += runtime->boundary; if ((snd_pcm_uframes_t)n < runtime->silence_filled) runtime->silence_filled -= n; else runtime->silence_filled = 0; - runtime->silence_start = runtime->control->appl_ptr; + runtime->silence_start = appl_ptr; } if (runtime->silence_filled >= runtime->buffer_size) return; @@ -2203,7 +2204,9 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, continue; /* draining */ } frames = size > avail ? avail : size; - cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; + appl_ptr = READ_ONCE(runtime->control->appl_ptr); + appl_ofs = appl_ptr % runtime->buffer_size; + cont = runtime->buffer_size - appl_ofs; if (frames > cont) frames = cont; if (snd_BUG_ON(!frames)) { @@ -2211,8 +2214,6 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, snd_pcm_stream_unlock_irq(substream); return -EINVAL; } - appl_ptr = runtime->control->appl_ptr; - appl_ofs = appl_ptr % runtime->buffer_size; snd_pcm_stream_unlock_irq(substream); err = writer(substream, appl_ofs, data, offset, frames, transfer); From 71683c32dee66cdb244a25490823731db1401dce Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Tue, 20 Jun 2017 16:33:50 +0800 Subject: [PATCH 345/418] ALSA: hda/realtek - Support headset mode for ALC234/ALC274/ALC294 This patch will enable headset mode for ALC234/ALC274/ALC294 platform. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 68 ++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 17fe05da0119..082b2db95056 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3841,6 +3841,16 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) UPDATE_COEF(0x4a, 3<<10, 0), {} }; + static struct coef_fw coef0274[] = { + UPDATE_COEF(0x4a, 0x0100, 0), + UPDATE_COEFEX(0x57, 0x05, 0x4000, 0), + UPDATE_COEF(0x6b, 0xf000, 0x5000), + UPDATE_COEF(0x4a, 0x0010, 0), + UPDATE_COEF(0x4a, 0x0c00, 0x0c00), + WRITE_COEF(0x45, 0x5289), + UPDATE_COEF(0x4a, 0x0c00, 0), + {} + }; switch (codec->core.vendor_id) { case 0x10ec0255: @@ -3851,6 +3861,11 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) alc_process_coef_fw(codec, coef0256); alc_process_coef_fw(codec, coef0255); break; + case 0x10ec0234: + case 0x10ec0274: + case 0x10ec0294: + alc_process_coef_fw(codec, coef0274); + break; case 0x10ec0233: case 0x10ec0283: alc_process_coef_fw(codec, coef0233); @@ -3928,7 +3943,12 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, UPDATE_COEF(0x63, 3<<14, 0), {} }; - + static struct coef_fw coef0274[] = { + UPDATE_COEFEX(0x57, 0x05, 0x4000, 0x4000), + UPDATE_COEF(0x4a, 0x0010, 0), + UPDATE_COEF(0x6b, 0xf000, 0), + {} + }; switch (codec->core.vendor_id) { case 0x10ec0255: @@ -3938,6 +3958,14 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, alc_process_coef_fw(codec, coef0255); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; + case 0x10ec0234: + case 0x10ec0274: + case 0x10ec0294: + alc_write_coef_idx(codec, 0x45, 0x4689); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + alc_process_coef_fw(codec, coef0274); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; case 0x10ec0233: case 0x10ec0283: alc_write_coef_idx(codec, 0x45, 0xc429); @@ -4035,6 +4063,13 @@ static void alc_headset_mode_default(struct hda_codec *codec) WRITE_COEF(0xb7, 0x802b), {} }; + static struct coef_fw coef0274[] = { + WRITE_COEF(0x45, 0x4289), + UPDATE_COEF(0x4a, 0x0010, 0x0010), + UPDATE_COEF(0x6b, 0x0f00, 0), + UPDATE_COEF(0x49, 0x0300, 0x0300), + {} + }; switch (codec->core.vendor_id) { case 0x10ec0225: @@ -4046,6 +4081,11 @@ static void alc_headset_mode_default(struct hda_codec *codec) case 0x10ec0256: alc_process_coef_fw(codec, coef0255); break; + case 0x10ec0234: + case 0x10ec0274: + case 0x10ec0294: + alc_process_coef_fw(codec, coef0274); + break; case 0x10ec0233: case 0x10ec0283: alc_process_coef_fw(codec, coef0233); @@ -4131,6 +4171,11 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) case 0x10ec0256: alc_process_coef_fw(codec, coef0256); break; + case 0x10ec0234: + case 0x10ec0274: + case 0x10ec0294: + alc_write_coef_idx(codec, 0x45, 0xd689); + break; case 0x10ec0233: case 0x10ec0283: alc_process_coef_fw(codec, coef0233); @@ -4225,6 +4270,11 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) case 0x10ec0256: alc_process_coef_fw(codec, coef0256); break; + case 0x10ec0234: + case 0x10ec0274: + case 0x10ec0294: + alc_write_coef_idx(codec, 0x45, 0xe689); + break; case 0x10ec0233: case 0x10ec0283: alc_process_coef_fw(codec, coef0233); @@ -4288,6 +4338,13 @@ static void alc_determine_headset_type(struct hda_codec *codec) UPDATE_COEF(0x49, 1<<8, 1<<8), {} }; + static struct coef_fw coef0274[] = { + UPDATE_COEF(0x4a, 0x0010, 0), + UPDATE_COEF(0x4a, 0x8000, 0), + WRITE_COEF(0x45, 0xd289), + UPDATE_COEF(0x49, 0x0300, 0x0300), + {} + }; switch (codec->core.vendor_id) { case 0x10ec0255: @@ -4297,6 +4354,14 @@ static void alc_determine_headset_type(struct hda_codec *codec) val = alc_read_coef_idx(codec, 0x46); is_ctia = (val & 0x0070) == 0x0070; break; + case 0x10ec0234: + case 0x10ec0274: + case 0x10ec0294: + alc_process_coef_fw(codec, coef0274); + msleep(80); + val = alc_read_coef_idx(codec, 0x46); + is_ctia = (val & 0x00f0) == 0x00f0; + break; case 0x10ec0233: case 0x10ec0283: alc_write_coef_idx(codec, 0x45, 0xd029); @@ -6568,6 +6633,7 @@ static int patch_alc269(struct hda_codec *codec) case 0x10ec0274: case 0x10ec0294: spec->codec_variant = ALC269_TYPE_ALC294; + alc_update_coef_idx(codec, 0x6b, 0x0018, (1<<4) | (1<<3)); /* UAJ MIC Vref control by verb */ break; case 0x10ec0700: case 0x10ec0701: From c2d6af53a43fd8bb528eac8f31ffb666e9c74cf7 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Wed, 21 Jun 2017 14:50:54 +0800 Subject: [PATCH 346/418] ALSA: hda/realtek - Add default procedure for suspend and resume state Except ALC269. This will reduce pop noise from headset or headphone. If codec enter to power save state, when plug headset or headphone.... It has a chance to cut off power by system. Our new codec use this procedure will be more stable during suspend and resume state. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 65 ++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 082b2db95056..c4a1b496d7bb 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3130,6 +3130,67 @@ static void alc256_shutup(struct hda_codec *codec) snd_hda_shutup_pins(codec); } +static void alc_default_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; + bool hp_pin_sense; + + if (!hp_pin) + return; + + msleep(30); + + hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); + + if (hp_pin_sense) + msleep(2); + + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + + if (hp_pin_sense) + msleep(85); + + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + + if (hp_pin_sense) + msleep(100); +} + +static void alc_default_shutup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; + bool hp_pin_sense; + + if (!hp_pin) { + alc269_shutup(codec); + return; + } + + hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); + + if (hp_pin_sense) + msleep(2); + + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + + if (hp_pin_sense) + msleep(85); + + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + + if (hp_pin_sense) + msleep(100); + + alc_auto_setup_eapd(codec, false); + snd_hda_shutup_pins(codec); +} + static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg, unsigned int val) { @@ -6536,7 +6597,8 @@ static int patch_alc269(struct hda_codec *codec) codec->patch_ops.suspend = alc269_suspend; codec->patch_ops.resume = alc269_resume; #endif - spec->shutup = alc269_shutup; + spec->shutup = alc_default_shutup; + spec->init_hook = alc_default_init; snd_hda_pick_fixup(codec, alc269_fixup_models, alc269_fixup_tbl, alc269_fixups); @@ -6576,6 +6638,7 @@ static int patch_alc269(struct hda_codec *codec) } if (err < 0) goto error; + spec->shutup = alc269_shutup; spec->init_hook = alc269_fill_coef; alc269_fill_coef(codec); break; From 372f69a01be178b896ebb8ef7021e0b165084b25 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 21 Jun 2017 04:37:18 +0000 Subject: [PATCH 347/418] ASoC: fsl: mpc5200_dma: remove unused psc_dma MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit linux/sound/soc/fsl/mpc5200_dma.c:305:18: warning: unused variable \ psc_dma’ [-Wunused-variable] Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_dma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index 0b82e209b6e3..1f7e70bfbd55 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c @@ -302,7 +302,6 @@ static int psc_dma_new(struct snd_soc_pcm_runtime *rtd) struct snd_card *card = rtd->card->snd_card; struct snd_soc_dai *dai = rtd->cpu_dai; struct snd_pcm *pcm = rtd->pcm; - struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); size_t size = psc_dma_hardware.buffer_bytes_max; int rc; From 73d7ee2e831f106ca5c745b2cf4fdbac5a4e9e4e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 21 Jun 2017 04:38:13 +0000 Subject: [PATCH 348/418] ASoC: pxa: add COMPILE_TEST on SND_PXA2XX_SOC It doesn't use asm header. We can add COMPILE_TEST Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/pxa/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 823b5a236d8d..960744e46edc 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -1,6 +1,6 @@ config SND_PXA2XX_SOC tristate "SoC Audio for the Intel PXA2xx chip" - depends on ARCH_PXA + depends on ARCH_PXA || COMPILE_TEST select SND_PXA2XX_LIB help Say Y or M if you want to add support for codecs attached to From 0507cb0226acfd7ba114c59f6a76fdc7a1c6b01e Mon Sep 17 00:00:00 2001 From: olivier moysan Date: Tue, 20 Jun 2017 11:58:46 +0200 Subject: [PATCH 349/418] ASoC: stm32: Add DT bindings for SPDIFRX interface Add documentation of device tree bindings for the STM32 SPDIFRX interface. Signed-off-by: olivier moysan Signed-off-by: Mark Brown --- .../bindings/sound/st,stm32-spdifrx.txt | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt diff --git a/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt b/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt new file mode 100644 index 000000000000..33826f2459fa --- /dev/null +++ b/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt @@ -0,0 +1,56 @@ +STMicroelectronics STM32 S/PDIF receiver (SPDIFRX). + +The SPDIFRX peripheral, is designed to receive an S/PDIF flow compliant with +IEC-60958 and IEC-61937. + +Required properties: + - compatible: should be "st,stm32h7-spdifrx" + - reg: cpu DAI IP base address and size + - clocks: must contain an entry for kclk (used as S/PDIF signal reference) + - clock-names: must contain "kclk" + - interrupts: cpu DAI interrupt line + - dmas: DMA specifiers for audio data DMA and iec control flow DMA + See STM32 DMA bindings, Documentation/devicetree/bindings/dma/stm32-dma.txt + - dma-names: two dmas have to be defined, "rx" and "rx-ctrl" + +Optional properties: + - resets: Reference to a reset controller asserting the SPDIFRX + +The device node should contain one 'port' child node with one child 'endpoint' +node, according to the bindings defined in Documentation/devicetree/bindings/ +graph.txt. + +Example: +spdifrx: spdifrx@40004000 { + compatible = "st,stm32h7-spdifrx"; + reg = <0x40004000 0x400>; + clocks = <&rcc SPDIFRX_CK>; + clock-names = "kclk"; + interrupts = <97>; + dmas = <&dmamux1 2 93 0x400 0x0>, + <&dmamux1 3 94 0x400 0x0>; + dma-names = "rx", "rx-ctrl"; + pinctrl-0 = <&spdifrx_pins>; + pinctrl-names = "default"; + + spdifrx_port: port { + cpu_endpoint: endpoint { + remote-endpoint = <&codec_endpoint>; + }; + }; +}; + +spdif_in: spdif-in { + compatible = "linux,spdif-dir"; + + codec_port: port { + codec_endpoint: endpoint { + remote-endpoint = <&cpu_endpoint>; + }; + }; +}; + +soundcard { + compatible = "audio-graph-card"; + dais = <&spdifrx_port>; +}; From 03e4d5d56fa5cbd47d0a8964db3722e7977723a3 Mon Sep 17 00:00:00 2001 From: olivier moysan Date: Tue, 20 Jun 2017 11:58:47 +0200 Subject: [PATCH 350/418] ASoC: stm32: Add SPDIFRX support Add SPDIFRX support to STM32. Signed-off-by: olivier moysan Signed-off-by: Mark Brown --- sound/soc/stm/Kconfig | 10 + sound/soc/stm/Makefile | 4 + sound/soc/stm/stm32_spdifrx.c | 998 ++++++++++++++++++++++++++++++++++ 3 files changed, 1012 insertions(+) create mode 100644 sound/soc/stm/stm32_spdifrx.c diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index 23600a5dd46f..3398e6c57f37 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -18,4 +18,14 @@ config SND_SOC_STM32_I2S help Say Y if you want to enable I2S for STM32 +config SND_SOC_STM32_SPDIFRX + tristate "STM32 S/PDIF receiver (SPDIFRX) support" + depends on ARCH_STM32 || COMPILE_TEST + depends on SND_SOC + select SND_SOC_GENERIC_DMAENGINE_PCM + select REGMAP_MMIO + select SND_SOC_SPDIF + help + Say Y if you want to enable S/PDIF capture for STM32 + endmenu diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile index 4140c67fa47b..4ed22e648a9a 100644 --- a/sound/soc/stm/Makefile +++ b/sound/soc/stm/Makefile @@ -8,3 +8,7 @@ obj-$(CONFIG_SND_SOC_STM32_SAI) += snd-soc-stm32-sai.o # I2S snd-soc-stm32-i2s-objs := stm32_i2s.o obj-$(CONFIG_SND_SOC_STM32_I2S) += snd-soc-stm32-i2s.o + +# SPDIFRX +snd-soc-stm32-spdifrx-objs := stm32_spdifrx.o +obj-$(CONFIG_SND_SOC_STM32_SPDIFRX) += snd-soc-stm32-spdifrx.o diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c new file mode 100644 index 000000000000..4e4250bdb75a --- /dev/null +++ b/sound/soc/stm/stm32_spdifrx.c @@ -0,0 +1,998 @@ +/* + * STM32 ALSA SoC Digital Audio Interface (SPDIF-rx) driver. + * + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author(s): Olivier Moysan for STMicroelectronics. + * + * License terms: GPL V2.0. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* SPDIF-rx Register Map */ +#define STM32_SPDIFRX_CR 0x00 +#define STM32_SPDIFRX_IMR 0x04 +#define STM32_SPDIFRX_SR 0x08 +#define STM32_SPDIFRX_IFCR 0x0C +#define STM32_SPDIFRX_DR 0x10 +#define STM32_SPDIFRX_CSR 0x14 +#define STM32_SPDIFRX_DIR 0x18 + +/* Bit definition for SPDIF_CR register */ +#define SPDIFRX_CR_SPDIFEN_SHIFT 0 +#define SPDIFRX_CR_SPDIFEN_MASK GENMASK(1, SPDIFRX_CR_SPDIFEN_SHIFT) +#define SPDIFRX_CR_SPDIFENSET(x) ((x) << SPDIFRX_CR_SPDIFEN_SHIFT) + +#define SPDIFRX_CR_RXDMAEN BIT(2) +#define SPDIFRX_CR_RXSTEO BIT(3) + +#define SPDIFRX_CR_DRFMT_SHIFT 4 +#define SPDIFRX_CR_DRFMT_MASK GENMASK(5, SPDIFRX_CR_DRFMT_SHIFT) +#define SPDIFRX_CR_DRFMTSET(x) ((x) << SPDIFRX_CR_DRFMT_SHIFT) + +#define SPDIFRX_CR_PMSK BIT(6) +#define SPDIFRX_CR_VMSK BIT(7) +#define SPDIFRX_CR_CUMSK BIT(8) +#define SPDIFRX_CR_PTMSK BIT(9) +#define SPDIFRX_CR_CBDMAEN BIT(10) +#define SPDIFRX_CR_CHSEL_SHIFT 11 +#define SPDIFRX_CR_CHSEL BIT(SPDIFRX_CR_CHSEL_SHIFT) + +#define SPDIFRX_CR_NBTR_SHIFT 12 +#define SPDIFRX_CR_NBTR_MASK GENMASK(13, SPDIFRX_CR_NBTR_SHIFT) +#define SPDIFRX_CR_NBTRSET(x) ((x) << SPDIFRX_CR_NBTR_SHIFT) + +#define SPDIFRX_CR_WFA BIT(14) + +#define SPDIFRX_CR_INSEL_SHIFT 16 +#define SPDIFRX_CR_INSEL_MASK GENMASK(18, PDIFRX_CR_INSEL_SHIFT) +#define SPDIFRX_CR_INSELSET(x) ((x) << SPDIFRX_CR_INSEL_SHIFT) + +#define SPDIFRX_CR_CKSEN_SHIFT 20 +#define SPDIFRX_CR_CKSEN BIT(20) +#define SPDIFRX_CR_CKSBKPEN BIT(21) + +/* Bit definition for SPDIFRX_IMR register */ +#define SPDIFRX_IMR_RXNEI BIT(0) +#define SPDIFRX_IMR_CSRNEIE BIT(1) +#define SPDIFRX_IMR_PERRIE BIT(2) +#define SPDIFRX_IMR_OVRIE BIT(3) +#define SPDIFRX_IMR_SBLKIE BIT(4) +#define SPDIFRX_IMR_SYNCDIE BIT(5) +#define SPDIFRX_IMR_IFEIE BIT(6) + +#define SPDIFRX_XIMR_MASK GENMASK(6, 0) + +/* Bit definition for SPDIFRX_SR register */ +#define SPDIFRX_SR_RXNE BIT(0) +#define SPDIFRX_SR_CSRNE BIT(1) +#define SPDIFRX_SR_PERR BIT(2) +#define SPDIFRX_SR_OVR BIT(3) +#define SPDIFRX_SR_SBD BIT(4) +#define SPDIFRX_SR_SYNCD BIT(5) +#define SPDIFRX_SR_FERR BIT(6) +#define SPDIFRX_SR_SERR BIT(7) +#define SPDIFRX_SR_TERR BIT(8) + +#define SPDIFRX_SR_WIDTH5_SHIFT 16 +#define SPDIFRX_SR_WIDTH5_MASK GENMASK(30, PDIFRX_SR_WIDTH5_SHIFT) +#define SPDIFRX_SR_WIDTH5SET(x) ((x) << SPDIFRX_SR_WIDTH5_SHIFT) + +/* Bit definition for SPDIFRX_IFCR register */ +#define SPDIFRX_IFCR_PERRCF BIT(2) +#define SPDIFRX_IFCR_OVRCF BIT(3) +#define SPDIFRX_IFCR_SBDCF BIT(4) +#define SPDIFRX_IFCR_SYNCDCF BIT(5) + +#define SPDIFRX_XIFCR_MASK GENMASK(5, 2) + +/* Bit definition for SPDIFRX_DR register (DRFMT = 0b00) */ +#define SPDIFRX_DR0_DR_SHIFT 0 +#define SPDIFRX_DR0_DR_MASK GENMASK(23, SPDIFRX_DR0_DR_SHIFT) +#define SPDIFRX_DR0_DRSET(x) ((x) << SPDIFRX_DR0_DR_SHIFT) + +#define SPDIFRX_DR0_PE BIT(24) + +#define SPDIFRX_DR0_V BIT(25) +#define SPDIFRX_DR0_U BIT(26) +#define SPDIFRX_DR0_C BIT(27) + +#define SPDIFRX_DR0_PT_SHIFT 28 +#define SPDIFRX_DR0_PT_MASK GENMASK(29, SPDIFRX_DR0_PT_SHIFT) +#define SPDIFRX_DR0_PTSET(x) ((x) << SPDIFRX_DR0_PT_SHIFT) + +/* Bit definition for SPDIFRX_DR register (DRFMT = 0b01) */ +#define SPDIFRX_DR1_PE BIT(0) +#define SPDIFRX_DR1_V BIT(1) +#define SPDIFRX_DR1_U BIT(2) +#define SPDIFRX_DR1_C BIT(3) + +#define SPDIFRX_DR1_PT_SHIFT 4 +#define SPDIFRX_DR1_PT_MASK GENMASK(5, SPDIFRX_DR1_PT_SHIFT) +#define SPDIFRX_DR1_PTSET(x) ((x) << SPDIFRX_DR1_PT_SHIFT) + +#define SPDIFRX_DR1_DR_SHIFT 8 +#define SPDIFRX_DR1_DR_MASK GENMASK(31, SPDIFRX_DR1_DR_SHIFT) +#define SPDIFRX_DR1_DRSET(x) ((x) << SPDIFRX_DR1_DR_SHIFT) + +/* Bit definition for SPDIFRX_DR register (DRFMT = 0b10) */ +#define SPDIFRX_DR1_DRNL1_SHIFT 0 +#define SPDIFRX_DR1_DRNL1_MASK GENMASK(15, SPDIFRX_DR1_DRNL1_SHIFT) +#define SPDIFRX_DR1_DRNL1SET(x) ((x) << SPDIFRX_DR1_DRNL1_SHIFT) + +#define SPDIFRX_DR1_DRNL2_SHIFT 16 +#define SPDIFRX_DR1_DRNL2_MASK GENMASK(31, SPDIFRX_DR1_DRNL2_SHIFT) +#define SPDIFRX_DR1_DRNL2SET(x) ((x) << SPDIFRX_DR1_DRNL2_SHIFT) + +/* Bit definition for SPDIFRX_CSR register */ +#define SPDIFRX_CSR_USR_SHIFT 0 +#define SPDIFRX_CSR_USR_MASK GENMASK(15, SPDIFRX_CSR_USR_SHIFT) +#define SPDIFRX_CSR_USRGET(x) (((x) & SPDIFRX_CSR_USR_MASK)\ + >> SPDIFRX_CSR_USR_SHIFT) + +#define SPDIFRX_CSR_CS_SHIFT 16 +#define SPDIFRX_CSR_CS_MASK GENMASK(23, SPDIFRX_CSR_CS_SHIFT) +#define SPDIFRX_CSR_CSGET(x) (((x) & SPDIFRX_CSR_CS_MASK)\ + >> SPDIFRX_CSR_CS_SHIFT) + +#define SPDIFRX_CSR_SOB BIT(24) + +/* Bit definition for SPDIFRX_DIR register */ +#define SPDIFRX_DIR_THI_SHIFT 0 +#define SPDIFRX_DIR_THI_MASK GENMASK(12, SPDIFRX_DIR_THI_SHIFT) +#define SPDIFRX_DIR_THI_SET(x) ((x) << SPDIFRX_DIR_THI_SHIFT) + +#define SPDIFRX_DIR_TLO_SHIFT 16 +#define SPDIFRX_DIR_TLO_MASK GENMASK(28, SPDIFRX_DIR_TLO_SHIFT) +#define SPDIFRX_DIR_TLO_SET(x) ((x) << SPDIFRX_DIR_TLO_SHIFT) + +#define SPDIFRX_SPDIFEN_DISABLE 0x0 +#define SPDIFRX_SPDIFEN_SYNC 0x1 +#define SPDIFRX_SPDIFEN_ENABLE 0x3 + +#define SPDIFRX_IN1 0x1 +#define SPDIFRX_IN2 0x2 +#define SPDIFRX_IN3 0x3 +#define SPDIFRX_IN4 0x4 +#define SPDIFRX_IN5 0x5 +#define SPDIFRX_IN6 0x6 +#define SPDIFRX_IN7 0x7 +#define SPDIFRX_IN8 0x8 + +#define SPDIFRX_NBTR_NONE 0x0 +#define SPDIFRX_NBTR_3 0x1 +#define SPDIFRX_NBTR_15 0x2 +#define SPDIFRX_NBTR_63 0x3 + +#define SPDIFRX_DRFMT_RIGHT 0x0 +#define SPDIFRX_DRFMT_LEFT 0x1 +#define SPDIFRX_DRFMT_PACKED 0x2 + +/* 192 CS bits in S/PDIF frame. i.e 24 CS bytes */ +#define SPDIFRX_CS_BYTES_NB 24 +#define SPDIFRX_UB_BYTES_NB 48 + +/* + * CSR register is retrieved as a 32 bits word + * It contains 1 channel status byte and 2 user data bytes + * 2 S/PDIF frames are acquired to get all CS/UB bits + */ +#define SPDIFRX_CSR_BUF_LENGTH (SPDIFRX_CS_BYTES_NB * 4 * 2) + +/** + * struct stm32_spdifrx_data - private data of SPDIFRX + * @pdev: device data pointer + * @base: mmio register base virtual address + * @regmap: SPDIFRX register map pointer + * @regmap_conf: SPDIFRX register map configuration pointer + * @cs_completion: channel status retrieving completion + * @kclk: kernel clock feeding the SPDIFRX clock generator + * @dma_params: dma configuration data for rx channel + * @substream: PCM substream data pointer + * @dmab: dma buffer info pointer + * @ctrl_chan: dma channel for S/PDIF control bits + * @desc:dma async transaction descriptor + * @slave_config: dma slave channel runtime config pointer + * @phys_addr: SPDIFRX registers physical base address + * @lock: synchronization enabling lock + * @cs: channel status buffer + * @ub: user data buffer + * @irq: SPDIFRX interrupt line + * @refcount: keep count of opened DMA channels + */ +struct stm32_spdifrx_data { + struct platform_device *pdev; + void __iomem *base; + struct regmap *regmap; + const struct regmap_config *regmap_conf; + struct completion cs_completion; + struct clk *kclk; + struct snd_dmaengine_dai_dma_data dma_params; + struct snd_pcm_substream *substream; + struct snd_dma_buffer *dmab; + struct dma_chan *ctrl_chan; + struct dma_async_tx_descriptor *desc; + struct dma_slave_config slave_config; + dma_addr_t phys_addr; + spinlock_t lock; /* Sync enabling lock */ + unsigned char cs[SPDIFRX_CS_BYTES_NB]; + unsigned char ub[SPDIFRX_UB_BYTES_NB]; + int irq; + int refcount; +}; + +static void stm32_spdifrx_dma_complete(void *data) +{ + struct stm32_spdifrx_data *spdifrx = (struct stm32_spdifrx_data *)data; + struct platform_device *pdev = spdifrx->pdev; + u32 *p_start = (u32 *)spdifrx->dmab->area; + u32 *p_end = p_start + (2 * SPDIFRX_CS_BYTES_NB) - 1; + u32 *ptr = p_start; + u16 *ub_ptr = (short *)spdifrx->ub; + int i = 0; + + regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, + SPDIFRX_CR_CBDMAEN, + (unsigned int)~SPDIFRX_CR_CBDMAEN); + + if (!spdifrx->dmab->area) + return; + + while (ptr <= p_end) { + if (*ptr & SPDIFRX_CSR_SOB) + break; + ptr++; + } + + if (ptr > p_end) { + dev_err(&pdev->dev, "Start of S/PDIF block not found\n"); + return; + } + + while (i < SPDIFRX_CS_BYTES_NB) { + spdifrx->cs[i] = (unsigned char)SPDIFRX_CSR_CSGET(*ptr); + *ub_ptr++ = SPDIFRX_CSR_USRGET(*ptr++); + if (ptr > p_end) { + dev_err(&pdev->dev, "Failed to get channel status\n"); + return; + } + i++; + } + + complete(&spdifrx->cs_completion); +} + +static int stm32_spdifrx_dma_ctrl_start(struct stm32_spdifrx_data *spdifrx) +{ + dma_cookie_t cookie; + int err; + + spdifrx->desc = dmaengine_prep_slave_single(spdifrx->ctrl_chan, + spdifrx->dmab->addr, + SPDIFRX_CSR_BUF_LENGTH, + DMA_DEV_TO_MEM, + DMA_CTRL_ACK); + if (!spdifrx->desc) + return -EINVAL; + + spdifrx->desc->callback = stm32_spdifrx_dma_complete; + spdifrx->desc->callback_param = spdifrx; + cookie = dmaengine_submit(spdifrx->desc); + err = dma_submit_error(cookie); + if (err) + return -EINVAL; + + dma_async_issue_pending(spdifrx->ctrl_chan); + + return 0; +} + +static void stm32_spdifrx_dma_ctrl_stop(struct stm32_spdifrx_data *spdifrx) +{ + dmaengine_terminate_async(spdifrx->ctrl_chan); +} + +static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) +{ + int cr, cr_mask, imr, ret; + + /* Enable IRQs */ + imr = SPDIFRX_IMR_IFEIE | SPDIFRX_IMR_SYNCDIE | SPDIFRX_IMR_PERRIE; + ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IMR, imr, imr); + if (ret) + return ret; + + spin_lock(&spdifrx->lock); + + spdifrx->refcount++; + + regmap_read(spdifrx->regmap, STM32_SPDIFRX_CR, &cr); + + if (!(cr & SPDIFRX_CR_SPDIFEN_MASK)) { + /* + * Start sync if SPDIFRX is still in idle state. + * SPDIFRX reception enabled when sync done + */ + dev_dbg(&spdifrx->pdev->dev, "start synchronization\n"); + + /* + * SPDIFRX configuration: + * Wait for activity before starting sync process. This avoid + * to issue sync errors when spdif signal is missing on input. + * Preamble, CS, user, validity and parity error bits not copied + * to DR register. + */ + cr = SPDIFRX_CR_WFA | SPDIFRX_CR_PMSK | SPDIFRX_CR_VMSK | + SPDIFRX_CR_CUMSK | SPDIFRX_CR_PTMSK | SPDIFRX_CR_RXSTEO; + cr_mask = cr; + + cr |= SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC); + cr_mask |= SPDIFRX_CR_SPDIFEN_MASK; + ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, + cr_mask, cr); + if (ret < 0) + dev_err(&spdifrx->pdev->dev, + "Failed to start synchronization\n"); + } + + spin_unlock(&spdifrx->lock); + + return ret; +} + +static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx) +{ + int cr, cr_mask, reg; + + spin_lock(&spdifrx->lock); + + if (--spdifrx->refcount) { + spin_unlock(&spdifrx->lock); + return; + } + + cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_DISABLE); + cr_mask = SPDIFRX_CR_SPDIFEN_MASK | SPDIFRX_CR_RXDMAEN; + + regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, cr_mask, cr); + + regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IMR, + SPDIFRX_XIMR_MASK, 0); + + regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IFCR, + SPDIFRX_XIFCR_MASK, SPDIFRX_XIFCR_MASK); + + /* dummy read to clear CSRNE and RXNE in status register */ + regmap_read(spdifrx->regmap, STM32_SPDIFRX_DR, ®); + regmap_read(spdifrx->regmap, STM32_SPDIFRX_CSR, ®); + + spin_unlock(&spdifrx->lock); +} + +static int stm32_spdifrx_dma_ctrl_register(struct device *dev, + struct stm32_spdifrx_data *spdifrx) +{ + int ret; + + spdifrx->dmab = devm_kzalloc(dev, sizeof(struct snd_dma_buffer), + GFP_KERNEL); + if (!spdifrx->dmab) + return -ENOMEM; + + spdifrx->dmab->dev.type = SNDRV_DMA_TYPE_DEV_IRAM; + spdifrx->dmab->dev.dev = dev; + ret = snd_dma_alloc_pages(spdifrx->dmab->dev.type, dev, + SPDIFRX_CSR_BUF_LENGTH, spdifrx->dmab); + if (ret < 0) { + dev_err(dev, "snd_dma_alloc_pages returned error %d\n", ret); + return ret; + } + + spdifrx->ctrl_chan = dma_request_chan(dev, "rx-ctrl"); + if (!spdifrx->ctrl_chan) { + dev_err(dev, "dma_request_slave_channel failed\n"); + return -EINVAL; + } + + spdifrx->slave_config.direction = DMA_DEV_TO_MEM; + spdifrx->slave_config.src_addr = (dma_addr_t)(spdifrx->phys_addr + + STM32_SPDIFRX_CSR); + spdifrx->slave_config.dst_addr = spdifrx->dmab->addr; + spdifrx->slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + spdifrx->slave_config.src_maxburst = 1; + + ret = dmaengine_slave_config(spdifrx->ctrl_chan, + &spdifrx->slave_config); + if (ret < 0) { + dev_err(dev, "dmaengine_slave_config returned error %d\n", ret); + dma_release_channel(spdifrx->ctrl_chan); + spdifrx->ctrl_chan = NULL; + } + + return ret; +}; + +static const char * const spdifrx_enum_input[] = { + "in0", "in1", "in2", "in3" +}; + +/* By default CS bits are retrieved from channel A */ +static const char * const spdifrx_enum_cs_channel[] = { + "A", "B" +}; + +static SOC_ENUM_SINGLE_DECL(ctrl_enum_input, + STM32_SPDIFRX_CR, SPDIFRX_CR_INSEL_SHIFT, + spdifrx_enum_input); + +static SOC_ENUM_SINGLE_DECL(ctrl_enum_cs_channel, + STM32_SPDIFRX_CR, SPDIFRX_CR_CHSEL_SHIFT, + spdifrx_enum_cs_channel); + +static int stm32_spdifrx_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + + return 0; +} + +static int stm32_spdifrx_ub_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + + return 0; +} + +static int stm32_spdifrx_get_ctrl_data(struct stm32_spdifrx_data *spdifrx) +{ + int ret = 0; + + memset(spdifrx->cs, 0, SPDIFRX_CS_BYTES_NB); + memset(spdifrx->ub, 0, SPDIFRX_UB_BYTES_NB); + + ret = stm32_spdifrx_dma_ctrl_start(spdifrx); + if (ret < 0) + return ret; + + ret = clk_prepare_enable(spdifrx->kclk); + if (ret) { + dev_err(&spdifrx->pdev->dev, "Enable kclk failed: %d\n", ret); + return ret; + } + + ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, + SPDIFRX_CR_CBDMAEN, SPDIFRX_CR_CBDMAEN); + if (ret < 0) + goto end; + + ret = stm32_spdifrx_start_sync(spdifrx); + if (ret < 0) + goto end; + + if (wait_for_completion_interruptible_timeout(&spdifrx->cs_completion, + msecs_to_jiffies(100)) + <= 0) { + dev_err(&spdifrx->pdev->dev, "Failed to get control data\n"); + ret = -EAGAIN; + } + + stm32_spdifrx_stop(spdifrx); + stm32_spdifrx_dma_ctrl_stop(spdifrx); + +end: + clk_disable_unprepare(spdifrx->kclk); + + return ret; +} + +static int stm32_spdifrx_capture_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); + + stm32_spdifrx_get_ctrl_data(spdifrx); + + ucontrol->value.iec958.status[0] = spdifrx->cs[0]; + ucontrol->value.iec958.status[1] = spdifrx->cs[1]; + ucontrol->value.iec958.status[2] = spdifrx->cs[2]; + ucontrol->value.iec958.status[3] = spdifrx->cs[3]; + ucontrol->value.iec958.status[4] = spdifrx->cs[4]; + + return 0; +} + +static int stm32_spdif_user_bits_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); + + stm32_spdifrx_get_ctrl_data(spdifrx); + + ucontrol->value.iec958.status[0] = spdifrx->ub[0]; + ucontrol->value.iec958.status[1] = spdifrx->ub[1]; + ucontrol->value.iec958.status[2] = spdifrx->ub[2]; + ucontrol->value.iec958.status[3] = spdifrx->ub[3]; + ucontrol->value.iec958.status[4] = spdifrx->ub[4]; + + return 0; +} + +static struct snd_kcontrol_new stm32_spdifrx_iec_ctrls[] = { + /* Channel status control */ + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = stm32_spdifrx_info, + .get = stm32_spdifrx_capture_get, + }, + /* User bits control */ + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 User Bit Capture Default", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = stm32_spdifrx_ub_info, + .get = stm32_spdif_user_bits_get, + }, +}; + +static struct snd_kcontrol_new stm32_spdifrx_ctrls[] = { + SOC_ENUM("SPDIFRX input", ctrl_enum_input), + SOC_ENUM("SPDIFRX CS channel", ctrl_enum_cs_channel), +}; + +static int stm32_spdifrx_dai_register_ctrls(struct snd_soc_dai *cpu_dai) +{ + int ret; + + ret = snd_soc_add_dai_controls(cpu_dai, stm32_spdifrx_iec_ctrls, + ARRAY_SIZE(stm32_spdifrx_iec_ctrls)); + if (ret < 0) + return ret; + + return snd_soc_add_component_controls(cpu_dai->component, + stm32_spdifrx_ctrls, + ARRAY_SIZE(stm32_spdifrx_ctrls)); +} + +static int stm32_spdifrx_dai_probe(struct snd_soc_dai *cpu_dai) +{ + struct stm32_spdifrx_data *spdifrx = dev_get_drvdata(cpu_dai->dev); + + spdifrx->dma_params.addr = (dma_addr_t)(spdifrx->phys_addr + + STM32_SPDIFRX_DR); + spdifrx->dma_params.maxburst = 1; + + snd_soc_dai_init_dma_data(cpu_dai, NULL, &spdifrx->dma_params); + + return stm32_spdifrx_dai_register_ctrls(cpu_dai); +} + +static bool stm32_spdifrx_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case STM32_SPDIFRX_CR: + case STM32_SPDIFRX_IMR: + case STM32_SPDIFRX_SR: + case STM32_SPDIFRX_IFCR: + case STM32_SPDIFRX_DR: + case STM32_SPDIFRX_CSR: + case STM32_SPDIFRX_DIR: + return true; + default: + return false; + } +} + +static bool stm32_spdifrx_volatile_reg(struct device *dev, unsigned int reg) +{ + if (reg == STM32_SPDIFRX_DR) + return true; + + return false; +} + +static bool stm32_spdifrx_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case STM32_SPDIFRX_CR: + case STM32_SPDIFRX_IMR: + case STM32_SPDIFRX_IFCR: + return true; + default: + return false; + } +} + +static const struct regmap_config stm32_h7_spdifrx_regmap_conf = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = STM32_SPDIFRX_DIR, + .readable_reg = stm32_spdifrx_readable_reg, + .volatile_reg = stm32_spdifrx_volatile_reg, + .writeable_reg = stm32_spdifrx_writeable_reg, + .fast_io = true, +}; + +static irqreturn_t stm32_spdifrx_isr(int irq, void *devid) +{ + struct stm32_spdifrx_data *spdifrx = (struct stm32_spdifrx_data *)devid; + struct snd_pcm_substream *substream = spdifrx->substream; + struct platform_device *pdev = spdifrx->pdev; + unsigned int cr, mask, sr, imr; + unsigned int flags; + int err = 0, err_xrun = 0; + + regmap_read(spdifrx->regmap, STM32_SPDIFRX_SR, &sr); + regmap_read(spdifrx->regmap, STM32_SPDIFRX_IMR, &imr); + + mask = imr & SPDIFRX_XIMR_MASK; + /* SERR, TERR, FERR IRQs are generated if IFEIE is set */ + if (mask & SPDIFRX_IMR_IFEIE) + mask |= (SPDIFRX_IMR_IFEIE << 1) | (SPDIFRX_IMR_IFEIE << 2); + + flags = sr & mask; + if (!flags) { + dev_err(&pdev->dev, "Unexpected IRQ. rflags=%#x, imr=%#x\n", + sr, imr); + return IRQ_NONE; + } + + /* Clear IRQs */ + regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IFCR, + SPDIFRX_XIFCR_MASK, flags); + + if (flags & SPDIFRX_SR_PERR) { + dev_dbg(&pdev->dev, "Parity error\n"); + err_xrun = 1; + } + + if (flags & SPDIFRX_SR_OVR) { + dev_dbg(&pdev->dev, "Overrun error\n"); + err_xrun = 1; + } + + if (flags & SPDIFRX_SR_SBD) + dev_dbg(&pdev->dev, "Synchronization block detected\n"); + + if (flags & SPDIFRX_SR_SYNCD) { + dev_dbg(&pdev->dev, "Synchronization done\n"); + + /* Enable spdifrx */ + cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_ENABLE); + regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, + SPDIFRX_CR_SPDIFEN_MASK, cr); + } + + if (flags & SPDIFRX_SR_FERR) { + dev_dbg(&pdev->dev, "Frame error\n"); + err = 1; + } + + if (flags & SPDIFRX_SR_SERR) { + dev_dbg(&pdev->dev, "Synchronization error\n"); + err = 1; + } + + if (flags & SPDIFRX_SR_TERR) { + dev_dbg(&pdev->dev, "Timeout error\n"); + err = 1; + } + + if (err) { + /* SPDIFRX in STATE_STOP. Disable SPDIFRX to clear errors */ + cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_DISABLE); + regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, + SPDIFRX_CR_SPDIFEN_MASK, cr); + + if (substream) + snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); + + return IRQ_HANDLED; + } + + if (err_xrun && substream) + snd_pcm_stop_xrun(substream); + + return IRQ_HANDLED; +} + +static int stm32_spdifrx_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); + int ret; + + spdifrx->substream = substream; + + ret = clk_prepare_enable(spdifrx->kclk); + if (ret) + dev_err(&spdifrx->pdev->dev, "Enable kclk failed: %d\n", ret); + + return ret; +} + +static int stm32_spdifrx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai) +{ + struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); + int data_size = params_width(params); + int fmt; + + switch (data_size) { + case 16: + fmt = SPDIFRX_DRFMT_PACKED; + spdifrx->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + break; + case 32: + fmt = SPDIFRX_DRFMT_LEFT; + spdifrx->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + break; + default: + dev_err(&spdifrx->pdev->dev, "Unexpected data format\n"); + return -EINVAL; + } + + snd_soc_dai_init_dma_data(cpu_dai, NULL, &spdifrx->dma_params); + + return regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, + SPDIFRX_CR_DRFMT_MASK, + SPDIFRX_CR_DRFMTSET(fmt)); +} + +static int stm32_spdifrx_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *cpu_dai) +{ + struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IMR, + SPDIFRX_IMR_OVRIE, SPDIFRX_IMR_OVRIE); + + regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, + SPDIFRX_CR_RXDMAEN, SPDIFRX_CR_RXDMAEN); + + ret = stm32_spdifrx_start_sync(spdifrx); + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_STOP: + stm32_spdifrx_stop(spdifrx); + break; + default: + return -EINVAL; + } + + return ret; +} + +static void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); + + spdifrx->substream = NULL; + clk_disable_unprepare(spdifrx->kclk); +} + +static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = { + .startup = stm32_spdifrx_startup, + .hw_params = stm32_spdifrx_hw_params, + .trigger = stm32_spdifrx_trigger, + .shutdown = stm32_spdifrx_shutdown, +}; + +static struct snd_soc_dai_driver stm32_spdifrx_dai[] = { + { + .name = "spdifrx-capture-cpu-dai", + .probe = stm32_spdifrx_dai_probe, + .capture = { + .stream_name = "CPU-Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &stm32_spdifrx_pcm_dai_ops, + } +}; + +static const struct snd_pcm_hardware stm32_spdifrx_pcm_hw = { + .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP, + .buffer_bytes_max = 8 * PAGE_SIZE, + .period_bytes_max = 2048, /* MDMA constraint */ + .periods_min = 2, + .periods_max = 8, +}; + +static const struct snd_soc_component_driver stm32_spdifrx_component = { + .name = "stm32-spdifrx", +}; + +static const struct snd_dmaengine_pcm_config stm32_spdifrx_pcm_config = { + .pcm_hardware = &stm32_spdifrx_pcm_hw, + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, +}; + +static const struct of_device_id stm32_spdifrx_ids[] = { + { + .compatible = "st,stm32h7-spdifrx", + .data = &stm32_h7_spdifrx_regmap_conf + }, + {} +}; + +static int stm_spdifrx_parse_of(struct platform_device *pdev, + struct stm32_spdifrx_data *spdifrx) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id; + struct resource *res; + + if (!np) + return -ENODEV; + + of_id = of_match_device(stm32_spdifrx_ids, &pdev->dev); + if (of_id) + spdifrx->regmap_conf = + (const struct regmap_config *)of_id->data; + else + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + spdifrx->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(spdifrx->base)) + return PTR_ERR(spdifrx->base); + + spdifrx->phys_addr = res->start; + + spdifrx->kclk = devm_clk_get(&pdev->dev, "kclk"); + if (IS_ERR(spdifrx->kclk)) { + dev_err(&pdev->dev, "Could not get kclk\n"); + return PTR_ERR(spdifrx->kclk); + } + + spdifrx->irq = platform_get_irq(pdev, 0); + if (spdifrx->irq < 0) { + dev_err(&pdev->dev, "No irq for node %s\n", pdev->name); + return spdifrx->irq; + } + + return 0; +} + +static int stm32_spdifrx_probe(struct platform_device *pdev) +{ + struct stm32_spdifrx_data *spdifrx; + struct reset_control *rst; + const struct snd_dmaengine_pcm_config *pcm_config = NULL; + int ret; + + spdifrx = devm_kzalloc(&pdev->dev, sizeof(*spdifrx), GFP_KERNEL); + if (!spdifrx) + return -ENOMEM; + + spdifrx->pdev = pdev; + init_completion(&spdifrx->cs_completion); + spin_lock_init(&spdifrx->lock); + + platform_set_drvdata(pdev, spdifrx); + + ret = stm_spdifrx_parse_of(pdev, spdifrx); + if (ret) + return ret; + + spdifrx->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "kclk", + spdifrx->base, + spdifrx->regmap_conf); + if (IS_ERR(spdifrx->regmap)) { + dev_err(&pdev->dev, "Regmap init failed\n"); + return PTR_ERR(spdifrx->regmap); + } + + ret = devm_request_irq(&pdev->dev, spdifrx->irq, stm32_spdifrx_isr, 0, + dev_name(&pdev->dev), spdifrx); + if (ret) { + dev_err(&pdev->dev, "IRQ request returned %d\n", ret); + return ret; + } + + rst = devm_reset_control_get(&pdev->dev, NULL); + if (!IS_ERR(rst)) { + reset_control_assert(rst); + udelay(2); + reset_control_deassert(rst); + } + + ret = devm_snd_soc_register_component(&pdev->dev, + &stm32_spdifrx_component, + stm32_spdifrx_dai, + ARRAY_SIZE(stm32_spdifrx_dai)); + if (ret) + return ret; + + ret = stm32_spdifrx_dma_ctrl_register(&pdev->dev, spdifrx); + if (ret) + goto error; + + pcm_config = &stm32_spdifrx_pcm_config; + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, pcm_config, 0); + if (ret) { + dev_err(&pdev->dev, "PCM DMA register returned %d\n", ret); + goto error; + } + + return 0; + +error: + if (spdifrx->ctrl_chan) + dma_release_channel(spdifrx->ctrl_chan); + if (spdifrx->dmab) + snd_dma_free_pages(spdifrx->dmab); + + return ret; +} + +static int stm32_spdifrx_remove(struct platform_device *pdev) +{ + struct stm32_spdifrx_data *spdifrx = platform_get_drvdata(pdev); + + if (spdifrx->ctrl_chan) + dma_release_channel(spdifrx->ctrl_chan); + + if (spdifrx->dmab) + snd_dma_free_pages(spdifrx->dmab); + + return 0; +} + +MODULE_DEVICE_TABLE(of, stm32_spdifrx_ids); + +static struct platform_driver stm32_spdifrx_driver = { + .driver = { + .name = "st,stm32-spdifrx", + .of_match_table = stm32_spdifrx_ids, + }, + .probe = stm32_spdifrx_probe, + .remove = stm32_spdifrx_remove, +}; + +module_platform_driver(stm32_spdifrx_driver); + +MODULE_DESCRIPTION("STM32 Soc spdifrx Interface"); +MODULE_AUTHOR("Olivier Moysan, "); +MODULE_ALIAS("platform:stm32-spdifrx"); +MODULE_LICENSE("GPL v2"); From 947f4eb58d2054b10a1d8146d0ab90b0e7fd3494 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 16 Jun 2017 00:02:59 +0000 Subject: [PATCH 351/418] ASoC: rsnd: fixup unsigned expression compared with zero: main_rate This patch fixes this WARNING sound/soc/sh/rcar/ssi.c:285:5-14: WARNING: Unsigned expression\ compared with zero: main_rate < 0 Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 2 +- sound/soc/sh/rcar/rsnd.h | 2 +- sound/soc/sh/rcar/ssi.c | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 4892c0a4b613..409bac331d27 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -763,7 +763,7 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv, struct snd_interval *baseline, struct snd_interval *iv) { struct snd_interval p; - int rate; + unsigned int rate; int i; snd_interval_any(&p); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 9428d4e288dd..99c57611df88 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -680,7 +680,7 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, struct device_node *playback, struct device_node *capture); -int rsnd_ssi_clk_query(struct rsnd_priv *priv, +unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv, int param1, int param2, int *idx); /* diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index c8956c3484dd..46feddd78ee2 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -208,14 +208,14 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io) return 0; } -int rsnd_ssi_clk_query(struct rsnd_priv *priv, +unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv, int param1, int param2, int *idx) { int ssi_clk_mul_table[] = { 1, 2, 4, 8, 16, 6, 12, }; int j, ret; - int main_rate; + unsigned int main_rate; for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) { @@ -245,7 +245,7 @@ int rsnd_ssi_clk_query(struct rsnd_priv *priv, return main_rate; } - return -EINVAL; + return 0; } static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, @@ -282,7 +282,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, } main_rate = rsnd_ssi_clk_query(priv, rate, chan, &idx); - if (main_rate < 0) { + if (!main_rate) { dev_err(dev, "unsupported clock rate\n"); return -EIO; } From 1943b0661184a5d17f31624dc8ac2c02a086c998 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 22 Jun 2017 10:32:31 +0100 Subject: [PATCH 352/418] ASoC: max9867: make array ni_div static const The array ni_div does not need to be in global scope and is not modified, so make it static const. Cleans up sparse warning: "symbol 'ni_div' was not declared. Should it be static?" Signed-off-by: Colin Ian King Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/max9867.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index 0247edc9c84e..2a40a69a7513 100644 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -132,7 +132,7 @@ enum rates { pcm_rate_48, max_pcm_rate, }; -struct ni_div_rates { +static const struct ni_div_rates { u32 mclk; u16 ni[max_pcm_rate]; } ni_div[] = { From 664d00d187608c66904e62ff2f24e7df49611ba5 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 22 Jun 2017 00:09:23 +0200 Subject: [PATCH 353/418] ASoC: es8316: add I2C dependency Without CONFIG_I2C, we get a build failure: sound/soc/codecs/es8316.c:633:1: error: data definition has no type or storage class [-Werror] sound/soc/codecs/es8316.c:633:1: error: type defaults to 'int' in declaration of 'module_i2c_driver' [-Werror=implicit-int] sound/soc/codecs/es8316.c:633:1: error: parameter names (without types) in function declaration [-Werror] sound/soc/codecs/es8316.c:623:26: error: 'es8316_i2c_driver' defined but not used [-Werror=unused-variable] This adds the required Kconfig dependency. Fixes: b8b88b70875a ("ASoC: add es8316 codec driver") Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c6286e5ba511..f0f794186186 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -546,6 +546,7 @@ config SND_SOC_ES7134 config SND_SOC_ES8316 tristate "Everest Semi ES8316 CODEC" + depends on I2C config SND_SOC_ES8328 tristate From 7de35c122e2dd8dc4d74b3782ced9c03115dc268 Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Thu, 22 Jun 2017 14:51:57 +0800 Subject: [PATCH 354/418] ASoC: add bindings for ZTE zx-aud96p22 audio codec It adds dt-bindings document for ZTE zx-aud96p22 audio codec. Signed-off-by: Baoyou Xie Acked-by: Rob Herring Signed-off-by: Shawn Guo Signed-off-by: Mark Brown --- .../bindings/sound/zte,zx-aud96p22.txt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/zte,zx-aud96p22.txt diff --git a/Documentation/devicetree/bindings/sound/zte,zx-aud96p22.txt b/Documentation/devicetree/bindings/sound/zte,zx-aud96p22.txt new file mode 100644 index 000000000000..41bb1040eb71 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/zte,zx-aud96p22.txt @@ -0,0 +1,24 @@ +ZTE ZX AUD96P22 Audio Codec + +Required properties: + - compatible: Must be "zte,zx-aud96p22" + - #sound-dai-cells: Should be 0 + - reg: I2C bus slave address of AUD96P22 + +Example: + + i2c0: i2c@1486000 { + compatible = "zte,zx296718-i2c"; + reg = <0x01486000 0x1000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&audiocrm AUDIO_I2C0_WCLK>; + clock-frequency = <1600000>; + + aud96p22: codec@22 { + compatible = "zte,zx-aud96p22"; + #sound-dai-cells = <0>; + reg = <0x22>; + }; + }; From 0e15bdfd8b1e3a94862522580161a2d1bb3882a7 Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Thu, 22 Jun 2017 14:51:58 +0800 Subject: [PATCH 355/418] ASoC: zx_aud96p22: add ZTE ZX AUD96P22 codec driver It adds ASoC driver for AUD96P22 stereo audio codec integrated on ZTE ZX family SoCs. The driver includes the support for a number of volume and mute controls, and power bits for various playback and recording components. Due to that the board for testing only supports playback, recording support is untested. Signed-off-by: Baoyou Xie Signed-off-by: Shawn Guo Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/zx_aud96p22.c | 403 +++++++++++++++++++++++++++++++++ 3 files changed, 410 insertions(+) create mode 100644 sound/soc/codecs/zx_aud96p22.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 883ed4c8a551..3425bbcea2d1 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1114,6 +1114,11 @@ config SND_SOC_WM9713 tristate select REGMAP_AC97 +config SND_SOC_ZX_AUD96P22 + tristate "ZTE ZX AUD96P22 CODEC" + depends on I2C + select REGMAP_I2C + # Amp config SND_SOC_LM4857 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 28a63fdaf982..d9858be7796a 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -224,6 +224,7 @@ snd-soc-wm9705-objs := wm9705.o snd-soc-wm9712-objs := wm9712.o snd-soc-wm9713-objs := wm9713.o snd-soc-wm-hubs-objs := wm_hubs.o +snd-soc-zx-aud96p22-objs := zx_aud96p22.o # Amp snd-soc-dio2125-objs := dio2125.o snd-soc-max9877-objs := max9877.o @@ -455,6 +456,7 @@ obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o +obj-$(CONFIG_SND_SOC_ZX_AUD96P22) += snd-soc-zx-aud96p22.o # Amp obj-$(CONFIG_SND_SOC_DIO2125) += snd-soc-dio2125.o diff --git a/sound/soc/codecs/zx_aud96p22.c b/sound/soc/codecs/zx_aud96p22.c new file mode 100644 index 000000000000..032fb7cf6cbd --- /dev/null +++ b/sound/soc/codecs/zx_aud96p22.c @@ -0,0 +1,403 @@ +/* + * Copyright (C) 2017 Sanechips Technology Co., Ltd. + * Copyright 2017 Linaro Ltd. + * + * Author: Baoyou Xie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AUD96P22_RESET 0x00 +#define RST_DAC_DPZ BIT(0) +#define RST_ADC_DPZ BIT(1) +#define AUD96P22_I2S1_CONFIG_0 0x03 +#define I2S1_MS_MODE BIT(3) +#define I2S1_MODE_MASK 0x7 +#define I2S1_MODE_RIGHT_J 0x0 +#define I2S1_MODE_I2S 0x1 +#define I2S1_MODE_LEFT_J 0x2 +#define AUD96P22_PD_0 0x15 +#define AUD96P22_PD_1 0x16 +#define AUD96P22_PD_3 0x18 +#define AUD96P22_PD_4 0x19 +#define AUD96P22_MUTE_0 0x1d +#define AUD96P22_MUTE_2 0x1f +#define AUD96P22_MUTE_4 0x21 +#define AUD96P22_RECVOL_0 0x24 +#define AUD96P22_RECVOL_1 0x25 +#define AUD96P22_PGA1VOL_0 0x26 +#define AUD96P22_PGA1VOL_1 0x27 +#define AUD96P22_LMVOL_0 0x34 +#define AUD96P22_LMVOL_1 0x35 +#define AUD96P22_HS1VOL_0 0x38 +#define AUD96P22_HS1VOL_1 0x39 +#define AUD96P22_PGA1SEL_0 0x47 +#define AUD96P22_PGA1SEL_1 0x48 +#define AUD96P22_LDR1SEL_0 0x59 +#define AUD96P22_LDR1SEL_1 0x60 +#define AUD96P22_LDR2SEL_0 0x5d +#define AUD96P22_REG_MAX 0xfb + +struct aud96p22_priv { + struct regmap *regmap; +}; + +static int aud96p22_adc_event(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 aud96p22_priv *priv = snd_soc_codec_get_drvdata(codec); + struct regmap *regmap = priv->regmap; + + if (event != SND_SOC_DAPM_POST_PMU) + return -EINVAL; + + /* Assert/de-assert the bit to reset ADC data path */ + regmap_update_bits(regmap, AUD96P22_RESET, RST_ADC_DPZ, 0); + regmap_update_bits(regmap, AUD96P22_RESET, RST_ADC_DPZ, RST_ADC_DPZ); + + return 0; +} + +static int aud96p22_dac_event(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 aud96p22_priv *priv = snd_soc_codec_get_drvdata(codec); + struct regmap *regmap = priv->regmap; + + if (event != SND_SOC_DAPM_POST_PMU) + return -EINVAL; + + /* Assert/de-assert the bit to reset DAC data path */ + regmap_update_bits(regmap, AUD96P22_RESET, RST_DAC_DPZ, 0); + regmap_update_bits(regmap, AUD96P22_RESET, RST_DAC_DPZ, RST_DAC_DPZ); + + return 0; +} + +static const DECLARE_TLV_DB_SCALE(lm_tlv, -11550, 50, 0); +static const DECLARE_TLV_DB_SCALE(hs_tlv, -3900, 300, 0); +static const DECLARE_TLV_DB_SCALE(rec_tlv, -9550, 50, 0); +static const DECLARE_TLV_DB_SCALE(pga_tlv, -1800, 100, 0); + +static const struct snd_kcontrol_new aud96p22_snd_controls[] = { + /* Volume control */ + SOC_DOUBLE_R_TLV("Master Playback Volume", AUD96P22_LMVOL_0, + AUD96P22_LMVOL_1, 0, 0xff, 0, lm_tlv), + SOC_DOUBLE_R_TLV("Headphone Volume", AUD96P22_HS1VOL_0, + AUD96P22_HS1VOL_1, 0, 0xf, 0, hs_tlv), + SOC_DOUBLE_R_TLV("Master Capture Volume", AUD96P22_RECVOL_0, + AUD96P22_RECVOL_1, 0, 0xff, 0, rec_tlv), + SOC_DOUBLE_R_TLV("Analogue Capture Volume", AUD96P22_PGA1VOL_0, + AUD96P22_PGA1VOL_1, 0, 0x37, 0, pga_tlv), + + /* Mute control */ + SOC_DOUBLE("Master Playback Switch", AUD96P22_MUTE_2, 0, 1, 1, 1), + SOC_DOUBLE("Headphone Switch", AUD96P22_MUTE_2, 4, 5, 1, 1), + SOC_DOUBLE("Line Out Switch", AUD96P22_MUTE_4, 0, 1, 1, 1), + SOC_DOUBLE("Speaker Switch", AUD96P22_MUTE_4, 2, 3, 1, 1), + SOC_DOUBLE("Master Capture Switch", AUD96P22_MUTE_0, 0, 1, 1, 1), + SOC_DOUBLE("Analogue Capture Switch", AUD96P22_MUTE_0, 2, 3, 1, 1), +}; + +/* Input mux kcontrols */ +static const unsigned int ain_mux_values[] = { + 0, 1, 3, 4, 5, +}; + +static const char * const ainl_mux_texts[] = { + "AINL1 differential", + "AINL1 single-ended", + "AINL3 single-ended", + "AINL2 differential", + "AINL2 single-ended", +}; + +static const char * const ainr_mux_texts[] = { + "AINR1 differential", + "AINR1 single-ended", + "AINR3 single-ended", + "AINR2 differential", + "AINR2 single-ended", +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(ainl_mux_enum, AUD96P22_PGA1SEL_0, + 0, 0x7, ainl_mux_texts, ain_mux_values); +static SOC_VALUE_ENUM_SINGLE_DECL(ainr_mux_enum, AUD96P22_PGA1SEL_1, + 0, 0x7, ainr_mux_texts, ain_mux_values); + +static const struct snd_kcontrol_new ainl_mux_kcontrol = + SOC_DAPM_ENUM("AINL Mux", ainl_mux_enum); +static const struct snd_kcontrol_new ainr_mux_kcontrol = + SOC_DAPM_ENUM("AINR Mux", ainr_mux_enum); + +/* Output mixer kcontrols */ +static const struct snd_kcontrol_new ld1_left_kcontrols[] = { + SOC_DAPM_SINGLE("DACL LD1L Switch", AUD96P22_LDR1SEL_0, 0, 1, 0), + SOC_DAPM_SINGLE("AINL LD1L Switch", AUD96P22_LDR1SEL_0, 1, 1, 0), + SOC_DAPM_SINGLE("AINR LD1L Switch", AUD96P22_LDR1SEL_0, 2, 1, 0), +}; + +static const struct snd_kcontrol_new ld1_right_kcontrols[] = { + SOC_DAPM_SINGLE("DACR LD1R Switch", AUD96P22_LDR1SEL_1, 8, 1, 0), + SOC_DAPM_SINGLE("AINR LD1R Switch", AUD96P22_LDR1SEL_1, 9, 1, 0), + SOC_DAPM_SINGLE("AINL LD1R Switch", AUD96P22_LDR1SEL_1, 10, 1, 0), +}; + +static const struct snd_kcontrol_new ld2_kcontrols[] = { + SOC_DAPM_SINGLE("DACL LD2 Switch", AUD96P22_LDR2SEL_0, 0, 1, 0), + SOC_DAPM_SINGLE("AINL LD2 Switch", AUD96P22_LDR2SEL_0, 1, 1, 0), + SOC_DAPM_SINGLE("DACR LD2 Switch", AUD96P22_LDR2SEL_0, 2, 1, 0), +}; + +static const struct snd_soc_dapm_widget aud96p22_dapm_widgets[] = { + /* Overall power bit */ + SND_SOC_DAPM_SUPPLY("POWER", AUD96P22_PD_0, 0, 0, NULL, 0), + + /* Input pins */ + SND_SOC_DAPM_INPUT("AINL1P"), + SND_SOC_DAPM_INPUT("AINL2P"), + SND_SOC_DAPM_INPUT("AINL3"), + SND_SOC_DAPM_INPUT("AINL1N"), + SND_SOC_DAPM_INPUT("AINL2N"), + SND_SOC_DAPM_INPUT("AINR2N"), + SND_SOC_DAPM_INPUT("AINR1N"), + SND_SOC_DAPM_INPUT("AINR3"), + SND_SOC_DAPM_INPUT("AINR2P"), + SND_SOC_DAPM_INPUT("AINR1P"), + + /* Input muxes */ + SND_SOC_DAPM_MUX("AINLMUX", AUD96P22_PD_1, 2, 0, &ainl_mux_kcontrol), + SND_SOC_DAPM_MUX("AINRMUX", AUD96P22_PD_1, 3, 0, &ainr_mux_kcontrol), + + /* ADCs */ + SND_SOC_DAPM_ADC_E("ADCL", "Capture Left", AUD96P22_PD_1, 0, 0, + aud96p22_adc_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_ADC_E("ADCR", "Capture Right", AUD96P22_PD_1, 1, 0, + aud96p22_adc_event, SND_SOC_DAPM_POST_PMU), + + /* DACs */ + SND_SOC_DAPM_DAC_E("DACL", "Playback Left", AUD96P22_PD_3, 0, 0, + aud96p22_dac_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_DAC_E("DACR", "Playback Right", AUD96P22_PD_3, 1, 0, + aud96p22_dac_event, SND_SOC_DAPM_POST_PMU), + + /* Output mixers */ + SND_SOC_DAPM_MIXER("LD1L", AUD96P22_PD_3, 6, 0, ld1_left_kcontrols, + ARRAY_SIZE(ld1_left_kcontrols)), + SND_SOC_DAPM_MIXER("LD1R", AUD96P22_PD_3, 7, 0, ld1_right_kcontrols, + ARRAY_SIZE(ld1_right_kcontrols)), + SND_SOC_DAPM_MIXER("LD2", AUD96P22_PD_4, 2, 0, ld2_kcontrols, + ARRAY_SIZE(ld2_kcontrols)), + + /* Headset power switch */ + SND_SOC_DAPM_SUPPLY("HS1L", AUD96P22_PD_3, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("HS1R", AUD96P22_PD_3, 5, 0, NULL, 0), + + /* Output pins */ + SND_SOC_DAPM_OUTPUT("HSOUTL"), + SND_SOC_DAPM_OUTPUT("LINEOUTL"), + SND_SOC_DAPM_OUTPUT("LINEOUTMP"), + SND_SOC_DAPM_OUTPUT("LINEOUTMN"), + SND_SOC_DAPM_OUTPUT("LINEOUTR"), + SND_SOC_DAPM_OUTPUT("HSOUTR"), +}; + +static const struct snd_soc_dapm_route aud96p22_dapm_routes[] = { + { "AINLMUX", "AINL1 differential", "AINL1N" }, + { "AINLMUX", "AINL1 single-ended", "AINL1P" }, + { "AINLMUX", "AINL3 single-ended", "AINL3" }, + { "AINLMUX", "AINL2 differential", "AINL2N" }, + { "AINLMUX", "AINL2 single-ended", "AINL2P" }, + + { "AINRMUX", "AINR1 differential", "AINR1N" }, + { "AINRMUX", "AINR1 single-ended", "AINR1P" }, + { "AINRMUX", "AINR3 single-ended", "AINR3" }, + { "AINRMUX", "AINR2 differential", "AINR2N" }, + { "AINRMUX", "AINR2 single-ended", "AINR2P" }, + + { "ADCL", NULL, "AINLMUX" }, + { "ADCR", NULL, "AINRMUX" }, + + { "ADCL", NULL, "POWER" }, + { "ADCR", NULL, "POWER" }, + { "DACL", NULL, "POWER" }, + { "DACR", NULL, "POWER" }, + + { "LD1L", "DACL LD1L Switch", "DACL" }, + { "LD1L", "AINL LD1L Switch", "AINLMUX" }, + { "LD1L", "AINR LD1L Switch", "AINRMUX" }, + + { "LD1R", "DACR LD1R Switch", "DACR" }, + { "LD1R", "AINR LD1R Switch", "AINRMUX" }, + { "LD1R", "AINL LD1R Switch", "AINLMUX" }, + + { "LD2", "DACL LD2 Switch", "DACL" }, + { "LD2", "AINL LD2 Switch", "AINLMUX" }, + { "LD2", "DACR LD2 Switch", "DACR" }, + + { "HSOUTL", NULL, "LD1L" }, + { "HSOUTR", NULL, "LD1R" }, + { "HSOUTL", NULL, "HS1L" }, + { "HSOUTR", NULL, "HS1R" }, + + { "LINEOUTL", NULL, "LD1L" }, + { "LINEOUTR", NULL, "LD1R" }, + + { "LINEOUTMP", NULL, "LD2" }, + { "LINEOUTMN", NULL, "LD2" }, +}; + +static struct snd_soc_codec_driver aud96p22_driver = { + .component_driver = { + .controls = aud96p22_snd_controls, + .num_controls = ARRAY_SIZE(aud96p22_snd_controls), + .dapm_widgets = aud96p22_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(aud96p22_dapm_widgets), + .dapm_routes = aud96p22_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(aud96p22_dapm_routes), + }, +}; + +static int aud96p22_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct aud96p22_priv *priv = snd_soc_codec_get_drvdata(dai->codec); + struct regmap *regmap = priv->regmap; + unsigned int val; + + /* Master/slave mode */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + val = 0; + break; + case SND_SOC_DAIFMT_CBM_CFM: + val = I2S1_MS_MODE; + break; + default: + return -EINVAL; + } + + regmap_update_bits(regmap, AUD96P22_I2S1_CONFIG_0, I2S1_MS_MODE, val); + + /* Audio format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_RIGHT_J: + val = I2S1_MODE_RIGHT_J; + break; + case SND_SOC_DAIFMT_I2S: + val = I2S1_MODE_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + val = I2S1_MODE_LEFT_J; + break; + default: + return -EINVAL; + } + + regmap_update_bits(regmap, AUD96P22_I2S1_CONFIG_0, I2S1_MODE_MASK, val); + + return 0; +} + +static struct snd_soc_dai_ops aud96p22_dai_ops = { + .set_fmt = aud96p22_set_fmt, +}; + +#define AUD96P22_RATES SNDRV_PCM_RATE_8000_192000 +#define AUD96P22_FORMATS (\ + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_driver aud96p22_dai = { + .name = "aud96p22-dai", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AUD96P22_RATES, + .formats = AUD96P22_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = AUD96P22_RATES, + .formats = AUD96P22_FORMATS, + }, + .ops = &aud96p22_dai_ops, +}; + +static const struct regmap_config aud96p22_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = AUD96P22_REG_MAX, + .cache_type = REGCACHE_RBTREE, +}; + +static int aud96p22_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct device *dev = &i2c->dev; + struct aud96p22_priv *priv; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + + priv->regmap = devm_regmap_init_i2c(i2c, &aud96p22_regmap); + if (IS_ERR(priv->regmap)) { + ret = PTR_ERR(priv->regmap); + dev_err(dev, "failed to init i2c regmap: %d\n", ret); + return ret; + } + + i2c_set_clientdata(i2c, priv); + + ret = snd_soc_register_codec(dev, &aud96p22_driver, &aud96p22_dai, 1); + if (ret) { + dev_err(dev, "failed to register codec: %d\n", ret); + return ret; + } + + return 0; +} + +static int aud96p22_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + return 0; +} + +const struct of_device_id aud96p22_dt_ids[] = { + { .compatible = "zte,zx-aud96p22", }, + { } +}; +MODULE_DEVICE_TABLE(of, aud96p22_dt_ids); + +static struct i2c_driver aud96p22_i2c_driver = { + .driver = { + .name = "zx_aud96p22", + .of_match_table = aud96p22_dt_ids, + }, + .probe = aud96p22_i2c_probe, + .remove = aud96p22_i2c_remove, +}; +module_i2c_driver(aud96p22_i2c_driver); + +MODULE_DESCRIPTION("ZTE ASoC AUD96P22 CODEC driver"); +MODULE_AUTHOR("Baoyou Xie "); +MODULE_LICENSE("GPL v2"); From 403d2fef06104275dd4909d2684c86aabe25c917 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Thu, 22 Jun 2017 10:41:51 +0800 Subject: [PATCH 356/418] ASoC: nau8825: default value for property Assign default value for codec private data when property not given. If without those default value and property, the codec will work abnormally. Signed-off-by: John Hsu Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 53 +++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 97fbeba9498f..c00b86dd80dc 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -2429,6 +2429,7 @@ static void nau8825_print_device_properties(struct nau8825 *nau8825) static int nau8825_read_device_properties(struct device *dev, struct nau8825 *nau8825) { + int ret; nau8825->jkdet_enable = device_property_read_bool(dev, "nuvoton,jkdet-enable"); @@ -2436,30 +2437,58 @@ static int nau8825_read_device_properties(struct device *dev, "nuvoton,jkdet-pull-enable"); nau8825->jkdet_pull_up = device_property_read_bool(dev, "nuvoton,jkdet-pull-up"); - device_property_read_u32(dev, "nuvoton,jkdet-polarity", + ret = device_property_read_u32(dev, "nuvoton,jkdet-polarity", &nau8825->jkdet_polarity); - device_property_read_u32(dev, "nuvoton,micbias-voltage", + if (ret) + nau8825->jkdet_polarity = 1; + ret = device_property_read_u32(dev, "nuvoton,micbias-voltage", &nau8825->micbias_voltage); - device_property_read_u32(dev, "nuvoton,vref-impedance", + if (ret) + nau8825->micbias_voltage = 6; + ret = device_property_read_u32(dev, "nuvoton,vref-impedance", &nau8825->vref_impedance); - device_property_read_u32(dev, "nuvoton,sar-threshold-num", + if (ret) + nau8825->vref_impedance = 2; + ret = device_property_read_u32(dev, "nuvoton,sar-threshold-num", &nau8825->sar_threshold_num); - device_property_read_u32_array(dev, "nuvoton,sar-threshold", + if (ret) + nau8825->sar_threshold_num = 4; + ret = device_property_read_u32_array(dev, "nuvoton,sar-threshold", nau8825->sar_threshold, nau8825->sar_threshold_num); - device_property_read_u32(dev, "nuvoton,sar-hysteresis", + if (ret) { + nau8825->sar_threshold[0] = 0x08; + nau8825->sar_threshold[1] = 0x12; + nau8825->sar_threshold[2] = 0x26; + nau8825->sar_threshold[3] = 0x73; + } + ret = device_property_read_u32(dev, "nuvoton,sar-hysteresis", &nau8825->sar_hysteresis); - device_property_read_u32(dev, "nuvoton,sar-voltage", + if (ret) + nau8825->sar_hysteresis = 0; + ret = device_property_read_u32(dev, "nuvoton,sar-voltage", &nau8825->sar_voltage); - device_property_read_u32(dev, "nuvoton,sar-compare-time", + if (ret) + nau8825->sar_voltage = 6; + ret = device_property_read_u32(dev, "nuvoton,sar-compare-time", &nau8825->sar_compare_time); - device_property_read_u32(dev, "nuvoton,sar-sampling-time", + if (ret) + nau8825->sar_compare_time = 1; + ret = device_property_read_u32(dev, "nuvoton,sar-sampling-time", &nau8825->sar_sampling_time); - device_property_read_u32(dev, "nuvoton,short-key-debounce", + if (ret) + nau8825->sar_sampling_time = 1; + ret = device_property_read_u32(dev, "nuvoton,short-key-debounce", &nau8825->key_debounce); - device_property_read_u32(dev, "nuvoton,jack-insert-debounce", + if (ret) + nau8825->key_debounce = 3; + ret = device_property_read_u32(dev, "nuvoton,jack-insert-debounce", &nau8825->jack_insert_debounce); - device_property_read_u32(dev, "nuvoton,jack-eject-debounce", + if (ret) + nau8825->jack_insert_debounce = 7; + ret = device_property_read_u32(dev, "nuvoton,jack-eject-debounce", &nau8825->jack_eject_debounce); + if (ret) + nau8825->jack_eject_debounce = 0; nau8825->mclk = devm_clk_get(dev, "mclk"); if (PTR_ERR(nau8825->mclk) == -EPROBE_DEFER) { From 8fe19795da1b9dea2353f016622842a2f163039e Mon Sep 17 00:00:00 2001 From: John Hsu Date: Thu, 22 Jun 2017 11:21:01 +0800 Subject: [PATCH 357/418] ASoC: nau8825: fix jack type detection issue after resume Fix the issue that mic type detection error after resume. The microphone type detection procedure will recognize testing signal on JKSLV pin, but before the procedure, JKSLV already had supply voltage, that results in the failure. Therefore, the patch turns off the power and reset the jack type configuration before suspend. Then redo the jack detection procedure after resume. The patch help to fix the issue as follows: Google issue 37973093: CTIA/OMTP jack type detection failure after resume Reported Issue Chrome OS Version : ChromeOS R59-9460.13.0 Type of hardware : DVT sample What steps will reproduce the problem? (1 Play a music (2 Insert a headphones (3 Close laptop lid 3 sec then open it What is the expected output? The music is normal in the headphones. What do you see instead? Singer voice in the music is not clear. How frequently does this problem reproduce? Always What is the impact to the user, and is there a workaround? If so, what is it? Re-insert the headset or close the laptop lid and then open it again can be repaired. Signed-off-by: John Hsu Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index c00b86dd80dc..503a6d8130b7 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -1612,7 +1612,6 @@ static int nau8825_jack_insert(struct nau8825 *nau8825) snd_soc_dapm_sync(dapm); break; case 2: - case 3: dev_dbg(nau8825->dev, "CTIA (micgnd2) mic connected\n"); type = SND_JACK_HEADSET; @@ -1632,6 +1631,11 @@ static int nau8825_jack_insert(struct nau8825 *nau8825) snd_soc_dapm_force_enable_pin(dapm, "SAR"); snd_soc_dapm_sync(dapm); break; + case 3: + /* detect error case */ + dev_err(nau8825->dev, "detection error; disable mic function\n"); + type = SND_JACK_HEADPHONE; + break; } /* Leaving HPOL/R grounded after jack insert by default. They will be @@ -2328,6 +2332,13 @@ static int nau8825_set_bias_level(struct snd_soc_codec *codec, break; case SND_SOC_BIAS_OFF: + /* Reset the configuration of jack type for detection */ + /* Detach 2kOhm Resistors from MICBIAS to MICGND1/2 */ + regmap_update_bits(nau8825->regmap, NAU8825_REG_MIC_BIAS, + NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2, 0); + /* ground HPL/HPR, MICGRND1/2 */ + regmap_update_bits(nau8825->regmap, + NAU8825_REG_HSD_CTRL, 0xf, 0xf); /* Cancel and reset cross talk detection funciton */ nau8825_xtalk_cancel(nau8825); /* Turn off all interruptions before system shutdown. Keep the @@ -2351,6 +2362,10 @@ static int __maybe_unused nau8825_suspend(struct snd_soc_codec *codec) disable_irq(nau8825->irq); snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); + /* Power down codec power; don't suppoet button wakeup */ + snd_soc_dapm_disable_pin(nau8825->dapm, "SAR"); + snd_soc_dapm_disable_pin(nau8825->dapm, "MICBIAS"); + snd_soc_dapm_sync(nau8825->dapm); regcache_cache_only(nau8825->regmap, true); regcache_mark_dirty(nau8825->regmap); From 2bda4288e771e51946e70329c9b79605e4612f10 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Thu, 22 Jun 2017 11:57:55 +0800 Subject: [PATCH 358/418] ASoC: nau8825: make crosstalk function optional Make crosstalk functoin optional. The jack detection can speed up without crosstalk detection. Let the decision of function usage to platform design. The patch helps the issue concern as follows: Google issue 35574278: Chell_headphone pop back from S3 There is a concern as follows: cras getting blocked for 2 seconds (worst-case 3 seconds) As I understand, ChromeOS expects resume finishes in 1 seconds. Video/Audio playing after 3 seconds of resume seems against the spec. If we really have to make the choice I would choose pop noise instead of waiting for 3 seconds. Signed-off-by: John Hsu Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 6 +++++- sound/soc/codecs/nau8825.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 503a6d8130b7..a8c7a556a6a8 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -1686,7 +1686,7 @@ static irqreturn_t nau8825_interrupt(int irq, void *data) } else if (active_irq & NAU8825_HEADSET_COMPLETION_IRQ) { if (nau8825_is_jack_inserted(regmap)) { event |= nau8825_jack_insert(nau8825); - if (!nau8825->high_imped) { + if (!nau8825->xtalk_bypass && !nau8825->high_imped) { /* Apply the cross talk suppression in the * headset without high impedance. */ @@ -2504,6 +2504,10 @@ static int nau8825_read_device_properties(struct device *dev, &nau8825->jack_eject_debounce); if (ret) nau8825->jack_eject_debounce = 0; + ret = device_property_read_u32(dev, "nuvoton,crosstalk-bypass", + &nau8825->xtalk_bypass); + if (ret) + nau8825->xtalk_bypass = 1; nau8825->mclk = devm_clk_get(dev, "mclk"); if (PTR_ERR(nau8825->mclk) == -EPROBE_DEFER) { diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index 514fd13c2f46..8aee5c8647ae 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -476,6 +476,7 @@ struct nau8825 { int xtalk_event_mask; bool xtalk_protect; int imp_rms[NAU8825_XTALK_IMM]; + int xtalk_bypass; }; int nau8825_enable_jack_detect(struct snd_soc_codec *codec, From 47ca9593decee772a48d630af815aabedf99e694 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 22 Jun 2017 06:21:49 +0000 Subject: [PATCH 359/418] ASoC: audio-graph-card: tidyup asoc_simple_card_canonicalize_cpu() parameter asoc_simple_card_canonicalize_cpu() 2nd param is asking CPU component's DAI links, not Card links. This patch fixup it. Otherwise, audio-graph-card can't handle CPU component correctly if CPU has mult-DAIs and Card uses only one of them Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 885b405d7844..ee752f62d89d 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -100,7 +100,6 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx); struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai; struct asoc_simple_dai *codec_dai = &dai_props->codec_dai; - struct snd_soc_card *card = graph_priv_to_card(priv); struct device_node *cpu_ep = of_get_next_child(cpu_port, NULL); struct device_node *codec_ep = of_graph_get_remote_endpoint(cpu_ep); struct device_node *rcpu_ep = of_graph_get_remote_endpoint(codec_ep); @@ -162,7 +161,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, dai_link->init = asoc_graph_card_dai_init; asoc_simple_card_canonicalize_cpu(dai_link, - card->num_links == 1); + of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); dai_link_of_err: of_node_put(cpu_ep); From 32f2bcce3ed10b93236d747701a9c04d51626cc2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 22 Jun 2017 06:22:14 +0000 Subject: [PATCH 360/418] ASoC: audio-graph-scu-card: tidyup asoc_simple_card_canonicalize_cpu() parameter asoc_simple_card_canonicalize_cpu() 2nd param is asking CPU component's DAI links, not Card links. This patch fixup it. Otherwise, audio-graph-card can't handle CPU component correctly if CPU has mult-DAIs and Card uses only one of them Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-scu-card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c index 05934b24627b..061c7a60d6b4 100644 --- a/sound/soc/generic/audio-graph-scu-card.c +++ b/sound/soc/generic/audio-graph-scu-card.c @@ -125,7 +125,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, /* card->num_links includes Codec */ asoc_simple_card_canonicalize_cpu(dai_link, - (card->num_links - 1) == 1); + of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); } else { /* FE is dummy */ dai_link->cpu_of_node = NULL; From f1f940490d3ccff96da9cc81d57c2c083c398a18 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 22 Jun 2017 06:22:49 +0000 Subject: [PATCH 361/418] ASoC: audio-graph-scu-card: support 2nd codec endpoint on DT audio-graph-scu-card can handle below connection which is mainly for sound mixing purpose. +----------+ +-------+ | CPU0--+--|-->| Codec | | | | +-------+ | CPU1--+ | +----------+ >From OF-graph point of view, it should have CPU0 <-> Codec, and CPU1 <-> Codec on DT. But current driver doesn't care about 2nd connection of Codec, because it is dummy from DPCM point of view. This patch can care 2nd Codec connection, and it should be supported from OF-graph point of view. It still have backward compatibility. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../bindings/sound/audio-graph-scu-card.txt | 9 ++++-- sound/soc/generic/audio-graph-scu-card.c | 28 +++++++++++++++++-- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt b/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt index b63c5594bbb3..8b8afe9fcb31 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt +++ b/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt @@ -90,9 +90,12 @@ Example 2. 2 CPU 1 Codec (Mixing) ... port { - codec_endpoint: endpoint { + codec_endpoint0: endpoint { remote-endpoint = <&cpu_endpoint0>; }; + codec_endpoint1: endpoint { + remote-endpoint = <&cpu_endpoint1>; + }; }; }; @@ -101,7 +104,7 @@ Example 2. 2 CPU 1 Codec (Mixing) ports { cpu_port0: port { cpu_endpoint0: endpoint { - remote-endpoint = <&codec_endpoint>; + remote-endpoint = <&codec_endpoint0>; dai-format = "left_j"; ... @@ -109,6 +112,8 @@ Example 2. 2 CPU 1 Codec (Mixing) }; cpu_port1: port { cpu_endpoint1: endpoint { + remote-endpoint = <&codec_endpoint1>; + dai-format = "left_j"; ... }; diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c index 061c7a60d6b4..dcd2df37bc3b 100644 --- a/sound/soc/generic/audio-graph-scu-card.c +++ b/sound/soc/generic/audio-graph-scu-card.c @@ -183,6 +183,8 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) struct device_node *cpu_ep; struct device_node *codec_ep; struct device_node *rcpu_ep; + struct device_node *codec_port; + struct device_node *codec_port_old; unsigned int daifmt = 0; int dai_idx, ret; int rc, codec; @@ -235,6 +237,7 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) } dai_idx = 0; + codec_port_old = NULL; for (codec = 0; codec < 2; codec++) { /* * To listup valid sounds continuously, @@ -245,15 +248,22 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) cpu_port = it.node; cpu_ep = of_get_next_child(cpu_port, NULL); codec_ep = of_graph_get_remote_endpoint(cpu_ep); + codec_port = of_graph_get_port_parent(codec_ep); of_node_put(cpu_port); of_node_put(cpu_ep); of_node_put(codec_ep); + of_node_put(codec_port); if (codec) { - if (!codec_ep) + if (!codec_port) continue; + if (codec_port_old == codec_port) + continue; + + codec_port_old = codec_port; + /* Back-End (= Codec) */ ret = asoc_graph_card_dai_link_of(codec_ep, priv, daifmt, dai_idx++, 0); if (ret < 0) @@ -284,22 +294,34 @@ static int asoc_graph_get_dais_count(struct device *dev) struct device_node *cpu_port; struct device_node *cpu_ep; struct device_node *codec_ep; + struct device_node *codec_port; + struct device_node *codec_port_old; int count = 0; int rc; + codec_port_old = NULL; of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { cpu_port = it.node; cpu_ep = of_get_next_child(cpu_port, NULL); codec_ep = of_graph_get_remote_endpoint(cpu_ep); + codec_port = of_graph_get_port_parent(codec_ep); of_node_put(cpu_port); of_node_put(cpu_ep); of_node_put(codec_ep); + of_node_put(codec_port); if (cpu_ep) count++; - if (codec_ep) - count++; + + if (!codec_port) + continue; + + if (codec_port_old == codec_port) + continue; + + count++; + codec_port_old = codec_port; } return count; From 42f945970af9df6216e3d771b4df371d02d8742c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 19 Jun 2017 22:39:18 +0200 Subject: [PATCH 362/418] ALSA: pcm: Add the explicit appl_ptr sync support Currently x86 platforms use the PCM status/control mmaps for transferring the PCM status and appl_ptr between kernel and user-spaces. The mmap is a most efficient way of communication, but it has a drawback per its nature, namely, it can't notify the change explicitly to kernel. The lack of appl_ptr update notification is a problem on a few existing drivers, but it's mostly a small issue and negligible. However, a new type of driver that uses DSP for a deep buffer management requires the exact position of appl_ptr for calculating the buffer prefetch size, and the asynchronous appl_ptr update between kernel and user-spaces becomes a significant problem for it. How can we enforce user-space to report the appl_ptr update? The way is relatively simple. Just by disabling the PCM control mmap, the user-space is supposed to fall back to the mode using SYNC_PTR ioctl, and the kernel gets control over that. This fallback mode is used in all non-x86 platforms as default, and also in the 32bit compatible model on all platforms including x86. It's been implemented already over a decade, so we can say it's fairly safe and stably working. With the help of the knowledge above, this patch introduces a new PCM info flag SNDRV_PCM_INFO_SYNC_APPLPTR for achieving the appl_ptr sync from user-space. When a driver sets this flag at open, the PCM status / control mmap is disabled, which effectively switches to SYNC_PTR mode in user-space side. In this version, both PCM status and control mmaps are disabled although only the latter, control mmap, is the target. It's because the current alsa-lib implementation supposes that both status and control mmaps are always coupled, thus it handles a fatal error when only one of them fails. Of course, the disablement of the status/control mmaps may bring a slight performance overhead. Thus, as of now, this should be used only for the dedicated devices that deserves. Note that the disablement of mmap is a sort of workaround. In the later patch, we'll introduce the way to identify the protocol version alsa-lib supports, and keep mmap working while the sync_ptr is performed together. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- include/uapi/sound/asound.h | 1 + sound/core/pcm_native.c | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index fd41697cb4d3..7eee52eb7462 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -268,6 +268,7 @@ typedef int __bitwise snd_pcm_subformat_t; #define SNDRV_PCM_INFO_MMAP_VALID 0x00000002 /* period data are valid during transfer */ #define SNDRV_PCM_INFO_DOUBLE 0x00000004 /* Double buffering needed for PCM start/stop */ #define SNDRV_PCM_INFO_BATCH 0x00000010 /* double buffering */ +#define SNDRV_PCM_INFO_SYNC_APPLPTR 0x00000020 /* need the explicit sync of appl_ptr update */ #define SNDRV_PCM_INFO_INTERLEAVED 0x00000100 /* channels are interleaved */ #define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200 /* channels are not interleaved */ #define SNDRV_PCM_INFO_COMPLEX 0x00000400 /* complex frame organization (mmap only) */ diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index d35c6614fdab..9ade0c8b54a3 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3376,10 +3376,29 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; return 0; } + +static bool pcm_status_mmap_allowed(struct snd_pcm_file *pcm_file) +{ + if (pcm_file->no_compat_mmap) + return false; + /* Disallow the status/control mmap when SYNC_APPLPTR flag is set; + * it enforces the user-space to fall back to snd_pcm_sync_ptr(), + * thus it effectively assures the manual update of appl_ptr. + * In theory, it should be enough to disallow only PCM control mmap, + * but since the current alsa-lib implementation requires both status + * and control mmaps always paired, we have to disable both of them. + */ + if (pcm_file->substream->runtime->hw.info & SNDRV_PCM_INFO_SYNC_APPLPTR) + return false; + return true; +} + #else /* ! coherent mmap */ /* * don't support mmap for status and control records. */ +#define pcm_status_mmap_allowed(pcm_file) false + static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area) { @@ -3563,11 +3582,11 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) offset = area->vm_pgoff << PAGE_SHIFT; switch (offset) { case SNDRV_PCM_MMAP_OFFSET_STATUS: - if (pcm_file->no_compat_mmap) + if (!pcm_status_mmap_allowed(pcm_file)) return -ENXIO; return snd_pcm_mmap_status(substream, file, area); case SNDRV_PCM_MMAP_OFFSET_CONTROL: - if (pcm_file->no_compat_mmap) + if (!pcm_status_mmap_allowed(pcm_file)) return -ENXIO; return snd_pcm_mmap_control(substream, file, area); default: From 532a7784c376f2332d38c4c1576843c66343713d Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Mon, 26 Jun 2017 12:30:32 +0800 Subject: [PATCH 363/418] ALSA: hda/realtek - There is no loopback mixer in the ALC234/274/294 We have a Lenovo machine with the codec ALC294 on it, without the patch, the Node 0x0b is regarded as the loopback mixer, but the Node 0x0b in this codec is "Vendor Defined Widget" instead of the audio mixer, please see the log below: Node 0x0b [Vendor Defined Widget] wcaps 0xf00000: Mono Control: name="Beep Playback Volume", index=0, device=0 ControlAmp: chs=3, dir=In, idx=4, ofs=0 Control: name="Beep Playback Switch", index=0, device=0 ControlAmp: chs=3, dir=In, idx=4, ofs=0 And I have consulted with Realtek, so far the ALC234/274/294 all don't have loopback mixer. Cc: Kailang Yang Signed-off-by: Hui Wang 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 c4a1b496d7bb..bc00a37acc8a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6696,6 +6696,7 @@ static int patch_alc269(struct hda_codec *codec) case 0x10ec0274: case 0x10ec0294: spec->codec_variant = ALC269_TYPE_ALC294; + spec->gen.mixer_nid = 0; /* ALC2x4 does not have any loopback mixer path */ alc_update_coef_idx(codec, 0x6b, 0x0018, (1<<4) | (1<<3)); /* UAJ MIC Vref control by verb */ break; case 0x10ec0700: From 4b671f57747468d7c810caaf955f79ff1aece4d4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 19 Jun 2017 23:11:54 +0200 Subject: [PATCH 364/418] ALSA: pcm: Add an ioctl to specify the supported protocol version We have an ioctl to inform the PCM protocol version the running kernel supports, but there is no way to know which protocol version the user-space can understand. This lack of information caused headaches in the past when we tried to extend the ABI. For example, because we couldn't guarantee the validity of the reserved bytes, we had to introduce a new ioctl SNDRV_PCM_IOCTL_STATUS_EXT for assigning a few new fields in the formerly reserved bits. If we could know that it's a new alsa-lib, we could assume the availability of the new fields, thus we could have reused the existing SNDRV_PCM_IOCTL_STATUS. In order to improve the ABI extensibility, this patch adds a new ioctl for user-space to inform its supporting protocol version to the kernel. By reporting the supported protocol from user-space, the kernel can judge which feature should be provided and which not. With the addition of the new ioctl, the PCM protocol version is bumped to 2.0.14, too. User-space checks the kernel protocol version via SNDRV_PCM_INFO_PVERSION, then it sets the supported version back via SNDRV_PCM_INFO_USER_PVERSION. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 1 + include/uapi/sound/asound.h | 3 ++- sound/core/pcm_compat.c | 1 + sound/core/pcm_native.c | 7 +++++++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 5a22075c5fcf..24febf9e177c 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -218,6 +218,7 @@ struct snd_pcm_ops { struct snd_pcm_file { struct snd_pcm_substream *substream; int no_compat_mmap; + unsigned int user_pversion; /* supported protocol version */ }; struct snd_pcm_hw_rule; diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 7eee52eb7462..1949923a40bf 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -152,7 +152,7 @@ struct snd_hwdep_dsp_image { * * *****************************************************************************/ -#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 13) +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 14) typedef unsigned long snd_pcm_uframes_t; typedef signed long snd_pcm_sframes_t; @@ -564,6 +564,7 @@ enum { #define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info) #define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int) #define SNDRV_PCM_IOCTL_TTSTAMP _IOW('A', 0x03, int) +#define SNDRV_PCM_IOCTL_USER_PVERSION _IOW('A', 0x04, int) #define SNDRV_PCM_IOCTL_HW_REFINE _IOWR('A', 0x10, struct snd_pcm_hw_params) #define SNDRV_PCM_IOCTL_HW_PARAMS _IOWR('A', 0x11, struct snd_pcm_hw_params) #define SNDRV_PCM_IOCTL_HW_FREE _IO('A', 0x12) diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 8a0f8d51e95d..10f537f4d735 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -676,6 +676,7 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l case SNDRV_PCM_IOCTL_INFO: case SNDRV_PCM_IOCTL_TSTAMP: case SNDRV_PCM_IOCTL_TTSTAMP: + case SNDRV_PCM_IOCTL_USER_PVERSION: case SNDRV_PCM_IOCTL_HWSYNC: case SNDRV_PCM_IOCTL_PREPARE: case SNDRV_PCM_IOCTL_RESET: diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 9ade0c8b54a3..1c53d93e68f2 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2770,6 +2770,8 @@ static int snd_pcm_common_ioctl(struct file *file, struct snd_pcm_substream *substream, unsigned int cmd, void __user *arg) { + struct snd_pcm_file *pcm_file = file->private_data; + switch (cmd) { case SNDRV_PCM_IOCTL_PVERSION: return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0; @@ -2779,6 +2781,11 @@ static int snd_pcm_common_ioctl(struct file *file, return 0; case SNDRV_PCM_IOCTL_TTSTAMP: return snd_pcm_tstamp(substream, arg); + case SNDRV_PCM_IOCTL_USER_PVERSION: + if (get_user(pcm_file->user_pversion, + (unsigned int __user *)arg)) + return -EFAULT; + return 0; case SNDRV_PCM_IOCTL_HW_REFINE: return snd_pcm_hw_refine_user(substream, arg); case SNDRV_PCM_IOCTL_HW_PARAMS: From b602aa8eb1a0f52f0f9a09728b3b1c9133136656 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Jun 2017 11:54:37 +0200 Subject: [PATCH 365/418] ALSA: pcm: Disable only control mmap for explicit appl_ptr sync Now that user-space (typically alsa-lib) can specify which protocol version it supports, we can optimize the kernel code depending on the reported protocol version. In this patch, we change the previous hack for enforcing the appl_ptr sync by disabling status/control mmap. Instead of forcibly disabling both mmaps, we disable only the control mmap when user-space declares the supported protocol version new enough. For older user-space, still both PCM status and control mmaps are disabled when requested by the driver due to the compatibility reason. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 1c53d93e68f2..0d1834310531 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3388,12 +3388,23 @@ static bool pcm_status_mmap_allowed(struct snd_pcm_file *pcm_file) { if (pcm_file->no_compat_mmap) return false; - /* Disallow the status/control mmap when SYNC_APPLPTR flag is set; + /* See pcm_control_mmap_allowed() below. + * Since older alsa-lib requires both status and control mmaps to be + * coupled, we have to disable the status mmap for old alsa-lib, too. + */ + if (pcm_file->user_pversion < SNDRV_PROTOCOL_VERSION(2, 0, 14) && + (pcm_file->substream->runtime->hw.info & SNDRV_PCM_INFO_SYNC_APPLPTR)) + return false; + return true; +} + +static bool pcm_control_mmap_allowed(struct snd_pcm_file *pcm_file) +{ + if (pcm_file->no_compat_mmap) + return false; + /* Disallow the control mmap when SYNC_APPLPTR flag is set; * it enforces the user-space to fall back to snd_pcm_sync_ptr(), * thus it effectively assures the manual update of appl_ptr. - * In theory, it should be enough to disallow only PCM control mmap, - * but since the current alsa-lib implementation requires both status - * and control mmaps always paired, we have to disable both of them. */ if (pcm_file->substream->runtime->hw.info & SNDRV_PCM_INFO_SYNC_APPLPTR) return false; @@ -3405,6 +3416,7 @@ static bool pcm_status_mmap_allowed(struct snd_pcm_file *pcm_file) * don't support mmap for status and control records. */ #define pcm_status_mmap_allowed(pcm_file) false +#define pcm_control_mmap_allowed(pcm_file) false static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area) @@ -3593,7 +3605,7 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) return -ENXIO; return snd_pcm_mmap_status(substream, file, area); case SNDRV_PCM_MMAP_OFFSET_CONTROL: - if (!pcm_status_mmap_allowed(pcm_file)) + if (!pcm_control_mmap_allowed(pcm_file)) return -ENXIO; return snd_pcm_mmap_control(substream, file, area); default: From f03293d8fc97f07dbe4c54ce495c8dac172dc6e1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Jun 2017 08:13:41 +0200 Subject: [PATCH 366/418] ALSA: Fix forgotten dependency fix for tristate OSS sequencer kconfig In the commit 3d774d5ef066 ("ALSA: seq: Allow the tristate build of OSS emulation") we changed CONFIG_SND_SEQUENCER_OSS to tristate, but a couple of places were forgotten, namely, opl3 and emux Makefile. These contain the line like snd-opl3-synth-$(CONFIG_SND_SEQUENCER_OSS) += opl3_oss.o and this doesn't work any longer as expected because snd-opl3-synth can be built-in while CONFIG_SND_SEQUENCER_OSS=m. This patch fixes these places to build properly for the new kconfig dependency. In the end, we had to use ifneq() to satisfy the requirement. It's a bit ugly, but lesser evil. Fixes: 3d774d5ef066 ("ALSA: seq: Allow the tristate build of OSS emulation") Reported-by: kbuild test robot Signed-off-by: Takashi Iwai --- sound/drivers/opl3/Makefile | 4 +++- sound/synth/emux/Makefile | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/drivers/opl3/Makefile b/sound/drivers/opl3/Makefile index 7f2c2a10c4e5..d72b1e7b51c4 100644 --- a/sound/drivers/opl3/Makefile +++ b/sound/drivers/opl3/Makefile @@ -5,7 +5,9 @@ snd-opl3-lib-objs := opl3_lib.o opl3_synth.o snd-opl3-synth-y := opl3_seq.o opl3_midi.o opl3_drums.o -snd-opl3-synth-$(CONFIG_SND_SEQUENCER_OSS) += opl3_oss.o +ifneq ($(CONFIG_SND_SEQUENCER_OSS),) +snd-opl3-synth-y += opl3_oss.o +endif obj-$(CONFIG_SND_OPL3_LIB) += snd-opl3-lib.o obj-$(CONFIG_SND_OPL4_LIB) += snd-opl3-lib.o diff --git a/sound/synth/emux/Makefile b/sound/synth/emux/Makefile index 4599108452fd..d1bac923eb1b 100644 --- a/sound/synth/emux/Makefile +++ b/sound/synth/emux/Makefile @@ -6,6 +6,8 @@ snd-emux-synth-objs := emux.o emux_synth.o emux_seq.o emux_nrpn.o \ emux_effect.o emux_hwdep.o soundfont.o snd-emux-synth-$(CONFIG_SND_PROC_FS) += emux_proc.o -snd-emux-synth-$(CONFIG_SND_SEQUENCER_OSS) += emux_oss.o +ifneq ($(CONFIG_SND_SEQUENCER_OSS),) +snd-emux-synth-y += emux_oss.o +endif obj-$(CONFIG_SND_SYNTH_EMUX) += snd-emux-synth.o From 17890880bbf7bac8171054c7dca7a5162b23c5c2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Jun 2017 12:45:34 +0200 Subject: [PATCH 367/418] ALSA: hda - Skip card registration when no codec is found It's nonsense to register a card object when no codec is bound on it, as we don't support the deferred codec binding. Instead of registering an empty card object, just skip the registration by returning an error from azx_codec_configure(). Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 1c60beb5b70a..d1eb14842340 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1345,6 +1345,9 @@ int azx_codec_configure(struct azx *chip) list_for_each_codec_safe(codec, next, &chip->bus) { snd_hda_codec_configure(codec); } + + if (!azx_bus(chip)->num_codecs) + return -ENODEV; return 0; } EXPORT_SYMBOL_GPL(azx_codec_configure); From fcc88d91cd36d1343a0ccc09444b21f6b0dad2d8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Jun 2017 12:54:53 +0200 Subject: [PATCH 368/418] ALSA: hda - Bind with i915 component before codec binding We used a on-demand i915 component binding for IvyBridge and SandyBridge HDMI codecs, but it has a potential problem of the nested module loading. For avoiding that situation, assure the i915 binding happening at the controller driver level for PCH controller devices, where the initialization is performed in a detached work, instead of calling from the codec driver probe. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 35 +++++++++++++++++++++-------------- sound/pci/hda/patch_hdmi.c | 17 +++++------------ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 01eb1dc7b5b3..433a2df9edad 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1384,8 +1384,10 @@ static int azx_free(struct azx *chip) if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { if (hda->need_i915_power) snd_hdac_display_power(bus, false); - snd_hdac_i915_exit(bus); } + if (chip->driver_type == AZX_DRIVER_PCH || + (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)) + snd_hdac_i915_exit(bus); kfree(hda); return 0; @@ -2201,16 +2203,9 @@ static int azx_probe_continue(struct azx *chip) hda->probe_continued = 1; - /* Request display power well for the HDA controller or codec. For - * Haswell/Broadwell, both the display HDA controller and codec need - * this power. For other platforms, like Baytrail/Braswell, only the - * display codec needs the power and it can be released after probe. - */ - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - /* HSW/BDW controllers need this power */ - if (CONTROLLER_IN_GPU(pci)) - hda->need_i915_power = 1; - + /* bind with i915 if needed */ + if (chip->driver_type == AZX_DRIVER_PCH || + (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)) { err = snd_hdac_i915_init(bus); if (err < 0) { /* if the controller is bound only with HDMI/DP @@ -2222,9 +2217,22 @@ static int azx_probe_continue(struct azx *chip) dev_err(chip->card->dev, "HSW/BDW HD-audio HDMI/DP requires binding with gfx driver\n"); goto out_free; - } else - goto skip_i915; + } else { + /* don't bother any longer */ + chip->driver_caps &= ~AZX_DCAPS_I915_POWERWELL; + } } + } + + /* Request display power well for the HDA controller or codec. For + * Haswell/Broadwell, both the display HDA controller and codec need + * this power. For other platforms, like Baytrail/Braswell, only the + * display codec needs the power and it can be released after probe. + */ + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { + /* HSW/BDW controllers need this power */ + if (CONTROLLER_IN_GPU(pci)) + hda->need_i915_power = 1; err = snd_hdac_display_power(bus, true); if (err < 0) { @@ -2234,7 +2242,6 @@ static int azx_probe_continue(struct azx *chip) } } - skip_i915: err = azx_first_init(chip); if (err < 0) goto out_free; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 90e4ff87445e..feed8e8de2af 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -174,7 +174,6 @@ struct hdmi_spec { /* i915/powerwell (Haswell+/Valleyview+) specific */ bool use_acomp_notifier; /* use i915 eld_notify callback for hotplug */ struct i915_audio_component_audio_ops i915_audio_ops; - bool i915_bound; /* was i915 bound in this driver? */ struct hdac_chmap chmap; hda_nid_t vendor_nid; @@ -2234,8 +2233,6 @@ static void generic_spec_free(struct hda_codec *codec) struct hdmi_spec *spec = codec->spec; if (spec) { - if (spec->i915_bound) - snd_hdac_i915_exit(&codec->bus->core); hdmi_array_free(spec); kfree(spec); codec->spec = NULL; @@ -2607,21 +2604,17 @@ static int patch_i915_cpt_hdmi(struct hda_codec *codec) struct hdmi_spec *spec; int err; - /* no i915 component should have been bound before this */ - if (WARN_ON(codec->bus->core.audio_component)) - return -EBUSY; + /* requires i915 binding */ + if (!codec->bus->core.audio_component) { + codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n"); + return -ENODEV; + } err = alloc_generic_hdmi(codec); if (err < 0) return err; spec = codec->spec; - /* Try to bind with i915 now */ - err = snd_hdac_i915_init(&codec->bus->core); - if (err < 0) - goto error; - spec->i915_bound = true; - err = hdmi_parse_codec(codec); if (err < 0) goto error; From 43f6c8d97bbdc05858b3d64e4c683821ce46c2db Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Jun 2017 14:18:29 +0200 Subject: [PATCH 369/418] ALSA: hda - Minor code refactoring for Intel HDMI codec parsers No functional change, just a slight reduction of lines. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 87 +++++++++++++++----------------------- 1 file changed, 34 insertions(+), 53 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index feed8e8de2af..8704ea43381e 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2503,19 +2503,41 @@ static void i915_pin_cvt_fixup(struct hda_codec *codec, } } +/* precondition and allocation for Intel codecs */ +static int alloc_intel_hdmi(struct hda_codec *codec) +{ + /* requires i915 binding */ + if (!codec->bus->core.audio_component) { + codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n"); + return -ENODEV; + } + + return alloc_generic_hdmi(codec); +} + +/* parse and post-process for Intel codecs */ +static int parse_intel_hdmi(struct hda_codec *codec) +{ + int err; + + err = hdmi_parse_codec(codec); + if (err < 0) { + generic_spec_free(codec); + return err; + } + + generic_hdmi_init_per_pins(codec); + register_i915_notifier(codec); + return 0; +} + /* Intel Haswell and onwards; audio component with eld notifier */ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid) { struct hdmi_spec *spec; int err; - /* HSW+ requires i915 binding */ - if (!codec->bus->core.audio_component) { - codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n"); - return -ENODEV; - } - - err = alloc_generic_hdmi(codec); + err = alloc_intel_hdmi(codec); if (err < 0) return err; spec = codec->spec; @@ -2539,15 +2561,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid) spec->ops.setup_stream = i915_hsw_setup_stream; spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup; - err = hdmi_parse_codec(codec); - if (err < 0) { - generic_spec_free(codec); - return err; - } - - generic_hdmi_init_per_pins(codec); - register_i915_notifier(codec); - return 0; + return parse_intel_hdmi(codec); } static int patch_i915_hsw_hdmi(struct hda_codec *codec) @@ -2566,13 +2580,7 @@ static int patch_i915_byt_hdmi(struct hda_codec *codec) struct hdmi_spec *spec; int err; - /* requires i915 binding */ - if (!codec->bus->core.audio_component) { - codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n"); - return -ENODEV; - } - - err = alloc_generic_hdmi(codec); + err = alloc_intel_hdmi(codec); if (err < 0) return err; spec = codec->spec; @@ -2587,45 +2595,18 @@ static int patch_i915_byt_hdmi(struct hda_codec *codec) spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup; - err = hdmi_parse_codec(codec); - if (err < 0) { - generic_spec_free(codec); - return err; - } - - generic_hdmi_init_per_pins(codec); - register_i915_notifier(codec); - return 0; + return parse_intel_hdmi(codec); } /* Intel IronLake, SandyBridge and IvyBridge; with eld notifier */ static int patch_i915_cpt_hdmi(struct hda_codec *codec) { - struct hdmi_spec *spec; int err; - /* requires i915 binding */ - if (!codec->bus->core.audio_component) { - codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n"); - return -ENODEV; - } - - err = alloc_generic_hdmi(codec); + err = alloc_intel_hdmi(codec); if (err < 0) return err; - spec = codec->spec; - - err = hdmi_parse_codec(codec); - if (err < 0) - goto error; - - generic_hdmi_init_per_pins(codec); - register_i915_notifier(codec); - return 0; - - error: - generic_spec_free(codec); - return err; + return parse_intel_hdmi(codec); } /* From 6b5da66322c50b4fa22f9343dcb968496f831361 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 28 Jun 2017 14:49:36 +0200 Subject: [PATCH 370/418] ASoC: rt5645: read jd1_1 status for jd detection Read the jd status after invert control. The benefit is we don't need to invert the reading jd status when jd invert is needed. Signed-off-by: Bard Liao Tested-by: Hans de Goede Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 87844a45886a..8e419ea418e9 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3238,24 +3238,16 @@ static void rt5645_jack_detect_work(struct work_struct *work) snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE); return; - case 1: /* 2 port */ - val = snd_soc_read(rt5645->codec, RT5645_A_JD_CTRL1) & 0x0070; - break; - default: /* 1 port */ - val = snd_soc_read(rt5645->codec, RT5645_A_JD_CTRL1) & 0x0020; + default: /* read rt5645 jd1_1 status */ + val = snd_soc_read(rt5645->codec, RT5645_INT_IRQ_ST) & 0x1000; break; } - switch (val) { - /* jack in */ - case 0x30: /* 2 port */ - case 0x0: /* 1 port or 2 port */ - if (rt5645->jack_type == 0) { - report = rt5645_jack_detect(rt5645->codec, 1); - /* for push button and jack out */ - break; - } + if (!val && (rt5645->jack_type == 0)) { /* jack in */ + report = rt5645_jack_detect(rt5645->codec, 1); + } else if (!val && rt5645->jack_type != 0) { + /* for push button and jack out */ btn_type = 0; if (snd_soc_read(rt5645->codec, RT5645_INT_IRQ_ST) & 0x4) { /* button pressed */ @@ -3302,19 +3294,12 @@ static void rt5645_jack_detect_work(struct work_struct *work) mod_timer(&rt5645->btn_check_timer, msecs_to_jiffies(100)); } - - break; - /* jack out */ - case 0x70: /* 2 port */ - case 0x10: /* 2 port */ - case 0x20: /* 1 port */ + } else { + /* jack out */ report = 0; snd_soc_update_bits(rt5645->codec, RT5645_INT_IRQ_ST, 0x1, 0x0); rt5645_jack_detect(rt5645->codec, 0); - break; - default: - break; } snd_soc_jack_report(rt5645->hp_jack, report, SND_JACK_HEADPHONE); From 895750228c9d3361ed82e9786322604de3232466 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 28 Jun 2017 14:49:37 +0200 Subject: [PATCH 371/418] ASoC: rt5645: rename jd_invert flag in platform data The jd_invert flag is actually used for level triggered IRQ. Rename it to let code more readable. Signed-off-by: Bard Liao Tested-by: Hans de Goede Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- include/sound/rt5645.h | 4 ++-- sound/soc/codecs/rt5645.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/sound/rt5645.h b/include/sound/rt5645.h index a5cf6152e778..c427f10a39ae 100644 --- a/include/sound/rt5645.h +++ b/include/sound/rt5645.h @@ -21,8 +21,8 @@ struct rt5645_platform_data { /* 0 = IN2P; 1 = GPIO6; 2 = GPIO10; 3 = GPIO12 */ unsigned int jd_mode; - /* Invert JD when jack insert */ - bool jd_invert; + /* Use level triggered irq */ + bool level_trigger_irq; }; #endif diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 8e419ea418e9..e0c09bbd3f12 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3151,7 +3151,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) snd_soc_dapm_sync(dapm); rt5645->jack_type = SND_JACK_HEADPHONE; } - if (rt5645->pdata.jd_invert) + if (rt5645->pdata.level_trigger_irq) regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR); } else { /* jack out */ @@ -3172,7 +3172,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) snd_soc_dapm_disable_pin(dapm, "LDO2"); snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); snd_soc_dapm_sync(dapm); - if (rt5645->pdata.jd_invert) + if (rt5645->pdata.level_trigger_irq) regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV); } @@ -3586,7 +3586,7 @@ static struct rt5645_platform_data buddy_platform_data = { .dmic1_data_pin = RT5645_DMIC_DATA_GPIO5, .dmic2_data_pin = RT5645_DMIC_DATA_IN2P, .jd_mode = 3, - .jd_invert = true, + .level_trigger_irq = true, }; static struct dmi_system_id dmi_platform_intel_broadwell[] = { @@ -3838,7 +3838,7 @@ 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) { + if (rt5645->pdata.level_trigger_irq) { regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV); } From aea086dda2d5df659a7c5d9efe85721e9442a133 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 28 Jun 2017 14:49:38 +0200 Subject: [PATCH 372/418] ASoC: rt5645: add inv_jd1_1 flag The flag will invert jd1_1 status. Which will be used if the jack connector is normal closed. Signed-off-by: Bard Liao Tested-by: Hans de Goede Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- include/sound/rt5645.h | 2 ++ sound/soc/codecs/rt5645.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/include/sound/rt5645.h b/include/sound/rt5645.h index c427f10a39ae..d0c33a9972b9 100644 --- a/include/sound/rt5645.h +++ b/include/sound/rt5645.h @@ -23,6 +23,8 @@ struct rt5645_platform_data { unsigned int jd_mode; /* Use level triggered irq */ bool level_trigger_irq; + /* Invert JD1_1 status polarity */ + bool inv_jd1_1; }; #endif diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index e0c09bbd3f12..162044d82632 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3833,6 +3833,10 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, default: break; } + if (rt5645->pdata.inv_jd1_1) { + regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, + RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV); + } } regmap_update_bits(rt5645->regmap, RT5645_ADDA_CLK1, From ea2b5a6e3a386b89d7f9148ff8be6c78d13542a0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Jun 2017 14:49:39 +0200 Subject: [PATCH 373/418] ASoC: rt5645: Add jack detection workaround for GPD Win GPD Win requires jd_mode=3 and the inverted flag for making the jack detection working. Unfortunately, the BIOS doesn't give a nice way to match with DMI strings, and the only working way so far is to match with the board vendor/name/version/date to some known patterns. Hopefully other vendors won't do such a stupid setup, too... Thanks to Hans de Goede for the DMI matching suggestion. Suggested-by: Hans de Goede Tested-by: Hans de Goede Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 162044d82632..308c22f5909a 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3599,6 +3599,33 @@ static struct dmi_system_id dmi_platform_intel_broadwell[] = { { } }; +static struct rt5645_platform_data gpd_win_platform_data = { + .jd_mode = 3, + .inv_jd1_1 = true, +}; + +static const struct dmi_system_id dmi_platform_gpd_win[] = { + { + /* + * Match for the GPDwin which unfortunately uses somewhat + * generic dmi strings, which is why we test for 4 strings. + * Comparing against 23 other byt/cht boards, board_vendor + * and board_name are unique to the GPDwin, where as only one + * other board has the same board_serial and 3 others have + * the same default product_name. Also the GPDwin is the + * only device to have both board_ and product_name not set. + */ + .ident = "GPD Win", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Default string"), + DMI_MATCH(DMI_BOARD_SERIAL, "Default string"), + DMI_MATCH(DMI_PRODUCT_NAME, "Default string"), + }, + }, + {} +}; + static bool rt5645_check_dp(struct device *dev) { if (device_property_present(dev, "realtek,in2-differential") || @@ -3649,6 +3676,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, rt5645_parse_dt(rt5645, &i2c->dev); else if (dmi_check_system(dmi_platform_intel_braswell)) rt5645->pdata = general_platform_data; + else if (dmi_check_system(dmi_platform_gpd_win)) + rt5645->pdata = gpd_win_platform_data; rt5645->gpiod_hp_det = devm_gpiod_get_optional(&i2c->dev, "hp-detect", GPIOD_IN); From a6ff8ddcf3f38ec84337e5e7eb3e0e9a73754cf5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 28 Jun 2017 15:01:24 +0200 Subject: [PATCH 374/418] ASoC: rt5645: del btn_check_timer on remove The timer may still be running when rt5645_i2c_remove() gets called, call del_timer_sync() to make sure it is stopped. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 87844a45886a..206b41688d96 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3897,6 +3897,7 @@ static int rt5645_i2c_remove(struct i2c_client *i2c) cancel_delayed_work_sync(&rt5645->jack_detect_work); cancel_delayed_work_sync(&rt5645->rcclock_work); + del_timer_sync(&rt5645->btn_check_timer); snd_soc_unregister_codec(&i2c->dev); regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies); From 81321fe9fb69004e71353a602f9d51f656469cdd Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 28 Jun 2017 15:20:06 +0300 Subject: [PATCH 375/418] ASoC: stm32: sai: remove some stray tabs This line was accidentally indented too far. Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai_sub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index ba3fdc777ed8..90d439613899 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -631,7 +631,7 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, dev_dbg(cpu_dai->dev, "SAI clock %d, divider %d\n", sai_clk_rate, div); mask = SAI_XCR1_MCKDIV_MASK(SAI_XCR1_MCKDIV_WIDTH(version)); - cr1 = SAI_XCR1_MCKDIV_SET(div); + cr1 = SAI_XCR1_MCKDIV_SET(div); ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, mask, cr1); if (ret < 0) { dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); From 98faf436ee05503e258ee934a9de8d8a3472b40f Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 28 Jun 2017 15:01:39 +0800 Subject: [PATCH 376/418] ASoC: Drop invalid DMI fields when setting card long name from DMI info Sometimes DMI fields may be invalid and so can't give useful vendor, product or board info, such as "Type2 - Board Manufacturer" or "Type1 - TBD by OEM". Including such invalid DMI fileds may create silly card long name. So this patch creates a black list of invalid strings. And if a DMI field contains any string in this list, it will be excluded from the card long name. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index aae099c0e502..e14e04cc0a93 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -68,6 +68,20 @@ static int pmdown_time = 5000; module_param(pmdown_time, int, 0); MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); +/* If a DMI filed contain strings in this blacklist (e.g. + * "Type2 - Board Manufacturer" or "Type1 - TBD by OEM"), it will be taken + * as invalid and dropped when setting the card long name from DMI info. + */ +static const char * const dmi_blacklist[] = { + "To be filled by OEM", + "TBD by OEM", + "Default String", + "Board Manufacturer", + "Board Vendor Name", + "Board Product Name", + NULL, /* terminator */ +}; + /* returns the minimum number of bytes needed to represent * a particular given value */ static int min_bytes_needed(unsigned long val) @@ -1933,6 +1947,22 @@ static void cleanup_dmi_name(char *name) name[j] = '\0'; } +/* Check if a DMI field is valid, i.e. not containing any string + * in the black list. + */ +static int is_dmi_valid(const char *field) +{ + int i = 0; + + while (dmi_blacklist[i]) { + if (strstr(field, dmi_blacklist[i])) + return 0; + i++; + }; + + return 1; +} + /** * snd_soc_set_dmi_name() - Register DMI names to card * @card: The card to register DMI names @@ -1975,17 +2005,18 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) /* make up dmi long name as: vendor.product.version.board */ vendor = dmi_get_system_info(DMI_BOARD_VENDOR); - if (!vendor) { + if (!vendor || !is_dmi_valid(vendor)) { dev_warn(card->dev, "ASoC: no DMI vendor name!\n"); return 0; } + snprintf(card->dmi_longname, sizeof(card->snd_card->longname), "%s", vendor); cleanup_dmi_name(card->dmi_longname); product = dmi_get_system_info(DMI_PRODUCT_NAME); - if (product) { + if (product && is_dmi_valid(product)) { len = strlen(card->dmi_longname); snprintf(card->dmi_longname + len, longname_buf_size - len, @@ -1999,7 +2030,7 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) * name in the product version field */ product_version = dmi_get_system_info(DMI_PRODUCT_VERSION); - if (product_version) { + if (product_version && is_dmi_valid(product_version)) { len = strlen(card->dmi_longname); snprintf(card->dmi_longname + len, longname_buf_size - len, @@ -2012,7 +2043,7 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) } board = dmi_get_system_info(DMI_BOARD_NAME); - if (board) { + if (board && is_dmi_valid(board)) { len = strlen(card->dmi_longname); snprintf(card->dmi_longname + len, longname_buf_size - len, From c25695ae88ce2683029c6c242d610e3b0e809efc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 23 Jun 2017 12:21:00 -0500 Subject: [PATCH 377/418] ASoC: Intel: cht_bsw_rt5672: 19.2MHz clock for Baytrail platforms Lenovo platforms use RT5670 with Baytrail, add the required MCLK control and configuration to 19.2MHz Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=96691 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5672.c | 89 ++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 9 deletions(-) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index e4d46d4360d7..bc2a52de06a3 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include #include @@ -31,8 +33,11 @@ #define CHT_PLAT_CLK_3_HZ 19200000 #define CHT_CODEC_DAI "rt5670-aif1" -static struct snd_soc_jack cht_bsw_headset; -static char cht_bsw_codec_name[16]; +struct cht_mc_private { + struct snd_soc_jack headset; + char codec_name[16]; + struct clk *mclk; +}; /* Headset jack detection DAPM pins */ static struct snd_soc_jack_pin cht_bsw_headset_pins[] = { @@ -64,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,6 +79,15 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, } 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; + } + } + /* set codec PLL source to the 19.2MHz platform clock (MCLK) */ ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK, CHT_PLAT_CLK_3_HZ, 48000 * 512); @@ -96,6 +111,9 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, */ snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, 48000 * 512, SND_SOC_CLOCK_IN); + + if (ctx->mclk) + clk_disable_unprepare(ctx->mclk); } return 0; } @@ -171,6 +189,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) int ret; struct snd_soc_dai *codec_dai = runtime->codec_dai; struct snd_soc_codec *codec = codec_dai->codec; + struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); @@ -194,13 +213,37 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) RT5670_CLK_SEL_I2S1_ASRC); ret = snd_soc_card_jack_new(runtime->card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2, &cht_bsw_headset, - cht_bsw_headset_pins, ARRAY_SIZE(cht_bsw_headset_pins)); + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2, + &ctx->headset, + cht_bsw_headset_pins, + ARRAY_SIZE(cht_bsw_headset_pins)); if (ret) return ret; - rt5670_set_jack_detect(codec, &cht_bsw_headset); + rt5670_set_jack_detect(codec, &ctx->headset); + 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; + } + } return 0; } @@ -341,34 +384,62 @@ static struct snd_soc_card snd_soc_card_cht = { .resume_post = cht_resume_post, }; +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; +} + #define RT5672_I2C_DEFAULT "i2c-10EC5670:00" static int snd_cht_mc_probe(struct platform_device *pdev) { int ret_val = 0; + struct cht_mc_private *drv; struct sst_acpi_mach *mach = pdev->dev.platform_data; const char *i2c_name; int i; - strcpy(cht_bsw_codec_name, RT5672_I2C_DEFAULT); + drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); + if (!drv) + return -ENOMEM; + + strcpy(drv->codec_name, RT5672_I2C_DEFAULT); /* fixup codec name based on HID */ if (mach) { i2c_name = sst_acpi_find_name_from_hid(mach->id); if (i2c_name) { - snprintf(cht_bsw_codec_name, sizeof(cht_bsw_codec_name), + snprintf(drv->codec_name, sizeof(drv->codec_name), "i2c-%s", i2c_name); for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { if (!strcmp(cht_dailink[i].codec_name, RT5672_I2C_DEFAULT)) { cht_dailink[i].codec_name = - cht_bsw_codec_name; + drv->codec_name; break; } } } } + 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(&snd_soc_card_cht, drv); + /* register the soc card */ snd_soc_card_cht.dev = &pdev->dev; ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); From 8cffb5034ee033fa292cb1ab7a082b57ce2c740b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 23 Jun 2017 12:21:01 -0500 Subject: [PATCH 378/418] ASoC: codecs: rt5670: fix jd mode for Lenovo Miix 2 10 jd mode 2 (3.3V) is required apparently Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=96691 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index e27c5a4a0a15..d90c74ef5c42 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2849,6 +2849,10 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Tablet B"), }, }, + {} +}; + +static const struct dmi_system_id dmi_platform_intel_bytcht_jdmode2[] = { { .ident = "Lenovo Thinkpad Tablet 10", .matches = { @@ -2883,6 +2887,11 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P; rt5670->pdata.dev_gpio = true; rt5670->pdata.jd_mode = 1; + } else if (dmi_check_system(dmi_platform_intel_bytcht_jdmode2)) { + rt5670->pdata.dmic_en = true; + rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P; + rt5670->pdata.dev_gpio = true; + rt5670->pdata.jd_mode = 2; } rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap); From 286345eef97ea8f4ea223410f025ed35f265e506 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Fri, 23 Jun 2017 12:35:00 -0400 Subject: [PATCH 379/418] ASoC: dwc: Added a quirk DW_I2S_QUIRK_16BIT_IDX_OVERRIDE to dwc driver Added quirk DW_I2S_QUIRK_16BIT_IDX_OVERRIDE to Designware driver. This quirk will set idx value to 1. By setting this quirk, it will override supported format as 16 bit resolution and bus width as 2 Bytes. Reviewed-by: Alex Deucher Signed-off-by: Vijendar Mukunda Signed-off-by: Alex Deucher Signed-off-by: Mark Brown --- include/sound/designware_i2s.h | 1 + sound/soc/dwc/dwc-i2s.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/include/sound/designware_i2s.h b/include/sound/designware_i2s.h index 5681855396c4..830f5caa915c 100644 --- a/include/sound/designware_i2s.h +++ b/include/sound/designware_i2s.h @@ -47,6 +47,7 @@ struct i2s_platform_data { #define DW_I2S_QUIRK_COMP_REG_OFFSET (1 << 0) #define DW_I2S_QUIRK_COMP_PARAM1 (1 << 1) + #define DW_I2S_QUIRK_16BIT_IDX_OVERRIDE (1 << 2) unsigned int quirks; unsigned int i2s_reg_comp1; unsigned int i2s_reg_comp2; diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index 9c46e4112026..916067638180 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -496,6 +496,8 @@ static int dw_configure_dai(struct dw_i2s_dev *dev, idx = COMP1_TX_WORDSIZE_0(comp1); if (WARN_ON(idx >= ARRAY_SIZE(formats))) return -EINVAL; + if (dev->quirks & DW_I2S_QUIRK_16BIT_IDX_OVERRIDE) + idx = 1; dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM; dw_i2s_dai->playback.channels_max = 1 << (COMP1_TX_CHANNELS(comp1) + 1); @@ -508,6 +510,8 @@ static int dw_configure_dai(struct dw_i2s_dev *dev, idx = COMP2_RX_WORDSIZE_0(comp2); if (WARN_ON(idx >= ARRAY_SIZE(formats))) return -EINVAL; + if (dev->quirks & DW_I2S_QUIRK_16BIT_IDX_OVERRIDE) + idx = 1; dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM; dw_i2s_dai->capture.channels_max = 1 << (COMP1_RX_CHANNELS(comp1) + 1); @@ -543,6 +547,8 @@ static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev, if (ret < 0) return ret; + if (dev->quirks & DW_I2S_QUIRK_16BIT_IDX_OVERRIDE) + idx = 1; /* Set DMA slaves info */ dev->play_dma_data.pd.data = pdata->play_dma_data; dev->capture_dma_data.pd.data = pdata->capture_dma_data; From 812a532655f56bcf70b8cc7345748534b56278c3 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Mon, 26 Jun 2017 15:35:16 +0800 Subject: [PATCH 380/418] ASoC: nau8825: debug message of crosstalk bypass Add debug message for crosstalk function bypass. Signed-off-by: John Hsu Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index a8c7a556a6a8..80bae481e75d 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -2440,6 +2440,8 @@ static void nau8825_print_device_properties(struct nau8825 *nau8825) nau8825->jack_insert_debounce); dev_dbg(dev, "jack-eject-debounce: %d\n", nau8825->jack_eject_debounce); + dev_dbg(dev, "crosstalk-bypass: %d\n", + nau8825->xtalk_bypass); } static int nau8825_read_device_properties(struct device *dev, From 8e2d163b736e719ef850493ac7740a61d30b8f23 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 28 Jun 2017 15:38:00 +0800 Subject: [PATCH 381/418] ASoC: rt5670: fix wrong audio route When we select "IF1_ADC4" for IF1 ADC Muxes, it is actually connected to "TxDP_ADC" widget. This patch fixes the audio route and remove the unexisting "IF1_ADC4" widget. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index e27c5a4a0a15..d95d2e693dc6 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -1717,7 +1717,6 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = { SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), /* DSP */ SND_SOC_DAPM_PGA("TxDP_ADC", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -2086,13 +2085,13 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { { "IF1 ADC1 IN1 Mux", "IF1_ADC3", "IF1_ADC3" }, { "IF1 ADC1 IN2 Mux", "IF1_ADC1_IN1", "IF1 ADC1 IN1 Mux" }, - { "IF1 ADC1 IN2 Mux", "IF1_ADC4", "IF1_ADC4" }, + { "IF1 ADC1 IN2 Mux", "IF1_ADC4", "TxDP_ADC" }, { "IF1 ADC2 IN Mux", "IF_ADC2", "IF_ADC2" }, { "IF1 ADC2 IN Mux", "VAD_ADC", "VAD_ADC" }, { "IF1 ADC2 IN1 Mux", "IF1_ADC2_IN", "IF1 ADC2 IN Mux" }, - { "IF1 ADC2 IN1 Mux", "IF1_ADC4", "IF1_ADC4" }, + { "IF1 ADC2 IN1 Mux", "IF1_ADC4", "TxDP_ADC" }, { "IF1_ADC1" , NULL, "IF1 ADC1 IN2 Mux" }, { "IF1_ADC2" , NULL, "IF1 ADC2 IN1 Mux" }, From 90384fcc054f701e17e9cbbff5c14db5f877c614 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 28 Jun 2017 15:38:01 +0800 Subject: [PATCH 382/418] ASoC: rt5670: remove duplicate route. { "ADC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll }, and { "ADC Stereo2 Filter", NULL, "PLL1", is_sys_clk_from_pll }, are defined twice in the driver. Signed-off-by: Bard Liao 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 d95d2e693dc6..1146a968cb4d 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2022,7 +2022,6 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { { "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" }, { "Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter" }, - { "ADC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll }, { "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" }, { "Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter" }, @@ -2061,7 +2060,6 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { { "Stereo2 ADC MIXL", NULL, "Stereo2 ADC LR Mux" }, { "Stereo2 ADC MIXL", NULL, "ADC Stereo2 Filter" }, - { "ADC Stereo2 Filter", NULL, "PLL1", is_sys_clk_from_pll }, { "Stereo2 ADC MIXR", NULL, "Sto2 ADC MIXR" }, { "Stereo2 ADC MIXR", NULL, "ADC Stereo2 Filter" }, From 6c28ce3c425e32d372c7c6ee98d3c3711f13ad69 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 28 Jun 2017 15:38:02 +0800 Subject: [PATCH 383/418] ASoC: rt5670: move set_sysclk to codec level Move set_sysclk to codec level and people can use it at both codec and dai level. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 1146a968cb4d..7fa63ad366dd 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2442,10 +2442,9 @@ static int rt5670_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai, - int clk_id, unsigned int freq, int dir) +static int rt5670_set_codec_sysclk(struct snd_soc_dai *dai, int clk_id, + int source, unsigned int freq, int dir) { - struct snd_soc_codec *codec = dai->codec; struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); unsigned int reg_val = 0; @@ -2469,7 +2468,7 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai, if (clk_id != RT5670_SCLK_S_RCCLK) rt5670->sysclk_src = clk_id; - dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + dev_dbg(codec->dev, "Sysclk : %dHz clock id : %d\n", freq, clk_id); return 0; } @@ -2721,7 +2720,6 @@ static int rt5670_resume(struct snd_soc_codec *codec) static const struct snd_soc_dai_ops rt5670_aif_dai_ops = { .hw_params = rt5670_hw_params, .set_fmt = rt5670_set_dai_fmt, - .set_sysclk = rt5670_set_dai_sysclk, .set_tdm_slot = rt5670_set_tdm_slot, .set_pll = rt5670_set_dai_pll, }; @@ -2774,6 +2772,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5670 = { .resume = rt5670_resume, .set_bias_level = rt5670_set_bias_level, .idle_bias_off = true, + .set_sysclk = rt5670_set_codec_sysclk, .component_driver = { .controls = rt5670_snd_controls, .num_controls = ARRAY_SIZE(rt5670_snd_controls), From 5800b6970c6408d77c0286cba715d506313a2043 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 27 Jun 2017 10:28:44 +0800 Subject: [PATCH 384/418] ASoC: rt5651: remove unexisting Muxes These MUXes are unexisting. So, remove them. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5651.c | 44 +-------------------------------------- 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index f5d34153e21f..db05b60d5002 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -586,44 +586,6 @@ static const struct snd_kcontrol_new hpo_r_mute_control = SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_HP_VOL, RT5651_R_MUTE_SFT, 1, 1); -/* INL/R source */ -static const char * const rt5651_inl_src[] = {"IN2P", "HPOVOLLP"}; - -static SOC_ENUM_SINGLE_DECL( - rt5651_inl_enum, RT5651_INL1_INR1_VOL, - RT5651_INL_SEL_SFT, rt5651_inl_src); - -static const struct snd_kcontrol_new rt5651_inl1_mux = - SOC_DAPM_ENUM("INL1 source", rt5651_inl_enum); - -static const char * const rt5651_inr1_src[] = {"IN2N", "HPOVOLRP"}; - -static SOC_ENUM_SINGLE_DECL( - rt5651_inr1_enum, RT5651_INL1_INR1_VOL, - RT5651_INR_SEL_SFT, rt5651_inr1_src); - -static const struct snd_kcontrol_new rt5651_inr1_mux = - SOC_DAPM_ENUM("INR1 source", rt5651_inr1_enum); - -static const char * const rt5651_inl2_src[] = {"IN3P", "OUTVOLLP"}; - -static SOC_ENUM_SINGLE_DECL( - rt5651_inl2_enum, RT5651_INL2_INR2_VOL, - RT5651_INL_SEL_SFT, rt5651_inl2_src); - -static const struct snd_kcontrol_new rt5651_inl2_mux = - SOC_DAPM_ENUM("INL2 source", rt5651_inl2_enum); - -static const char * const rt5651_inr2_src[] = {"IN3N", "OUTVOLRP"}; - -static SOC_ENUM_SINGLE_DECL( - rt5651_inr2_enum, RT5651_INL2_INR2_VOL, - RT5651_INR_SEL_SFT, rt5651_inr2_src); - -static const struct snd_kcontrol_new rt5651_inr2_mux = - SOC_DAPM_ENUM("INR2 source", rt5651_inr2_enum); - - /* Stereo ADC source */ static const char * const rt5651_stereo1_adc1_src[] = {"DD MIX", "ADC"}; @@ -955,11 +917,7 @@ static const struct snd_soc_dapm_widget rt5651_dapm_widgets[] = { RT5651_PWR_IN2_L_BIT, 0, NULL, 0), SND_SOC_DAPM_PGA("INR2 VOL", RT5651_PWR_VOL, RT5651_PWR_IN2_R_BIT, 0, NULL, 0), - /* IN Mux */ - SND_SOC_DAPM_MUX("INL1 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inl1_mux), - SND_SOC_DAPM_MUX("INR1 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inr1_mux), - SND_SOC_DAPM_MUX("INL2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inl2_mux), - SND_SOC_DAPM_MUX("INR2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inr2_mux), + /* REC Mixer */ SND_SOC_DAPM_MIXER("RECMIXL", RT5651_PWR_MIXER, RT5651_PWR_RM_L_BIT, 0, rt5651_rec_l_mix, ARRAY_SIZE(rt5651_rec_l_mix)), From 105e56f1ec335ab62b920882e755da49e81e5b60 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 27 Jun 2017 10:05:29 +0800 Subject: [PATCH 385/418] ASoC: rt5645: enable speaker protection features This patch is uploaded for enabling the speaker protection features of the audio codec. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 308c22f5909a..630374ee692a 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -59,7 +59,7 @@ static const struct regmap_range_cfg rt5645_ranges[] = { static const struct reg_sequence init_list[] = { {RT5645_PR_BASE + 0x3d, 0x3600}, - {RT5645_PR_BASE + 0x1c, 0xfd20}, + {RT5645_PR_BASE + 0x1c, 0xfd70}, {RT5645_PR_BASE + 0x20, 0x611f}, {RT5645_PR_BASE + 0x21, 0x4040}, {RT5645_PR_BASE + 0x23, 0x0004}, @@ -3759,6 +3759,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, ret); } + regmap_update_bits(rt5645->regmap, RT5645_CLSD_OUT_CTRL, 0xc0, 0xc0); + if (rt5645->pdata.in2_diff) regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL, RT5645_IN_DF2, RT5645_IN_DF2); From e3839bd6f56a291f00a4c3737eb15ca0344a82a9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 19 Jun 2017 00:39:29 +0000 Subject: [PATCH 386/418] drm: dw-hdmi-i2s: add .get_dai_id callback for ALSA SoC ALSA SoC needs to know connected DAI ID for probing. It is not a big problem if device/driver was only for sound, but getting DAI ID will be difficult if device includes both Video/Sound, like HDMI. To solve this issue, this patch adds new .get_dai_id callback on hdmi_codec_ops. dw-hdmi-i2s will assume that HDMI sound will be connected to reg = <2>. Then, ALSA SoC side will recognized it as DAI 0 ports { #address-cells = <1>; #size-cells = <0>; port@0 { reg = <0>; /* HDMI Video IN */ }; port@1 { reg = <1>; /* HDMI OUT */ }; port@2 { reg = <2>; /* HDMI Sound IN */ }; }; Signed-off-by: Kuninori Morimoto Acked-by: Archit Taneja Signed-off-by: Mark Brown --- .../display/bridge/renesas,dw-hdmi.txt | 9 +++++++- .../drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 21 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.txt b/Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.txt index f6b3f36d422b..81b68580e199 100644 --- a/Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.txt +++ b/Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.txt @@ -25,7 +25,8 @@ Required properties: - clock-names: Shall contain "iahb" and "isfr" as defined in dw_hdmi.txt. - ports: See dw_hdmi.txt. The DWC HDMI shall have one port numbered 0 corresponding to the video input of the controller and one port numbered 1 - corresponding to its HDMI output. Each port shall have a single endpoint. + corresponding to its HDMI output, and one port numbered 2 corresponding to + sound input of the controller. Each port shall have a single endpoint. Optional properties: @@ -59,6 +60,12 @@ Example: remote-endpoint = <&hdmi0_con>; }; }; + port@2 { + reg = <2>; + rcar_dw_hdmi0_sound_in: endpoint { + remote-endpoint = <&hdmi_sound_out>; + }; + }; }; }; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c index aaf287d2e91d..b2cf59f54c88 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c @@ -82,9 +82,30 @@ static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data) hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0); } +static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component, + struct device_node *endpoint) +{ + struct of_endpoint of_ep; + int ret; + + ret = of_graph_parse_endpoint(endpoint, &of_ep); + if (ret < 0) + return ret; + + /* + * HDMI sound should be located as reg = <2> + * Then, it is sound port 0 + */ + if (of_ep.port == 2) + return 0; + + return -EINVAL; +} + static struct hdmi_codec_ops dw_hdmi_i2s_ops = { .hw_params = dw_hdmi_i2s_hw_params, .audio_shutdown = dw_hdmi_i2s_audio_shutdown, + .get_dai_id = dw_hdmi_i2s_get_dai_id, }; static int snd_dw_hdmi_probe(struct platform_device *pdev) From 7204e97685634813d8456f1900b7f38fa7701e60 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 13 Jun 2017 14:59:49 -0700 Subject: [PATCH 387/418] drm: adv7511_audio: Add .get_dai_id callback to map port number to dai id ALSA SoC needs to know connected DAI ID for probing. Using the new audio-card-graph approach, ports/endpoints are used to describe how the links are connected. Unfortunately, since ports/endpoints are used as well for video linkages, there are some issues mixing the port ids to the two (video and audio) namespaces. To solve this issue, this patch adds new .get_dai_id callback on hdmi_codec_ops. The will assume that HDMI audio out will be connected to reg = <2>. This will then be remapped to the ALSA SoC side will as DAI 0. Allowing the adv7511's hdmi audio support to be used with the audio-card-graph. Credit to Kuninori Morimoto who's patch to dw-hdmi-i2s-audio.c was what this was mostly copy-pasted from. Cc: Kuninori Morimoto Cc: Archit Taneja Cc: Mark Brown Cc: Rob Herring Cc: David Airlie Cc: Lars-Peter Clausen Cc: Linux-ALSA Cc: dri-devel@lists.freedesktop.org Signed-off-by: John Stultz Signed-off-by: Mark Brown --- .../bindings/display/bridge/adi,adv7511.txt | 8 +++++++ .../gpu/drm/bridge/adv7511/adv7511_audio.c | 22 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt index 00ea670b8c4d..06668bca7ffc 100644 --- a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt +++ b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt @@ -78,6 +78,7 @@ graph bindings specified in Documentation/devicetree/bindings/graph.txt. remote endpoint phandle should be a reference to a valid mipi_dsi_host device node. - Video port 1 for the HDMI output +- Audio port 2 for the HDMI audio input Example @@ -112,5 +113,12 @@ Example remote-endpoint = <&hdmi_connector_in>; }; }; + + port@2 { + reg = <2>; + codec_endpoint: endpoint { + remote-endpoint = <&i2s0_cpu_endpoint>; + }; + }; }; }; diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c index cf92ebfe6ab7..67469c26bae8 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "adv7511.h" @@ -182,10 +183,31 @@ static void audio_shutdown(struct device *dev, void *data) { } +static int adv7511_hdmi_i2s_get_dai_id(struct snd_soc_component *component, + struct device_node *endpoint) +{ + struct of_endpoint of_ep; + int ret; + + ret = of_graph_parse_endpoint(endpoint, &of_ep); + if (ret < 0) + return ret; + + /* + * HDMI sound should be located as reg = <2> + * Then, it is sound port 0 + */ + if (of_ep.port == 2) + return 0; + + return -EINVAL; +} + static const struct hdmi_codec_ops adv7511_codec_ops = { .hw_params = adv7511_hdmi_hw_params, .audio_shutdown = audio_shutdown, .audio_startup = audio_startup, + .get_dai_id = adv7511_hdmi_i2s_get_dai_id, }; static struct hdmi_codec_pdata codec_data = { From fcc6c877a01f83cbce1cca885ea62df6a10d33c3 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Thu, 29 Jun 2017 15:21:27 +0800 Subject: [PATCH 388/418] ALSA: hda/realtek - Support Dell headset mode for ALC3271 Add DELL4_MIC_NO_PRESENCE model. Add the pin configuration value of this machine into the pin_quirk table to make DELL4_MIC_NO_PRESENCE apply to this machine. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index bc00a37acc8a..c79491a1cd47 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5105,6 +5105,7 @@ enum { ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, + ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, ALC269_FIXUP_HEADSET_MODE, ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC, ALC269_FIXUP_ASPIRE_HEADSET_MIC, @@ -5405,6 +5406,16 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC }, + [ALC269_FIXUP_DELL4_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */ + { 0x1b, 0x01a1913d }, /* use as headphone mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_HEADSET_MODE + }, [ALC269_FIXUP_HEADSET_MODE] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_headset_mode, @@ -6535,6 +6546,11 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x17, 0x90170110}, {0x1a, 0x03011020}, {0x21, 0x03211030}), + SND_HDA_PIN_QUIRK(0x10ec0299, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, + ALC225_STANDARD_PINS, + {0x12, 0xb7a60130}, + {0x13, 0xb8a60140}, + {0x17, 0x90170110}), {} }; From 343fe850668cc38ba0524aa5880b041b2567ae5c Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 29 Jun 2017 16:02:56 +0530 Subject: [PATCH 389/418] ALSA: pcm: constify attribute_group structures. attribute_groups are not supposed to change at runtime. All functions working with attribute_groups provided by work with const attribute_group. So mark the non-const structs as const. File size before: text data bss dec hex filename 9781 240 8 10029 272d sound/core/pcm.o File size After adding 'const': text data bss dec hex filename 9813 176 8 9997 270d sound/core/pcm.o Signed-off-by: Arvind Yadav Signed-off-by: Takashi Iwai --- sound/core/pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 4b3290447398..89c7485519cb 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -1067,7 +1067,7 @@ static struct attribute *pcm_dev_attrs[] = { NULL }; -static struct attribute_group pcm_dev_attr_group = { +static const struct attribute_group pcm_dev_attr_group = { .attrs = pcm_dev_attrs, }; From a5a041b6b50bcaf96f96e5db4850d11006d61d26 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 29 Jun 2017 16:07:01 +0530 Subject: [PATCH 390/418] ALSA: hda: constify attribute_group structures. attribute_groups are not supposed to change at runtime. All functions working with attribute_groups provided by work with const attribute_group. So mark the non-const structs as const. File size before: text data bss dec hex filename 995 608 0 1603 643 sound/pci/hda/hda_sysfs.o File size After adding 'const': text data bss dec hex filename 1035 544 0 1579 62b sound/pci/hda/hda_sysfs.o Signed-off-by: Arvind Yadav Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c index 9739fce9e032..9b7efece4484 100644 --- a/sound/pci/hda/hda_sysfs.c +++ b/sound/pci/hda/hda_sysfs.c @@ -761,7 +761,7 @@ static struct attribute *hda_dev_attrs[] = { NULL }; -static struct attribute_group hda_dev_attr_group = { +static const struct attribute_group hda_dev_attr_group = { .attrs = hda_dev_attrs, }; From dba9b7b6ca1af60fd21137c18795a81a5652c5ae Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 29 Jun 2017 16:18:12 +0200 Subject: [PATCH 391/418] ALSA: hda - Fix doubly initialization of i915 component In the commit fcc88d91cd36 ("ALSA: hda - Bind with i915 component before codec binding"), the binding with i915 audio component is moved to be performed always at probing the controller. This fixed the potential problems on IVB, but now it brought another issue on HSW and BDW. These two platforms give two individual HD-audio controllers, one for the analog codec on PCH and another for HDMI over gfx. Since I decided to take a lazy path to check only AZX_DRIVER_PCH type in the commit above, now both controllers try to bind with i915, and you see a kernel WARNING. This patch tries to address it again properly. Now a new DCAPS bit, AZX_DCAPS_I915_COMPONENT, is introduced for indicating the binding with i915 component in addition to the existing I915_POWERWELL bit flag. Each PCI entry has to give this new flag if it requires the binding with i915 component. For HSW/BDW PCH (i.e. the ones defined by AZX_DCAPS_INTEL_PCH) doesn't contain AZX_DCAPS_I915_COMPONENT bit while others have it. While we're at it, add parentheses around the bit flag check for avoiding possible compiler warnings, too. The bug was spotted by Intel CI tests. Fixes: fcc88d91cd36 ("ALSA: hda - Bind with i915 component before codec binding") Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=196219 Reported-by: Martin Peres Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.h | 6 ++++- sound/pci/hda/hda_intel.c | 40 +++++++++++++++++++--------------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 35a9ab2cac46..a68e75b00ea3 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -32,7 +32,11 @@ #define AZX_DCAPS_NO_MSI (1 << 9) /* No MSI support */ #define AZX_DCAPS_SNOOP_MASK (3 << 10) /* snoop type mask */ #define AZX_DCAPS_SNOOP_OFF (1 << 12) /* snoop default off */ -/* 13 unused */ +#ifdef CONFIG_SND_HDA_I915 +#define AZX_DCAPS_I915_COMPONENT (1 << 13) /* bind with i915 gfx */ +#else +#define AZX_DCAPS_I915_COMPONENT 0 /* NOP */ +#endif /* 14 unused */ #define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */ #define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index a157582b8f2c..03e34edc8f24 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -293,38 +293,43 @@ enum { (AZX_DCAPS_NO_ALIGN_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY |\ AZX_DCAPS_SNOOP_TYPE(SCH)) -/* PCH up to IVB; no runtime PM */ +/* PCH up to IVB; no runtime PM; bind with i915 gfx */ #define AZX_DCAPS_INTEL_PCH_NOPM \ - (AZX_DCAPS_INTEL_PCH_BASE) + (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT) /* PCH for HSW/BDW; with runtime PM */ +/* no i915 binding for this as HSW/BDW has another controller for HDMI */ #define AZX_DCAPS_INTEL_PCH \ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME) /* HSW HDMI */ #define AZX_DCAPS_INTEL_HASWELL \ (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\ - AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_POWERWELL |\ - AZX_DCAPS_SNOOP_TYPE(SCH)) + AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\ + AZX_DCAPS_I915_POWERWELL | AZX_DCAPS_SNOOP_TYPE(SCH)) /* Broadwell HDMI can't use position buffer reliably, force to use LPIB */ #define AZX_DCAPS_INTEL_BROADWELL \ (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_POSFIX_LPIB |\ - AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_POWERWELL |\ - AZX_DCAPS_SNOOP_TYPE(SCH)) + AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\ + AZX_DCAPS_I915_POWERWELL | AZX_DCAPS_SNOOP_TYPE(SCH)) #define AZX_DCAPS_INTEL_BAYTRAIL \ - (AZX_DCAPS_INTEL_PCH_NOPM | AZX_DCAPS_I915_POWERWELL) + (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT |\ + AZX_DCAPS_I915_POWERWELL) #define AZX_DCAPS_INTEL_BRASWELL \ - (AZX_DCAPS_INTEL_PCH | AZX_DCAPS_I915_POWERWELL) + (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\ + AZX_DCAPS_I915_COMPONENT | AZX_DCAPS_I915_POWERWELL) #define AZX_DCAPS_INTEL_SKYLAKE \ - (AZX_DCAPS_INTEL_PCH | AZX_DCAPS_SEPARATE_STREAM_TAG |\ + (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\ + AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT |\ AZX_DCAPS_I915_POWERWELL) #define AZX_DCAPS_INTEL_BROXTON \ - (AZX_DCAPS_INTEL_PCH | AZX_DCAPS_SEPARATE_STREAM_TAG |\ + (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\ + AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT |\ AZX_DCAPS_I915_POWERWELL) /* quirks for ATI SB / AMD Hudson */ @@ -1008,7 +1013,7 @@ static int azx_suspend(struct device *dev) if (chip->msi) pci_disable_msi(chip->pci); - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL + if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && hda->need_i915_power) snd_hdac_display_power(bus, false); @@ -1114,7 +1119,7 @@ static int azx_runtime_suspend(struct device *dev) azx_stop_chip(chip); azx_enter_link_reset(chip); azx_clear_irq_pending(chip); - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL + if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && hda->need_i915_power) snd_hdac_display_power(azx_bus(chip), false); @@ -1380,8 +1385,7 @@ static int azx_free(struct azx *chip) if (hda->need_i915_power) snd_hdac_display_power(bus, false); } - if (chip->driver_type == AZX_DRIVER_PCH || - (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)) + if (chip->driver_type & AZX_DCAPS_I915_COMPONENT) snd_hdac_i915_exit(bus); kfree(hda); @@ -2199,8 +2203,7 @@ static int azx_probe_continue(struct azx *chip) hda->probe_continued = 1; /* bind with i915 if needed */ - if (chip->driver_type == AZX_DRIVER_PCH || - (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)) { + if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT) { err = snd_hdac_i915_init(bus); if (err < 0) { /* if the controller is bound only with HDMI/DP @@ -2214,7 +2217,8 @@ static int azx_probe_continue(struct azx *chip) goto out_free; } else { /* don't bother any longer */ - chip->driver_caps &= ~AZX_DCAPS_I915_POWERWELL; + chip->driver_caps &= + ~(AZX_DCAPS_I915_COMPONENT | AZX_DCAPS_I915_POWERWELL); } } } @@ -2279,7 +2283,7 @@ static int azx_probe_continue(struct azx *chip) pm_runtime_put_autosuspend(&pci->dev); out_free: - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL + if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && !hda->need_i915_power) snd_hdac_display_power(bus, false); From 4731d5de4b1ca8d2565782cc3aeac392db07c075 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Fri, 30 Jun 2017 15:22:57 +0800 Subject: [PATCH 392/418] ALSA: hda/realtek - Remove ALC285 device ID 0x0285 Device ID was not used. It just assigned for alias of ALC293 as backup. So, remove it first. Because our new codec will use this device ID. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c79491a1cd47..80c7c832d442 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -340,7 +340,6 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) case 0x10ec0299: alc_update_coef_idx(codec, 0x10, 1<<9, 0); break; - case 0x10ec0285: case 0x10ec0293: alc_update_coef_idx(codec, 0xa, 1<<13, 0); break; @@ -2738,7 +2737,7 @@ enum { ALC269_TYPE_ALC282, ALC269_TYPE_ALC283, ALC269_TYPE_ALC284, - ALC269_TYPE_ALC285, + ALC269_TYPE_ALC293, ALC269_TYPE_ALC286, ALC269_TYPE_ALC298, ALC269_TYPE_ALC255, @@ -2764,7 +2763,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) case ALC269_TYPE_ALC269VC: case ALC269_TYPE_ALC280: case ALC269_TYPE_ALC284: - case ALC269_TYPE_ALC285: + case ALC269_TYPE_ALC293: ssids = alc269va_ssids; break; case ALC269_TYPE_ALC269VB: @@ -6678,9 +6677,8 @@ static int patch_alc269(struct hda_codec *codec) case 0x10ec0292: spec->codec_variant = ALC269_TYPE_ALC284; break; - case 0x10ec0285: case 0x10ec0293: - spec->codec_variant = ALC269_TYPE_ALC285; + spec->codec_variant = ALC269_TYPE_ALC293; break; case 0x10ec0286: case 0x10ec0288: @@ -7752,7 +7750,6 @@ static const struct hda_device_id snd_hda_id_realtek[] = { HDA_CODEC_ENTRY(0x10ec0282, "ALC282", patch_alc269), HDA_CODEC_ENTRY(0x10ec0283, "ALC283", patch_alc269), HDA_CODEC_ENTRY(0x10ec0284, "ALC284", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0285, "ALC285", patch_alc269), HDA_CODEC_ENTRY(0x10ec0286, "ALC286", patch_alc269), HDA_CODEC_ENTRY(0x10ec0288, "ALC288", patch_alc269), HDA_CODEC_ENTRY(0x10ec0290, "ALC290", patch_alc269), From 0a6f0600efc3df0179a33188c30b5026bd9d1c27 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Fri, 30 Jun 2017 16:00:48 +0800 Subject: [PATCH 393/418] ALSA: hda/realtek - New codecs support for ALC215/ALC285/ALC289 Add new codecs support for ALC215 ALC285 ALC289. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 80c7c832d442..c39bc497650c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -327,6 +327,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) case 0x10ec0292: alc_update_coef_idx(codec, 0x4, 1<<15, 0); break; + case 0x10ec0215: case 0x10ec0225: case 0x10ec0233: case 0x10ec0255: @@ -335,8 +336,10 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) case 0x10ec0283: case 0x10ec0286: case 0x10ec0288: + case 0x10ec0285: case 0x10ec0295: case 0x10ec0298: + case 0x10ec0289: case 0x10ec0299: alc_update_coef_idx(codec, 0x10, 1<<9, 0); break; @@ -2742,6 +2745,7 @@ enum { ALC269_TYPE_ALC298, ALC269_TYPE_ALC255, ALC269_TYPE_ALC256, + ALC269_TYPE_ALC215, ALC269_TYPE_ALC225, ALC269_TYPE_ALC294, ALC269_TYPE_ALC700, @@ -2774,6 +2778,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) case ALC269_TYPE_ALC298: case ALC269_TYPE_ALC255: case ALC269_TYPE_ALC256: + case ALC269_TYPE_ALC215: case ALC269_TYPE_ALC225: case ALC269_TYPE_ALC294: case ALC269_TYPE_ALC700: @@ -6698,6 +6703,12 @@ static int patch_alc269(struct hda_codec *codec) spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */ alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/ break; + case 0x10ec0215: + case 0x10ec0285: + case 0x10ec0289: + spec->codec_variant = ALC269_TYPE_ALC215; + spec->gen.mixer_nid = 0; + break; case 0x10ec0225: case 0x10ec0295: spec->codec_variant = ALC269_TYPE_ALC225; @@ -7728,6 +7739,7 @@ static int patch_alc680(struct hda_codec *codec) * patch entries */ static const struct hda_device_id snd_hda_id_realtek[] = { + HDA_CODEC_ENTRY(0x10ec0215, "ALC215", patch_alc269), HDA_CODEC_ENTRY(0x10ec0221, "ALC221", patch_alc269), HDA_CODEC_ENTRY(0x10ec0225, "ALC225", patch_alc269), HDA_CODEC_ENTRY(0x10ec0231, "ALC231", patch_alc269), @@ -7750,8 +7762,10 @@ static const struct hda_device_id snd_hda_id_realtek[] = { HDA_CODEC_ENTRY(0x10ec0282, "ALC282", patch_alc269), HDA_CODEC_ENTRY(0x10ec0283, "ALC283", patch_alc269), HDA_CODEC_ENTRY(0x10ec0284, "ALC284", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0285, "ALC285", patch_alc269), HDA_CODEC_ENTRY(0x10ec0286, "ALC286", patch_alc269), HDA_CODEC_ENTRY(0x10ec0288, "ALC288", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0289, "ALC289", patch_alc269), HDA_CODEC_ENTRY(0x10ec0290, "ALC290", patch_alc269), HDA_CODEC_ENTRY(0x10ec0292, "ALC292", patch_alc269), HDA_CODEC_ENTRY(0x10ec0293, "ALC293", patch_alc269), From 836e4fedee8df123a203a0ded090251de66b9bd1 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 30 Jun 2017 10:16:36 +0100 Subject: [PATCH 394/418] ASoC: ak4642: make arrays fs_list and ps_list static const Don't populate the arrays fs_list and ps_list on the stack but make them static const. Makes the object code smaller: Before: text data bss dec hex filename 12084 4888 64 17036 428c sound/soc/codecs/ak4642.o After: text data bss dec hex filename 11883 5032 64 16979 4253 sound/soc/codecs/ak4642.o Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/codecs/ak4642.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 23ab9646c351..66de8a2013a6 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -433,7 +433,7 @@ static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) static int ak4642_set_mcko(struct snd_soc_codec *codec, u32 frequency) { - u32 fs_list[] = { + static const u32 fs_list[] = { [0] = 8000, [1] = 12000, [2] = 16000, @@ -447,7 +447,7 @@ static int ak4642_set_mcko(struct snd_soc_codec *codec, [14] = 29400, [15] = 44100, }; - u32 ps_list[] = { + static const u32 ps_list[] = { [0] = 256, [1] = 128, [2] = 64, From bb97142bcf8c042103e87d035a120f522d12e788 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 29 Jun 2017 14:22:25 +0100 Subject: [PATCH 395/418] ASoC: topology: Fix usage of SND_SOC_TPLG_INDEX_ALL during load SND_SOC_TPLG_INDEX_ALL is used by drivers to tell the core to load all topology component indexes, not just the index in the header. Fix this so that SND_SOC_TPLG_INDEX_ALL will load all components no matter their index. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 12e189701924..6070e35455aa 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -2381,7 +2381,7 @@ static int soc_tplg_load_header(struct soc_tplg *tplg, /* check for matching ID */ if (hdr->index != tplg->req_index && - hdr->index != SND_SOC_TPLG_INDEX_ALL) + tplg->req_index != SND_SOC_TPLG_INDEX_ALL) return 0; tplg->index = hdr->index; From b75a65118d287aadeade8b106ed0da7b5e42c167 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 29 Jun 2017 14:22:26 +0100 Subject: [PATCH 396/418] ASoC: topology: show index in debug when adding DAPM routes Makes the debug output much more useful. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 6070e35455aa..73308e6d3729 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1163,7 +1163,8 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, return -EINVAL; } - dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes\n", count); + dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes for index %d\n", count, + hdr->index); for (i = 0; i < count; i++) { elem = (struct snd_soc_tplg_dapm_graph_elem *)tplg->pos; From 8a70b4544ef4f094cc2c52734e097cc358f56603 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 29 Jun 2017 14:22:24 +0100 Subject: [PATCH 397/418] ASoC: dapm: Add new widget type for constructing DAPM graphs on DSPs. Add some DAPM widget types to better support the construction of DAPM graphs within DSPs. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown --- Documentation/sound/soc/dapm.rst | 18 ++++++++++++++++++ include/sound/soc-dapm.h | 7 +++++++ include/uapi/sound/asoc.h | 10 +++++++++- sound/soc/soc-topology.c | 8 ++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst index a27f42befa4d..8e44107933ab 100644 --- a/Documentation/sound/soc/dapm.rst +++ b/Documentation/sound/soc/dapm.rst @@ -105,6 +105,24 @@ Pre Special PRE widget (exec before all others) Post Special POST widget (exec after all others) +Buffer + Inter widget audio data buffer within a DSP. +Scheduler + DSP internal scheduler that schedules component/pipeline processing + work. +Effect + Widget that performs an audio processing effect. +SRC + Sample Rate Converter within DSP or CODEC +ASRC + Asynchronous Sample Rate Converter within DSP or CODEC +Encoder + Widget that encodes audio data from one format (usually PCM) to another + usually more compressed format. +Decoder + Widget that decodes audio data from a compressed format to an + uncompressed format like PCM. + (Widgets are defined in include/sound/soc-dapm.h) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index a466f4bdc835..344b96c206a3 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -510,6 +510,13 @@ enum snd_soc_dapm_type { snd_soc_dapm_dai_out, snd_soc_dapm_dai_link, /* link between two DAI structures */ snd_soc_dapm_kcontrol, /* Auto-disabled kcontrol */ + snd_soc_dapm_buffer, /* DSP/CODEC internal buffer */ + snd_soc_dapm_scheduler, /* DSP/CODEC internal scheduler */ + snd_soc_dapm_effect, /* DSP/CODEC effect component */ + snd_soc_dapm_src, /* DSP/CODEC SRC component */ + snd_soc_dapm_asrc, /* DSP/CODEC ASRC component */ + snd_soc_dapm_encoder, /* FW/SW audio encoder component */ + snd_soc_dapm_decoder, /* FW/SW audio decoder component */ }; enum snd_soc_dapm_subclass { diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h index 6702533c8bd8..78014ec56357 100644 --- a/include/uapi/sound/asoc.h +++ b/include/uapi/sound/asoc.h @@ -73,7 +73,15 @@ #define SND_SOC_TPLG_DAPM_DAI_IN 13 #define SND_SOC_TPLG_DAPM_DAI_OUT 14 #define SND_SOC_TPLG_DAPM_DAI_LINK 15 -#define SND_SOC_TPLG_DAPM_LAST SND_SOC_TPLG_DAPM_DAI_LINK +#define SND_SOC_TPLG_DAPM_BUFFER 16 +#define SND_SOC_TPLG_DAPM_SCHEDULER 17 +#define SND_SOC_TPLG_DAPM_EFFECT 18 +#define SND_SOC_TPLG_DAPM_SIGGEN 19 +#define SND_SOC_TPLG_DAPM_SRC 20 +#define SND_SOC_TPLG_DAPM_ASRC 21 +#define SND_SOC_TPLG_DAPM_ENCODER 22 +#define SND_SOC_TPLG_DAPM_DECODER 23 +#define SND_SOC_TPLG_DAPM_LAST SND_SOC_TPLG_DAPM_DECODER /* Header magic number and string sizes */ #define SND_SOC_TPLG_MAGIC 0x41536F43 /* ASoC */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 002772e3ba2c..dd3a391476ae 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -242,6 +242,14 @@ static const struct soc_tplg_map dapm_map[] = { {SND_SOC_TPLG_DAPM_DAI_IN, snd_soc_dapm_dai_in}, {SND_SOC_TPLG_DAPM_DAI_OUT, snd_soc_dapm_dai_out}, {SND_SOC_TPLG_DAPM_DAI_LINK, snd_soc_dapm_dai_link}, + {SND_SOC_TPLG_DAPM_BUFFER, snd_soc_dapm_buffer}, + {SND_SOC_TPLG_DAPM_SCHEDULER, snd_soc_dapm_scheduler}, + {SND_SOC_TPLG_DAPM_EFFECT, snd_soc_dapm_effect}, + {SND_SOC_TPLG_DAPM_SIGGEN, snd_soc_dapm_siggen}, + {SND_SOC_TPLG_DAPM_SRC, snd_soc_dapm_src}, + {SND_SOC_TPLG_DAPM_ASRC, snd_soc_dapm_asrc}, + {SND_SOC_TPLG_DAPM_ENCODER, snd_soc_dapm_encoder}, + {SND_SOC_TPLG_DAPM_DECODER, snd_soc_dapm_decoder}, }; static int tplc_chan_get_reg(struct soc_tplg *tplg, From c243d96378bd0dc1249a335c282133f05e93c253 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 29 Jun 2017 09:47:55 +0800 Subject: [PATCH 398/418] ASoC: rt5670: fix incompatible pointer type of set_sysclk The first parameter is codec not dai. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 7fa63ad366dd..64756dc95261 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2442,7 +2442,7 @@ static int rt5670_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static int rt5670_set_codec_sysclk(struct snd_soc_dai *dai, int clk_id, +static int rt5670_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir) { struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); From fc3ba81a5adac413312019413c91b1e6a5d8d1fa Mon Sep 17 00:00:00 2001 From: John Hsu Date: Thu, 29 Jun 2017 11:41:30 +0800 Subject: [PATCH 399/418] ASoC: nau8825: change crosstalk-bypass property to bool type The property type of "nuvoton,crosstalk-bypass" changes to boolean. The document is updated as well. Signed-off-by: John Hsu Signed-off-by: John Hsu Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/nau8825.txt | 3 +++ sound/soc/codecs/nau8825.c | 6 ++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/nau8825.txt b/Documentation/devicetree/bindings/sound/nau8825.txt index d3374231c871..2f5e973285a6 100644 --- a/Documentation/devicetree/bindings/sound/nau8825.txt +++ b/Documentation/devicetree/bindings/sound/nau8825.txt @@ -69,6 +69,8 @@ Optional properties: - nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms - nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms + - nuvoton,crosstalk-bypass: make crosstalk function bypass if set. + - clocks: list of phandle and clock specifier pairs according to common clock bindings for the clocks described in clock-names - clock-names: should include "mclk" for the MCLK master clock @@ -96,6 +98,7 @@ Example: nuvoton,short-key-debounce = <2>; nuvoton,jack-insert-debounce = <7>; nuvoton,jack-eject-debounce = <7>; + nuvoton,crosstalk-bypass; clock-names = "mclk"; clocks = <&tegra_car TEGRA210_CLK_CLK_OUT_2>; diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 80bae481e75d..46a30eaa7ace 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -2506,10 +2506,8 @@ static int nau8825_read_device_properties(struct device *dev, &nau8825->jack_eject_debounce); if (ret) nau8825->jack_eject_debounce = 0; - ret = device_property_read_u32(dev, "nuvoton,crosstalk-bypass", - &nau8825->xtalk_bypass); - if (ret) - nau8825->xtalk_bypass = 1; + nau8825->xtalk_bypass = device_property_read_bool(dev, + "nuvoton,crosstalk-bypass"); nau8825->mclk = devm_clk_get(dev, "mclk"); if (PTR_ERR(nau8825->mclk) == -EPROBE_DEFER) { From 49ebf13b0453d8535cd53abb514e1683a1875208 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 29 Jun 2017 10:40:50 +0530 Subject: [PATCH 400/418] ASoC: rsnd: constify dev_pm_ops structures. dev_pm_ops are not supposed to change at runtime. All functions working with dev_pm_ops provided by work with const dev_pm_ops. So mark the non-const structs as const. File size before: text data bss dec hex filename 8172 920 0 9092 2384 sound/soc/sh/rcar/core.o File size After adding 'const': text data bss dec hex filename 8364 728 0 9092 2384 sound/soc/sh/rcar/core.o Signed-off-by: Arvind Yadav 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 409bac331d27..3f2ced26ed37 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1534,7 +1534,7 @@ static int rsnd_resume(struct device *dev) return 0; } -static struct dev_pm_ops rsnd_pm_ops = { +static const struct dev_pm_ops rsnd_pm_ops = { .suspend = rsnd_suspend, .resume = rsnd_resume, }; From b059ca720e2ac04380240500eb8d8ba931898570 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 29 Jun 2017 20:07:50 +0800 Subject: [PATCH 401/418] ASoC: rt5665: calibration should be done before jack detection We will set some volatile registers in jack detection function. But those volatile registers will be clear in rt5665_calibrate function because we set cache bypass and reset codec in rt5665_calibrate function. This patch add a flag to make sure that rt5665_calibrate is done before starting jack detection. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 7420010fd8e9..370ed54d1e15 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -70,6 +70,7 @@ struct rt5665_priv { int jack_type; int irq_work_delay_time; unsigned int sar_adc_value; + bool calibration_done; }; static const struct reg_default rt5665_reg[] = { @@ -1305,6 +1306,11 @@ static void rt5665_jack_detect_handler(struct work_struct *work) usleep_range(10000, 15000); } + while (!rt5665->calibration_done) { + pr_debug("%s calibration not ready\n", __func__); + usleep_range(10000, 15000); + } + mutex_lock(&rt5665->calibrate_mutex); val = snd_soc_read(rt5665->codec, RT5665_AJD1_CTRL) & 0x0010; @@ -4695,6 +4701,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) regmap_write(rt5665->regmap, RT5665_ASRC_8, 0x0120); out_unlock: + rt5665->calibration_done = true; mutex_unlock(&rt5665->calibrate_mutex); } From a0c683d734e0b3589892c17d0e1187f20d2c3a54 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Thu, 29 Jun 2017 21:26:37 +0800 Subject: [PATCH 402/418] ASoC: audio-graph-card: update bindings for amplifier support The audio-graph-card should be able to support widgets and routing in the same way as what simple-audio-card does. The patch adds the properties into audio-graph-card bindings. Then an optional property 'pa-gpios' for controlling external amplifier, which depends on DAPM widgets and routing, is added. Signed-off-by: Shawn Guo Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/audio-graph-card.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/audio-graph-card.txt b/Documentation/devicetree/bindings/sound/audio-graph-card.txt index bac4b1b1060f..6e6720aa33f1 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph-card.txt +++ b/Documentation/devicetree/bindings/sound/audio-graph-card.txt @@ -10,6 +10,8 @@ see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt Below are same as Simple-Card. - label +- widgets +- routing - dai-format - frame-master - bitclock-master @@ -24,6 +26,9 @@ Required properties: - compatible : "audio-graph-card"; - dais : list of CPU DAI port{s} +Optional properties: +- pa-gpios: GPIO used to control external amplifier. + Example: Single DAI case sound_card { From f986907c9225cf48e9a55233b086039152bb5b99 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Thu, 29 Jun 2017 21:26:38 +0800 Subject: [PATCH 403/418] ASoC: audio-graph-card: add widgets and routing for external amplifier support It's very common that audio card has a machine level amplifier which is controlled by GPIO. The patch adds DAPM widgets and routing support into audio-graph-card driver, and creates an output driver widget with event to control the amplifier via GPIO. Signed-off-by: Shawn Guo Acked-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 48 +++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index ee752f62d89d..105ec3a6e30d 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,34 @@ struct graph_card_data { struct asoc_simple_dai codec_dai; } *dai_props; struct snd_soc_dai_link *dai_link; + struct gpio_desc *pa_gpio; +}; + +static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct graph_card_data *priv = snd_soc_card_get_drvdata(dapm->card); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + gpiod_set_value_cansleep(priv->pa_gpio, 1); + break; + case SND_SOC_DAPM_PRE_PMD: + gpiod_set_value_cansleep(priv->pa_gpio, 0); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_dapm_widget asoc_graph_card_dapm_widgets[] = { + SND_SOC_DAPM_OUT_DRV_E("Amplifier", SND_SOC_NOPM, + 0, 0, NULL, 0, asoc_graph_card_outdrv_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), }; #define graph_priv_to_card(priv) (&(priv)->snd_card) @@ -180,8 +209,16 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) int rc, idx = 0; int ret; + ret = asoc_simple_card_of_parse_widgets(card, NULL); + if (ret < 0) + return ret; + + ret = asoc_simple_card_of_parse_routing(card, NULL, 1); + if (ret < 0) + return ret; + /* - * we need to consider "widgets", "routing", "mclk-fs" around here + * we need to consider "mclk-fs" around here * see simple-card */ @@ -233,6 +270,13 @@ static int asoc_graph_card_probe(struct platform_device *pdev) if (!dai_props || !dai_link) return -ENOMEM; + priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); + if (IS_ERR(priv->pa_gpio)) { + ret = PTR_ERR(priv->pa_gpio); + dev_err(dev, "failed to get amplifier gpio: %d\n", ret); + return ret; + } + priv->dai_props = dai_props; priv->dai_link = dai_link; @@ -242,6 +286,8 @@ static int asoc_graph_card_probe(struct platform_device *pdev) card->dev = dev; card->dai_link = dai_link; card->num_links = num; + card->dapm_widgets = asoc_graph_card_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets); ret = asoc_graph_card_parse_of(priv); if (ret < 0) { From 8288591368fcb470024348a9b846f7b3f791be44 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 30 Jun 2017 10:50:59 +0100 Subject: [PATCH 404/418] ASoC: rsnd: make arrays path and cmd_case static const Don't populate the arrays path and cmd_case on the stack but make them static const. Makes the object code smaller: Before: text data bss dec hex filename 2673 624 0 3297 ce1 sound/soc/sh/rcar/cmd.o After: text data bss dec hex filename 2398 768 0 3166 c5e sound/soc/sh/rcar/cmd.o Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/sh/rcar/cmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c index 9a136d86e2a9..f1d4fb566892 100644 --- a/sound/soc/sh/rcar/cmd.c +++ b/sound/soc/sh/rcar/cmd.c @@ -31,7 +31,7 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); struct device *dev = rsnd_priv_to_dev(priv); u32 data; - u32 path[] = { + static const u32 path[] = { [1] = 1 << 0, [5] = 1 << 8, [6] = 1 << 12, @@ -71,7 +71,7 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, } else { struct rsnd_mod *src = rsnd_io_to_mod_src(io); - u8 cmd_case[] = { + static const u8 cmd_case[] = { [0] = 0x3, [1] = 0x3, [2] = 0x4, From 4999b0214b05a08b42bbafcb29a0b9c413002d3f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 29 Jun 2017 18:08:33 +0200 Subject: [PATCH 405/418] ASoC: rt5645: Add quirk override by module option For making the development easier, add quirk module option to override the platform data setup. For example, a platform with inverted jack detection with jd_mode=2, pass the value 0x21 (0x1 = inv_jd1_1, 0x20 = jd_mode=2). It overrides the whole pdata fields, so pass it carefully. Signed-off-by: Takashi Iwai Tested-by: James Cameron Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 630374ee692a..909f4a6aaef1 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -34,6 +34,17 @@ #include "rl6231.h" #include "rt5645.h" +#define QUIRK_INV_JD1_1(q) ((q) & 1) +#define QUIRK_LEVEL_IRQ(q) (((q) >> 1) & 1) +#define QUIRK_IN2_DIFF(q) (((q) >> 2) & 1) +#define QUIRK_JD_MODE(q) (((q) >> 4) & 7) +#define QUIRK_DMIC1_DATA_PIN(q) (((q) >> 8) & 3) +#define QUIRK_DMIC2_DATA_PIN(q) (((q) >> 12) & 3) + +static unsigned int quirk = -1; +module_param(quirk, uint, 0444); +MODULE_PARM_DESC(quirk, "RT5645 pdata quirk override"); + #define RT5645_DEVICE_ID 0x6308 #define RT5650_DEVICE_ID 0x6419 @@ -3679,6 +3690,15 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, else if (dmi_check_system(dmi_platform_gpd_win)) rt5645->pdata = gpd_win_platform_data; + if (quirk != -1) { + rt5645->pdata.in2_diff = QUIRK_IN2_DIFF(quirk); + rt5645->pdata.level_trigger_irq = QUIRK_LEVEL_IRQ(quirk); + rt5645->pdata.inv_jd1_1 = QUIRK_INV_JD1_1(quirk); + rt5645->pdata.jd_mode = QUIRK_JD_MODE(quirk); + rt5645->pdata.dmic1_data_pin = QUIRK_DMIC1_DATA_PIN(quirk); + rt5645->pdata.dmic2_data_pin = QUIRK_DMIC2_DATA_PIN(quirk); + } + rt5645->gpiod_hp_det = devm_gpiod_get_optional(&i2c->dev, "hp-detect", GPIOD_IN); From 46b5a4d249ac6798cee28de9f51ef80777d16a3e Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 30 Jun 2017 00:27:13 +0800 Subject: [PATCH 406/418] ASoC: fix semicolon.cocci warnings sound/soc/soc-core.c:1961:2-3: Unneeded semicolon Remove unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci Fixes: 98faf436ee05 ("ASoC: Drop invalid DMI fields when setting card long name from DMI info") CC: Mengdong Lin Signed-off-by: Fengguang Wu 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 e14e04cc0a93..6bd593dc9b54 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1958,7 +1958,7 @@ static int is_dmi_valid(const char *field) if (strstr(field, dmi_blacklist[i])) return 0; i++; - }; + } return 1; } From 5cdf6c09ca9de3f037ba2d770206f3374459602d Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 30 Jun 2017 09:06:05 +0530 Subject: [PATCH 407/418] ASoC: Intel: Skylake: Add debugfs support For debug, the kernel debugfs mechanism is available. We can add various debug options for driver like module configuration read, firmware register read etc. This patch adds debugfs as a child to asoc plaform component and caller is added for skylake driver to do init and cleanup of debugfs. Signed-off-by: Vinod Koul Signed-off-by: Vunny Sodhi Signed-off-by: Guneshwor Singh Signed-off-by: Mark Brown --- sound/soc/intel/skylake/Makefile | 4 +++ sound/soc/intel/skylake/skl-debug.c | 55 +++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-pcm.c | 6 +++- sound/soc/intel/skylake/skl.c | 2 ++ sound/soc/intel/skylake/skl.h | 16 +++++++++ 5 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/skylake/skl-debug.c diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index 60fbc9bbe473..e7d77722d560 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -1,6 +1,10 @@ snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o skl-messages.o \ skl-topology.o +ifdef CONFIG_DEBUG_FS + snd-soc-skl-objs += skl-debug.o +endif + obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o # Skylake IPC Support diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c new file mode 100644 index 000000000000..6bc4565773c5 --- /dev/null +++ b/sound/soc/intel/skylake/skl-debug.c @@ -0,0 +1,55 @@ +/* + * skl-debug.c - Debugfs for skl driver + * + * Copyright (C) 2016-17 Intel Corp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include "skl.h" + +struct skl_debug { + struct skl *skl; + struct device *dev; + + struct dentry *fs; +}; + +struct skl_debug *skl_debugfs_init(struct skl *skl) +{ + struct skl_debug *d; + + d = devm_kzalloc(&skl->pci->dev, sizeof(*d), GFP_KERNEL); + if (!d) + return NULL; + + /* create the debugfs dir with platform component's debugfs as parent */ + d->fs = debugfs_create_dir("dsp", + skl->platform->component.debugfs_root); + if (IS_ERR(d->fs) || !d->fs) { + dev_err(&skl->pci->dev, "debugfs root creation failed\n"); + return NULL; + } + + d->skl = skl; + d->dev = &skl->pci->dev; + + return d; +} + +void skl_debugfs_exit(struct skl_debug *d) +{ + debugfs_remove_recursive(d->fs); + + kfree(d); + +} diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index e91bbcffc856..0ebea34a4988 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1249,12 +1249,16 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform) pm_runtime_get_sync(platform->dev); if ((ebus_to_hbus(ebus))->ppcap) { + skl->platform = platform; + + /* init debugfs */ + skl->debugfs = skl_debugfs_init(skl); + ret = skl_tplg_init(platform, ebus); if (ret < 0) { dev_err(platform->dev, "Failed to init topology!\n"); return ret; } - skl->platform = platform; /* load the firmwares, since all is set */ ops = skl_get_dsp_ops(skl->pci->device); diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index e761550c6dad..410ce83f4a49 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -866,6 +866,8 @@ static void skl_remove(struct pci_dev *pci) /* codec removal, invoke bus_device_remove */ snd_hdac_ext_bus_device_remove(ebus); + skl_debugfs_exit(skl->debugfs); + skl->debugfs = NULL; skl_platform_unregister(&pci->dev); skl_free_dsp(skl); skl_machine_device_unregister(skl); diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 2a630fcb7f08..a47779c819d5 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -42,6 +42,8 @@ struct skl_dsp_resource { u32 mem; }; +struct skl_debug; + struct skl { struct hdac_ext_bus ebus; struct pci_dev *pci; @@ -66,6 +68,8 @@ struct skl { int supend_active; struct work_struct probe_work; + + struct skl_debug *debugfs; }; #define skl_to_ebus(s) (&(s)->ebus) @@ -116,4 +120,16 @@ void skl_update_d0i3c(struct device *dev, bool enable); int skl_nhlt_create_sysfs(struct skl *skl); void skl_nhlt_remove_sysfs(struct skl *skl); +#ifdef CONFIG_DEBUG_FS +struct skl_debug *skl_debugfs_init(struct skl *skl); +void skl_debugfs_exit(struct skl_debug *d); +#else +static inline struct skl_debug *skl_debugfs_init(struct skl *skl) +{ + return NULL; +} +static inline void skl_debugfs_exit(struct skl_debug *d) +{} +#endif + #endif /* __SOUND_SOC_SKL_H */ From d14700a01f9101c2bc75c24fc859c8d85ba7e623 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 30 Jun 2017 09:06:06 +0530 Subject: [PATCH 408/418] ASoC: Intel: Skylake: Debugfs facility to dump module config Driver modules have lot of information represented in struct skl_module_cfg. Knowing this is useful for debug, so enable debugfs for this structure. Signed-off-by: Vinod Koul Signed-off-by: Vunny Sodhi Signed-off-by: Guneshwor Singh Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-debug.c | 156 +++++++++++++++++++++++++ sound/soc/intel/skylake/skl-topology.c | 3 + sound/soc/intel/skylake/skl.h | 10 ++ 3 files changed, 169 insertions(+) diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c index 6bc4565773c5..be3238c63200 100644 --- a/sound/soc/intel/skylake/skl-debug.c +++ b/sound/soc/intel/skylake/skl-debug.c @@ -16,14 +16,159 @@ #include #include #include "skl.h" +#include "skl-tplg-interface.h" +#include "skl-topology.h" + +#define MOD_BUF PAGE_SIZE struct skl_debug { struct skl *skl; struct device *dev; struct dentry *fs; + struct dentry *modules; }; +static ssize_t skl_print_pins(struct skl_module_pin *m_pin, char *buf, + int max_pin, ssize_t size, bool direction) +{ + int i; + ssize_t ret = 0; + + for (i = 0; i < max_pin; i++) + ret += snprintf(buf + size, MOD_BUF - size, + "%s %d\n\tModule %d\n\tInstance %d\n\t" + "In-used %s\n\tType %s\n" + "\tState %d\n\tIndex %d\n", + direction ? "Input Pin:" : "Output Pin:", + i, m_pin[i].id.module_id, + m_pin[i].id.instance_id, + m_pin[i].in_use ? "Used" : "Unused", + m_pin[i].is_dynamic ? "Dynamic" : "Static", + m_pin[i].pin_state, i); + return ret; +} + +static ssize_t skl_print_fmt(struct skl_module_fmt *fmt, char *buf, + ssize_t size, bool direction) +{ + return snprintf(buf + size, MOD_BUF - size, + "%s\n\tCh %d\n\tFreq %d\n\tBit depth %d\n\t" + "Valid bit depth %d\n\tCh config %#x\n\tInterleaving %d\n\t" + "Sample Type %d\n\tCh Map %#x\n", + direction ? "Input Format:" : "Output Format:", + fmt->channels, fmt->s_freq, fmt->bit_depth, + fmt->valid_bit_depth, fmt->ch_cfg, + fmt->interleaving_style, fmt->sample_type, + fmt->ch_map); +} + +static ssize_t module_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct skl_module_cfg *mconfig = file->private_data; + char *buf; + ssize_t ret; + + buf = kzalloc(MOD_BUF, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = snprintf(buf, MOD_BUF, "Module:\n\tUUID %pUL\n\tModule id %d\n" + "\tInstance id %d\n\tPvt_id %d\n", mconfig->guid, + mconfig->id.module_id, mconfig->id.instance_id, + mconfig->id.pvt_id); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "Resources:\n\tMCPS %#x\n\tIBS %#x\n\tOBS %#x\t\n", + mconfig->mcps, mconfig->ibs, mconfig->obs); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "Module data:\n\tCore %d\n\tIn queue %d\n\t" + "Out queue %d\n\tType %s\n", + mconfig->core_id, mconfig->max_in_queue, + mconfig->max_out_queue, + mconfig->is_loadable ? "loadable" : "inbuilt"); + + ret += skl_print_fmt(mconfig->in_fmt, buf, ret, true); + ret += skl_print_fmt(mconfig->out_fmt, buf, ret, false); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "Fixup:\n\tParams %#x\n\tConverter %#x\n", + mconfig->params_fixup, mconfig->converter); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "Module Gateway:\n\tType %#x\n\tVbus %#x\n\tHW conn %#x\n\tSlot %#x\n", + mconfig->dev_type, mconfig->vbus_id, + mconfig->hw_conn_type, mconfig->time_slot); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "Pipeline:\n\tID %d\n\tPriority %d\n\tConn Type %d\n\t" + "Pages %#x\n", mconfig->pipe->ppl_id, + mconfig->pipe->pipe_priority, mconfig->pipe->conn_type, + mconfig->pipe->memory_pages); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "\tParams:\n\t\tHost DMA %d\n\t\tLink DMA %d\n", + mconfig->pipe->p_params->host_dma_id, + mconfig->pipe->p_params->link_dma_id); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "\tPCM params:\n\t\tCh %d\n\t\tFreq %d\n\t\tFormat %d\n", + mconfig->pipe->p_params->ch, + mconfig->pipe->p_params->s_freq, + mconfig->pipe->p_params->s_fmt); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "\tLink %#x\n\tStream %#x\n", + mconfig->pipe->p_params->linktype, + mconfig->pipe->p_params->stream); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "\tState %d\n\tPassthru %s\n", + mconfig->pipe->state, + mconfig->pipe->passthru ? "true" : "false"); + + ret += skl_print_pins(mconfig->m_in_pin, buf, + mconfig->max_in_queue, ret, true); + ret += skl_print_pins(mconfig->m_out_pin, buf, + mconfig->max_out_queue, ret, false); + + ret += snprintf(buf + ret, MOD_BUF - ret, + "Other:\n\tDomain %d\n\tHomogenous Input %s\n\t" + "Homogenous Output %s\n\tIn Queue Mask %d\n\t" + "Out Queue Mask %d\n\tDMA ID %d\n\tMem Pages %d\n\t" + "Module Type %d\n\tModule State %d\n", + mconfig->domain, + mconfig->homogenous_inputs ? "true" : "false", + mconfig->homogenous_outputs ? "true" : "false", + mconfig->in_queue_mask, mconfig->out_queue_mask, + mconfig->dma_id, mconfig->mem_pages, mconfig->m_state, + mconfig->m_type); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); + + kfree(buf); + return ret; +} + +static const struct file_operations mcfg_fops = { + .open = simple_open, + .read = module_read, + .llseek = default_llseek, +}; + + +void skl_debug_init_module(struct skl_debug *d, + struct snd_soc_dapm_widget *w, + struct skl_module_cfg *mconfig) +{ + if (!debugfs_create_file(w->name, 0444, + d->modules, mconfig, + &mcfg_fops)) + dev_err(d->dev, "%s: module debugfs init failed\n", w->name); +} + struct skl_debug *skl_debugfs_init(struct skl *skl) { struct skl_debug *d; @@ -43,7 +188,18 @@ struct skl_debug *skl_debugfs_init(struct skl *skl) d->skl = skl; d->dev = &skl->pci->dev; + /* now create the module dir */ + d->modules = debugfs_create_dir("modules", d->fs); + if (IS_ERR(d->modules) || !d->modules) { + dev_err(&skl->pci->dev, "modules debugfs create failed\n"); + goto err; + } + return d; + +err: + debugfs_remove_recursive(d->fs); + return NULL; } void skl_debugfs_exit(struct skl_debug *d) diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 9569f118e97e..c02da16fdfd6 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -2472,6 +2472,9 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig); if (ret < 0) return ret; + + skl_debug_init_module(skl->debugfs, w, mconfig); + bind_event: if (tplg_w->event_type == 0) { dev_dbg(bus->dev, "ASoC: No event handler required\n"); diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index a47779c819d5..14e7778d7f80 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -23,6 +23,7 @@ #include #include +#include #include "skl-nhlt.h" #define SKL_SUSPEND_DELAY 2000 @@ -120,9 +121,14 @@ void skl_update_d0i3c(struct device *dev, bool enable); int skl_nhlt_create_sysfs(struct skl *skl); void skl_nhlt_remove_sysfs(struct skl *skl); +struct skl_module_cfg; + #ifdef CONFIG_DEBUG_FS struct skl_debug *skl_debugfs_init(struct skl *skl); void skl_debugfs_exit(struct skl_debug *d); +void skl_debug_init_module(struct skl_debug *d, + struct snd_soc_dapm_widget *w, + struct skl_module_cfg *mconfig); #else static inline struct skl_debug *skl_debugfs_init(struct skl *skl) { @@ -130,6 +136,10 @@ static inline struct skl_debug *skl_debugfs_init(struct skl *skl) } static inline void skl_debugfs_exit(struct skl_debug *d) {} +static inline void skl_debug_init_module(struct skl_debug *d, + struct snd_soc_dapm_widget *w, + struct skl_module_cfg *mconfig) +{} #endif #endif /* __SOUND_SOC_SKL_H */ From 09e914d6b647cf23d81a226e1f1c4464bafdeb2d Mon Sep 17 00:00:00 2001 From: Guneshwor Singh Date: Fri, 30 Jun 2017 09:06:07 +0530 Subject: [PATCH 409/418] ASoC: Intel: Skylake: Add sram address to sst_addr structure SRAM address and memory window size differ for different platforms. So add members to sst_addr structure and initialize them in the respective dsp_init(). Signed-off-by: Guneshwor Singh Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-dsp-priv.h | 4 ++++ sound/soc/intel/skylake/bxt-sst.c | 4 ++++ sound/soc/intel/skylake/skl-sst.c | 5 +++++ 3 files changed, 13 insertions(+) diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index d13c84364c3c..8734040d64d3 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -77,6 +77,10 @@ struct sst_addr { u32 dram_offset; u32 dsp_iram_offset; u32 dsp_dram_offset; + u32 sram0_base; + u32 sram1_base; + u32 w0_stat_sz; + u32 w0_up_sz; void __iomem *lpe; void __iomem *shim; void __iomem *pci_cfg; diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index f5e7dbb1ba39..cf11b84888b9 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -573,6 +573,10 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, sst->fw_ops = bxt_fw_ops; sst->addr.lpe = mmio_base; sst->addr.shim = mmio_base; + sst->addr.sram0_base = BXT_ADSP_SRAM0_BASE; + sst->addr.sram1_base = BXT_ADSP_SRAM1_BASE; + sst->addr.w0_stat_sz = SKL_ADSP_W0_STAT_SZ; + sst->addr.w0_up_sz = SKL_ADSP_W0_UP_SZ; sst_dsp_mailbox_init(sst, (BXT_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), SKL_ADSP_W0_UP_SZ, BXT_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 155e456b7a3a..aba9ea11ac74 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -553,6 +553,11 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, sst = skl->dsp; sst->addr.lpe = mmio_base; sst->addr.shim = mmio_base; + sst->addr.sram0_base = SKL_ADSP_SRAM0_BASE; + sst->addr.sram1_base = SKL_ADSP_SRAM1_BASE; + sst->addr.w0_stat_sz = SKL_ADSP_W0_STAT_SZ; + sst->addr.w0_up_sz = SKL_ADSP_W0_UP_SZ; + sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); From bdd0384a5ada8bb5745e5f29c10a5ba88827efad Mon Sep 17 00:00:00 2001 From: Vunny Sodhi Date: Fri, 30 Jun 2017 09:06:08 +0530 Subject: [PATCH 410/418] ASoC: Intel: Skylake: Add support to read firmware registers This patch adds debugfs support to read fw registers, mailbox offsets and sram address. Signed-off-by: Mousumi Jana Signed-off-by: Ramesh Babu Signed-off-by: Jayachandran B Signed-off-by: Pardha Saradhi K Signed-off-by: Vunny Sodhi Signed-off-by: Guneshwor Singh Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-debug.c | 57 +++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c index be3238c63200..75497b1fda45 100644 --- a/sound/soc/intel/skylake/skl-debug.c +++ b/sound/soc/intel/skylake/skl-debug.c @@ -16,10 +16,15 @@ #include #include #include "skl.h" +#include "skl-sst-dsp.h" +#include "skl-sst-ipc.h" #include "skl-tplg-interface.h" #include "skl-topology.h" +#include "../common/sst-dsp-priv.h" #define MOD_BUF PAGE_SIZE +#define FW_REG_BUF PAGE_SIZE +#define FW_REG_SIZE 0x60 struct skl_debug { struct skl *skl; @@ -27,6 +32,7 @@ struct skl_debug { struct dentry *fs; struct dentry *modules; + u8 fw_read_buff[FW_REG_BUF]; }; static ssize_t skl_print_pins(struct skl_module_pin *m_pin, char *buf, @@ -169,6 +175,51 @@ void skl_debug_init_module(struct skl_debug *d, dev_err(d->dev, "%s: module debugfs init failed\n", w->name); } +static ssize_t fw_softreg_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct skl_debug *d = file->private_data; + struct sst_dsp *sst = d->skl->skl_sst->dsp; + size_t w0_stat_sz = sst->addr.w0_stat_sz; + void __iomem *in_base = sst->mailbox.in_base; + void __iomem *fw_reg_addr; + unsigned int offset; + char *tmp; + ssize_t ret = 0; + + tmp = kzalloc(FW_REG_BUF, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + fw_reg_addr = in_base - w0_stat_sz; + memset(d->fw_read_buff, 0, FW_REG_BUF); + + if (w0_stat_sz > 0) + __iowrite32_copy(d->fw_read_buff, fw_reg_addr, w0_stat_sz >> 2); + + for (offset = 0; offset < FW_REG_SIZE; offset += 16) { + ret += snprintf(tmp + ret, FW_REG_BUF - ret, "%#.4x: ", offset); + hex_dump_to_buffer(d->fw_read_buff + offset, 16, 16, 4, + tmp + ret, FW_REG_BUF - ret, 0); + ret += strlen(tmp + ret); + + /* print newline for each offset */ + if (FW_REG_BUF - ret > 0) + tmp[ret++] = '\n'; + } + + ret = simple_read_from_buffer(user_buf, count, ppos, tmp, ret); + kfree(tmp); + + return ret; +} + +static const struct file_operations soft_regs_ctrl_fops = { + .open = simple_open, + .read = fw_softreg_read, + .llseek = default_llseek, +}; + struct skl_debug *skl_debugfs_init(struct skl *skl) { struct skl_debug *d; @@ -195,6 +246,12 @@ struct skl_debug *skl_debugfs_init(struct skl *skl) goto err; } + if (!debugfs_create_file("fw_soft_regs_rd", 0444, d->fs, d, + &soft_regs_ctrl_fops)) { + dev_err(d->dev, "fw soft regs control debugfs init failed\n"); + goto err; + } + return d; err: From 1967158fff819b38f4e46763ca8df067b4b69f59 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 30 Jun 2017 15:18:41 -0500 Subject: [PATCH 411/418] ALSA: x86: fix error return code in hdmi_lpe_audio_probe() platform_get_irq() returns an error code, but the intel_hdmi_audio driver ignores it and always returns -ENODEV. This is not correct, and prevents -EPROBE_DEFER from being propagated properly. Also, notice that platform_get_irq() no longer returns 0 on error. Print error message and propagate the return value of platform_get_irq on failure. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index b11d3920b9a5..37f06ffdf1e6 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1699,8 +1699,8 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) /* get resources */ irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "Could not get irq resource\n"); - return -ENODEV; + dev_err(&pdev->dev, "Could not get irq resource: %d\n", irq); + return irq; } res_mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0); From 7720113516eacd7b91272c2298b1b392ae1ae436 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 30 Jun 2017 17:34:23 -0500 Subject: [PATCH 412/418] ALSA: atmel: ac97c: fix error return code in atmel_ac97c_probe() platform_get_irq() returns an error code, but the ac97c driver ignores it and always returns -ENXIO. This is not correct, and prevents -EPROBE_DEFER from being propagated properly. Notice that platform_get_irq() no longer returns 0 on error. Print and propagate the return value of platform_get_irq on failure. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Takashi Iwai --- sound/atmel/ac97c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 65e6948e3995..9d2c9d9af688 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -774,8 +774,8 @@ static int atmel_ac97c_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_dbg(&pdev->dev, "could not get irq\n"); - return -ENXIO; + dev_dbg(&pdev->dev, "could not get irq: %d\n", irq); + return irq; } pclk = clk_get(&pdev->dev, "ac97_clk"); From d8b53bff0a499cd05a5026307af9a5f41f604ea3 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 2 Jul 2017 11:44:43 +0900 Subject: [PATCH 413/418] ALSA: pcm: add a documentation for tracepoints In PCM interface/protocol for userspace, parameters of runtime for PCM substream is decided by an interaction between applications and ALSA PCM core. In former commits, some tracepoints were added to probe a part of the interaction. This commit adds a documentation about the interaction and the tracepoints. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- Documentation/sound/designs/index.rst | 1 + Documentation/sound/designs/tracepoints.rst | 172 ++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 Documentation/sound/designs/tracepoints.rst diff --git a/Documentation/sound/designs/index.rst b/Documentation/sound/designs/index.rst index 04dcdae3e4f2..f0749943ccb2 100644 --- a/Documentation/sound/designs/index.rst +++ b/Documentation/sound/designs/index.rst @@ -9,6 +9,7 @@ Designs and Implementations compress-offload timestamping jack-controls + tracepoints procfile powersave oss-emulation diff --git a/Documentation/sound/designs/tracepoints.rst b/Documentation/sound/designs/tracepoints.rst new file mode 100644 index 000000000000..78bc5572f829 --- /dev/null +++ b/Documentation/sound/designs/tracepoints.rst @@ -0,0 +1,172 @@ +=================== +Tracepoints in ALSA +=================== + +2017/07/02 +Takasahi Sakamoto + +Tracepoints in ALSA PCM core +============================ + +ALSA PCM core registers ``snd_pcm`` subsystem to kernel tracepoint system. +This subsystem includes two categories of tracepoints; for state of PCM buffer +and for processing of PCM hardware parameters. These tracepoints are available +when corresponding kernel configurations are enabled. When ``CONFIG_SND_DEBUG`` +is enabled, the latter tracepoints are available. When additional +``SND_PCM_XRUN_DEBUG`` is enabled too, the former trace points are enabled. + +Tracepoints for state of PCM buffer +------------------------------------ + +This category includes four tracepoints; ``hwptr``, ``applptr``, ``xrun`` and +``hw_ptr_error``. + +Tracepoints for processing of PCM hardware parameters +----------------------------------------------------- + +This category includes two tracepoints; ``hw_mask_param`` and +``hw_interval_param``. + +In a design of ALSA PCM core, data transmission is abstracted as PCM substream. +Applications manage PCM substream to maintain data transmission for PCM frames. +Before starting the data transmission, applications need to configure PCM +substream. In this procedure, PCM hardware parameters are decided by +interaction between applications and ALSA PCM core. Once decided, runtime of +the PCM substream keeps the parameters. + +The parameters are described in :c:type:`struct snd_pcm_hw_params`. This +structure includes several types of parameters. Applications set preferable +value to these parameters, then execute ioctl(2) with SNDRV_PCM_IOCTL_HW_REFINE +or SNDRV_PCM_IOCTL_HW_PARAMS. The former is used just for refining available +set of parameters. The latter is used for an actual decision of the parameters. + +The :c:type:`struct snd_pcm_hw_params` structure has below members: + +``flags`` + Configurable. ALSA PCM core and some drivers handle this flag to select + convenient parameters or change their behaviour. +``masks`` + Configurable. This type of parameter is described in + :c:type:`struct snd_mask` and represent mask values. As of PCM protocol + v2.0.13, three types are defined. + + - SNDRV_PCM_HW_PARAM_ACCESS + - SNDRV_PCM_HW_PARAM_FORMAT + - SNDRV_PCM_HW_PARAM_SUBFORMAT +``intervals`` + Configurable. This type of parameter is described in + :c:type:`struct snd_interval` and represent values with a range. As of + PCM protocol v2.0.13, twelve types are defined. + + - SNDRV_PCM_HW_PARAM_SAMPLE_BITS + - SNDRV_PCM_HW_PARAM_FRAME_BITS + - SNDRV_PCM_HW_PARAM_CHANNELS + - SNDRV_PCM_HW_PARAM_RATE + - SNDRV_PCM_HW_PARAM_PERIOD_TIME + - SNDRV_PCM_HW_PARAM_PERIOD_SIZE + - SNDRV_PCM_HW_PARAM_PERIOD_BYTES + - SNDRV_PCM_HW_PARAM_PERIODS + - SNDRV_PCM_HW_PARAM_BUFFER_TIME + - SNDRV_PCM_HW_PARAM_BUFFER_SIZE + - SNDRV_PCM_HW_PARAM_BUFFER_BYTES + - SNDRV_PCM_HW_PARAM_TICK_TIME +``rmask`` + Configurable. This is evaluated at ioctl(2) with + SNDRV_PCM_IOCTL_HW_REFINE only. Applications can select which + mask/interval parameter can be changed by ALSA PCM core. For + SNDRV_PCM_IOCTL_HW_PARAMS, this mask is ignored and all of parameters + are going to be changed. +``cmask`` + Read-only. After returning from ioctl(2), buffer in user space for + :c:type:`struct snd_pcm_hw_params` includes result of each operation. + This mask represents which mask/interval parameter is actually changed. +``info`` + Read-only. This represents hardware/driver capabilities as bit flags + with SNDRV_PCM_INFO_XXX. Typically, applications execute ioctl(2) with + SNDRV_PCM_IOCTL_HW_REFINE to retrieve this flag, then decide candidates + of parameters and execute ioctl(2) with SNDRV_PCM_IOCTL_HW_PARAMS to + configure PCM substream. +``msbits`` + Read-only. This value represents available bit width in MSB side of + a PCM sample. When a parameter of SNDRV_PCM_HW_PARAM_SAMPLE_BITS was + decided as a fixed number, this value is also calculated according to + it. Else, zero. But this behaviour depends on implementations in driver + side. +``rate_num`` + Read-only. This value represents numerator of sampling rate in fraction + notation. Basically, when a parameter of SNDRV_PCM_HW_PARAM_RATE was + decided as a single value, this value is also calculated according to + it. Else, zero. But this behaviour depends on implementations in driver + side. +``rate_den`` + Read-only. This value represents denominator of sampling rate in + fraction notation. Basically, when a parameter of + SNDRV_PCM_HW_PARAM_RATE was decided as a single value, this value is + also calculated according to it. Else, zero. But this behaviour depends + on implementations in driver side. +``fifo_size`` + Read-only. This value represents the size of FIFO in serial sound + interface of hardware. Basically, each driver can assigns a proper + value to this parameter but some drivers intentionally set zero with + a care of hardware design or data transmission protocol. + +ALSA PCM core handles buffer of :c:type:`struct snd_pcm_hw_params` when +applications execute ioctl(2) with SNDRV_PCM_HW_REFINE or SNDRV_PCM_HW_PARAMS. +Parameters in the buffer are changed according to +:c:type:`struct snd_pcm_hardware` and rules of constraints in the runtime. The +structure describes capabilities of handled hardware. The rules describes +dependencies on which a parameter is decided according to several parameters. +A rule has a callback function, and drivers can register arbitrary functions +to compute the target parameter. ALSA PCM core registers some rules to the +runtime as a default. + +Each driver can join in the interaction as long as it prepared for two stuffs +in a callback of :c:type:`struct snd_pcm_ops.open`. + +1. In the callback, drivers are expected to change a member of + :c:type:`struct snd_pcm_hardware` type in the runtime, according to + capacities of corresponding hardware. +2. In the same callback, drivers are also expected to register additional rules + of constraints into the runtime when several parameters have dependencies + due to hardware design. + +The driver can refers to result of the interaction in a callback of +:c:type:`struct snd_pcm_ops.hw_params`, however it should not change the +content. + +Tracepoints in this category are designed to trace changes of the +mask/interval parameters. When ALSA PCM core changes them, ``hw_mask_param`` or +``hw_interval_param`` event is probed according to type of the changed parameter. + +ALSA PCM core also has a pretty print format for each of the tracepoints. Below +is an example for ``hw_mask_param``. + +:: + + hw_mask_param: pcmC0D0p 001/023 FORMAT 00000000000000000000001000000044 00000000000000000000001000000044 + + +Below is an example for ``hw_interval_param``. + +:: + + hw_interval_param: pcmC0D0p 000/023 BUFFER_SIZE 0 0 [0 4294967295] 0 1 [0 4294967295] + +The first three fields are common. They represent name of ALSA PCM character +device, rules of constraint and name of the changed parameter, in order. The +field for rules of constraint consists of two sub-fields; index of applied rule +and total number of rules added to the runtime. As an exception, the index 000 +means that the parameter is changed by ALSA PCM core, regardless of the rules. + +The rest of field represent state of the parameter before/after changing. These +fields are different according to type of the parameter. For parameters of mask +type, the fields represent hexadecimal dump of content of the parameter. For +parameters of interval type, the fields represent values of each member of +``empty``, ``integer``, ``openmin``, ``min``, ``max``, ``openmax`` in +:c:type:`struct snd_interval` in this order. + +Tracepoints in drivers +====================== + +Some drivers have tracepoints for developers' convenience. For them, please +refer to each documentation or implementation. From b4576de87243c32fab50dda9f8eba1e3cf13a7e2 Mon Sep 17 00:00:00 2001 From: "Shih-Yuan Lee (FourDollars)" Date: Mon, 3 Jul 2017 14:13:29 +0800 Subject: [PATCH 414/418] ALSA: hda/realtek - Fix typo of pincfg for Dell quirk The PIN number for Dell headset mode of ALC3271 is wrong. Fixes: fcc6c877a01f ("ALSA: hda/realtek - Support Dell headset mode for ALC3271") Signed-off-by: Shih-Yuan Lee (FourDollars) 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 c39bc497650c..d0cf1f39c346 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6553,7 +6553,7 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { SND_HDA_PIN_QUIRK(0x10ec0299, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, ALC225_STANDARD_PINS, {0x12, 0xb7a60130}, - {0x13, 0xb8a60140}, + {0x13, 0xb8a61140}, {0x17, 0x90170110}), {} }; From a178232ddab55048e347b43b697bfa5013ef819e Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Mon, 3 Jul 2017 17:26:50 +0800 Subject: [PATCH 415/418] ALSA: hda/realtek - Remove GPIO_MASK GPIO_MASK was introduced in commit "df694daa3c01 [ALSA] hda-codec - Add the support of ALC262,ALC883,ALC885,ALC861" but it's not being used. So we can simply remove it. Signed-off-by: Kai-Heng Feng Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d0cf1f39c346..cd6987b5c6d9 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -41,9 +41,6 @@ /* keep halting ALC5505 DSP, for power saving */ #define HALT_REALTEK_ALC5505 -/* for GPIO Poll */ -#define GPIO_MASK 0x03 - /* extra amp-initialization sequence types */ enum { ALC_INIT_NONE, From 58be77537aa12ca0c6c91eaf37902ad5f8c812bd Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 3 Jul 2017 13:54:46 +0530 Subject: [PATCH 416/418] ASoC: Intel: Skylake: explicitly add the headers sst-dsp.h Commit bdd0384a5ada ("ASoC: Intel: Skylake: Add support to read firmware registers") introduced firmware register read so added sst-dsp-priv.h but missed adding sst-dsp.h as that leads to below compiler warning: In file included from sound/soc/intel/skylake/skl-debug.c:23:0: >> sound/soc/intel/skylake/../common/sst-dsp-priv.h:63:42: warning: 'struct sst_pdata' declared inside parameter list [enabled by default] int (*init)(struct sst_dsp *sst, struct sst_pdata *pdata); ^ >> sound/soc/intel/skylake/../common/sst-dsp-priv.h:63:42: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default] So add the missing header. Fixes: bdd0384a5ada ("ASoC: Intel: Skylake: Add support to read firmware registers") Reported-by: kbuild test robot Signed-off-by: Vinod Koul Signed-off-by: Guneshwor Singh Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-debug.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c index 75497b1fda45..34d06abbf796 100644 --- a/sound/soc/intel/skylake/skl-debug.c +++ b/sound/soc/intel/skylake/skl-debug.c @@ -20,6 +20,7 @@ #include "skl-sst-ipc.h" #include "skl-tplg-interface.h" #include "skl-topology.h" +#include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" #define MOD_BUF PAGE_SIZE From 7d3d6e0645dd3689e625161b9e312108e66b2b51 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 3 Jul 2017 13:54:47 +0530 Subject: [PATCH 417/418] ASoC: Intel: Skylake: Remove driver debugfs exit For driver debugfs, debugfs_remove_recursive() is called which is not needed as it is already done in ASoC core debugfs. And a device managed memory need not be freed explicitly as device core frees it up. So remove unnecessary skl_debugfs_exit(). Fixes: 5cdf6c09ca9d ASoC: ("Intel: Skylake: Add debugfs support") Reported-by: Julia Lawall Reported-by: kbuild test robot Signed-off-by: Vinod Koul Signed-off-by: Guneshwor Singh Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-debug.c | 8 -------- sound/soc/intel/skylake/skl.c | 1 - sound/soc/intel/skylake/skl.h | 3 --- 3 files changed, 12 deletions(-) diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c index 34d06abbf796..dc20d91f62e6 100644 --- a/sound/soc/intel/skylake/skl-debug.c +++ b/sound/soc/intel/skylake/skl-debug.c @@ -259,11 +259,3 @@ err: debugfs_remove_recursive(d->fs); return NULL; } - -void skl_debugfs_exit(struct skl_debug *d) -{ - debugfs_remove_recursive(d->fs); - - kfree(d); - -} diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 410ce83f4a49..334917ee41cf 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -866,7 +866,6 @@ static void skl_remove(struct pci_dev *pci) /* codec removal, invoke bus_device_remove */ snd_hdac_ext_bus_device_remove(ebus); - skl_debugfs_exit(skl->debugfs); skl->debugfs = NULL; skl_platform_unregister(&pci->dev); skl_free_dsp(skl); diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 14e7778d7f80..a6b134b4c037 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -125,7 +125,6 @@ struct skl_module_cfg; #ifdef CONFIG_DEBUG_FS struct skl_debug *skl_debugfs_init(struct skl *skl); -void skl_debugfs_exit(struct skl_debug *d); void skl_debug_init_module(struct skl_debug *d, struct snd_soc_dapm_widget *w, struct skl_module_cfg *mconfig); @@ -134,8 +133,6 @@ static inline struct skl_debug *skl_debugfs_init(struct skl *skl) { return NULL; } -static inline void skl_debugfs_exit(struct skl_debug *d) -{} static inline void skl_debug_init_module(struct skl_debug *d, struct snd_soc_dapm_widget *w, struct skl_module_cfg *mconfig) From fc18282cdcba984ab89c74d7e844c10114ae0795 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 4 Jul 2017 16:04:38 +0200 Subject: [PATCH 418/418] ALSA: hda - Fix unbalance of i915 module refcount The commit dba9b7b6ca1a ("ALSA: hda - Fix doubly initialization of i915 component") contained a typo that leads to the unbalance of i915 module reference. The value to be checked is not chip->driver_type but chip->driver_caps. Fixes: dba9b7b6ca1a ("ALSA: hda - Fix doubly initialization of i915 component") Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=196219 Reported-by: Martin Peres Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 03e34edc8f24..5ae8ddab6412 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1385,7 +1385,7 @@ static int azx_free(struct azx *chip) if (hda->need_i915_power) snd_hdac_display_power(bus, false); } - if (chip->driver_type & AZX_DCAPS_I915_COMPONENT) + if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT) snd_hdac_i915_exit(bus); kfree(hda);