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.c344
1 files changed, 258 insertions, 86 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index af3326c63504..2c87061c2a6b 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -10,11 +10,6 @@
10 * Free Software Foundation; either version 2 of the License, or (at your 10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. 11 * option) any later version.
12 * 12 *
13 * Revision history
14 * 12th Aug 2005 Initial version.
15 * 25th Oct 2005 Implemented path power domain.
16 * 18th Dec 2005 Implemented machine and stream level power domain.
17 *
18 * Features: 13 * Features:
19 * o Changes power status of internal codec blocks depending on the 14 * o Changes power status of internal codec blocks depending on the
20 * dynamic configuration of codec internal audio paths and active 15 * dynamic configuration of codec internal audio paths and active
@@ -50,23 +45,10 @@
50#include <sound/initval.h> 45#include <sound/initval.h>
51 46
52/* debug */ 47/* debug */
53#define DAPM_DEBUG 0 48#ifdef DEBUG
54#if DAPM_DEBUG
55#define dump_dapm(codec, action) dbg_dump_dapm(codec, action) 49#define dump_dapm(codec, action) dbg_dump_dapm(codec, action)
56#define dbg(format, arg...) printk(format, ## arg)
57#else 50#else
58#define dump_dapm(codec, action) 51#define dump_dapm(codec, action)
59#define dbg(format, arg...)
60#endif
61
62#define POP_DEBUG 0
63#if POP_DEBUG
64#define POP_TIME 500 /* 500 msecs - change if pop debug is too fast */
65#define pop_wait(time) schedule_timeout_uninterruptible(msecs_to_jiffies(time))
66#define pop_dbg(format, arg...) printk(format, ## arg); pop_wait(POP_TIME)
67#else
68#define pop_dbg(format, arg...)
69#define pop_wait(time)
70#endif 52#endif
71 53
72/* dapm power sequences - make this per codec in the future */ 54/* dapm power sequences - make this per codec in the future */
@@ -85,6 +67,28 @@ static int dapm_status = 1;
85module_param(dapm_status, int, 0); 67module_param(dapm_status, int, 0);
86MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); 68MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries");
87 69
70static unsigned int pop_time;
71
72static void pop_wait(void)
73{
74 if (pop_time)
75 schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
76}
77
78static void pop_dbg(const char *fmt, ...)
79{
80 va_list args;
81
82 va_start(args, fmt);
83
84 if (pop_time) {
85 vprintk(fmt, args);
86 pop_wait();
87 }
88
89 va_end(args);
90}
91
88/* create a new dapm widget */ 92/* create a new dapm widget */
89static inline struct snd_soc_dapm_widget *dapm_cnew_widget( 93static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
90 const struct snd_soc_dapm_widget *_widget) 94 const struct snd_soc_dapm_widget *_widget)
@@ -222,11 +226,12 @@ static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
222 change = old != new; 226 change = old != new;
223 if (change) { 227 if (change) {
224 pop_dbg("pop test %s : %s in %d ms\n", widget->name, 228 pop_dbg("pop test %s : %s in %d ms\n", widget->name,
225 widget->power ? "on" : "off", POP_TIME); 229 widget->power ? "on" : "off", pop_time);
226 snd_soc_write(codec, widget->reg, new); 230 snd_soc_write(codec, widget->reg, new);
227 pop_wait(POP_TIME); 231 pop_wait();
228 } 232 }
229 dbg("reg %x old %x new %x change %d\n", widget->reg, old, new, change); 233 pr_debug("reg %x old %x new %x change %d\n", widget->reg,
234 old, new, change);
230 return change; 235 return change;
231} 236}
232 237
@@ -448,6 +453,25 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
448} 453}
449 454
450/* 455/*
456 * Handler for generic register modifier widget.
457 */
458int dapm_reg_event(struct snd_soc_dapm_widget *w,
459 struct snd_kcontrol *kcontrol, int event)
460{
461 unsigned int val;
462
463 if (SND_SOC_DAPM_EVENT_ON(event))
464 val = w->on_val;
465 else
466 val = w->off_val;
467
468 snd_soc_update_bits(w->codec, -(w->reg + 1),
469 w->mask << w->shift, val << w->shift);
470
471 return 0;
472}
473
474/*
451 * Scan each dapm widget for complete audio path. 475 * Scan each dapm widget for complete audio path.
452 * A complete path is a route that has valid endpoints i.e.:- 476 * A complete path is a route that has valid endpoints i.e.:-
453 * 477 *
@@ -565,8 +589,8 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
565 /* call any power change event handlers */ 589 /* call any power change event handlers */
566 if (power_change) { 590 if (power_change) {
567 if (w->event) { 591 if (w->event) {
568 dbg("power %s event for %s flags %x\n", 592 pr_debug("power %s event for %s flags %x\n",
569 w->power ? "on" : "off", w->name, w->event_flags); 593 w->power ? "on" : "off", w->name, w->event_flags);
570 if (power) { 594 if (power) {
571 /* power up event */ 595 /* power up event */
572 if (w->event_flags & SND_SOC_DAPM_PRE_PMU) { 596 if (w->event_flags & SND_SOC_DAPM_PRE_PMU) {
@@ -608,7 +632,7 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
608 return ret; 632 return ret;
609} 633}
610 634
611#if DAPM_DEBUG 635#ifdef DEBUG
612static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) 636static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
613{ 637{
614 struct snd_soc_dapm_widget *w; 638 struct snd_soc_dapm_widget *w;
@@ -693,8 +717,10 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
693 path->connect = 0; /* old connection must be powered down */ 717 path->connect = 0; /* old connection must be powered down */
694 } 718 }
695 719
696 if (found) 720 if (found) {
697 dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); 721 dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
722 dump_dapm(widget->codec, "mux power update");
723 }
698 724
699 return 0; 725 return 0;
700} 726}
@@ -730,8 +756,10 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
730 break; 756 break;
731 } 757 }
732 758
733 if (found) 759 if (found) {
734 dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); 760 dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
761 dump_dapm(widget->codec, "mixer power update");
762 }
735 763
736 return 0; 764 return 0;
737} 765}
@@ -768,21 +796,18 @@ static ssize_t dapm_widget_show(struct device *dev,
768 } 796 }
769 } 797 }
770 798
771 switch(codec->dapm_state){ 799 switch (codec->bias_level) {
772 case SNDRV_CTL_POWER_D0: 800 case SND_SOC_BIAS_ON:
773 state = "D0"; 801 state = "On";
774 break; 802 break;
775 case SNDRV_CTL_POWER_D1: 803 case SND_SOC_BIAS_PREPARE:
776 state = "D1"; 804 state = "Prepare";
777 break; 805 break;
778 case SNDRV_CTL_POWER_D2: 806 case SND_SOC_BIAS_STANDBY:
779 state = "D2"; 807 state = "Standby";
780 break; 808 break;
781 case SNDRV_CTL_POWER_D3hot: 809 case SND_SOC_BIAS_OFF:
782 state = "D3hot"; 810 state = "Off";
783 break;
784 case SNDRV_CTL_POWER_D3cold:
785 state = "D3cold";
786 break; 811 break;
787 } 812 }
788 count += sprintf(buf + count, "PM State: %s\n", state); 813 count += sprintf(buf + count, "PM State: %s\n", state);
@@ -792,20 +817,51 @@ static ssize_t dapm_widget_show(struct device *dev,
792 817
793static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); 818static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
794 819
820/* pop/click delay times */
821static ssize_t dapm_pop_time_show(struct device *dev,
822 struct device_attribute *attr, char *buf)
823{
824 return sprintf(buf, "%d\n", pop_time);
825}
826
827static ssize_t dapm_pop_time_store(struct device *dev,
828 struct device_attribute *attr,
829 const char *buf, size_t count)
830
831{
832 unsigned long val;
833
834 if (strict_strtoul(buf, 10, &val) >= 0)
835 pop_time = val;
836 else
837 printk(KERN_ERR "Unable to parse pop_time setting\n");
838
839 return count;
840}
841
842static DEVICE_ATTR(dapm_pop_time, 0744, dapm_pop_time_show,
843 dapm_pop_time_store);
844
795int snd_soc_dapm_sys_add(struct device *dev) 845int snd_soc_dapm_sys_add(struct device *dev)
796{ 846{
797 int ret = 0; 847 int ret = 0;
798 848
799 if (dapm_status) 849 if (dapm_status) {
800 ret = device_create_file(dev, &dev_attr_dapm_widget); 850 ret = device_create_file(dev, &dev_attr_dapm_widget);
801 851
852 if (ret == 0)
853 ret = device_create_file(dev, &dev_attr_dapm_pop_time);
854 }
855
802 return ret; 856 return ret;
803} 857}
804 858
805static void snd_soc_dapm_sys_remove(struct device *dev) 859static void snd_soc_dapm_sys_remove(struct device *dev)
806{ 860{
807 if (dapm_status) 861 if (dapm_status) {
862 device_remove_file(dev, &dev_attr_dapm_pop_time);
808 device_remove_file(dev, &dev_attr_dapm_widget); 863 device_remove_file(dev, &dev_attr_dapm_widget);
864 }
809} 865}
810 866
811/* free all dapm widgets and resources */ 867/* free all dapm widgets and resources */
@@ -826,8 +882,25 @@ static void dapm_free_widgets(struct snd_soc_codec *codec)
826 } 882 }
827} 883}
828 884
885static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec,
886 char *pin, int status)
887{
888 struct snd_soc_dapm_widget *w;
889
890 list_for_each_entry(w, &codec->dapm_widgets, list) {
891 if (!strcmp(w->name, pin)) {
892 pr_debug("dapm: %s: pin %s\n", codec->name, pin);
893 w->connected = status;
894 return 0;
895 }
896 }
897
898 pr_err("dapm: %s: configuring unknown pin %s\n", codec->name, pin);
899 return -EINVAL;
900}
901
829/** 902/**
830 * snd_soc_dapm_sync_endpoints - scan and power dapm paths 903 * snd_soc_dapm_sync - scan and power dapm paths
831 * @codec: audio codec 904 * @codec: audio codec
832 * 905 *
833 * Walks all dapm audio paths and powers widgets according to their 906 * Walks all dapm audio paths and powers widgets according to their
@@ -835,27 +908,16 @@ static void dapm_free_widgets(struct snd_soc_codec *codec)
835 * 908 *
836 * Returns 0 for success. 909 * Returns 0 for success.
837 */ 910 */
838int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec) 911int snd_soc_dapm_sync(struct snd_soc_codec *codec)
839{ 912{
840 return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); 913 int ret = dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
914 dump_dapm(codec, "sync");
915 return ret;
841} 916}
842EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_endpoints); 917EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
843 918
844/** 919static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
845 * snd_soc_dapm_connect_input - connect dapm widgets 920 const char *sink, const char *control, const char *source)
846 * @codec: audio codec
847 * @sink: name of target widget
848 * @control: mixer control name
849 * @source: name of source name
850 *
851 * Connects 2 dapm widgets together via a named audio path. The sink is
852 * the widget receiving the audio signal, whilst the source is the sender
853 * of the audio signal.
854 *
855 * Returns 0 for success else error.
856 */
857int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink,
858 const char * control, const char *source)
859{ 921{
860 struct snd_soc_dapm_path *path; 922 struct snd_soc_dapm_path *path;
861 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; 923 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
@@ -957,9 +1019,64 @@ err:
957 kfree(path); 1019 kfree(path);
958 return ret; 1020 return ret;
959} 1021}
1022
1023/**
1024 * snd_soc_dapm_connect_input - connect dapm widgets
1025 * @codec: audio codec
1026 * @sink: name of target widget
1027 * @control: mixer control name
1028 * @source: name of source name
1029 *
1030 * Connects 2 dapm widgets together via a named audio path. The sink is
1031 * the widget receiving the audio signal, whilst the source is the sender
1032 * of the audio signal.
1033 *
1034 * This function has been deprecated in favour of snd_soc_dapm_add_routes().
1035 *
1036 * Returns 0 for success else error.
1037 */
1038int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink,
1039 const char *control, const char *source)
1040{
1041 return snd_soc_dapm_add_route(codec, sink, control, source);
1042}
960EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input); 1043EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input);
961 1044
962/** 1045/**
1046 * snd_soc_dapm_add_routes - Add routes between DAPM widgets
1047 * @codec: codec
1048 * @route: audio routes
1049 * @num: number of routes
1050 *
1051 * Connects 2 dapm widgets together via a named audio path. The sink is
1052 * the widget receiving the audio signal, whilst the source is the sender
1053 * of the audio signal.
1054 *
1055 * Returns 0 for success else error. On error all resources can be freed
1056 * with a call to snd_soc_card_free().
1057 */
1058int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
1059 const struct snd_soc_dapm_route *route, int num)
1060{
1061 int i, ret;
1062
1063 for (i = 0; i < num; i++) {
1064 ret = snd_soc_dapm_add_route(codec, route->sink,
1065 route->control, route->source);
1066 if (ret < 0) {
1067 printk(KERN_ERR "Failed to add route %s->%s\n",
1068 route->source,
1069 route->sink);
1070 return ret;
1071 }
1072 route++;
1073 }
1074
1075 return 0;
1076}
1077EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
1078
1079/**
963 * snd_soc_dapm_new_widgets - add new dapm widgets 1080 * snd_soc_dapm_new_widgets - add new dapm widgets
964 * @codec: audio codec 1081 * @codec: audio codec
965 * 1082 *
@@ -1234,6 +1351,33 @@ int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
1234EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); 1351EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
1235 1352
1236/** 1353/**
1354 * snd_soc_dapm_new_controls - create new dapm controls
1355 * @codec: audio codec
1356 * @widget: widget array
1357 * @num: number of widgets
1358 *
1359 * Creates new DAPM controls based upon the templates.
1360 *
1361 * Returns 0 for success else error.
1362 */
1363int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
1364 const struct snd_soc_dapm_widget *widget,
1365 int num)
1366{
1367 int i, ret;
1368
1369 for (i = 0; i < num; i++) {
1370 ret = snd_soc_dapm_new_control(codec, widget);
1371 if (ret < 0)
1372 return ret;
1373 widget++;
1374 }
1375 return 0;
1376}
1377EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
1378
1379
1380/**
1237 * snd_soc_dapm_stream_event - send a stream event to the dapm core 1381 * snd_soc_dapm_stream_event - send a stream event to the dapm core
1238 * @codec: audio codec 1382 * @codec: audio codec
1239 * @stream: stream name 1383 * @stream: stream name
@@ -1257,8 +1401,8 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
1257 { 1401 {
1258 if (!w->sname) 1402 if (!w->sname)
1259 continue; 1403 continue;
1260 dbg("widget %s\n %s stream %s event %d\n", w->name, w->sname, 1404 pr_debug("widget %s\n %s stream %s event %d\n",
1261 stream, event); 1405 w->name, w->sname, stream, event);
1262 if (strstr(w->sname, stream)) { 1406 if (strstr(w->sname, stream)) {
1263 switch(event) { 1407 switch(event) {
1264 case SND_SOC_DAPM_STREAM_START: 1408 case SND_SOC_DAPM_STREAM_START:
@@ -1294,53 +1438,81 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
1294EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); 1438EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
1295 1439
1296/** 1440/**
1297 * snd_soc_dapm_device_event - send a device event to the dapm core 1441 * snd_soc_dapm_set_bias_level - set the bias level for the system
1298 * @socdev: audio device 1442 * @socdev: audio device
1299 * @event: device event 1443 * @level: level to configure
1300 * 1444 *
1301 * Sends a device event to the dapm core. The core then makes any 1445 * Configure the bias (power) levels for the SoC audio device.
1302 * necessary machine or codec power changes..
1303 * 1446 *
1304 * Returns 0 for success else error. 1447 * Returns 0 for success else error.
1305 */ 1448 */
1306int snd_soc_dapm_device_event(struct snd_soc_device *socdev, int event) 1449int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
1450 enum snd_soc_bias_level level)
1307{ 1451{
1308 struct snd_soc_codec *codec = socdev->codec; 1452 struct snd_soc_codec *codec = socdev->codec;
1309 struct snd_soc_machine *machine = socdev->machine; 1453 struct snd_soc_machine *machine = socdev->machine;
1454 int ret = 0;
1310 1455
1311 if (machine->dapm_event) 1456 if (machine->set_bias_level)
1312 machine->dapm_event(machine, event); 1457 ret = machine->set_bias_level(machine, level);
1313 if (codec->dapm_event) 1458 if (ret == 0 && codec->set_bias_level)
1314 codec->dapm_event(codec, event); 1459 ret = codec->set_bias_level(codec, level);
1315 return 0; 1460
1461 return ret;
1316} 1462}
1317EXPORT_SYMBOL_GPL(snd_soc_dapm_device_event);
1318 1463
1319/** 1464/**
1320 * snd_soc_dapm_set_endpoint - set audio endpoint status 1465 * snd_soc_dapm_enable_pin - enable pin.
1466 * @snd_soc_codec: SoC codec
1467 * @pin: pin name
1468 *
1469 * Enables input/output pin and it's parents or children widgets iff there is
1470 * a valid audio route and active audio stream.
1471 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
1472 * do any widget power switching.
1473 */
1474int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin)
1475{
1476 return snd_soc_dapm_set_pin(codec, pin, 1);
1477}
1478EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
1479
1480/**
1481 * snd_soc_dapm_disable_pin - disable pin.
1482 * @codec: SoC codec
1483 * @pin: pin name
1484 *
1485 * Disables input/output pin and it's parents or children widgets.
1486 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
1487 * do any widget power switching.
1488 */
1489int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin)
1490{
1491 return snd_soc_dapm_set_pin(codec, pin, 0);
1492}
1493EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
1494
1495/**
1496 * snd_soc_dapm_get_pin_status - get audio pin status
1321 * @codec: audio codec 1497 * @codec: audio codec
1322 * @endpoint: audio signal endpoint (or start point) 1498 * @pin: audio signal pin endpoint (or start point)
1323 * @status: point status
1324 * 1499 *
1325 * Set audio endpoint status - connected or disconnected. 1500 * Get audio pin status - connected or disconnected.
1326 * 1501 *
1327 * Returns 0 for success else error. 1502 * Returns 1 for connected otherwise 0.
1328 */ 1503 */
1329int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec, 1504int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin)
1330 char *endpoint, int status)
1331{ 1505{
1332 struct snd_soc_dapm_widget *w; 1506 struct snd_soc_dapm_widget *w;
1333 1507
1334 list_for_each_entry(w, &codec->dapm_widgets, list) { 1508 list_for_each_entry(w, &codec->dapm_widgets, list) {
1335 if (!strcmp(w->name, endpoint)) { 1509 if (!strcmp(w->name, pin))
1336 w->connected = status; 1510 return w->connected;
1337 return 0;
1338 }
1339 } 1511 }
1340 1512
1341 return -ENODEV; 1513 return 0;
1342} 1514}
1343EXPORT_SYMBOL_GPL(snd_soc_dapm_set_endpoint); 1515EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
1344 1516
1345/** 1517/**
1346 * snd_soc_dapm_free - free dapm resources 1518 * snd_soc_dapm_free - free dapm resources