2020-05-01 09:58:50 -05:00
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2019-04-12 11:05:07 -05:00
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
//
// Copyright(c) 2018 Intel Corporation. All rights reserved.
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
/* Mixer Controls */
# include <linux/pm_runtime.h>
2019-10-08 11:44:43 -05:00
# include <linux/leds.h>
2019-04-12 11:05:07 -05:00
# include "sof-priv.h"
2019-12-04 15:15:51 -06:00
# include "sof-audio.h"
2019-04-12 11:05:07 -05:00
int snd_sof_volume_get ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2022-03-17 10:50:31 -07:00
struct soc_mixer_control * sm = ( struct soc_mixer_control * ) kcontrol - > private_value ;
2019-04-12 11:05:07 -05:00
struct snd_sof_control * scontrol = sm - > dobj . private ;
2022-03-17 10:50:31 -07:00
struct snd_soc_component * scomp = scontrol - > scomp ;
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata ( scomp ) ;
const struct sof_ipc_tplg_ops * tplg_ops = sdev - > ipc - > ops - > tplg ;
2021-09-03 14:40:18 +03:00
2022-03-17 10:50:31 -07:00
if ( tplg_ops - > control - > volume_get )
return tplg_ops - > control - > volume_get ( scontrol , ucontrol ) ;
2019-04-12 11:05:07 -05:00
return 0 ;
}
int snd_sof_volume_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2022-03-17 10:50:31 -07:00
struct soc_mixer_control * sm = ( struct soc_mixer_control * ) kcontrol - > private_value ;
2019-04-12 11:05:07 -05:00
struct snd_sof_control * scontrol = sm - > dobj . private ;
2019-12-04 15:15:51 -06:00
struct snd_soc_component * scomp = scontrol - > scomp ;
2022-03-17 10:50:31 -07:00
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata ( scomp ) ;
const struct sof_ipc_tplg_ops * tplg_ops = sdev - > ipc - > ops - > tplg ;
if ( tplg_ops - > control - > volume_put )
return tplg_ops - > control - > volume_put ( scontrol , ucontrol ) ;
2019-04-12 11:05:07 -05:00
2022-03-17 10:50:31 -07:00
return false ;
2019-04-12 11:05:07 -05:00
}
2020-11-11 19:31:05 +02:00
int snd_sof_volume_info ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
{
struct soc_mixer_control * sm = ( struct soc_mixer_control * ) kcontrol - > private_value ;
struct snd_sof_control * scontrol = sm - > dobj . private ;
unsigned int channels = scontrol - > num_channels ;
int platform_max ;
if ( ! sm - > platform_max )
sm - > platform_max = sm - > max ;
platform_max = sm - > platform_max ;
if ( platform_max = = 1 & & ! strstr ( kcontrol - > id . name , " Volume " ) )
uinfo - > type = SNDRV_CTL_ELEM_TYPE_BOOLEAN ;
else
uinfo - > type = SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = channels ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = platform_max - sm - > min ;
return 0 ;
}
2019-04-12 11:05:07 -05:00
int snd_sof_switch_get ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2022-03-17 10:50:32 -07:00
struct soc_mixer_control * sm = ( struct soc_mixer_control * ) kcontrol - > private_value ;
2019-04-12 11:05:07 -05:00
struct snd_sof_control * scontrol = sm - > dobj . private ;
2022-03-17 10:50:32 -07:00
struct snd_soc_component * scomp = scontrol - > scomp ;
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata ( scomp ) ;
const struct sof_ipc_tplg_ops * tplg_ops = sdev - > ipc - > ops - > tplg ;
2021-09-03 14:40:18 +03:00
2022-03-17 10:50:32 -07:00
if ( tplg_ops - > control - > switch_get )
return tplg_ops - > control - > switch_get ( scontrol , ucontrol ) ;
2019-04-12 11:05:07 -05:00
return 0 ;
}
int snd_sof_switch_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2022-03-17 10:50:32 -07:00
struct soc_mixer_control * sm = ( struct soc_mixer_control * ) kcontrol - > private_value ;
2019-04-12 11:05:07 -05:00
struct snd_sof_control * scontrol = sm - > dobj . private ;
2019-12-04 15:15:51 -06:00
struct snd_soc_component * scomp = scontrol - > scomp ;
2022-03-17 10:50:32 -07:00
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata ( scomp ) ;
const struct sof_ipc_tplg_ops * tplg_ops = sdev - > ipc - > ops - > tplg ;
2019-04-12 11:05:07 -05:00
2022-03-17 10:50:32 -07:00
if ( tplg_ops - > control - > switch_put )
return tplg_ops - > control - > switch_put ( scontrol , ucontrol ) ;
2019-06-12 12:01:48 -05:00
2022-03-17 10:50:32 -07:00
return false ;
2019-04-12 11:05:07 -05:00
}
int snd_sof_enum_get ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2022-03-17 10:50:33 -07:00
struct soc_enum * se = ( struct soc_enum * ) kcontrol - > private_value ;
2019-04-12 11:05:07 -05:00
struct snd_sof_control * scontrol = se - > dobj . private ;
2022-03-17 10:50:33 -07:00
struct snd_soc_component * scomp = scontrol - > scomp ;
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata ( scomp ) ;
const struct sof_ipc_tplg_ops * tplg_ops = sdev - > ipc - > ops - > tplg ;
2021-09-03 14:40:18 +03:00
2022-03-17 10:50:33 -07:00
if ( tplg_ops - > control - > enum_get )
return tplg_ops - > control - > enum_get ( scontrol , ucontrol ) ;
2019-04-12 11:05:07 -05:00
return 0 ;
}
int snd_sof_enum_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2022-03-17 10:50:33 -07:00
struct soc_enum * se = ( struct soc_enum * ) kcontrol - > private_value ;
2019-04-12 11:05:07 -05:00
struct snd_sof_control * scontrol = se - > dobj . private ;
2019-12-04 15:15:51 -06:00
struct snd_soc_component * scomp = scontrol - > scomp ;
2022-03-17 10:50:33 -07:00
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata ( scomp ) ;
const struct sof_ipc_tplg_ops * tplg_ops = sdev - > ipc - > ops - > tplg ;
2019-04-12 11:05:07 -05:00
2022-03-17 10:50:33 -07:00
if ( tplg_ops - > control - > enum_put )
return tplg_ops - > control - > enum_put ( scontrol , ucontrol ) ;
2019-06-12 12:01:48 -05:00
2022-03-17 10:50:33 -07:00
return false ;
2019-04-12 11:05:07 -05:00
}
int snd_sof_bytes_get ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2022-03-17 10:50:34 -07:00
struct soc_bytes_ext * be = ( struct soc_bytes_ext * ) kcontrol - > private_value ;
2019-04-12 11:05:07 -05:00
struct snd_sof_control * scontrol = be - > dobj . private ;
2019-12-04 15:15:51 -06:00
struct snd_soc_component * scomp = scontrol - > scomp ;
2022-03-17 10:50:34 -07:00
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata ( scomp ) ;
const struct sof_ipc_tplg_ops * tplg_ops = sdev - > ipc - > ops - > tplg ;
2020-09-17 13:56:32 +03:00
2022-03-17 10:50:34 -07:00
if ( tplg_ops - > control - > bytes_get )
return tplg_ops - > control - > bytes_get ( scontrol , ucontrol ) ;
2019-04-12 11:05:07 -05:00
2020-09-17 13:56:30 +03:00
return 0 ;
2019-04-12 11:05:07 -05:00
}
int snd_sof_bytes_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2022-03-17 10:50:34 -07:00
struct soc_bytes_ext * be = ( struct soc_bytes_ext * ) kcontrol - > private_value ;
2019-04-12 11:05:07 -05:00
struct snd_sof_control * scontrol = be - > dobj . private ;
2019-12-04 15:15:51 -06:00
struct snd_soc_component * scomp = scontrol - > scomp ;
2022-03-17 10:50:34 -07:00
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata ( scomp ) ;
const struct sof_ipc_tplg_ops * tplg_ops = sdev - > ipc - > ops - > tplg ;
2019-04-12 11:05:07 -05:00
2022-03-17 10:50:34 -07:00
if ( tplg_ops - > control - > bytes_put )
return tplg_ops - > control - > bytes_put ( scontrol , ucontrol ) ;
2019-06-12 12:01:48 -05:00
return 0 ;
2019-04-12 11:05:07 -05:00
}
int snd_sof_bytes_ext_put ( struct snd_kcontrol * kcontrol ,
const unsigned int __user * binary_data ,
unsigned int size )
{
2022-03-17 10:50:35 -07:00
struct soc_bytes_ext * be = ( struct soc_bytes_ext * ) kcontrol - > private_value ;
2019-04-12 11:05:07 -05:00
struct snd_sof_control * scontrol = be - > dobj . private ;
2019-12-04 15:15:51 -06:00
struct snd_soc_component * scomp = scontrol - > scomp ;
2022-03-17 10:50:35 -07:00
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata ( scomp ) ;
const struct sof_ipc_tplg_ops * tplg_ops = sdev - > ipc - > ops - > tplg ;
2019-04-12 11:05:07 -05:00
2020-09-21 14:08:12 +03:00
/* make sure we have at least a header */
if ( size < sizeof ( struct snd_ctl_tlv ) )
return - EINVAL ;
2022-03-17 10:50:35 -07:00
if ( tplg_ops - > control - > bytes_ext_put )
return tplg_ops - > control - > bytes_ext_put ( scontrol , binary_data , size ) ;
2019-04-12 11:05:07 -05:00
2019-06-12 12:01:48 -05:00
return 0 ;
2019-04-12 11:05:07 -05:00
}
2020-09-08 12:28:25 +03:00
int snd_sof_bytes_ext_volatile_get ( struct snd_kcontrol * kcontrol , unsigned int __user * binary_data ,
unsigned int size )
{
struct soc_bytes_ext * be = ( struct soc_bytes_ext * ) kcontrol - > private_value ;
struct snd_sof_control * scontrol = be - > dobj . private ;
struct snd_soc_component * scomp = scontrol - > scomp ;
2022-03-17 10:50:35 -07:00
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata ( scomp ) ;
const struct sof_ipc_tplg_ops * tplg_ops = sdev - > ipc - > ops - > tplg ;
int ret , err ;
2020-09-21 14:08:11 +03:00
2022-04-26 13:41:03 -05:00
ret = pm_runtime_resume_and_get ( scomp - > dev ) ;
2020-09-17 13:56:29 +03:00
if ( ret < 0 & & ret ! = - EACCES ) {
2022-03-17 10:50:35 -07:00
dev_err_ratelimited ( scomp - > dev , " %s: failed to resume %d \n " , __func__ , ret ) ;
2020-09-08 12:28:25 +03:00
return ret ;
}
2022-03-17 10:50:35 -07:00
if ( tplg_ops - > control - > bytes_ext_volatile_get )
ret = tplg_ops - > control - > bytes_ext_volatile_get ( scontrol , binary_data , size ) ;
2020-09-08 12:28:25 +03:00
pm_runtime_mark_last_busy ( scomp - > dev ) ;
err = pm_runtime_put_autosuspend ( scomp - > dev ) ;
if ( err < 0 )
2022-03-17 10:50:35 -07:00
dev_err_ratelimited ( scomp - > dev , " %s: failed to idle %d \n " , __func__ , err ) ;
2020-09-08 12:28:25 +03:00
return ret ;
}
2019-04-12 11:05:07 -05:00
int snd_sof_bytes_ext_get ( struct snd_kcontrol * kcontrol ,
unsigned int __user * binary_data ,
unsigned int size )
{
2022-03-17 10:50:35 -07:00
struct soc_bytes_ext * be = ( struct soc_bytes_ext * ) kcontrol - > private_value ;
2019-04-12 11:05:07 -05:00
struct snd_sof_control * scontrol = be - > dobj . private ;
2019-12-04 15:15:51 -06:00
struct snd_soc_component * scomp = scontrol - > scomp ;
2022-03-17 10:50:35 -07:00
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata ( scomp ) ;
const struct sof_ipc_tplg_ops * tplg_ops = sdev - > ipc - > ops - > tplg ;
2019-04-12 11:05:07 -05:00
2022-03-17 10:50:35 -07:00
if ( tplg_ops - > control - > bytes_ext_get )
return tplg_ops - > control - > bytes_ext_get ( scontrol , binary_data , size ) ;
2019-04-12 11:05:07 -05:00
2020-09-17 13:56:30 +03:00
return 0 ;
2019-04-12 11:05:07 -05:00
}