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.c274
1 files changed, 79 insertions, 195 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index c8a780d0d057..a74b9bf23d9f 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -254,7 +254,6 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
254static void dapm_kcontrol_free(struct snd_kcontrol *kctl) 254static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
255{ 255{
256 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl); 256 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
257 kfree(data->widget);
258 kfree(data->wlist); 257 kfree(data->wlist);
259 kfree(data); 258 kfree(data);
260} 259}
@@ -379,86 +378,24 @@ static void dapm_reset(struct snd_soc_card *card)
379static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg, 378static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg,
380 unsigned int *value) 379 unsigned int *value)
381{ 380{
382 if (w->codec) { 381 if (!w->dapm->component)
383 *value = snd_soc_read(w->codec, reg); 382 return -EIO;
384 return 0; 383 return snd_soc_component_read(w->dapm->component, reg, value);
385 } else if (w->platform) {
386 *value = snd_soc_platform_read(w->platform, reg);
387 return 0;
388 }
389
390 dev_err(w->dapm->dev, "ASoC: no valid widget read method\n");
391 return -1;
392}
393
394static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg,
395 unsigned int val)
396{
397 if (w->codec)
398 return snd_soc_write(w->codec, reg, val);
399 else if (w->platform)
400 return snd_soc_platform_write(w->platform, reg, val);
401
402 dev_err(w->dapm->dev, "ASoC: no valid widget write method\n");
403 return -1;
404}
405
406static inline void soc_widget_lock(struct snd_soc_dapm_widget *w)
407{
408 if (w->codec && !w->codec->using_regmap)
409 mutex_lock(&w->codec->mutex);
410 else if (w->platform)
411 mutex_lock(&w->platform->mutex);
412} 384}
413 385
414static inline void soc_widget_unlock(struct snd_soc_dapm_widget *w) 386static int soc_widget_update_bits(struct snd_soc_dapm_widget *w,
387 int reg, unsigned int mask, unsigned int value)
415{ 388{
416 if (w->codec && !w->codec->using_regmap) 389 if (!w->dapm->component)
417 mutex_unlock(&w->codec->mutex); 390 return -EIO;
418 else if (w->platform) 391 return snd_soc_component_update_bits_async(w->dapm->component, reg,
419 mutex_unlock(&w->platform->mutex); 392 mask, value);
420} 393}
421 394
422static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm) 395static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
423{ 396{
424 if (dapm->codec && dapm->codec->using_regmap) 397 if (dapm->component)
425 regmap_async_complete(dapm->codec->control_data); 398 snd_soc_component_async_complete(dapm->component);
426}
427
428static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w,
429 unsigned short reg, unsigned int mask, unsigned int value)
430{
431 bool change;
432 unsigned int old, new;
433 int ret;
434
435 if (w->codec && w->codec->using_regmap) {
436 ret = regmap_update_bits_check_async(w->codec->control_data,
437 reg, mask, value,
438 &change);
439 if (ret != 0)
440 return ret;
441 } else {
442 soc_widget_lock(w);
443 ret = soc_widget_read(w, reg, &old);
444 if (ret < 0) {
445 soc_widget_unlock(w);
446 return ret;
447 }
448
449 new = (old & ~mask) | (value & mask);
450 change = old != new;
451 if (change) {
452 ret = soc_widget_write(w, reg, new);
453 if (ret < 0) {
454 soc_widget_unlock(w);
455 return ret;
456 }
457 }
458 soc_widget_unlock(w);
459 }
460
461 return change;
462} 399}
463 400
464/** 401/**
@@ -1121,26 +1058,6 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
1121} 1058}
1122 1059
1123/* 1060/*
1124 * Handler for generic register modifier widget.
1125 */
1126int dapm_reg_event(struct snd_soc_dapm_widget *w,
1127 struct snd_kcontrol *kcontrol, int event)
1128{
1129 unsigned int val;
1130
1131 if (SND_SOC_DAPM_EVENT_ON(event))
1132 val = w->on_val;
1133 else
1134 val = w->off_val;
1135
1136 soc_widget_update_bits_locked(w, -(w->reg + 1),
1137 w->mask << w->shift, val << w->shift);
1138
1139 return 0;
1140}
1141EXPORT_SYMBOL_GPL(dapm_reg_event);
1142
1143/*
1144 * Handler for regulator supply widget. 1061 * Handler for regulator supply widget.
1145 */ 1062 */
1146int dapm_regulator_event(struct snd_soc_dapm_widget *w, 1063int dapm_regulator_event(struct snd_soc_dapm_widget *w,
@@ -1429,7 +1346,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_card *card,
1429 "pop test : Applying 0x%x/0x%x to %x in %dms\n", 1346 "pop test : Applying 0x%x/0x%x to %x in %dms\n",
1430 value, mask, reg, card->pop_time); 1347 value, mask, reg, card->pop_time);
1431 pop_wait(card->pop_time); 1348 pop_wait(card->pop_time);
1432 soc_widget_update_bits_locked(w, reg, mask, value); 1349 soc_widget_update_bits(w, reg, mask, value);
1433 } 1350 }
1434 1351
1435 list_for_each_entry(w, pending, power_list) { 1352 list_for_each_entry(w, pending, power_list) {
@@ -1575,8 +1492,7 @@ static void dapm_widget_update(struct snd_soc_card *card)
1575 if (!w) 1492 if (!w)
1576 return; 1493 return;
1577 1494
1578 ret = soc_widget_update_bits_locked(w, update->reg, update->mask, 1495 ret = soc_widget_update_bits(w, update->reg, update->mask, update->val);
1579 update->val);
1580 if (ret < 0) 1496 if (ret < 0)
1581 dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n", 1497 dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
1582 w->name, ret); 1498 w->name, ret);
@@ -1613,8 +1529,11 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
1613 "ASoC: Failed to turn on bias: %d\n", ret); 1529 "ASoC: Failed to turn on bias: %d\n", ret);
1614 } 1530 }
1615 1531
1616 /* Prepare for a STADDBY->ON or ON->STANDBY transition */ 1532 /* Prepare for a transition to ON or away from ON */
1617 if (d->bias_level != d->target_bias_level) { 1533 if ((d->target_bias_level == SND_SOC_BIAS_ON &&
1534 d->bias_level != SND_SOC_BIAS_ON) ||
1535 (d->target_bias_level != SND_SOC_BIAS_ON &&
1536 d->bias_level == SND_SOC_BIAS_ON)) {
1618 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE); 1537 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
1619 if (ret != 0) 1538 if (ret != 0)
1620 dev_err(d->dev, 1539 dev_err(d->dev,
@@ -2444,8 +2363,7 @@ err:
2444} 2363}
2445 2364
2446static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, 2365static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
2447 const struct snd_soc_dapm_route *route, 2366 const struct snd_soc_dapm_route *route)
2448 unsigned int is_prefixed)
2449{ 2367{
2450 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; 2368 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
2451 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL; 2369 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
@@ -2455,7 +2373,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
2455 char prefixed_source[80]; 2373 char prefixed_source[80];
2456 int ret; 2374 int ret;
2457 2375
2458 if (dapm->codec && dapm->codec->name_prefix && !is_prefixed) { 2376 if (dapm->codec && dapm->codec->name_prefix) {
2459 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", 2377 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
2460 dapm->codec->name_prefix, route->sink); 2378 dapm->codec->name_prefix, route->sink);
2461 sink = prefixed_sink; 2379 sink = prefixed_sink;
@@ -2583,7 +2501,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
2583 2501
2584 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); 2502 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
2585 for (i = 0; i < num; i++) { 2503 for (i = 0; i < num; i++) {
2586 r = snd_soc_dapm_add_route(dapm, route, false); 2504 r = snd_soc_dapm_add_route(dapm, route);
2587 if (r < 0) { 2505 if (r < 0) {
2588 dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n", 2506 dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n",
2589 route->source, 2507 route->source,
@@ -2855,22 +2773,19 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
2855 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); 2773 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
2856 2774
2857 change = dapm_kcontrol_set_value(kcontrol, val); 2775 change = dapm_kcontrol_set_value(kcontrol, val);
2858
2859 if (reg != SND_SOC_NOPM) {
2860 mask = mask << shift;
2861 val = val << shift;
2862
2863 change = snd_soc_test_bits(codec, reg, mask, val);
2864 }
2865
2866 if (change) { 2776 if (change) {
2867 if (reg != SND_SOC_NOPM) { 2777 if (reg != SND_SOC_NOPM) {
2868 update.kcontrol = kcontrol; 2778 mask = mask << shift;
2869 update.reg = reg; 2779 val = val << shift;
2870 update.mask = mask; 2780
2871 update.val = val; 2781 if (snd_soc_test_bits(codec, reg, mask, val)) {
2782 update.kcontrol = kcontrol;
2783 update.reg = reg;
2784 update.mask = mask;
2785 update.val = val;
2786 card->update = &update;
2787 }
2872 2788
2873 card->update = &update;
2874 } 2789 }
2875 2790
2876 ret = soc_dapm_mixer_update_power(card, kcontrol, connect); 2791 ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
@@ -3309,11 +3224,11 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
3309 struct snd_soc_dapm_widget *source, 3224 struct snd_soc_dapm_widget *source,
3310 struct snd_soc_dapm_widget *sink) 3225 struct snd_soc_dapm_widget *sink)
3311{ 3226{
3312 struct snd_soc_dapm_route routes[2];
3313 struct snd_soc_dapm_widget template; 3227 struct snd_soc_dapm_widget template;
3314 struct snd_soc_dapm_widget *w; 3228 struct snd_soc_dapm_widget *w;
3315 size_t len; 3229 size_t len;
3316 char *link_name; 3230 char *link_name;
3231 int ret;
3317 3232
3318 len = strlen(source->name) + strlen(sink->name) + 2; 3233 len = strlen(source->name) + strlen(sink->name) + 2;
3319 link_name = devm_kzalloc(card->dev, len, GFP_KERNEL); 3234 link_name = devm_kzalloc(card->dev, len, GFP_KERNEL);
@@ -3340,15 +3255,10 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
3340 3255
3341 w->params = params; 3256 w->params = params;
3342 3257
3343 memset(&routes, 0, sizeof(routes)); 3258 ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL);
3344 3259 if (ret)
3345 routes[0].source = source->name; 3260 return ret;
3346 routes[0].sink = link_name; 3261 return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL);
3347 routes[1].source = link_name;
3348 routes[1].sink = sink->name;
3349
3350 return snd_soc_dapm_add_routes(&card->dapm, routes,
3351 ARRAY_SIZE(routes));
3352} 3262}
3353 3263
3354int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, 3264int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
@@ -3406,6 +3316,7 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
3406int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) 3316int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
3407{ 3317{
3408 struct snd_soc_dapm_widget *dai_w, *w; 3318 struct snd_soc_dapm_widget *dai_w, *w;
3319 struct snd_soc_dapm_widget *src, *sink;
3409 struct snd_soc_dai *dai; 3320 struct snd_soc_dai *dai;
3410 3321
3411 /* For each DAI widget... */ 3322 /* For each DAI widget... */
@@ -3436,25 +3347,15 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
3436 if (!w->sname || !strstr(w->sname, dai_w->name)) 3347 if (!w->sname || !strstr(w->sname, dai_w->name))
3437 continue; 3348 continue;
3438 3349
3439 if (dai->driver->playback.stream_name && 3350 if (dai_w->id == snd_soc_dapm_dai_in) {
3440 strstr(w->sname, 3351 src = dai_w;
3441 dai->driver->playback.stream_name)) { 3352 sink = w;
3442 dev_dbg(dai->dev, "%s -> %s\n", 3353 } else {
3443 dai->playback_widget->name, w->name); 3354 src = w;
3444 3355 sink = dai_w;
3445 snd_soc_dapm_add_path(w->dapm,
3446 dai->playback_widget, w, NULL, NULL);
3447 }
3448
3449 if (dai->driver->capture.stream_name &&
3450 strstr(w->sname,
3451 dai->driver->capture.stream_name)) {
3452 dev_dbg(dai->dev, "%s -> %s\n",
3453 w->name, dai->capture_widget->name);
3454
3455 snd_soc_dapm_add_path(w->dapm, w,
3456 dai->capture_widget, NULL, NULL);
3457 } 3356 }
3357 dev_dbg(dai->dev, "%s -> %s\n", src->name, sink->name);
3358 snd_soc_dapm_add_path(w->dapm, src, sink, NULL, NULL);
3458 } 3359 }
3459 } 3360 }
3460 3361
@@ -3464,20 +3365,21 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
3464void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) 3365void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
3465{ 3366{
3466 struct snd_soc_pcm_runtime *rtd = card->rtd; 3367 struct snd_soc_pcm_runtime *rtd = card->rtd;
3368 struct snd_soc_dapm_widget *sink, *source;
3467 struct snd_soc_dai *cpu_dai, *codec_dai; 3369 struct snd_soc_dai *cpu_dai, *codec_dai;
3468 struct snd_soc_dapm_route r;
3469 int i; 3370 int i;
3470 3371
3471 memset(&r, 0, sizeof(r));
3472
3473 /* for each BE DAI link... */ 3372 /* for each BE DAI link... */
3474 for (i = 0; i < card->num_rtd; i++) { 3373 for (i = 0; i < card->num_rtd; i++) {
3475 rtd = &card->rtd[i]; 3374 rtd = &card->rtd[i];
3476 cpu_dai = rtd->cpu_dai; 3375 cpu_dai = rtd->cpu_dai;
3477 codec_dai = rtd->codec_dai; 3376 codec_dai = rtd->codec_dai;
3478 3377
3479 /* dynamic FE links have no fixed DAI mapping */ 3378 /*
3480 if (rtd->dai_link->dynamic) 3379 * dynamic FE links have no fixed DAI mapping.
3380 * CODEC<->CODEC links have no direct connection.
3381 */
3382 if (rtd->dai_link->dynamic || rtd->dai_link->params)
3481 continue; 3383 continue;
3482 3384
3483 /* there is no point in connecting BE DAI links with dummies */ 3385 /* there is no point in connecting BE DAI links with dummies */
@@ -3487,55 +3389,49 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
3487 3389
3488 /* connect BE DAI playback if widgets are valid */ 3390 /* connect BE DAI playback if widgets are valid */
3489 if (codec_dai->playback_widget && cpu_dai->playback_widget) { 3391 if (codec_dai->playback_widget && cpu_dai->playback_widget) {
3490 r.source = cpu_dai->playback_widget->name; 3392 source = cpu_dai->playback_widget;
3491 r.sink = codec_dai->playback_widget->name; 3393 sink = codec_dai->playback_widget;
3492 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", 3394 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
3493 cpu_dai->codec->name, r.source, 3395 cpu_dai->codec->name, source->name,
3494 codec_dai->platform->name, r.sink); 3396 codec_dai->platform->name, sink->name);
3495 3397
3496 snd_soc_dapm_add_route(&card->dapm, &r, true); 3398 snd_soc_dapm_add_path(&card->dapm, source, sink,
3399 NULL, NULL);
3497 } 3400 }
3498 3401
3499 /* connect BE DAI capture if widgets are valid */ 3402 /* connect BE DAI capture if widgets are valid */
3500 if (codec_dai->capture_widget && cpu_dai->capture_widget) { 3403 if (codec_dai->capture_widget && cpu_dai->capture_widget) {
3501 r.source = codec_dai->capture_widget->name; 3404 source = codec_dai->capture_widget;
3502 r.sink = cpu_dai->capture_widget->name; 3405 sink = cpu_dai->capture_widget;
3503 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", 3406 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
3504 codec_dai->codec->name, r.source, 3407 codec_dai->codec->name, source->name,
3505 cpu_dai->platform->name, r.sink); 3408 cpu_dai->platform->name, sink->name);
3506 3409
3507 snd_soc_dapm_add_route(&card->dapm, &r, true); 3410 snd_soc_dapm_add_path(&card->dapm, source, sink,
3411 NULL, NULL);
3508 } 3412 }
3509
3510 } 3413 }
3511} 3414}
3512 3415
3513static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, 3416static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
3514 int event) 3417 int event)
3515{ 3418{
3419 struct snd_soc_dapm_widget *w;
3516 3420
3517 struct snd_soc_dapm_widget *w_cpu, *w_codec; 3421 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
3518 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 3422 w = dai->playback_widget;
3519 struct snd_soc_dai *codec_dai = rtd->codec_dai; 3423 else
3520 3424 w = dai->capture_widget;
3521 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
3522 w_cpu = cpu_dai->playback_widget;
3523 w_codec = codec_dai->playback_widget;
3524 } else {
3525 w_cpu = cpu_dai->capture_widget;
3526 w_codec = codec_dai->capture_widget;
3527 }
3528
3529 if (w_cpu) {
3530 3425
3531 dapm_mark_dirty(w_cpu, "stream event"); 3426 if (w) {
3427 dapm_mark_dirty(w, "stream event");
3532 3428
3533 switch (event) { 3429 switch (event) {
3534 case SND_SOC_DAPM_STREAM_START: 3430 case SND_SOC_DAPM_STREAM_START:
3535 w_cpu->active = 1; 3431 w->active = 1;
3536 break; 3432 break;
3537 case SND_SOC_DAPM_STREAM_STOP: 3433 case SND_SOC_DAPM_STREAM_STOP:
3538 w_cpu->active = 0; 3434 w->active = 0;
3539 break; 3435 break;
3540 case SND_SOC_DAPM_STREAM_SUSPEND: 3436 case SND_SOC_DAPM_STREAM_SUSPEND:
3541 case SND_SOC_DAPM_STREAM_RESUME: 3437 case SND_SOC_DAPM_STREAM_RESUME:
@@ -3544,25 +3440,13 @@ static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3544 break; 3440 break;
3545 } 3441 }
3546 } 3442 }
3443}
3547 3444
3548 if (w_codec) { 3445static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3549 3446 int event)
3550 dapm_mark_dirty(w_codec, "stream event"); 3447{
3551 3448 soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event);
3552 switch (event) { 3449 soc_dapm_dai_stream_event(rtd->codec_dai, stream, event);
3553 case SND_SOC_DAPM_STREAM_START:
3554 w_codec->active = 1;
3555 break;
3556 case SND_SOC_DAPM_STREAM_STOP:
3557 w_codec->active = 0;
3558 break;
3559 case SND_SOC_DAPM_STREAM_SUSPEND:
3560 case SND_SOC_DAPM_STREAM_RESUME:
3561 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
3562 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
3563 break;
3564 }
3565 }
3566 3450
3567 dapm_power_widgets(rtd->card, event); 3451 dapm_power_widgets(rtd->card, event);
3568} 3452}