aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-dapm.c
diff options
context:
space:
mode:
authorLiam Girdwood <lrg@slimlogic.co.uk>2010-03-17 16:15:21 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-08-12 09:00:00 -0400
commitf0fba2ad1b6b53d5360125c41953b7afcd6deff0 (patch)
treef6ad50905f8daa616593c978d7ae992e73241180 /sound/soc/soc-dapm.c
parentbda7d2a862e6b788bca2d02d38a07966a9c92e48 (diff)
ASoC: multi-component - ASoC Multi-Component Support
This patch extends the ASoC API to allow sound cards to have more than one CODEC and more than one platform DMA controller. This is achieved by dividing some current ASoC structures that contain both driver data and device data into structures that only either contain device data or driver data. i.e. struct snd_soc_codec ---> struct snd_soc_codec (device data) +-> struct snd_soc_codec_driver (driver data) struct snd_soc_platform ---> struct snd_soc_platform (device data) +-> struct snd_soc_platform_driver (driver data) struct snd_soc_dai ---> struct snd_soc_dai (device data) +-> struct snd_soc_dai_driver (driver data) struct snd_soc_device ---> deleted This now allows ASoC to be more tightly aligned with the Linux driver model and also means that every ASoC codec, platform and (platform) DAI is a kernel device. ASoC component private data is now stored as device private data. The ASoC sound card struct snd_soc_card has also been updated to store lists of it's components rather than a pointer to a codec and platform. The PCM runtime struct soc_pcm_runtime now has pointers to all its components. This patch adds DAPM support for ASoC multi-component and removes struct snd_soc_socdev from DAPM core. All DAPM calls are now made on a card, codec or runtime PCM level basis rather than using snd_soc_socdev. Other notable multi-component changes:- * Stream operations now de-reference less structures. * close_delayed work() now runs on a DAI basis rather than looping all DAIs in a card. * PM suspend()/resume() operations can now handle N CODECs and Platforms per sound card. * Added soc_bind_dai_link() to bind the component devices to the sound card. * Added soc_dai_link_probe() and soc_dai_link_remove() to probe and remove DAI link components. * sysfs entries can now be registered per component per card. * snd_soc_new_pcms() functionailty rolled into dai_link_probe(). * snd_soc_register_codec() now does all the codec list and mutex init. This patch changes the probe() and remove() of the CODEC drivers as follows:- o Make CODEC driver a platform driver o Moved all struct snd_soc_codec list, mutex, etc initialiasation to core. o Removed all static codec pointers (drivers now support > 1 codec dev) o snd_soc_register_pcms() now done by core. o snd_soc_register_dai() folded into snd_soc_register_codec(). CS4270 portions: Acked-by: Timur Tabi <timur@freescale.com> Some TLV320aic23 and Cirrus platform fixes. Signed-off-by: Ryan Mallon <ryan@bluewatersys.com> TI CODEC and OMAP fixes Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Signed-off-by: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> Signed-off-by: Jarkko Nikula <jhnikula@gmail.com> Samsung platform and misc fixes :- Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Reviewed-by: Jassi Brar <jassi.brar@samsung.com> Signed-off-by: Seungwhan Youn <sw.youn@samsung.com> MPC8610 and PPC fixes. Signed-off-by: Timur Tabi <timur@freescale.com> i.MX fixes and some core fixes. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> J4740 platform fixes:- Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> CC: Tony Lindgren <tony@atomide.com> CC: Nicolas Ferre <nicolas.ferre@atmel.com> CC: Kevin Hilman <khilman@deeprootsystems.com> CC: Sascha Hauer <s.hauer@pengutronix.de> CC: Atsushi Nemoto <anemo@mba.ocn.ne.jp> CC: Kuninori Morimoto <morimoto.kuninori@renesas.com> CC: Daniel Gloeckner <dg@emlix.com> CC: Manuel Lauss <mano@roarinelk.homelinux.net> CC: Mike Frysinger <vapier.adi@gmail.com> CC: Arnaud Patard <apatard@mandriva.com> CC: Wan ZongShun <mcuos.com@gmail.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r--sound/soc/soc-dapm.c88
1 files changed, 45 insertions, 43 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 03cb7c05ebec..035cab85cb66 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -112,43 +112,41 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
112 112
113/** 113/**
114 * snd_soc_dapm_set_bias_level - set the bias level for the system 114 * snd_soc_dapm_set_bias_level - set the bias level for the system
115 * @socdev: audio device 115 * @card: audio device
116 * @level: level to configure 116 * @level: level to configure
117 * 117 *
118 * Configure the bias (power) levels for the SoC audio device. 118 * Configure the bias (power) levels for the SoC audio device.
119 * 119 *
120 * Returns 0 for success else error. 120 * Returns 0 for success else error.
121 */ 121 */
122static int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, 122static int snd_soc_dapm_set_bias_level(struct snd_soc_card *card,
123 enum snd_soc_bias_level level) 123 struct snd_soc_codec *codec, enum snd_soc_bias_level level)
124{ 124{
125 struct snd_soc_card *card = socdev->card;
126 struct snd_soc_codec *codec = socdev->card->codec;
127 int ret = 0; 125 int ret = 0;
128 126
129 switch (level) { 127 switch (level) {
130 case SND_SOC_BIAS_ON: 128 case SND_SOC_BIAS_ON:
131 dev_dbg(socdev->dev, "Setting full bias\n"); 129 dev_dbg(codec->dev, "Setting full bias\n");
132 break; 130 break;
133 case SND_SOC_BIAS_PREPARE: 131 case SND_SOC_BIAS_PREPARE:
134 dev_dbg(socdev->dev, "Setting bias prepare\n"); 132 dev_dbg(codec->dev, "Setting bias prepare\n");
135 break; 133 break;
136 case SND_SOC_BIAS_STANDBY: 134 case SND_SOC_BIAS_STANDBY:
137 dev_dbg(socdev->dev, "Setting standby bias\n"); 135 dev_dbg(codec->dev, "Setting standby bias\n");
138 break; 136 break;
139 case SND_SOC_BIAS_OFF: 137 case SND_SOC_BIAS_OFF:
140 dev_dbg(socdev->dev, "Setting bias off\n"); 138 dev_dbg(codec->dev, "Setting bias off\n");
141 break; 139 break;
142 default: 140 default:
143 dev_err(socdev->dev, "Setting invalid bias %d\n", level); 141 dev_err(codec->dev, "Setting invalid bias %d\n", level);
144 return -EINVAL; 142 return -EINVAL;
145 } 143 }
146 144
147 if (card->set_bias_level) 145 if (card && card->set_bias_level)
148 ret = card->set_bias_level(card, level); 146 ret = card->set_bias_level(card, level);
149 if (ret == 0) { 147 if (ret == 0) {
150 if (codec->set_bias_level) 148 if (codec->driver->set_bias_level)
151 ret = codec->set_bias_level(codec, level); 149 ret = codec->driver->set_bias_level(codec, level);
152 else 150 else
153 codec->bias_level = level; 151 codec->bias_level = level;
154 } 152 }
@@ -370,7 +368,7 @@ static int dapm_new_mixer(struct snd_soc_codec *codec,
370 368
371 path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, 369 path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
372 path->long_name); 370 path->long_name);
373 ret = snd_ctl_add(codec->card, path->kcontrol); 371 ret = snd_ctl_add(codec->card->snd_card, path->kcontrol);
374 if (ret < 0) { 372 if (ret < 0) {
375 printk(KERN_ERR "asoc: failed to add dapm kcontrol %s: %d\n", 373 printk(KERN_ERR "asoc: failed to add dapm kcontrol %s: %d\n",
376 path->long_name, 374 path->long_name,
@@ -398,7 +396,7 @@ static int dapm_new_mux(struct snd_soc_codec *codec,
398 } 396 }
399 397
400 kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name); 398 kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
401 ret = snd_ctl_add(codec->card, kcontrol); 399 ret = snd_ctl_add(codec->card->snd_card, kcontrol);
402 if (ret < 0) 400 if (ret < 0)
403 goto err; 401 goto err;
404 402
@@ -437,9 +435,9 @@ static inline void dapm_clear_walk(struct snd_soc_codec *codec)
437 */ 435 */
438static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget) 436static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
439{ 437{
440 struct snd_soc_codec *codec = widget->codec; 438 int level = snd_power_get_state(widget->codec->card->snd_card);
441 439
442 switch (snd_power_get_state(codec->card)) { 440 switch (level) {
443 case SNDRV_CTL_POWER_D3hot: 441 case SNDRV_CTL_POWER_D3hot:
444 case SNDRV_CTL_POWER_D3cold: 442 case SNDRV_CTL_POWER_D3cold:
445 if (widget->ignore_suspend) 443 if (widget->ignore_suspend)
@@ -893,7 +891,7 @@ static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list,
893 */ 891 */
894static int dapm_power_widgets(struct snd_soc_codec *codec, int event) 892static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
895{ 893{
896 struct snd_soc_device *socdev = codec->socdev; 894 struct snd_soc_card *card = codec->card;
897 struct snd_soc_dapm_widget *w; 895 struct snd_soc_dapm_widget *w;
898 LIST_HEAD(up_list); 896 LIST_HEAD(up_list);
899 LIST_HEAD(down_list); 897 LIST_HEAD(down_list);
@@ -966,7 +964,7 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
966 } 964 }
967 965
968 if (sys_power && codec->bias_level == SND_SOC_BIAS_OFF) { 966 if (sys_power && codec->bias_level == SND_SOC_BIAS_OFF) {
969 ret = snd_soc_dapm_set_bias_level(socdev, 967 ret = snd_soc_dapm_set_bias_level(card, codec,
970 SND_SOC_BIAS_STANDBY); 968 SND_SOC_BIAS_STANDBY);
971 if (ret != 0) 969 if (ret != 0)
972 pr_err("Failed to turn on bias: %d\n", ret); 970 pr_err("Failed to turn on bias: %d\n", ret);
@@ -975,8 +973,7 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
975 /* If we're changing to all on or all off then prepare */ 973 /* If we're changing to all on or all off then prepare */
976 if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) || 974 if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) ||
977 (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) { 975 (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) {
978 ret = snd_soc_dapm_set_bias_level(socdev, 976 ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_PREPARE);
979 SND_SOC_BIAS_PREPARE);
980 if (ret != 0) 977 if (ret != 0)
981 pr_err("Failed to prepare bias: %d\n", ret); 978 pr_err("Failed to prepare bias: %d\n", ret);
982 } 979 }
@@ -989,8 +986,7 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
989 986
990 /* If we just powered the last thing off drop to standby bias */ 987 /* If we just powered the last thing off drop to standby bias */
991 if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) { 988 if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) {
992 ret = snd_soc_dapm_set_bias_level(socdev, 989 ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_STANDBY);
993 SND_SOC_BIAS_STANDBY);
994 if (ret != 0) 990 if (ret != 0)
995 pr_err("Failed to apply standby bias: %d\n", ret); 991 pr_err("Failed to apply standby bias: %d\n", ret);
996 } 992 }
@@ -998,15 +994,14 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
998 /* If we're in standby and can support bias off then do that */ 994 /* If we're in standby and can support bias off then do that */
999 if (codec->bias_level == SND_SOC_BIAS_STANDBY && 995 if (codec->bias_level == SND_SOC_BIAS_STANDBY &&
1000 codec->idle_bias_off) { 996 codec->idle_bias_off) {
1001 ret = snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF); 997 ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_OFF);
1002 if (ret != 0) 998 if (ret != 0)
1003 pr_err("Failed to turn off bias: %d\n", ret); 999 pr_err("Failed to turn off bias: %d\n", ret);
1004 } 1000 }
1005 1001
1006 /* If we just powered up then move to active bias */ 1002 /* If we just powered up then move to active bias */
1007 if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) { 1003 if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) {
1008 ret = snd_soc_dapm_set_bias_level(socdev, 1004 ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_ON);
1009 SND_SOC_BIAS_ON);
1010 if (ret != 0) 1005 if (ret != 0)
1011 pr_err("Failed to apply active bias: %d\n", ret); 1006 pr_err("Failed to apply active bias: %d\n", ret);
1012 } 1007 }
@@ -1188,8 +1183,9 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
1188static ssize_t dapm_widget_show(struct device *dev, 1183static ssize_t dapm_widget_show(struct device *dev,
1189 struct device_attribute *attr, char *buf) 1184 struct device_attribute *attr, char *buf)
1190{ 1185{
1191 struct snd_soc_device *devdata = dev_get_drvdata(dev); 1186 struct snd_soc_pcm_runtime *rtd =
1192 struct snd_soc_codec *codec = devdata->card->codec; 1187 container_of(dev, struct snd_soc_pcm_runtime, dev);
1188 struct snd_soc_codec *codec =rtd->codec;
1193 struct snd_soc_dapm_widget *w; 1189 struct snd_soc_dapm_widget *w;
1194 int count = 0; 1190 int count = 0;
1195 char *state = "not set"; 1191 char *state = "not set";
@@ -1998,9 +1994,10 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
1998 * 1994 *
1999 * Returns 0 for success else error. 1995 * Returns 0 for success else error.
2000 */ 1996 */
2001int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, 1997int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
2002 char *stream, int event) 1998 const char *stream, int event)
2003{ 1999{
2000 struct snd_soc_codec *codec = rtd->codec;
2004 struct snd_soc_dapm_widget *w; 2001 struct snd_soc_dapm_widget *w;
2005 2002
2006 if (stream == NULL) 2003 if (stream == NULL)
@@ -2168,25 +2165,19 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
2168 2165
2169/** 2166/**
2170 * snd_soc_dapm_free - free dapm resources 2167 * snd_soc_dapm_free - free dapm resources
2171 * @socdev: SoC device 2168 * @card: SoC device
2172 * 2169 *
2173 * Free all dapm widgets and resources. 2170 * Free all dapm widgets and resources.
2174 */ 2171 */
2175void snd_soc_dapm_free(struct snd_soc_device *socdev) 2172void snd_soc_dapm_free(struct snd_soc_codec *codec)
2176{ 2173{
2177 struct snd_soc_codec *codec = socdev->card->codec; 2174 snd_soc_dapm_sys_remove(codec->dev);
2178
2179 snd_soc_dapm_sys_remove(socdev->dev);
2180 dapm_free_widgets(codec); 2175 dapm_free_widgets(codec);
2181} 2176}
2182EXPORT_SYMBOL_GPL(snd_soc_dapm_free); 2177EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
2183 2178
2184/* 2179static void soc_dapm_shutdown_codec(struct snd_soc_codec *codec)
2185 * snd_soc_dapm_shutdown - callback for system shutdown
2186 */
2187void snd_soc_dapm_shutdown(struct snd_soc_device *socdev)
2188{ 2180{
2189 struct snd_soc_codec *codec = socdev->card->codec;
2190 struct snd_soc_dapm_widget *w; 2181 struct snd_soc_dapm_widget *w;
2191 LIST_HEAD(down_list); 2182 LIST_HEAD(down_list);
2192 int powerdown = 0; 2183 int powerdown = 0;
@@ -2203,12 +2194,23 @@ void snd_soc_dapm_shutdown(struct snd_soc_device *socdev)
2203 * standby. 2194 * standby.
2204 */ 2195 */
2205 if (powerdown) { 2196 if (powerdown) {
2206 snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_PREPARE); 2197 snd_soc_dapm_set_bias_level(NULL, codec, SND_SOC_BIAS_PREPARE);
2207 dapm_seq_run(codec, &down_list, 0, dapm_down_seq); 2198 dapm_seq_run(codec, &down_list, 0, dapm_down_seq);
2208 snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_STANDBY); 2199 snd_soc_dapm_set_bias_level(NULL, codec, SND_SOC_BIAS_STANDBY);
2209 } 2200 }
2201}
2202
2203/*
2204 * snd_soc_dapm_shutdown - callback for system shutdown
2205 */
2206void snd_soc_dapm_shutdown(struct snd_soc_card *card)
2207{
2208 struct snd_soc_codec *codec;
2209
2210 list_for_each_entry(codec, &card->codec_dev_list, list)
2211 soc_dapm_shutdown_codec(codec);
2210 2212
2211 snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF); 2213 snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_OFF);
2212} 2214}
2213 2215
2214/* Module information */ 2216/* Module information */