On 09/22/16 23:06, Nikita Yushchenko wrote: > tlv320dac31xx is a subset of tlv320aic31xx: > - it does not have MIC inputs and ADC, thus capture is not supported, > - it has analog inputs AIN1/AIN2 that can be mixed into output. > > Although tlv320dac31xx does work with tlv320aic31xx driver, this setup > does register non-existent widgets and non-existent capture stream. > Thus userspace lists non-existent objects in user interfaces, an can > access these, causing operations with device registers that are > declared as "reserved" in tlv320dac31xx datasheet. > > This patch fixes this situation by separating controls/widgets/routes > into common, aic31xx-specific, and dac31xx-specific parts. Only parts > that match actual hardware (as declared in "compatible" device tree > property) are registered. This patch can not be applied on linux-next due to 1bb99f2a0068 ASoC: codec duplicated callback function goes to component on tlv320aic31xx Can you update this patch on top of next? Can you update the Documentation/devicetree/bindings/sound/tlv320aic31xx.txt as well? -- Péter > > Signed-off-by: Nikita Yushchenko <nikita.yoush@xxxxxxxxxxxxxxxxxx> > --- > sound/soc/codecs/tlv320aic31xx.c | 212 ++++++++++++++++++++++++++++----------- > sound/soc/codecs/tlv320aic31xx.h | 2 + > 2 files changed, 158 insertions(+), 56 deletions(-) > > diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c > index 3c5e1df..fb7d648 100644 > --- a/sound/soc/codecs/tlv320aic31xx.c > +++ b/sound/soc/codecs/tlv320aic31xx.c > @@ -273,10 +273,20 @@ static const DECLARE_TLV_DB_SCALE(sp_vol_tlv, -6350, 50, 0); > /* > * controls to be exported to the user space > */ > -static const struct snd_kcontrol_new aic31xx_snd_controls[] = { > +static const struct snd_kcontrol_new common31xx_snd_controls[] = { > SOC_DOUBLE_R_S_TLV("DAC Playback Volume", AIC31XX_LDACVOL, > AIC31XX_RDACVOL, 0, -127, 48, 7, 0, dac_vol_tlv), > > + SOC_DOUBLE_R("HP Driver Playback Switch", AIC31XX_HPLGAIN, > + AIC31XX_HPRGAIN, 2, 1, 0), > + SOC_DOUBLE_R_TLV("HP Driver Playback Volume", AIC31XX_HPLGAIN, > + AIC31XX_HPRGAIN, 3, 0x09, 0, hp_drv_tlv), > + > + SOC_DOUBLE_R_TLV("HP Analog Playback Volume", AIC31XX_LANALOGHPL, > + AIC31XX_RANALOGHPR, 0, 0x7F, 1, hp_vol_tlv), > +}; > + > +static const struct snd_kcontrol_new aic31xx_snd_controls[] = { > SOC_SINGLE_TLV("ADC Fine Capture Volume", AIC31XX_ADCFGA, 4, 4, 1, > adc_fgain_tlv), > > @@ -286,14 +296,6 @@ static const struct snd_kcontrol_new aic31xx_snd_controls[] = { > > SOC_SINGLE_TLV("Mic PGA Capture Volume", AIC31XX_MICPGA, 0, > 119, 0, mic_pga_tlv), > - > - SOC_DOUBLE_R("HP Driver Playback Switch", AIC31XX_HPLGAIN, > - AIC31XX_HPRGAIN, 2, 1, 0), > - SOC_DOUBLE_R_TLV("HP Driver Playback Volume", AIC31XX_HPLGAIN, > - AIC31XX_HPRGAIN, 3, 0x09, 0, hp_drv_tlv), > - > - SOC_DOUBLE_R_TLV("HP Analog Playback Volume", AIC31XX_LANALOGHPL, > - AIC31XX_RANALOGHPR, 0, 0x7F, 1, hp_vol_tlv), > }; > > static const struct snd_kcontrol_new aic311x_snd_controls[] = { > @@ -397,17 +399,28 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w, > return 0; > } > > -static const struct snd_kcontrol_new left_output_switches[] = { > +static const struct snd_kcontrol_new aic31xx_left_output_switches[] = { > SOC_DAPM_SINGLE("From Left DAC", AIC31XX_DACMIXERROUTE, 6, 1, 0), > SOC_DAPM_SINGLE("From MIC1LP", AIC31XX_DACMIXERROUTE, 5, 1, 0), > SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 4, 1, 0), > }; > > -static const struct snd_kcontrol_new right_output_switches[] = { > +static const struct snd_kcontrol_new aic31xx_right_output_switches[] = { > SOC_DAPM_SINGLE("From Right DAC", AIC31XX_DACMIXERROUTE, 2, 1, 0), > SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 1, 1, 0), > }; > > +static const struct snd_kcontrol_new dac31xx_left_output_switches[] = { > + SOC_DAPM_SINGLE("From Left DAC", AIC31XX_DACMIXERROUTE, 6, 1, 0), > + SOC_DAPM_SINGLE("From AIN1", AIC31XX_DACMIXERROUTE, 5, 1, 0), > + SOC_DAPM_SINGLE("From AIN2", AIC31XX_DACMIXERROUTE, 4, 1, 0), > +}; > + > +static const struct snd_kcontrol_new dac31xx_right_output_switches[] = { > + SOC_DAPM_SINGLE("From Right DAC", AIC31XX_DACMIXERROUTE, 2, 1, 0), > + SOC_DAPM_SINGLE("From AIN2", AIC31XX_DACMIXERROUTE, 1, 1, 0), > +}; > + > static const struct snd_kcontrol_new p_term_mic1lp = > SOC_DAPM_ENUM("MIC1LP P-Terminal", mic1lp_p_enum); > > @@ -457,7 +470,7 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, > return 0; > } > > -static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = { > +static const struct snd_soc_dapm_widget common31xx_dapm_widgets[] = { > SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0), > > SND_SOC_DAPM_MUX("DAC Left Input", > @@ -473,14 +486,7 @@ static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = { > AIC31XX_DACSETUP, 6, 0, aic31xx_dapm_power_event, > SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), > > - /* Output Mixers */ > - SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0, > - left_output_switches, > - ARRAY_SIZE(left_output_switches)), > - SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0, > - right_output_switches, > - ARRAY_SIZE(right_output_switches)), > - > + /* HP */ > SND_SOC_DAPM_SWITCH("HP Left", SND_SOC_NOPM, 0, 0, > &aic31xx_dapm_hpl_switch), > SND_SOC_DAPM_SWITCH("HP Right", SND_SOC_NOPM, 0, 0, > @@ -494,10 +500,34 @@ static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = { > NULL, 0, aic31xx_dapm_power_event, > SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), > > - /* ADC */ > - SND_SOC_DAPM_ADC_E("ADC", "Capture", AIC31XX_ADCSETUP, 7, 0, > - aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU | > - SND_SOC_DAPM_POST_PMD), > + /* Mic Bias */ > + SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, mic_bias_event, > + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), > + > + /* Outputs */ > + SND_SOC_DAPM_OUTPUT("HPL"), > + SND_SOC_DAPM_OUTPUT("HPR"), > +}; > + > +static const struct snd_soc_dapm_widget dac31xx_dapm_widgets[] = { > + /* Inputs */ > + SND_SOC_DAPM_INPUT("AIN1"), > + SND_SOC_DAPM_INPUT("AIN2"), > + > + /* Output Mixers */ > + SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0, > + dac31xx_left_output_switches, > + ARRAY_SIZE(dac31xx_left_output_switches)), > + SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0, > + dac31xx_right_output_switches, > + ARRAY_SIZE(dac31xx_right_output_switches)), > +}; > + > +static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = { > + /* Inputs */ > + SND_SOC_DAPM_INPUT("MIC1LP"), > + SND_SOC_DAPM_INPUT("MIC1RP"), > + SND_SOC_DAPM_INPUT("MIC1LM"), > > /* Input Selection to MIC_PGA */ > SND_SOC_DAPM_MUX("MIC1LP P-Terminal", SND_SOC_NOPM, 0, 0, > @@ -507,24 +537,25 @@ static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = { > SND_SOC_DAPM_MUX("MIC1LM P-Terminal", SND_SOC_NOPM, 0, 0, > &p_term_mic1lm), > > + /* ADC */ > + SND_SOC_DAPM_ADC_E("ADC", "Capture", AIC31XX_ADCSETUP, 7, 0, > + aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU | > + SND_SOC_DAPM_POST_PMD), > + > SND_SOC_DAPM_MUX("MIC1LM M-Terminal", SND_SOC_NOPM, 0, 0, > &m_term_mic1lm), > + > /* Enabling & Disabling MIC Gain Ctl */ > SND_SOC_DAPM_PGA("MIC_GAIN_CTL", AIC31XX_MICPGA, > 7, 1, NULL, 0), > > - /* Mic Bias */ > - SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, mic_bias_event, > - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), > - > - /* Outputs */ > - SND_SOC_DAPM_OUTPUT("HPL"), > - SND_SOC_DAPM_OUTPUT("HPR"), > - > - /* Inputs */ > - SND_SOC_DAPM_INPUT("MIC1LP"), > - SND_SOC_DAPM_INPUT("MIC1RP"), > - SND_SOC_DAPM_INPUT("MIC1LM"), > + /* Output Mixers */ > + SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0, > + aic31xx_left_output_switches, > + ARRAY_SIZE(aic31xx_left_output_switches)), > + SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0, > + aic31xx_right_output_switches, > + ARRAY_SIZE(aic31xx_right_output_switches)), > }; > > static const struct snd_soc_dapm_widget aic311x_dapm_widgets[] = { > @@ -554,7 +585,7 @@ static const struct snd_soc_dapm_widget aic310x_dapm_widgets[] = { > }; > > static const struct snd_soc_dapm_route > -aic31xx_audio_map[] = { > +common31xx_audio_map[] = { > /* DAC Input Routing */ > {"DAC Left Input", "Left Data", "DAC IN"}, > {"DAC Left Input", "Right Data", "DAC IN"}, > @@ -565,6 +596,31 @@ aic31xx_audio_map[] = { > {"DAC Left", NULL, "DAC Left Input"}, > {"DAC Right", NULL, "DAC Right Input"}, > > + /* HPL path */ > + {"HP Left", "Switch", "Output Left"}, > + {"HPL Driver", NULL, "HP Left"}, > + {"HPL", NULL, "HPL Driver"}, > + > + /* HPR path */ > + {"HP Right", "Switch", "Output Right"}, > + {"HPR Driver", NULL, "HP Right"}, > + {"HPR", NULL, "HPR Driver"}, > +}; > + > +static const struct snd_soc_dapm_route > +dac31xx_audio_map[] = { > + /* Left Output */ > + {"Output Left", "From Left DAC", "DAC Left"}, > + {"Output Left", "From AIN1", "AIN1"}, > + {"Output Left", "From AIN2", "AIN2"}, > + > + /* Right Output */ > + {"Output Right", "From Right DAC", "DAC Right"}, > + {"Output Right", "From AIN2", "AIN2"}, > +}; > + > +static const struct snd_soc_dapm_route > +aic31xx_audio_map[] = { > /* Mic input */ > {"MIC1LP P-Terminal", "FFR 10 Ohm", "MIC1LP"}, > {"MIC1LP P-Terminal", "FFR 20 Ohm", "MIC1LP"}, > @@ -595,16 +651,6 @@ aic31xx_audio_map[] = { > /* Right Output */ > {"Output Right", "From Right DAC", "DAC Right"}, > {"Output Right", "From MIC1RP", "MIC1RP"}, > - > - /* HPL path */ > - {"HP Left", "Switch", "Output Left"}, > - {"HPL Driver", NULL, "HP Left"}, > - {"HPL", NULL, "HPL Driver"}, > - > - /* HPR path */ > - {"HP Right", "Switch", "Output Right"}, > - {"HPR Driver", NULL, "HP Right"}, > - {"HPR", NULL, "HPR Driver"}, > }; > > static const struct snd_soc_dapm_route > @@ -633,6 +679,13 @@ static int aic31xx_add_controls(struct snd_soc_codec *codec) > int ret = 0; > struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); > > + if (!(aic31xx->pdata.codec_type & DAC31XX_BIT)) > + ret = snd_soc_add_codec_controls( > + codec, aic31xx_snd_controls, > + ARRAY_SIZE(aic31xx_snd_controls)); > + if (ret) > + return ret; > + > if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) > ret = snd_soc_add_codec_controls( > codec, aic311x_snd_controls, > @@ -651,6 +704,30 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec) > struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); > int ret = 0; > > + if (aic31xx->pdata.codec_type & DAC31XX_BIT) { > + ret = snd_soc_dapm_new_controls( > + dapm, dac31xx_dapm_widgets, > + ARRAY_SIZE(dac31xx_dapm_widgets)); > + if (ret) > + return ret; > + > + ret = snd_soc_dapm_add_routes(dapm, dac31xx_audio_map, > + ARRAY_SIZE(dac31xx_audio_map)); > + if (ret) > + return ret; > + } else { > + ret = snd_soc_dapm_new_controls( > + dapm, aic31xx_dapm_widgets, > + ARRAY_SIZE(aic31xx_dapm_widgets)); > + if (ret) > + return ret; > + > + ret = snd_soc_dapm_add_routes(dapm, aic31xx_audio_map, > + ARRAY_SIZE(aic31xx_audio_map)); > + if (ret) > + return ret; > + } > + > if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) { > ret = snd_soc_dapm_new_controls( > dapm, aic311x_dapm_widgets, > @@ -1114,12 +1191,12 @@ static struct snd_soc_codec_driver soc_codec_driver_aic31xx = { > .set_bias_level = aic31xx_set_bias_level, > .suspend_bias_off = true, > > - .controls = aic31xx_snd_controls, > - .num_controls = ARRAY_SIZE(aic31xx_snd_controls), > - .dapm_widgets = aic31xx_dapm_widgets, > - .num_dapm_widgets = ARRAY_SIZE(aic31xx_dapm_widgets), > - .dapm_routes = aic31xx_audio_map, > - .num_dapm_routes = ARRAY_SIZE(aic31xx_audio_map), > + .controls = common31xx_snd_controls, > + .num_controls = ARRAY_SIZE(common31xx_snd_controls), > + .dapm_widgets = common31xx_dapm_widgets, > + .num_dapm_widgets = ARRAY_SIZE(common31xx_dapm_widgets), > + .dapm_routes = common31xx_audio_map, > + .num_dapm_routes = ARRAY_SIZE(common31xx_audio_map), > }; > > static const struct snd_soc_dai_ops aic31xx_dai_ops = { > @@ -1129,6 +1206,21 @@ static const struct snd_soc_dai_ops aic31xx_dai_ops = { > .digital_mute = aic31xx_dac_mute, > }; > > +static struct snd_soc_dai_driver dac31xx_dai_driver[] = { > + { > + .name = "tlv32dac31xx-hifi", > + .playback = { > + .stream_name = "Playback", > + .channels_min = 1, > + .channels_max = 2, > + .rates = AIC31XX_RATES, > + .formats = AIC31XX_FORMATS, > + }, > + .ops = &aic31xx_dai_ops, > + .symmetric_rates = 1, > + } > +}; > + > static struct snd_soc_dai_driver aic31xx_dai_driver[] = { > { > .name = "tlv320aic31xx-hifi", > @@ -1259,9 +1351,16 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, > if (ret) > return ret; > > - return snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx, > - aic31xx_dai_driver, > - ARRAY_SIZE(aic31xx_dai_driver)); > + if (aic31xx->pdata.codec_type & DAC31XX_BIT) > + return snd_soc_register_codec(&i2c->dev, > + &soc_codec_driver_aic31xx, > + dac31xx_dai_driver, > + ARRAY_SIZE(dac31xx_dai_driver)); > + else > + return snd_soc_register_codec(&i2c->dev, > + &soc_codec_driver_aic31xx, > + aic31xx_dai_driver, > + ARRAY_SIZE(aic31xx_dai_driver)); > } > > static int aic31xx_i2c_remove(struct i2c_client *i2c) > @@ -1277,6 +1376,7 @@ static const struct i2c_device_id aic31xx_i2c_id[] = { > { "tlv320aic3110", AIC3110 }, > { "tlv320aic3120", AIC3120 }, > { "tlv320aic3111", AIC3111 }, > + { "tlv320dac3100", DAC3100 }, > { } > }; > MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); > diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h > index ac9b146..5acd5b6 100644 > --- a/sound/soc/codecs/tlv320aic31xx.h > +++ b/sound/soc/codecs/tlv320aic31xx.h > @@ -24,12 +24,14 @@ > > #define AIC31XX_STEREO_CLASS_D_BIT 0x1 > #define AIC31XX_MINIDSP_BIT 0x2 > +#define DAC31XX_BIT 0x4 > > enum aic31xx_type { > AIC3100 = 0, > AIC3110 = AIC31XX_STEREO_CLASS_D_BIT, > AIC3120 = AIC31XX_MINIDSP_BIT, > AIC3111 = (AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT), > + DAC3100 = DAC31XX_BIT, > }; > > struct aic31xx_pdata { > _______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxx http://mailman.alsa-project.org/mailman/listinfo/alsa-devel