control.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. //
  3. // Copyright(c) 2021-2022 Intel Corporation
  4. //
  5. // Authors: Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
  6. // Cezary Rojewski <cezary.rojewski@intel.com>
  7. //
  8. #include <sound/soc.h>
  9. #include "avs.h"
  10. #include "control.h"
  11. #include "messages.h"
  12. #include "path.h"
  13. static struct avs_dev *avs_get_kcontrol_adev(struct snd_kcontrol *kcontrol)
  14. {
  15. struct snd_soc_dapm_widget *w;
  16. w = snd_soc_dapm_kcontrol_widget(kcontrol);
  17. return to_avs_dev(w->dapm->component->dev);
  18. }
  19. static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 id)
  20. {
  21. struct avs_path *path;
  22. struct avs_path_pipeline *ppl;
  23. struct avs_path_module *mod;
  24. spin_lock(&adev->path_list_lock);
  25. list_for_each_entry(path, &adev->path_list, node) {
  26. list_for_each_entry(ppl, &path->ppl_list, node) {
  27. list_for_each_entry(mod, &ppl->mod_list, node) {
  28. if (guid_equal(&mod->template->cfg_ext->type, &AVS_PEAKVOL_MOD_UUID)
  29. && mod->template->ctl_id == id) {
  30. spin_unlock(&adev->path_list_lock);
  31. return mod;
  32. }
  33. }
  34. }
  35. }
  36. spin_unlock(&adev->path_list_lock);
  37. return NULL;
  38. }
  39. int avs_control_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  40. {
  41. struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
  42. struct avs_control_data *ctl_data = (struct avs_control_data *)mc->dobj.private;
  43. struct avs_dev *adev = avs_get_kcontrol_adev(kcontrol);
  44. struct avs_volume_cfg *dspvols = NULL;
  45. struct avs_path_module *active_module;
  46. size_t num_dspvols;
  47. int ret = 0;
  48. /* prevent access to modules while path is being constructed */
  49. mutex_lock(&adev->path_mutex);
  50. active_module = avs_get_volume_module(adev, ctl_data->id);
  51. if (active_module) {
  52. ret = avs_ipc_peakvol_get_volume(adev, active_module->module_id,
  53. active_module->instance_id, &dspvols,
  54. &num_dspvols);
  55. if (!ret)
  56. ucontrol->value.integer.value[0] = dspvols[0].target_volume;
  57. ret = AVS_IPC_RET(ret);
  58. kfree(dspvols);
  59. } else {
  60. ucontrol->value.integer.value[0] = ctl_data->volume;
  61. }
  62. mutex_unlock(&adev->path_mutex);
  63. return ret;
  64. }
  65. int avs_control_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  66. {
  67. struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
  68. struct avs_control_data *ctl_data = (struct avs_control_data *)mc->dobj.private;
  69. struct avs_dev *adev = avs_get_kcontrol_adev(kcontrol);
  70. long *volume = &ctl_data->volume;
  71. struct avs_path_module *active_module;
  72. struct avs_volume_cfg dspvol = {0};
  73. long ctlvol = ucontrol->value.integer.value[0];
  74. int ret = 0, changed = 0;
  75. if (ctlvol < 0 || ctlvol > mc->max)
  76. return -EINVAL;
  77. /* prevent access to modules while path is being constructed */
  78. mutex_lock(&adev->path_mutex);
  79. if (*volume != ctlvol) {
  80. *volume = ctlvol;
  81. changed = 1;
  82. }
  83. active_module = avs_get_volume_module(adev, ctl_data->id);
  84. if (active_module) {
  85. dspvol.channel_id = AVS_ALL_CHANNELS_MASK;
  86. dspvol.target_volume = *volume;
  87. ret = avs_ipc_peakvol_set_volume(adev, active_module->module_id,
  88. active_module->instance_id, &dspvol);
  89. ret = AVS_IPC_RET(ret);
  90. }
  91. mutex_unlock(&adev->path_mutex);
  92. return ret ? ret : changed;
  93. }