2022-12-14 19:54:58 +01:00
// SPDX-License-Identifier: GPL-2.0-only
//
// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
//
// Authors: Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
// Cezary Rojewski <cezary.rojewski@intel.com>
//
# include <sound/soc.h>
# include "avs.h"
# include "control.h"
# include "messages.h"
# include "path.h"
static struct avs_dev * avs_get_kcontrol_adev ( struct snd_kcontrol * kcontrol )
{
struct snd_soc_dapm_widget * w ;
w = snd_soc_dapm_kcontrol_widget ( kcontrol ) ;
return to_avs_dev ( w - > dapm - > component - > dev ) ;
}
2023-05-19 22:17:05 +02:00
static struct avs_path_module * avs_get_volume_module ( struct avs_dev * adev , u32 id )
2022-12-14 19:54:58 +01:00
{
2022-12-14 19:54:59 +01:00
struct avs_path * path ;
struct avs_path_pipeline * ppl ;
struct avs_path_module * mod ;
2023-05-19 22:17:05 +02:00
spin_lock ( & adev - > path_list_lock ) ;
list_for_each_entry ( path , & adev - > path_list , node ) {
list_for_each_entry ( ppl , & path - > ppl_list , node ) {
list_for_each_entry ( mod , & ppl - > mod_list , node ) {
if ( guid_equal ( & mod - > template - > cfg_ext - > type , & AVS_PEAKVOL_MOD_UUID )
& & mod - > template - > ctl_id = = id ) {
spin_unlock ( & adev - > path_list_lock ) ;
2022-12-14 19:54:59 +01:00
return mod ;
2023-05-19 22:17:05 +02:00
}
}
}
}
spin_unlock ( & adev - > path_list_lock ) ;
2022-12-14 19:54:59 +01:00
2022-12-14 19:54:58 +01:00
return NULL ;
}
int avs_control_volume_get ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
{
struct soc_mixer_control * mc = ( struct soc_mixer_control * ) kcontrol - > private_value ;
struct avs_control_data * ctl_data = ( struct avs_control_data * ) mc - > dobj . private ;
struct avs_dev * adev = avs_get_kcontrol_adev ( kcontrol ) ;
struct avs_volume_cfg * dspvols = NULL ;
struct avs_path_module * active_module ;
size_t num_dspvols ;
int ret = 0 ;
/* prevent access to modules while path is being constructed */
mutex_lock ( & adev - > path_mutex ) ;
2023-05-19 22:17:05 +02:00
active_module = avs_get_volume_module ( adev , ctl_data - > id ) ;
2022-12-14 19:54:58 +01:00
if ( active_module ) {
ret = avs_ipc_peakvol_get_volume ( adev , active_module - > module_id ,
active_module - > instance_id , & dspvols ,
& num_dspvols ) ;
if ( ! ret )
ucontrol - > value . integer . value [ 0 ] = dspvols [ 0 ] . target_volume ;
ret = AVS_IPC_RET ( ret ) ;
kfree ( dspvols ) ;
} else {
ucontrol - > value . integer . value [ 0 ] = ctl_data - > volume ;
}
mutex_unlock ( & adev - > path_mutex ) ;
return ret ;
}
int avs_control_volume_put ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
{
struct soc_mixer_control * mc = ( struct soc_mixer_control * ) kcontrol - > private_value ;
struct avs_control_data * ctl_data = ( struct avs_control_data * ) mc - > dobj . private ;
struct avs_dev * adev = avs_get_kcontrol_adev ( kcontrol ) ;
long * volume = & ctl_data - > volume ;
struct avs_path_module * active_module ;
struct avs_volume_cfg dspvol = { 0 } ;
long ctlvol = ucontrol - > value . integer . value [ 0 ] ;
int ret = 0 , changed = 0 ;
if ( ctlvol < 0 | | ctlvol > mc - > max )
return - EINVAL ;
/* prevent access to modules while path is being constructed */
mutex_lock ( & adev - > path_mutex ) ;
if ( * volume ! = ctlvol ) {
* volume = ctlvol ;
changed = 1 ;
}
2023-05-19 22:17:05 +02:00
active_module = avs_get_volume_module ( adev , ctl_data - > id ) ;
2022-12-14 19:54:58 +01:00
if ( active_module ) {
dspvol . channel_id = AVS_ALL_CHANNELS_MASK ;
dspvol . target_volume = * volume ;
ret = avs_ipc_peakvol_set_volume ( adev , active_module - > module_id ,
active_module - > instance_id , & dspvol ) ;
ret = AVS_IPC_RET ( ret ) ;
}
mutex_unlock ( & adev - > path_mutex ) ;
return ret ? ret : changed ;
}