@@ -169,6 +169,142 @@ static int cs35l45_dsp_audio_ev(struct snd_soc_dapm_widget *w,
169169 return 0 ;
170170}
171171
172+ static int cs35l45_activate_ctl (struct snd_soc_component * component ,
173+ const char * ctl_name , bool active )
174+ {
175+ struct snd_card * card = component -> card -> snd_card ;
176+ struct snd_kcontrol * kcontrol ;
177+ struct snd_kcontrol_volatile * vd ;
178+ unsigned int index_offset ;
179+ char name [SNDRV_CTL_ELEM_ID_NAME_MAXLEN ];
180+
181+ if (component -> name_prefix )
182+ snprintf (name , SNDRV_CTL_ELEM_ID_NAME_MAXLEN , "%s %s" ,
183+ component -> name_prefix , ctl_name );
184+ else
185+ snprintf (name , SNDRV_CTL_ELEM_ID_NAME_MAXLEN , "%s" , ctl_name );
186+
187+ kcontrol = snd_soc_card_get_kcontrol (component -> card , name );
188+ if (!kcontrol ) {
189+ dev_err (component -> dev , "Can't find kcontrol %s\n" , name );
190+ return - EINVAL ;
191+ }
192+
193+ index_offset = snd_ctl_get_ioff (kcontrol , & kcontrol -> id );
194+ vd = & kcontrol -> vd [index_offset ];
195+ if (active )
196+ vd -> access |= SNDRV_CTL_ELEM_ACCESS_WRITE ;
197+ else
198+ vd -> access &= ~SNDRV_CTL_ELEM_ACCESS_WRITE ;
199+
200+ snd_ctl_notify (card , SNDRV_CTL_EVENT_MASK_INFO , & kcontrol -> id );
201+
202+ return 0 ;
203+ }
204+
205+ static int cs35l45_amplifier_mode_get (struct snd_kcontrol * kcontrol ,
206+ struct snd_ctl_elem_value * ucontrol )
207+ {
208+ struct snd_soc_component * component =
209+ snd_soc_kcontrol_component (kcontrol );
210+ struct cs35l45_private * cs35l45 =
211+ snd_soc_component_get_drvdata (component );
212+
213+ ucontrol -> value .integer .value [0 ] = cs35l45 -> amplifier_mode ;
214+
215+ return 0 ;
216+ }
217+
218+ static int cs35l45_amplifier_mode_put (struct snd_kcontrol * kcontrol ,
219+ struct snd_ctl_elem_value * ucontrol )
220+ {
221+ struct snd_soc_component * component =
222+ snd_soc_kcontrol_component (kcontrol );
223+ struct cs35l45_private * cs35l45 =
224+ snd_soc_component_get_drvdata (component );
225+ struct snd_soc_dapm_context * dapm =
226+ snd_soc_component_get_dapm (component );
227+ unsigned int amp_state ;
228+ int ret ;
229+
230+ if ((ucontrol -> value .integer .value [0 ] == cs35l45 -> amplifier_mode ) ||
231+ (ucontrol -> value .integer .value [0 ] > AMP_MODE_RCV ))
232+ return 0 ;
233+
234+ snd_soc_dapm_mutex_lock (dapm );
235+
236+ ret = regmap_read (cs35l45 -> regmap , CS35L45_BLOCK_ENABLES , & amp_state );
237+ if (ret < 0 ) {
238+ dev_err (cs35l45 -> dev , "Failed to read AMP state: %d\n" , ret );
239+ snd_soc_dapm_mutex_unlock (dapm );
240+ return ret ;
241+ }
242+
243+ regmap_clear_bits (cs35l45 -> regmap , CS35L45_BLOCK_ENABLES ,
244+ CS35L45_AMP_EN_MASK );
245+ snd_soc_component_disable_pin_unlocked (component , "SPK" );
246+ snd_soc_dapm_sync_unlocked (dapm );
247+
248+ if (ucontrol -> value .integer .value [0 ] == AMP_MODE_SPK ) {
249+ regmap_clear_bits (cs35l45 -> regmap , CS35L45_BLOCK_ENABLES ,
250+ CS35L45_RCV_EN_MASK );
251+
252+ regmap_update_bits (cs35l45 -> regmap , CS35L45_BLOCK_ENABLES ,
253+ CS35L45_BST_EN_MASK ,
254+ CS35L45_BST_ENABLE << CS35L45_BST_EN_SHIFT );
255+
256+ regmap_update_bits (cs35l45 -> regmap , CS35L45_HVLV_CONFIG ,
257+ CS35L45_HVLV_MODE_MASK ,
258+ CS35L45_HVLV_OPERATION <<
259+ CS35L45_HVLV_MODE_SHIFT );
260+
261+ ret = cs35l45_activate_ctl (component , "Analog PCM Volume" , true);
262+ if (ret < 0 )
263+ dev_err (cs35l45 -> dev ,
264+ "Unable to deactivate ctl (%d)\n" , ret );
265+
266+ } else /* AMP_MODE_RCV */ {
267+ regmap_set_bits (cs35l45 -> regmap , CS35L45_BLOCK_ENABLES ,
268+ CS35L45_RCV_EN_MASK );
269+
270+ regmap_update_bits (cs35l45 -> regmap , CS35L45_BLOCK_ENABLES ,
271+ CS35L45_BST_EN_MASK ,
272+ CS35L45_BST_DISABLE_FET_OFF <<
273+ CS35L45_BST_EN_SHIFT );
274+
275+ regmap_update_bits (cs35l45 -> regmap , CS35L45_HVLV_CONFIG ,
276+ CS35L45_HVLV_MODE_MASK ,
277+ CS35L45_FORCE_LV_OPERATION <<
278+ CS35L45_HVLV_MODE_SHIFT );
279+
280+ regmap_clear_bits (cs35l45 -> regmap ,
281+ CS35L45_BLOCK_ENABLES2 ,
282+ CS35L45_AMP_DRE_EN_MASK );
283+
284+ regmap_update_bits (cs35l45 -> regmap , CS35L45_AMP_GAIN ,
285+ CS35L45_AMP_GAIN_PCM_MASK ,
286+ CS35L45_AMP_GAIN_PCM_13DBV <<
287+ CS35L45_AMP_GAIN_PCM_SHIFT );
288+
289+ ret = cs35l45_activate_ctl (component , "Analog PCM Volume" , false);
290+ if (ret < 0 )
291+ dev_err (cs35l45 -> dev ,
292+ "Unable to deactivate ctl (%d)\n" , ret );
293+ }
294+
295+ if (amp_state & CS35L45_AMP_EN_MASK )
296+ regmap_set_bits (cs35l45 -> regmap , CS35L45_BLOCK_ENABLES ,
297+ CS35L45_AMP_EN_MASK );
298+
299+ snd_soc_component_enable_pin_unlocked (component , "SPK" );
300+ snd_soc_dapm_sync_unlocked (dapm );
301+ snd_soc_dapm_mutex_unlock (dapm );
302+
303+ cs35l45 -> amplifier_mode = ucontrol -> value .integer .value [0 ];
304+
305+ return 1 ;
306+ }
307+
172308static const char * const cs35l45_asp_tx_txt [] = {
173309 "Zero" , "ASP_RX1" , "ASP_RX2" ,
174310 "VMON" , "IMON" , "ERR_VOL" ,
@@ -432,9 +568,19 @@ static const struct snd_soc_dapm_route cs35l45_dapm_routes[] = {
432568 { "SPK" , NULL , "AMP" },
433569};
434570
571+ static const char * const amplifier_mode_texts [] = {"SPK" , "RCV" };
572+ static SOC_ENUM_SINGLE_DECL (amplifier_mode_enum , SND_SOC_NOPM , 0 ,
573+ amplifier_mode_texts ) ;
574+ static DECLARE_TLV_DB_SCALE (amp_gain_tlv , 1000 , 300 , 0 ) ;
435575static const DECLARE_TLV_DB_SCALE (cs35l45_dig_pcm_vol_tlv , -10225 , 25 , true) ;
436576
437577static const struct snd_kcontrol_new cs35l45_controls [] = {
578+ SOC_ENUM_EXT ("Amplifier Mode" , amplifier_mode_enum ,
579+ cs35l45_amplifier_mode_get , cs35l45_amplifier_mode_put ),
580+ SOC_SINGLE_TLV ("Analog PCM Volume" , CS35L45_AMP_GAIN ,
581+ CS35L45_AMP_GAIN_PCM_SHIFT ,
582+ CS35L45_AMP_GAIN_PCM_MASK >> CS35L45_AMP_GAIN_PCM_SHIFT ,
583+ 0 , amp_gain_tlv ),
438584 /* Ignore bit 0: it is beyond the resolution of TLV_DB_SCALE */
439585 SOC_SINGLE_S_TLV ("Digital PCM Volume" ,
440586 CS35L45_AMP_PCM_CONTROL ,
@@ -1104,6 +1250,8 @@ static int cs35l45_initialize(struct cs35l45_private *cs35l45)
11041250 if (ret < 0 )
11051251 return ret ;
11061252
1253+ cs35l45 -> amplifier_mode = AMP_MODE_SPK ;
1254+
11071255 return 0 ;
11081256}
11091257
0 commit comments