aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2014-05-30 14:42:57 -0400
committerMark Brown <broonie@linaro.org>2014-06-03 05:41:16 -0400
commite1d4d3c854f25cff6c6c139588570e124d5e8fa4 (patch)
treed3fcf11a7912943e8924dae0ef82cb0a81f23be7 /sound/soc
parenta2fbbbf10d7a11a949c32625e7088ad46f3c4bbc (diff)
ASoC: free jack GPIOs before the sound card is freed
This is the same change as commit fb6b8e71448a "ASoC: tegra: free jack GPIOs before the sound card is freed", but applied to all other ASoC machine drivers where code inspection indicates the same problem exists. That commit's description is: ========== snd_soc_jack_add_gpios() schedules a work queue item to poll the GPIO to generate an initial jack status report. If sound card initialization fails, that work item needs to be cancelled, so it doesn't run after the card has been freed. Specifically, freeing the card calls snd_jack_dev_free() which calls snd_jack_dev_disconnect() which sets jack->input_dev = NULL, and input_dev is used by snd_jack_report(), which is called from the work queue item. snd_soc_jack_free_gpios() cancels the work item. The Tegra ASoC machine drivers do call this function in the platform driver remove() callback. However, this happens after the sound card is freed, at least when the card is freed due to errors late during snd_soc_instantiate_card(). This leaves a window where the work item can execute after the card is freed. In next-20140522, sound card initialization does fail for unrelated reasons, and hits the problem described above. To solve this, fix the Tegra ASoC machine drivers to clean up the Jack GPIOs during the snd_soc_card's .remove() callback, which is executed before the overall card object is freed. also, guard the cleanup call based on whether we actually setup up the GPIOs in the first place. Ideally, we'd do the cleanup in a struct snd_soc_dai_link .fini/remove function to match where the GPIOs get set up. However, there is no such callback. ========== Note that I have not even compile-tested this in most cases, since most of the drivers rely on specific mach-* support I don't have enabled, and don't support COMPILE_TEST. Testing by the relevant board maintainers would be useful. Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/omap/ams-delta.c14
-rw-r--r--sound/soc/omap/omap-twl4030.c28
-rw-r--r--sound/soc/omap/rx51.c18
-rw-r--r--sound/soc/pxa/hx4700.c9
-rw-r--r--sound/soc/samsung/h1940_uda1380.c11
-rw-r--r--sound/soc/samsung/rx1950_uda1380.c12
-rw-r--r--sound/soc/samsung/smartq_wm8987.c11
7 files changed, 69 insertions, 34 deletions
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index bb243c663e6b..1f41951d8b7f 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -527,6 +527,15 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
527 return 0; 527 return 0;
528} 528}
529 529
530static int ams_delta_card_remove(struct snd_soc_pcm_runtime *rtd)
531{
532 snd_soc_jack_free_gpios(&ams_delta_hook_switch,
533 ARRAY_SIZE(ams_delta_hook_switch_gpios),
534 ams_delta_hook_switch_gpios);
535
536 return 0;
537}
538
530/* DAI glue - connects codec <--> CPU */ 539/* DAI glue - connects codec <--> CPU */
531static struct snd_soc_dai_link ams_delta_dai_link = { 540static struct snd_soc_dai_link ams_delta_dai_link = {
532 .name = "CX20442", 541 .name = "CX20442",
@@ -543,6 +552,7 @@ static struct snd_soc_dai_link ams_delta_dai_link = {
543static struct snd_soc_card ams_delta_audio_card = { 552static struct snd_soc_card ams_delta_audio_card = {
544 .name = "AMS_DELTA", 553 .name = "AMS_DELTA",
545 .owner = THIS_MODULE, 554 .owner = THIS_MODULE,
555 .remove = ams_delta_card_remove,
546 .dai_link = &ams_delta_dai_link, 556 .dai_link = &ams_delta_dai_link,
547 .num_links = 1, 557 .num_links = 1,
548 558
@@ -579,10 +589,6 @@ static int ams_delta_remove(struct platform_device *pdev)
579 dev_warn(&pdev->dev, 589 dev_warn(&pdev->dev,
580 "failed to unregister V253 line discipline\n"); 590 "failed to unregister V253 line discipline\n");
581 591
582 snd_soc_jack_free_gpios(&ams_delta_hook_switch,
583 ARRAY_SIZE(ams_delta_hook_switch_gpios),
584 ams_delta_hook_switch_gpios);
585
586 snd_soc_unregister_card(card); 592 snd_soc_unregister_card(card);
587 card->dev = NULL; 593 card->dev = NULL;
588 return 0; 594 return 0;
diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c
index 64141db311b2..b4e282871658 100644
--- a/sound/soc/omap/omap-twl4030.c
+++ b/sound/soc/omap/omap-twl4030.c
@@ -231,6 +231,19 @@ static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd)
231 return ret; 231 return ret;
232} 232}
233 233
234static int omap_twl4030_card_remove(struct snd_soc_pcm_runtime *rtd)
235{
236 struct snd_soc_card *card = rtd->card;
237 struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card);
238
239 if (priv->jack_detect > 0)
240 snd_soc_jack_free_gpios(&priv->hs_jack,
241 ARRAY_SIZE(hs_jack_gpios),
242 hs_jack_gpios);
243
244 return 0;
245}
246
234/* Digital audio interface glue - connects codec <--> CPU */ 247/* Digital audio interface glue - connects codec <--> CPU */
235static struct snd_soc_dai_link omap_twl4030_dai_links[] = { 248static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
236 { 249 {
@@ -258,6 +271,7 @@ static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
258/* Audio machine driver */ 271/* Audio machine driver */
259static struct snd_soc_card omap_twl4030_card = { 272static struct snd_soc_card omap_twl4030_card = {
260 .owner = THIS_MODULE, 273 .owner = THIS_MODULE,
274 .remove = omap_twl4030_card_remove,
261 .dai_link = omap_twl4030_dai_links, 275 .dai_link = omap_twl4030_dai_links,
262 .num_links = ARRAY_SIZE(omap_twl4030_dai_links), 276 .num_links = ARRAY_SIZE(omap_twl4030_dai_links),
263 277
@@ -353,19 +367,6 @@ static int omap_twl4030_probe(struct platform_device *pdev)
353 return 0; 367 return 0;
354} 368}
355 369
356static int omap_twl4030_remove(struct platform_device *pdev)
357{
358 struct snd_soc_card *card = platform_get_drvdata(pdev);
359 struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card);
360
361 if (priv->jack_detect > 0)
362 snd_soc_jack_free_gpios(&priv->hs_jack,
363 ARRAY_SIZE(hs_jack_gpios),
364 hs_jack_gpios);
365
366 return 0;
367}
368
369static const struct of_device_id omap_twl4030_of_match[] = { 370static const struct of_device_id omap_twl4030_of_match[] = {
370 {.compatible = "ti,omap-twl4030", }, 371 {.compatible = "ti,omap-twl4030", },
371 { }, 372 { },
@@ -380,7 +381,6 @@ static struct platform_driver omap_twl4030_driver = {
380 .of_match_table = omap_twl4030_of_match, 381 .of_match_table = omap_twl4030_of_match,
381 }, 382 },
382 .probe = omap_twl4030_probe, 383 .probe = omap_twl4030_probe,
383 .remove = omap_twl4030_remove,
384}; 384};
385 385
386module_platform_driver(omap_twl4030_driver); 386module_platform_driver(omap_twl4030_driver);
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 6951dc812055..47a10290535b 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -334,6 +334,14 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
334 return err; 334 return err;
335} 335}
336 336
337static int rx51_card_remove(struct snd_soc_pcm_runtime *rtd)
338{
339 snd_soc_jack_free_gpios(&rx51_av_jack, ARRAY_SIZE(rx51_av_jack_gpios),
340 rx51_av_jack_gpios);
341
342 return 0;
343}
344
337/* Digital audio interface glue - connects codec <--> CPU */ 345/* Digital audio interface glue - connects codec <--> CPU */
338static struct snd_soc_dai_link rx51_dai[] = { 346static struct snd_soc_dai_link rx51_dai[] = {
339 { 347 {
@@ -368,6 +376,7 @@ static struct snd_soc_codec_conf rx51_codec_conf[] = {
368static struct snd_soc_card rx51_sound_card = { 376static struct snd_soc_card rx51_sound_card = {
369 .name = "RX-51", 377 .name = "RX-51",
370 .owner = THIS_MODULE, 378 .owner = THIS_MODULE,
379 .remove = rx51_card_remove,
371 .dai_link = rx51_dai, 380 .dai_link = rx51_dai,
372 .num_links = ARRAY_SIZE(rx51_dai), 381 .num_links = ARRAY_SIZE(rx51_dai),
373 .aux_dev = rx51_aux_dev, 382 .aux_dev = rx51_aux_dev,
@@ -499,14 +508,6 @@ static int rx51_soc_probe(struct platform_device *pdev)
499 return 0; 508 return 0;
500} 509}
501 510
502static int rx51_soc_remove(struct platform_device *pdev)
503{
504 snd_soc_jack_free_gpios(&rx51_av_jack, ARRAY_SIZE(rx51_av_jack_gpios),
505 rx51_av_jack_gpios);
506
507 return 0;
508}
509
510#if defined(CONFIG_OF) 511#if defined(CONFIG_OF)
511static const struct of_device_id rx51_audio_of_match[] = { 512static const struct of_device_id rx51_audio_of_match[] = {
512 { .compatible = "nokia,n900-audio", }, 513 { .compatible = "nokia,n900-audio", },
@@ -522,7 +523,6 @@ static struct platform_driver rx51_soc_driver = {
522 .of_match_table = of_match_ptr(rx51_audio_of_match), 523 .of_match_table = of_match_ptr(rx51_audio_of_match),
523 }, 524 },
524 .probe = rx51_soc_probe, 525 .probe = rx51_soc_probe,
525 .remove = rx51_soc_remove,
526}; 526};
527 527
528module_platform_driver(rx51_soc_driver); 528module_platform_driver(rx51_soc_driver);
diff --git a/sound/soc/pxa/hx4700.c b/sound/soc/pxa/hx4700.c
index dcc9b04bd92c..6b81acaffddd 100644
--- a/sound/soc/pxa/hx4700.c
+++ b/sound/soc/pxa/hx4700.c
@@ -152,6 +152,13 @@ static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd)
152 return err; 152 return err;
153} 153}
154 154
155static int hx4700_card_remove(struct snd_soc_pcm_runtime *rtd)
156{
157 snd_soc_jack_free_gpios(&hs_jack, 1, &hs_jack_gpio);
158
159 return 0;
160}
161
155/* hx4700 digital audio interface glue - connects codec <--> CPU */ 162/* hx4700 digital audio interface glue - connects codec <--> CPU */
156static struct snd_soc_dai_link hx4700_dai = { 163static struct snd_soc_dai_link hx4700_dai = {
157 .name = "ak4641", 164 .name = "ak4641",
@@ -170,6 +177,7 @@ static struct snd_soc_dai_link hx4700_dai = {
170static struct snd_soc_card snd_soc_card_hx4700 = { 177static struct snd_soc_card snd_soc_card_hx4700 = {
171 .name = "iPAQ hx4700", 178 .name = "iPAQ hx4700",
172 .owner = THIS_MODULE, 179 .owner = THIS_MODULE,
180 .remove = hx4700_card_remove,
173 .dai_link = &hx4700_dai, 181 .dai_link = &hx4700_dai,
174 .num_links = 1, 182 .num_links = 1,
175 .dapm_widgets = hx4700_dapm_widgets, 183 .dapm_widgets = hx4700_dapm_widgets,
@@ -206,7 +214,6 @@ static int hx4700_audio_probe(struct platform_device *pdev)
206 214
207static int hx4700_audio_remove(struct platform_device *pdev) 215static int hx4700_audio_remove(struct platform_device *pdev)
208{ 216{
209 snd_soc_jack_free_gpios(&hs_jack, 1, &hs_jack_gpio);
210 snd_soc_unregister_card(&snd_soc_card_hx4700); 217 snd_soc_unregister_card(&snd_soc_card_hx4700);
211 218
212 gpio_set_value(GPIO92_HX4700_HP_DRIVER, 0); 219 gpio_set_value(GPIO92_HX4700_HP_DRIVER, 0);
diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c
index 9f2fb69dbaae..720357f11a7f 100644
--- a/sound/soc/samsung/h1940_uda1380.c
+++ b/sound/soc/samsung/h1940_uda1380.c
@@ -189,6 +189,14 @@ static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd)
189 return 0; 189 return 0;
190} 190}
191 191
192static int h1940_uda1380_card_remove(struct snd_soc_pcm_runtime *rtd)
193{
194 snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
195 hp_jack_gpios);
196
197 return 0;
198}
199
192/* s3c24xx digital audio interface glue - connects codec <--> CPU */ 200/* s3c24xx digital audio interface glue - connects codec <--> CPU */
193static struct snd_soc_dai_link h1940_uda1380_dai[] = { 201static struct snd_soc_dai_link h1940_uda1380_dai[] = {
194 { 202 {
@@ -206,6 +214,7 @@ static struct snd_soc_dai_link h1940_uda1380_dai[] = {
206static struct snd_soc_card h1940_asoc = { 214static struct snd_soc_card h1940_asoc = {
207 .name = "h1940", 215 .name = "h1940",
208 .owner = THIS_MODULE, 216 .owner = THIS_MODULE,
217 .remove = h1940_uda1380_card_remove,
209 .dai_link = h1940_uda1380_dai, 218 .dai_link = h1940_uda1380_dai,
210 .num_links = ARRAY_SIZE(h1940_uda1380_dai), 219 .num_links = ARRAY_SIZE(h1940_uda1380_dai),
211 220
@@ -257,8 +266,6 @@ err_out:
257static void __exit h1940_exit(void) 266static void __exit h1940_exit(void)
258{ 267{
259 platform_device_unregister(s3c24xx_snd_device); 268 platform_device_unregister(s3c24xx_snd_device);
260 snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
261 hp_jack_gpios);
262 gpio_free(S3C_GPIO_END + 9); 269 gpio_free(S3C_GPIO_END + 9);
263} 270}
264 271
diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c
index 5b3e504d3a32..192aa9fc102f 100644
--- a/sound/soc/samsung/rx1950_uda1380.c
+++ b/sound/soc/samsung/rx1950_uda1380.c
@@ -31,6 +31,7 @@
31#include "s3c24xx-i2s.h" 31#include "s3c24xx-i2s.h"
32 32
33static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd); 33static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd);
34static int rx1950_uda1380_card_remove(struct snd_soc_pcm_runtime *rtd);
34static int rx1950_startup(struct snd_pcm_substream *substream); 35static int rx1950_startup(struct snd_pcm_substream *substream);
35static int rx1950_hw_params(struct snd_pcm_substream *substream, 36static int rx1950_hw_params(struct snd_pcm_substream *substream,
36 struct snd_pcm_hw_params *params); 37 struct snd_pcm_hw_params *params);
@@ -116,6 +117,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
116static struct snd_soc_card rx1950_asoc = { 117static struct snd_soc_card rx1950_asoc = {
117 .name = "rx1950", 118 .name = "rx1950",
118 .owner = THIS_MODULE, 119 .owner = THIS_MODULE,
120 .remove = rx1950_uda1380_card_remove,
119 .dai_link = rx1950_uda1380_dai, 121 .dai_link = rx1950_uda1380_dai,
120 .num_links = ARRAY_SIZE(rx1950_uda1380_dai), 122 .num_links = ARRAY_SIZE(rx1950_uda1380_dai),
121 123
@@ -234,6 +236,14 @@ static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
234 return 0; 236 return 0;
235} 237}
236 238
239static int rx1950_uda1380_card_remove(struct snd_soc_pcm_runtime *rtd)
240{
241 snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
242 hp_jack_gpios);
243
244 return 0;
245}
246
237static int __init rx1950_init(void) 247static int __init rx1950_init(void)
238{ 248{
239 int ret; 249 int ret;
@@ -278,8 +288,6 @@ err_gpio:
278static void __exit rx1950_exit(void) 288static void __exit rx1950_exit(void)
279{ 289{
280 platform_device_unregister(s3c24xx_snd_device); 290 platform_device_unregister(s3c24xx_snd_device);
281 snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
282 hp_jack_gpios);
283 gpio_free(S3C2410_GPA(1)); 291 gpio_free(S3C2410_GPA(1));
284} 292}
285 293
diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c
index df55db5d3554..271a904277a1 100644
--- a/sound/soc/samsung/smartq_wm8987.c
+++ b/sound/soc/samsung/smartq_wm8987.c
@@ -182,6 +182,14 @@ static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd)
182 return err; 182 return err;
183} 183}
184 184
185static int smartq_wm8987_card_remove(struct snd_soc_pcm_runtime *rtd)
186{
187 snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios),
188 smartq_jack_gpios);
189
190 return 0;
191}
192
185static struct snd_soc_dai_link smartq_dai[] = { 193static struct snd_soc_dai_link smartq_dai[] = {
186 { 194 {
187 .name = "wm8987", 195 .name = "wm8987",
@@ -198,6 +206,7 @@ static struct snd_soc_dai_link smartq_dai[] = {
198static struct snd_soc_card snd_soc_smartq = { 206static struct snd_soc_card snd_soc_smartq = {
199 .name = "SmartQ", 207 .name = "SmartQ",
200 .owner = THIS_MODULE, 208 .owner = THIS_MODULE,
209 .remove = smartq_wm8987_card_remove,
201 .dai_link = smartq_dai, 210 .dai_link = smartq_dai,
202 .num_links = ARRAY_SIZE(smartq_dai), 211 .num_links = ARRAY_SIZE(smartq_dai),
203 212
@@ -259,8 +268,6 @@ err_unregister_device:
259static void __exit smartq_exit(void) 268static void __exit smartq_exit(void)
260{ 269{
261 gpio_free(S3C64XX_GPK(12)); 270 gpio_free(S3C64XX_GPK(12));
262 snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios),
263 smartq_jack_gpios);
264 271
265 platform_device_unregister(smartq_snd_device); 272 platform_device_unregister(smartq_snd_device);
266} 273}