aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/soc-dapm.h3
-rw-r--r--include/sound/soc.h1
-rw-r--r--sound/soc/soc-core.c6
-rw-r--r--sound/soc/soc-dapm.c164
4 files changed, 166 insertions, 8 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 8d7416e46861..eda881402dda 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -378,6 +378,7 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
378void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card); 378void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card);
379int snd_soc_dapm_new_pcm(struct snd_soc_card *card, 379int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
380 const struct snd_soc_pcm_stream *params, 380 const struct snd_soc_pcm_stream *params,
381 unsigned int num_params,
381 struct snd_soc_dapm_widget *source, 382 struct snd_soc_dapm_widget *source,
382 struct snd_soc_dapm_widget *sink); 383 struct snd_soc_dapm_widget *sink);
383 384
@@ -531,6 +532,8 @@ struct snd_soc_dapm_widget {
531 void *priv; /* widget specific data */ 532 void *priv; /* widget specific data */
532 struct regulator *regulator; /* attached regulator */ 533 struct regulator *regulator; /* attached regulator */
533 const struct snd_soc_pcm_stream *params; /* params for dai links */ 534 const struct snd_soc_pcm_stream *params; /* params for dai links */
535 unsigned int num_params; /* number of params for dai links */
536 unsigned int params_select; /* currently selected param for dai link */
534 537
535 /* dapm control */ 538 /* dapm control */
536 int reg; /* negative reg = no direct dapm */ 539 int reg; /* negative reg = no direct dapm */
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 0d1ade195628..4636a058372b 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -941,6 +941,7 @@ struct snd_soc_dai_link {
941 int be_id; /* optional ID for machine driver BE identification */ 941 int be_id; /* optional ID for machine driver BE identification */
942 942
943 const struct snd_soc_pcm_stream *params; 943 const struct snd_soc_pcm_stream *params;
944 unsigned int num_params;
944 945
945 unsigned int dai_fmt; /* format to set on init */ 946 unsigned int dai_fmt; /* format to set on init */
946 947
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 30579ca5bacb..700ac2ffe696 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1245,7 +1245,8 @@ static int soc_link_dai_widgets(struct snd_soc_card *card,
1245 capture_w = cpu_dai->capture_widget; 1245 capture_w = cpu_dai->capture_widget;
1246 if (play_w && capture_w) { 1246 if (play_w && capture_w) {
1247 ret = snd_soc_dapm_new_pcm(card, dai_link->params, 1247 ret = snd_soc_dapm_new_pcm(card, dai_link->params,
1248 capture_w, play_w); 1248 dai_link->num_params, capture_w,
1249 play_w);
1249 if (ret != 0) { 1250 if (ret != 0) {
1250 dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", 1251 dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
1251 play_w->name, capture_w->name, ret); 1252 play_w->name, capture_w->name, ret);
@@ -1257,7 +1258,8 @@ static int soc_link_dai_widgets(struct snd_soc_card *card,
1257 capture_w = codec_dai->capture_widget; 1258 capture_w = codec_dai->capture_widget;
1258 if (play_w && capture_w) { 1259 if (play_w && capture_w) {
1259 ret = snd_soc_dapm_new_pcm(card, dai_link->params, 1260 ret = snd_soc_dapm_new_pcm(card, dai_link->params,
1260 capture_w, play_w); 1261 dai_link->num_params, capture_w,
1262 play_w);
1261 if (ret != 0) { 1263 if (ret != 0) {
1262 dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", 1264 dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
1263 play_w->name, capture_w->name, ret); 1265 play_w->name, capture_w->name, ret);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index b6f88202b8c9..6828b4ed5447 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -853,6 +853,36 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w)
853 return 0; 853 return 0;
854} 854}
855 855
856/* create new dapm dai link control */
857static int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
858{
859 int i, ret;
860 struct snd_kcontrol *kcontrol;
861 struct snd_soc_dapm_context *dapm = w->dapm;
862 struct snd_card *card = dapm->card->snd_card;
863
864 /* create control for links with > 1 config */
865 if (w->num_params <= 1)
866 return 0;
867
868 /* add kcontrol */
869 for (i = 0; i < w->num_kcontrols; i++) {
870 kcontrol = snd_soc_cnew(&w->kcontrol_news[i], w,
871 w->name, NULL);
872 ret = snd_ctl_add(card, kcontrol);
873 if (ret < 0) {
874 dev_err(dapm->dev,
875 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
876 w->name, w->kcontrol_news[i].name, ret);
877 return ret;
878 }
879 kcontrol->private_data = w;
880 w->kcontrols[i] = kcontrol;
881 }
882
883 return 0;
884}
885
856/* We implement power down on suspend by checking the power state of 886/* We implement power down on suspend by checking the power state of
857 * the ALSA card - when we are suspending the ALSA state for the card 887 * the ALSA card - when we are suspending the ALSA state for the card
858 * is set to D3. 888 * is set to D3.
@@ -2719,6 +2749,9 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
2719 case snd_soc_dapm_out_drv: 2749 case snd_soc_dapm_out_drv:
2720 dapm_new_pga(w); 2750 dapm_new_pga(w);
2721 break; 2751 break;
2752 case snd_soc_dapm_dai_link:
2753 dapm_new_dai_link(w);
2754 break;
2722 default: 2755 default:
2723 break; 2756 break;
2724 } 2757 }
@@ -3193,7 +3226,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
3193{ 3226{
3194 struct snd_soc_dapm_path *source_p, *sink_p; 3227 struct snd_soc_dapm_path *source_p, *sink_p;
3195 struct snd_soc_dai *source, *sink; 3228 struct snd_soc_dai *source, *sink;
3196 const struct snd_soc_pcm_stream *config = w->params; 3229 const struct snd_soc_pcm_stream *config = w->params + w->params_select;
3197 struct snd_pcm_substream substream; 3230 struct snd_pcm_substream substream;
3198 struct snd_pcm_hw_params *params = NULL; 3231 struct snd_pcm_hw_params *params = NULL;
3199 u64 fmt; 3232 u64 fmt;
@@ -3285,8 +3318,39 @@ out:
3285 return ret; 3318 return ret;
3286} 3319}
3287 3320
3321static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol,
3322 struct snd_ctl_elem_value *ucontrol)
3323{
3324 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3325
3326 ucontrol->value.integer.value[0] = w->params_select;
3327
3328 return 0;
3329}
3330
3331static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
3332 struct snd_ctl_elem_value *ucontrol)
3333{
3334 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3335
3336 /* Can't change the config when widget is already powered */
3337 if (w->power)
3338 return -EBUSY;
3339
3340 if (ucontrol->value.integer.value[0] == w->params_select)
3341 return 0;
3342
3343 if (ucontrol->value.integer.value[0] >= w->num_params)
3344 return -EINVAL;
3345
3346 w->params_select = ucontrol->value.integer.value[0];
3347
3348 return 0;
3349}
3350
3288int snd_soc_dapm_new_pcm(struct snd_soc_card *card, 3351int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
3289 const struct snd_soc_pcm_stream *params, 3352 const struct snd_soc_pcm_stream *params,
3353 unsigned int num_params,
3290 struct snd_soc_dapm_widget *source, 3354 struct snd_soc_dapm_widget *source,
3291 struct snd_soc_dapm_widget *sink) 3355 struct snd_soc_dapm_widget *sink)
3292{ 3356{
@@ -3294,14 +3358,61 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
3294 struct snd_soc_dapm_widget *w; 3358 struct snd_soc_dapm_widget *w;
3295 size_t len; 3359 size_t len;
3296 char *link_name; 3360 char *link_name;
3297 int ret; 3361 int ret, count;
3362 unsigned long private_value;
3363 const char **w_param_text;
3364 struct soc_enum w_param_enum[] = {
3365 SOC_ENUM_SINGLE(0, 0, 0, NULL),
3366 };
3367 struct snd_kcontrol_new kcontrol_dai_link[] = {
3368 SOC_ENUM_EXT(NULL, w_param_enum[0],
3369 snd_soc_dapm_dai_link_get,
3370 snd_soc_dapm_dai_link_put),
3371 };
3372 const struct snd_soc_pcm_stream *config = params;
3373
3374 w_param_text = devm_kcalloc(card->dev, num_params,
3375 sizeof(char *), GFP_KERNEL);
3376 if (!w_param_text)
3377 return -ENOMEM;
3298 3378
3299 len = strlen(source->name) + strlen(sink->name) + 2; 3379 len = strlen(source->name) + strlen(sink->name) + 2;
3300 link_name = devm_kzalloc(card->dev, len, GFP_KERNEL); 3380 link_name = devm_kzalloc(card->dev, len, GFP_KERNEL);
3301 if (!link_name) 3381 if (!link_name) {
3302 return -ENOMEM; 3382 ret = -ENOMEM;
3383 goto outfree_w_param;
3384 }
3303 snprintf(link_name, len, "%s-%s", source->name, sink->name); 3385 snprintf(link_name, len, "%s-%s", source->name, sink->name);
3304 3386
3387 for (count = 0 ; count < num_params; count++) {
3388 if (!config->stream_name) {
3389 dev_warn(card->dapm.dev,
3390 "ASoC: anonymous config %d for dai link %s\n",
3391 count, link_name);
3392 len = strlen("Anonymous Configuration ") + 3;
3393 w_param_text[count] =
3394 devm_kzalloc(card->dev, len, GFP_KERNEL);
3395 if (!w_param_text[count]) {
3396 ret = -ENOMEM;
3397 goto outfree_link_name;
3398 }
3399 snprintf(w_param_text[count], len,
3400 "Anonymous Configuration %d", count);
3401 } else {
3402 w_param_text[count] = devm_kmemdup(card->dev,
3403 config->stream_name,
3404 strlen(config->stream_name) + 1,
3405 GFP_KERNEL);
3406 if (!w_param_text[count]) {
3407 ret = -ENOMEM;
3408 goto outfree_link_name;
3409 }
3410 }
3411 config++;
3412 }
3413 w_param_enum[0].items = num_params;
3414 w_param_enum[0].texts = w_param_text;
3415
3305 memset(&template, 0, sizeof(template)); 3416 memset(&template, 0, sizeof(template));
3306 template.reg = SND_SOC_NOPM; 3417 template.reg = SND_SOC_NOPM;
3307 template.id = snd_soc_dapm_dai_link; 3418 template.id = snd_soc_dapm_dai_link;
@@ -3309,6 +3420,30 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
3309 template.event = snd_soc_dai_link_event; 3420 template.event = snd_soc_dai_link_event;
3310 template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 3421 template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3311 SND_SOC_DAPM_PRE_PMD; 3422 SND_SOC_DAPM_PRE_PMD;
3423 template.num_kcontrols = 1;
3424 /* duplicate w_param_enum on heap so that memory persists */
3425 private_value =
3426 (unsigned long) devm_kmemdup(card->dev,
3427 (void *)(kcontrol_dai_link[0].private_value),
3428 sizeof(struct soc_enum), GFP_KERNEL);
3429 if (!private_value) {
3430 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3431 link_name);
3432 ret = -ENOMEM;
3433 goto outfree_link_name;
3434 }
3435 kcontrol_dai_link[0].private_value = private_value;
3436 /* duplicate kcontrol_dai_link on heap so that memory persists */
3437 template.kcontrol_news =
3438 devm_kmemdup(card->dev, &kcontrol_dai_link[0],
3439 sizeof(struct snd_kcontrol_new),
3440 GFP_KERNEL);
3441 if (!template.kcontrol_news) {
3442 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3443 link_name);
3444 ret = -ENOMEM;
3445 goto outfree_private_value;
3446 }
3312 3447
3313 dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name); 3448 dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
3314 3449
@@ -3316,15 +3451,32 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
3316 if (!w) { 3451 if (!w) {
3317 dev_err(card->dev, "ASoC: Failed to create %s widget\n", 3452 dev_err(card->dev, "ASoC: Failed to create %s widget\n",
3318 link_name); 3453 link_name);
3319 return -ENOMEM; 3454 ret = -ENOMEM;
3455 goto outfree_kcontrol_news;
3320 } 3456 }
3321 3457
3322 w->params = params; 3458 w->params = params;
3459 w->num_params = num_params;
3323 3460
3324 ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL); 3461 ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL);
3325 if (ret) 3462 if (ret)
3326 return ret; 3463 goto outfree_w;
3327 return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL); 3464 return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL);
3465
3466outfree_w:
3467 devm_kfree(card->dev, w);
3468outfree_kcontrol_news:
3469 devm_kfree(card->dev, (void *)template.kcontrol_news);
3470outfree_private_value:
3471 devm_kfree(card->dev, (void *)private_value);
3472outfree_link_name:
3473 devm_kfree(card->dev, link_name);
3474outfree_w_param:
3475 for (count = 0 ; count < num_params; count++)
3476 devm_kfree(card->dev, (void *)w_param_text[count]);
3477 devm_kfree(card->dev, w_param_text);
3478
3479 return ret;
3328} 3480}
3329 3481
3330int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, 3482int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,