aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-dapm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r--sound/soc/soc-dapm.c152
1 files changed, 84 insertions, 68 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index f9d100bc8479..efbd0b37810a 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2,8 +2,7 @@
2 * soc-dapm.c -- ALSA SoC Dynamic Audio Power Management 2 * soc-dapm.c -- ALSA SoC Dynamic Audio Power Management
3 * 3 *
4 * Copyright 2005 Wolfson Microelectronics PLC. 4 * Copyright 2005 Wolfson Microelectronics PLC.
5 * Author: Liam Girdwood 5 * Author: Liam Girdwood <lrg@slimlogic.co.uk>
6 * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
7 * 6 *
8 * This program is free software; you can redistribute it and/or modify it 7 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the 8 * under the terms of the GNU General Public License as published by the
@@ -38,6 +37,7 @@
38#include <linux/bitops.h> 37#include <linux/bitops.h>
39#include <linux/platform_device.h> 38#include <linux/platform_device.h>
40#include <linux/jiffies.h> 39#include <linux/jiffies.h>
40#include <linux/debugfs.h>
41#include <sound/core.h> 41#include <sound/core.h>
42#include <sound/pcm.h> 42#include <sound/pcm.h>
43#include <sound/pcm_params.h> 43#include <sound/pcm_params.h>
@@ -67,7 +67,9 @@ static int dapm_status = 1;
67module_param(dapm_status, int, 0); 67module_param(dapm_status, int, 0);
68MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); 68MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries");
69 69
70static unsigned int pop_time; 70static struct dentry *asoc_debugfs;
71
72static u32 pop_time;
71 73
72static void pop_wait(void) 74static void pop_wait(void)
73{ 75{
@@ -104,10 +106,13 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
104 case snd_soc_dapm_switch: 106 case snd_soc_dapm_switch:
105 case snd_soc_dapm_mixer: { 107 case snd_soc_dapm_mixer: {
106 int val; 108 int val;
107 int reg = w->kcontrols[i].private_value & 0xff; 109 struct soc_mixer_control *mc = (struct soc_mixer_control *)
108 int shift = (w->kcontrols[i].private_value >> 8) & 0x0f; 110 w->kcontrols[i].private_value;
109 int mask = (w->kcontrols[i].private_value >> 16) & 0xff; 111 unsigned int reg = mc->reg;
110 int invert = (w->kcontrols[i].private_value >> 24) & 0x01; 112 unsigned int shift = mc->shift;
113 int max = mc->max;
114 unsigned int mask = (1 << fls(max)) - 1;
115 unsigned int invert = mc->invert;
111 116
112 val = snd_soc_read(w->codec, reg); 117 val = snd_soc_read(w->codec, reg);
113 val = (val >> shift) & mask; 118 val = (val >> shift) & mask;
@@ -122,13 +127,13 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
122 struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value; 127 struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;
123 int val, item, bitmask; 128 int val, item, bitmask;
124 129
125 for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) 130 for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
126 ; 131 ;
127 val = snd_soc_read(w->codec, e->reg); 132 val = snd_soc_read(w->codec, e->reg);
128 item = (val >> e->shift_l) & (bitmask - 1); 133 item = (val >> e->shift_l) & (bitmask - 1);
129 134
130 p->connect = 0; 135 p->connect = 0;
131 for (i = 0; i < e->mask; i++) { 136 for (i = 0; i < e->max; i++) {
132 if (!(strcmp(p->name, e->texts[i])) && item == i) 137 if (!(strcmp(p->name, e->texts[i])) && item == i)
133 p->connect = 1; 138 p->connect = 1;
134 } 139 }
@@ -165,7 +170,7 @@ static int dapm_connect_mux(struct snd_soc_codec *codec,
165 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 170 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
166 int i; 171 int i;
167 172
168 for (i = 0; i < e->mask; i++) { 173 for (i = 0; i < e->max; i++) {
169 if (!(strcmp(control_name, e->texts[i]))) { 174 if (!(strcmp(control_name, e->texts[i]))) {
170 list_add(&path->list, &codec->dapm_paths); 175 list_add(&path->list, &codec->dapm_paths);
171 list_add(&path->list_sink, &dest->sources); 176 list_add(&path->list_sink, &dest->sources);
@@ -247,16 +252,19 @@ static int dapm_set_pga(struct snd_soc_dapm_widget *widget, int power)
247 return 0; 252 return 0;
248 253
249 if (widget->num_kcontrols && k) { 254 if (widget->num_kcontrols && k) {
250 int reg = k->private_value & 0xff; 255 struct soc_mixer_control *mc =
251 int shift = (k->private_value >> 8) & 0x0f; 256 (struct soc_mixer_control *)k->private_value;
252 int mask = (k->private_value >> 16) & 0xff; 257 unsigned int reg = mc->reg;
253 int invert = (k->private_value >> 24) & 0x01; 258 unsigned int shift = mc->shift;
259 int max = mc->max;
260 unsigned int mask = (1 << fls(max)) - 1;
261 unsigned int invert = mc->invert;
254 262
255 if (power) { 263 if (power) {
256 int i; 264 int i;
257 /* power up has happended, increase volume to last level */ 265 /* power up has happended, increase volume to last level */
258 if (invert) { 266 if (invert) {
259 for (i = mask; i > widget->saved_value; i--) 267 for (i = max; i > widget->saved_value; i--)
260 snd_soc_update_bits(widget->codec, reg, mask, i); 268 snd_soc_update_bits(widget->codec, reg, mask, i);
261 } else { 269 } else {
262 for (i = 0; i < widget->saved_value; i++) 270 for (i = 0; i < widget->saved_value; i++)
@@ -684,7 +692,7 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
684/* test and update the power status of a mux widget */ 692/* test and update the power status of a mux widget */
685static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, 693static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
686 struct snd_kcontrol *kcontrol, int mask, 694 struct snd_kcontrol *kcontrol, int mask,
687 int val, struct soc_enum* e) 695 int mux, int val, struct soc_enum *e)
688{ 696{
689 struct snd_soc_dapm_path *path; 697 struct snd_soc_dapm_path *path;
690 int found = 0; 698 int found = 0;
@@ -700,12 +708,12 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
700 if (path->kcontrol != kcontrol) 708 if (path->kcontrol != kcontrol)
701 continue; 709 continue;
702 710
703 if (!path->name || ! e->texts[val]) 711 if (!path->name || !e->texts[mux])
704 continue; 712 continue;
705 713
706 found = 1; 714 found = 1;
707 /* we now need to match the string in the enum to the path */ 715 /* we now need to match the string in the enum to the path */
708 if (!(strcmp(path->name, e->texts[val]))) 716 if (!(strcmp(path->name, e->texts[mux])))
709 path->connect = 1; /* new connection */ 717 path->connect = 1; /* new connection */
710 else 718 else
711 path->connect = 0; /* old connection must be powered down */ 719 path->connect = 0; /* old connection must be powered down */
@@ -811,51 +819,35 @@ static ssize_t dapm_widget_show(struct device *dev,
811 819
812static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); 820static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
813 821
814/* pop/click delay times */
815static ssize_t dapm_pop_time_show(struct device *dev,
816 struct device_attribute *attr, char *buf)
817{
818 return sprintf(buf, "%d\n", pop_time);
819}
820
821static ssize_t dapm_pop_time_store(struct device *dev,
822 struct device_attribute *attr,
823 const char *buf, size_t count)
824
825{
826 unsigned long val;
827
828 if (strict_strtoul(buf, 10, &val) >= 0)
829 pop_time = val;
830 else
831 printk(KERN_ERR "Unable to parse pop_time setting\n");
832
833 return count;
834}
835
836static DEVICE_ATTR(dapm_pop_time, 0744, dapm_pop_time_show,
837 dapm_pop_time_store);
838
839int snd_soc_dapm_sys_add(struct device *dev) 822int snd_soc_dapm_sys_add(struct device *dev)
840{ 823{
841 int ret = 0; 824 int ret = 0;
842 825
843 if (dapm_status) { 826 if (!dapm_status)
844 ret = device_create_file(dev, &dev_attr_dapm_widget); 827 return 0;
845 828
846 if (ret == 0) 829 ret = device_create_file(dev, &dev_attr_dapm_widget);
847 ret = device_create_file(dev, &dev_attr_dapm_pop_time); 830 if (ret != 0)
848 } 831 return ret;
849 832
850 return ret; 833 asoc_debugfs = debugfs_create_dir("asoc", NULL);
834 if (!IS_ERR(asoc_debugfs))
835 debugfs_create_u32("dapm_pop_time", 0744, asoc_debugfs,
836 &pop_time);
837 else
838 asoc_debugfs = NULL;
839
840 return 0;
851} 841}
852 842
853static void snd_soc_dapm_sys_remove(struct device *dev) 843static void snd_soc_dapm_sys_remove(struct device *dev)
854{ 844{
855 if (dapm_status) { 845 if (dapm_status) {
856 device_remove_file(dev, &dev_attr_dapm_pop_time);
857 device_remove_file(dev, &dev_attr_dapm_widget); 846 device_remove_file(dev, &dev_attr_dapm_widget);
858 } 847 }
848
849 if (asoc_debugfs)
850 debugfs_remove_recursive(asoc_debugfs);
859} 851}
860 852
861/* free all dapm widgets and resources */ 853/* free all dapm widgets and resources */
@@ -1133,12 +1125,14 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
1133 struct snd_ctl_elem_value *ucontrol) 1125 struct snd_ctl_elem_value *ucontrol)
1134{ 1126{
1135 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); 1127 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1136 int reg = kcontrol->private_value & 0xff; 1128 struct soc_mixer_control *mc =
1137 int shift = (kcontrol->private_value >> 8) & 0x0f; 1129 (struct soc_mixer_control *)kcontrol->private_value;
1138 int rshift = (kcontrol->private_value >> 12) & 0x0f; 1130 unsigned int reg = mc->reg;
1139 int max = (kcontrol->private_value >> 16) & 0xff; 1131 unsigned int shift = mc->shift;
1140 int invert = (kcontrol->private_value >> 24) & 0x01; 1132 unsigned int rshift = mc->rshift;
1141 int mask = (1 << fls(max)) - 1; 1133 int max = mc->max;
1134 unsigned int invert = mc->invert;
1135 unsigned int mask = (1 << fls(max)) - 1;
1142 1136
1143 /* return the saved value if we are powered down */ 1137 /* return the saved value if we are powered down */
1144 if (widget->id == snd_soc_dapm_pga && !widget->power) { 1138 if (widget->id == snd_soc_dapm_pga && !widget->power) {
@@ -1176,12 +1170,14 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
1176 struct snd_ctl_elem_value *ucontrol) 1170 struct snd_ctl_elem_value *ucontrol)
1177{ 1171{
1178 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); 1172 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1179 int reg = kcontrol->private_value & 0xff; 1173 struct soc_mixer_control *mc =
1180 int shift = (kcontrol->private_value >> 8) & 0x0f; 1174 (struct soc_mixer_control *)kcontrol->private_value;
1181 int rshift = (kcontrol->private_value >> 12) & 0x0f; 1175 unsigned int reg = mc->reg;
1182 int max = (kcontrol->private_value >> 16) & 0xff; 1176 unsigned int shift = mc->shift;
1183 int mask = (1 << fls(max)) - 1; 1177 unsigned int rshift = mc->rshift;
1184 int invert = (kcontrol->private_value >> 24) & 0x01; 1178 int max = mc->max;
1179 unsigned int mask = (1 << fls(max)) - 1;
1180 unsigned int invert = mc->invert;
1185 unsigned short val, val2, val_mask; 1181 unsigned short val, val2, val_mask;
1186 int ret; 1182 int ret;
1187 1183
@@ -1248,7 +1244,7 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
1248 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 1244 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1249 unsigned short val, bitmask; 1245 unsigned short val, bitmask;
1250 1246
1251 for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) 1247 for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
1252 ; 1248 ;
1253 val = snd_soc_read(widget->codec, e->reg); 1249 val = snd_soc_read(widget->codec, e->reg);
1254 ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); 1250 ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
@@ -1278,15 +1274,15 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
1278 unsigned short mask, bitmask; 1274 unsigned short mask, bitmask;
1279 int ret = 0; 1275 int ret = 0;
1280 1276
1281 for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) 1277 for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
1282 ; 1278 ;
1283 if (ucontrol->value.enumerated.item[0] > e->mask - 1) 1279 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1284 return -EINVAL; 1280 return -EINVAL;
1285 mux = ucontrol->value.enumerated.item[0]; 1281 mux = ucontrol->value.enumerated.item[0];
1286 val = mux << e->shift_l; 1282 val = mux << e->shift_l;
1287 mask = (bitmask - 1) << e->shift_l; 1283 mask = (bitmask - 1) << e->shift_l;
1288 if (e->shift_l != e->shift_r) { 1284 if (e->shift_l != e->shift_r) {
1289 if (ucontrol->value.enumerated.item[1] > e->mask - 1) 1285 if (ucontrol->value.enumerated.item[1] > e->max - 1)
1290 return -EINVAL; 1286 return -EINVAL;
1291 val |= ucontrol->value.enumerated.item[1] << e->shift_r; 1287 val |= ucontrol->value.enumerated.item[1] << e->shift_r;
1292 mask |= (bitmask - 1) << e->shift_r; 1288 mask |= (bitmask - 1) << e->shift_r;
@@ -1294,7 +1290,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
1294 1290
1295 mutex_lock(&widget->codec->mutex); 1291 mutex_lock(&widget->codec->mutex);
1296 widget->value = val; 1292 widget->value = val;
1297 dapm_mux_update_power(widget, kcontrol, mask, mux, e); 1293 dapm_mux_update_power(widget, kcontrol, mask, mux, val, e);
1298 if (widget->event) { 1294 if (widget->event) {
1299 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { 1295 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
1300 ret = widget->event(widget, 1296 ret = widget->event(widget,
@@ -1487,6 +1483,26 @@ int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin)
1487EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); 1483EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
1488 1484
1489/** 1485/**
1486 * snd_soc_dapm_nc_pin - permanently disable pin.
1487 * @codec: SoC codec
1488 * @pin: pin name
1489 *
1490 * Marks the specified pin as being not connected, disabling it along
1491 * any parent or child widgets. At present this is identical to
1492 * snd_soc_dapm_disable_pin() but in future it will be extended to do
1493 * additional things such as disabling controls which only affect
1494 * paths through the pin.
1495 *
1496 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
1497 * do any widget power switching.
1498 */
1499int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin)
1500{
1501 return snd_soc_dapm_set_pin(codec, pin, 0);
1502}
1503EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
1504
1505/**
1490 * snd_soc_dapm_get_pin_status - get audio pin status 1506 * snd_soc_dapm_get_pin_status - get audio pin status
1491 * @codec: audio codec 1507 * @codec: audio codec
1492 * @pin: audio signal pin endpoint (or start point) 1508 * @pin: audio signal pin endpoint (or start point)
@@ -1524,6 +1540,6 @@ void snd_soc_dapm_free(struct snd_soc_device *socdev)
1524EXPORT_SYMBOL_GPL(snd_soc_dapm_free); 1540EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
1525 1541
1526/* Module information */ 1542/* Module information */
1527MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); 1543MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
1528MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC"); 1544MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
1529MODULE_LICENSE("GPL"); 1545MODULE_LICENSE("GPL");