diff options
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 110 |
1 files changed, 92 insertions, 18 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index dcade130157f..dc8ff13187f7 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -371,12 +371,16 @@ static void dapm_reset(struct snd_soc_card *card) | |||
371 | } | 371 | } |
372 | } | 372 | } |
373 | 373 | ||
374 | static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg) | 374 | static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg, |
375 | unsigned int *value) | ||
375 | { | 376 | { |
376 | if (w->codec) | 377 | if (w->codec) { |
377 | return snd_soc_read(w->codec, reg); | 378 | *value = snd_soc_read(w->codec, reg); |
378 | else if (w->platform) | 379 | return 0; |
379 | return snd_soc_platform_read(w->platform, reg); | 380 | } else if (w->platform) { |
381 | *value = snd_soc_platform_read(w->platform, reg); | ||
382 | return 0; | ||
383 | } | ||
380 | 384 | ||
381 | dev_err(w->dapm->dev, "ASoC: no valid widget read method\n"); | 385 | dev_err(w->dapm->dev, "ASoC: no valid widget read method\n"); |
382 | return -1; | 386 | return -1; |
@@ -430,13 +434,12 @@ static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w, | |||
430 | return ret; | 434 | return ret; |
431 | } else { | 435 | } else { |
432 | soc_widget_lock(w); | 436 | soc_widget_lock(w); |
433 | ret = soc_widget_read(w, reg); | 437 | ret = soc_widget_read(w, reg, &old); |
434 | if (ret < 0) { | 438 | if (ret < 0) { |
435 | soc_widget_unlock(w); | 439 | soc_widget_unlock(w); |
436 | return ret; | 440 | return ret; |
437 | } | 441 | } |
438 | 442 | ||
439 | old = ret; | ||
440 | new = (old & ~mask) | (value & mask); | 443 | new = (old & ~mask) | (value & mask); |
441 | change = old != new; | 444 | change = old != new; |
442 | if (change) { | 445 | if (change) { |
@@ -513,7 +516,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
513 | unsigned int invert = mc->invert; | 516 | unsigned int invert = mc->invert; |
514 | 517 | ||
515 | if (reg != SND_SOC_NOPM) { | 518 | if (reg != SND_SOC_NOPM) { |
516 | val = soc_widget_read(w, reg); | 519 | soc_widget_read(w, reg, &val); |
517 | val = (val >> shift) & mask; | 520 | val = (val >> shift) & mask; |
518 | if (invert) | 521 | if (invert) |
519 | val = max - val; | 522 | val = max - val; |
@@ -529,7 +532,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
529 | w->kcontrol_news[i].private_value; | 532 | w->kcontrol_news[i].private_value; |
530 | int val, item; | 533 | int val, item; |
531 | 534 | ||
532 | val = soc_widget_read(w, e->reg); | 535 | soc_widget_read(w, e->reg, &val); |
533 | item = (val >> e->shift_l) & e->mask; | 536 | item = (val >> e->shift_l) & e->mask; |
534 | 537 | ||
535 | if (item < e->max && !strcmp(p->name, e->texts[item])) | 538 | if (item < e->max && !strcmp(p->name, e->texts[item])) |
@@ -558,7 +561,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
558 | w->kcontrol_news[i].private_value; | 561 | w->kcontrol_news[i].private_value; |
559 | int val, item; | 562 | int val, item; |
560 | 563 | ||
561 | val = soc_widget_read(w, e->reg); | 564 | soc_widget_read(w, e->reg, &val); |
562 | val = (val >> e->shift_l) & e->mask; | 565 | val = (val >> e->shift_l) & e->mask; |
563 | for (item = 0; item < e->max; item++) { | 566 | for (item = 0; item < e->max; item++) { |
564 | if (val == e->values[item]) | 567 | if (val == e->values[item]) |
@@ -2473,7 +2476,8 @@ err: | |||
2473 | } | 2476 | } |
2474 | 2477 | ||
2475 | static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | 2478 | static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, |
2476 | const struct snd_soc_dapm_route *route) | 2479 | const struct snd_soc_dapm_route *route, |
2480 | unsigned int is_prefixed) | ||
2477 | { | 2481 | { |
2478 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; | 2482 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; |
2479 | struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL; | 2483 | struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL; |
@@ -2483,7 +2487,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2483 | char prefixed_source[80]; | 2487 | char prefixed_source[80]; |
2484 | int ret; | 2488 | int ret; |
2485 | 2489 | ||
2486 | if (dapm->codec && dapm->codec->name_prefix) { | 2490 | if (dapm->codec && dapm->codec->name_prefix && !is_prefixed) { |
2487 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", | 2491 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", |
2488 | dapm->codec->name_prefix, route->sink); | 2492 | dapm->codec->name_prefix, route->sink); |
2489 | sink = prefixed_sink; | 2493 | sink = prefixed_sink; |
@@ -2611,7 +2615,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, | |||
2611 | 2615 | ||
2612 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); | 2616 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); |
2613 | for (i = 0; i < num; i++) { | 2617 | for (i = 0; i < num; i++) { |
2614 | r = snd_soc_dapm_add_route(dapm, route); | 2618 | r = snd_soc_dapm_add_route(dapm, route, false); |
2615 | if (r < 0) { | 2619 | if (r < 0) { |
2616 | dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n", | 2620 | dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n", |
2617 | route->source, | 2621 | route->source, |
@@ -2782,7 +2786,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) | |||
2782 | 2786 | ||
2783 | /* Read the initial power state from the device */ | 2787 | /* Read the initial power state from the device */ |
2784 | if (w->reg >= 0) { | 2788 | if (w->reg >= 0) { |
2785 | val = soc_widget_read(w, w->reg) >> w->shift; | 2789 | soc_widget_read(w, w->reg, &val); |
2790 | val = val >> w->shift; | ||
2786 | val &= w->mask; | 2791 | val &= w->mask; |
2787 | if (val == w->on_val) | 2792 | if (val == w->on_val) |
2788 | w->power = 1; | 2793 | w->power = 1; |
@@ -2868,6 +2873,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
2868 | unsigned int val; | 2873 | unsigned int val; |
2869 | int connect, change; | 2874 | int connect, change; |
2870 | struct snd_soc_dapm_update update; | 2875 | struct snd_soc_dapm_update update; |
2876 | int ret = 0; | ||
2871 | 2877 | ||
2872 | if (snd_soc_volsw_is_stereo(mc)) | 2878 | if (snd_soc_volsw_is_stereo(mc)) |
2873 | dev_warn(codec->dapm.dev, | 2879 | dev_warn(codec->dapm.dev, |
@@ -2901,12 +2907,16 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
2901 | card->update = &update; | 2907 | card->update = &update; |
2902 | } | 2908 | } |
2903 | 2909 | ||
2904 | soc_dapm_mixer_update_power(card, kcontrol, connect); | 2910 | ret = soc_dapm_mixer_update_power(card, kcontrol, connect); |
2905 | 2911 | ||
2906 | card->update = NULL; | 2912 | card->update = NULL; |
2907 | } | 2913 | } |
2908 | 2914 | ||
2909 | mutex_unlock(&card->dapm_mutex); | 2915 | mutex_unlock(&card->dapm_mutex); |
2916 | |||
2917 | if (ret > 0) | ||
2918 | soc_dpcm_runtime_update(card); | ||
2919 | |||
2910 | return change; | 2920 | return change; |
2911 | } | 2921 | } |
2912 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); | 2922 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); |
@@ -2955,6 +2965,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
2955 | unsigned int val, mux, change; | 2965 | unsigned int val, mux, change; |
2956 | unsigned int mask; | 2966 | unsigned int mask; |
2957 | struct snd_soc_dapm_update update; | 2967 | struct snd_soc_dapm_update update; |
2968 | int ret = 0; | ||
2958 | 2969 | ||
2959 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 2970 | if (ucontrol->value.enumerated.item[0] > e->max - 1) |
2960 | return -EINVAL; | 2971 | return -EINVAL; |
@@ -2978,12 +2989,16 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
2978 | update.val = val; | 2989 | update.val = val; |
2979 | card->update = &update; | 2990 | card->update = &update; |
2980 | 2991 | ||
2981 | soc_dapm_mux_update_power(card, kcontrol, mux, e); | 2992 | ret = soc_dapm_mux_update_power(card, kcontrol, mux, e); |
2982 | 2993 | ||
2983 | card->update = NULL; | 2994 | card->update = NULL; |
2984 | } | 2995 | } |
2985 | 2996 | ||
2986 | mutex_unlock(&card->dapm_mutex); | 2997 | mutex_unlock(&card->dapm_mutex); |
2998 | |||
2999 | if (ret > 0) | ||
3000 | soc_dpcm_runtime_update(card); | ||
3001 | |||
2987 | return change; | 3002 | return change; |
2988 | } | 3003 | } |
2989 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); | 3004 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); |
@@ -3019,6 +3034,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | |||
3019 | struct soc_enum *e = | 3034 | struct soc_enum *e = |
3020 | (struct soc_enum *)kcontrol->private_value; | 3035 | (struct soc_enum *)kcontrol->private_value; |
3021 | int change; | 3036 | int change; |
3037 | int ret = 0; | ||
3022 | 3038 | ||
3023 | if (ucontrol->value.enumerated.item[0] >= e->max) | 3039 | if (ucontrol->value.enumerated.item[0] >= e->max) |
3024 | return -EINVAL; | 3040 | return -EINVAL; |
@@ -3028,9 +3044,13 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | |||
3028 | value = ucontrol->value.enumerated.item[0]; | 3044 | value = ucontrol->value.enumerated.item[0]; |
3029 | change = dapm_kcontrol_set_value(kcontrol, value); | 3045 | change = dapm_kcontrol_set_value(kcontrol, value); |
3030 | if (change) | 3046 | if (change) |
3031 | soc_dapm_mux_update_power(card, kcontrol, value, e); | 3047 | ret = soc_dapm_mux_update_power(card, kcontrol, value, e); |
3032 | 3048 | ||
3033 | mutex_unlock(&card->dapm_mutex); | 3049 | mutex_unlock(&card->dapm_mutex); |
3050 | |||
3051 | if (ret > 0) | ||
3052 | soc_dpcm_runtime_update(card); | ||
3053 | |||
3034 | return change; | 3054 | return change; |
3035 | } | 3055 | } |
3036 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); | 3056 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); |
@@ -3097,6 +3117,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
3097 | unsigned int val, mux, change; | 3117 | unsigned int val, mux, change; |
3098 | unsigned int mask; | 3118 | unsigned int mask; |
3099 | struct snd_soc_dapm_update update; | 3119 | struct snd_soc_dapm_update update; |
3120 | int ret = 0; | ||
3100 | 3121 | ||
3101 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 3122 | if (ucontrol->value.enumerated.item[0] > e->max - 1) |
3102 | return -EINVAL; | 3123 | return -EINVAL; |
@@ -3120,12 +3141,16 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
3120 | update.val = val; | 3141 | update.val = val; |
3121 | card->update = &update; | 3142 | card->update = &update; |
3122 | 3143 | ||
3123 | soc_dapm_mux_update_power(card, kcontrol, mux, e); | 3144 | ret = soc_dapm_mux_update_power(card, kcontrol, mux, e); |
3124 | 3145 | ||
3125 | card->update = NULL; | 3146 | card->update = NULL; |
3126 | } | 3147 | } |
3127 | 3148 | ||
3128 | mutex_unlock(&card->dapm_mutex); | 3149 | mutex_unlock(&card->dapm_mutex); |
3150 | |||
3151 | if (ret > 0) | ||
3152 | soc_dpcm_runtime_update(card); | ||
3153 | |||
3129 | return change; | 3154 | return change; |
3130 | } | 3155 | } |
3131 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); | 3156 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); |
@@ -3614,6 +3639,55 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) | |||
3614 | return 0; | 3639 | return 0; |
3615 | } | 3640 | } |
3616 | 3641 | ||
3642 | void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) | ||
3643 | { | ||
3644 | struct snd_soc_pcm_runtime *rtd = card->rtd; | ||
3645 | struct snd_soc_dai *cpu_dai, *codec_dai; | ||
3646 | struct snd_soc_dapm_route r; | ||
3647 | int i; | ||
3648 | |||
3649 | memset(&r, 0, sizeof(r)); | ||
3650 | |||
3651 | /* for each BE DAI link... */ | ||
3652 | for (i = 0; i < card->num_rtd; i++) { | ||
3653 | rtd = &card->rtd[i]; | ||
3654 | cpu_dai = rtd->cpu_dai; | ||
3655 | codec_dai = rtd->codec_dai; | ||
3656 | |||
3657 | /* dynamic FE links have no fixed DAI mapping */ | ||
3658 | if (rtd->dai_link->dynamic) | ||
3659 | continue; | ||
3660 | |||
3661 | /* there is no point in connecting BE DAI links with dummies */ | ||
3662 | if (snd_soc_dai_is_dummy(codec_dai) || | ||
3663 | snd_soc_dai_is_dummy(cpu_dai)) | ||
3664 | continue; | ||
3665 | |||
3666 | /* connect BE DAI playback if widgets are valid */ | ||
3667 | if (codec_dai->playback_widget && cpu_dai->playback_widget) { | ||
3668 | r.source = cpu_dai->playback_widget->name; | ||
3669 | r.sink = codec_dai->playback_widget->name; | ||
3670 | dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", | ||
3671 | cpu_dai->codec->name, r.source, | ||
3672 | codec_dai->platform->name, r.sink); | ||
3673 | |||
3674 | snd_soc_dapm_add_route(&card->dapm, &r, true); | ||
3675 | } | ||
3676 | |||
3677 | /* connect BE DAI capture if widgets are valid */ | ||
3678 | if (codec_dai->capture_widget && cpu_dai->capture_widget) { | ||
3679 | r.source = codec_dai->capture_widget->name; | ||
3680 | r.sink = cpu_dai->capture_widget->name; | ||
3681 | dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", | ||
3682 | codec_dai->codec->name, r.source, | ||
3683 | cpu_dai->platform->name, r.sink); | ||
3684 | |||
3685 | snd_soc_dapm_add_route(&card->dapm, &r, true); | ||
3686 | } | ||
3687 | |||
3688 | } | ||
3689 | } | ||
3690 | |||
3617 | static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, | 3691 | static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, |
3618 | int event) | 3692 | int event) |
3619 | { | 3693 | { |