|
16 | 16 | #include <linux/minmax.h> |
17 | 17 | #include <linux/module.h> |
18 | 18 | #include <linux/overflow.h> |
| 19 | +#include <linux/pm_runtime.h> |
19 | 20 | #include <linux/regmap.h> |
20 | 21 | #include <linux/soundwire/sdw_registers.h> |
21 | 22 | #include <linux/string_helpers.h> |
@@ -115,6 +116,41 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun |
115 | 116 | } |
116 | 117 | EXPORT_SYMBOL_NS(sdca_asoc_count_component, "SND_SOC_SDCA"); |
117 | 118 |
|
| 119 | +static int ge_put_enum_double(struct snd_kcontrol *kcontrol, |
| 120 | + struct snd_ctl_elem_value *ucontrol) |
| 121 | +{ |
| 122 | + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol); |
| 123 | + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); |
| 124 | + struct device *dev = component->dev; |
| 125 | + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
| 126 | + unsigned int *item = ucontrol->value.enumerated.item; |
| 127 | + unsigned int reg = e->reg; |
| 128 | + int ret; |
| 129 | + |
| 130 | + reg &= ~SDW_SDCA_CTL_CSEL(0x3F); |
| 131 | + reg |= SDW_SDCA_CTL_CSEL(SDCA_CTL_GE_DETECTED_MODE); |
| 132 | + |
| 133 | + ret = pm_runtime_resume_and_get(dev); |
| 134 | + if (ret < 0) { |
| 135 | + dev_err(dev, "failed to resume writing %s: %d\n", |
| 136 | + kcontrol->id.name, ret); |
| 137 | + return ret; |
| 138 | + } |
| 139 | + |
| 140 | + ret = snd_soc_component_read(component, reg); |
| 141 | + pm_runtime_put(dev); |
| 142 | + if (ret < 0) |
| 143 | + return ret; |
| 144 | + else if (ret <= SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS) |
| 145 | + return -EBUSY; |
| 146 | + |
| 147 | + ret = snd_soc_enum_item_to_val(e, item[0]); |
| 148 | + if (ret <= SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS) |
| 149 | + return -EINVAL; |
| 150 | + |
| 151 | + return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); |
| 152 | +} |
| 153 | + |
118 | 154 | static int entity_early_parse_ge(struct device *dev, |
119 | 155 | struct sdca_function_data *function, |
120 | 156 | struct sdca_entity *entity) |
@@ -191,7 +227,7 @@ static int entity_early_parse_ge(struct device *dev, |
191 | 227 | kctl->name = control_name; |
192 | 228 | kctl->info = snd_soc_info_enum_double; |
193 | 229 | kctl->get = snd_soc_dapm_get_enum_double; |
194 | | - kctl->put = snd_soc_dapm_put_enum_double; |
| 230 | + kctl->put = ge_put_enum_double; |
195 | 231 | kctl->private_value = (unsigned long)soc_enum; |
196 | 232 |
|
197 | 233 | entity->ge.kctl = kctl; |
@@ -792,6 +828,48 @@ static int control_limit_kctl(struct device *dev, |
792 | 828 | return 0; |
793 | 829 | } |
794 | 830 |
|
| 831 | +static int volatile_get_volsw(struct snd_kcontrol *kcontrol, |
| 832 | + struct snd_ctl_elem_value *ucontrol) |
| 833 | +{ |
| 834 | + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
| 835 | + struct device *dev = component->dev; |
| 836 | + int ret; |
| 837 | + |
| 838 | + ret = pm_runtime_resume_and_get(dev); |
| 839 | + if (ret < 0) { |
| 840 | + dev_err(dev, "failed to resume reading %s: %d\n", |
| 841 | + kcontrol->id.name, ret); |
| 842 | + return ret; |
| 843 | + } |
| 844 | + |
| 845 | + ret = snd_soc_get_volsw(kcontrol, ucontrol); |
| 846 | + |
| 847 | + pm_runtime_put(dev); |
| 848 | + |
| 849 | + return ret; |
| 850 | +} |
| 851 | + |
| 852 | +static int volatile_put_volsw(struct snd_kcontrol *kcontrol, |
| 853 | + struct snd_ctl_elem_value *ucontrol) |
| 854 | +{ |
| 855 | + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
| 856 | + struct device *dev = component->dev; |
| 857 | + int ret; |
| 858 | + |
| 859 | + ret = pm_runtime_resume_and_get(dev); |
| 860 | + if (ret < 0) { |
| 861 | + dev_err(dev, "failed to resume writing %s: %d\n", |
| 862 | + kcontrol->id.name, ret); |
| 863 | + return ret; |
| 864 | + } |
| 865 | + |
| 866 | + ret = snd_soc_put_volsw(kcontrol, ucontrol); |
| 867 | + |
| 868 | + pm_runtime_put(dev); |
| 869 | + |
| 870 | + return ret; |
| 871 | +} |
| 872 | + |
795 | 873 | static int populate_control(struct device *dev, |
796 | 874 | struct sdca_function_data *function, |
797 | 875 | struct sdca_entity *entity, |
@@ -849,8 +927,13 @@ static int populate_control(struct device *dev, |
849 | 927 | (*kctl)->private_value = (unsigned long)mc; |
850 | 928 | (*kctl)->iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
851 | 929 | (*kctl)->info = snd_soc_info_volsw; |
852 | | - (*kctl)->get = snd_soc_get_volsw; |
853 | | - (*kctl)->put = snd_soc_put_volsw; |
| 930 | + if (control->is_volatile) { |
| 931 | + (*kctl)->get = volatile_get_volsw; |
| 932 | + (*kctl)->put = volatile_put_volsw; |
| 933 | + } else { |
| 934 | + (*kctl)->get = snd_soc_get_volsw; |
| 935 | + (*kctl)->put = snd_soc_put_volsw; |
| 936 | + } |
854 | 937 |
|
855 | 938 | if (readonly_control(control)) |
856 | 939 | (*kctl)->access = SNDRV_CTL_ELEM_ACCESS_READ; |
|
0 commit comments