aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/soc-dapm.h15
-rw-r--r--include/sound/soc.h30
-rw-r--r--sound/soc/soc-core.c107
-rw-r--r--sound/soc/soc-dapm.c197
4 files changed, 346 insertions, 3 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 7ee2f70ca42e..4af1083e3287 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -85,6 +85,10 @@
85#define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \ 85#define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
86{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \ 86{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
87 .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1} 87 .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
88#define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
89{ .id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \
90 .shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
91 .num_kcontrols = 1}
88 92
89/* path domain with event - event handler must return 0 for success */ 93/* path domain with event - event handler must return 0 for success */
90#define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \ 94#define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
@@ -172,6 +176,12 @@
172 .get = snd_soc_dapm_get_enum_double, \ 176 .get = snd_soc_dapm_get_enum_double, \
173 .put = snd_soc_dapm_put_enum_double, \ 177 .put = snd_soc_dapm_put_enum_double, \
174 .private_value = (unsigned long)&xenum } 178 .private_value = (unsigned long)&xenum }
179#define SOC_DAPM_VALUE_ENUM(xname, xenum) \
180{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
181 .info = snd_soc_info_value_enum_double, \
182 .get = snd_soc_dapm_get_value_enum_double, \
183 .put = snd_soc_dapm_put_value_enum_double, \
184 .private_value = (unsigned long)&xenum }
175 185
176/* dapm stream operations */ 186/* dapm stream operations */
177#define SND_SOC_DAPM_STREAM_NOP 0x0 187#define SND_SOC_DAPM_STREAM_NOP 0x0
@@ -214,6 +224,10 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
214 struct snd_ctl_elem_value *ucontrol); 224 struct snd_ctl_elem_value *ucontrol);
215int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, 225int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
216 struct snd_ctl_elem_value *ucontrol); 226 struct snd_ctl_elem_value *ucontrol);
227int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
228 struct snd_ctl_elem_value *ucontrol);
229int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
230 struct snd_ctl_elem_value *ucontrol);
217int snd_soc_dapm_new_control(struct snd_soc_codec *codec, 231int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
218 const struct snd_soc_dapm_widget *widget); 232 const struct snd_soc_dapm_widget *widget);
219int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, 233int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
@@ -247,6 +261,7 @@ enum snd_soc_dapm_type {
247 snd_soc_dapm_input = 0, /* input pin */ 261 snd_soc_dapm_input = 0, /* input pin */
248 snd_soc_dapm_output, /* output pin */ 262 snd_soc_dapm_output, /* output pin */
249 snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */ 263 snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */
264 snd_soc_dapm_value_mux, /* selects 1 analog signal from many inputs */
250 snd_soc_dapm_mixer, /* mixes several analog signals together */ 265 snd_soc_dapm_mixer, /* mixes several analog signals together */
251 snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */ 266 snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */
252 snd_soc_dapm_adc, /* analog to digital converter */ 267 snd_soc_dapm_adc, /* analog to digital converter */
diff --git a/include/sound/soc.h b/include/sound/soc.h
index f86e455d3828..9b930d342116 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -94,11 +94,22 @@
94 SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts) 94 SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts)
95#define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \ 95#define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \
96{ .max = xmax, .texts = xtexts } 96{ .max = xmax, .texts = xtexts }
97#define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xmax, xtexts, xvalues) \
98{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
99 .mask = xmask, .max = xmax, .texts = xtexts, .values = xvalues}
100#define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xmax, xtexts, xvalues) \
101 SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xmax, xtexts, xvalues)
97#define SOC_ENUM(xname, xenum) \ 102#define SOC_ENUM(xname, xenum) \
98{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ 103{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
99 .info = snd_soc_info_enum_double, \ 104 .info = snd_soc_info_enum_double, \
100 .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \ 105 .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \
101 .private_value = (unsigned long)&xenum } 106 .private_value = (unsigned long)&xenum }
107#define SOC_VALUE_ENUM(xname, xenum) \
108{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
109 .info = snd_soc_info_value_enum_double, \
110 .get = snd_soc_get_value_enum_double, \
111 .put = snd_soc_put_value_enum_double, \
112 .private_value = (unsigned long)&xenum }
102#define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\ 113#define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\
103 xhandler_get, xhandler_put) \ 114 xhandler_get, xhandler_put) \
104{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 115{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
@@ -200,6 +211,12 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
200 struct snd_ctl_elem_value *ucontrol); 211 struct snd_ctl_elem_value *ucontrol);
201int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, 212int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
202 struct snd_ctl_elem_value *ucontrol); 213 struct snd_ctl_elem_value *ucontrol);
214int snd_soc_info_value_enum_double(struct snd_kcontrol *kcontrol,
215 struct snd_ctl_elem_info *uinfo);
216int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol,
217 struct snd_ctl_elem_value *ucontrol);
218int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
219 struct snd_ctl_elem_value *ucontrol);
203int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, 220int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
204 struct snd_ctl_elem_info *uinfo); 221 struct snd_ctl_elem_info *uinfo);
205int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, 222int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
@@ -406,6 +423,19 @@ struct soc_enum {
406 void *dapm; 423 void *dapm;
407}; 424};
408 425
426/* semi enumerated kcontrol */
427struct soc_value_enum {
428 unsigned short reg;
429 unsigned short reg2;
430 unsigned char shift_l;
431 unsigned char shift_r;
432 unsigned int max;
433 unsigned int mask;
434 const char **texts;
435 const unsigned int *values;
436 void *dapm;
437};
438
409#include <sound/soc-dai.h> 439#include <sound/soc-dai.h>
410 440
411#endif 441#endif
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index f73c1341437c..6cbe7e82f238 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1585,6 +1585,113 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
1585EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); 1585EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
1586 1586
1587/** 1587/**
1588 * snd_soc_info_value_enum_double - semi enumerated double mixer info callback
1589 * @kcontrol: mixer control
1590 * @uinfo: control element information
1591 *
1592 * Callback to provide information about a double semi enumerated
1593 * mixer control.
1594 *
1595 * Semi enumerated mixer: the enumerated items are referred as values. Can be
1596 * used for handling bitfield coded enumeration for example.
1597 *
1598 * Returns 0 for success.
1599 */
1600int snd_soc_info_value_enum_double(struct snd_kcontrol *kcontrol,
1601 struct snd_ctl_elem_info *uinfo)
1602{
1603 struct soc_value_enum *e = (struct soc_value_enum *)
1604 kcontrol->private_value;
1605
1606 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1607 uinfo->count = e->shift_l == e->shift_r ? 1 : 2;
1608 uinfo->value.enumerated.items = e->max;
1609
1610 if (uinfo->value.enumerated.item > e->max - 1)
1611 uinfo->value.enumerated.item = e->max - 1;
1612 strcpy(uinfo->value.enumerated.name,
1613 e->texts[uinfo->value.enumerated.item]);
1614 return 0;
1615}
1616EXPORT_SYMBOL_GPL(snd_soc_info_value_enum_double);
1617
1618/**
1619 * snd_soc_get_value_enum_double - semi enumerated double mixer get callback
1620 * @kcontrol: mixer control
1621 * @ucontrol: control element information
1622 *
1623 * Callback to get the value of a double semi enumerated mixer.
1624 *
1625 * Semi enumerated mixer: the enumerated items are referred as values. Can be
1626 * used for handling bitfield coded enumeration for example.
1627 *
1628 * Returns 0 for success.
1629 */
1630int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol,
1631 struct snd_ctl_elem_value *ucontrol)
1632{
1633 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1634 struct soc_value_enum *e = (struct soc_value_enum *)
1635 kcontrol->private_value;
1636 unsigned short reg_val, val, mux;
1637
1638 reg_val = snd_soc_read(codec, e->reg);
1639 val = (reg_val >> e->shift_l) & e->mask;
1640 for (mux = 0; mux < e->max; mux++) {
1641 if (val == e->values[mux])
1642 break;
1643 }
1644 ucontrol->value.enumerated.item[0] = mux;
1645 if (e->shift_l != e->shift_r) {
1646 val = (reg_val >> e->shift_r) & e->mask;
1647 for (mux = 0; mux < e->max; mux++) {
1648 if (val == e->values[mux])
1649 break;
1650 }
1651 ucontrol->value.enumerated.item[1] = mux;
1652 }
1653
1654 return 0;
1655}
1656EXPORT_SYMBOL_GPL(snd_soc_get_value_enum_double);
1657
1658/**
1659 * snd_soc_put_value_enum_double - semi enumerated double mixer put callback
1660 * @kcontrol: mixer control
1661 * @ucontrol: control element information
1662 *
1663 * Callback to set the value of a double semi enumerated mixer.
1664 *
1665 * Semi enumerated mixer: the enumerated items are referred as values. Can be
1666 * used for handling bitfield coded enumeration for example.
1667 *
1668 * Returns 0 for success.
1669 */
1670int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
1671 struct snd_ctl_elem_value *ucontrol)
1672{
1673 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1674 struct soc_value_enum *e = (struct soc_value_enum *)
1675 kcontrol->private_value;
1676 unsigned short val;
1677 unsigned short mask;
1678
1679 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1680 return -EINVAL;
1681 val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l;
1682 mask = e->mask << e->shift_l;
1683 if (e->shift_l != e->shift_r) {
1684 if (ucontrol->value.enumerated.item[1] > e->max - 1)
1685 return -EINVAL;
1686 val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r;
1687 mask |= e->mask << e->shift_r;
1688 }
1689
1690 return snd_soc_update_bits(codec, e->reg, mask, val);
1691}
1692EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double);
1693
1694/**
1588 * snd_soc_info_enum_ext - external enumerated single mixer info callback 1695 * snd_soc_info_enum_ext - external enumerated single mixer info callback
1589 * @kcontrol: mixer control 1696 * @kcontrol: mixer control
1590 * @uinfo: control element information 1697 * @uinfo: control element information
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 6c79ca6df0bf..ad0d801677c1 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -53,13 +53,15 @@
53/* dapm power sequences - make this per codec in the future */ 53/* dapm power sequences - make this per codec in the future */
54static int dapm_up_seq[] = { 54static int dapm_up_seq[] = {
55 snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic, 55 snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic,
56 snd_soc_dapm_mux, snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_pga, 56 snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_dac,
57 snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post 57 snd_soc_dapm_mixer, snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp,
58 snd_soc_dapm_spk, snd_soc_dapm_post
58}; 59};
59static int dapm_down_seq[] = { 60static int dapm_down_seq[] = {
60 snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, 61 snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
61 snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic, 62 snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic,
62 snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_post 63 snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_value_mux,
64 snd_soc_dapm_post
63}; 65};
64 66
65static int dapm_status = 1; 67static int dapm_status = 1;
@@ -134,6 +136,25 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
134 } 136 }
135 } 137 }
136 break; 138 break;
139 case snd_soc_dapm_value_mux: {
140 struct soc_value_enum *e = (struct soc_value_enum *)
141 w->kcontrols[i].private_value;
142 int val, item;
143
144 val = snd_soc_read(w->codec, e->reg);
145 val = (val >> e->shift_l) & e->mask;
146 for (item = 0; item < e->max; item++) {
147 if (val == e->values[item])
148 break;
149 }
150
151 p->connect = 0;
152 for (i = 0; i < e->max; i++) {
153 if (!(strcmp(p->name, e->texts[i])) && item == i)
154 p->connect = 1;
155 }
156 }
157 break;
137 /* does not effect routing - always connected */ 158 /* does not effect routing - always connected */
138 case snd_soc_dapm_pga: 159 case snd_soc_dapm_pga:
139 case snd_soc_dapm_output: 160 case snd_soc_dapm_output:
@@ -179,6 +200,30 @@ static int dapm_connect_mux(struct snd_soc_codec *codec,
179 return -ENODEV; 200 return -ENODEV;
180} 201}
181 202
203/* connect value_mux widget to it's interconnecting audio paths */
204static int dapm_connect_value_mux(struct snd_soc_codec *codec,
205 struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
206 struct snd_soc_dapm_path *path, const char *control_name,
207 const struct snd_kcontrol_new *kcontrol)
208{
209 struct soc_value_enum *e = (struct soc_value_enum *)
210 kcontrol->private_value;
211 int i;
212
213 for (i = 0; i < e->max; i++) {
214 if (!(strcmp(control_name, e->texts[i]))) {
215 list_add(&path->list, &codec->dapm_paths);
216 list_add(&path->list_sink, &dest->sources);
217 list_add(&path->list_source, &src->sinks);
218 path->name = (char *)e->texts[i];
219 dapm_set_path_status(dest, path, 0);
220 return 0;
221 }
222 }
223
224 return -ENODEV;
225}
226
182/* connect mixer widget to it's interconnecting audio paths */ 227/* connect mixer widget to it's interconnecting audio paths */
183static int dapm_connect_mixer(struct snd_soc_codec *codec, 228static int dapm_connect_mixer(struct snd_soc_codec *codec,
184 struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, 229 struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
@@ -653,6 +698,7 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
653 case snd_soc_dapm_vmid: 698 case snd_soc_dapm_vmid:
654 continue; 699 continue;
655 case snd_soc_dapm_mux: 700 case snd_soc_dapm_mux:
701 case snd_soc_dapm_value_mux:
656 case snd_soc_dapm_output: 702 case snd_soc_dapm_output:
657 case snd_soc_dapm_input: 703 case snd_soc_dapm_input:
658 case snd_soc_dapm_switch: 704 case snd_soc_dapm_switch:
@@ -728,6 +774,45 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
728 return 0; 774 return 0;
729} 775}
730 776
777/* test and update the power status of a value_mux widget */
778static int dapm_value_mux_update_power(struct snd_soc_dapm_widget *widget,
779 struct snd_kcontrol *kcontrol, int mask,
780 int mux, int val, struct soc_value_enum *e)
781{
782 struct snd_soc_dapm_path *path;
783 int found = 0;
784
785 if (widget->id != snd_soc_dapm_value_mux)
786 return -ENODEV;
787
788 if (!snd_soc_test_bits(widget->codec, e->reg, mask, val))
789 return 0;
790
791 /* find dapm widget path assoc with kcontrol */
792 list_for_each_entry(path, &widget->codec->dapm_paths, list) {
793 if (path->kcontrol != kcontrol)
794 continue;
795
796 if (!path->name || !e->texts[mux])
797 continue;
798
799 found = 1;
800 /* we now need to match the string in the enum to the path */
801 if (!(strcmp(path->name, e->texts[mux])))
802 path->connect = 1; /* new connection */
803 else
804 path->connect = 0; /* old connection must be
805 powered down */
806 }
807
808 if (found) {
809 dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
810 dump_dapm(widget->codec, "mux power update");
811 }
812
813 return 0;
814}
815
731/* test and update the power status of a mixer or switch widget */ 816/* test and update the power status of a mixer or switch widget */
732static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, 817static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
733 struct snd_kcontrol *kcontrol, int reg, 818 struct snd_kcontrol *kcontrol, int reg,
@@ -965,6 +1050,12 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
965 if (ret != 0) 1050 if (ret != 0)
966 goto err; 1051 goto err;
967 break; 1052 break;
1053 case snd_soc_dapm_value_mux:
1054 ret = dapm_connect_value_mux(codec, wsource, wsink, path,
1055 control, &wsink->kcontrols[0]);
1056 if (ret != 0)
1057 goto err;
1058 break;
968 case snd_soc_dapm_switch: 1059 case snd_soc_dapm_switch:
969 case snd_soc_dapm_mixer: 1060 case snd_soc_dapm_mixer:
970 ret = dapm_connect_mixer(codec, wsource, wsink, path, control); 1061 ret = dapm_connect_mixer(codec, wsource, wsink, path, control);
@@ -1047,6 +1138,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
1047 dapm_new_mixer(codec, w); 1138 dapm_new_mixer(codec, w);
1048 break; 1139 break;
1049 case snd_soc_dapm_mux: 1140 case snd_soc_dapm_mux:
1141 case snd_soc_dapm_value_mux:
1050 dapm_new_mux(codec, w); 1142 dapm_new_mux(codec, w);
1051 break; 1143 break;
1052 case snd_soc_dapm_adc: 1144 case snd_soc_dapm_adc:
@@ -1274,6 +1366,105 @@ out:
1274EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); 1366EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
1275 1367
1276/** 1368/**
1369 * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get
1370 * callback
1371 * @kcontrol: mixer control
1372 * @ucontrol: control element information
1373 *
1374 * Callback to get the value of a dapm semi enumerated double mixer control.
1375 *
1376 * Semi enumerated mixer: the enumerated items are referred as values. Can be
1377 * used for handling bitfield coded enumeration for example.
1378 *
1379 * Returns 0 for success.
1380 */
1381int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
1382 struct snd_ctl_elem_value *ucontrol)
1383{
1384 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1385 struct soc_value_enum *e = (struct soc_value_enum *)
1386 kcontrol->private_value;
1387 unsigned short reg_val, val, mux;
1388
1389 reg_val = snd_soc_read(widget->codec, e->reg);
1390 val = (reg_val >> e->shift_l) & e->mask;
1391 for (mux = 0; mux < e->max; mux++) {
1392 if (val == e->values[mux])
1393 break;
1394 }
1395 ucontrol->value.enumerated.item[0] = mux;
1396 if (e->shift_l != e->shift_r) {
1397 val = (reg_val >> e->shift_r) & e->mask;
1398 for (mux = 0; mux < e->max; mux++) {
1399 if (val == e->values[mux])
1400 break;
1401 }
1402 ucontrol->value.enumerated.item[1] = mux;
1403 }
1404
1405 return 0;
1406}
1407EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double);
1408
1409/**
1410 * snd_soc_dapm_put_value_enum_double - dapm semi enumerated double mixer set
1411 * callback
1412 * @kcontrol: mixer control
1413 * @ucontrol: control element information
1414 *
1415 * Callback to set the value of a dapm semi enumerated double mixer control.
1416 *
1417 * Semi enumerated mixer: the enumerated items are referred as values. Can be
1418 * used for handling bitfield coded enumeration for example.
1419 *
1420 * Returns 0 for success.
1421 */
1422int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
1423 struct snd_ctl_elem_value *ucontrol)
1424{
1425 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1426 struct soc_value_enum *e = (struct soc_value_enum *)
1427 kcontrol->private_value;
1428 unsigned short val, mux;
1429 unsigned short mask;
1430 int ret = 0;
1431
1432 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1433 return -EINVAL;
1434 mux = ucontrol->value.enumerated.item[0];
1435 val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l;
1436 mask = e->mask << e->shift_l;
1437 if (e->shift_l != e->shift_r) {
1438 if (ucontrol->value.enumerated.item[1] > e->max - 1)
1439 return -EINVAL;
1440 val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r;
1441 mask |= e->mask << e->shift_r;
1442 }
1443
1444 mutex_lock(&widget->codec->mutex);
1445 widget->value = val;
1446 dapm_value_mux_update_power(widget, kcontrol, mask, mux, val, e);
1447 if (widget->event) {
1448 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
1449 ret = widget->event(widget,
1450 kcontrol, SND_SOC_DAPM_PRE_REG);
1451 if (ret < 0)
1452 goto out;
1453 }
1454 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
1455 if (widget->event_flags & SND_SOC_DAPM_POST_REG)
1456 ret = widget->event(widget,
1457 kcontrol, SND_SOC_DAPM_POST_REG);
1458 } else
1459 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
1460
1461out:
1462 mutex_unlock(&widget->codec->mutex);
1463 return ret;
1464}
1465EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
1466
1467/**
1277 * snd_soc_dapm_new_control - create new dapm control 1468 * snd_soc_dapm_new_control - create new dapm control
1278 * @codec: audio codec 1469 * @codec: audio codec
1279 * @widget: widget template 1470 * @widget: widget template