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.c259
1 files changed, 69 insertions, 190 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 6d6ceee447d5..a74b9bf23d9f 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -378,86 +378,24 @@ static void dapm_reset(struct snd_soc_card *card)
378static 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,
379 unsigned int *value) 379 unsigned int *value)
380{ 380{
381 if (w->codec) { 381 if (!w->dapm->component)
382 *value = snd_soc_read(w->codec, reg); 382 return -EIO;
383 return 0; 383 return snd_soc_component_read(w->dapm->component, reg, value);
384 } else if (w->platform) {
385 *value = snd_soc_platform_read(w->platform, reg);
386 return 0;
387 }
388
389 dev_err(w->dapm->dev, "ASoC: no valid widget read method\n");
390 return -1;
391}
392
393static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg,
394 unsigned int val)
395{
396 if (w->codec)
397 return snd_soc_write(w->codec, reg, val);
398 else if (w->platform)
399 return snd_soc_platform_write(w->platform, reg, val);
400
401 dev_err(w->dapm->dev, "ASoC: no valid widget write method\n");
402 return -1;
403}
404
405static inline void soc_widget_lock(struct snd_soc_dapm_widget *w)
406{
407 if (w->codec && !w->codec->using_regmap)
408 mutex_lock(&w->codec->mutex);
409 else if (w->platform)
410 mutex_lock(&w->platform->mutex);
411} 384}
412 385
413static 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)
414{ 388{
415 if (w->codec && !w->codec->using_regmap) 389 if (!w->dapm->component)
416 mutex_unlock(&w->codec->mutex); 390 return -EIO;
417 else if (w->platform) 391 return snd_soc_component_update_bits_async(w->dapm->component, reg,
418 mutex_unlock(&w->platform->mutex); 392 mask, value);
419} 393}
420 394
421static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm) 395static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
422{ 396{
423 if (dapm->codec && dapm->codec->using_regmap) 397 if (dapm->component)
424 regmap_async_complete(dapm->codec->control_data); 398 snd_soc_component_async_complete(dapm->component);
425}
426
427static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w,
428 unsigned short reg, unsigned int mask, unsigned int value)
429{
430 bool change;
431 unsigned int old, new;
432 int ret;
433
434 if (w->codec && w->codec->using_regmap) {
435 ret = regmap_update_bits_check_async(w->codec->control_data,
436 reg, mask, value,
437 &change);
438 if (ret != 0)
439 return ret;
440 } else {
441 soc_widget_lock(w);
442 ret = soc_widget_read(w, reg, &old);
443 if (ret < 0) {
444 soc_widget_unlock(w);
445 return ret;
446 }
447
448 new = (old & ~mask) | (value & mask);
449 change = old != new;
450 if (change) {
451 ret = soc_widget_write(w, reg, new);
452 if (ret < 0) {
453 soc_widget_unlock(w);
454 return ret;
455 }
456 }
457 soc_widget_unlock(w);
458 }
459
460 return change;
461} 399}
462 400
463/** 401/**
@@ -1120,26 +1058,6 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
1120} 1058}
1121 1059
1122/* 1060/*
1123 * Handler for generic register modifier widget.
1124 */
1125int dapm_reg_event(struct snd_soc_dapm_widget *w,
1126 struct snd_kcontrol *kcontrol, int event)
1127{
1128 unsigned int val;
1129
1130 if (SND_SOC_DAPM_EVENT_ON(event))
1131 val = w->on_val;
1132 else
1133 val = w->off_val;
1134
1135 soc_widget_update_bits_locked(w, -(w->reg + 1),
1136 w->mask << w->shift, val << w->shift);
1137
1138 return 0;
1139}
1140EXPORT_SYMBOL_GPL(dapm_reg_event);
1141
1142/*
1143 * Handler for regulator supply widget. 1061 * Handler for regulator supply widget.
1144 */ 1062 */
1145int dapm_regulator_event(struct snd_soc_dapm_widget *w, 1063int dapm_regulator_event(struct snd_soc_dapm_widget *w,
@@ -1428,7 +1346,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_card *card,
1428 "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",
1429 value, mask, reg, card->pop_time); 1347 value, mask, reg, card->pop_time);
1430 pop_wait(card->pop_time); 1348 pop_wait(card->pop_time);
1431 soc_widget_update_bits_locked(w, reg, mask, value); 1349 soc_widget_update_bits(w, reg, mask, value);
1432 } 1350 }
1433 1351
1434 list_for_each_entry(w, pending, power_list) { 1352 list_for_each_entry(w, pending, power_list) {
@@ -1574,8 +1492,7 @@ static void dapm_widget_update(struct snd_soc_card *card)
1574 if (!w) 1492 if (!w)
1575 return; 1493 return;
1576 1494
1577 ret = soc_widget_update_bits_locked(w, update->reg, update->mask, 1495 ret = soc_widget_update_bits(w, update->reg, update->mask, update->val);
1578 update->val);
1579 if (ret < 0) 1496 if (ret < 0)
1580 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",
1581 w->name, ret); 1498 w->name, ret);
@@ -2446,8 +2363,7 @@ err:
2446} 2363}
2447 2364
2448static 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,
2449 const struct snd_soc_dapm_route *route, 2366 const struct snd_soc_dapm_route *route)
2450 unsigned int is_prefixed)
2451{ 2367{
2452 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; 2368 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
2453 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL; 2369 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
@@ -2457,7 +2373,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
2457 char prefixed_source[80]; 2373 char prefixed_source[80];
2458 int ret; 2374 int ret;
2459 2375
2460 if (dapm->codec && dapm->codec->name_prefix && !is_prefixed) { 2376 if (dapm->codec && dapm->codec->name_prefix) {
2461 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", 2377 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
2462 dapm->codec->name_prefix, route->sink); 2378 dapm->codec->name_prefix, route->sink);
2463 sink = prefixed_sink; 2379 sink = prefixed_sink;
@@ -2585,7 +2501,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
2585 2501
2586 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);
2587 for (i = 0; i < num; i++) { 2503 for (i = 0; i < num; i++) {
2588 r = snd_soc_dapm_add_route(dapm, route, false); 2504 r = snd_soc_dapm_add_route(dapm, route);
2589 if (r < 0) { 2505 if (r < 0) {
2590 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",
2591 route->source, 2507 route->source,
@@ -2857,22 +2773,19 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
2857 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); 2773 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
2858 2774
2859 change = dapm_kcontrol_set_value(kcontrol, val); 2775 change = dapm_kcontrol_set_value(kcontrol, val);
2860
2861 if (reg != SND_SOC_NOPM) {
2862 mask = mask << shift;
2863 val = val << shift;
2864
2865 change = snd_soc_test_bits(codec, reg, mask, val);
2866 }
2867
2868 if (change) { 2776 if (change) {
2869 if (reg != SND_SOC_NOPM) { 2777 if (reg != SND_SOC_NOPM) {
2870 update.kcontrol = kcontrol; 2778 mask = mask << shift;
2871 update.reg = reg; 2779 val = val << shift;
2872 update.mask = mask; 2780
2873 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 }
2874 2788
2875 card->update = &update;
2876 } 2789 }
2877 2790
2878 ret = soc_dapm_mixer_update_power(card, kcontrol, connect); 2791 ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
@@ -3311,11 +3224,11 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
3311 struct snd_soc_dapm_widget *source, 3224 struct snd_soc_dapm_widget *source,
3312 struct snd_soc_dapm_widget *sink) 3225 struct snd_soc_dapm_widget *sink)
3313{ 3226{
3314 struct snd_soc_dapm_route routes[2];
3315 struct snd_soc_dapm_widget template; 3227 struct snd_soc_dapm_widget template;
3316 struct snd_soc_dapm_widget *w; 3228 struct snd_soc_dapm_widget *w;
3317 size_t len; 3229 size_t len;
3318 char *link_name; 3230 char *link_name;
3231 int ret;
3319 3232
3320 len = strlen(source->name) + strlen(sink->name) + 2; 3233 len = strlen(source->name) + strlen(sink->name) + 2;
3321 link_name = devm_kzalloc(card->dev, len, GFP_KERNEL); 3234 link_name = devm_kzalloc(card->dev, len, GFP_KERNEL);
@@ -3342,15 +3255,10 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
3342 3255
3343 w->params = params; 3256 w->params = params;
3344 3257
3345 memset(&routes, 0, sizeof(routes)); 3258 ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL);
3346 3259 if (ret)
3347 routes[0].source = source->name; 3260 return ret;
3348 routes[0].sink = link_name; 3261 return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL);
3349 routes[1].source = link_name;
3350 routes[1].sink = sink->name;
3351
3352 return snd_soc_dapm_add_routes(&card->dapm, routes,
3353 ARRAY_SIZE(routes));
3354} 3262}
3355 3263
3356int 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,
@@ -3408,6 +3316,7 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
3408int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) 3316int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
3409{ 3317{
3410 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;
3411 struct snd_soc_dai *dai; 3320 struct snd_soc_dai *dai;
3412 3321
3413 /* For each DAI widget... */ 3322 /* For each DAI widget... */
@@ -3438,25 +3347,15 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
3438 if (!w->sname || !strstr(w->sname, dai_w->name)) 3347 if (!w->sname || !strstr(w->sname, dai_w->name))
3439 continue; 3348 continue;
3440 3349
3441 if (dai->driver->playback.stream_name && 3350 if (dai_w->id == snd_soc_dapm_dai_in) {
3442 strstr(w->sname, 3351 src = dai_w;
3443 dai->driver->playback.stream_name)) { 3352 sink = w;
3444 dev_dbg(dai->dev, "%s -> %s\n", 3353 } else {
3445 dai->playback_widget->name, w->name); 3354 src = w;
3446 3355 sink = dai_w;
3447 snd_soc_dapm_add_path(w->dapm,
3448 dai->playback_widget, w, NULL, NULL);
3449 }
3450
3451 if (dai->driver->capture.stream_name &&
3452 strstr(w->sname,
3453 dai->driver->capture.stream_name)) {
3454 dev_dbg(dai->dev, "%s -> %s\n",
3455 w->name, dai->capture_widget->name);
3456
3457 snd_soc_dapm_add_path(w->dapm, w,
3458 dai->capture_widget, NULL, NULL);
3459 } 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);
3460 } 3359 }
3461 } 3360 }
3462 3361
@@ -3466,12 +3365,10 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
3466void 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)
3467{ 3366{
3468 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;
3469 struct snd_soc_dai *cpu_dai, *codec_dai; 3369 struct snd_soc_dai *cpu_dai, *codec_dai;
3470 struct snd_soc_dapm_route r;
3471 int i; 3370 int i;
3472 3371
3473 memset(&r, 0, sizeof(r));
3474
3475 /* for each BE DAI link... */ 3372 /* for each BE DAI link... */
3476 for (i = 0; i < card->num_rtd; i++) { 3373 for (i = 0; i < card->num_rtd; i++) {
3477 rtd = &card->rtd[i]; 3374 rtd = &card->rtd[i];
@@ -3492,55 +3389,49 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
3492 3389
3493 /* connect BE DAI playback if widgets are valid */ 3390 /* connect BE DAI playback if widgets are valid */
3494 if (codec_dai->playback_widget && cpu_dai->playback_widget) { 3391 if (codec_dai->playback_widget && cpu_dai->playback_widget) {
3495 r.source = cpu_dai->playback_widget->name; 3392 source = cpu_dai->playback_widget;
3496 r.sink = codec_dai->playback_widget->name; 3393 sink = codec_dai->playback_widget;
3497 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",
3498 cpu_dai->codec->name, r.source, 3395 cpu_dai->codec->name, source->name,
3499 codec_dai->platform->name, r.sink); 3396 codec_dai->platform->name, sink->name);
3500 3397
3501 snd_soc_dapm_add_route(&card->dapm, &r, true); 3398 snd_soc_dapm_add_path(&card->dapm, source, sink,
3399 NULL, NULL);
3502 } 3400 }
3503 3401
3504 /* connect BE DAI capture if widgets are valid */ 3402 /* connect BE DAI capture if widgets are valid */
3505 if (codec_dai->capture_widget && cpu_dai->capture_widget) { 3403 if (codec_dai->capture_widget && cpu_dai->capture_widget) {
3506 r.source = codec_dai->capture_widget->name; 3404 source = codec_dai->capture_widget;
3507 r.sink = cpu_dai->capture_widget->name; 3405 sink = cpu_dai->capture_widget;
3508 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",
3509 codec_dai->codec->name, r.source, 3407 codec_dai->codec->name, source->name,
3510 cpu_dai->platform->name, r.sink); 3408 cpu_dai->platform->name, sink->name);
3511 3409
3512 snd_soc_dapm_add_route(&card->dapm, &r, true); 3410 snd_soc_dapm_add_path(&card->dapm, source, sink,
3411 NULL, NULL);
3513 } 3412 }
3514
3515 } 3413 }
3516} 3414}
3517 3415
3518static 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,
3519 int event) 3417 int event)
3520{ 3418{
3419 struct snd_soc_dapm_widget *w;
3521 3420
3522 struct snd_soc_dapm_widget *w_cpu, *w_codec; 3421 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
3523 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 3422 w = dai->playback_widget;
3524 struct snd_soc_dai *codec_dai = rtd->codec_dai; 3423 else
3525 3424 w = dai->capture_widget;
3526 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
3527 w_cpu = cpu_dai->playback_widget;
3528 w_codec = codec_dai->playback_widget;
3529 } else {
3530 w_cpu = cpu_dai->capture_widget;
3531 w_codec = codec_dai->capture_widget;
3532 }
3533
3534 if (w_cpu) {
3535 3425
3536 dapm_mark_dirty(w_cpu, "stream event"); 3426 if (w) {
3427 dapm_mark_dirty(w, "stream event");
3537 3428
3538 switch (event) { 3429 switch (event) {
3539 case SND_SOC_DAPM_STREAM_START: 3430 case SND_SOC_DAPM_STREAM_START:
3540 w_cpu->active = 1; 3431 w->active = 1;
3541 break; 3432 break;
3542 case SND_SOC_DAPM_STREAM_STOP: 3433 case SND_SOC_DAPM_STREAM_STOP:
3543 w_cpu->active = 0; 3434 w->active = 0;
3544 break; 3435 break;
3545 case SND_SOC_DAPM_STREAM_SUSPEND: 3436 case SND_SOC_DAPM_STREAM_SUSPEND:
3546 case SND_SOC_DAPM_STREAM_RESUME: 3437 case SND_SOC_DAPM_STREAM_RESUME:
@@ -3549,25 +3440,13 @@ static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3549 break; 3440 break;
3550 } 3441 }
3551 } 3442 }
3443}
3552 3444
3553 if (w_codec) { 3445static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3554 3446 int event)
3555 dapm_mark_dirty(w_codec, "stream event"); 3447{
3556 3448 soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event);
3557 switch (event) { 3449 soc_dapm_dai_stream_event(rtd->codec_dai, stream, event);
3558 case SND_SOC_DAPM_STREAM_START:
3559 w_codec->active = 1;
3560 break;
3561 case SND_SOC_DAPM_STREAM_STOP:
3562 w_codec->active = 0;
3563 break;
3564 case SND_SOC_DAPM_STREAM_SUSPEND:
3565 case SND_SOC_DAPM_STREAM_RESUME:
3566 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
3567 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
3568 break;
3569 }
3570 }
3571 3450
3572 dapm_power_widgets(rtd->card, event); 3451 dapm_power_widgets(rtd->card, event);
3573} 3452}