diff options
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 306 |
1 files changed, 173 insertions, 133 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index a74b9bf23d9f..8348352dc2c6 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -350,12 +350,27 @@ static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol, | |||
350 | } | 350 | } |
351 | 351 | ||
352 | /** | 352 | /** |
353 | * snd_soc_dapm_kcontrol_dapm() - Returns the dapm context associated to a | ||
354 | * kcontrol | ||
355 | * @kcontrol: The kcontrol | ||
356 | * | ||
357 | * Note: This function must only be used on kcontrols that are known to have | ||
358 | * been registered for a CODEC. Otherwise the behaviour is undefined. | ||
359 | */ | ||
360 | struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm( | ||
361 | struct snd_kcontrol *kcontrol) | ||
362 | { | ||
363 | return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->dapm; | ||
364 | } | ||
365 | EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm); | ||
366 | |||
367 | /** | ||
353 | * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol | 368 | * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol |
354 | * @kcontrol: The kcontrol | 369 | * @kcontrol: The kcontrol |
355 | */ | 370 | */ |
356 | struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol) | 371 | struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol) |
357 | { | 372 | { |
358 | return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->codec; | 373 | return snd_soc_dapm_to_codec(snd_soc_dapm_kcontrol_dapm(kcontrol)); |
359 | } | 374 | } |
360 | EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_codec); | 375 | EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_codec); |
361 | 376 | ||
@@ -375,23 +390,38 @@ static void dapm_reset(struct snd_soc_card *card) | |||
375 | } | 390 | } |
376 | } | 391 | } |
377 | 392 | ||
378 | static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg, | 393 | static const char *soc_dapm_prefix(struct snd_soc_dapm_context *dapm) |
394 | { | ||
395 | if (!dapm->component) | ||
396 | return NULL; | ||
397 | return dapm->component->name_prefix; | ||
398 | } | ||
399 | |||
400 | static int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg, | ||
379 | unsigned int *value) | 401 | unsigned int *value) |
380 | { | 402 | { |
381 | if (!w->dapm->component) | 403 | if (!dapm->component) |
382 | return -EIO; | 404 | return -EIO; |
383 | return snd_soc_component_read(w->dapm->component, reg, value); | 405 | return snd_soc_component_read(dapm->component, reg, value); |
384 | } | 406 | } |
385 | 407 | ||
386 | static int soc_widget_update_bits(struct snd_soc_dapm_widget *w, | 408 | static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm, |
387 | int reg, unsigned int mask, unsigned int value) | 409 | int reg, unsigned int mask, unsigned int value) |
388 | { | 410 | { |
389 | if (!w->dapm->component) | 411 | if (!dapm->component) |
390 | return -EIO; | 412 | return -EIO; |
391 | return snd_soc_component_update_bits_async(w->dapm->component, reg, | 413 | return snd_soc_component_update_bits_async(dapm->component, reg, |
392 | mask, value); | 414 | mask, value); |
393 | } | 415 | } |
394 | 416 | ||
417 | static int soc_dapm_test_bits(struct snd_soc_dapm_context *dapm, | ||
418 | int reg, unsigned int mask, unsigned int value) | ||
419 | { | ||
420 | if (!dapm->component) | ||
421 | return -EIO; | ||
422 | return snd_soc_component_test_bits(dapm->component, reg, mask, value); | ||
423 | } | ||
424 | |||
395 | static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm) | 425 | static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm) |
396 | { | 426 | { |
397 | if (dapm->component) | 427 | if (dapm->component) |
@@ -420,15 +450,10 @@ static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm, | |||
420 | if (ret != 0) | 450 | if (ret != 0) |
421 | goto out; | 451 | goto out; |
422 | 452 | ||
423 | if (dapm->codec) { | 453 | if (dapm->set_bias_level) |
424 | if (dapm->codec->driver->set_bias_level) | 454 | ret = dapm->set_bias_level(dapm, level); |
425 | ret = dapm->codec->driver->set_bias_level(dapm->codec, | 455 | else if (!card || dapm != &card->dapm) |
426 | level); | ||
427 | else | ||
428 | dapm->bias_level = level; | ||
429 | } else if (!card || dapm != &card->dapm) { | ||
430 | dapm->bias_level = level; | 456 | dapm->bias_level = level; |
431 | } | ||
432 | 457 | ||
433 | if (ret != 0) | 458 | if (ret != 0) |
434 | goto out; | 459 | goto out; |
@@ -452,7 +477,7 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | |||
452 | int i; | 477 | int i; |
453 | 478 | ||
454 | if (e->reg != SND_SOC_NOPM) { | 479 | if (e->reg != SND_SOC_NOPM) { |
455 | soc_widget_read(dest, e->reg, &val); | 480 | soc_dapm_read(dapm, e->reg, &val); |
456 | val = (val >> e->shift_l) & e->mask; | 481 | val = (val >> e->shift_l) & e->mask; |
457 | item = snd_soc_enum_val_to_item(e, val); | 482 | item = snd_soc_enum_val_to_item(e, val); |
458 | } else { | 483 | } else { |
@@ -496,7 +521,7 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w, | |||
496 | unsigned int val; | 521 | unsigned int val; |
497 | 522 | ||
498 | if (reg != SND_SOC_NOPM) { | 523 | if (reg != SND_SOC_NOPM) { |
499 | soc_widget_read(w, reg, &val); | 524 | soc_dapm_read(w->dapm, reg, &val); |
500 | val = (val >> shift) & mask; | 525 | val = (val >> shift) & mask; |
501 | if (invert) | 526 | if (invert) |
502 | val = max - val; | 527 | val = max - val; |
@@ -570,11 +595,7 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
570 | const char *name; | 595 | const char *name; |
571 | int ret; | 596 | int ret; |
572 | 597 | ||
573 | if (dapm->codec) | 598 | prefix = soc_dapm_prefix(dapm); |
574 | prefix = dapm->codec->name_prefix; | ||
575 | else | ||
576 | prefix = NULL; | ||
577 | |||
578 | if (prefix) | 599 | if (prefix) |
579 | prefix_len = strlen(prefix) + 1; | 600 | prefix_len = strlen(prefix) + 1; |
580 | else | 601 | else |
@@ -1308,16 +1329,18 @@ static void dapm_seq_check_event(struct snd_soc_card *card, | |||
1308 | static void dapm_seq_run_coalesced(struct snd_soc_card *card, | 1329 | static void dapm_seq_run_coalesced(struct snd_soc_card *card, |
1309 | struct list_head *pending) | 1330 | struct list_head *pending) |
1310 | { | 1331 | { |
1332 | struct snd_soc_dapm_context *dapm; | ||
1311 | struct snd_soc_dapm_widget *w; | 1333 | struct snd_soc_dapm_widget *w; |
1312 | int reg; | 1334 | int reg; |
1313 | unsigned int value = 0; | 1335 | unsigned int value = 0; |
1314 | unsigned int mask = 0; | 1336 | unsigned int mask = 0; |
1315 | 1337 | ||
1316 | reg = list_first_entry(pending, struct snd_soc_dapm_widget, | 1338 | w = list_first_entry(pending, struct snd_soc_dapm_widget, power_list); |
1317 | power_list)->reg; | 1339 | reg = w->reg; |
1340 | dapm = w->dapm; | ||
1318 | 1341 | ||
1319 | list_for_each_entry(w, pending, power_list) { | 1342 | list_for_each_entry(w, pending, power_list) { |
1320 | WARN_ON(reg != w->reg); | 1343 | WARN_ON(reg != w->reg || dapm != w->dapm); |
1321 | w->power = w->new_power; | 1344 | w->power = w->new_power; |
1322 | 1345 | ||
1323 | mask |= w->mask << w->shift; | 1346 | mask |= w->mask << w->shift; |
@@ -1326,7 +1349,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_card *card, | |||
1326 | else | 1349 | else |
1327 | value |= w->off_val << w->shift; | 1350 | value |= w->off_val << w->shift; |
1328 | 1351 | ||
1329 | pop_dbg(w->dapm->dev, card->pop_time, | 1352 | pop_dbg(dapm->dev, card->pop_time, |
1330 | "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n", | 1353 | "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n", |
1331 | w->name, reg, value, mask); | 1354 | w->name, reg, value, mask); |
1332 | 1355 | ||
@@ -1339,14 +1362,12 @@ static void dapm_seq_run_coalesced(struct snd_soc_card *card, | |||
1339 | /* Any widget will do, they should all be updating the | 1362 | /* Any widget will do, they should all be updating the |
1340 | * same register. | 1363 | * same register. |
1341 | */ | 1364 | */ |
1342 | w = list_first_entry(pending, struct snd_soc_dapm_widget, | ||
1343 | power_list); | ||
1344 | 1365 | ||
1345 | pop_dbg(w->dapm->dev, card->pop_time, | 1366 | pop_dbg(dapm->dev, card->pop_time, |
1346 | "pop test : Applying 0x%x/0x%x to %x in %dms\n", | 1367 | "pop test : Applying 0x%x/0x%x to %x in %dms\n", |
1347 | value, mask, reg, card->pop_time); | 1368 | value, mask, reg, card->pop_time); |
1348 | pop_wait(card->pop_time); | 1369 | pop_wait(card->pop_time); |
1349 | soc_widget_update_bits(w, reg, mask, value); | 1370 | soc_dapm_update_bits(dapm, reg, mask, value); |
1350 | } | 1371 | } |
1351 | 1372 | ||
1352 | list_for_each_entry(w, pending, power_list) { | 1373 | list_for_each_entry(w, pending, power_list) { |
@@ -1492,7 +1513,8 @@ static void dapm_widget_update(struct snd_soc_card *card) | |||
1492 | if (!w) | 1513 | if (!w) |
1493 | return; | 1514 | return; |
1494 | 1515 | ||
1495 | ret = soc_widget_update_bits(w, update->reg, update->mask, update->val); | 1516 | ret = soc_dapm_update_bits(w->dapm, update->reg, update->mask, |
1517 | update->val); | ||
1496 | if (ret < 0) | 1518 | if (ret < 0) |
1497 | dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n", | 1519 | dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n", |
1498 | w->name, ret); | 1520 | w->name, ret); |
@@ -2062,17 +2084,13 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm, | |||
2062 | } | 2084 | } |
2063 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); | 2085 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); |
2064 | 2086 | ||
2065 | /* show dapm widget status in sys fs */ | 2087 | static ssize_t dapm_widget_show_codec(struct snd_soc_codec *codec, char *buf) |
2066 | static ssize_t dapm_widget_show(struct device *dev, | ||
2067 | struct device_attribute *attr, char *buf) | ||
2068 | { | 2088 | { |
2069 | struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); | ||
2070 | struct snd_soc_codec *codec =rtd->codec; | ||
2071 | struct snd_soc_dapm_widget *w; | 2089 | struct snd_soc_dapm_widget *w; |
2072 | int count = 0; | 2090 | int count = 0; |
2073 | char *state = "not set"; | 2091 | char *state = "not set"; |
2074 | 2092 | ||
2075 | list_for_each_entry(w, &codec->card->widgets, list) { | 2093 | list_for_each_entry(w, &codec->component.card->widgets, list) { |
2076 | if (w->dapm != &codec->dapm) | 2094 | if (w->dapm != &codec->dapm) |
2077 | continue; | 2095 | continue; |
2078 | 2096 | ||
@@ -2120,6 +2138,21 @@ static ssize_t dapm_widget_show(struct device *dev, | |||
2120 | return count; | 2138 | return count; |
2121 | } | 2139 | } |
2122 | 2140 | ||
2141 | /* show dapm widget status in sys fs */ | ||
2142 | static ssize_t dapm_widget_show(struct device *dev, | ||
2143 | struct device_attribute *attr, char *buf) | ||
2144 | { | ||
2145 | struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); | ||
2146 | int i, count = 0; | ||
2147 | |||
2148 | for (i = 0; i < rtd->num_codecs; i++) { | ||
2149 | struct snd_soc_codec *codec = rtd->codec_dais[i]->codec; | ||
2150 | count += dapm_widget_show_codec(codec, buf + count); | ||
2151 | } | ||
2152 | |||
2153 | return count; | ||
2154 | } | ||
2155 | |||
2123 | static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); | 2156 | static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); |
2124 | 2157 | ||
2125 | int snd_soc_dapm_sys_add(struct device *dev) | 2158 | int snd_soc_dapm_sys_add(struct device *dev) |
@@ -2371,14 +2404,16 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2371 | const char *source; | 2404 | const char *source; |
2372 | char prefixed_sink[80]; | 2405 | char prefixed_sink[80]; |
2373 | char prefixed_source[80]; | 2406 | char prefixed_source[80]; |
2407 | const char *prefix; | ||
2374 | int ret; | 2408 | int ret; |
2375 | 2409 | ||
2376 | if (dapm->codec && dapm->codec->name_prefix) { | 2410 | prefix = soc_dapm_prefix(dapm); |
2411 | if (prefix) { | ||
2377 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", | 2412 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", |
2378 | dapm->codec->name_prefix, route->sink); | 2413 | prefix, route->sink); |
2379 | sink = prefixed_sink; | 2414 | sink = prefixed_sink; |
2380 | snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", | 2415 | snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", |
2381 | dapm->codec->name_prefix, route->source); | 2416 | prefix, route->source); |
2382 | source = prefixed_source; | 2417 | source = prefixed_source; |
2383 | } else { | 2418 | } else { |
2384 | sink = route->sink; | 2419 | sink = route->sink; |
@@ -2439,6 +2474,7 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, | |||
2439 | const char *source; | 2474 | const char *source; |
2440 | char prefixed_sink[80]; | 2475 | char prefixed_sink[80]; |
2441 | char prefixed_source[80]; | 2476 | char prefixed_source[80]; |
2477 | const char *prefix; | ||
2442 | 2478 | ||
2443 | if (route->control) { | 2479 | if (route->control) { |
2444 | dev_err(dapm->dev, | 2480 | dev_err(dapm->dev, |
@@ -2446,12 +2482,13 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, | |||
2446 | return -EINVAL; | 2482 | return -EINVAL; |
2447 | } | 2483 | } |
2448 | 2484 | ||
2449 | if (dapm->codec && dapm->codec->name_prefix) { | 2485 | prefix = soc_dapm_prefix(dapm); |
2486 | if (prefix) { | ||
2450 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", | 2487 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", |
2451 | dapm->codec->name_prefix, route->sink); | 2488 | prefix, route->sink); |
2452 | sink = prefixed_sink; | 2489 | sink = prefixed_sink; |
2453 | snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", | 2490 | snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", |
2454 | dapm->codec->name_prefix, route->source); | 2491 | prefix, route->source); |
2455 | source = prefixed_source; | 2492 | source = prefixed_source; |
2456 | } else { | 2493 | } else { |
2457 | sink = route->sink; | 2494 | sink = route->sink; |
@@ -2670,7 +2707,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) | |||
2670 | 2707 | ||
2671 | /* Read the initial power state from the device */ | 2708 | /* Read the initial power state from the device */ |
2672 | if (w->reg >= 0) { | 2709 | if (w->reg >= 0) { |
2673 | soc_widget_read(w, w->reg, &val); | 2710 | soc_dapm_read(w->dapm, w->reg, &val); |
2674 | val = val >> w->shift; | 2711 | val = val >> w->shift; |
2675 | val &= w->mask; | 2712 | val &= w->mask; |
2676 | if (val == w->on_val) | 2713 | if (val == w->on_val) |
@@ -2701,8 +2738,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); | |||
2701 | int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | 2738 | int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, |
2702 | struct snd_ctl_elem_value *ucontrol) | 2739 | struct snd_ctl_elem_value *ucontrol) |
2703 | { | 2740 | { |
2704 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | 2741 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
2705 | struct snd_soc_card *card = codec->card; | 2742 | struct snd_soc_card *card = dapm->card; |
2706 | struct soc_mixer_control *mc = | 2743 | struct soc_mixer_control *mc = |
2707 | (struct soc_mixer_control *)kcontrol->private_value; | 2744 | (struct soc_mixer_control *)kcontrol->private_value; |
2708 | int reg = mc->reg; | 2745 | int reg = mc->reg; |
@@ -2711,17 +2748,20 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | |||
2711 | unsigned int mask = (1 << fls(max)) - 1; | 2748 | unsigned int mask = (1 << fls(max)) - 1; |
2712 | unsigned int invert = mc->invert; | 2749 | unsigned int invert = mc->invert; |
2713 | unsigned int val; | 2750 | unsigned int val; |
2751 | int ret = 0; | ||
2714 | 2752 | ||
2715 | if (snd_soc_volsw_is_stereo(mc)) | 2753 | if (snd_soc_volsw_is_stereo(mc)) |
2716 | dev_warn(codec->dapm.dev, | 2754 | dev_warn(dapm->dev, |
2717 | "ASoC: Control '%s' is stereo, which is not supported\n", | 2755 | "ASoC: Control '%s' is stereo, which is not supported\n", |
2718 | kcontrol->id.name); | 2756 | kcontrol->id.name); |
2719 | 2757 | ||
2720 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2758 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2721 | if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) | 2759 | if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) { |
2722 | val = (snd_soc_read(codec, reg) >> shift) & mask; | 2760 | ret = soc_dapm_read(dapm, reg, &val); |
2723 | else | 2761 | val = (val >> shift) & mask; |
2762 | } else { | ||
2724 | val = dapm_kcontrol_get_value(kcontrol); | 2763 | val = dapm_kcontrol_get_value(kcontrol); |
2764 | } | ||
2725 | mutex_unlock(&card->dapm_mutex); | 2765 | mutex_unlock(&card->dapm_mutex); |
2726 | 2766 | ||
2727 | if (invert) | 2767 | if (invert) |
@@ -2729,7 +2769,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | |||
2729 | else | 2769 | else |
2730 | ucontrol->value.integer.value[0] = val; | 2770 | ucontrol->value.integer.value[0] = val; |
2731 | 2771 | ||
2732 | return 0; | 2772 | return ret; |
2733 | } | 2773 | } |
2734 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); | 2774 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); |
2735 | 2775 | ||
@@ -2745,8 +2785,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); | |||
2745 | int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | 2785 | int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, |
2746 | struct snd_ctl_elem_value *ucontrol) | 2786 | struct snd_ctl_elem_value *ucontrol) |
2747 | { | 2787 | { |
2748 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | 2788 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
2749 | struct snd_soc_card *card = codec->card; | 2789 | struct snd_soc_card *card = dapm->card; |
2750 | struct soc_mixer_control *mc = | 2790 | struct soc_mixer_control *mc = |
2751 | (struct soc_mixer_control *)kcontrol->private_value; | 2791 | (struct soc_mixer_control *)kcontrol->private_value; |
2752 | int reg = mc->reg; | 2792 | int reg = mc->reg; |
@@ -2755,12 +2795,12 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
2755 | unsigned int mask = (1 << fls(max)) - 1; | 2795 | unsigned int mask = (1 << fls(max)) - 1; |
2756 | unsigned int invert = mc->invert; | 2796 | unsigned int invert = mc->invert; |
2757 | unsigned int val; | 2797 | unsigned int val; |
2758 | int connect, change; | 2798 | int connect, change, reg_change = 0; |
2759 | struct snd_soc_dapm_update update; | 2799 | struct snd_soc_dapm_update update; |
2760 | int ret = 0; | 2800 | int ret = 0; |
2761 | 2801 | ||
2762 | if (snd_soc_volsw_is_stereo(mc)) | 2802 | if (snd_soc_volsw_is_stereo(mc)) |
2763 | dev_warn(codec->dapm.dev, | 2803 | dev_warn(dapm->dev, |
2764 | "ASoC: Control '%s' is stereo, which is not supported\n", | 2804 | "ASoC: Control '%s' is stereo, which is not supported\n", |
2765 | kcontrol->id.name); | 2805 | kcontrol->id.name); |
2766 | 2806 | ||
@@ -2773,20 +2813,23 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
2773 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2813 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2774 | 2814 | ||
2775 | change = dapm_kcontrol_set_value(kcontrol, val); | 2815 | change = dapm_kcontrol_set_value(kcontrol, val); |
2776 | if (change) { | ||
2777 | if (reg != SND_SOC_NOPM) { | ||
2778 | mask = mask << shift; | ||
2779 | val = val << shift; | ||
2780 | |||
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 | } | ||
2788 | 2816 | ||
2817 | if (reg != SND_SOC_NOPM) { | ||
2818 | mask = mask << shift; | ||
2819 | val = val << shift; | ||
2820 | |||
2821 | reg_change = soc_dapm_test_bits(dapm, reg, mask, val); | ||
2822 | } | ||
2823 | |||
2824 | if (change || reg_change) { | ||
2825 | if (reg_change) { | ||
2826 | update.kcontrol = kcontrol; | ||
2827 | update.reg = reg; | ||
2828 | update.mask = mask; | ||
2829 | update.val = val; | ||
2830 | card->update = &update; | ||
2789 | } | 2831 | } |
2832 | change |= reg_change; | ||
2790 | 2833 | ||
2791 | ret = soc_dapm_mixer_update_power(card, kcontrol, connect); | 2834 | ret = soc_dapm_mixer_update_power(card, kcontrol, connect); |
2792 | 2835 | ||
@@ -2814,12 +2857,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); | |||
2814 | int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | 2857 | int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, |
2815 | struct snd_ctl_elem_value *ucontrol) | 2858 | struct snd_ctl_elem_value *ucontrol) |
2816 | { | 2859 | { |
2817 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | 2860 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
2818 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2861 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2819 | unsigned int reg_val, val; | 2862 | unsigned int reg_val, val; |
2863 | int ret = 0; | ||
2820 | 2864 | ||
2821 | if (e->reg != SND_SOC_NOPM) | 2865 | if (e->reg != SND_SOC_NOPM) |
2822 | reg_val = snd_soc_read(codec, e->reg); | 2866 | ret = soc_dapm_read(dapm, e->reg, ®_val); |
2823 | else | 2867 | else |
2824 | reg_val = dapm_kcontrol_get_value(kcontrol); | 2868 | reg_val = dapm_kcontrol_get_value(kcontrol); |
2825 | 2869 | ||
@@ -2831,7 +2875,7 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | |||
2831 | ucontrol->value.enumerated.item[1] = val; | 2875 | ucontrol->value.enumerated.item[1] = val; |
2832 | } | 2876 | } |
2833 | 2877 | ||
2834 | return 0; | 2878 | return ret; |
2835 | } | 2879 | } |
2836 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); | 2880 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); |
2837 | 2881 | ||
@@ -2847,8 +2891,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); | |||
2847 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | 2891 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, |
2848 | struct snd_ctl_elem_value *ucontrol) | 2892 | struct snd_ctl_elem_value *ucontrol) |
2849 | { | 2893 | { |
2850 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | 2894 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
2851 | struct snd_soc_card *card = codec->card; | 2895 | struct snd_soc_card *card = dapm->card; |
2852 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2896 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2853 | unsigned int *item = ucontrol->value.enumerated.item; | 2897 | unsigned int *item = ucontrol->value.enumerated.item; |
2854 | unsigned int val, change; | 2898 | unsigned int val, change; |
@@ -2871,7 +2915,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
2871 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2915 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2872 | 2916 | ||
2873 | if (e->reg != SND_SOC_NOPM) | 2917 | if (e->reg != SND_SOC_NOPM) |
2874 | change = snd_soc_test_bits(codec, e->reg, mask, val); | 2918 | change = soc_dapm_test_bits(dapm, e->reg, mask, val); |
2875 | else | 2919 | else |
2876 | change = dapm_kcontrol_set_value(kcontrol, val); | 2920 | change = dapm_kcontrol_set_value(kcontrol, val); |
2877 | 2921 | ||
@@ -2968,6 +3012,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
2968 | const struct snd_soc_dapm_widget *widget) | 3012 | const struct snd_soc_dapm_widget *widget) |
2969 | { | 3013 | { |
2970 | struct snd_soc_dapm_widget *w; | 3014 | struct snd_soc_dapm_widget *w; |
3015 | const char *prefix; | ||
2971 | int ret; | 3016 | int ret; |
2972 | 3017 | ||
2973 | if ((w = dapm_cnew_widget(widget)) == NULL) | 3018 | if ((w = dapm_cnew_widget(widget)) == NULL) |
@@ -3008,9 +3053,9 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3008 | break; | 3053 | break; |
3009 | } | 3054 | } |
3010 | 3055 | ||
3011 | if (dapm->codec && dapm->codec->name_prefix) | 3056 | prefix = soc_dapm_prefix(dapm); |
3012 | w->name = kasprintf(GFP_KERNEL, "%s %s", | 3057 | if (prefix) |
3013 | dapm->codec->name_prefix, widget->name); | 3058 | w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name); |
3014 | else | 3059 | else |
3015 | w->name = kasprintf(GFP_KERNEL, "%s", widget->name); | 3060 | w->name = kasprintf(GFP_KERNEL, "%s", widget->name); |
3016 | 3061 | ||
@@ -3063,7 +3108,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3063 | 3108 | ||
3064 | w->dapm = dapm; | 3109 | w->dapm = dapm; |
3065 | w->codec = dapm->codec; | 3110 | w->codec = dapm->codec; |
3066 | w->platform = dapm->platform; | ||
3067 | INIT_LIST_HEAD(&w->sources); | 3111 | INIT_LIST_HEAD(&w->sources); |
3068 | INIT_LIST_HEAD(&w->sinks); | 3112 | INIT_LIST_HEAD(&w->sinks); |
3069 | INIT_LIST_HEAD(&w->list); | 3113 | INIT_LIST_HEAD(&w->list); |
@@ -3170,27 +3214,15 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, | |||
3170 | 3214 | ||
3171 | switch (event) { | 3215 | switch (event) { |
3172 | case SND_SOC_DAPM_PRE_PMU: | 3216 | case SND_SOC_DAPM_PRE_PMU: |
3173 | if (source->driver->ops && source->driver->ops->hw_params) { | 3217 | substream.stream = SNDRV_PCM_STREAM_CAPTURE; |
3174 | substream.stream = SNDRV_PCM_STREAM_CAPTURE; | 3218 | ret = soc_dai_hw_params(&substream, params, source); |
3175 | ret = source->driver->ops->hw_params(&substream, | 3219 | if (ret < 0) |
3176 | params, source); | 3220 | goto out; |
3177 | if (ret != 0) { | ||
3178 | dev_err(source->dev, | ||
3179 | "ASoC: hw_params() failed: %d\n", ret); | ||
3180 | goto out; | ||
3181 | } | ||
3182 | } | ||
3183 | 3221 | ||
3184 | if (sink->driver->ops && sink->driver->ops->hw_params) { | 3222 | substream.stream = SNDRV_PCM_STREAM_PLAYBACK; |
3185 | substream.stream = SNDRV_PCM_STREAM_PLAYBACK; | 3223 | ret = soc_dai_hw_params(&substream, params, sink); |
3186 | ret = sink->driver->ops->hw_params(&substream, params, | 3224 | if (ret < 0) |
3187 | sink); | 3225 | goto out; |
3188 | if (ret != 0) { | ||
3189 | dev_err(sink->dev, | ||
3190 | "ASoC: hw_params() failed: %d\n", ret); | ||
3191 | goto out; | ||
3192 | } | ||
3193 | } | ||
3194 | break; | 3226 | break; |
3195 | 3227 | ||
3196 | case SND_SOC_DAPM_POST_PMU: | 3228 | case SND_SOC_DAPM_POST_PMU: |
@@ -3362,25 +3394,15 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) | |||
3362 | return 0; | 3394 | return 0; |
3363 | } | 3395 | } |
3364 | 3396 | ||
3365 | void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) | 3397 | static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, |
3398 | struct snd_soc_pcm_runtime *rtd) | ||
3366 | { | 3399 | { |
3367 | struct snd_soc_pcm_runtime *rtd = card->rtd; | 3400 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
3368 | struct snd_soc_dapm_widget *sink, *source; | 3401 | struct snd_soc_dapm_widget *sink, *source; |
3369 | struct snd_soc_dai *cpu_dai, *codec_dai; | ||
3370 | int i; | 3402 | int i; |
3371 | 3403 | ||
3372 | /* for each BE DAI link... */ | 3404 | for (i = 0; i < rtd->num_codecs; i++) { |
3373 | for (i = 0; i < card->num_rtd; i++) { | 3405 | struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; |
3374 | rtd = &card->rtd[i]; | ||
3375 | cpu_dai = rtd->cpu_dai; | ||
3376 | codec_dai = rtd->codec_dai; | ||
3377 | |||
3378 | /* | ||
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) | ||
3383 | continue; | ||
3384 | 3406 | ||
3385 | /* there is no point in connecting BE DAI links with dummies */ | 3407 | /* there is no point in connecting BE DAI links with dummies */ |
3386 | if (snd_soc_dai_is_dummy(codec_dai) || | 3408 | if (snd_soc_dai_is_dummy(codec_dai) || |
@@ -3392,8 +3414,8 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) | |||
3392 | source = cpu_dai->playback_widget; | 3414 | source = cpu_dai->playback_widget; |
3393 | sink = codec_dai->playback_widget; | 3415 | sink = codec_dai->playback_widget; |
3394 | dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", | 3416 | dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", |
3395 | cpu_dai->codec->name, source->name, | 3417 | cpu_dai->component->name, source->name, |
3396 | codec_dai->platform->name, sink->name); | 3418 | codec_dai->component->name, sink->name); |
3397 | 3419 | ||
3398 | snd_soc_dapm_add_path(&card->dapm, source, sink, | 3420 | snd_soc_dapm_add_path(&card->dapm, source, sink, |
3399 | NULL, NULL); | 3421 | NULL, NULL); |
@@ -3404,8 +3426,8 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) | |||
3404 | source = codec_dai->capture_widget; | 3426 | source = codec_dai->capture_widget; |
3405 | sink = cpu_dai->capture_widget; | 3427 | sink = cpu_dai->capture_widget; |
3406 | dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", | 3428 | dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", |
3407 | codec_dai->codec->name, source->name, | 3429 | codec_dai->component->name, source->name, |
3408 | cpu_dai->platform->name, sink->name); | 3430 | cpu_dai->component->name, sink->name); |
3409 | 3431 | ||
3410 | snd_soc_dapm_add_path(&card->dapm, source, sink, | 3432 | snd_soc_dapm_add_path(&card->dapm, source, sink, |
3411 | NULL, NULL); | 3433 | NULL, NULL); |
@@ -3442,11 +3464,34 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream, | |||
3442 | } | 3464 | } |
3443 | } | 3465 | } |
3444 | 3466 | ||
3467 | void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) | ||
3468 | { | ||
3469 | struct snd_soc_pcm_runtime *rtd = card->rtd; | ||
3470 | int i; | ||
3471 | |||
3472 | /* for each BE DAI link... */ | ||
3473 | for (i = 0; i < card->num_rtd; i++) { | ||
3474 | rtd = &card->rtd[i]; | ||
3475 | |||
3476 | /* | ||
3477 | * dynamic FE links have no fixed DAI mapping. | ||
3478 | * CODEC<->CODEC links have no direct connection. | ||
3479 | */ | ||
3480 | if (rtd->dai_link->dynamic || rtd->dai_link->params) | ||
3481 | continue; | ||
3482 | |||
3483 | dapm_connect_dai_link_widgets(card, rtd); | ||
3484 | } | ||
3485 | } | ||
3486 | |||
3445 | static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, | 3487 | static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, |
3446 | int event) | 3488 | int event) |
3447 | { | 3489 | { |
3490 | int i; | ||
3491 | |||
3448 | soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event); | 3492 | soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event); |
3449 | soc_dapm_dai_stream_event(rtd->codec_dai, stream, event); | 3493 | for (i = 0; i < rtd->num_codecs; i++) |
3494 | soc_dapm_dai_stream_event(rtd->codec_dais[i], stream, event); | ||
3450 | 3495 | ||
3451 | dapm_power_widgets(rtd->card, event); | 3496 | dapm_power_widgets(rtd->card, event); |
3452 | } | 3497 | } |
@@ -3755,36 +3800,31 @@ static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card, | |||
3755 | } | 3800 | } |
3756 | 3801 | ||
3757 | /** | 3802 | /** |
3758 | * snd_soc_dapm_auto_nc_codec_pins - call snd_soc_dapm_nc_pin for unused pins | 3803 | * snd_soc_dapm_auto_nc_pins - call snd_soc_dapm_nc_pin for unused pins |
3759 | * @codec: The codec whose pins should be processed | 3804 | * @card: The card whose pins should be processed |
3760 | * | 3805 | * |
3761 | * Automatically call snd_soc_dapm_nc_pin() for any external pins in the codec | 3806 | * Automatically call snd_soc_dapm_nc_pin() for any external pins in the card |
3762 | * which are unused. Pins are used if they are connected externally to the | 3807 | * which are unused. Pins are used if they are connected externally to a |
3763 | * codec, whether that be to some other device, or a loop-back connection to | 3808 | * component, whether that be to some other device, or a loop-back connection to |
3764 | * the codec itself. | 3809 | * the component itself. |
3765 | */ | 3810 | */ |
3766 | void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec) | 3811 | void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card) |
3767 | { | 3812 | { |
3768 | struct snd_soc_card *card = codec->card; | ||
3769 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
3770 | struct snd_soc_dapm_widget *w; | 3813 | struct snd_soc_dapm_widget *w; |
3771 | 3814 | ||
3772 | dev_dbg(codec->dev, "ASoC: Auto NC: DAPMs: card:%p codec:%p\n", | 3815 | dev_dbg(card->dev, "ASoC: Auto NC: DAPMs: card:%p\n", &card->dapm); |
3773 | &card->dapm, &codec->dapm); | ||
3774 | 3816 | ||
3775 | list_for_each_entry(w, &card->widgets, list) { | 3817 | list_for_each_entry(w, &card->widgets, list) { |
3776 | if (w->dapm != dapm) | ||
3777 | continue; | ||
3778 | switch (w->id) { | 3818 | switch (w->id) { |
3779 | case snd_soc_dapm_input: | 3819 | case snd_soc_dapm_input: |
3780 | case snd_soc_dapm_output: | 3820 | case snd_soc_dapm_output: |
3781 | case snd_soc_dapm_micbias: | 3821 | case snd_soc_dapm_micbias: |
3782 | dev_dbg(codec->dev, "ASoC: Auto NC: Checking widget %s\n", | 3822 | dev_dbg(card->dev, "ASoC: Auto NC: Checking widget %s\n", |
3783 | w->name); | 3823 | w->name); |
3784 | if (!snd_soc_dapm_widget_in_card_paths(card, w)) { | 3824 | if (!snd_soc_dapm_widget_in_card_paths(card, w)) { |
3785 | dev_dbg(codec->dev, | 3825 | dev_dbg(card->dev, |
3786 | "... Not in map; disabling\n"); | 3826 | "... Not in map; disabling\n"); |
3787 | snd_soc_dapm_nc_pin(dapm, w->name); | 3827 | snd_soc_dapm_nc_pin(w->dapm, w->name); |
3788 | } | 3828 | } |
3789 | break; | 3829 | break; |
3790 | default: | 3830 | default: |