@@ -201,6 +201,102 @@ static int sof_ipc4_volume_get(struct snd_sof_control *scontrol,
201201 return 0 ;
202202}
203203
204+ static int
205+ sof_ipc4_set_generic_control_data (struct snd_sof_dev * sdev ,
206+ struct snd_sof_widget * swidget ,
207+ struct snd_sof_control * scontrol , bool lock )
208+ {
209+ struct sof_ipc4_control_data * cdata = scontrol -> ipc_control_data ;
210+ struct sof_ipc4_control_msg_payload * data ;
211+ struct sof_ipc4_msg * msg = & cdata -> msg ;
212+ size_t data_size ;
213+ unsigned int i ;
214+ int ret ;
215+
216+ data_size = struct_size (data , chanv , scontrol -> num_channels );
217+ data = kzalloc (data_size , GFP_KERNEL );
218+ if (!data )
219+ return - ENOMEM ;
220+
221+ data -> id = cdata -> index ;
222+ data -> num_elems = scontrol -> num_channels ;
223+ for (i = 0 ; i < scontrol -> num_channels ; i ++ ) {
224+ data -> chanv [i ].channel = cdata -> chanv [i ].channel ;
225+ data -> chanv [i ].value = cdata -> chanv [i ].value ;
226+ }
227+
228+ msg -> data_ptr = data ;
229+ msg -> data_size = data_size ;
230+
231+ ret = sof_ipc4_set_get_kcontrol_data (scontrol , true, lock );
232+ msg -> data_ptr = NULL ;
233+ msg -> data_size = 0 ;
234+ if (ret < 0 )
235+ dev_err (sdev -> dev , "Failed to set control update for %s\n" ,
236+ scontrol -> name );
237+
238+ kfree (data );
239+
240+ return ret ;
241+ }
242+
243+ static bool sof_ipc4_switch_put (struct snd_sof_control * scontrol ,
244+ struct snd_ctl_elem_value * ucontrol )
245+ {
246+ struct sof_ipc4_control_data * cdata = scontrol -> ipc_control_data ;
247+ struct snd_soc_component * scomp = scontrol -> scomp ;
248+ struct snd_sof_dev * sdev = snd_soc_component_get_drvdata (scomp );
249+ struct snd_sof_widget * swidget ;
250+ bool widget_found = false;
251+ bool change = false;
252+ unsigned int i ;
253+ u32 value ;
254+ int ret ;
255+
256+ /* update each channel */
257+ for (i = 0 ; i < scontrol -> num_channels ; i ++ ) {
258+ value = ucontrol -> value .integer .value [i ];
259+ change = change || (value != cdata -> chanv [i ].value );
260+ cdata -> chanv [i ].channel = i ;
261+ cdata -> chanv [i ].value = value ;
262+ }
263+
264+ if (!pm_runtime_active (scomp -> dev ))
265+ return change ;
266+
267+ /* find widget associated with the control */
268+ list_for_each_entry (swidget , & sdev -> widget_list , list ) {
269+ if (swidget -> comp_id == scontrol -> comp_id ) {
270+ widget_found = true;
271+ break ;
272+ }
273+ }
274+
275+ if (!widget_found ) {
276+ dev_err (scomp -> dev , "Failed to find widget for kcontrol %s\n" , scontrol -> name );
277+ return false;
278+ }
279+
280+ ret = sof_ipc4_set_generic_control_data (sdev , swidget , scontrol , true);
281+ if (ret < 0 )
282+ return false;
283+
284+ return change ;
285+ }
286+
287+ static int sof_ipc4_switch_get (struct snd_sof_control * scontrol ,
288+ struct snd_ctl_elem_value * ucontrol )
289+ {
290+ struct sof_ipc4_control_data * cdata = scontrol -> ipc_control_data ;
291+ unsigned int i ;
292+
293+ /* read back each channel */
294+ for (i = 0 ; i < scontrol -> num_channels ; i ++ )
295+ ucontrol -> value .integer .value [i ] = cdata -> chanv [i ].value ;
296+
297+ return 0 ;
298+ }
299+
204300static int sof_ipc4_set_get_bytes_data (struct snd_sof_dev * sdev ,
205301 struct snd_sof_control * scontrol ,
206302 bool set , bool lock )
@@ -438,6 +534,16 @@ static int sof_ipc4_bytes_ext_volatile_get(struct snd_sof_control *scontrol,
438534 return _sof_ipc4_bytes_ext_get (scontrol , binary_data , size , true);
439535}
440536
537+ static int
538+ sof_ipc4_volsw_setup (struct snd_sof_dev * sdev , struct snd_sof_widget * swidget ,
539+ struct snd_sof_control * scontrol )
540+ {
541+ if (scontrol -> max == 1 )
542+ return sof_ipc4_set_generic_control_data (sdev , swidget , scontrol , false);
543+
544+ return sof_ipc4_set_volume_data (sdev , swidget , scontrol , false);
545+ }
546+
441547/* set up all controls for the widget */
442548static int sof_ipc4_widget_kcontrol_setup (struct snd_sof_dev * sdev , struct snd_sof_widget * swidget )
443549{
@@ -450,8 +556,7 @@ static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_s
450556 case SND_SOC_TPLG_CTL_VOLSW :
451557 case SND_SOC_TPLG_CTL_VOLSW_SX :
452558 case SND_SOC_TPLG_CTL_VOLSW_XR_SX :
453- ret = sof_ipc4_set_volume_data (sdev , swidget ,
454- scontrol , false);
559+ ret = sof_ipc4_volsw_setup (sdev , swidget , scontrol );
455560 break ;
456561 case SND_SOC_TPLG_CTL_BYTES :
457562 ret = sof_ipc4_set_get_bytes_data (sdev , scontrol ,
@@ -498,6 +603,8 @@ sof_ipc4_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_I
498603const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = {
499604 .volume_put = sof_ipc4_volume_put ,
500605 .volume_get = sof_ipc4_volume_get ,
606+ .switch_put = sof_ipc4_switch_put ,
607+ .switch_get = sof_ipc4_switch_get ,
501608 .bytes_put = sof_ipc4_bytes_put ,
502609 .bytes_get = sof_ipc4_bytes_get ,
503610 .bytes_ext_put = sof_ipc4_bytes_ext_put ,
0 commit comments