aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Zabel <philipp.zabel@gmail.com>2008-01-10 08:37:42 -0500
committerJaroslav Kysela <perex@perex.cz>2008-01-31 11:29:50 -0500
commita7a4ac86b4754f44eb06221f3087debb4775d588 (patch)
tree63240035ca77fca21c4bb3b0db7566f53501053a
parent0b4d221b8d56deefca4984d01b3a010107ae1f72 (diff)
[ALSA] ASoC TLV support
Add TLV support to ASoC. Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com> Signed-off-by: Liam Girdwood <lg@opensource.wolfsonmicro.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
-rw-r--r--include/sound/soc-dapm.h24
-rw-r--r--include/sound/soc.h58
-rw-r--r--sound/soc/soc-core.c66
-rw-r--r--sound/soc/soc-dapm.c14
4 files changed, 114 insertions, 48 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 4158cbaa0f25..491f81e89847 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -131,18 +131,34 @@
131 .shift = wshift, .invert = winvert} 131 .shift = wshift, .invert = winvert}
132 132
133/* dapm kcontrol types */ 133/* dapm kcontrol types */
134#define SOC_DAPM_SINGLE(xname, reg, shift, mask, invert) \ 134#define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \
135{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 135{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
136 .info = snd_soc_info_volsw, \ 136 .info = snd_soc_info_volsw, \
137 .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ 137 .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
138 .private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) } 138 .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
139#define SOC_DAPM_DOUBLE(xname, reg, shift_left, shift_right, mask, invert, \ 139#define SOC_DAPM_DOUBLE(xname, reg, shift_left, shift_right, max, invert, \
140 power) \ 140 power) \
141{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ 141{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
142 .info = snd_soc_info_volsw, \ 142 .info = snd_soc_info_volsw, \
143 .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ 143 .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
144 .private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) |\ 144 .private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) |\
145 ((mask) << 16) | ((invert) << 24) } 145 ((max) << 16) | ((invert) << 24) }
146#define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
147{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
148 .info = snd_soc_info_volsw, \
149 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
150 .tlv.p = (tlv_array), \
151 .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
152 .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
153#define SOC_DAPM_DOUBLE_TLV(xname, reg, shift_left, shift_right, max, invert, \
154 power, tlv_array) \
155{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
156 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
157 .tlv.p = (tlv_array), \
158 .info = snd_soc_info_volsw, \
159 .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
160 .private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) |\
161 ((max) << 16) | ((invert) << 24) }
146#define SOC_DAPM_ENUM(xname, xenum) \ 162#define SOC_DAPM_ENUM(xname, xenum) \
147{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 163{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
148 .info = snd_soc_info_enum_double, \ 164 .info = snd_soc_info_enum_double, \
diff --git a/include/sound/soc.h b/include/sound/soc.h
index add5f948e383..0afcdfe42a46 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -26,27 +26,53 @@
26/* 26/*
27 * Convenience kcontrol builders 27 * Convenience kcontrol builders
28 */ 28 */
29#define SOC_SINGLE_VALUE(reg,shift,mask,invert) ((reg) | ((shift) << 8) |\ 29#define SOC_SINGLE_VALUE(reg, shift, max, invert) ((reg) | ((shift) << 8) |\
30 ((shift) << 12) | ((mask) << 16) | ((invert) << 24)) 30 ((shift) << 12) | ((max) << 16) | ((invert) << 24))
31#define SOC_SINGLE_VALUE_EXT(reg,mask,invert) ((reg) | ((mask) << 16) |\ 31#define SOC_SINGLE_VALUE_EXT(reg, max, invert) ((reg) | ((max) << 16) |\
32 ((invert) << 31)) 32 ((invert) << 31))
33#define SOC_SINGLE(xname, reg, shift, mask, invert) \ 33#define SOC_SINGLE(xname, reg, shift, max, invert) \
34{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 34{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
35 .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ 35 .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
36 .put = snd_soc_put_volsw, \ 36 .put = snd_soc_put_volsw, \
37 .private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) } 37 .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
38#define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \ 38#define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
39{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
40 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
41 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
42 .tlv.p = (tlv_array), \
43 .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
44 .put = snd_soc_put_volsw, \
45 .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
46#define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \
39{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ 47{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
40 .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ 48 .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
41 .put = snd_soc_put_volsw, \ 49 .put = snd_soc_put_volsw, \
42 .private_value = (reg) | ((shift_left) << 8) | \ 50 .private_value = (reg) | ((shift_left) << 8) | \
43 ((shift_right) << 12) | ((mask) << 16) | ((invert) << 24) } 51 ((shift_right) << 12) | ((max) << 16) | ((invert) << 24) }
44#define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert) \ 52#define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, max, invert) \
45{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ 53{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
46 .info = snd_soc_info_volsw_2r, \ 54 .info = snd_soc_info_volsw_2r, \
47 .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \ 55 .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
48 .private_value = (reg_left) | ((shift) << 8) | \ 56 .private_value = (reg_left) | ((shift) << 8) | \
49 ((mask) << 12) | ((invert) << 20) | ((reg_right) << 24) } 57 ((max) << 12) | ((invert) << 20) | ((reg_right) << 24) }
58#define SOC_DOUBLE_TLV(xname, reg, shift_left, shift_right, max, invert, tlv_array) \
59{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
60 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
61 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
62 .tlv.p = (tlv_array), \
63 .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
64 .put = snd_soc_put_volsw, \
65 .private_value = (reg) | ((shift_left) << 8) | \
66 ((shift_right) << 12) | ((max) << 16) | ((invert) << 24) }
67#define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, shift, max, invert, tlv_array) \
68{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
69 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
70 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
71 .tlv.p = (tlv_array), \
72 .info = snd_soc_info_volsw_2r, \
73 .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
74 .private_value = (reg_left) | ((shift) << 8) | \
75 ((max) << 12) | ((invert) << 20) | ((reg_right) << 24) }
50#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \ 76#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \
51{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ 77{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
52 .mask = xmask, .texts = xtexts } 78 .mask = xmask, .texts = xtexts }
@@ -104,9 +130,21 @@
104#define SND_SOC_DAIFMT_GATED (1 << 4) /* clock is gated when not Tx/Rx */ 130#define SND_SOC_DAIFMT_GATED (1 << 4) /* clock is gated when not Tx/Rx */
105 131
106/* 132/*
133 * DAI Sync
134 * Synchronous LR (Left Right) clocks and Frame signals.
135 */
136#define SND_SOC_DAIFMT_SYNC (0 << 5) /* Tx FRM = Rx FRM */
137#define SND_SOC_DAIFMT_ASYNC (1 << 5) /* Tx FRM ~ Rx FRM */
138
139/*
140 * TDM
141 */
142#define SND_SOC_DAIFMT_TDM (1 << 6)
143
144/*
107 * DAI hardware signal inversions 145 * DAI hardware signal inversions
108 */ 146 */
109#define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bit clock + frame */ 147#define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bclk + frm */
110#define SND_SOC_DAIFMT_NB_IF (1 << 8) /* normal bclk + inv frm */ 148#define SND_SOC_DAIFMT_NB_IF (1 << 8) /* normal bclk + inv frm */
111#define SND_SOC_DAIFMT_IB_NF (2 << 8) /* invert bclk + nor frm */ 149#define SND_SOC_DAIFMT_IB_NF (2 << 8) /* invert bclk + nor frm */
112#define SND_SOC_DAIFMT_IB_IF (3 << 8) /* invert bclk + frm */ 150#define SND_SOC_DAIFMT_IB_IF (3 << 8) /* invert bclk + frm */
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index bd656db347ee..e748b00466b7 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1213,7 +1213,6 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
1213 memcpy(&template, _template, sizeof(template)); 1213 memcpy(&template, _template, sizeof(template));
1214 if (long_name) 1214 if (long_name)
1215 template.name = long_name; 1215 template.name = long_name;
1216 template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1217 template.index = 0; 1216 template.index = 0;
1218 1217
1219 return snd_ctl_new1(&template, data); 1218 return snd_ctl_new1(&template, data);
@@ -1348,13 +1347,16 @@ EXPORT_SYMBOL_GPL(snd_soc_info_enum_ext);
1348int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, 1347int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
1349 struct snd_ctl_elem_info *uinfo) 1348 struct snd_ctl_elem_info *uinfo)
1350{ 1349{
1351 int mask = kcontrol->private_value; 1350 int max = kcontrol->private_value;
1351
1352 if (max == 1)
1353 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1354 else
1355 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1352 1356
1353 uinfo->type =
1354 mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
1355 uinfo->count = 1; 1357 uinfo->count = 1;
1356 uinfo->value.integer.min = 0; 1358 uinfo->value.integer.min = 0;
1357 uinfo->value.integer.max = mask; 1359 uinfo->value.integer.max = max;
1358 return 0; 1360 return 0;
1359} 1361}
1360EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext); 1362EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext);
@@ -1371,15 +1373,18 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext);
1371int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, 1373int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
1372 struct snd_ctl_elem_info *uinfo) 1374 struct snd_ctl_elem_info *uinfo)
1373{ 1375{
1374 int mask = (kcontrol->private_value >> 16) & 0xff; 1376 int max = (kcontrol->private_value >> 16) & 0xff;
1375 int shift = (kcontrol->private_value >> 8) & 0x0f; 1377 int shift = (kcontrol->private_value >> 8) & 0x0f;
1376 int rshift = (kcontrol->private_value >> 12) & 0x0f; 1378 int rshift = (kcontrol->private_value >> 12) & 0x0f;
1377 1379
1378 uinfo->type = 1380 if (max == 1)
1379 mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; 1381 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1382 else
1383 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1384
1380 uinfo->count = shift == rshift ? 1 : 2; 1385 uinfo->count = shift == rshift ? 1 : 2;
1381 uinfo->value.integer.min = 0; 1386 uinfo->value.integer.min = 0;
1382 uinfo->value.integer.max = mask; 1387 uinfo->value.integer.max = max;
1383 return 0; 1388 return 0;
1384} 1389}
1385EXPORT_SYMBOL_GPL(snd_soc_info_volsw); 1390EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
@@ -1400,7 +1405,8 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
1400 int reg = kcontrol->private_value & 0xff; 1405 int reg = kcontrol->private_value & 0xff;
1401 int shift = (kcontrol->private_value >> 8) & 0x0f; 1406 int shift = (kcontrol->private_value >> 8) & 0x0f;
1402 int rshift = (kcontrol->private_value >> 12) & 0x0f; 1407 int rshift = (kcontrol->private_value >> 12) & 0x0f;
1403 int mask = (kcontrol->private_value >> 16) & 0xff; 1408 int max = (kcontrol->private_value >> 16) & 0xff;
1409 int mask = (1 << fls(max)) - 1;
1404 int invert = (kcontrol->private_value >> 24) & 0x01; 1410 int invert = (kcontrol->private_value >> 24) & 0x01;
1405 1411
1406 ucontrol->value.integer.value[0] = 1412 ucontrol->value.integer.value[0] =
@@ -1410,10 +1416,10 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
1410 (snd_soc_read(codec, reg) >> rshift) & mask; 1416 (snd_soc_read(codec, reg) >> rshift) & mask;
1411 if (invert) { 1417 if (invert) {
1412 ucontrol->value.integer.value[0] = 1418 ucontrol->value.integer.value[0] =
1413 mask - ucontrol->value.integer.value[0]; 1419 max - ucontrol->value.integer.value[0];
1414 if (shift != rshift) 1420 if (shift != rshift)
1415 ucontrol->value.integer.value[1] = 1421 ucontrol->value.integer.value[1] =
1416 mask - ucontrol->value.integer.value[1]; 1422 max - ucontrol->value.integer.value[1];
1417 } 1423 }
1418 1424
1419 return 0; 1425 return 0;
@@ -1436,25 +1442,24 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
1436 int reg = kcontrol->private_value & 0xff; 1442 int reg = kcontrol->private_value & 0xff;
1437 int shift = (kcontrol->private_value >> 8) & 0x0f; 1443 int shift = (kcontrol->private_value >> 8) & 0x0f;
1438 int rshift = (kcontrol->private_value >> 12) & 0x0f; 1444 int rshift = (kcontrol->private_value >> 12) & 0x0f;
1439 int mask = (kcontrol->private_value >> 16) & 0xff; 1445 int max = (kcontrol->private_value >> 16) & 0xff;
1446 int mask = (1 << fls(max)) - 1;
1440 int invert = (kcontrol->private_value >> 24) & 0x01; 1447 int invert = (kcontrol->private_value >> 24) & 0x01;
1441 int err;
1442 unsigned short val, val2, val_mask; 1448 unsigned short val, val2, val_mask;
1443 1449
1444 val = (ucontrol->value.integer.value[0] & mask); 1450 val = (ucontrol->value.integer.value[0] & mask);
1445 if (invert) 1451 if (invert)
1446 val = mask - val; 1452 val = max - val;
1447 val_mask = mask << shift; 1453 val_mask = mask << shift;
1448 val = val << shift; 1454 val = val << shift;
1449 if (shift != rshift) { 1455 if (shift != rshift) {
1450 val2 = (ucontrol->value.integer.value[1] & mask); 1456 val2 = (ucontrol->value.integer.value[1] & mask);
1451 if (invert) 1457 if (invert)
1452 val2 = mask - val2; 1458 val2 = max - val2;
1453 val_mask |= mask << rshift; 1459 val_mask |= mask << rshift;
1454 val |= val2 << rshift; 1460 val |= val2 << rshift;
1455 } 1461 }
1456 err = snd_soc_update_bits(codec, reg, val_mask, val); 1462 return snd_soc_update_bits(codec, reg, val_mask, val);
1457 return err;
1458} 1463}
1459EXPORT_SYMBOL_GPL(snd_soc_put_volsw); 1464EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
1460 1465
@@ -1471,13 +1476,16 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
1471int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, 1476int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol,
1472 struct snd_ctl_elem_info *uinfo) 1477 struct snd_ctl_elem_info *uinfo)
1473{ 1478{
1474 int mask = (kcontrol->private_value >> 12) & 0xff; 1479 int max = (kcontrol->private_value >> 12) & 0xff;
1480
1481 if (max == 1)
1482 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1483 else
1484 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1475 1485
1476 uinfo->type =
1477 mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
1478 uinfo->count = 2; 1486 uinfo->count = 2;
1479 uinfo->value.integer.min = 0; 1487 uinfo->value.integer.min = 0;
1480 uinfo->value.integer.max = mask; 1488 uinfo->value.integer.max = max;
1481 return 0; 1489 return 0;
1482} 1490}
1483EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r); 1491EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r);
@@ -1498,7 +1506,8 @@ int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
1498 int reg = kcontrol->private_value & 0xff; 1506 int reg = kcontrol->private_value & 0xff;
1499 int reg2 = (kcontrol->private_value >> 24) & 0xff; 1507 int reg2 = (kcontrol->private_value >> 24) & 0xff;
1500 int shift = (kcontrol->private_value >> 8) & 0x0f; 1508 int shift = (kcontrol->private_value >> 8) & 0x0f;
1501 int mask = (kcontrol->private_value >> 12) & 0xff; 1509 int max = (kcontrol->private_value >> 12) & 0xff;
1510 int mask = (1<<fls(max))-1;
1502 int invert = (kcontrol->private_value >> 20) & 0x01; 1511 int invert = (kcontrol->private_value >> 20) & 0x01;
1503 1512
1504 ucontrol->value.integer.value[0] = 1513 ucontrol->value.integer.value[0] =
@@ -1507,9 +1516,9 @@ int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
1507 (snd_soc_read(codec, reg2) >> shift) & mask; 1516 (snd_soc_read(codec, reg2) >> shift) & mask;
1508 if (invert) { 1517 if (invert) {
1509 ucontrol->value.integer.value[0] = 1518 ucontrol->value.integer.value[0] =
1510 mask - ucontrol->value.integer.value[0]; 1519 max - ucontrol->value.integer.value[0];
1511 ucontrol->value.integer.value[1] = 1520 ucontrol->value.integer.value[1] =
1512 mask - ucontrol->value.integer.value[1]; 1521 max - ucontrol->value.integer.value[1];
1513 } 1522 }
1514 1523
1515 return 0; 1524 return 0;
@@ -1532,7 +1541,8 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
1532 int reg = kcontrol->private_value & 0xff; 1541 int reg = kcontrol->private_value & 0xff;
1533 int reg2 = (kcontrol->private_value >> 24) & 0xff; 1542 int reg2 = (kcontrol->private_value >> 24) & 0xff;
1534 int shift = (kcontrol->private_value >> 8) & 0x0f; 1543 int shift = (kcontrol->private_value >> 8) & 0x0f;
1535 int mask = (kcontrol->private_value >> 12) & 0xff; 1544 int max = (kcontrol->private_value >> 12) & 0xff;
1545 int mask = (1 << fls(max)) - 1;
1536 int invert = (kcontrol->private_value >> 20) & 0x01; 1546 int invert = (kcontrol->private_value >> 20) & 0x01;
1537 int err; 1547 int err;
1538 unsigned short val, val2, val_mask; 1548 unsigned short val, val2, val_mask;
@@ -1542,8 +1552,8 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
1542 val2 = (ucontrol->value.integer.value[1] & mask); 1552 val2 = (ucontrol->value.integer.value[1] & mask);
1543 1553
1544 if (invert) { 1554 if (invert) {
1545 val = mask - val; 1555 val = max - val;
1546 val2 = mask - val2; 1556 val2 = max - val2;
1547 } 1557 }
1548 1558
1549 val = val << shift; 1559 val = val << shift;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 16ebb60ed3d4..7eb6c5c03775 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1018,8 +1018,9 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
1018 int reg = kcontrol->private_value & 0xff; 1018 int reg = kcontrol->private_value & 0xff;
1019 int shift = (kcontrol->private_value >> 8) & 0x0f; 1019 int shift = (kcontrol->private_value >> 8) & 0x0f;
1020 int rshift = (kcontrol->private_value >> 12) & 0x0f; 1020 int rshift = (kcontrol->private_value >> 12) & 0x0f;
1021 int mask = (kcontrol->private_value >> 16) & 0xff; 1021 int max = (kcontrol->private_value >> 16) & 0xff;
1022 int invert = (kcontrol->private_value >> 24) & 0x01; 1022 int invert = (kcontrol->private_value >> 24) & 0x01;
1023 int mask = (1 << fls(max)) - 1;
1023 1024
1024 /* return the saved value if we are powered down */ 1025 /* return the saved value if we are powered down */
1025 if (widget->id == snd_soc_dapm_pga && !widget->power) { 1026 if (widget->id == snd_soc_dapm_pga && !widget->power) {
@@ -1034,10 +1035,10 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
1034 (snd_soc_read(widget->codec, reg) >> rshift) & mask; 1035 (snd_soc_read(widget->codec, reg) >> rshift) & mask;
1035 if (invert) { 1036 if (invert) {
1036 ucontrol->value.integer.value[0] = 1037 ucontrol->value.integer.value[0] =
1037 mask - ucontrol->value.integer.value[0]; 1038 max - ucontrol->value.integer.value[0];
1038 if (shift != rshift) 1039 if (shift != rshift)
1039 ucontrol->value.integer.value[1] = 1040 ucontrol->value.integer.value[1] =
1040 mask - ucontrol->value.integer.value[1]; 1041 max - ucontrol->value.integer.value[1];
1041 } 1042 }
1042 1043
1043 return 0; 1044 return 0;
@@ -1060,7 +1061,8 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
1060 int reg = kcontrol->private_value & 0xff; 1061 int reg = kcontrol->private_value & 0xff;
1061 int shift = (kcontrol->private_value >> 8) & 0x0f; 1062 int shift = (kcontrol->private_value >> 8) & 0x0f;
1062 int rshift = (kcontrol->private_value >> 12) & 0x0f; 1063 int rshift = (kcontrol->private_value >> 12) & 0x0f;
1063 int mask = (kcontrol->private_value >> 16) & 0xff; 1064 int max = (kcontrol->private_value >> 16) & 0xff;
1065 int mask = (1 << fls(max)) - 1;
1064 int invert = (kcontrol->private_value >> 24) & 0x01; 1066 int invert = (kcontrol->private_value >> 24) & 0x01;
1065 unsigned short val, val2, val_mask; 1067 unsigned short val, val2, val_mask;
1066 int ret; 1068 int ret;
@@ -1068,13 +1070,13 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
1068 val = (ucontrol->value.integer.value[0] & mask); 1070 val = (ucontrol->value.integer.value[0] & mask);
1069 1071
1070 if (invert) 1072 if (invert)
1071 val = mask - val; 1073 val = max - val;
1072 val_mask = mask << shift; 1074 val_mask = mask << shift;
1073 val = val << shift; 1075 val = val << shift;
1074 if (shift != rshift) { 1076 if (shift != rshift) {
1075 val2 = (ucontrol->value.integer.value[1] & mask); 1077 val2 = (ucontrol->value.integer.value[1] & mask);
1076 if (invert) 1078 if (invert)
1077 val2 = mask - val2; 1079 val2 = max - val2;
1078 val_mask |= mask << rshift; 1080 val_mask |= mask << rshift;
1079 val |= val2 << rshift; 1081 val |= val2 << rshift;
1080 } 1082 }