@@ -108,67 +108,152 @@ static void tegra210_mvc_conv_vol(struct tegra210_mvc *mvc, u8 chan, s32 val)
108108 }
109109}
110110
111- static int tegra210_mvc_get_mute (struct snd_kcontrol * kcontrol ,
112- struct snd_ctl_elem_value * ucontrol )
111+ static u32 tegra210_mvc_get_ctrl_reg (struct snd_kcontrol * kcontrol )
113112{
114113 struct snd_soc_component * cmpnt = snd_soc_kcontrol_component (kcontrol );
115114 struct tegra210_mvc * mvc = snd_soc_component_get_drvdata (cmpnt );
116- u8 mute_mask ;
117115 u32 val ;
118116
119117 pm_runtime_get_sync (cmpnt -> dev );
120118 regmap_read (mvc -> regmap , TEGRA210_MVC_CTRL , & val );
121119 pm_runtime_put (cmpnt -> dev );
122120
123- mute_mask = (val >> TEGRA210_MVC_MUTE_SHIFT ) &
124- TEGRA210_MUTE_MASK_EN ;
121+ return val ;
122+ }
123+
124+ static int tegra210_mvc_get_mute (struct snd_kcontrol * kcontrol ,
125+ struct snd_ctl_elem_value * ucontrol )
126+ {
127+ u32 val = tegra210_mvc_get_ctrl_reg (kcontrol );
128+ u8 mute_mask = TEGRA210_GET_MUTE_VAL (val );
125129
126- ucontrol -> value .integer .value [0 ] = mute_mask ;
130+ /*
131+ * If per channel control is enabled, then return
132+ * exact mute/unmute setting of all channels.
133+ *
134+ * Else report setting based on CH0 bit to reflect
135+ * the correct HW state.
136+ */
137+ if (val & TEGRA210_MVC_PER_CHAN_CTRL_EN ) {
138+ ucontrol -> value .integer .value [0 ] = mute_mask ;
139+ } else {
140+ if (mute_mask & TEGRA210_MVC_CH0_MUTE_EN )
141+ ucontrol -> value .integer .value [0 ] =
142+ TEGRA210_MUTE_MASK_EN ;
143+ else
144+ ucontrol -> value .integer .value [0 ] = 0 ;
145+ }
127146
128147 return 0 ;
129148}
130149
131- static int tegra210_mvc_put_mute (struct snd_kcontrol * kcontrol ,
132- struct snd_ctl_elem_value * ucontrol )
150+ static int tegra210_mvc_get_master_mute (struct snd_kcontrol * kcontrol ,
151+ struct snd_ctl_elem_value * ucontrol )
152+ {
153+ u32 val = tegra210_mvc_get_ctrl_reg (kcontrol );
154+ u8 mute_mask = TEGRA210_GET_MUTE_VAL (val );
155+
156+ /*
157+ * If per channel control is disabled, then return
158+ * master mute/unmute setting based on CH0 bit.
159+ *
160+ * Else report settings based on state of all
161+ * channels.
162+ */
163+ if (!(val & TEGRA210_MVC_PER_CHAN_CTRL_EN )) {
164+ ucontrol -> value .integer .value [0 ] =
165+ mute_mask & TEGRA210_MVC_CH0_MUTE_EN ;
166+ } else {
167+ if (mute_mask == TEGRA210_MUTE_MASK_EN )
168+ ucontrol -> value .integer .value [0 ] =
169+ TEGRA210_MVC_CH0_MUTE_EN ;
170+ else
171+ ucontrol -> value .integer .value [0 ] = 0 ;
172+ }
173+
174+ return 0 ;
175+ }
176+
177+ static int tegra210_mvc_volume_switch_timeout (struct snd_soc_component * cmpnt )
133178{
134- struct soc_mixer_control * mc =
135- (struct soc_mixer_control * )kcontrol -> private_value ;
136- struct snd_soc_component * cmpnt = snd_soc_kcontrol_component (kcontrol );
137179 struct tegra210_mvc * mvc = snd_soc_component_get_drvdata (cmpnt );
138- unsigned int value ;
139- u8 new_mask , old_mask ;
180+ u32 value ;
140181 int err ;
141182
142- pm_runtime_get_sync (cmpnt -> dev );
143-
144- /* Check if VOLUME_SWITCH is triggered */
145183 err = regmap_read_poll_timeout (mvc -> regmap , TEGRA210_MVC_SWITCH ,
146184 value , !(value & TEGRA210_MVC_VOLUME_SWITCH_MASK ),
147185 10 , 10000 );
148186 if (err < 0 )
149- goto end ;
187+ dev_err (cmpnt -> dev ,
188+ "Volume switch trigger is still active, err = %d\n" ,
189+ err );
150190
151- regmap_read (mvc -> regmap , TEGRA210_MVC_CTRL , & value );
191+ return err ;
192+ }
152193
153- old_mask = (value >> TEGRA210_MVC_MUTE_SHIFT ) & TEGRA210_MUTE_MASK_EN ;
154- new_mask = ucontrol -> value .integer .value [0 ];
194+ static int tegra210_mvc_update_mute (struct snd_kcontrol * kcontrol ,
195+ struct snd_ctl_elem_value * ucontrol ,
196+ bool per_chan_ctrl )
197+ {
198+ struct snd_soc_component * cmpnt = snd_soc_kcontrol_component (kcontrol );
199+ struct tegra210_mvc * mvc = snd_soc_component_get_drvdata (cmpnt );
200+ u32 mute_val = ucontrol -> value .integer .value [0 ];
201+ u32 per_ch_ctrl_val ;
202+ bool change = false;
203+ int err ;
155204
156- if (new_mask == old_mask ) {
157- err = 0 ;
205+ pm_runtime_get_sync (cmpnt -> dev );
206+
207+ err = tegra210_mvc_volume_switch_timeout (cmpnt );
208+ if (err < 0 )
158209 goto end ;
210+
211+ if (per_chan_ctrl ) {
212+ per_ch_ctrl_val = TEGRA210_MVC_PER_CHAN_CTRL_EN ;
213+ } else {
214+ per_ch_ctrl_val = 0 ;
215+
216+ if (mute_val )
217+ mute_val = TEGRA210_MUTE_MASK_EN ;
159218 }
160219
161- err = regmap_update_bits (mvc -> regmap , mc -> reg ,
220+ regmap_update_bits_check (mvc -> regmap , TEGRA210_MVC_CTRL ,
162221 TEGRA210_MVC_MUTE_MASK ,
163- new_mask << TEGRA210_MVC_MUTE_SHIFT );
164- if (err < 0 )
165- goto end ;
222+ mute_val << TEGRA210_MVC_MUTE_SHIFT ,
223+ & change );
166224
167- err = 1 ;
225+ if (change ) {
226+ regmap_update_bits (mvc -> regmap , TEGRA210_MVC_CTRL ,
227+ TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK ,
228+ per_ch_ctrl_val );
229+
230+ regmap_update_bits (mvc -> regmap , TEGRA210_MVC_SWITCH ,
231+ TEGRA210_MVC_VOLUME_SWITCH_MASK ,
232+ TEGRA210_MVC_VOLUME_SWITCH_TRIGGER );
233+ }
168234
169235end :
170236 pm_runtime_put (cmpnt -> dev );
171- return err ;
237+
238+ if (err < 0 )
239+ return err ;
240+
241+ if (change )
242+ return 1 ;
243+
244+ return 0 ;
245+ }
246+
247+ static int tegra210_mvc_put_mute (struct snd_kcontrol * kcontrol ,
248+ struct snd_ctl_elem_value * ucontrol )
249+ {
250+ return tegra210_mvc_update_mute (kcontrol , ucontrol , true);
251+ }
252+
253+ static int tegra210_mvc_put_master_mute (struct snd_kcontrol * kcontrol ,
254+ struct snd_ctl_elem_value * ucontrol )
255+ {
256+ return tegra210_mvc_update_mute (kcontrol , ucontrol , false);
172257}
173258
174259static int tegra210_mvc_get_vol (struct snd_kcontrol * kcontrol ,
@@ -178,7 +263,7 @@ static int tegra210_mvc_get_vol(struct snd_kcontrol *kcontrol,
178263 (struct soc_mixer_control * )kcontrol -> private_value ;
179264 struct snd_soc_component * cmpnt = snd_soc_kcontrol_component (kcontrol );
180265 struct tegra210_mvc * mvc = snd_soc_component_get_drvdata (cmpnt );
181- u8 chan = (mc -> reg - TEGRA210_MVC_TARGET_VOL ) / REG_SIZE ;
266+ u8 chan = TEGRA210_MVC_GET_CHAN (mc -> reg , TEGRA210_MVC_TARGET_VOL );
182267 s32 val = mvc -> volume [chan ];
183268
184269 if (mvc -> curve_type == CURVE_POLY ) {
@@ -193,44 +278,55 @@ static int tegra210_mvc_get_vol(struct snd_kcontrol *kcontrol,
193278 return 0 ;
194279}
195280
196- static int tegra210_mvc_put_vol (struct snd_kcontrol * kcontrol ,
197- struct snd_ctl_elem_value * ucontrol )
281+ static int tegra210_mvc_get_master_vol (struct snd_kcontrol * kcontrol ,
282+ struct snd_ctl_elem_value * ucontrol )
283+ {
284+ return tegra210_mvc_get_vol (kcontrol , ucontrol );
285+ }
286+
287+ static int tegra210_mvc_update_vol (struct snd_kcontrol * kcontrol ,
288+ struct snd_ctl_elem_value * ucontrol ,
289+ bool per_ch_enable )
198290{
199291 struct soc_mixer_control * mc =
200292 (struct soc_mixer_control * )kcontrol -> private_value ;
201293 struct snd_soc_component * cmpnt = snd_soc_kcontrol_component (kcontrol );
202294 struct tegra210_mvc * mvc = snd_soc_component_get_drvdata (cmpnt );
203- unsigned int reg = mc -> reg ;
204- unsigned int value ;
205- u8 chan ;
206- int err , old_volume ;
295+ u8 chan = TEGRA210_MVC_GET_CHAN (mc -> reg , TEGRA210_MVC_TARGET_VOL );
296+ int old_volume = mvc -> volume [chan ];
297+ int err , i ;
207298
208299 pm_runtime_get_sync (cmpnt -> dev );
209300
210- /* Check if VOLUME_SWITCH is triggered */
211- err = regmap_read_poll_timeout (mvc -> regmap , TEGRA210_MVC_SWITCH ,
212- value , !(value & TEGRA210_MVC_VOLUME_SWITCH_MASK ),
213- 10 , 10000 );
301+ err = tegra210_mvc_volume_switch_timeout (cmpnt );
214302 if (err < 0 )
215303 goto end ;
216304
217- chan = (reg - TEGRA210_MVC_TARGET_VOL ) / REG_SIZE ;
218- old_volume = mvc -> volume [chan ];
219-
220- tegra210_mvc_conv_vol (mvc , chan ,
221- ucontrol -> value .integer .value [0 ]);
305+ tegra210_mvc_conv_vol (mvc , chan , ucontrol -> value .integer .value [0 ]);
222306
223307 if (mvc -> volume [chan ] == old_volume ) {
224308 err = 0 ;
225309 goto end ;
226310 }
227311
312+ if (per_ch_enable ) {
313+ regmap_update_bits (mvc -> regmap , TEGRA210_MVC_CTRL ,
314+ TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK ,
315+ TEGRA210_MVC_PER_CHAN_CTRL_EN );
316+ } else {
317+ regmap_update_bits (mvc -> regmap , TEGRA210_MVC_CTRL ,
318+ TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK , 0 );
319+
320+ for (i = 1 ; i < TEGRA210_MVC_MAX_CHAN_COUNT ; i ++ )
321+ mvc -> volume [i ] = mvc -> volume [chan ];
322+ }
323+
228324 /* Configure init volume same as target volume */
229325 regmap_write (mvc -> regmap ,
230326 TEGRA210_MVC_REG_OFFSET (TEGRA210_MVC_INIT_VOL , chan ),
231327 mvc -> volume [chan ]);
232328
233- regmap_write (mvc -> regmap , reg , mvc -> volume [chan ]);
329+ regmap_write (mvc -> regmap , mc -> reg , mvc -> volume [chan ]);
234330
235331 regmap_update_bits (mvc -> regmap , TEGRA210_MVC_SWITCH ,
236332 TEGRA210_MVC_VOLUME_SWITCH_MASK ,
@@ -240,9 +336,22 @@ static int tegra210_mvc_put_vol(struct snd_kcontrol *kcontrol,
240336
241337end :
242338 pm_runtime_put (cmpnt -> dev );
339+
243340 return err ;
244341}
245342
343+ static int tegra210_mvc_put_vol (struct snd_kcontrol * kcontrol ,
344+ struct snd_ctl_elem_value * ucontrol )
345+ {
346+ return tegra210_mvc_update_vol (kcontrol , ucontrol , true);
347+ }
348+
349+ static int tegra210_mvc_put_master_vol (struct snd_kcontrol * kcontrol ,
350+ struct snd_ctl_elem_value * ucontrol )
351+ {
352+ return tegra210_mvc_update_vol (kcontrol , ucontrol , false);
353+ }
354+
246355static void tegra210_mvc_reset_vol_settings (struct tegra210_mvc * mvc ,
247356 struct device * dev )
248357{
@@ -436,6 +545,16 @@ static const struct snd_kcontrol_new tegra210_mvc_vol_ctrl[] = {
436545 TEGRA210_MVC_CTRL , 0 , TEGRA210_MUTE_MASK_EN , 0 ,
437546 tegra210_mvc_get_mute , tegra210_mvc_put_mute ),
438547
548+ /* Master volume */
549+ SOC_SINGLE_EXT ("Volume" , TEGRA210_MVC_TARGET_VOL , 0 , 16000 , 0 ,
550+ tegra210_mvc_get_master_vol ,
551+ tegra210_mvc_put_master_vol ),
552+
553+ /* Master mute */
554+ SOC_SINGLE_EXT ("Mute" , TEGRA210_MVC_CTRL , 0 , 1 , 0 ,
555+ tegra210_mvc_get_master_mute ,
556+ tegra210_mvc_put_master_mute ),
557+
439558 SOC_ENUM_EXT ("Curve Type" , tegra210_mvc_curve_type_ctrl ,
440559 tegra210_mvc_get_curve_type , tegra210_mvc_put_curve_type ),
441560};
0 commit comments