162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// soc-dapm.c  --  ALSA SoC Dynamic Audio Power Management
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci// Copyright 2005 Wolfson Microelectronics PLC.
662306a36Sopenharmony_ci// Author: Liam Girdwood <lrg@slimlogic.co.uk>
762306a36Sopenharmony_ci//
862306a36Sopenharmony_ci//  Features:
962306a36Sopenharmony_ci//    o Changes power status of internal codec blocks depending on the
1062306a36Sopenharmony_ci//      dynamic configuration of codec internal audio paths and active
1162306a36Sopenharmony_ci//      DACs/ADCs.
1262306a36Sopenharmony_ci//    o Platform power domain - can support external components i.e. amps and
1362306a36Sopenharmony_ci//      mic/headphone insertion events.
1462306a36Sopenharmony_ci//    o Automatic Mic Bias support
1562306a36Sopenharmony_ci//    o Jack insertion power event initiation - e.g. hp insertion will enable
1662306a36Sopenharmony_ci//      sinks, dacs, etc
1762306a36Sopenharmony_ci//    o Delayed power down of audio subsystem to reduce pops between a quick
1862306a36Sopenharmony_ci//      device reopen.
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/init.h>
2262306a36Sopenharmony_ci#include <linux/async.h>
2362306a36Sopenharmony_ci#include <linux/delay.h>
2462306a36Sopenharmony_ci#include <linux/pm.h>
2562306a36Sopenharmony_ci#include <linux/bitops.h>
2662306a36Sopenharmony_ci#include <linux/platform_device.h>
2762306a36Sopenharmony_ci#include <linux/jiffies.h>
2862306a36Sopenharmony_ci#include <linux/debugfs.h>
2962306a36Sopenharmony_ci#include <linux/pm_runtime.h>
3062306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
3162306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h>
3262306a36Sopenharmony_ci#include <linux/clk.h>
3362306a36Sopenharmony_ci#include <linux/slab.h>
3462306a36Sopenharmony_ci#include <sound/core.h>
3562306a36Sopenharmony_ci#include <sound/pcm.h>
3662306a36Sopenharmony_ci#include <sound/pcm_params.h>
3762306a36Sopenharmony_ci#include <sound/soc.h>
3862306a36Sopenharmony_ci#include <sound/initval.h>
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#include <trace/events/asoc.h>
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define SND_SOC_DAPM_DIR_REVERSE(x) ((x == SND_SOC_DAPM_DIR_IN) ? \
4562306a36Sopenharmony_ci	SND_SOC_DAPM_DIR_OUT : SND_SOC_DAPM_DIR_IN)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define snd_soc_dapm_for_each_direction(dir) \
4862306a36Sopenharmony_ci	for ((dir) = SND_SOC_DAPM_DIR_IN; (dir) <= SND_SOC_DAPM_DIR_OUT; \
4962306a36Sopenharmony_ci		(dir)++)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
5262306a36Sopenharmony_ci	struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
5362306a36Sopenharmony_ci	const char *control,
5462306a36Sopenharmony_ci	int (*connected)(struct snd_soc_dapm_widget *source,
5562306a36Sopenharmony_ci			 struct snd_soc_dapm_widget *sink));
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistruct snd_soc_dapm_widget *
5862306a36Sopenharmony_cisnd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
5962306a36Sopenharmony_ci			 const struct snd_soc_dapm_widget *widget);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistruct snd_soc_dapm_widget *
6262306a36Sopenharmony_cisnd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
6362306a36Sopenharmony_ci			 const struct snd_soc_dapm_widget *widget);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic unsigned int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/* dapm power sequences - make this per codec in the future */
6862306a36Sopenharmony_cistatic int dapm_up_seq[] = {
6962306a36Sopenharmony_ci	[snd_soc_dapm_pre] = 1,
7062306a36Sopenharmony_ci	[snd_soc_dapm_regulator_supply] = 2,
7162306a36Sopenharmony_ci	[snd_soc_dapm_pinctrl] = 2,
7262306a36Sopenharmony_ci	[snd_soc_dapm_clock_supply] = 2,
7362306a36Sopenharmony_ci	[snd_soc_dapm_supply] = 3,
7462306a36Sopenharmony_ci	[snd_soc_dapm_dai_link] = 3,
7562306a36Sopenharmony_ci	[snd_soc_dapm_micbias] = 4,
7662306a36Sopenharmony_ci	[snd_soc_dapm_vmid] = 4,
7762306a36Sopenharmony_ci	[snd_soc_dapm_dai_in] = 5,
7862306a36Sopenharmony_ci	[snd_soc_dapm_dai_out] = 5,
7962306a36Sopenharmony_ci	[snd_soc_dapm_aif_in] = 5,
8062306a36Sopenharmony_ci	[snd_soc_dapm_aif_out] = 5,
8162306a36Sopenharmony_ci	[snd_soc_dapm_mic] = 6,
8262306a36Sopenharmony_ci	[snd_soc_dapm_siggen] = 6,
8362306a36Sopenharmony_ci	[snd_soc_dapm_input] = 6,
8462306a36Sopenharmony_ci	[snd_soc_dapm_output] = 6,
8562306a36Sopenharmony_ci	[snd_soc_dapm_mux] = 7,
8662306a36Sopenharmony_ci	[snd_soc_dapm_demux] = 7,
8762306a36Sopenharmony_ci	[snd_soc_dapm_dac] = 8,
8862306a36Sopenharmony_ci	[snd_soc_dapm_switch] = 9,
8962306a36Sopenharmony_ci	[snd_soc_dapm_mixer] = 9,
9062306a36Sopenharmony_ci	[snd_soc_dapm_mixer_named_ctl] = 9,
9162306a36Sopenharmony_ci	[snd_soc_dapm_pga] = 10,
9262306a36Sopenharmony_ci	[snd_soc_dapm_buffer] = 10,
9362306a36Sopenharmony_ci	[snd_soc_dapm_scheduler] = 10,
9462306a36Sopenharmony_ci	[snd_soc_dapm_effect] = 10,
9562306a36Sopenharmony_ci	[snd_soc_dapm_src] = 10,
9662306a36Sopenharmony_ci	[snd_soc_dapm_asrc] = 10,
9762306a36Sopenharmony_ci	[snd_soc_dapm_encoder] = 10,
9862306a36Sopenharmony_ci	[snd_soc_dapm_decoder] = 10,
9962306a36Sopenharmony_ci	[snd_soc_dapm_adc] = 11,
10062306a36Sopenharmony_ci	[snd_soc_dapm_out_drv] = 12,
10162306a36Sopenharmony_ci	[snd_soc_dapm_hp] = 12,
10262306a36Sopenharmony_ci	[snd_soc_dapm_line] = 12,
10362306a36Sopenharmony_ci	[snd_soc_dapm_sink] = 12,
10462306a36Sopenharmony_ci	[snd_soc_dapm_spk] = 13,
10562306a36Sopenharmony_ci	[snd_soc_dapm_kcontrol] = 14,
10662306a36Sopenharmony_ci	[snd_soc_dapm_post] = 15,
10762306a36Sopenharmony_ci};
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic int dapm_down_seq[] = {
11062306a36Sopenharmony_ci	[snd_soc_dapm_pre] = 1,
11162306a36Sopenharmony_ci	[snd_soc_dapm_kcontrol] = 2,
11262306a36Sopenharmony_ci	[snd_soc_dapm_adc] = 3,
11362306a36Sopenharmony_ci	[snd_soc_dapm_spk] = 4,
11462306a36Sopenharmony_ci	[snd_soc_dapm_hp] = 5,
11562306a36Sopenharmony_ci	[snd_soc_dapm_line] = 5,
11662306a36Sopenharmony_ci	[snd_soc_dapm_out_drv] = 5,
11762306a36Sopenharmony_ci	[snd_soc_dapm_sink] = 6,
11862306a36Sopenharmony_ci	[snd_soc_dapm_pga] = 6,
11962306a36Sopenharmony_ci	[snd_soc_dapm_buffer] = 6,
12062306a36Sopenharmony_ci	[snd_soc_dapm_scheduler] = 6,
12162306a36Sopenharmony_ci	[snd_soc_dapm_effect] = 6,
12262306a36Sopenharmony_ci	[snd_soc_dapm_src] = 6,
12362306a36Sopenharmony_ci	[snd_soc_dapm_asrc] = 6,
12462306a36Sopenharmony_ci	[snd_soc_dapm_encoder] = 6,
12562306a36Sopenharmony_ci	[snd_soc_dapm_decoder] = 6,
12662306a36Sopenharmony_ci	[snd_soc_dapm_switch] = 7,
12762306a36Sopenharmony_ci	[snd_soc_dapm_mixer_named_ctl] = 7,
12862306a36Sopenharmony_ci	[snd_soc_dapm_mixer] = 7,
12962306a36Sopenharmony_ci	[snd_soc_dapm_dac] = 8,
13062306a36Sopenharmony_ci	[snd_soc_dapm_mic] = 9,
13162306a36Sopenharmony_ci	[snd_soc_dapm_siggen] = 9,
13262306a36Sopenharmony_ci	[snd_soc_dapm_input] = 9,
13362306a36Sopenharmony_ci	[snd_soc_dapm_output] = 9,
13462306a36Sopenharmony_ci	[snd_soc_dapm_micbias] = 10,
13562306a36Sopenharmony_ci	[snd_soc_dapm_vmid] = 10,
13662306a36Sopenharmony_ci	[snd_soc_dapm_mux] = 11,
13762306a36Sopenharmony_ci	[snd_soc_dapm_demux] = 11,
13862306a36Sopenharmony_ci	[snd_soc_dapm_aif_in] = 12,
13962306a36Sopenharmony_ci	[snd_soc_dapm_aif_out] = 12,
14062306a36Sopenharmony_ci	[snd_soc_dapm_dai_in] = 12,
14162306a36Sopenharmony_ci	[snd_soc_dapm_dai_out] = 12,
14262306a36Sopenharmony_ci	[snd_soc_dapm_dai_link] = 13,
14362306a36Sopenharmony_ci	[snd_soc_dapm_supply] = 14,
14462306a36Sopenharmony_ci	[snd_soc_dapm_clock_supply] = 15,
14562306a36Sopenharmony_ci	[snd_soc_dapm_pinctrl] = 15,
14662306a36Sopenharmony_ci	[snd_soc_dapm_regulator_supply] = 15,
14762306a36Sopenharmony_ci	[snd_soc_dapm_post] = 16,
14862306a36Sopenharmony_ci};
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic void dapm_assert_locked(struct snd_soc_dapm_context *dapm)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	if (snd_soc_card_is_instantiated(dapm->card))
15362306a36Sopenharmony_ci		snd_soc_dapm_mutex_assert_held(dapm);
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic void pop_wait(u32 pop_time)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	if (pop_time)
15962306a36Sopenharmony_ci		schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci__printf(3, 4)
16362306a36Sopenharmony_cistatic void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	va_list args;
16662306a36Sopenharmony_ci	char *buf;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (!pop_time)
16962306a36Sopenharmony_ci		return;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
17262306a36Sopenharmony_ci	if (buf == NULL)
17362306a36Sopenharmony_ci		return;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	va_start(args, fmt);
17662306a36Sopenharmony_ci	vsnprintf(buf, PAGE_SIZE, fmt, args);
17762306a36Sopenharmony_ci	dev_info(dev, "%s", buf);
17862306a36Sopenharmony_ci	va_end(args);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	kfree(buf);
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	return !list_empty(&w->dirty);
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	dapm_assert_locked(w->dapm);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if (!dapm_dirty_widget(w)) {
19362306a36Sopenharmony_ci		dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n",
19462306a36Sopenharmony_ci			 w->name, reason);
19562306a36Sopenharmony_ci		list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci/*
20062306a36Sopenharmony_ci * Common implementation for dapm_widget_invalidate_input_paths() and
20162306a36Sopenharmony_ci * dapm_widget_invalidate_output_paths(). The function is inlined since the
20262306a36Sopenharmony_ci * combined size of the two specialized functions is only marginally larger then
20362306a36Sopenharmony_ci * the size of the generic function and at the same time the fast path of the
20462306a36Sopenharmony_ci * specialized functions is significantly smaller than the generic function.
20562306a36Sopenharmony_ci */
20662306a36Sopenharmony_cistatic __always_inline void dapm_widget_invalidate_paths(
20762306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w, enum snd_soc_dapm_direction dir)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
21062306a36Sopenharmony_ci	struct snd_soc_dapm_widget *node;
21162306a36Sopenharmony_ci	struct snd_soc_dapm_path *p;
21262306a36Sopenharmony_ci	LIST_HEAD(list);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	dapm_assert_locked(w->dapm);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (w->endpoints[dir] == -1)
21762306a36Sopenharmony_ci		return;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	list_add_tail(&w->work_list, &list);
22062306a36Sopenharmony_ci	w->endpoints[dir] = -1;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	list_for_each_entry(w, &list, work_list) {
22362306a36Sopenharmony_ci		snd_soc_dapm_widget_for_each_path(w, dir, p) {
22462306a36Sopenharmony_ci			if (p->is_supply || p->weak || !p->connect)
22562306a36Sopenharmony_ci				continue;
22662306a36Sopenharmony_ci			node = p->node[rdir];
22762306a36Sopenharmony_ci			if (node->endpoints[dir] != -1) {
22862306a36Sopenharmony_ci				node->endpoints[dir] = -1;
22962306a36Sopenharmony_ci				list_add_tail(&node->work_list, &list);
23062306a36Sopenharmony_ci			}
23162306a36Sopenharmony_ci		}
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci/*
23662306a36Sopenharmony_ci * dapm_widget_invalidate_input_paths() - Invalidate the cached number of
23762306a36Sopenharmony_ci *  input paths
23862306a36Sopenharmony_ci * @w: The widget for which to invalidate the cached number of input paths
23962306a36Sopenharmony_ci *
24062306a36Sopenharmony_ci * Resets the cached number of inputs for the specified widget and all widgets
24162306a36Sopenharmony_ci * that can be reached via outcoming paths from the widget.
24262306a36Sopenharmony_ci *
24362306a36Sopenharmony_ci * This function must be called if the number of output paths for a widget might
24462306a36Sopenharmony_ci * have changed. E.g. if the source state of a widget changes or a path is added
24562306a36Sopenharmony_ci * or activated with the widget as the sink.
24662306a36Sopenharmony_ci */
24762306a36Sopenharmony_cistatic void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	dapm_widget_invalidate_paths(w, SND_SOC_DAPM_DIR_IN);
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci/*
25362306a36Sopenharmony_ci * dapm_widget_invalidate_output_paths() - Invalidate the cached number of
25462306a36Sopenharmony_ci *  output paths
25562306a36Sopenharmony_ci * @w: The widget for which to invalidate the cached number of output paths
25662306a36Sopenharmony_ci *
25762306a36Sopenharmony_ci * Resets the cached number of outputs for the specified widget and all widgets
25862306a36Sopenharmony_ci * that can be reached via incoming paths from the widget.
25962306a36Sopenharmony_ci *
26062306a36Sopenharmony_ci * This function must be called if the number of output paths for a widget might
26162306a36Sopenharmony_ci * have changed. E.g. if the sink state of a widget changes or a path is added
26262306a36Sopenharmony_ci * or activated with the widget as the source.
26362306a36Sopenharmony_ci */
26462306a36Sopenharmony_cistatic void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	dapm_widget_invalidate_paths(w, SND_SOC_DAPM_DIR_OUT);
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci/*
27062306a36Sopenharmony_ci * dapm_path_invalidate() - Invalidates the cached number of inputs and outputs
27162306a36Sopenharmony_ci *  for the widgets connected to a path
27262306a36Sopenharmony_ci * @p: The path to invalidate
27362306a36Sopenharmony_ci *
27462306a36Sopenharmony_ci * Resets the cached number of inputs for the sink of the path and the cached
27562306a36Sopenharmony_ci * number of outputs for the source of the path.
27662306a36Sopenharmony_ci *
27762306a36Sopenharmony_ci * This function must be called when a path is added, removed or the connected
27862306a36Sopenharmony_ci * state changes.
27962306a36Sopenharmony_ci */
28062306a36Sopenharmony_cistatic void dapm_path_invalidate(struct snd_soc_dapm_path *p)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	/*
28362306a36Sopenharmony_ci	 * Weak paths or supply paths do not influence the number of input or
28462306a36Sopenharmony_ci	 * output paths of their neighbors.
28562306a36Sopenharmony_ci	 */
28662306a36Sopenharmony_ci	if (p->weak || p->is_supply)
28762306a36Sopenharmony_ci		return;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	/*
29062306a36Sopenharmony_ci	 * The number of connected endpoints is the sum of the number of
29162306a36Sopenharmony_ci	 * connected endpoints of all neighbors. If a node with 0 connected
29262306a36Sopenharmony_ci	 * endpoints is either connected or disconnected that sum won't change,
29362306a36Sopenharmony_ci	 * so there is no need to re-check the path.
29462306a36Sopenharmony_ci	 */
29562306a36Sopenharmony_ci	if (p->source->endpoints[SND_SOC_DAPM_DIR_IN] != 0)
29662306a36Sopenharmony_ci		dapm_widget_invalidate_input_paths(p->sink);
29762306a36Sopenharmony_ci	if (p->sink->endpoints[SND_SOC_DAPM_DIR_OUT] != 0)
29862306a36Sopenharmony_ci		dapm_widget_invalidate_output_paths(p->source);
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_civoid dapm_mark_endpoints_dirty(struct snd_soc_card *card)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock_root(card);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	for_each_card_widgets(card, w) {
30862306a36Sopenharmony_ci		if (w->is_ep) {
30962306a36Sopenharmony_ci			dapm_mark_dirty(w, "Rechecking endpoints");
31062306a36Sopenharmony_ci			if (w->is_ep & SND_SOC_DAPM_EP_SINK)
31162306a36Sopenharmony_ci				dapm_widget_invalidate_output_paths(w);
31262306a36Sopenharmony_ci			if (w->is_ep & SND_SOC_DAPM_EP_SOURCE)
31362306a36Sopenharmony_ci				dapm_widget_invalidate_input_paths(w);
31462306a36Sopenharmony_ci		}
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(card);
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci/* create a new dapm widget */
32262306a36Sopenharmony_cistatic inline struct snd_soc_dapm_widget *dapm_cnew_widget(
32362306a36Sopenharmony_ci	const struct snd_soc_dapm_widget *_widget)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	w = kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
32862306a36Sopenharmony_ci	if (!w)
32962306a36Sopenharmony_ci		return NULL;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	/*
33262306a36Sopenharmony_ci	 * w->name is duplicated in caller, but w->sname isn't.
33362306a36Sopenharmony_ci	 * Duplicate it here if defined
33462306a36Sopenharmony_ci	 */
33562306a36Sopenharmony_ci	if (_widget->sname) {
33662306a36Sopenharmony_ci		w->sname = kstrdup_const(_widget->sname, GFP_KERNEL);
33762306a36Sopenharmony_ci		if (!w->sname) {
33862306a36Sopenharmony_ci			kfree(w);
33962306a36Sopenharmony_ci			return NULL;
34062306a36Sopenharmony_ci		}
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci	return w;
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistruct dapm_kcontrol_data {
34662306a36Sopenharmony_ci	unsigned int value;
34762306a36Sopenharmony_ci	struct snd_soc_dapm_widget *widget;
34862306a36Sopenharmony_ci	struct list_head paths;
34962306a36Sopenharmony_ci	struct snd_soc_dapm_widget_list *wlist;
35062306a36Sopenharmony_ci};
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
35362306a36Sopenharmony_ci	struct snd_kcontrol *kcontrol, const char *ctrl_name)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	struct dapm_kcontrol_data *data;
35662306a36Sopenharmony_ci	struct soc_mixer_control *mc;
35762306a36Sopenharmony_ci	struct soc_enum *e;
35862306a36Sopenharmony_ci	const char *name;
35962306a36Sopenharmony_ci	int ret;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	data = kzalloc(sizeof(*data), GFP_KERNEL);
36262306a36Sopenharmony_ci	if (!data)
36362306a36Sopenharmony_ci		return -ENOMEM;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	INIT_LIST_HEAD(&data->paths);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	switch (widget->id) {
36862306a36Sopenharmony_ci	case snd_soc_dapm_switch:
36962306a36Sopenharmony_ci	case snd_soc_dapm_mixer:
37062306a36Sopenharmony_ci	case snd_soc_dapm_mixer_named_ctl:
37162306a36Sopenharmony_ci		mc = (struct soc_mixer_control *)kcontrol->private_value;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci		if (mc->autodisable) {
37462306a36Sopenharmony_ci			struct snd_soc_dapm_widget template;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci			if (snd_soc_volsw_is_stereo(mc))
37762306a36Sopenharmony_ci				dev_warn(widget->dapm->dev,
37862306a36Sopenharmony_ci					 "ASoC: Unsupported stereo autodisable control '%s'\n",
37962306a36Sopenharmony_ci					 ctrl_name);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci			name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
38262306a36Sopenharmony_ci					 "Autodisable");
38362306a36Sopenharmony_ci			if (!name) {
38462306a36Sopenharmony_ci				ret = -ENOMEM;
38562306a36Sopenharmony_ci				goto err_data;
38662306a36Sopenharmony_ci			}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci			memset(&template, 0, sizeof(template));
38962306a36Sopenharmony_ci			template.reg = mc->reg;
39062306a36Sopenharmony_ci			template.mask = (1 << fls(mc->max)) - 1;
39162306a36Sopenharmony_ci			template.shift = mc->shift;
39262306a36Sopenharmony_ci			if (mc->invert)
39362306a36Sopenharmony_ci				template.off_val = mc->max;
39462306a36Sopenharmony_ci			else
39562306a36Sopenharmony_ci				template.off_val = 0;
39662306a36Sopenharmony_ci			template.on_val = template.off_val;
39762306a36Sopenharmony_ci			template.id = snd_soc_dapm_kcontrol;
39862306a36Sopenharmony_ci			template.name = name;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci			data->value = template.on_val;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci			data->widget =
40362306a36Sopenharmony_ci				snd_soc_dapm_new_control_unlocked(widget->dapm,
40462306a36Sopenharmony_ci				&template);
40562306a36Sopenharmony_ci			kfree(name);
40662306a36Sopenharmony_ci			if (IS_ERR(data->widget)) {
40762306a36Sopenharmony_ci				ret = PTR_ERR(data->widget);
40862306a36Sopenharmony_ci				goto err_data;
40962306a36Sopenharmony_ci			}
41062306a36Sopenharmony_ci		}
41162306a36Sopenharmony_ci		break;
41262306a36Sopenharmony_ci	case snd_soc_dapm_demux:
41362306a36Sopenharmony_ci	case snd_soc_dapm_mux:
41462306a36Sopenharmony_ci		e = (struct soc_enum *)kcontrol->private_value;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci		if (e->autodisable) {
41762306a36Sopenharmony_ci			struct snd_soc_dapm_widget template;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci			name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
42062306a36Sopenharmony_ci					 "Autodisable");
42162306a36Sopenharmony_ci			if (!name) {
42262306a36Sopenharmony_ci				ret = -ENOMEM;
42362306a36Sopenharmony_ci				goto err_data;
42462306a36Sopenharmony_ci			}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci			memset(&template, 0, sizeof(template));
42762306a36Sopenharmony_ci			template.reg = e->reg;
42862306a36Sopenharmony_ci			template.mask = e->mask;
42962306a36Sopenharmony_ci			template.shift = e->shift_l;
43062306a36Sopenharmony_ci			template.off_val = snd_soc_enum_item_to_val(e, 0);
43162306a36Sopenharmony_ci			template.on_val = template.off_val;
43262306a36Sopenharmony_ci			template.id = snd_soc_dapm_kcontrol;
43362306a36Sopenharmony_ci			template.name = name;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci			data->value = template.on_val;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci			data->widget = snd_soc_dapm_new_control_unlocked(
43862306a36Sopenharmony_ci						widget->dapm, &template);
43962306a36Sopenharmony_ci			kfree(name);
44062306a36Sopenharmony_ci			if (IS_ERR(data->widget)) {
44162306a36Sopenharmony_ci				ret = PTR_ERR(data->widget);
44262306a36Sopenharmony_ci				goto err_data;
44362306a36Sopenharmony_ci			}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci			snd_soc_dapm_add_path(widget->dapm, data->widget,
44662306a36Sopenharmony_ci					      widget, NULL, NULL);
44762306a36Sopenharmony_ci		} else if (e->reg != SND_SOC_NOPM) {
44862306a36Sopenharmony_ci			data->value = soc_dapm_read(widget->dapm, e->reg) &
44962306a36Sopenharmony_ci				      (e->mask << e->shift_l);
45062306a36Sopenharmony_ci		}
45162306a36Sopenharmony_ci		break;
45262306a36Sopenharmony_ci	default:
45362306a36Sopenharmony_ci		break;
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	kcontrol->private_data = data;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	return 0;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_cierr_data:
46162306a36Sopenharmony_ci	kfree(data);
46262306a36Sopenharmony_ci	return ret;
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_cistatic void dapm_kcontrol_free(struct snd_kcontrol *kctl)
46662306a36Sopenharmony_ci{
46762306a36Sopenharmony_ci	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	list_del(&data->paths);
47062306a36Sopenharmony_ci	kfree(data->wlist);
47162306a36Sopenharmony_ci	kfree(data);
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
47562306a36Sopenharmony_ci	const struct snd_kcontrol *kcontrol)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	return data->wlist;
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
48362306a36Sopenharmony_ci	struct snd_soc_dapm_widget *widget)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
48662306a36Sopenharmony_ci	struct snd_soc_dapm_widget_list *new_wlist;
48762306a36Sopenharmony_ci	unsigned int n;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	if (data->wlist)
49062306a36Sopenharmony_ci		n = data->wlist->num_widgets + 1;
49162306a36Sopenharmony_ci	else
49262306a36Sopenharmony_ci		n = 1;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	new_wlist = krealloc(data->wlist,
49562306a36Sopenharmony_ci			     struct_size(new_wlist, widgets, n),
49662306a36Sopenharmony_ci			     GFP_KERNEL);
49762306a36Sopenharmony_ci	if (!new_wlist)
49862306a36Sopenharmony_ci		return -ENOMEM;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	new_wlist->widgets[n - 1] = widget;
50162306a36Sopenharmony_ci	new_wlist->num_widgets = n;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	data->wlist = new_wlist;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	return 0;
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
50962306a36Sopenharmony_ci	struct snd_soc_dapm_path *path)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	list_add_tail(&path->list_kcontrol, &data->paths);
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
51762306a36Sopenharmony_ci{
51862306a36Sopenharmony_ci	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	if (!data->widget)
52162306a36Sopenharmony_ci		return true;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	return data->widget->power;
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic struct list_head *dapm_kcontrol_get_path_list(
52762306a36Sopenharmony_ci	const struct snd_kcontrol *kcontrol)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	return &data->paths;
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci#define dapm_kcontrol_for_each_path(path, kcontrol) \
53562306a36Sopenharmony_ci	list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
53662306a36Sopenharmony_ci		list_kcontrol)
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ciunsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	return data->value;
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dapm_kcontrol_get_value);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_cistatic bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
54762306a36Sopenharmony_ci	unsigned int value)
54862306a36Sopenharmony_ci{
54962306a36Sopenharmony_ci	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	if (data->value == value)
55262306a36Sopenharmony_ci		return false;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	if (data->widget) {
55562306a36Sopenharmony_ci		switch (dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->id) {
55662306a36Sopenharmony_ci		case snd_soc_dapm_switch:
55762306a36Sopenharmony_ci		case snd_soc_dapm_mixer:
55862306a36Sopenharmony_ci		case snd_soc_dapm_mixer_named_ctl:
55962306a36Sopenharmony_ci			data->widget->on_val = value & data->widget->mask;
56062306a36Sopenharmony_ci			break;
56162306a36Sopenharmony_ci		case snd_soc_dapm_demux:
56262306a36Sopenharmony_ci		case snd_soc_dapm_mux:
56362306a36Sopenharmony_ci			data->widget->on_val = value >> data->widget->shift;
56462306a36Sopenharmony_ci			break;
56562306a36Sopenharmony_ci		default:
56662306a36Sopenharmony_ci			data->widget->on_val = value;
56762306a36Sopenharmony_ci			break;
56862306a36Sopenharmony_ci		}
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	data->value = value;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	return true;
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci/**
57762306a36Sopenharmony_ci * snd_soc_dapm_kcontrol_widget() - Returns the widget associated to a
57862306a36Sopenharmony_ci *   kcontrol
57962306a36Sopenharmony_ci * @kcontrol: The kcontrol
58062306a36Sopenharmony_ci */
58162306a36Sopenharmony_cistruct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(
58262306a36Sopenharmony_ci				struct snd_kcontrol *kcontrol)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	return dapm_kcontrol_get_wlist(kcontrol)->widgets[0];
58562306a36Sopenharmony_ci}
58662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_widget);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci/**
58962306a36Sopenharmony_ci * snd_soc_dapm_kcontrol_dapm() - Returns the dapm context associated to a
59062306a36Sopenharmony_ci *  kcontrol
59162306a36Sopenharmony_ci * @kcontrol: The kcontrol
59262306a36Sopenharmony_ci *
59362306a36Sopenharmony_ci * Note: This function must only be used on kcontrols that are known to have
59462306a36Sopenharmony_ci * been registered for a CODEC. Otherwise the behaviour is undefined.
59562306a36Sopenharmony_ci */
59662306a36Sopenharmony_cistruct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
59762306a36Sopenharmony_ci	struct snd_kcontrol *kcontrol)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->dapm;
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_cistatic void dapm_reset(struct snd_soc_card *card)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	snd_soc_dapm_mutex_assert_held(card);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	for_each_card_widgets(card, w) {
61262306a36Sopenharmony_ci		w->new_power = w->power;
61362306a36Sopenharmony_ci		w->power_checked = false;
61462306a36Sopenharmony_ci	}
61562306a36Sopenharmony_ci}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_cistatic const char *soc_dapm_prefix(struct snd_soc_dapm_context *dapm)
61862306a36Sopenharmony_ci{
61962306a36Sopenharmony_ci	if (!dapm->component)
62062306a36Sopenharmony_ci		return NULL;
62162306a36Sopenharmony_ci	return dapm->component->name_prefix;
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_cistatic unsigned int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	if (!dapm->component)
62762306a36Sopenharmony_ci		return -EIO;
62862306a36Sopenharmony_ci	return  snd_soc_component_read(dapm->component, reg);
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cistatic int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm,
63262306a36Sopenharmony_ci	int reg, unsigned int mask, unsigned int value)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	if (!dapm->component)
63562306a36Sopenharmony_ci		return -EIO;
63662306a36Sopenharmony_ci	return snd_soc_component_update_bits(dapm->component, reg,
63762306a36Sopenharmony_ci					     mask, value);
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_cistatic int soc_dapm_test_bits(struct snd_soc_dapm_context *dapm,
64162306a36Sopenharmony_ci	int reg, unsigned int mask, unsigned int value)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	if (!dapm->component)
64462306a36Sopenharmony_ci		return -EIO;
64562306a36Sopenharmony_ci	return snd_soc_component_test_bits(dapm->component, reg, mask, value);
64662306a36Sopenharmony_ci}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	if (dapm->component)
65162306a36Sopenharmony_ci		snd_soc_component_async_complete(dapm->component);
65262306a36Sopenharmony_ci}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_cistatic struct snd_soc_dapm_widget *
65562306a36Sopenharmony_cidapm_wcache_lookup(struct snd_soc_dapm_widget *w, const char *name)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	if (w) {
65862306a36Sopenharmony_ci		struct list_head *wlist = &w->dapm->card->widgets;
65962306a36Sopenharmony_ci		const int depth = 2;
66062306a36Sopenharmony_ci		int i = 0;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci		list_for_each_entry_from(w, wlist, list) {
66362306a36Sopenharmony_ci			if (!strcmp(name, w->name))
66462306a36Sopenharmony_ci				return w;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci			if (++i == depth)
66762306a36Sopenharmony_ci				break;
66862306a36Sopenharmony_ci		}
66962306a36Sopenharmony_ci	}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	return NULL;
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci/**
67562306a36Sopenharmony_ci * snd_soc_dapm_force_bias_level() - Sets the DAPM bias level
67662306a36Sopenharmony_ci * @dapm: The DAPM context for which to set the level
67762306a36Sopenharmony_ci * @level: The level to set
67862306a36Sopenharmony_ci *
67962306a36Sopenharmony_ci * Forces the DAPM bias level to a specific state. It will call the bias level
68062306a36Sopenharmony_ci * callback of DAPM context with the specified level. This will even happen if
68162306a36Sopenharmony_ci * the context is already at the same level. Furthermore it will not go through
68262306a36Sopenharmony_ci * the normal bias level sequencing, meaning any intermediate states between the
68362306a36Sopenharmony_ci * current and the target state will not be entered.
68462306a36Sopenharmony_ci *
68562306a36Sopenharmony_ci * Note that the change in bias level is only temporary and the next time
68662306a36Sopenharmony_ci * snd_soc_dapm_sync() is called the state will be set to the level as
68762306a36Sopenharmony_ci * determined by the DAPM core. The function is mainly intended to be used to
68862306a36Sopenharmony_ci * used during probe or resume from suspend to power up the device so
68962306a36Sopenharmony_ci * initialization can be done, before the DAPM core takes over.
69062306a36Sopenharmony_ci */
69162306a36Sopenharmony_ciint snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
69262306a36Sopenharmony_ci	enum snd_soc_bias_level level)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	int ret = 0;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	if (dapm->component)
69762306a36Sopenharmony_ci		ret = snd_soc_component_set_bias_level(dapm->component, level);
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	if (ret == 0)
70062306a36Sopenharmony_ci		dapm->bias_level = level;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	return ret;
70362306a36Sopenharmony_ci}
70462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_force_bias_level);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci/**
70762306a36Sopenharmony_ci * snd_soc_dapm_set_bias_level - set the bias level for the system
70862306a36Sopenharmony_ci * @dapm: DAPM context
70962306a36Sopenharmony_ci * @level: level to configure
71062306a36Sopenharmony_ci *
71162306a36Sopenharmony_ci * Configure the bias (power) levels for the SoC audio device.
71262306a36Sopenharmony_ci *
71362306a36Sopenharmony_ci * Returns 0 for success else error.
71462306a36Sopenharmony_ci */
71562306a36Sopenharmony_cistatic int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
71662306a36Sopenharmony_ci				       enum snd_soc_bias_level level)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	struct snd_soc_card *card = dapm->card;
71962306a36Sopenharmony_ci	int ret = 0;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	trace_snd_soc_bias_level_start(card, level);
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	ret = snd_soc_card_set_bias_level(card, dapm, level);
72462306a36Sopenharmony_ci	if (ret != 0)
72562306a36Sopenharmony_ci		goto out;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	if (!card || dapm != &card->dapm)
72862306a36Sopenharmony_ci		ret = snd_soc_dapm_force_bias_level(dapm, level);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	if (ret != 0)
73162306a36Sopenharmony_ci		goto out;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	ret = snd_soc_card_set_bias_level_post(card, dapm, level);
73462306a36Sopenharmony_ciout:
73562306a36Sopenharmony_ci	trace_snd_soc_bias_level_done(card, level);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	return ret;
73862306a36Sopenharmony_ci}
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci/* connect mux widget to its interconnecting audio paths */
74162306a36Sopenharmony_cistatic int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
74262306a36Sopenharmony_ci	struct snd_soc_dapm_path *path, const char *control_name,
74362306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w)
74462306a36Sopenharmony_ci{
74562306a36Sopenharmony_ci	const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0];
74662306a36Sopenharmony_ci	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
74762306a36Sopenharmony_ci	unsigned int item;
74862306a36Sopenharmony_ci	int i;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	if (e->reg != SND_SOC_NOPM) {
75162306a36Sopenharmony_ci		unsigned int val;
75262306a36Sopenharmony_ci		val = soc_dapm_read(dapm, e->reg);
75362306a36Sopenharmony_ci		val = (val >> e->shift_l) & e->mask;
75462306a36Sopenharmony_ci		item = snd_soc_enum_val_to_item(e, val);
75562306a36Sopenharmony_ci	} else {
75662306a36Sopenharmony_ci		/* since a virtual mux has no backing registers to
75762306a36Sopenharmony_ci		 * decide which path to connect, it will try to match
75862306a36Sopenharmony_ci		 * with the first enumeration.  This is to ensure
75962306a36Sopenharmony_ci		 * that the default mux choice (the first) will be
76062306a36Sopenharmony_ci		 * correctly powered up during initialization.
76162306a36Sopenharmony_ci		 */
76262306a36Sopenharmony_ci		item = 0;
76362306a36Sopenharmony_ci	}
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	i = match_string(e->texts, e->items, control_name);
76662306a36Sopenharmony_ci	if (i < 0)
76762306a36Sopenharmony_ci		return -ENODEV;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	path->name = e->texts[i];
77062306a36Sopenharmony_ci	path->connect = (i == item);
77162306a36Sopenharmony_ci	return 0;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci/* set up initial codec paths */
77662306a36Sopenharmony_cistatic void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i,
77762306a36Sopenharmony_ci				       int nth_path)
77862306a36Sopenharmony_ci{
77962306a36Sopenharmony_ci	struct soc_mixer_control *mc = (struct soc_mixer_control *)
78062306a36Sopenharmony_ci		p->sink->kcontrol_news[i].private_value;
78162306a36Sopenharmony_ci	unsigned int reg = mc->reg;
78262306a36Sopenharmony_ci	unsigned int invert = mc->invert;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	if (reg != SND_SOC_NOPM) {
78562306a36Sopenharmony_ci		unsigned int shift = mc->shift;
78662306a36Sopenharmony_ci		unsigned int max = mc->max;
78762306a36Sopenharmony_ci		unsigned int mask = (1 << fls(max)) - 1;
78862306a36Sopenharmony_ci		unsigned int val = soc_dapm_read(p->sink->dapm, reg);
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci		/*
79162306a36Sopenharmony_ci		 * The nth_path argument allows this function to know
79262306a36Sopenharmony_ci		 * which path of a kcontrol it is setting the initial
79362306a36Sopenharmony_ci		 * status for. Ideally this would support any number
79462306a36Sopenharmony_ci		 * of paths and channels. But since kcontrols only come
79562306a36Sopenharmony_ci		 * in mono and stereo variants, we are limited to 2
79662306a36Sopenharmony_ci		 * channels.
79762306a36Sopenharmony_ci		 *
79862306a36Sopenharmony_ci		 * The following code assumes for stereo controls the
79962306a36Sopenharmony_ci		 * first path is the left channel, and all remaining
80062306a36Sopenharmony_ci		 * paths are the right channel.
80162306a36Sopenharmony_ci		 */
80262306a36Sopenharmony_ci		if (snd_soc_volsw_is_stereo(mc) && nth_path > 0) {
80362306a36Sopenharmony_ci			if (reg != mc->rreg)
80462306a36Sopenharmony_ci				val = soc_dapm_read(p->sink->dapm, mc->rreg);
80562306a36Sopenharmony_ci			val = (val >> mc->rshift) & mask;
80662306a36Sopenharmony_ci		} else {
80762306a36Sopenharmony_ci			val = (val >> shift) & mask;
80862306a36Sopenharmony_ci		}
80962306a36Sopenharmony_ci		if (invert)
81062306a36Sopenharmony_ci			val = max - val;
81162306a36Sopenharmony_ci		p->connect = !!val;
81262306a36Sopenharmony_ci	} else {
81362306a36Sopenharmony_ci		/* since a virtual mixer has no backing registers to
81462306a36Sopenharmony_ci		 * decide which path to connect, it will try to match
81562306a36Sopenharmony_ci		 * with initial state.  This is to ensure
81662306a36Sopenharmony_ci		 * that the default mixer choice will be
81762306a36Sopenharmony_ci		 * correctly powered up during initialization.
81862306a36Sopenharmony_ci		 */
81962306a36Sopenharmony_ci		p->connect = invert;
82062306a36Sopenharmony_ci	}
82162306a36Sopenharmony_ci}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci/* connect mixer widget to its interconnecting audio paths */
82462306a36Sopenharmony_cistatic int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
82562306a36Sopenharmony_ci	struct snd_soc_dapm_path *path, const char *control_name)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	int i, nth_path = 0;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	/* search for mixer kcontrol */
83062306a36Sopenharmony_ci	for (i = 0; i < path->sink->num_kcontrols; i++) {
83162306a36Sopenharmony_ci		if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) {
83262306a36Sopenharmony_ci			path->name = path->sink->kcontrol_news[i].name;
83362306a36Sopenharmony_ci			dapm_set_mixer_path_status(path, i, nth_path++);
83462306a36Sopenharmony_ci			return 0;
83562306a36Sopenharmony_ci		}
83662306a36Sopenharmony_ci	}
83762306a36Sopenharmony_ci	return -ENODEV;
83862306a36Sopenharmony_ci}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_cistatic int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
84162306a36Sopenharmony_ci	struct snd_soc_dapm_widget *kcontrolw,
84262306a36Sopenharmony_ci	const struct snd_kcontrol_new *kcontrol_new,
84362306a36Sopenharmony_ci	struct snd_kcontrol **kcontrol)
84462306a36Sopenharmony_ci{
84562306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
84662306a36Sopenharmony_ci	int i;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	*kcontrol = NULL;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	for_each_card_widgets(dapm->card, w) {
85162306a36Sopenharmony_ci		if (w == kcontrolw || w->dapm != kcontrolw->dapm)
85262306a36Sopenharmony_ci			continue;
85362306a36Sopenharmony_ci		for (i = 0; i < w->num_kcontrols; i++) {
85462306a36Sopenharmony_ci			if (&w->kcontrol_news[i] == kcontrol_new) {
85562306a36Sopenharmony_ci				if (w->kcontrols)
85662306a36Sopenharmony_ci					*kcontrol = w->kcontrols[i];
85762306a36Sopenharmony_ci				return 1;
85862306a36Sopenharmony_ci			}
85962306a36Sopenharmony_ci		}
86062306a36Sopenharmony_ci	}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	return 0;
86362306a36Sopenharmony_ci}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci/*
86662306a36Sopenharmony_ci * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
86762306a36Sopenharmony_ci * create it. Either way, add the widget into the control's widget list
86862306a36Sopenharmony_ci */
86962306a36Sopenharmony_cistatic int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
87062306a36Sopenharmony_ci	int kci)
87162306a36Sopenharmony_ci{
87262306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm = w->dapm;
87362306a36Sopenharmony_ci	struct snd_card *card = dapm->card->snd_card;
87462306a36Sopenharmony_ci	const char *prefix;
87562306a36Sopenharmony_ci	size_t prefix_len;
87662306a36Sopenharmony_ci	int shared;
87762306a36Sopenharmony_ci	struct snd_kcontrol *kcontrol;
87862306a36Sopenharmony_ci	bool wname_in_long_name, kcname_in_long_name;
87962306a36Sopenharmony_ci	char *long_name = NULL;
88062306a36Sopenharmony_ci	const char *name;
88162306a36Sopenharmony_ci	int ret = 0;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	prefix = soc_dapm_prefix(dapm);
88462306a36Sopenharmony_ci	if (prefix)
88562306a36Sopenharmony_ci		prefix_len = strlen(prefix) + 1;
88662306a36Sopenharmony_ci	else
88762306a36Sopenharmony_ci		prefix_len = 0;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
89062306a36Sopenharmony_ci					 &kcontrol);
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	if (!kcontrol) {
89362306a36Sopenharmony_ci		if (shared) {
89462306a36Sopenharmony_ci			wname_in_long_name = false;
89562306a36Sopenharmony_ci			kcname_in_long_name = true;
89662306a36Sopenharmony_ci		} else {
89762306a36Sopenharmony_ci			switch (w->id) {
89862306a36Sopenharmony_ci			case snd_soc_dapm_switch:
89962306a36Sopenharmony_ci			case snd_soc_dapm_mixer:
90062306a36Sopenharmony_ci			case snd_soc_dapm_pga:
90162306a36Sopenharmony_ci			case snd_soc_dapm_effect:
90262306a36Sopenharmony_ci			case snd_soc_dapm_out_drv:
90362306a36Sopenharmony_ci				wname_in_long_name = true;
90462306a36Sopenharmony_ci				kcname_in_long_name = true;
90562306a36Sopenharmony_ci				break;
90662306a36Sopenharmony_ci			case snd_soc_dapm_mixer_named_ctl:
90762306a36Sopenharmony_ci				wname_in_long_name = false;
90862306a36Sopenharmony_ci				kcname_in_long_name = true;
90962306a36Sopenharmony_ci				break;
91062306a36Sopenharmony_ci			case snd_soc_dapm_demux:
91162306a36Sopenharmony_ci			case snd_soc_dapm_mux:
91262306a36Sopenharmony_ci				wname_in_long_name = true;
91362306a36Sopenharmony_ci				kcname_in_long_name = false;
91462306a36Sopenharmony_ci				break;
91562306a36Sopenharmony_ci			default:
91662306a36Sopenharmony_ci				return -EINVAL;
91762306a36Sopenharmony_ci			}
91862306a36Sopenharmony_ci		}
91962306a36Sopenharmony_ci		if (w->no_wname_in_kcontrol_name)
92062306a36Sopenharmony_ci			wname_in_long_name = false;
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci		if (wname_in_long_name && kcname_in_long_name) {
92362306a36Sopenharmony_ci			/*
92462306a36Sopenharmony_ci			 * The control will get a prefix from the control
92562306a36Sopenharmony_ci			 * creation process but we're also using the same
92662306a36Sopenharmony_ci			 * prefix for widgets so cut the prefix off the
92762306a36Sopenharmony_ci			 * front of the widget name.
92862306a36Sopenharmony_ci			 */
92962306a36Sopenharmony_ci			long_name = kasprintf(GFP_KERNEL, "%s %s",
93062306a36Sopenharmony_ci				 w->name + prefix_len,
93162306a36Sopenharmony_ci				 w->kcontrol_news[kci].name);
93262306a36Sopenharmony_ci			if (long_name == NULL)
93362306a36Sopenharmony_ci				return -ENOMEM;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci			name = long_name;
93662306a36Sopenharmony_ci		} else if (wname_in_long_name) {
93762306a36Sopenharmony_ci			long_name = NULL;
93862306a36Sopenharmony_ci			name = w->name + prefix_len;
93962306a36Sopenharmony_ci		} else {
94062306a36Sopenharmony_ci			long_name = NULL;
94162306a36Sopenharmony_ci			name = w->kcontrol_news[kci].name;
94262306a36Sopenharmony_ci		}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci		kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
94562306a36Sopenharmony_ci					prefix);
94662306a36Sopenharmony_ci		if (!kcontrol) {
94762306a36Sopenharmony_ci			ret = -ENOMEM;
94862306a36Sopenharmony_ci			goto exit_free;
94962306a36Sopenharmony_ci		}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci		kcontrol->private_free = dapm_kcontrol_free;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci		ret = dapm_kcontrol_data_alloc(w, kcontrol, name);
95462306a36Sopenharmony_ci		if (ret) {
95562306a36Sopenharmony_ci			snd_ctl_free_one(kcontrol);
95662306a36Sopenharmony_ci			goto exit_free;
95762306a36Sopenharmony_ci		}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci		ret = snd_ctl_add(card, kcontrol);
96062306a36Sopenharmony_ci		if (ret < 0) {
96162306a36Sopenharmony_ci			dev_err(dapm->dev,
96262306a36Sopenharmony_ci				"ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
96362306a36Sopenharmony_ci				w->name, name, ret);
96462306a36Sopenharmony_ci			goto exit_free;
96562306a36Sopenharmony_ci		}
96662306a36Sopenharmony_ci	}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	ret = dapm_kcontrol_add_widget(kcontrol, w);
96962306a36Sopenharmony_ci	if (ret == 0)
97062306a36Sopenharmony_ci		w->kcontrols[kci] = kcontrol;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ciexit_free:
97362306a36Sopenharmony_ci	kfree(long_name);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	return ret;
97662306a36Sopenharmony_ci}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci/* create new dapm mixer control */
97962306a36Sopenharmony_cistatic int dapm_new_mixer(struct snd_soc_dapm_widget *w)
98062306a36Sopenharmony_ci{
98162306a36Sopenharmony_ci	int i, ret;
98262306a36Sopenharmony_ci	struct snd_soc_dapm_path *path;
98362306a36Sopenharmony_ci	struct dapm_kcontrol_data *data;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	/* add kcontrol */
98662306a36Sopenharmony_ci	for (i = 0; i < w->num_kcontrols; i++) {
98762306a36Sopenharmony_ci		/* match name */
98862306a36Sopenharmony_ci		snd_soc_dapm_widget_for_each_source_path(w, path) {
98962306a36Sopenharmony_ci			/* mixer/mux paths name must match control name */
99062306a36Sopenharmony_ci			if (path->name != (char *)w->kcontrol_news[i].name)
99162306a36Sopenharmony_ci				continue;
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci			if (!w->kcontrols[i]) {
99462306a36Sopenharmony_ci				ret = dapm_create_or_share_kcontrol(w, i);
99562306a36Sopenharmony_ci				if (ret < 0)
99662306a36Sopenharmony_ci					return ret;
99762306a36Sopenharmony_ci			}
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci			dapm_kcontrol_add_path(w->kcontrols[i], path);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci			data = snd_kcontrol_chip(w->kcontrols[i]);
100262306a36Sopenharmony_ci			if (data->widget)
100362306a36Sopenharmony_ci				snd_soc_dapm_add_path(data->widget->dapm,
100462306a36Sopenharmony_ci						      data->widget,
100562306a36Sopenharmony_ci						      path->source,
100662306a36Sopenharmony_ci						      NULL, NULL);
100762306a36Sopenharmony_ci		}
100862306a36Sopenharmony_ci	}
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	return 0;
101162306a36Sopenharmony_ci}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci/* create new dapm mux control */
101462306a36Sopenharmony_cistatic int dapm_new_mux(struct snd_soc_dapm_widget *w)
101562306a36Sopenharmony_ci{
101662306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm = w->dapm;
101762306a36Sopenharmony_ci	enum snd_soc_dapm_direction dir;
101862306a36Sopenharmony_ci	struct snd_soc_dapm_path *path;
101962306a36Sopenharmony_ci	const char *type;
102062306a36Sopenharmony_ci	int ret;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	switch (w->id) {
102362306a36Sopenharmony_ci	case snd_soc_dapm_mux:
102462306a36Sopenharmony_ci		dir = SND_SOC_DAPM_DIR_OUT;
102562306a36Sopenharmony_ci		type = "mux";
102662306a36Sopenharmony_ci		break;
102762306a36Sopenharmony_ci	case snd_soc_dapm_demux:
102862306a36Sopenharmony_ci		dir = SND_SOC_DAPM_DIR_IN;
102962306a36Sopenharmony_ci		type = "demux";
103062306a36Sopenharmony_ci		break;
103162306a36Sopenharmony_ci	default:
103262306a36Sopenharmony_ci		return -EINVAL;
103362306a36Sopenharmony_ci	}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	if (w->num_kcontrols != 1) {
103662306a36Sopenharmony_ci		dev_err(dapm->dev,
103762306a36Sopenharmony_ci			"ASoC: %s %s has incorrect number of controls\n", type,
103862306a36Sopenharmony_ci			w->name);
103962306a36Sopenharmony_ci		return -EINVAL;
104062306a36Sopenharmony_ci	}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	if (list_empty(&w->edges[dir])) {
104362306a36Sopenharmony_ci		dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name);
104462306a36Sopenharmony_ci		return -EINVAL;
104562306a36Sopenharmony_ci	}
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	ret = dapm_create_or_share_kcontrol(w, 0);
104862306a36Sopenharmony_ci	if (ret < 0)
104962306a36Sopenharmony_ci		return ret;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	snd_soc_dapm_widget_for_each_path(w, dir, path) {
105262306a36Sopenharmony_ci		if (path->name)
105362306a36Sopenharmony_ci			dapm_kcontrol_add_path(w->kcontrols[0], path);
105462306a36Sopenharmony_ci	}
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	return 0;
105762306a36Sopenharmony_ci}
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci/* create new dapm volume control */
106062306a36Sopenharmony_cistatic int dapm_new_pga(struct snd_soc_dapm_widget *w)
106162306a36Sopenharmony_ci{
106262306a36Sopenharmony_ci	int i;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	for (i = 0; i < w->num_kcontrols; i++) {
106562306a36Sopenharmony_ci		int ret = dapm_create_or_share_kcontrol(w, i);
106662306a36Sopenharmony_ci		if (ret < 0)
106762306a36Sopenharmony_ci			return ret;
106862306a36Sopenharmony_ci	}
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	return 0;
107162306a36Sopenharmony_ci}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci/* create new dapm dai link control */
107462306a36Sopenharmony_cistatic int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
107562306a36Sopenharmony_ci{
107662306a36Sopenharmony_ci	int i;
107762306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = w->priv;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	/* create control for links with > 1 config */
108062306a36Sopenharmony_ci	if (rtd->dai_link->num_c2c_params <= 1)
108162306a36Sopenharmony_ci		return 0;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	/* add kcontrol */
108462306a36Sopenharmony_ci	for (i = 0; i < w->num_kcontrols; i++) {
108562306a36Sopenharmony_ci		struct snd_soc_dapm_context *dapm = w->dapm;
108662306a36Sopenharmony_ci		struct snd_card *card = dapm->card->snd_card;
108762306a36Sopenharmony_ci		struct snd_kcontrol *kcontrol = snd_soc_cnew(&w->kcontrol_news[i],
108862306a36Sopenharmony_ci							     w, w->name, NULL);
108962306a36Sopenharmony_ci		int ret = snd_ctl_add(card, kcontrol);
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci		if (ret < 0) {
109262306a36Sopenharmony_ci			dev_err(dapm->dev,
109362306a36Sopenharmony_ci				"ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
109462306a36Sopenharmony_ci				w->name, w->kcontrol_news[i].name, ret);
109562306a36Sopenharmony_ci			return ret;
109662306a36Sopenharmony_ci		}
109762306a36Sopenharmony_ci		kcontrol->private_data = w;
109862306a36Sopenharmony_ci		w->kcontrols[i] = kcontrol;
109962306a36Sopenharmony_ci	}
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	return 0;
110262306a36Sopenharmony_ci}
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci/* We implement power down on suspend by checking the power state of
110562306a36Sopenharmony_ci * the ALSA card - when we are suspending the ALSA state for the card
110662306a36Sopenharmony_ci * is set to D3.
110762306a36Sopenharmony_ci */
110862306a36Sopenharmony_cistatic int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
110962306a36Sopenharmony_ci{
111062306a36Sopenharmony_ci	int level = snd_power_get_state(widget->dapm->card->snd_card);
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	switch (level) {
111362306a36Sopenharmony_ci	case SNDRV_CTL_POWER_D3hot:
111462306a36Sopenharmony_ci	case SNDRV_CTL_POWER_D3cold:
111562306a36Sopenharmony_ci		if (widget->ignore_suspend)
111662306a36Sopenharmony_ci			dev_dbg(widget->dapm->dev, "ASoC: %s ignoring suspend\n",
111762306a36Sopenharmony_ci				widget->name);
111862306a36Sopenharmony_ci		return widget->ignore_suspend;
111962306a36Sopenharmony_ci	default:
112062306a36Sopenharmony_ci		return 1;
112162306a36Sopenharmony_ci	}
112262306a36Sopenharmony_ci}
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_cistatic void dapm_widget_list_free(struct snd_soc_dapm_widget_list **list)
112562306a36Sopenharmony_ci{
112662306a36Sopenharmony_ci	kfree(*list);
112762306a36Sopenharmony_ci}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_cistatic int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list,
113062306a36Sopenharmony_ci	struct list_head *widgets)
113162306a36Sopenharmony_ci{
113262306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
113362306a36Sopenharmony_ci	struct list_head *it;
113462306a36Sopenharmony_ci	unsigned int size = 0;
113562306a36Sopenharmony_ci	unsigned int i = 0;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	list_for_each(it, widgets)
113862306a36Sopenharmony_ci		size++;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	*list = kzalloc(struct_size(*list, widgets, size), GFP_KERNEL);
114162306a36Sopenharmony_ci	if (*list == NULL)
114262306a36Sopenharmony_ci		return -ENOMEM;
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	list_for_each_entry(w, widgets, work_list)
114562306a36Sopenharmony_ci		(*list)->widgets[i++] = w;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	(*list)->num_widgets = i;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	return 0;
115062306a36Sopenharmony_ci}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci/*
115362306a36Sopenharmony_ci * Recursively reset the cached number of inputs or outputs for the specified
115462306a36Sopenharmony_ci * widget and all widgets that can be reached via incoming or outcoming paths
115562306a36Sopenharmony_ci * from the widget.
115662306a36Sopenharmony_ci */
115762306a36Sopenharmony_cistatic void invalidate_paths_ep(struct snd_soc_dapm_widget *widget,
115862306a36Sopenharmony_ci	enum snd_soc_dapm_direction dir)
115962306a36Sopenharmony_ci{
116062306a36Sopenharmony_ci	enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
116162306a36Sopenharmony_ci	struct snd_soc_dapm_path *path;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	widget->endpoints[dir] = -1;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	snd_soc_dapm_widget_for_each_path(widget, rdir, path) {
116662306a36Sopenharmony_ci		if (path->weak || path->is_supply)
116762306a36Sopenharmony_ci			continue;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci		if (path->walking)
117062306a36Sopenharmony_ci			return;
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci		if (path->connect) {
117362306a36Sopenharmony_ci			path->walking = 1;
117462306a36Sopenharmony_ci			invalidate_paths_ep(path->node[dir], dir);
117562306a36Sopenharmony_ci			path->walking = 0;
117662306a36Sopenharmony_ci		}
117762306a36Sopenharmony_ci	}
117862306a36Sopenharmony_ci}
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci/*
118162306a36Sopenharmony_ci * Common implementation for is_connected_output_ep() and
118262306a36Sopenharmony_ci * is_connected_input_ep(). The function is inlined since the combined size of
118362306a36Sopenharmony_ci * the two specialized functions is only marginally larger then the size of the
118462306a36Sopenharmony_ci * generic function and at the same time the fast path of the specialized
118562306a36Sopenharmony_ci * functions is significantly smaller than the generic function.
118662306a36Sopenharmony_ci */
118762306a36Sopenharmony_cistatic __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget,
118862306a36Sopenharmony_ci	struct list_head *list, enum snd_soc_dapm_direction dir,
118962306a36Sopenharmony_ci	int (*fn)(struct snd_soc_dapm_widget *, struct list_head *,
119062306a36Sopenharmony_ci		  bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
119162306a36Sopenharmony_ci						enum snd_soc_dapm_direction)),
119262306a36Sopenharmony_ci	bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
119362306a36Sopenharmony_ci				      enum snd_soc_dapm_direction))
119462306a36Sopenharmony_ci{
119562306a36Sopenharmony_ci	enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
119662306a36Sopenharmony_ci	struct snd_soc_dapm_path *path;
119762306a36Sopenharmony_ci	int con = 0;
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	if (widget->endpoints[dir] >= 0)
120062306a36Sopenharmony_ci		return widget->endpoints[dir];
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	DAPM_UPDATE_STAT(widget, path_checks);
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	/* do we need to add this widget to the list ? */
120562306a36Sopenharmony_ci	if (list)
120662306a36Sopenharmony_ci		list_add_tail(&widget->work_list, list);
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	if (custom_stop_condition && custom_stop_condition(widget, dir)) {
120962306a36Sopenharmony_ci		list = NULL;
121062306a36Sopenharmony_ci		custom_stop_condition = NULL;
121162306a36Sopenharmony_ci	}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	if ((widget->is_ep & SND_SOC_DAPM_DIR_TO_EP(dir)) && widget->connected) {
121462306a36Sopenharmony_ci		widget->endpoints[dir] = snd_soc_dapm_suspend_check(widget);
121562306a36Sopenharmony_ci		return widget->endpoints[dir];
121662306a36Sopenharmony_ci	}
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	snd_soc_dapm_widget_for_each_path(widget, rdir, path) {
121962306a36Sopenharmony_ci		DAPM_UPDATE_STAT(widget, neighbour_checks);
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci		if (path->weak || path->is_supply)
122262306a36Sopenharmony_ci			continue;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci		if (path->walking)
122562306a36Sopenharmony_ci			return 1;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci		trace_snd_soc_dapm_path(widget, dir, path);
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci		if (path->connect) {
123062306a36Sopenharmony_ci			path->walking = 1;
123162306a36Sopenharmony_ci			con += fn(path->node[dir], list, custom_stop_condition);
123262306a36Sopenharmony_ci			path->walking = 0;
123362306a36Sopenharmony_ci		}
123462306a36Sopenharmony_ci	}
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	widget->endpoints[dir] = con;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	return con;
123962306a36Sopenharmony_ci}
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci/*
124262306a36Sopenharmony_ci * Recursively check for a completed path to an active or physically connected
124362306a36Sopenharmony_ci * output widget. Returns number of complete paths.
124462306a36Sopenharmony_ci *
124562306a36Sopenharmony_ci * Optionally, can be supplied with a function acting as a stopping condition.
124662306a36Sopenharmony_ci * This function takes the dapm widget currently being examined and the walk
124762306a36Sopenharmony_ci * direction as an arguments, it should return true if widgets from that point
124862306a36Sopenharmony_ci * in the graph onwards should not be added to the widget list.
124962306a36Sopenharmony_ci */
125062306a36Sopenharmony_cistatic int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
125162306a36Sopenharmony_ci	struct list_head *list,
125262306a36Sopenharmony_ci	bool (*custom_stop_condition)(struct snd_soc_dapm_widget *i,
125362306a36Sopenharmony_ci				      enum snd_soc_dapm_direction))
125462306a36Sopenharmony_ci{
125562306a36Sopenharmony_ci	return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_OUT,
125662306a36Sopenharmony_ci			is_connected_output_ep, custom_stop_condition);
125762306a36Sopenharmony_ci}
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci/*
126062306a36Sopenharmony_ci * Recursively check for a completed path to an active or physically connected
126162306a36Sopenharmony_ci * input widget. Returns number of complete paths.
126262306a36Sopenharmony_ci *
126362306a36Sopenharmony_ci * Optionally, can be supplied with a function acting as a stopping condition.
126462306a36Sopenharmony_ci * This function takes the dapm widget currently being examined and the walk
126562306a36Sopenharmony_ci * direction as an arguments, it should return true if the walk should be
126662306a36Sopenharmony_ci * stopped and false otherwise.
126762306a36Sopenharmony_ci */
126862306a36Sopenharmony_cistatic int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
126962306a36Sopenharmony_ci	struct list_head *list,
127062306a36Sopenharmony_ci	bool (*custom_stop_condition)(struct snd_soc_dapm_widget *i,
127162306a36Sopenharmony_ci				      enum snd_soc_dapm_direction))
127262306a36Sopenharmony_ci{
127362306a36Sopenharmony_ci	return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_IN,
127462306a36Sopenharmony_ci			is_connected_input_ep, custom_stop_condition);
127562306a36Sopenharmony_ci}
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci/**
127862306a36Sopenharmony_ci * snd_soc_dapm_dai_get_connected_widgets - query audio path and it's widgets.
127962306a36Sopenharmony_ci * @dai: the soc DAI.
128062306a36Sopenharmony_ci * @stream: stream direction.
128162306a36Sopenharmony_ci * @list: list of active widgets for this stream.
128262306a36Sopenharmony_ci * @custom_stop_condition: (optional) a function meant to stop the widget graph
128362306a36Sopenharmony_ci *                         walk based on custom logic.
128462306a36Sopenharmony_ci *
128562306a36Sopenharmony_ci * Queries DAPM graph as to whether a valid audio stream path exists for
128662306a36Sopenharmony_ci * the initial stream specified by name. This takes into account
128762306a36Sopenharmony_ci * current mixer and mux kcontrol settings. Creates list of valid widgets.
128862306a36Sopenharmony_ci *
128962306a36Sopenharmony_ci * Optionally, can be supplied with a function acting as a stopping condition.
129062306a36Sopenharmony_ci * This function takes the dapm widget currently being examined and the walk
129162306a36Sopenharmony_ci * direction as an arguments, it should return true if the walk should be
129262306a36Sopenharmony_ci * stopped and false otherwise.
129362306a36Sopenharmony_ci *
129462306a36Sopenharmony_ci * Returns the number of valid paths or negative error.
129562306a36Sopenharmony_ci */
129662306a36Sopenharmony_ciint snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
129762306a36Sopenharmony_ci	struct snd_soc_dapm_widget_list **list,
129862306a36Sopenharmony_ci	bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
129962306a36Sopenharmony_ci				      enum snd_soc_dapm_direction))
130062306a36Sopenharmony_ci{
130162306a36Sopenharmony_ci	struct snd_soc_card *card = dai->component->card;
130262306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, stream);
130362306a36Sopenharmony_ci	LIST_HEAD(widgets);
130462306a36Sopenharmony_ci	int paths;
130562306a36Sopenharmony_ci	int ret;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(card);
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
131062306a36Sopenharmony_ci		invalidate_paths_ep(w, SND_SOC_DAPM_DIR_OUT);
131162306a36Sopenharmony_ci		paths = is_connected_output_ep(w, &widgets,
131262306a36Sopenharmony_ci				custom_stop_condition);
131362306a36Sopenharmony_ci	} else {
131462306a36Sopenharmony_ci		invalidate_paths_ep(w, SND_SOC_DAPM_DIR_IN);
131562306a36Sopenharmony_ci		paths = is_connected_input_ep(w, &widgets,
131662306a36Sopenharmony_ci				custom_stop_condition);
131762306a36Sopenharmony_ci	}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	/* Drop starting point */
132062306a36Sopenharmony_ci	list_del(widgets.next);
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	ret = dapm_widget_list_create(list, &widgets);
132362306a36Sopenharmony_ci	if (ret)
132462306a36Sopenharmony_ci		paths = ret;
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	trace_snd_soc_dapm_connected(paths, stream);
132762306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(card);
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	return paths;
133062306a36Sopenharmony_ci}
133162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_dai_get_connected_widgets);
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_civoid snd_soc_dapm_dai_free_widgets(struct snd_soc_dapm_widget_list **list)
133462306a36Sopenharmony_ci{
133562306a36Sopenharmony_ci	dapm_widget_list_free(list);
133662306a36Sopenharmony_ci}
133762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_dai_free_widgets);
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci/*
134062306a36Sopenharmony_ci * Handler for regulator supply widget.
134162306a36Sopenharmony_ci */
134262306a36Sopenharmony_ciint dapm_regulator_event(struct snd_soc_dapm_widget *w,
134362306a36Sopenharmony_ci		   struct snd_kcontrol *kcontrol, int event)
134462306a36Sopenharmony_ci{
134562306a36Sopenharmony_ci	int ret;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	soc_dapm_async_complete(w->dapm);
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	if (SND_SOC_DAPM_EVENT_ON(event)) {
135062306a36Sopenharmony_ci		if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
135162306a36Sopenharmony_ci			ret = regulator_allow_bypass(w->regulator, false);
135262306a36Sopenharmony_ci			if (ret != 0)
135362306a36Sopenharmony_ci				dev_warn(w->dapm->dev,
135462306a36Sopenharmony_ci					 "ASoC: Failed to unbypass %s: %d\n",
135562306a36Sopenharmony_ci					 w->name, ret);
135662306a36Sopenharmony_ci		}
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci		return regulator_enable(w->regulator);
135962306a36Sopenharmony_ci	} else {
136062306a36Sopenharmony_ci		if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
136162306a36Sopenharmony_ci			ret = regulator_allow_bypass(w->regulator, true);
136262306a36Sopenharmony_ci			if (ret != 0)
136362306a36Sopenharmony_ci				dev_warn(w->dapm->dev,
136462306a36Sopenharmony_ci					 "ASoC: Failed to bypass %s: %d\n",
136562306a36Sopenharmony_ci					 w->name, ret);
136662306a36Sopenharmony_ci		}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci		return regulator_disable_deferred(w->regulator, w->shift);
136962306a36Sopenharmony_ci	}
137062306a36Sopenharmony_ci}
137162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dapm_regulator_event);
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci/*
137462306a36Sopenharmony_ci * Handler for pinctrl widget.
137562306a36Sopenharmony_ci */
137662306a36Sopenharmony_ciint dapm_pinctrl_event(struct snd_soc_dapm_widget *w,
137762306a36Sopenharmony_ci		       struct snd_kcontrol *kcontrol, int event)
137862306a36Sopenharmony_ci{
137962306a36Sopenharmony_ci	struct snd_soc_dapm_pinctrl_priv *priv = w->priv;
138062306a36Sopenharmony_ci	struct pinctrl *p = w->pinctrl;
138162306a36Sopenharmony_ci	struct pinctrl_state *s;
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	if (!p || !priv)
138462306a36Sopenharmony_ci		return -EIO;
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	if (SND_SOC_DAPM_EVENT_ON(event))
138762306a36Sopenharmony_ci		s = pinctrl_lookup_state(p, priv->active_state);
138862306a36Sopenharmony_ci	else
138962306a36Sopenharmony_ci		s = pinctrl_lookup_state(p, priv->sleep_state);
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	if (IS_ERR(s))
139262306a36Sopenharmony_ci		return PTR_ERR(s);
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	return pinctrl_select_state(p, s);
139562306a36Sopenharmony_ci}
139662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dapm_pinctrl_event);
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci/*
139962306a36Sopenharmony_ci * Handler for clock supply widget.
140062306a36Sopenharmony_ci */
140162306a36Sopenharmony_ciint dapm_clock_event(struct snd_soc_dapm_widget *w,
140262306a36Sopenharmony_ci		   struct snd_kcontrol *kcontrol, int event)
140362306a36Sopenharmony_ci{
140462306a36Sopenharmony_ci	if (!w->clk)
140562306a36Sopenharmony_ci		return -EIO;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	soc_dapm_async_complete(w->dapm);
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	if (SND_SOC_DAPM_EVENT_ON(event)) {
141062306a36Sopenharmony_ci		return clk_prepare_enable(w->clk);
141162306a36Sopenharmony_ci	} else {
141262306a36Sopenharmony_ci		clk_disable_unprepare(w->clk);
141362306a36Sopenharmony_ci		return 0;
141462306a36Sopenharmony_ci	}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	return 0;
141762306a36Sopenharmony_ci}
141862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dapm_clock_event);
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_cistatic int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
142162306a36Sopenharmony_ci{
142262306a36Sopenharmony_ci	if (w->power_checked)
142362306a36Sopenharmony_ci		return w->new_power;
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	if (w->force)
142662306a36Sopenharmony_ci		w->new_power = 1;
142762306a36Sopenharmony_ci	else
142862306a36Sopenharmony_ci		w->new_power = w->power_check(w);
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	w->power_checked = true;
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	return w->new_power;
143362306a36Sopenharmony_ci}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci/* Generic check to see if a widget should be powered. */
143662306a36Sopenharmony_cistatic int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
143762306a36Sopenharmony_ci{
143862306a36Sopenharmony_ci	int in, out;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	DAPM_UPDATE_STAT(w, power_checks);
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	in = is_connected_input_ep(w, NULL, NULL);
144362306a36Sopenharmony_ci	out = is_connected_output_ep(w, NULL, NULL);
144462306a36Sopenharmony_ci	return out != 0 && in != 0;
144562306a36Sopenharmony_ci}
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci/* Check to see if a power supply is needed */
144862306a36Sopenharmony_cistatic int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
144962306a36Sopenharmony_ci{
145062306a36Sopenharmony_ci	struct snd_soc_dapm_path *path;
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	DAPM_UPDATE_STAT(w, power_checks);
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	/* Check if one of our outputs is connected */
145562306a36Sopenharmony_ci	snd_soc_dapm_widget_for_each_sink_path(w, path) {
145662306a36Sopenharmony_ci		DAPM_UPDATE_STAT(w, neighbour_checks);
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci		if (path->weak)
145962306a36Sopenharmony_ci			continue;
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci		if (path->connected &&
146262306a36Sopenharmony_ci		    !path->connected(path->source, path->sink))
146362306a36Sopenharmony_ci			continue;
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci		if (dapm_widget_power_check(path->sink))
146662306a36Sopenharmony_ci			return 1;
146762306a36Sopenharmony_ci	}
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	return 0;
147062306a36Sopenharmony_ci}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_cistatic int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
147362306a36Sopenharmony_ci{
147462306a36Sopenharmony_ci	return w->connected;
147562306a36Sopenharmony_ci}
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_cistatic int dapm_seq_compare(struct snd_soc_dapm_widget *a,
147862306a36Sopenharmony_ci			    struct snd_soc_dapm_widget *b,
147962306a36Sopenharmony_ci			    bool power_up)
148062306a36Sopenharmony_ci{
148162306a36Sopenharmony_ci	int *sort;
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	BUILD_BUG_ON(ARRAY_SIZE(dapm_up_seq) != SND_SOC_DAPM_TYPE_COUNT);
148462306a36Sopenharmony_ci	BUILD_BUG_ON(ARRAY_SIZE(dapm_down_seq) != SND_SOC_DAPM_TYPE_COUNT);
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	if (power_up)
148762306a36Sopenharmony_ci		sort = dapm_up_seq;
148862306a36Sopenharmony_ci	else
148962306a36Sopenharmony_ci		sort = dapm_down_seq;
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	WARN_ONCE(sort[a->id] == 0, "offset a->id %d not initialized\n", a->id);
149262306a36Sopenharmony_ci	WARN_ONCE(sort[b->id] == 0, "offset b->id %d not initialized\n", b->id);
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	if (sort[a->id] != sort[b->id])
149562306a36Sopenharmony_ci		return sort[a->id] - sort[b->id];
149662306a36Sopenharmony_ci	if (a->subseq != b->subseq) {
149762306a36Sopenharmony_ci		if (power_up)
149862306a36Sopenharmony_ci			return a->subseq - b->subseq;
149962306a36Sopenharmony_ci		else
150062306a36Sopenharmony_ci			return b->subseq - a->subseq;
150162306a36Sopenharmony_ci	}
150262306a36Sopenharmony_ci	if (a->reg != b->reg)
150362306a36Sopenharmony_ci		return a->reg - b->reg;
150462306a36Sopenharmony_ci	if (a->dapm != b->dapm)
150562306a36Sopenharmony_ci		return (unsigned long)a->dapm - (unsigned long)b->dapm;
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	return 0;
150862306a36Sopenharmony_ci}
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci/* Insert a widget in order into a DAPM power sequence. */
151162306a36Sopenharmony_cistatic void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
151262306a36Sopenharmony_ci			    struct list_head *list,
151362306a36Sopenharmony_ci			    bool power_up)
151462306a36Sopenharmony_ci{
151562306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	list_for_each_entry(w, list, power_list)
151862306a36Sopenharmony_ci		if (dapm_seq_compare(new_widget, w, power_up) < 0) {
151962306a36Sopenharmony_ci			list_add_tail(&new_widget->power_list, &w->power_list);
152062306a36Sopenharmony_ci			return;
152162306a36Sopenharmony_ci		}
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	list_add_tail(&new_widget->power_list, list);
152462306a36Sopenharmony_ci}
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_cistatic void dapm_seq_check_event(struct snd_soc_card *card,
152762306a36Sopenharmony_ci				 struct snd_soc_dapm_widget *w, int event)
152862306a36Sopenharmony_ci{
152962306a36Sopenharmony_ci	const char *ev_name;
153062306a36Sopenharmony_ci	int power;
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	switch (event) {
153362306a36Sopenharmony_ci	case SND_SOC_DAPM_PRE_PMU:
153462306a36Sopenharmony_ci		ev_name = "PRE_PMU";
153562306a36Sopenharmony_ci		power = 1;
153662306a36Sopenharmony_ci		break;
153762306a36Sopenharmony_ci	case SND_SOC_DAPM_POST_PMU:
153862306a36Sopenharmony_ci		ev_name = "POST_PMU";
153962306a36Sopenharmony_ci		power = 1;
154062306a36Sopenharmony_ci		break;
154162306a36Sopenharmony_ci	case SND_SOC_DAPM_PRE_PMD:
154262306a36Sopenharmony_ci		ev_name = "PRE_PMD";
154362306a36Sopenharmony_ci		power = 0;
154462306a36Sopenharmony_ci		break;
154562306a36Sopenharmony_ci	case SND_SOC_DAPM_POST_PMD:
154662306a36Sopenharmony_ci		ev_name = "POST_PMD";
154762306a36Sopenharmony_ci		power = 0;
154862306a36Sopenharmony_ci		break;
154962306a36Sopenharmony_ci	case SND_SOC_DAPM_WILL_PMU:
155062306a36Sopenharmony_ci		ev_name = "WILL_PMU";
155162306a36Sopenharmony_ci		power = 1;
155262306a36Sopenharmony_ci		break;
155362306a36Sopenharmony_ci	case SND_SOC_DAPM_WILL_PMD:
155462306a36Sopenharmony_ci		ev_name = "WILL_PMD";
155562306a36Sopenharmony_ci		power = 0;
155662306a36Sopenharmony_ci		break;
155762306a36Sopenharmony_ci	default:
155862306a36Sopenharmony_ci		WARN(1, "Unknown event %d\n", event);
155962306a36Sopenharmony_ci		return;
156062306a36Sopenharmony_ci	}
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	if (w->new_power != power)
156362306a36Sopenharmony_ci		return;
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	if (w->event && (w->event_flags & event)) {
156662306a36Sopenharmony_ci		int ret;
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci		pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
156962306a36Sopenharmony_ci			w->name, ev_name);
157062306a36Sopenharmony_ci		soc_dapm_async_complete(w->dapm);
157162306a36Sopenharmony_ci		trace_snd_soc_dapm_widget_event_start(w, event);
157262306a36Sopenharmony_ci		ret = w->event(w, NULL, event);
157362306a36Sopenharmony_ci		trace_snd_soc_dapm_widget_event_done(w, event);
157462306a36Sopenharmony_ci		if (ret < 0)
157562306a36Sopenharmony_ci			dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
157662306a36Sopenharmony_ci			       ev_name, w->name, ret);
157762306a36Sopenharmony_ci	}
157862306a36Sopenharmony_ci}
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci/* Apply the coalesced changes from a DAPM sequence */
158162306a36Sopenharmony_cistatic void dapm_seq_run_coalesced(struct snd_soc_card *card,
158262306a36Sopenharmony_ci				   struct list_head *pending)
158362306a36Sopenharmony_ci{
158462306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm;
158562306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
158662306a36Sopenharmony_ci	int reg;
158762306a36Sopenharmony_ci	unsigned int value = 0;
158862306a36Sopenharmony_ci	unsigned int mask = 0;
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	w = list_first_entry(pending, struct snd_soc_dapm_widget, power_list);
159162306a36Sopenharmony_ci	reg = w->reg;
159262306a36Sopenharmony_ci	dapm = w->dapm;
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	list_for_each_entry(w, pending, power_list) {
159562306a36Sopenharmony_ci		WARN_ON(reg != w->reg || dapm != w->dapm);
159662306a36Sopenharmony_ci		w->power = w->new_power;
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci		mask |= w->mask << w->shift;
159962306a36Sopenharmony_ci		if (w->power)
160062306a36Sopenharmony_ci			value |= w->on_val << w->shift;
160162306a36Sopenharmony_ci		else
160262306a36Sopenharmony_ci			value |= w->off_val << w->shift;
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci		pop_dbg(dapm->dev, card->pop_time,
160562306a36Sopenharmony_ci			"pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
160662306a36Sopenharmony_ci			w->name, reg, value, mask);
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci		/* Check for events */
160962306a36Sopenharmony_ci		dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU);
161062306a36Sopenharmony_ci		dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD);
161162306a36Sopenharmony_ci	}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	if (reg >= 0) {
161462306a36Sopenharmony_ci		/* Any widget will do, they should all be updating the
161562306a36Sopenharmony_ci		 * same register.
161662306a36Sopenharmony_ci		 */
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci		pop_dbg(dapm->dev, card->pop_time,
161962306a36Sopenharmony_ci			"pop test : Applying 0x%x/0x%x to %x in %dms\n",
162062306a36Sopenharmony_ci			value, mask, reg, card->pop_time);
162162306a36Sopenharmony_ci		pop_wait(card->pop_time);
162262306a36Sopenharmony_ci		soc_dapm_update_bits(dapm, reg, mask, value);
162362306a36Sopenharmony_ci	}
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	list_for_each_entry(w, pending, power_list) {
162662306a36Sopenharmony_ci		dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU);
162762306a36Sopenharmony_ci		dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD);
162862306a36Sopenharmony_ci	}
162962306a36Sopenharmony_ci}
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci/* Apply a DAPM power sequence.
163262306a36Sopenharmony_ci *
163362306a36Sopenharmony_ci * We walk over a pre-sorted list of widgets to apply power to.  In
163462306a36Sopenharmony_ci * order to minimise the number of writes to the device required
163562306a36Sopenharmony_ci * multiple widgets will be updated in a single write where possible.
163662306a36Sopenharmony_ci * Currently anything that requires more than a single write is not
163762306a36Sopenharmony_ci * handled.
163862306a36Sopenharmony_ci */
163962306a36Sopenharmony_cistatic void dapm_seq_run(struct snd_soc_card *card,
164062306a36Sopenharmony_ci	struct list_head *list, int event, bool power_up)
164162306a36Sopenharmony_ci{
164262306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w, *n;
164362306a36Sopenharmony_ci	struct snd_soc_dapm_context *d;
164462306a36Sopenharmony_ci	LIST_HEAD(pending);
164562306a36Sopenharmony_ci	int cur_sort = -1;
164662306a36Sopenharmony_ci	int cur_subseq = -1;
164762306a36Sopenharmony_ci	int cur_reg = SND_SOC_NOPM;
164862306a36Sopenharmony_ci	struct snd_soc_dapm_context *cur_dapm = NULL;
164962306a36Sopenharmony_ci	int i;
165062306a36Sopenharmony_ci	int *sort;
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	if (power_up)
165362306a36Sopenharmony_ci		sort = dapm_up_seq;
165462306a36Sopenharmony_ci	else
165562306a36Sopenharmony_ci		sort = dapm_down_seq;
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	list_for_each_entry_safe(w, n, list, power_list) {
165862306a36Sopenharmony_ci		int ret = 0;
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci		/* Do we need to apply any queued changes? */
166162306a36Sopenharmony_ci		if (sort[w->id] != cur_sort || w->reg != cur_reg ||
166262306a36Sopenharmony_ci		    w->dapm != cur_dapm || w->subseq != cur_subseq) {
166362306a36Sopenharmony_ci			if (!list_empty(&pending))
166462306a36Sopenharmony_ci				dapm_seq_run_coalesced(card, &pending);
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci			if (cur_dapm && cur_dapm->component) {
166762306a36Sopenharmony_ci				for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
166862306a36Sopenharmony_ci					if (sort[i] == cur_sort)
166962306a36Sopenharmony_ci						snd_soc_component_seq_notifier(
167062306a36Sopenharmony_ci							cur_dapm->component,
167162306a36Sopenharmony_ci							i, cur_subseq);
167262306a36Sopenharmony_ci			}
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci			if (cur_dapm && w->dapm != cur_dapm)
167562306a36Sopenharmony_ci				soc_dapm_async_complete(cur_dapm);
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci			INIT_LIST_HEAD(&pending);
167862306a36Sopenharmony_ci			cur_sort = -1;
167962306a36Sopenharmony_ci			cur_subseq = INT_MIN;
168062306a36Sopenharmony_ci			cur_reg = SND_SOC_NOPM;
168162306a36Sopenharmony_ci			cur_dapm = NULL;
168262306a36Sopenharmony_ci		}
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci		switch (w->id) {
168562306a36Sopenharmony_ci		case snd_soc_dapm_pre:
168662306a36Sopenharmony_ci			if (!w->event)
168762306a36Sopenharmony_ci				continue;
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci			if (event == SND_SOC_DAPM_STREAM_START)
169062306a36Sopenharmony_ci				ret = w->event(w,
169162306a36Sopenharmony_ci					       NULL, SND_SOC_DAPM_PRE_PMU);
169262306a36Sopenharmony_ci			else if (event == SND_SOC_DAPM_STREAM_STOP)
169362306a36Sopenharmony_ci				ret = w->event(w,
169462306a36Sopenharmony_ci					       NULL, SND_SOC_DAPM_PRE_PMD);
169562306a36Sopenharmony_ci			break;
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci		case snd_soc_dapm_post:
169862306a36Sopenharmony_ci			if (!w->event)
169962306a36Sopenharmony_ci				continue;
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci			if (event == SND_SOC_DAPM_STREAM_START)
170262306a36Sopenharmony_ci				ret = w->event(w,
170362306a36Sopenharmony_ci					       NULL, SND_SOC_DAPM_POST_PMU);
170462306a36Sopenharmony_ci			else if (event == SND_SOC_DAPM_STREAM_STOP)
170562306a36Sopenharmony_ci				ret = w->event(w,
170662306a36Sopenharmony_ci					       NULL, SND_SOC_DAPM_POST_PMD);
170762306a36Sopenharmony_ci			break;
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci		default:
171062306a36Sopenharmony_ci			/* Queue it up for application */
171162306a36Sopenharmony_ci			cur_sort = sort[w->id];
171262306a36Sopenharmony_ci			cur_subseq = w->subseq;
171362306a36Sopenharmony_ci			cur_reg = w->reg;
171462306a36Sopenharmony_ci			cur_dapm = w->dapm;
171562306a36Sopenharmony_ci			list_move(&w->power_list, &pending);
171662306a36Sopenharmony_ci			break;
171762306a36Sopenharmony_ci		}
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci		if (ret < 0)
172062306a36Sopenharmony_ci			dev_err(w->dapm->dev,
172162306a36Sopenharmony_ci				"ASoC: Failed to apply widget power: %d\n", ret);
172262306a36Sopenharmony_ci	}
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	if (!list_empty(&pending))
172562306a36Sopenharmony_ci		dapm_seq_run_coalesced(card, &pending);
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	if (cur_dapm && cur_dapm->component) {
172862306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
172962306a36Sopenharmony_ci			if (sort[i] == cur_sort)
173062306a36Sopenharmony_ci				snd_soc_component_seq_notifier(
173162306a36Sopenharmony_ci					cur_dapm->component,
173262306a36Sopenharmony_ci					i, cur_subseq);
173362306a36Sopenharmony_ci	}
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	for_each_card_dapms(card, d)
173662306a36Sopenharmony_ci		soc_dapm_async_complete(d);
173762306a36Sopenharmony_ci}
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_cistatic void dapm_widget_update(struct snd_soc_card *card)
174062306a36Sopenharmony_ci{
174162306a36Sopenharmony_ci	struct snd_soc_dapm_update *update = card->update;
174262306a36Sopenharmony_ci	struct snd_soc_dapm_widget_list *wlist;
174362306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w = NULL;
174462306a36Sopenharmony_ci	unsigned int wi;
174562306a36Sopenharmony_ci	int ret;
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	if (!update || !dapm_kcontrol_is_powered(update->kcontrol))
174862306a36Sopenharmony_ci		return;
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	wlist = dapm_kcontrol_get_wlist(update->kcontrol);
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci	for_each_dapm_widgets(wlist, wi, w) {
175362306a36Sopenharmony_ci		if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
175462306a36Sopenharmony_ci			ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
175562306a36Sopenharmony_ci			if (ret != 0)
175662306a36Sopenharmony_ci				dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
175762306a36Sopenharmony_ci					   w->name, ret);
175862306a36Sopenharmony_ci		}
175962306a36Sopenharmony_ci	}
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	if (!w)
176262306a36Sopenharmony_ci		return;
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	ret = soc_dapm_update_bits(w->dapm, update->reg, update->mask,
176562306a36Sopenharmony_ci		update->val);
176662306a36Sopenharmony_ci	if (ret < 0)
176762306a36Sopenharmony_ci		dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
176862306a36Sopenharmony_ci			w->name, ret);
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	if (update->has_second_set) {
177162306a36Sopenharmony_ci		ret = soc_dapm_update_bits(w->dapm, update->reg2,
177262306a36Sopenharmony_ci					   update->mask2, update->val2);
177362306a36Sopenharmony_ci		if (ret < 0)
177462306a36Sopenharmony_ci			dev_err(w->dapm->dev,
177562306a36Sopenharmony_ci				"ASoC: %s DAPM update failed: %d\n",
177662306a36Sopenharmony_ci				w->name, ret);
177762306a36Sopenharmony_ci	}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	for_each_dapm_widgets(wlist, wi, w) {
178062306a36Sopenharmony_ci		if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
178162306a36Sopenharmony_ci			ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
178262306a36Sopenharmony_ci			if (ret != 0)
178362306a36Sopenharmony_ci				dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
178462306a36Sopenharmony_ci					   w->name, ret);
178562306a36Sopenharmony_ci		}
178662306a36Sopenharmony_ci	}
178762306a36Sopenharmony_ci}
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci/* Async callback run prior to DAPM sequences - brings to _PREPARE if
179062306a36Sopenharmony_ci * they're changing state.
179162306a36Sopenharmony_ci */
179262306a36Sopenharmony_cistatic void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
179362306a36Sopenharmony_ci{
179462306a36Sopenharmony_ci	struct snd_soc_dapm_context *d = data;
179562306a36Sopenharmony_ci	int ret;
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	/* If we're off and we're not supposed to go into STANDBY */
179862306a36Sopenharmony_ci	if (d->bias_level == SND_SOC_BIAS_OFF &&
179962306a36Sopenharmony_ci	    d->target_bias_level != SND_SOC_BIAS_OFF) {
180062306a36Sopenharmony_ci		if (d->dev && cookie)
180162306a36Sopenharmony_ci			pm_runtime_get_sync(d->dev);
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci		ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
180462306a36Sopenharmony_ci		if (ret != 0)
180562306a36Sopenharmony_ci			dev_err(d->dev,
180662306a36Sopenharmony_ci				"ASoC: Failed to turn on bias: %d\n", ret);
180762306a36Sopenharmony_ci	}
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	/* Prepare for a transition to ON or away from ON */
181062306a36Sopenharmony_ci	if ((d->target_bias_level == SND_SOC_BIAS_ON &&
181162306a36Sopenharmony_ci	     d->bias_level != SND_SOC_BIAS_ON) ||
181262306a36Sopenharmony_ci	    (d->target_bias_level != SND_SOC_BIAS_ON &&
181362306a36Sopenharmony_ci	     d->bias_level == SND_SOC_BIAS_ON)) {
181462306a36Sopenharmony_ci		ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
181562306a36Sopenharmony_ci		if (ret != 0)
181662306a36Sopenharmony_ci			dev_err(d->dev,
181762306a36Sopenharmony_ci				"ASoC: Failed to prepare bias: %d\n", ret);
181862306a36Sopenharmony_ci	}
181962306a36Sopenharmony_ci}
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci/* Async callback run prior to DAPM sequences - brings to their final
182262306a36Sopenharmony_ci * state.
182362306a36Sopenharmony_ci */
182462306a36Sopenharmony_cistatic void dapm_post_sequence_async(void *data, async_cookie_t cookie)
182562306a36Sopenharmony_ci{
182662306a36Sopenharmony_ci	struct snd_soc_dapm_context *d = data;
182762306a36Sopenharmony_ci	int ret;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	/* If we just powered the last thing off drop to standby bias */
183062306a36Sopenharmony_ci	if (d->bias_level == SND_SOC_BIAS_PREPARE &&
183162306a36Sopenharmony_ci	    (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
183262306a36Sopenharmony_ci	     d->target_bias_level == SND_SOC_BIAS_OFF)) {
183362306a36Sopenharmony_ci		ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
183462306a36Sopenharmony_ci		if (ret != 0)
183562306a36Sopenharmony_ci			dev_err(d->dev, "ASoC: Failed to apply standby bias: %d\n",
183662306a36Sopenharmony_ci				ret);
183762306a36Sopenharmony_ci	}
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	/* If we're in standby and can support bias off then do that */
184062306a36Sopenharmony_ci	if (d->bias_level == SND_SOC_BIAS_STANDBY &&
184162306a36Sopenharmony_ci	    d->target_bias_level == SND_SOC_BIAS_OFF) {
184262306a36Sopenharmony_ci		ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
184362306a36Sopenharmony_ci		if (ret != 0)
184462306a36Sopenharmony_ci			dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n",
184562306a36Sopenharmony_ci				ret);
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci		if (d->dev && cookie)
184862306a36Sopenharmony_ci			pm_runtime_put(d->dev);
184962306a36Sopenharmony_ci	}
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	/* If we just powered up then move to active bias */
185262306a36Sopenharmony_ci	if (d->bias_level == SND_SOC_BIAS_PREPARE &&
185362306a36Sopenharmony_ci	    d->target_bias_level == SND_SOC_BIAS_ON) {
185462306a36Sopenharmony_ci		ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
185562306a36Sopenharmony_ci		if (ret != 0)
185662306a36Sopenharmony_ci			dev_err(d->dev, "ASoC: Failed to apply active bias: %d\n",
185762306a36Sopenharmony_ci				ret);
185862306a36Sopenharmony_ci	}
185962306a36Sopenharmony_ci}
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_cistatic void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
186262306a36Sopenharmony_ci				       bool power, bool connect)
186362306a36Sopenharmony_ci{
186462306a36Sopenharmony_ci	/* If a connection is being made or broken then that update
186562306a36Sopenharmony_ci	 * will have marked the peer dirty, otherwise the widgets are
186662306a36Sopenharmony_ci	 * not connected and this update has no impact. */
186762306a36Sopenharmony_ci	if (!connect)
186862306a36Sopenharmony_ci		return;
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	/* If the peer is already in the state we're moving to then we
187162306a36Sopenharmony_ci	 * won't have an impact on it. */
187262306a36Sopenharmony_ci	if (power != peer->power)
187362306a36Sopenharmony_ci		dapm_mark_dirty(peer, "peer state change");
187462306a36Sopenharmony_ci}
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_cistatic void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
187762306a36Sopenharmony_ci				  struct list_head *up_list,
187862306a36Sopenharmony_ci				  struct list_head *down_list)
187962306a36Sopenharmony_ci{
188062306a36Sopenharmony_ci	struct snd_soc_dapm_path *path;
188162306a36Sopenharmony_ci	int power;
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	switch (w->id) {
188462306a36Sopenharmony_ci	case snd_soc_dapm_pre:
188562306a36Sopenharmony_ci		power = 0;
188662306a36Sopenharmony_ci		goto end;
188762306a36Sopenharmony_ci	case snd_soc_dapm_post:
188862306a36Sopenharmony_ci		power = 1;
188962306a36Sopenharmony_ci		goto end;
189062306a36Sopenharmony_ci	default:
189162306a36Sopenharmony_ci		break;
189262306a36Sopenharmony_ci	}
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	power = dapm_widget_power_check(w);
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	if (w->power == power)
189762306a36Sopenharmony_ci		return;
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	trace_snd_soc_dapm_widget_power(w, power);
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	/*
190262306a36Sopenharmony_ci	 * If we changed our power state perhaps our neigbours
190362306a36Sopenharmony_ci	 * changed also.
190462306a36Sopenharmony_ci	 */
190562306a36Sopenharmony_ci	snd_soc_dapm_widget_for_each_source_path(w, path)
190662306a36Sopenharmony_ci		dapm_widget_set_peer_power(path->source, power, path->connect);
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci	/*
190962306a36Sopenharmony_ci	 * Supplies can't affect their outputs, only their inputs
191062306a36Sopenharmony_ci	 */
191162306a36Sopenharmony_ci	if (!w->is_supply)
191262306a36Sopenharmony_ci		snd_soc_dapm_widget_for_each_sink_path(w, path)
191362306a36Sopenharmony_ci			dapm_widget_set_peer_power(path->sink, power, path->connect);
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ciend:
191662306a36Sopenharmony_ci	if (power)
191762306a36Sopenharmony_ci		dapm_seq_insert(w, up_list, true);
191862306a36Sopenharmony_ci	else
191962306a36Sopenharmony_ci		dapm_seq_insert(w, down_list, false);
192062306a36Sopenharmony_ci}
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_cistatic bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
192362306a36Sopenharmony_ci{
192462306a36Sopenharmony_ci	if (dapm->idle_bias_off)
192562306a36Sopenharmony_ci		return true;
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	switch (snd_power_get_state(dapm->card->snd_card)) {
192862306a36Sopenharmony_ci	case SNDRV_CTL_POWER_D3hot:
192962306a36Sopenharmony_ci	case SNDRV_CTL_POWER_D3cold:
193062306a36Sopenharmony_ci		return dapm->suspend_bias_off;
193162306a36Sopenharmony_ci	default:
193262306a36Sopenharmony_ci		break;
193362306a36Sopenharmony_ci	}
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	return false;
193662306a36Sopenharmony_ci}
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci/*
193962306a36Sopenharmony_ci * Scan each dapm widget for complete audio path.
194062306a36Sopenharmony_ci * A complete path is a route that has valid endpoints i.e.:-
194162306a36Sopenharmony_ci *
194262306a36Sopenharmony_ci *  o DAC to output pin.
194362306a36Sopenharmony_ci *  o Input pin to ADC.
194462306a36Sopenharmony_ci *  o Input pin to Output pin (bypass, sidetone)
194562306a36Sopenharmony_ci *  o DAC to ADC (loopback).
194662306a36Sopenharmony_ci */
194762306a36Sopenharmony_cistatic int dapm_power_widgets(struct snd_soc_card *card, int event)
194862306a36Sopenharmony_ci{
194962306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
195062306a36Sopenharmony_ci	struct snd_soc_dapm_context *d;
195162306a36Sopenharmony_ci	LIST_HEAD(up_list);
195262306a36Sopenharmony_ci	LIST_HEAD(down_list);
195362306a36Sopenharmony_ci	ASYNC_DOMAIN_EXCLUSIVE(async_domain);
195462306a36Sopenharmony_ci	enum snd_soc_bias_level bias;
195562306a36Sopenharmony_ci	int ret;
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci	snd_soc_dapm_mutex_assert_held(card);
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	trace_snd_soc_dapm_start(card);
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	for_each_card_dapms(card, d) {
196262306a36Sopenharmony_ci		if (dapm_idle_bias_off(d))
196362306a36Sopenharmony_ci			d->target_bias_level = SND_SOC_BIAS_OFF;
196462306a36Sopenharmony_ci		else
196562306a36Sopenharmony_ci			d->target_bias_level = SND_SOC_BIAS_STANDBY;
196662306a36Sopenharmony_ci	}
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	dapm_reset(card);
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	/* Check which widgets we need to power and store them in
197162306a36Sopenharmony_ci	 * lists indicating if they should be powered up or down.  We
197262306a36Sopenharmony_ci	 * only check widgets that have been flagged as dirty but note
197362306a36Sopenharmony_ci	 * that new widgets may be added to the dirty list while we
197462306a36Sopenharmony_ci	 * iterate.
197562306a36Sopenharmony_ci	 */
197662306a36Sopenharmony_ci	list_for_each_entry(w, &card->dapm_dirty, dirty) {
197762306a36Sopenharmony_ci		dapm_power_one_widget(w, &up_list, &down_list);
197862306a36Sopenharmony_ci	}
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	for_each_card_widgets(card, w) {
198162306a36Sopenharmony_ci		switch (w->id) {
198262306a36Sopenharmony_ci		case snd_soc_dapm_pre:
198362306a36Sopenharmony_ci		case snd_soc_dapm_post:
198462306a36Sopenharmony_ci			/* These widgets always need to be powered */
198562306a36Sopenharmony_ci			break;
198662306a36Sopenharmony_ci		default:
198762306a36Sopenharmony_ci			list_del_init(&w->dirty);
198862306a36Sopenharmony_ci			break;
198962306a36Sopenharmony_ci		}
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci		if (w->new_power) {
199262306a36Sopenharmony_ci			d = w->dapm;
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci			/* Supplies and micbiases only bring the
199562306a36Sopenharmony_ci			 * context up to STANDBY as unless something
199662306a36Sopenharmony_ci			 * else is active and passing audio they
199762306a36Sopenharmony_ci			 * generally don't require full power.  Signal
199862306a36Sopenharmony_ci			 * generators are virtual pins and have no
199962306a36Sopenharmony_ci			 * power impact themselves.
200062306a36Sopenharmony_ci			 */
200162306a36Sopenharmony_ci			switch (w->id) {
200262306a36Sopenharmony_ci			case snd_soc_dapm_siggen:
200362306a36Sopenharmony_ci			case snd_soc_dapm_vmid:
200462306a36Sopenharmony_ci				break;
200562306a36Sopenharmony_ci			case snd_soc_dapm_supply:
200662306a36Sopenharmony_ci			case snd_soc_dapm_regulator_supply:
200762306a36Sopenharmony_ci			case snd_soc_dapm_pinctrl:
200862306a36Sopenharmony_ci			case snd_soc_dapm_clock_supply:
200962306a36Sopenharmony_ci			case snd_soc_dapm_micbias:
201062306a36Sopenharmony_ci				if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
201162306a36Sopenharmony_ci					d->target_bias_level = SND_SOC_BIAS_STANDBY;
201262306a36Sopenharmony_ci				break;
201362306a36Sopenharmony_ci			default:
201462306a36Sopenharmony_ci				d->target_bias_level = SND_SOC_BIAS_ON;
201562306a36Sopenharmony_ci				break;
201662306a36Sopenharmony_ci			}
201762306a36Sopenharmony_ci		}
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	}
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_ci	/* Force all contexts in the card to the same bias state if
202262306a36Sopenharmony_ci	 * they're not ground referenced.
202362306a36Sopenharmony_ci	 */
202462306a36Sopenharmony_ci	bias = SND_SOC_BIAS_OFF;
202562306a36Sopenharmony_ci	for_each_card_dapms(card, d)
202662306a36Sopenharmony_ci		if (d->target_bias_level > bias)
202762306a36Sopenharmony_ci			bias = d->target_bias_level;
202862306a36Sopenharmony_ci	for_each_card_dapms(card, d)
202962306a36Sopenharmony_ci		if (!dapm_idle_bias_off(d))
203062306a36Sopenharmony_ci			d->target_bias_level = bias;
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	trace_snd_soc_dapm_walk_done(card);
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci	/* Run card bias changes at first */
203562306a36Sopenharmony_ci	dapm_pre_sequence_async(&card->dapm, 0);
203662306a36Sopenharmony_ci	/* Run other bias changes in parallel */
203762306a36Sopenharmony_ci	for_each_card_dapms(card, d) {
203862306a36Sopenharmony_ci		if (d != &card->dapm && d->bias_level != d->target_bias_level)
203962306a36Sopenharmony_ci			async_schedule_domain(dapm_pre_sequence_async, d,
204062306a36Sopenharmony_ci						&async_domain);
204162306a36Sopenharmony_ci	}
204262306a36Sopenharmony_ci	async_synchronize_full_domain(&async_domain);
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_ci	list_for_each_entry(w, &down_list, power_list) {
204562306a36Sopenharmony_ci		dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD);
204662306a36Sopenharmony_ci	}
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	list_for_each_entry(w, &up_list, power_list) {
204962306a36Sopenharmony_ci		dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU);
205062306a36Sopenharmony_ci	}
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	/* Power down widgets first; try to avoid amplifying pops. */
205362306a36Sopenharmony_ci	dapm_seq_run(card, &down_list, event, false);
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	dapm_widget_update(card);
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	/* Now power up. */
205862306a36Sopenharmony_ci	dapm_seq_run(card, &up_list, event, true);
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	/* Run all the bias changes in parallel */
206162306a36Sopenharmony_ci	for_each_card_dapms(card, d) {
206262306a36Sopenharmony_ci		if (d != &card->dapm && d->bias_level != d->target_bias_level)
206362306a36Sopenharmony_ci			async_schedule_domain(dapm_post_sequence_async, d,
206462306a36Sopenharmony_ci						&async_domain);
206562306a36Sopenharmony_ci	}
206662306a36Sopenharmony_ci	async_synchronize_full_domain(&async_domain);
206762306a36Sopenharmony_ci	/* Run card bias changes at last */
206862306a36Sopenharmony_ci	dapm_post_sequence_async(&card->dapm, 0);
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci	/* do we need to notify any clients that DAPM event is complete */
207162306a36Sopenharmony_ci	for_each_card_dapms(card, d) {
207262306a36Sopenharmony_ci		if (!d->component)
207362306a36Sopenharmony_ci			continue;
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci		ret = snd_soc_component_stream_event(d->component, event);
207662306a36Sopenharmony_ci		if (ret < 0)
207762306a36Sopenharmony_ci			return ret;
207862306a36Sopenharmony_ci	}
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci	pop_dbg(card->dev, card->pop_time,
208162306a36Sopenharmony_ci		"DAPM sequencing finished, waiting %dms\n", card->pop_time);
208262306a36Sopenharmony_ci	pop_wait(card->pop_time);
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	trace_snd_soc_dapm_done(card);
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	return 0;
208762306a36Sopenharmony_ci}
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
209062306a36Sopenharmony_cistatic ssize_t dapm_widget_power_read_file(struct file *file,
209162306a36Sopenharmony_ci					   char __user *user_buf,
209262306a36Sopenharmony_ci					   size_t count, loff_t *ppos)
209362306a36Sopenharmony_ci{
209462306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w = file->private_data;
209562306a36Sopenharmony_ci	enum snd_soc_dapm_direction dir, rdir;
209662306a36Sopenharmony_ci	char *buf;
209762306a36Sopenharmony_ci	int in, out;
209862306a36Sopenharmony_ci	ssize_t ret;
209962306a36Sopenharmony_ci	struct snd_soc_dapm_path *p = NULL;
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
210262306a36Sopenharmony_ci	if (!buf)
210362306a36Sopenharmony_ci		return -ENOMEM;
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock_root(w->dapm);
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci	/* Supply widgets are not handled by is_connected_{input,output}_ep() */
210862306a36Sopenharmony_ci	if (w->is_supply) {
210962306a36Sopenharmony_ci		in = 0;
211062306a36Sopenharmony_ci		out = 0;
211162306a36Sopenharmony_ci	} else {
211262306a36Sopenharmony_ci		in = is_connected_input_ep(w, NULL, NULL);
211362306a36Sopenharmony_ci		out = is_connected_output_ep(w, NULL, NULL);
211462306a36Sopenharmony_ci	}
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	ret = scnprintf(buf, PAGE_SIZE, "%s: %s%s  in %d out %d",
211762306a36Sopenharmony_ci		       w->name, w->power ? "On" : "Off",
211862306a36Sopenharmony_ci		       w->force ? " (forced)" : "", in, out);
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	if (w->reg >= 0)
212162306a36Sopenharmony_ci		ret += scnprintf(buf + ret, PAGE_SIZE - ret,
212262306a36Sopenharmony_ci				" - R%d(0x%x) mask 0x%x",
212362306a36Sopenharmony_ci				w->reg, w->reg, w->mask << w->shift);
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci	ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	if (w->sname)
212862306a36Sopenharmony_ci		ret += scnprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
212962306a36Sopenharmony_ci				w->sname,
213062306a36Sopenharmony_ci				w->active ? "active" : "inactive");
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci	snd_soc_dapm_for_each_direction(dir) {
213362306a36Sopenharmony_ci		rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
213462306a36Sopenharmony_ci		snd_soc_dapm_widget_for_each_path(w, dir, p) {
213562306a36Sopenharmony_ci			if (p->connected && !p->connected(p->source, p->sink))
213662306a36Sopenharmony_ci				continue;
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci			if (!p->connect)
213962306a36Sopenharmony_ci				continue;
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci			ret += scnprintf(buf + ret, PAGE_SIZE - ret,
214262306a36Sopenharmony_ci					" %s  \"%s\" \"%s\"\n",
214362306a36Sopenharmony_ci					(rdir == SND_SOC_DAPM_DIR_IN) ? "in" : "out",
214462306a36Sopenharmony_ci					p->name ? p->name : "static",
214562306a36Sopenharmony_ci					p->node[rdir]->name);
214662306a36Sopenharmony_ci		}
214762306a36Sopenharmony_ci	}
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(w->dapm);
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	kfree(buf);
215462306a36Sopenharmony_ci	return ret;
215562306a36Sopenharmony_ci}
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_cistatic const struct file_operations dapm_widget_power_fops = {
215862306a36Sopenharmony_ci	.open = simple_open,
215962306a36Sopenharmony_ci	.read = dapm_widget_power_read_file,
216062306a36Sopenharmony_ci	.llseek = default_llseek,
216162306a36Sopenharmony_ci};
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_cistatic ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
216462306a36Sopenharmony_ci				   size_t count, loff_t *ppos)
216562306a36Sopenharmony_ci{
216662306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm = file->private_data;
216762306a36Sopenharmony_ci	char *level;
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci	switch (dapm->bias_level) {
217062306a36Sopenharmony_ci	case SND_SOC_BIAS_ON:
217162306a36Sopenharmony_ci		level = "On\n";
217262306a36Sopenharmony_ci		break;
217362306a36Sopenharmony_ci	case SND_SOC_BIAS_PREPARE:
217462306a36Sopenharmony_ci		level = "Prepare\n";
217562306a36Sopenharmony_ci		break;
217662306a36Sopenharmony_ci	case SND_SOC_BIAS_STANDBY:
217762306a36Sopenharmony_ci		level = "Standby\n";
217862306a36Sopenharmony_ci		break;
217962306a36Sopenharmony_ci	case SND_SOC_BIAS_OFF:
218062306a36Sopenharmony_ci		level = "Off\n";
218162306a36Sopenharmony_ci		break;
218262306a36Sopenharmony_ci	default:
218362306a36Sopenharmony_ci		WARN(1, "Unknown bias_level %d\n", dapm->bias_level);
218462306a36Sopenharmony_ci		level = "Unknown\n";
218562306a36Sopenharmony_ci		break;
218662306a36Sopenharmony_ci	}
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	return simple_read_from_buffer(user_buf, count, ppos, level,
218962306a36Sopenharmony_ci				       strlen(level));
219062306a36Sopenharmony_ci}
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_cistatic const struct file_operations dapm_bias_fops = {
219362306a36Sopenharmony_ci	.open = simple_open,
219462306a36Sopenharmony_ci	.read = dapm_bias_read_file,
219562306a36Sopenharmony_ci	.llseek = default_llseek,
219662306a36Sopenharmony_ci};
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_civoid snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
219962306a36Sopenharmony_ci	struct dentry *parent)
220062306a36Sopenharmony_ci{
220162306a36Sopenharmony_ci	if (!parent || IS_ERR(parent))
220262306a36Sopenharmony_ci		return;
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci	dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci	debugfs_create_file("bias_level", 0444, dapm->debugfs_dapm, dapm,
220762306a36Sopenharmony_ci			    &dapm_bias_fops);
220862306a36Sopenharmony_ci}
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_cistatic void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
221162306a36Sopenharmony_ci{
221262306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm = w->dapm;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	if (!dapm->debugfs_dapm || !w->name)
221562306a36Sopenharmony_ci		return;
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci	debugfs_create_file(w->name, 0444, dapm->debugfs_dapm, w,
221862306a36Sopenharmony_ci			    &dapm_widget_power_fops);
221962306a36Sopenharmony_ci}
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_cistatic void dapm_debugfs_free_widget(struct snd_soc_dapm_widget *w)
222262306a36Sopenharmony_ci{
222362306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm = w->dapm;
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	if (!dapm->debugfs_dapm || !w->name)
222662306a36Sopenharmony_ci		return;
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci	debugfs_lookup_and_remove(w->name, dapm->debugfs_dapm);
222962306a36Sopenharmony_ci}
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_cistatic void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
223262306a36Sopenharmony_ci{
223362306a36Sopenharmony_ci	debugfs_remove_recursive(dapm->debugfs_dapm);
223462306a36Sopenharmony_ci	dapm->debugfs_dapm = NULL;
223562306a36Sopenharmony_ci}
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci#else
223862306a36Sopenharmony_civoid snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
223962306a36Sopenharmony_ci	struct dentry *parent)
224062306a36Sopenharmony_ci{
224162306a36Sopenharmony_ci}
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_cistatic inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
224462306a36Sopenharmony_ci{
224562306a36Sopenharmony_ci}
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_cistatic inline void dapm_debugfs_free_widget(struct snd_soc_dapm_widget *w)
224862306a36Sopenharmony_ci{
224962306a36Sopenharmony_ci}
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_cistatic inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
225262306a36Sopenharmony_ci{
225362306a36Sopenharmony_ci}
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci#endif
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci/*
225862306a36Sopenharmony_ci * soc_dapm_connect_path() - Connects or disconnects a path
225962306a36Sopenharmony_ci * @path: The path to update
226062306a36Sopenharmony_ci * @connect: The new connect state of the path. True if the path is connected,
226162306a36Sopenharmony_ci *  false if it is disconnected.
226262306a36Sopenharmony_ci * @reason: The reason why the path changed (for debugging only)
226362306a36Sopenharmony_ci */
226462306a36Sopenharmony_cistatic void soc_dapm_connect_path(struct snd_soc_dapm_path *path,
226562306a36Sopenharmony_ci	bool connect, const char *reason)
226662306a36Sopenharmony_ci{
226762306a36Sopenharmony_ci	if (path->connect == connect)
226862306a36Sopenharmony_ci		return;
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci	path->connect = connect;
227162306a36Sopenharmony_ci	dapm_mark_dirty(path->source, reason);
227262306a36Sopenharmony_ci	dapm_mark_dirty(path->sink, reason);
227362306a36Sopenharmony_ci	dapm_path_invalidate(path);
227462306a36Sopenharmony_ci}
227562306a36Sopenharmony_ci
227662306a36Sopenharmony_ci/* test and update the power status of a mux widget */
227762306a36Sopenharmony_cistatic int soc_dapm_mux_update_power(struct snd_soc_card *card,
227862306a36Sopenharmony_ci				 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
227962306a36Sopenharmony_ci{
228062306a36Sopenharmony_ci	struct snd_soc_dapm_path *path;
228162306a36Sopenharmony_ci	int found = 0;
228262306a36Sopenharmony_ci	bool connect;
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	snd_soc_dapm_mutex_assert_held(card);
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci	/* find dapm widget path assoc with kcontrol */
228762306a36Sopenharmony_ci	dapm_kcontrol_for_each_path(path, kcontrol) {
228862306a36Sopenharmony_ci		found = 1;
228962306a36Sopenharmony_ci		/* we now need to match the string in the enum to the path */
229062306a36Sopenharmony_ci		if (e && !(strcmp(path->name, e->texts[mux])))
229162306a36Sopenharmony_ci			connect = true;
229262306a36Sopenharmony_ci		else
229362306a36Sopenharmony_ci			connect = false;
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci		soc_dapm_connect_path(path, connect, "mux update");
229662306a36Sopenharmony_ci	}
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci	if (found)
229962306a36Sopenharmony_ci		dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	return found;
230262306a36Sopenharmony_ci}
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ciint snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
230562306a36Sopenharmony_ci	struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
230662306a36Sopenharmony_ci	struct snd_soc_dapm_update *update)
230762306a36Sopenharmony_ci{
230862306a36Sopenharmony_ci	struct snd_soc_card *card = dapm->card;
230962306a36Sopenharmony_ci	int ret;
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(card);
231262306a36Sopenharmony_ci	card->update = update;
231362306a36Sopenharmony_ci	ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
231462306a36Sopenharmony_ci	card->update = NULL;
231562306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(card);
231662306a36Sopenharmony_ci	if (ret > 0)
231762306a36Sopenharmony_ci		snd_soc_dpcm_runtime_update(card);
231862306a36Sopenharmony_ci	return ret;
231962306a36Sopenharmony_ci}
232062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci/* test and update the power status of a mixer or switch widget */
232362306a36Sopenharmony_cistatic int soc_dapm_mixer_update_power(struct snd_soc_card *card,
232462306a36Sopenharmony_ci				       struct snd_kcontrol *kcontrol,
232562306a36Sopenharmony_ci				       int connect, int rconnect)
232662306a36Sopenharmony_ci{
232762306a36Sopenharmony_ci	struct snd_soc_dapm_path *path;
232862306a36Sopenharmony_ci	int found = 0;
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	snd_soc_dapm_mutex_assert_held(card);
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci	/* find dapm widget path assoc with kcontrol */
233362306a36Sopenharmony_ci	dapm_kcontrol_for_each_path(path, kcontrol) {
233462306a36Sopenharmony_ci		/*
233562306a36Sopenharmony_ci		 * Ideally this function should support any number of
233662306a36Sopenharmony_ci		 * paths and channels. But since kcontrols only come
233762306a36Sopenharmony_ci		 * in mono and stereo variants, we are limited to 2
233862306a36Sopenharmony_ci		 * channels.
233962306a36Sopenharmony_ci		 *
234062306a36Sopenharmony_ci		 * The following code assumes for stereo controls the
234162306a36Sopenharmony_ci		 * first path (when 'found == 0') is the left channel,
234262306a36Sopenharmony_ci		 * and all remaining paths (when 'found == 1') are the
234362306a36Sopenharmony_ci		 * right channel.
234462306a36Sopenharmony_ci		 *
234562306a36Sopenharmony_ci		 * A stereo control is signified by a valid 'rconnect'
234662306a36Sopenharmony_ci		 * value, either 0 for unconnected, or >= 0 for connected.
234762306a36Sopenharmony_ci		 * This is chosen instead of using snd_soc_volsw_is_stereo,
234862306a36Sopenharmony_ci		 * so that the behavior of snd_soc_dapm_mixer_update_power
234962306a36Sopenharmony_ci		 * doesn't change even when the kcontrol passed in is
235062306a36Sopenharmony_ci		 * stereo.
235162306a36Sopenharmony_ci		 *
235262306a36Sopenharmony_ci		 * It passes 'connect' as the path connect status for
235362306a36Sopenharmony_ci		 * the left channel, and 'rconnect' for the right
235462306a36Sopenharmony_ci		 * channel.
235562306a36Sopenharmony_ci		 */
235662306a36Sopenharmony_ci		if (found && rconnect >= 0)
235762306a36Sopenharmony_ci			soc_dapm_connect_path(path, rconnect, "mixer update");
235862306a36Sopenharmony_ci		else
235962306a36Sopenharmony_ci			soc_dapm_connect_path(path, connect, "mixer update");
236062306a36Sopenharmony_ci		found = 1;
236162306a36Sopenharmony_ci	}
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci	if (found)
236462306a36Sopenharmony_ci		dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci	return found;
236762306a36Sopenharmony_ci}
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ciint snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
237062306a36Sopenharmony_ci	struct snd_kcontrol *kcontrol, int connect,
237162306a36Sopenharmony_ci	struct snd_soc_dapm_update *update)
237262306a36Sopenharmony_ci{
237362306a36Sopenharmony_ci	struct snd_soc_card *card = dapm->card;
237462306a36Sopenharmony_ci	int ret;
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(card);
237762306a36Sopenharmony_ci	card->update = update;
237862306a36Sopenharmony_ci	ret = soc_dapm_mixer_update_power(card, kcontrol, connect, -1);
237962306a36Sopenharmony_ci	card->update = NULL;
238062306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(card);
238162306a36Sopenharmony_ci	if (ret > 0)
238262306a36Sopenharmony_ci		snd_soc_dpcm_runtime_update(card);
238362306a36Sopenharmony_ci	return ret;
238462306a36Sopenharmony_ci}
238562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_cistatic ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt,
238862306a36Sopenharmony_ci					  char *buf, int count)
238962306a36Sopenharmony_ci{
239062306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
239162306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
239262306a36Sopenharmony_ci	char *state = "not set";
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci	/* card won't be set for the dummy component, as a spot fix
239562306a36Sopenharmony_ci	 * we're checking for that case specifically here but in future
239662306a36Sopenharmony_ci	 * we will ensure that the dummy component looks like others.
239762306a36Sopenharmony_ci	 */
239862306a36Sopenharmony_ci	if (!cmpnt->card)
239962306a36Sopenharmony_ci		return 0;
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci	for_each_card_widgets(cmpnt->card, w) {
240262306a36Sopenharmony_ci		if (w->dapm != dapm)
240362306a36Sopenharmony_ci			continue;
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci		/* only display widgets that burn power */
240662306a36Sopenharmony_ci		switch (w->id) {
240762306a36Sopenharmony_ci		case snd_soc_dapm_hp:
240862306a36Sopenharmony_ci		case snd_soc_dapm_mic:
240962306a36Sopenharmony_ci		case snd_soc_dapm_spk:
241062306a36Sopenharmony_ci		case snd_soc_dapm_line:
241162306a36Sopenharmony_ci		case snd_soc_dapm_micbias:
241262306a36Sopenharmony_ci		case snd_soc_dapm_dac:
241362306a36Sopenharmony_ci		case snd_soc_dapm_adc:
241462306a36Sopenharmony_ci		case snd_soc_dapm_pga:
241562306a36Sopenharmony_ci		case snd_soc_dapm_effect:
241662306a36Sopenharmony_ci		case snd_soc_dapm_out_drv:
241762306a36Sopenharmony_ci		case snd_soc_dapm_mixer:
241862306a36Sopenharmony_ci		case snd_soc_dapm_mixer_named_ctl:
241962306a36Sopenharmony_ci		case snd_soc_dapm_supply:
242062306a36Sopenharmony_ci		case snd_soc_dapm_regulator_supply:
242162306a36Sopenharmony_ci		case snd_soc_dapm_pinctrl:
242262306a36Sopenharmony_ci		case snd_soc_dapm_clock_supply:
242362306a36Sopenharmony_ci			if (w->name)
242462306a36Sopenharmony_ci				count += sysfs_emit_at(buf, count, "%s: %s\n",
242562306a36Sopenharmony_ci					w->name, w->power ? "On":"Off");
242662306a36Sopenharmony_ci		break;
242762306a36Sopenharmony_ci		default:
242862306a36Sopenharmony_ci		break;
242962306a36Sopenharmony_ci		}
243062306a36Sopenharmony_ci	}
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_ci	switch (snd_soc_dapm_get_bias_level(dapm)) {
243362306a36Sopenharmony_ci	case SND_SOC_BIAS_ON:
243462306a36Sopenharmony_ci		state = "On";
243562306a36Sopenharmony_ci		break;
243662306a36Sopenharmony_ci	case SND_SOC_BIAS_PREPARE:
243762306a36Sopenharmony_ci		state = "Prepare";
243862306a36Sopenharmony_ci		break;
243962306a36Sopenharmony_ci	case SND_SOC_BIAS_STANDBY:
244062306a36Sopenharmony_ci		state = "Standby";
244162306a36Sopenharmony_ci		break;
244262306a36Sopenharmony_ci	case SND_SOC_BIAS_OFF:
244362306a36Sopenharmony_ci		state = "Off";
244462306a36Sopenharmony_ci		break;
244562306a36Sopenharmony_ci	}
244662306a36Sopenharmony_ci	count += sysfs_emit_at(buf, count, "PM State: %s\n", state);
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	return count;
244962306a36Sopenharmony_ci}
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci/* show dapm widget status in sys fs */
245262306a36Sopenharmony_cistatic ssize_t dapm_widget_show(struct device *dev,
245362306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
245462306a36Sopenharmony_ci{
245562306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
245662306a36Sopenharmony_ci	struct snd_soc_dai *codec_dai;
245762306a36Sopenharmony_ci	int i, count = 0;
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock_root(rtd->card);
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci	for_each_rtd_codec_dais(rtd, i, codec_dai) {
246262306a36Sopenharmony_ci		struct snd_soc_component *cmpnt = codec_dai->component;
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci		count = dapm_widget_show_component(cmpnt, buf, count);
246562306a36Sopenharmony_ci	}
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(rtd->card);
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci	return count;
247062306a36Sopenharmony_ci}
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(dapm_widget);
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_cistruct attribute *soc_dapm_dev_attrs[] = {
247562306a36Sopenharmony_ci	&dev_attr_dapm_widget.attr,
247662306a36Sopenharmony_ci	NULL
247762306a36Sopenharmony_ci};
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_cistatic void dapm_free_path(struct snd_soc_dapm_path *path)
248062306a36Sopenharmony_ci{
248162306a36Sopenharmony_ci	list_del(&path->list_node[SND_SOC_DAPM_DIR_IN]);
248262306a36Sopenharmony_ci	list_del(&path->list_node[SND_SOC_DAPM_DIR_OUT]);
248362306a36Sopenharmony_ci	list_del(&path->list_kcontrol);
248462306a36Sopenharmony_ci	list_del(&path->list);
248562306a36Sopenharmony_ci	kfree(path);
248662306a36Sopenharmony_ci}
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci/**
248962306a36Sopenharmony_ci * snd_soc_dapm_free_widget - Free specified widget
249062306a36Sopenharmony_ci * @w: widget to free
249162306a36Sopenharmony_ci *
249262306a36Sopenharmony_ci * Removes widget from all paths and frees memory occupied by it.
249362306a36Sopenharmony_ci */
249462306a36Sopenharmony_civoid snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
249562306a36Sopenharmony_ci{
249662306a36Sopenharmony_ci	struct snd_soc_dapm_path *p, *next_p;
249762306a36Sopenharmony_ci	enum snd_soc_dapm_direction dir;
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci	if (!w)
250062306a36Sopenharmony_ci		return;
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci	list_del(&w->list);
250362306a36Sopenharmony_ci	list_del(&w->dirty);
250462306a36Sopenharmony_ci	/*
250562306a36Sopenharmony_ci	 * remove source and sink paths associated to this widget.
250662306a36Sopenharmony_ci	 * While removing the path, remove reference to it from both
250762306a36Sopenharmony_ci	 * source and sink widgets so that path is removed only once.
250862306a36Sopenharmony_ci	 */
250962306a36Sopenharmony_ci	snd_soc_dapm_for_each_direction(dir) {
251062306a36Sopenharmony_ci		snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p)
251162306a36Sopenharmony_ci			dapm_free_path(p);
251262306a36Sopenharmony_ci	}
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci	dapm_debugfs_free_widget(w);
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci	kfree(w->kcontrols);
251762306a36Sopenharmony_ci	kfree_const(w->name);
251862306a36Sopenharmony_ci	kfree_const(w->sname);
251962306a36Sopenharmony_ci	kfree(w);
252062306a36Sopenharmony_ci}
252162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_free_widget);
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci/* free all dapm widgets and resources */
252462306a36Sopenharmony_cistatic void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
252562306a36Sopenharmony_ci{
252662306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w, *next_w;
252762306a36Sopenharmony_ci
252862306a36Sopenharmony_ci	for_each_card_widgets_safe(dapm->card, w, next_w) {
252962306a36Sopenharmony_ci		if (w->dapm != dapm)
253062306a36Sopenharmony_ci			continue;
253162306a36Sopenharmony_ci		snd_soc_dapm_free_widget(w);
253262306a36Sopenharmony_ci	}
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci	dapm->wcache_sink	= NULL;
253562306a36Sopenharmony_ci	dapm->wcache_source	= NULL;
253662306a36Sopenharmony_ci}
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_cistatic struct snd_soc_dapm_widget *dapm_find_widget(
253962306a36Sopenharmony_ci			struct snd_soc_dapm_context *dapm, const char *pin,
254062306a36Sopenharmony_ci			bool search_other_contexts)
254162306a36Sopenharmony_ci{
254262306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
254362306a36Sopenharmony_ci	struct snd_soc_dapm_widget *fallback = NULL;
254462306a36Sopenharmony_ci	char prefixed_pin[80];
254562306a36Sopenharmony_ci	const char *pin_name;
254662306a36Sopenharmony_ci	const char *prefix = soc_dapm_prefix(dapm);
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ci	if (prefix) {
254962306a36Sopenharmony_ci		snprintf(prefixed_pin, sizeof(prefixed_pin), "%s %s",
255062306a36Sopenharmony_ci			 prefix, pin);
255162306a36Sopenharmony_ci		pin_name = prefixed_pin;
255262306a36Sopenharmony_ci	} else {
255362306a36Sopenharmony_ci		pin_name = pin;
255462306a36Sopenharmony_ci	}
255562306a36Sopenharmony_ci
255662306a36Sopenharmony_ci	for_each_card_widgets(dapm->card, w) {
255762306a36Sopenharmony_ci		if (!strcmp(w->name, pin_name)) {
255862306a36Sopenharmony_ci			if (w->dapm == dapm)
255962306a36Sopenharmony_ci				return w;
256062306a36Sopenharmony_ci			else
256162306a36Sopenharmony_ci				fallback = w;
256262306a36Sopenharmony_ci		}
256362306a36Sopenharmony_ci	}
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_ci	if (search_other_contexts)
256662306a36Sopenharmony_ci		return fallback;
256762306a36Sopenharmony_ci
256862306a36Sopenharmony_ci	return NULL;
256962306a36Sopenharmony_ci}
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci/*
257262306a36Sopenharmony_ci * set the DAPM pin status:
257362306a36Sopenharmony_ci * returns 1 when the value has been updated, 0 when unchanged, or a negative
257462306a36Sopenharmony_ci * error code; called from kcontrol put callback
257562306a36Sopenharmony_ci */
257662306a36Sopenharmony_cistatic int __snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
257762306a36Sopenharmony_ci				  const char *pin, int status)
257862306a36Sopenharmony_ci{
257962306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
258062306a36Sopenharmony_ci	int ret = 0;
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci	dapm_assert_locked(dapm);
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci	if (!w) {
258562306a36Sopenharmony_ci		dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin);
258662306a36Sopenharmony_ci		return -EINVAL;
258762306a36Sopenharmony_ci	}
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ci	if (w->connected != status) {
259062306a36Sopenharmony_ci		dapm_mark_dirty(w, "pin configuration");
259162306a36Sopenharmony_ci		dapm_widget_invalidate_input_paths(w);
259262306a36Sopenharmony_ci		dapm_widget_invalidate_output_paths(w);
259362306a36Sopenharmony_ci		ret = 1;
259462306a36Sopenharmony_ci	}
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci	w->connected = status;
259762306a36Sopenharmony_ci	if (status == 0)
259862306a36Sopenharmony_ci		w->force = 0;
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_ci	return ret;
260162306a36Sopenharmony_ci}
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_ci/*
260462306a36Sopenharmony_ci * similar as __snd_soc_dapm_set_pin(), but returns 0 when successful;
260562306a36Sopenharmony_ci * called from several API functions below
260662306a36Sopenharmony_ci */
260762306a36Sopenharmony_cistatic int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
260862306a36Sopenharmony_ci				const char *pin, int status)
260962306a36Sopenharmony_ci{
261062306a36Sopenharmony_ci	int ret = __snd_soc_dapm_set_pin(dapm, pin, status);
261162306a36Sopenharmony_ci
261262306a36Sopenharmony_ci	return ret < 0 ? ret : 0;
261362306a36Sopenharmony_ci}
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci/**
261662306a36Sopenharmony_ci * snd_soc_dapm_sync_unlocked - scan and power dapm paths
261762306a36Sopenharmony_ci * @dapm: DAPM context
261862306a36Sopenharmony_ci *
261962306a36Sopenharmony_ci * Walks all dapm audio paths and powers widgets according to their
262062306a36Sopenharmony_ci * stream or path usage.
262162306a36Sopenharmony_ci *
262262306a36Sopenharmony_ci * Requires external locking.
262362306a36Sopenharmony_ci *
262462306a36Sopenharmony_ci * Returns 0 for success.
262562306a36Sopenharmony_ci */
262662306a36Sopenharmony_ciint snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm)
262762306a36Sopenharmony_ci{
262862306a36Sopenharmony_ci	/*
262962306a36Sopenharmony_ci	 * Suppress early reports (eg, jacks syncing their state) to avoid
263062306a36Sopenharmony_ci	 * silly DAPM runs during card startup.
263162306a36Sopenharmony_ci	 */
263262306a36Sopenharmony_ci	if (!snd_soc_card_is_instantiated(dapm->card))
263362306a36Sopenharmony_ci		return 0;
263462306a36Sopenharmony_ci
263562306a36Sopenharmony_ci	return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
263662306a36Sopenharmony_ci}
263762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked);
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_ci/**
264062306a36Sopenharmony_ci * snd_soc_dapm_sync - scan and power dapm paths
264162306a36Sopenharmony_ci * @dapm: DAPM context
264262306a36Sopenharmony_ci *
264362306a36Sopenharmony_ci * Walks all dapm audio paths and powers widgets according to their
264462306a36Sopenharmony_ci * stream or path usage.
264562306a36Sopenharmony_ci *
264662306a36Sopenharmony_ci * Returns 0 for success.
264762306a36Sopenharmony_ci */
264862306a36Sopenharmony_ciint snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
264962306a36Sopenharmony_ci{
265062306a36Sopenharmony_ci	int ret;
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(dapm);
265362306a36Sopenharmony_ci	ret = snd_soc_dapm_sync_unlocked(dapm);
265462306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(dapm);
265562306a36Sopenharmony_ci	return ret;
265662306a36Sopenharmony_ci}
265762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_cistatic int dapm_update_dai_chan(struct snd_soc_dapm_path *p,
266062306a36Sopenharmony_ci				struct snd_soc_dapm_widget *w,
266162306a36Sopenharmony_ci				int channels)
266262306a36Sopenharmony_ci{
266362306a36Sopenharmony_ci	switch (w->id) {
266462306a36Sopenharmony_ci	case snd_soc_dapm_aif_out:
266562306a36Sopenharmony_ci	case snd_soc_dapm_aif_in:
266662306a36Sopenharmony_ci		break;
266762306a36Sopenharmony_ci	default:
266862306a36Sopenharmony_ci		return 0;
266962306a36Sopenharmony_ci	}
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_ci	dev_dbg(w->dapm->dev, "%s DAI route %s -> %s\n",
267262306a36Sopenharmony_ci		w->channel < channels ? "Connecting" : "Disconnecting",
267362306a36Sopenharmony_ci		p->source->name, p->sink->name);
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_ci	if (w->channel < channels)
267662306a36Sopenharmony_ci		soc_dapm_connect_path(p, true, "dai update");
267762306a36Sopenharmony_ci	else
267862306a36Sopenharmony_ci		soc_dapm_connect_path(p, false, "dai update");
267962306a36Sopenharmony_ci
268062306a36Sopenharmony_ci	return 0;
268162306a36Sopenharmony_ci}
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_cistatic int dapm_update_dai_unlocked(struct snd_pcm_substream *substream,
268462306a36Sopenharmony_ci				    struct snd_pcm_hw_params *params,
268562306a36Sopenharmony_ci				    struct snd_soc_dai *dai)
268662306a36Sopenharmony_ci{
268762306a36Sopenharmony_ci	int dir = substream->stream;
268862306a36Sopenharmony_ci	int channels = params_channels(params);
268962306a36Sopenharmony_ci	struct snd_soc_dapm_path *p;
269062306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
269162306a36Sopenharmony_ci	int ret;
269262306a36Sopenharmony_ci
269362306a36Sopenharmony_ci	w = snd_soc_dai_get_widget(dai, dir);
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	if (!w)
269662306a36Sopenharmony_ci		return 0;
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci	dev_dbg(dai->dev, "Update DAI routes for %s %s\n", dai->name,
269962306a36Sopenharmony_ci		dir == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture");
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_ci	snd_soc_dapm_widget_for_each_sink_path(w, p) {
270262306a36Sopenharmony_ci		ret = dapm_update_dai_chan(p, p->sink, channels);
270362306a36Sopenharmony_ci		if (ret < 0)
270462306a36Sopenharmony_ci			return ret;
270562306a36Sopenharmony_ci	}
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci	snd_soc_dapm_widget_for_each_source_path(w, p) {
270862306a36Sopenharmony_ci		ret = dapm_update_dai_chan(p, p->source, channels);
270962306a36Sopenharmony_ci		if (ret < 0)
271062306a36Sopenharmony_ci			return ret;
271162306a36Sopenharmony_ci	}
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci	return 0;
271462306a36Sopenharmony_ci}
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ciint snd_soc_dapm_update_dai(struct snd_pcm_substream *substream,
271762306a36Sopenharmony_ci			    struct snd_pcm_hw_params *params,
271862306a36Sopenharmony_ci			    struct snd_soc_dai *dai)
271962306a36Sopenharmony_ci{
272062306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
272162306a36Sopenharmony_ci	int ret;
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(rtd->card);
272462306a36Sopenharmony_ci	ret = dapm_update_dai_unlocked(substream, params, dai);
272562306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(rtd->card);
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_ci	return ret;
272862306a36Sopenharmony_ci}
272962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_update_dai);
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ciint snd_soc_dapm_widget_name_cmp(struct snd_soc_dapm_widget *widget, const char *s)
273262306a36Sopenharmony_ci{
273362306a36Sopenharmony_ci	struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
273462306a36Sopenharmony_ci	const char *wname = widget->name;
273562306a36Sopenharmony_ci
273662306a36Sopenharmony_ci	if (component->name_prefix)
273762306a36Sopenharmony_ci		wname += strlen(component->name_prefix) + 1; /* plus space */
273862306a36Sopenharmony_ci
273962306a36Sopenharmony_ci	return strcmp(wname, s);
274062306a36Sopenharmony_ci}
274162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_widget_name_cmp);
274262306a36Sopenharmony_ci
274362306a36Sopenharmony_ci/*
274462306a36Sopenharmony_ci * dapm_update_widget_flags() - Re-compute widget sink and source flags
274562306a36Sopenharmony_ci * @w: The widget for which to update the flags
274662306a36Sopenharmony_ci *
274762306a36Sopenharmony_ci * Some widgets have a dynamic category which depends on which neighbors they
274862306a36Sopenharmony_ci * are connected to. This function update the category for these widgets.
274962306a36Sopenharmony_ci *
275062306a36Sopenharmony_ci * This function must be called whenever a path is added or removed to a widget.
275162306a36Sopenharmony_ci */
275262306a36Sopenharmony_cistatic void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
275362306a36Sopenharmony_ci{
275462306a36Sopenharmony_ci	enum snd_soc_dapm_direction dir;
275562306a36Sopenharmony_ci	struct snd_soc_dapm_path *p;
275662306a36Sopenharmony_ci	unsigned int ep;
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci	switch (w->id) {
275962306a36Sopenharmony_ci	case snd_soc_dapm_input:
276062306a36Sopenharmony_ci		/* On a fully routed card an input is never a source */
276162306a36Sopenharmony_ci		if (w->dapm->card->fully_routed)
276262306a36Sopenharmony_ci			return;
276362306a36Sopenharmony_ci		ep = SND_SOC_DAPM_EP_SOURCE;
276462306a36Sopenharmony_ci		snd_soc_dapm_widget_for_each_source_path(w, p) {
276562306a36Sopenharmony_ci			if (p->source->id == snd_soc_dapm_micbias ||
276662306a36Sopenharmony_ci				p->source->id == snd_soc_dapm_mic ||
276762306a36Sopenharmony_ci				p->source->id == snd_soc_dapm_line ||
276862306a36Sopenharmony_ci				p->source->id == snd_soc_dapm_output) {
276962306a36Sopenharmony_ci					ep = 0;
277062306a36Sopenharmony_ci					break;
277162306a36Sopenharmony_ci			}
277262306a36Sopenharmony_ci		}
277362306a36Sopenharmony_ci		break;
277462306a36Sopenharmony_ci	case snd_soc_dapm_output:
277562306a36Sopenharmony_ci		/* On a fully routed card a output is never a sink */
277662306a36Sopenharmony_ci		if (w->dapm->card->fully_routed)
277762306a36Sopenharmony_ci			return;
277862306a36Sopenharmony_ci		ep = SND_SOC_DAPM_EP_SINK;
277962306a36Sopenharmony_ci		snd_soc_dapm_widget_for_each_sink_path(w, p) {
278062306a36Sopenharmony_ci			if (p->sink->id == snd_soc_dapm_spk ||
278162306a36Sopenharmony_ci				p->sink->id == snd_soc_dapm_hp ||
278262306a36Sopenharmony_ci				p->sink->id == snd_soc_dapm_line ||
278362306a36Sopenharmony_ci				p->sink->id == snd_soc_dapm_input) {
278462306a36Sopenharmony_ci					ep = 0;
278562306a36Sopenharmony_ci					break;
278662306a36Sopenharmony_ci			}
278762306a36Sopenharmony_ci		}
278862306a36Sopenharmony_ci		break;
278962306a36Sopenharmony_ci	case snd_soc_dapm_line:
279062306a36Sopenharmony_ci		ep = 0;
279162306a36Sopenharmony_ci		snd_soc_dapm_for_each_direction(dir) {
279262306a36Sopenharmony_ci			if (!list_empty(&w->edges[dir]))
279362306a36Sopenharmony_ci				ep |= SND_SOC_DAPM_DIR_TO_EP(dir);
279462306a36Sopenharmony_ci		}
279562306a36Sopenharmony_ci		break;
279662306a36Sopenharmony_ci	default:
279762306a36Sopenharmony_ci		return;
279862306a36Sopenharmony_ci	}
279962306a36Sopenharmony_ci
280062306a36Sopenharmony_ci	w->is_ep = ep;
280162306a36Sopenharmony_ci}
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_cistatic int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm,
280462306a36Sopenharmony_ci	struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
280562306a36Sopenharmony_ci	const char *control)
280662306a36Sopenharmony_ci{
280762306a36Sopenharmony_ci	bool dynamic_source = false;
280862306a36Sopenharmony_ci	bool dynamic_sink = false;
280962306a36Sopenharmony_ci
281062306a36Sopenharmony_ci	if (!control)
281162306a36Sopenharmony_ci		return 0;
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_ci	switch (source->id) {
281462306a36Sopenharmony_ci	case snd_soc_dapm_demux:
281562306a36Sopenharmony_ci		dynamic_source = true;
281662306a36Sopenharmony_ci		break;
281762306a36Sopenharmony_ci	default:
281862306a36Sopenharmony_ci		break;
281962306a36Sopenharmony_ci	}
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_ci	switch (sink->id) {
282262306a36Sopenharmony_ci	case snd_soc_dapm_mux:
282362306a36Sopenharmony_ci	case snd_soc_dapm_switch:
282462306a36Sopenharmony_ci	case snd_soc_dapm_mixer:
282562306a36Sopenharmony_ci	case snd_soc_dapm_mixer_named_ctl:
282662306a36Sopenharmony_ci		dynamic_sink = true;
282762306a36Sopenharmony_ci		break;
282862306a36Sopenharmony_ci	default:
282962306a36Sopenharmony_ci		break;
283062306a36Sopenharmony_ci	}
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_ci	if (dynamic_source && dynamic_sink) {
283362306a36Sopenharmony_ci		dev_err(dapm->dev,
283462306a36Sopenharmony_ci			"Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n",
283562306a36Sopenharmony_ci			source->name, control, sink->name);
283662306a36Sopenharmony_ci		return -EINVAL;
283762306a36Sopenharmony_ci	} else if (!dynamic_source && !dynamic_sink) {
283862306a36Sopenharmony_ci		dev_err(dapm->dev,
283962306a36Sopenharmony_ci			"Control not supported for path %s -> [%s] -> %s\n",
284062306a36Sopenharmony_ci			source->name, control, sink->name);
284162306a36Sopenharmony_ci		return -EINVAL;
284262306a36Sopenharmony_ci	}
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci	return 0;
284562306a36Sopenharmony_ci}
284662306a36Sopenharmony_ci
284762306a36Sopenharmony_cistatic int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
284862306a36Sopenharmony_ci	struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
284962306a36Sopenharmony_ci	const char *control,
285062306a36Sopenharmony_ci	int (*connected)(struct snd_soc_dapm_widget *source,
285162306a36Sopenharmony_ci			 struct snd_soc_dapm_widget *sink))
285262306a36Sopenharmony_ci{
285362306a36Sopenharmony_ci	enum snd_soc_dapm_direction dir;
285462306a36Sopenharmony_ci	struct snd_soc_dapm_path *path;
285562306a36Sopenharmony_ci	int ret;
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_ci	if (wsink->is_supply && !wsource->is_supply) {
285862306a36Sopenharmony_ci		dev_err(dapm->dev,
285962306a36Sopenharmony_ci			"Connecting non-supply widget to supply widget is not supported (%s -> %s)\n",
286062306a36Sopenharmony_ci			wsource->name, wsink->name);
286162306a36Sopenharmony_ci		return -EINVAL;
286262306a36Sopenharmony_ci	}
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ci	if (connected && !wsource->is_supply) {
286562306a36Sopenharmony_ci		dev_err(dapm->dev,
286662306a36Sopenharmony_ci			"connected() callback only supported for supply widgets (%s -> %s)\n",
286762306a36Sopenharmony_ci			wsource->name, wsink->name);
286862306a36Sopenharmony_ci		return -EINVAL;
286962306a36Sopenharmony_ci	}
287062306a36Sopenharmony_ci
287162306a36Sopenharmony_ci	if (wsource->is_supply && control) {
287262306a36Sopenharmony_ci		dev_err(dapm->dev,
287362306a36Sopenharmony_ci			"Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n",
287462306a36Sopenharmony_ci			wsource->name, control, wsink->name);
287562306a36Sopenharmony_ci		return -EINVAL;
287662306a36Sopenharmony_ci	}
287762306a36Sopenharmony_ci
287862306a36Sopenharmony_ci	ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control);
287962306a36Sopenharmony_ci	if (ret)
288062306a36Sopenharmony_ci		return ret;
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ci	path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
288362306a36Sopenharmony_ci	if (!path)
288462306a36Sopenharmony_ci		return -ENOMEM;
288562306a36Sopenharmony_ci
288662306a36Sopenharmony_ci	path->node[SND_SOC_DAPM_DIR_IN] = wsource;
288762306a36Sopenharmony_ci	path->node[SND_SOC_DAPM_DIR_OUT] = wsink;
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_ci	path->connected = connected;
289062306a36Sopenharmony_ci	INIT_LIST_HEAD(&path->list);
289162306a36Sopenharmony_ci	INIT_LIST_HEAD(&path->list_kcontrol);
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_ci	if (wsource->is_supply || wsink->is_supply)
289462306a36Sopenharmony_ci		path->is_supply = 1;
289562306a36Sopenharmony_ci
289662306a36Sopenharmony_ci	/* connect static paths */
289762306a36Sopenharmony_ci	if (control == NULL) {
289862306a36Sopenharmony_ci		path->connect = 1;
289962306a36Sopenharmony_ci	} else {
290062306a36Sopenharmony_ci		switch (wsource->id) {
290162306a36Sopenharmony_ci		case snd_soc_dapm_demux:
290262306a36Sopenharmony_ci			ret = dapm_connect_mux(dapm, path, control, wsource);
290362306a36Sopenharmony_ci			if (ret)
290462306a36Sopenharmony_ci				goto err;
290562306a36Sopenharmony_ci			break;
290662306a36Sopenharmony_ci		default:
290762306a36Sopenharmony_ci			break;
290862306a36Sopenharmony_ci		}
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci		switch (wsink->id) {
291162306a36Sopenharmony_ci		case snd_soc_dapm_mux:
291262306a36Sopenharmony_ci			ret = dapm_connect_mux(dapm, path, control, wsink);
291362306a36Sopenharmony_ci			if (ret != 0)
291462306a36Sopenharmony_ci				goto err;
291562306a36Sopenharmony_ci			break;
291662306a36Sopenharmony_ci		case snd_soc_dapm_switch:
291762306a36Sopenharmony_ci		case snd_soc_dapm_mixer:
291862306a36Sopenharmony_ci		case snd_soc_dapm_mixer_named_ctl:
291962306a36Sopenharmony_ci			ret = dapm_connect_mixer(dapm, path, control);
292062306a36Sopenharmony_ci			if (ret != 0)
292162306a36Sopenharmony_ci				goto err;
292262306a36Sopenharmony_ci			break;
292362306a36Sopenharmony_ci		default:
292462306a36Sopenharmony_ci			break;
292562306a36Sopenharmony_ci		}
292662306a36Sopenharmony_ci	}
292762306a36Sopenharmony_ci
292862306a36Sopenharmony_ci	list_add(&path->list, &dapm->card->paths);
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci	snd_soc_dapm_for_each_direction(dir)
293162306a36Sopenharmony_ci		list_add(&path->list_node[dir], &path->node[dir]->edges[dir]);
293262306a36Sopenharmony_ci
293362306a36Sopenharmony_ci	snd_soc_dapm_for_each_direction(dir) {
293462306a36Sopenharmony_ci		dapm_update_widget_flags(path->node[dir]);
293562306a36Sopenharmony_ci		dapm_mark_dirty(path->node[dir], "Route added");
293662306a36Sopenharmony_ci	}
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci	if (snd_soc_card_is_instantiated(dapm->card) && path->connect)
293962306a36Sopenharmony_ci		dapm_path_invalidate(path);
294062306a36Sopenharmony_ci
294162306a36Sopenharmony_ci	return 0;
294262306a36Sopenharmony_cierr:
294362306a36Sopenharmony_ci	kfree(path);
294462306a36Sopenharmony_ci	return ret;
294562306a36Sopenharmony_ci}
294662306a36Sopenharmony_ci
294762306a36Sopenharmony_cistatic int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
294862306a36Sopenharmony_ci				  const struct snd_soc_dapm_route *route)
294962306a36Sopenharmony_ci{
295062306a36Sopenharmony_ci	struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
295162306a36Sopenharmony_ci	struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
295262306a36Sopenharmony_ci	const char *sink;
295362306a36Sopenharmony_ci	const char *source;
295462306a36Sopenharmony_ci	char prefixed_sink[80];
295562306a36Sopenharmony_ci	char prefixed_source[80];
295662306a36Sopenharmony_ci	const char *prefix;
295762306a36Sopenharmony_ci	unsigned int sink_ref = 0;
295862306a36Sopenharmony_ci	unsigned int source_ref = 0;
295962306a36Sopenharmony_ci	int ret;
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci	prefix = soc_dapm_prefix(dapm);
296262306a36Sopenharmony_ci	if (prefix) {
296362306a36Sopenharmony_ci		snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
296462306a36Sopenharmony_ci			 prefix, route->sink);
296562306a36Sopenharmony_ci		sink = prefixed_sink;
296662306a36Sopenharmony_ci		snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
296762306a36Sopenharmony_ci			 prefix, route->source);
296862306a36Sopenharmony_ci		source = prefixed_source;
296962306a36Sopenharmony_ci	} else {
297062306a36Sopenharmony_ci		sink = route->sink;
297162306a36Sopenharmony_ci		source = route->source;
297262306a36Sopenharmony_ci	}
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci	wsource	= dapm_wcache_lookup(dapm->wcache_source, source);
297562306a36Sopenharmony_ci	wsink	= dapm_wcache_lookup(dapm->wcache_sink,   sink);
297662306a36Sopenharmony_ci
297762306a36Sopenharmony_ci	if (wsink && wsource)
297862306a36Sopenharmony_ci		goto skip_search;
297962306a36Sopenharmony_ci
298062306a36Sopenharmony_ci	/*
298162306a36Sopenharmony_ci	 * find src and dest widgets over all widgets but favor a widget from
298262306a36Sopenharmony_ci	 * current DAPM context
298362306a36Sopenharmony_ci	 */
298462306a36Sopenharmony_ci	for_each_card_widgets(dapm->card, w) {
298562306a36Sopenharmony_ci		if (!wsink && !(strcmp(w->name, sink))) {
298662306a36Sopenharmony_ci			wtsink = w;
298762306a36Sopenharmony_ci			if (w->dapm == dapm) {
298862306a36Sopenharmony_ci				wsink = w;
298962306a36Sopenharmony_ci				if (wsource)
299062306a36Sopenharmony_ci					break;
299162306a36Sopenharmony_ci			}
299262306a36Sopenharmony_ci			sink_ref++;
299362306a36Sopenharmony_ci			if (sink_ref > 1)
299462306a36Sopenharmony_ci				dev_warn(dapm->dev,
299562306a36Sopenharmony_ci					"ASoC: sink widget %s overwritten\n",
299662306a36Sopenharmony_ci					w->name);
299762306a36Sopenharmony_ci			continue;
299862306a36Sopenharmony_ci		}
299962306a36Sopenharmony_ci		if (!wsource && !(strcmp(w->name, source))) {
300062306a36Sopenharmony_ci			wtsource = w;
300162306a36Sopenharmony_ci			if (w->dapm == dapm) {
300262306a36Sopenharmony_ci				wsource = w;
300362306a36Sopenharmony_ci				if (wsink)
300462306a36Sopenharmony_ci					break;
300562306a36Sopenharmony_ci			}
300662306a36Sopenharmony_ci			source_ref++;
300762306a36Sopenharmony_ci			if (source_ref > 1)
300862306a36Sopenharmony_ci				dev_warn(dapm->dev,
300962306a36Sopenharmony_ci					"ASoC: source widget %s overwritten\n",
301062306a36Sopenharmony_ci					w->name);
301162306a36Sopenharmony_ci		}
301262306a36Sopenharmony_ci	}
301362306a36Sopenharmony_ci	/* use widget from another DAPM context if not found from this */
301462306a36Sopenharmony_ci	if (!wsink)
301562306a36Sopenharmony_ci		wsink = wtsink;
301662306a36Sopenharmony_ci	if (!wsource)
301762306a36Sopenharmony_ci		wsource = wtsource;
301862306a36Sopenharmony_ci
301962306a36Sopenharmony_ci	ret = -ENODEV;
302062306a36Sopenharmony_ci	if (!wsource)
302162306a36Sopenharmony_ci		goto err;
302262306a36Sopenharmony_ci	if (!wsink)
302362306a36Sopenharmony_ci		goto err;
302462306a36Sopenharmony_ci
302562306a36Sopenharmony_ciskip_search:
302662306a36Sopenharmony_ci	/* update cache */
302762306a36Sopenharmony_ci	dapm->wcache_sink	= wsink;
302862306a36Sopenharmony_ci	dapm->wcache_source	= wsource;
302962306a36Sopenharmony_ci
303062306a36Sopenharmony_ci	ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
303162306a36Sopenharmony_ci		route->connected);
303262306a36Sopenharmony_cierr:
303362306a36Sopenharmony_ci	if (ret)
303462306a36Sopenharmony_ci		dev_err(dapm->dev, "ASoC: Failed to add route %s%s -%s%s%s> %s%s\n",
303562306a36Sopenharmony_ci			source, !wsource ? "(*)" : "",
303662306a36Sopenharmony_ci			!route->control ? "" : "> [",
303762306a36Sopenharmony_ci			!route->control ? "" : route->control,
303862306a36Sopenharmony_ci			!route->control ? "" : "] -",
303962306a36Sopenharmony_ci			sink,  !wsink ? "(*)" : "");
304062306a36Sopenharmony_ci	return ret;
304162306a36Sopenharmony_ci}
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_cistatic int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
304462306a36Sopenharmony_ci				  const struct snd_soc_dapm_route *route)
304562306a36Sopenharmony_ci{
304662306a36Sopenharmony_ci	struct snd_soc_dapm_path *path, *p;
304762306a36Sopenharmony_ci	const char *sink;
304862306a36Sopenharmony_ci	const char *source;
304962306a36Sopenharmony_ci	char prefixed_sink[80];
305062306a36Sopenharmony_ci	char prefixed_source[80];
305162306a36Sopenharmony_ci	const char *prefix;
305262306a36Sopenharmony_ci
305362306a36Sopenharmony_ci	if (route->control) {
305462306a36Sopenharmony_ci		dev_err(dapm->dev,
305562306a36Sopenharmony_ci			"ASoC: Removal of routes with controls not supported\n");
305662306a36Sopenharmony_ci		return -EINVAL;
305762306a36Sopenharmony_ci	}
305862306a36Sopenharmony_ci
305962306a36Sopenharmony_ci	prefix = soc_dapm_prefix(dapm);
306062306a36Sopenharmony_ci	if (prefix) {
306162306a36Sopenharmony_ci		snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
306262306a36Sopenharmony_ci			 prefix, route->sink);
306362306a36Sopenharmony_ci		sink = prefixed_sink;
306462306a36Sopenharmony_ci		snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
306562306a36Sopenharmony_ci			 prefix, route->source);
306662306a36Sopenharmony_ci		source = prefixed_source;
306762306a36Sopenharmony_ci	} else {
306862306a36Sopenharmony_ci		sink = route->sink;
306962306a36Sopenharmony_ci		source = route->source;
307062306a36Sopenharmony_ci	}
307162306a36Sopenharmony_ci
307262306a36Sopenharmony_ci	path = NULL;
307362306a36Sopenharmony_ci	list_for_each_entry(p, &dapm->card->paths, list) {
307462306a36Sopenharmony_ci		if (strcmp(p->source->name, source) != 0)
307562306a36Sopenharmony_ci			continue;
307662306a36Sopenharmony_ci		if (strcmp(p->sink->name, sink) != 0)
307762306a36Sopenharmony_ci			continue;
307862306a36Sopenharmony_ci		path = p;
307962306a36Sopenharmony_ci		break;
308062306a36Sopenharmony_ci	}
308162306a36Sopenharmony_ci
308262306a36Sopenharmony_ci	if (path) {
308362306a36Sopenharmony_ci		struct snd_soc_dapm_widget *wsource = path->source;
308462306a36Sopenharmony_ci		struct snd_soc_dapm_widget *wsink = path->sink;
308562306a36Sopenharmony_ci
308662306a36Sopenharmony_ci		dapm_mark_dirty(wsource, "Route removed");
308762306a36Sopenharmony_ci		dapm_mark_dirty(wsink, "Route removed");
308862306a36Sopenharmony_ci		if (path->connect)
308962306a36Sopenharmony_ci			dapm_path_invalidate(path);
309062306a36Sopenharmony_ci
309162306a36Sopenharmony_ci		dapm_free_path(path);
309262306a36Sopenharmony_ci
309362306a36Sopenharmony_ci		/* Update any path related flags */
309462306a36Sopenharmony_ci		dapm_update_widget_flags(wsource);
309562306a36Sopenharmony_ci		dapm_update_widget_flags(wsink);
309662306a36Sopenharmony_ci	} else {
309762306a36Sopenharmony_ci		dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
309862306a36Sopenharmony_ci			 source, sink);
309962306a36Sopenharmony_ci	}
310062306a36Sopenharmony_ci
310162306a36Sopenharmony_ci	return 0;
310262306a36Sopenharmony_ci}
310362306a36Sopenharmony_ci
310462306a36Sopenharmony_ci/**
310562306a36Sopenharmony_ci * snd_soc_dapm_add_routes - Add routes between DAPM widgets
310662306a36Sopenharmony_ci * @dapm: DAPM context
310762306a36Sopenharmony_ci * @route: audio routes
310862306a36Sopenharmony_ci * @num: number of routes
310962306a36Sopenharmony_ci *
311062306a36Sopenharmony_ci * Connects 2 dapm widgets together via a named audio path. The sink is
311162306a36Sopenharmony_ci * the widget receiving the audio signal, whilst the source is the sender
311262306a36Sopenharmony_ci * of the audio signal.
311362306a36Sopenharmony_ci *
311462306a36Sopenharmony_ci * Returns 0 for success else error. On error all resources can be freed
311562306a36Sopenharmony_ci * with a call to snd_soc_card_free().
311662306a36Sopenharmony_ci */
311762306a36Sopenharmony_ciint snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
311862306a36Sopenharmony_ci			    const struct snd_soc_dapm_route *route, int num)
311962306a36Sopenharmony_ci{
312062306a36Sopenharmony_ci	int i, ret = 0;
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(dapm);
312362306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
312462306a36Sopenharmony_ci		int r = snd_soc_dapm_add_route(dapm, route);
312562306a36Sopenharmony_ci		if (r < 0)
312662306a36Sopenharmony_ci			ret = r;
312762306a36Sopenharmony_ci		route++;
312862306a36Sopenharmony_ci	}
312962306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(dapm);
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ci	return ret;
313262306a36Sopenharmony_ci}
313362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
313462306a36Sopenharmony_ci
313562306a36Sopenharmony_ci/**
313662306a36Sopenharmony_ci * snd_soc_dapm_del_routes - Remove routes between DAPM widgets
313762306a36Sopenharmony_ci * @dapm: DAPM context
313862306a36Sopenharmony_ci * @route: audio routes
313962306a36Sopenharmony_ci * @num: number of routes
314062306a36Sopenharmony_ci *
314162306a36Sopenharmony_ci * Removes routes from the DAPM context.
314262306a36Sopenharmony_ci */
314362306a36Sopenharmony_ciint snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
314462306a36Sopenharmony_ci			    const struct snd_soc_dapm_route *route, int num)
314562306a36Sopenharmony_ci{
314662306a36Sopenharmony_ci	int i;
314762306a36Sopenharmony_ci
314862306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(dapm);
314962306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
315062306a36Sopenharmony_ci		snd_soc_dapm_del_route(dapm, route);
315162306a36Sopenharmony_ci		route++;
315262306a36Sopenharmony_ci	}
315362306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(dapm);
315462306a36Sopenharmony_ci
315562306a36Sopenharmony_ci	return 0;
315662306a36Sopenharmony_ci}
315762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes);
315862306a36Sopenharmony_ci
315962306a36Sopenharmony_cistatic int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
316062306a36Sopenharmony_ci				   const struct snd_soc_dapm_route *route)
316162306a36Sopenharmony_ci{
316262306a36Sopenharmony_ci	struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
316362306a36Sopenharmony_ci							      route->source,
316462306a36Sopenharmony_ci							      true);
316562306a36Sopenharmony_ci	struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
316662306a36Sopenharmony_ci							    route->sink,
316762306a36Sopenharmony_ci							    true);
316862306a36Sopenharmony_ci	struct snd_soc_dapm_path *path;
316962306a36Sopenharmony_ci	int count = 0;
317062306a36Sopenharmony_ci
317162306a36Sopenharmony_ci	if (!source) {
317262306a36Sopenharmony_ci		dev_err(dapm->dev, "ASoC: Unable to find source %s for weak route\n",
317362306a36Sopenharmony_ci			route->source);
317462306a36Sopenharmony_ci		return -ENODEV;
317562306a36Sopenharmony_ci	}
317662306a36Sopenharmony_ci
317762306a36Sopenharmony_ci	if (!sink) {
317862306a36Sopenharmony_ci		dev_err(dapm->dev, "ASoC: Unable to find sink %s for weak route\n",
317962306a36Sopenharmony_ci			route->sink);
318062306a36Sopenharmony_ci		return -ENODEV;
318162306a36Sopenharmony_ci	}
318262306a36Sopenharmony_ci
318362306a36Sopenharmony_ci	if (route->control || route->connected)
318462306a36Sopenharmony_ci		dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n",
318562306a36Sopenharmony_ci			 route->source, route->sink);
318662306a36Sopenharmony_ci
318762306a36Sopenharmony_ci	snd_soc_dapm_widget_for_each_sink_path(source, path) {
318862306a36Sopenharmony_ci		if (path->sink == sink) {
318962306a36Sopenharmony_ci			path->weak = 1;
319062306a36Sopenharmony_ci			count++;
319162306a36Sopenharmony_ci		}
319262306a36Sopenharmony_ci	}
319362306a36Sopenharmony_ci
319462306a36Sopenharmony_ci	if (count == 0)
319562306a36Sopenharmony_ci		dev_err(dapm->dev, "ASoC: No path found for weak route %s->%s\n",
319662306a36Sopenharmony_ci			route->source, route->sink);
319762306a36Sopenharmony_ci	if (count > 1)
319862306a36Sopenharmony_ci		dev_warn(dapm->dev, "ASoC: %d paths found for weak route %s->%s\n",
319962306a36Sopenharmony_ci			 count, route->source, route->sink);
320062306a36Sopenharmony_ci
320162306a36Sopenharmony_ci	return 0;
320262306a36Sopenharmony_ci}
320362306a36Sopenharmony_ci
320462306a36Sopenharmony_ci/**
320562306a36Sopenharmony_ci * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
320662306a36Sopenharmony_ci * @dapm: DAPM context
320762306a36Sopenharmony_ci * @route: audio routes
320862306a36Sopenharmony_ci * @num: number of routes
320962306a36Sopenharmony_ci *
321062306a36Sopenharmony_ci * Mark existing routes matching those specified in the passed array
321162306a36Sopenharmony_ci * as being weak, meaning that they are ignored for the purpose of
321262306a36Sopenharmony_ci * power decisions.  The main intended use case is for sidetone paths
321362306a36Sopenharmony_ci * which couple audio between other independent paths if they are both
321462306a36Sopenharmony_ci * active in order to make the combination work better at the user
321562306a36Sopenharmony_ci * level but which aren't intended to be "used".
321662306a36Sopenharmony_ci *
321762306a36Sopenharmony_ci * Note that CODEC drivers should not use this as sidetone type paths
321862306a36Sopenharmony_ci * can frequently also be used as bypass paths.
321962306a36Sopenharmony_ci */
322062306a36Sopenharmony_ciint snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
322162306a36Sopenharmony_ci			     const struct snd_soc_dapm_route *route, int num)
322262306a36Sopenharmony_ci{
322362306a36Sopenharmony_ci	int i;
322462306a36Sopenharmony_ci	int ret = 0;
322562306a36Sopenharmony_ci
322662306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock_root(dapm);
322762306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
322862306a36Sopenharmony_ci		int err = snd_soc_dapm_weak_route(dapm, route);
322962306a36Sopenharmony_ci		if (err)
323062306a36Sopenharmony_ci			ret = err;
323162306a36Sopenharmony_ci		route++;
323262306a36Sopenharmony_ci	}
323362306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(dapm);
323462306a36Sopenharmony_ci
323562306a36Sopenharmony_ci	return ret;
323662306a36Sopenharmony_ci}
323762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
323862306a36Sopenharmony_ci
323962306a36Sopenharmony_ci/**
324062306a36Sopenharmony_ci * snd_soc_dapm_new_widgets - add new dapm widgets
324162306a36Sopenharmony_ci * @card: card to be checked for new dapm widgets
324262306a36Sopenharmony_ci *
324362306a36Sopenharmony_ci * Checks the codec for any new dapm widgets and creates them if found.
324462306a36Sopenharmony_ci *
324562306a36Sopenharmony_ci * Returns 0 for success.
324662306a36Sopenharmony_ci */
324762306a36Sopenharmony_ciint snd_soc_dapm_new_widgets(struct snd_soc_card *card)
324862306a36Sopenharmony_ci{
324962306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
325062306a36Sopenharmony_ci	unsigned int val;
325162306a36Sopenharmony_ci
325262306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock_root(card);
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci	for_each_card_widgets(card, w)
325562306a36Sopenharmony_ci	{
325662306a36Sopenharmony_ci		if (w->new)
325762306a36Sopenharmony_ci			continue;
325862306a36Sopenharmony_ci
325962306a36Sopenharmony_ci		if (w->num_kcontrols) {
326062306a36Sopenharmony_ci			w->kcontrols = kcalloc(w->num_kcontrols,
326162306a36Sopenharmony_ci						sizeof(struct snd_kcontrol *),
326262306a36Sopenharmony_ci						GFP_KERNEL);
326362306a36Sopenharmony_ci			if (!w->kcontrols) {
326462306a36Sopenharmony_ci				snd_soc_dapm_mutex_unlock(card);
326562306a36Sopenharmony_ci				return -ENOMEM;
326662306a36Sopenharmony_ci			}
326762306a36Sopenharmony_ci		}
326862306a36Sopenharmony_ci
326962306a36Sopenharmony_ci		switch(w->id) {
327062306a36Sopenharmony_ci		case snd_soc_dapm_switch:
327162306a36Sopenharmony_ci		case snd_soc_dapm_mixer:
327262306a36Sopenharmony_ci		case snd_soc_dapm_mixer_named_ctl:
327362306a36Sopenharmony_ci			dapm_new_mixer(w);
327462306a36Sopenharmony_ci			break;
327562306a36Sopenharmony_ci		case snd_soc_dapm_mux:
327662306a36Sopenharmony_ci		case snd_soc_dapm_demux:
327762306a36Sopenharmony_ci			dapm_new_mux(w);
327862306a36Sopenharmony_ci			break;
327962306a36Sopenharmony_ci		case snd_soc_dapm_pga:
328062306a36Sopenharmony_ci		case snd_soc_dapm_effect:
328162306a36Sopenharmony_ci		case snd_soc_dapm_out_drv:
328262306a36Sopenharmony_ci			dapm_new_pga(w);
328362306a36Sopenharmony_ci			break;
328462306a36Sopenharmony_ci		case snd_soc_dapm_dai_link:
328562306a36Sopenharmony_ci			dapm_new_dai_link(w);
328662306a36Sopenharmony_ci			break;
328762306a36Sopenharmony_ci		default:
328862306a36Sopenharmony_ci			break;
328962306a36Sopenharmony_ci		}
329062306a36Sopenharmony_ci
329162306a36Sopenharmony_ci		/* Read the initial power state from the device */
329262306a36Sopenharmony_ci		if (w->reg >= 0) {
329362306a36Sopenharmony_ci			val = soc_dapm_read(w->dapm, w->reg);
329462306a36Sopenharmony_ci			val = val >> w->shift;
329562306a36Sopenharmony_ci			val &= w->mask;
329662306a36Sopenharmony_ci			if (val == w->on_val)
329762306a36Sopenharmony_ci				w->power = 1;
329862306a36Sopenharmony_ci		}
329962306a36Sopenharmony_ci
330062306a36Sopenharmony_ci		w->new = 1;
330162306a36Sopenharmony_ci
330262306a36Sopenharmony_ci		dapm_mark_dirty(w, "new widget");
330362306a36Sopenharmony_ci		dapm_debugfs_add_widget(w);
330462306a36Sopenharmony_ci	}
330562306a36Sopenharmony_ci
330662306a36Sopenharmony_ci	dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
330762306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(card);
330862306a36Sopenharmony_ci	return 0;
330962306a36Sopenharmony_ci}
331062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
331162306a36Sopenharmony_ci
331262306a36Sopenharmony_ci/**
331362306a36Sopenharmony_ci * snd_soc_dapm_get_volsw - dapm mixer get callback
331462306a36Sopenharmony_ci * @kcontrol: mixer control
331562306a36Sopenharmony_ci * @ucontrol: control element information
331662306a36Sopenharmony_ci *
331762306a36Sopenharmony_ci * Callback to get the value of a dapm mixer control.
331862306a36Sopenharmony_ci *
331962306a36Sopenharmony_ci * Returns 0 for success.
332062306a36Sopenharmony_ci */
332162306a36Sopenharmony_ciint snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
332262306a36Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
332362306a36Sopenharmony_ci{
332462306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
332562306a36Sopenharmony_ci	struct soc_mixer_control *mc =
332662306a36Sopenharmony_ci		(struct soc_mixer_control *)kcontrol->private_value;
332762306a36Sopenharmony_ci	int reg = mc->reg;
332862306a36Sopenharmony_ci	unsigned int shift = mc->shift;
332962306a36Sopenharmony_ci	int max = mc->max;
333062306a36Sopenharmony_ci	unsigned int width = fls(max);
333162306a36Sopenharmony_ci	unsigned int mask = (1 << fls(max)) - 1;
333262306a36Sopenharmony_ci	unsigned int invert = mc->invert;
333362306a36Sopenharmony_ci	unsigned int reg_val, val, rval = 0;
333462306a36Sopenharmony_ci
333562306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(dapm);
333662306a36Sopenharmony_ci	if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) {
333762306a36Sopenharmony_ci		reg_val = soc_dapm_read(dapm, reg);
333862306a36Sopenharmony_ci		val = (reg_val >> shift) & mask;
333962306a36Sopenharmony_ci
334062306a36Sopenharmony_ci		if (reg != mc->rreg)
334162306a36Sopenharmony_ci			reg_val = soc_dapm_read(dapm, mc->rreg);
334262306a36Sopenharmony_ci
334362306a36Sopenharmony_ci		if (snd_soc_volsw_is_stereo(mc))
334462306a36Sopenharmony_ci			rval = (reg_val >> mc->rshift) & mask;
334562306a36Sopenharmony_ci	} else {
334662306a36Sopenharmony_ci		reg_val = dapm_kcontrol_get_value(kcontrol);
334762306a36Sopenharmony_ci		val = reg_val & mask;
334862306a36Sopenharmony_ci
334962306a36Sopenharmony_ci		if (snd_soc_volsw_is_stereo(mc))
335062306a36Sopenharmony_ci			rval = (reg_val >> width) & mask;
335162306a36Sopenharmony_ci	}
335262306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(dapm);
335362306a36Sopenharmony_ci
335462306a36Sopenharmony_ci	if (invert)
335562306a36Sopenharmony_ci		ucontrol->value.integer.value[0] = max - val;
335662306a36Sopenharmony_ci	else
335762306a36Sopenharmony_ci		ucontrol->value.integer.value[0] = val;
335862306a36Sopenharmony_ci
335962306a36Sopenharmony_ci	if (snd_soc_volsw_is_stereo(mc)) {
336062306a36Sopenharmony_ci		if (invert)
336162306a36Sopenharmony_ci			ucontrol->value.integer.value[1] = max - rval;
336262306a36Sopenharmony_ci		else
336362306a36Sopenharmony_ci			ucontrol->value.integer.value[1] = rval;
336462306a36Sopenharmony_ci	}
336562306a36Sopenharmony_ci
336662306a36Sopenharmony_ci	return 0;
336762306a36Sopenharmony_ci}
336862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
336962306a36Sopenharmony_ci
337062306a36Sopenharmony_ci/**
337162306a36Sopenharmony_ci * snd_soc_dapm_put_volsw - dapm mixer set callback
337262306a36Sopenharmony_ci * @kcontrol: mixer control
337362306a36Sopenharmony_ci * @ucontrol: control element information
337462306a36Sopenharmony_ci *
337562306a36Sopenharmony_ci * Callback to set the value of a dapm mixer control.
337662306a36Sopenharmony_ci *
337762306a36Sopenharmony_ci * Returns 0 for success.
337862306a36Sopenharmony_ci */
337962306a36Sopenharmony_ciint snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
338062306a36Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
338162306a36Sopenharmony_ci{
338262306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
338362306a36Sopenharmony_ci	struct snd_soc_card *card = dapm->card;
338462306a36Sopenharmony_ci	struct soc_mixer_control *mc =
338562306a36Sopenharmony_ci		(struct soc_mixer_control *)kcontrol->private_value;
338662306a36Sopenharmony_ci	int reg = mc->reg;
338762306a36Sopenharmony_ci	unsigned int shift = mc->shift;
338862306a36Sopenharmony_ci	int max = mc->max;
338962306a36Sopenharmony_ci	unsigned int width = fls(max);
339062306a36Sopenharmony_ci	unsigned int mask = (1 << width) - 1;
339162306a36Sopenharmony_ci	unsigned int invert = mc->invert;
339262306a36Sopenharmony_ci	unsigned int val, rval = 0;
339362306a36Sopenharmony_ci	int connect, rconnect = -1, change, reg_change = 0;
339462306a36Sopenharmony_ci	struct snd_soc_dapm_update update = {};
339562306a36Sopenharmony_ci	int ret = 0;
339662306a36Sopenharmony_ci
339762306a36Sopenharmony_ci	val = (ucontrol->value.integer.value[0] & mask);
339862306a36Sopenharmony_ci	connect = !!val;
339962306a36Sopenharmony_ci
340062306a36Sopenharmony_ci	if (invert)
340162306a36Sopenharmony_ci		val = max - val;
340262306a36Sopenharmony_ci
340362306a36Sopenharmony_ci	if (snd_soc_volsw_is_stereo(mc)) {
340462306a36Sopenharmony_ci		rval = (ucontrol->value.integer.value[1] & mask);
340562306a36Sopenharmony_ci		rconnect = !!rval;
340662306a36Sopenharmony_ci		if (invert)
340762306a36Sopenharmony_ci			rval = max - rval;
340862306a36Sopenharmony_ci	}
340962306a36Sopenharmony_ci
341062306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(card);
341162306a36Sopenharmony_ci
341262306a36Sopenharmony_ci	/* This assumes field width < (bits in unsigned int / 2) */
341362306a36Sopenharmony_ci	if (width > sizeof(unsigned int) * 8 / 2)
341462306a36Sopenharmony_ci		dev_warn(dapm->dev,
341562306a36Sopenharmony_ci			 "ASoC: control %s field width limit exceeded\n",
341662306a36Sopenharmony_ci			 kcontrol->id.name);
341762306a36Sopenharmony_ci	change = dapm_kcontrol_set_value(kcontrol, val | (rval << width));
341862306a36Sopenharmony_ci
341962306a36Sopenharmony_ci	if (reg != SND_SOC_NOPM) {
342062306a36Sopenharmony_ci		val = val << shift;
342162306a36Sopenharmony_ci		rval = rval << mc->rshift;
342262306a36Sopenharmony_ci
342362306a36Sopenharmony_ci		reg_change = soc_dapm_test_bits(dapm, reg, mask << shift, val);
342462306a36Sopenharmony_ci
342562306a36Sopenharmony_ci		if (snd_soc_volsw_is_stereo(mc))
342662306a36Sopenharmony_ci			reg_change |= soc_dapm_test_bits(dapm, mc->rreg,
342762306a36Sopenharmony_ci							 mask << mc->rshift,
342862306a36Sopenharmony_ci							 rval);
342962306a36Sopenharmony_ci	}
343062306a36Sopenharmony_ci
343162306a36Sopenharmony_ci	if (change || reg_change) {
343262306a36Sopenharmony_ci		if (reg_change) {
343362306a36Sopenharmony_ci			if (snd_soc_volsw_is_stereo(mc)) {
343462306a36Sopenharmony_ci				update.has_second_set = true;
343562306a36Sopenharmony_ci				update.reg2 = mc->rreg;
343662306a36Sopenharmony_ci				update.mask2 = mask << mc->rshift;
343762306a36Sopenharmony_ci				update.val2 = rval;
343862306a36Sopenharmony_ci			}
343962306a36Sopenharmony_ci			update.kcontrol = kcontrol;
344062306a36Sopenharmony_ci			update.reg = reg;
344162306a36Sopenharmony_ci			update.mask = mask << shift;
344262306a36Sopenharmony_ci			update.val = val;
344362306a36Sopenharmony_ci			card->update = &update;
344462306a36Sopenharmony_ci		}
344562306a36Sopenharmony_ci
344662306a36Sopenharmony_ci		ret = soc_dapm_mixer_update_power(card, kcontrol, connect,
344762306a36Sopenharmony_ci						  rconnect);
344862306a36Sopenharmony_ci
344962306a36Sopenharmony_ci		card->update = NULL;
345062306a36Sopenharmony_ci	}
345162306a36Sopenharmony_ci
345262306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(card);
345362306a36Sopenharmony_ci
345462306a36Sopenharmony_ci	if (ret > 0)
345562306a36Sopenharmony_ci		snd_soc_dpcm_runtime_update(card);
345662306a36Sopenharmony_ci
345762306a36Sopenharmony_ci	return change;
345862306a36Sopenharmony_ci}
345962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
346062306a36Sopenharmony_ci
346162306a36Sopenharmony_ci/**
346262306a36Sopenharmony_ci * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
346362306a36Sopenharmony_ci * @kcontrol: mixer control
346462306a36Sopenharmony_ci * @ucontrol: control element information
346562306a36Sopenharmony_ci *
346662306a36Sopenharmony_ci * Callback to get the value of a dapm enumerated double mixer control.
346762306a36Sopenharmony_ci *
346862306a36Sopenharmony_ci * Returns 0 for success.
346962306a36Sopenharmony_ci */
347062306a36Sopenharmony_ciint snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
347162306a36Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
347262306a36Sopenharmony_ci{
347362306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
347462306a36Sopenharmony_ci	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
347562306a36Sopenharmony_ci	unsigned int reg_val, val;
347662306a36Sopenharmony_ci
347762306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(dapm);
347862306a36Sopenharmony_ci	if (e->reg != SND_SOC_NOPM && dapm_kcontrol_is_powered(kcontrol)) {
347962306a36Sopenharmony_ci		reg_val = soc_dapm_read(dapm, e->reg);
348062306a36Sopenharmony_ci	} else {
348162306a36Sopenharmony_ci		reg_val = dapm_kcontrol_get_value(kcontrol);
348262306a36Sopenharmony_ci	}
348362306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(dapm);
348462306a36Sopenharmony_ci
348562306a36Sopenharmony_ci	val = (reg_val >> e->shift_l) & e->mask;
348662306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
348762306a36Sopenharmony_ci	if (e->shift_l != e->shift_r) {
348862306a36Sopenharmony_ci		val = (reg_val >> e->shift_r) & e->mask;
348962306a36Sopenharmony_ci		val = snd_soc_enum_val_to_item(e, val);
349062306a36Sopenharmony_ci		ucontrol->value.enumerated.item[1] = val;
349162306a36Sopenharmony_ci	}
349262306a36Sopenharmony_ci
349362306a36Sopenharmony_ci	return 0;
349462306a36Sopenharmony_ci}
349562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_ci/**
349862306a36Sopenharmony_ci * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
349962306a36Sopenharmony_ci * @kcontrol: mixer control
350062306a36Sopenharmony_ci * @ucontrol: control element information
350162306a36Sopenharmony_ci *
350262306a36Sopenharmony_ci * Callback to set the value of a dapm enumerated double mixer control.
350362306a36Sopenharmony_ci *
350462306a36Sopenharmony_ci * Returns 0 for success.
350562306a36Sopenharmony_ci */
350662306a36Sopenharmony_ciint snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
350762306a36Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
350862306a36Sopenharmony_ci{
350962306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
351062306a36Sopenharmony_ci	struct snd_soc_card *card = dapm->card;
351162306a36Sopenharmony_ci	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
351262306a36Sopenharmony_ci	unsigned int *item = ucontrol->value.enumerated.item;
351362306a36Sopenharmony_ci	unsigned int val, change, reg_change = 0;
351462306a36Sopenharmony_ci	unsigned int mask;
351562306a36Sopenharmony_ci	struct snd_soc_dapm_update update = {};
351662306a36Sopenharmony_ci	int ret = 0;
351762306a36Sopenharmony_ci
351862306a36Sopenharmony_ci	if (item[0] >= e->items)
351962306a36Sopenharmony_ci		return -EINVAL;
352062306a36Sopenharmony_ci
352162306a36Sopenharmony_ci	val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
352262306a36Sopenharmony_ci	mask = e->mask << e->shift_l;
352362306a36Sopenharmony_ci	if (e->shift_l != e->shift_r) {
352462306a36Sopenharmony_ci		if (item[1] > e->items)
352562306a36Sopenharmony_ci			return -EINVAL;
352662306a36Sopenharmony_ci		val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r;
352762306a36Sopenharmony_ci		mask |= e->mask << e->shift_r;
352862306a36Sopenharmony_ci	}
352962306a36Sopenharmony_ci
353062306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(card);
353162306a36Sopenharmony_ci
353262306a36Sopenharmony_ci	change = dapm_kcontrol_set_value(kcontrol, val);
353362306a36Sopenharmony_ci
353462306a36Sopenharmony_ci	if (e->reg != SND_SOC_NOPM)
353562306a36Sopenharmony_ci		reg_change = soc_dapm_test_bits(dapm, e->reg, mask, val);
353662306a36Sopenharmony_ci
353762306a36Sopenharmony_ci	if (change || reg_change) {
353862306a36Sopenharmony_ci		if (reg_change) {
353962306a36Sopenharmony_ci			update.kcontrol = kcontrol;
354062306a36Sopenharmony_ci			update.reg = e->reg;
354162306a36Sopenharmony_ci			update.mask = mask;
354262306a36Sopenharmony_ci			update.val = val;
354362306a36Sopenharmony_ci			card->update = &update;
354462306a36Sopenharmony_ci		}
354562306a36Sopenharmony_ci
354662306a36Sopenharmony_ci		ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);
354762306a36Sopenharmony_ci
354862306a36Sopenharmony_ci		card->update = NULL;
354962306a36Sopenharmony_ci	}
355062306a36Sopenharmony_ci
355162306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(card);
355262306a36Sopenharmony_ci
355362306a36Sopenharmony_ci	if (ret > 0)
355462306a36Sopenharmony_ci		snd_soc_dpcm_runtime_update(card);
355562306a36Sopenharmony_ci
355662306a36Sopenharmony_ci	return change;
355762306a36Sopenharmony_ci}
355862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
355962306a36Sopenharmony_ci
356062306a36Sopenharmony_ci/**
356162306a36Sopenharmony_ci * snd_soc_dapm_info_pin_switch - Info for a pin switch
356262306a36Sopenharmony_ci *
356362306a36Sopenharmony_ci * @kcontrol: mixer control
356462306a36Sopenharmony_ci * @uinfo: control element information
356562306a36Sopenharmony_ci *
356662306a36Sopenharmony_ci * Callback to provide information about a pin switch control.
356762306a36Sopenharmony_ci */
356862306a36Sopenharmony_ciint snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
356962306a36Sopenharmony_ci				 struct snd_ctl_elem_info *uinfo)
357062306a36Sopenharmony_ci{
357162306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
357262306a36Sopenharmony_ci	uinfo->count = 1;
357362306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
357462306a36Sopenharmony_ci	uinfo->value.integer.max = 1;
357562306a36Sopenharmony_ci
357662306a36Sopenharmony_ci	return 0;
357762306a36Sopenharmony_ci}
357862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
357962306a36Sopenharmony_ci
358062306a36Sopenharmony_ci/**
358162306a36Sopenharmony_ci * snd_soc_dapm_get_pin_switch - Get information for a pin switch
358262306a36Sopenharmony_ci *
358362306a36Sopenharmony_ci * @kcontrol: mixer control
358462306a36Sopenharmony_ci * @ucontrol: Value
358562306a36Sopenharmony_ci */
358662306a36Sopenharmony_ciint snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
358762306a36Sopenharmony_ci				struct snd_ctl_elem_value *ucontrol)
358862306a36Sopenharmony_ci{
358962306a36Sopenharmony_ci	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
359062306a36Sopenharmony_ci	const char *pin = (const char *)kcontrol->private_value;
359162306a36Sopenharmony_ci
359262306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(card);
359362306a36Sopenharmony_ci
359462306a36Sopenharmony_ci	ucontrol->value.integer.value[0] =
359562306a36Sopenharmony_ci		snd_soc_dapm_get_pin_status(&card->dapm, pin);
359662306a36Sopenharmony_ci
359762306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(card);
359862306a36Sopenharmony_ci
359962306a36Sopenharmony_ci	return 0;
360062306a36Sopenharmony_ci}
360162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
360262306a36Sopenharmony_ci
360362306a36Sopenharmony_ci/**
360462306a36Sopenharmony_ci * snd_soc_dapm_put_pin_switch - Set information for a pin switch
360562306a36Sopenharmony_ci *
360662306a36Sopenharmony_ci * @kcontrol: mixer control
360762306a36Sopenharmony_ci * @ucontrol: Value
360862306a36Sopenharmony_ci */
360962306a36Sopenharmony_ciint snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
361062306a36Sopenharmony_ci				struct snd_ctl_elem_value *ucontrol)
361162306a36Sopenharmony_ci{
361262306a36Sopenharmony_ci	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
361362306a36Sopenharmony_ci	const char *pin = (const char *)kcontrol->private_value;
361462306a36Sopenharmony_ci	int ret;
361562306a36Sopenharmony_ci
361662306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(card);
361762306a36Sopenharmony_ci	ret = __snd_soc_dapm_set_pin(&card->dapm, pin,
361862306a36Sopenharmony_ci				     !!ucontrol->value.integer.value[0]);
361962306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(card);
362062306a36Sopenharmony_ci
362162306a36Sopenharmony_ci	snd_soc_dapm_sync(&card->dapm);
362262306a36Sopenharmony_ci	return ret;
362362306a36Sopenharmony_ci}
362462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
362562306a36Sopenharmony_ci
362662306a36Sopenharmony_cistruct snd_soc_dapm_widget *
362762306a36Sopenharmony_cisnd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
362862306a36Sopenharmony_ci			 const struct snd_soc_dapm_widget *widget)
362962306a36Sopenharmony_ci{
363062306a36Sopenharmony_ci	enum snd_soc_dapm_direction dir;
363162306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
363262306a36Sopenharmony_ci	const char *prefix;
363362306a36Sopenharmony_ci	int ret = -ENOMEM;
363462306a36Sopenharmony_ci
363562306a36Sopenharmony_ci	if ((w = dapm_cnew_widget(widget)) == NULL)
363662306a36Sopenharmony_ci		goto cnew_failed;
363762306a36Sopenharmony_ci
363862306a36Sopenharmony_ci	prefix = soc_dapm_prefix(dapm);
363962306a36Sopenharmony_ci	if (prefix)
364062306a36Sopenharmony_ci		w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name);
364162306a36Sopenharmony_ci	else
364262306a36Sopenharmony_ci		w->name = kstrdup_const(widget->name, GFP_KERNEL);
364362306a36Sopenharmony_ci	if (!w->name)
364462306a36Sopenharmony_ci		goto name_failed;
364562306a36Sopenharmony_ci
364662306a36Sopenharmony_ci	switch (w->id) {
364762306a36Sopenharmony_ci	case snd_soc_dapm_regulator_supply:
364862306a36Sopenharmony_ci		w->regulator = devm_regulator_get(dapm->dev, widget->name);
364962306a36Sopenharmony_ci		if (IS_ERR(w->regulator)) {
365062306a36Sopenharmony_ci			ret = PTR_ERR(w->regulator);
365162306a36Sopenharmony_ci			goto request_failed;
365262306a36Sopenharmony_ci		}
365362306a36Sopenharmony_ci
365462306a36Sopenharmony_ci		if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
365562306a36Sopenharmony_ci			ret = regulator_allow_bypass(w->regulator, true);
365662306a36Sopenharmony_ci			if (ret != 0)
365762306a36Sopenharmony_ci				dev_warn(dapm->dev,
365862306a36Sopenharmony_ci					 "ASoC: Failed to bypass %s: %d\n",
365962306a36Sopenharmony_ci					 w->name, ret);
366062306a36Sopenharmony_ci		}
366162306a36Sopenharmony_ci		break;
366262306a36Sopenharmony_ci	case snd_soc_dapm_pinctrl:
366362306a36Sopenharmony_ci		w->pinctrl = devm_pinctrl_get(dapm->dev);
366462306a36Sopenharmony_ci		if (IS_ERR(w->pinctrl)) {
366562306a36Sopenharmony_ci			ret = PTR_ERR(w->pinctrl);
366662306a36Sopenharmony_ci			goto request_failed;
366762306a36Sopenharmony_ci		}
366862306a36Sopenharmony_ci
366962306a36Sopenharmony_ci		/* set to sleep_state when initializing */
367062306a36Sopenharmony_ci		dapm_pinctrl_event(w, NULL, SND_SOC_DAPM_POST_PMD);
367162306a36Sopenharmony_ci		break;
367262306a36Sopenharmony_ci	case snd_soc_dapm_clock_supply:
367362306a36Sopenharmony_ci		w->clk = devm_clk_get(dapm->dev, widget->name);
367462306a36Sopenharmony_ci		if (IS_ERR(w->clk)) {
367562306a36Sopenharmony_ci			ret = PTR_ERR(w->clk);
367662306a36Sopenharmony_ci			goto request_failed;
367762306a36Sopenharmony_ci		}
367862306a36Sopenharmony_ci		break;
367962306a36Sopenharmony_ci	default:
368062306a36Sopenharmony_ci		break;
368162306a36Sopenharmony_ci	}
368262306a36Sopenharmony_ci
368362306a36Sopenharmony_ci	switch (w->id) {
368462306a36Sopenharmony_ci	case snd_soc_dapm_mic:
368562306a36Sopenharmony_ci		w->is_ep = SND_SOC_DAPM_EP_SOURCE;
368662306a36Sopenharmony_ci		w->power_check = dapm_generic_check_power;
368762306a36Sopenharmony_ci		break;
368862306a36Sopenharmony_ci	case snd_soc_dapm_input:
368962306a36Sopenharmony_ci		if (!dapm->card->fully_routed)
369062306a36Sopenharmony_ci			w->is_ep = SND_SOC_DAPM_EP_SOURCE;
369162306a36Sopenharmony_ci		w->power_check = dapm_generic_check_power;
369262306a36Sopenharmony_ci		break;
369362306a36Sopenharmony_ci	case snd_soc_dapm_spk:
369462306a36Sopenharmony_ci	case snd_soc_dapm_hp:
369562306a36Sopenharmony_ci		w->is_ep = SND_SOC_DAPM_EP_SINK;
369662306a36Sopenharmony_ci		w->power_check = dapm_generic_check_power;
369762306a36Sopenharmony_ci		break;
369862306a36Sopenharmony_ci	case snd_soc_dapm_output:
369962306a36Sopenharmony_ci		if (!dapm->card->fully_routed)
370062306a36Sopenharmony_ci			w->is_ep = SND_SOC_DAPM_EP_SINK;
370162306a36Sopenharmony_ci		w->power_check = dapm_generic_check_power;
370262306a36Sopenharmony_ci		break;
370362306a36Sopenharmony_ci	case snd_soc_dapm_vmid:
370462306a36Sopenharmony_ci	case snd_soc_dapm_siggen:
370562306a36Sopenharmony_ci		w->is_ep = SND_SOC_DAPM_EP_SOURCE;
370662306a36Sopenharmony_ci		w->power_check = dapm_always_on_check_power;
370762306a36Sopenharmony_ci		break;
370862306a36Sopenharmony_ci	case snd_soc_dapm_sink:
370962306a36Sopenharmony_ci		w->is_ep = SND_SOC_DAPM_EP_SINK;
371062306a36Sopenharmony_ci		w->power_check = dapm_always_on_check_power;
371162306a36Sopenharmony_ci		break;
371262306a36Sopenharmony_ci
371362306a36Sopenharmony_ci	case snd_soc_dapm_mux:
371462306a36Sopenharmony_ci	case snd_soc_dapm_demux:
371562306a36Sopenharmony_ci	case snd_soc_dapm_switch:
371662306a36Sopenharmony_ci	case snd_soc_dapm_mixer:
371762306a36Sopenharmony_ci	case snd_soc_dapm_mixer_named_ctl:
371862306a36Sopenharmony_ci	case snd_soc_dapm_adc:
371962306a36Sopenharmony_ci	case snd_soc_dapm_aif_out:
372062306a36Sopenharmony_ci	case snd_soc_dapm_dac:
372162306a36Sopenharmony_ci	case snd_soc_dapm_aif_in:
372262306a36Sopenharmony_ci	case snd_soc_dapm_pga:
372362306a36Sopenharmony_ci	case snd_soc_dapm_buffer:
372462306a36Sopenharmony_ci	case snd_soc_dapm_scheduler:
372562306a36Sopenharmony_ci	case snd_soc_dapm_effect:
372662306a36Sopenharmony_ci	case snd_soc_dapm_src:
372762306a36Sopenharmony_ci	case snd_soc_dapm_asrc:
372862306a36Sopenharmony_ci	case snd_soc_dapm_encoder:
372962306a36Sopenharmony_ci	case snd_soc_dapm_decoder:
373062306a36Sopenharmony_ci	case snd_soc_dapm_out_drv:
373162306a36Sopenharmony_ci	case snd_soc_dapm_micbias:
373262306a36Sopenharmony_ci	case snd_soc_dapm_line:
373362306a36Sopenharmony_ci	case snd_soc_dapm_dai_link:
373462306a36Sopenharmony_ci	case snd_soc_dapm_dai_out:
373562306a36Sopenharmony_ci	case snd_soc_dapm_dai_in:
373662306a36Sopenharmony_ci		w->power_check = dapm_generic_check_power;
373762306a36Sopenharmony_ci		break;
373862306a36Sopenharmony_ci	case snd_soc_dapm_supply:
373962306a36Sopenharmony_ci	case snd_soc_dapm_regulator_supply:
374062306a36Sopenharmony_ci	case snd_soc_dapm_pinctrl:
374162306a36Sopenharmony_ci	case snd_soc_dapm_clock_supply:
374262306a36Sopenharmony_ci	case snd_soc_dapm_kcontrol:
374362306a36Sopenharmony_ci		w->is_supply = 1;
374462306a36Sopenharmony_ci		w->power_check = dapm_supply_check_power;
374562306a36Sopenharmony_ci		break;
374662306a36Sopenharmony_ci	default:
374762306a36Sopenharmony_ci		w->power_check = dapm_always_on_check_power;
374862306a36Sopenharmony_ci		break;
374962306a36Sopenharmony_ci	}
375062306a36Sopenharmony_ci
375162306a36Sopenharmony_ci	w->dapm = dapm;
375262306a36Sopenharmony_ci	INIT_LIST_HEAD(&w->list);
375362306a36Sopenharmony_ci	INIT_LIST_HEAD(&w->dirty);
375462306a36Sopenharmony_ci	/* see for_each_card_widgets */
375562306a36Sopenharmony_ci	list_add_tail(&w->list, &dapm->card->widgets);
375662306a36Sopenharmony_ci
375762306a36Sopenharmony_ci	snd_soc_dapm_for_each_direction(dir) {
375862306a36Sopenharmony_ci		INIT_LIST_HEAD(&w->edges[dir]);
375962306a36Sopenharmony_ci		w->endpoints[dir] = -1;
376062306a36Sopenharmony_ci	}
376162306a36Sopenharmony_ci
376262306a36Sopenharmony_ci	/* machine layer sets up unconnected pins and insertions */
376362306a36Sopenharmony_ci	w->connected = 1;
376462306a36Sopenharmony_ci	return w;
376562306a36Sopenharmony_ci
376662306a36Sopenharmony_cirequest_failed:
376762306a36Sopenharmony_ci	dev_err_probe(dapm->dev, ret, "ASoC: Failed to request %s\n",
376862306a36Sopenharmony_ci		      w->name);
376962306a36Sopenharmony_ci	kfree_const(w->name);
377062306a36Sopenharmony_ciname_failed:
377162306a36Sopenharmony_ci	kfree_const(w->sname);
377262306a36Sopenharmony_ci	kfree(w);
377362306a36Sopenharmony_cicnew_failed:
377462306a36Sopenharmony_ci	return ERR_PTR(ret);
377562306a36Sopenharmony_ci}
377662306a36Sopenharmony_ci
377762306a36Sopenharmony_ci/**
377862306a36Sopenharmony_ci * snd_soc_dapm_new_control - create new dapm control
377962306a36Sopenharmony_ci * @dapm: DAPM context
378062306a36Sopenharmony_ci * @widget: widget template
378162306a36Sopenharmony_ci *
378262306a36Sopenharmony_ci * Creates new DAPM control based upon a template.
378362306a36Sopenharmony_ci *
378462306a36Sopenharmony_ci * Returns a widget pointer on success or an error pointer on failure
378562306a36Sopenharmony_ci */
378662306a36Sopenharmony_cistruct snd_soc_dapm_widget *
378762306a36Sopenharmony_cisnd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
378862306a36Sopenharmony_ci			 const struct snd_soc_dapm_widget *widget)
378962306a36Sopenharmony_ci{
379062306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
379162306a36Sopenharmony_ci
379262306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(dapm);
379362306a36Sopenharmony_ci	w = snd_soc_dapm_new_control_unlocked(dapm, widget);
379462306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(dapm);
379562306a36Sopenharmony_ci
379662306a36Sopenharmony_ci	return w;
379762306a36Sopenharmony_ci}
379862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
379962306a36Sopenharmony_ci
380062306a36Sopenharmony_ci/**
380162306a36Sopenharmony_ci * snd_soc_dapm_new_controls - create new dapm controls
380262306a36Sopenharmony_ci * @dapm: DAPM context
380362306a36Sopenharmony_ci * @widget: widget array
380462306a36Sopenharmony_ci * @num: number of widgets
380562306a36Sopenharmony_ci *
380662306a36Sopenharmony_ci * Creates new DAPM controls based upon the templates.
380762306a36Sopenharmony_ci *
380862306a36Sopenharmony_ci * Returns 0 for success else error.
380962306a36Sopenharmony_ci */
381062306a36Sopenharmony_ciint snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
381162306a36Sopenharmony_ci	const struct snd_soc_dapm_widget *widget,
381262306a36Sopenharmony_ci	int num)
381362306a36Sopenharmony_ci{
381462306a36Sopenharmony_ci	int i;
381562306a36Sopenharmony_ci	int ret = 0;
381662306a36Sopenharmony_ci
381762306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock_root(dapm);
381862306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
381962306a36Sopenharmony_ci		struct snd_soc_dapm_widget *w = snd_soc_dapm_new_control_unlocked(dapm, widget);
382062306a36Sopenharmony_ci		if (IS_ERR(w)) {
382162306a36Sopenharmony_ci			ret = PTR_ERR(w);
382262306a36Sopenharmony_ci			break;
382362306a36Sopenharmony_ci		}
382462306a36Sopenharmony_ci		widget++;
382562306a36Sopenharmony_ci	}
382662306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(dapm);
382762306a36Sopenharmony_ci	return ret;
382862306a36Sopenharmony_ci}
382962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
383062306a36Sopenharmony_ci
383162306a36Sopenharmony_cistatic int
383262306a36Sopenharmony_cisnd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
383362306a36Sopenharmony_ci			       struct snd_pcm_substream *substream)
383462306a36Sopenharmony_ci{
383562306a36Sopenharmony_ci	struct snd_soc_dapm_path *path;
383662306a36Sopenharmony_ci	struct snd_soc_dai *source, *sink;
383762306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
383862306a36Sopenharmony_ci	struct snd_pcm_hw_params *params = NULL;
383962306a36Sopenharmony_ci	const struct snd_soc_pcm_stream *config = NULL;
384062306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = NULL;
384162306a36Sopenharmony_ci	unsigned int fmt;
384262306a36Sopenharmony_ci	int ret = 0;
384362306a36Sopenharmony_ci
384462306a36Sopenharmony_ci	/*
384562306a36Sopenharmony_ci	 * NOTE
384662306a36Sopenharmony_ci	 *
384762306a36Sopenharmony_ci	 * snd_pcm_hw_params is quite large (608 bytes on arm64) and is
384862306a36Sopenharmony_ci	 * starting to get a bit excessive for allocation on the stack,
384962306a36Sopenharmony_ci	 * especially when you're building with some of the KASAN type
385062306a36Sopenharmony_ci	 * stuff that increases stack usage.
385162306a36Sopenharmony_ci	 * So, we use kzalloc()/kfree() for params in this function.
385262306a36Sopenharmony_ci	 */
385362306a36Sopenharmony_ci	params = kzalloc(sizeof(*params), GFP_KERNEL);
385462306a36Sopenharmony_ci	if (!params)
385562306a36Sopenharmony_ci		return -ENOMEM;
385662306a36Sopenharmony_ci
385762306a36Sopenharmony_ci	runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
385862306a36Sopenharmony_ci	if (!runtime) {
385962306a36Sopenharmony_ci		ret = -ENOMEM;
386062306a36Sopenharmony_ci		goto out;
386162306a36Sopenharmony_ci	}
386262306a36Sopenharmony_ci
386362306a36Sopenharmony_ci	substream->runtime = runtime;
386462306a36Sopenharmony_ci
386562306a36Sopenharmony_ci	substream->stream = SNDRV_PCM_STREAM_CAPTURE;
386662306a36Sopenharmony_ci	snd_soc_dapm_widget_for_each_source_path(w, path) {
386762306a36Sopenharmony_ci		source = path->source->priv;
386862306a36Sopenharmony_ci
386962306a36Sopenharmony_ci		ret = snd_soc_dai_startup(source, substream);
387062306a36Sopenharmony_ci		if (ret < 0)
387162306a36Sopenharmony_ci			goto out;
387262306a36Sopenharmony_ci
387362306a36Sopenharmony_ci		snd_soc_dai_activate(source, substream->stream);
387462306a36Sopenharmony_ci	}
387562306a36Sopenharmony_ci
387662306a36Sopenharmony_ci	substream->stream = SNDRV_PCM_STREAM_PLAYBACK;
387762306a36Sopenharmony_ci	snd_soc_dapm_widget_for_each_sink_path(w, path) {
387862306a36Sopenharmony_ci		sink = path->sink->priv;
387962306a36Sopenharmony_ci
388062306a36Sopenharmony_ci		ret = snd_soc_dai_startup(sink, substream);
388162306a36Sopenharmony_ci		if (ret < 0)
388262306a36Sopenharmony_ci			goto out;
388362306a36Sopenharmony_ci
388462306a36Sopenharmony_ci		snd_soc_dai_activate(sink, substream->stream);
388562306a36Sopenharmony_ci	}
388662306a36Sopenharmony_ci
388762306a36Sopenharmony_ci	substream->hw_opened = 1;
388862306a36Sopenharmony_ci
388962306a36Sopenharmony_ci	/*
389062306a36Sopenharmony_ci	 * Note: getting the config after .startup() gives a chance to
389162306a36Sopenharmony_ci	 * either party on the link to alter the configuration if
389262306a36Sopenharmony_ci	 * necessary
389362306a36Sopenharmony_ci	 */
389462306a36Sopenharmony_ci	config = rtd->dai_link->c2c_params + rtd->c2c_params_select;
389562306a36Sopenharmony_ci	if (!config) {
389662306a36Sopenharmony_ci		dev_err(w->dapm->dev, "ASoC: link config missing\n");
389762306a36Sopenharmony_ci		ret = -EINVAL;
389862306a36Sopenharmony_ci		goto out;
389962306a36Sopenharmony_ci	}
390062306a36Sopenharmony_ci
390162306a36Sopenharmony_ci	/* Be a little careful as we don't want to overflow the mask array */
390262306a36Sopenharmony_ci	if (!config->formats) {
390362306a36Sopenharmony_ci		dev_warn(w->dapm->dev, "ASoC: Invalid format was specified\n");
390462306a36Sopenharmony_ci
390562306a36Sopenharmony_ci		ret = -EINVAL;
390662306a36Sopenharmony_ci		goto out;
390762306a36Sopenharmony_ci	}
390862306a36Sopenharmony_ci
390962306a36Sopenharmony_ci	fmt = ffs(config->formats) - 1;
391062306a36Sopenharmony_ci
391162306a36Sopenharmony_ci	snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
391262306a36Sopenharmony_ci	hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
391362306a36Sopenharmony_ci		config->rate_min;
391462306a36Sopenharmony_ci	hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
391562306a36Sopenharmony_ci		config->rate_max;
391662306a36Sopenharmony_ci	hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
391762306a36Sopenharmony_ci		= config->channels_min;
391862306a36Sopenharmony_ci	hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
391962306a36Sopenharmony_ci		= config->channels_max;
392062306a36Sopenharmony_ci
392162306a36Sopenharmony_ci	substream->stream = SNDRV_PCM_STREAM_CAPTURE;
392262306a36Sopenharmony_ci	snd_soc_dapm_widget_for_each_source_path(w, path) {
392362306a36Sopenharmony_ci		source = path->source->priv;
392462306a36Sopenharmony_ci
392562306a36Sopenharmony_ci		ret = snd_soc_dai_hw_params(source, substream, params);
392662306a36Sopenharmony_ci		if (ret < 0)
392762306a36Sopenharmony_ci			goto out;
392862306a36Sopenharmony_ci
392962306a36Sopenharmony_ci		dapm_update_dai_unlocked(substream, params, source);
393062306a36Sopenharmony_ci	}
393162306a36Sopenharmony_ci
393262306a36Sopenharmony_ci	substream->stream = SNDRV_PCM_STREAM_PLAYBACK;
393362306a36Sopenharmony_ci	snd_soc_dapm_widget_for_each_sink_path(w, path) {
393462306a36Sopenharmony_ci		sink = path->sink->priv;
393562306a36Sopenharmony_ci
393662306a36Sopenharmony_ci		ret = snd_soc_dai_hw_params(sink, substream, params);
393762306a36Sopenharmony_ci		if (ret < 0)
393862306a36Sopenharmony_ci			goto out;
393962306a36Sopenharmony_ci
394062306a36Sopenharmony_ci		dapm_update_dai_unlocked(substream, params, sink);
394162306a36Sopenharmony_ci	}
394262306a36Sopenharmony_ci
394362306a36Sopenharmony_ci	runtime->format = params_format(params);
394462306a36Sopenharmony_ci	runtime->subformat = params_subformat(params);
394562306a36Sopenharmony_ci	runtime->channels = params_channels(params);
394662306a36Sopenharmony_ci	runtime->rate = params_rate(params);
394762306a36Sopenharmony_ci
394862306a36Sopenharmony_ciout:
394962306a36Sopenharmony_ci	/* see above NOTE */
395062306a36Sopenharmony_ci	kfree(params);
395162306a36Sopenharmony_ci
395262306a36Sopenharmony_ci	return ret;
395362306a36Sopenharmony_ci}
395462306a36Sopenharmony_ci
395562306a36Sopenharmony_cistatic int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
395662306a36Sopenharmony_ci				  struct snd_kcontrol *kcontrol, int event)
395762306a36Sopenharmony_ci{
395862306a36Sopenharmony_ci	struct snd_soc_dapm_path *path;
395962306a36Sopenharmony_ci	struct snd_soc_dai *source, *sink;
396062306a36Sopenharmony_ci	struct snd_pcm_substream *substream = w->priv;
396162306a36Sopenharmony_ci	int ret = 0, saved_stream = substream->stream;
396262306a36Sopenharmony_ci
396362306a36Sopenharmony_ci	if (WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) ||
396462306a36Sopenharmony_ci		    list_empty(&w->edges[SND_SOC_DAPM_DIR_IN])))
396562306a36Sopenharmony_ci		return -EINVAL;
396662306a36Sopenharmony_ci
396762306a36Sopenharmony_ci	switch (event) {
396862306a36Sopenharmony_ci	case SND_SOC_DAPM_PRE_PMU:
396962306a36Sopenharmony_ci		ret = snd_soc_dai_link_event_pre_pmu(w, substream);
397062306a36Sopenharmony_ci		if (ret < 0)
397162306a36Sopenharmony_ci			goto out;
397262306a36Sopenharmony_ci
397362306a36Sopenharmony_ci		break;
397462306a36Sopenharmony_ci
397562306a36Sopenharmony_ci	case SND_SOC_DAPM_POST_PMU:
397662306a36Sopenharmony_ci		snd_soc_dapm_widget_for_each_sink_path(w, path) {
397762306a36Sopenharmony_ci			sink = path->sink->priv;
397862306a36Sopenharmony_ci
397962306a36Sopenharmony_ci			snd_soc_dai_digital_mute(sink, 0, SNDRV_PCM_STREAM_PLAYBACK);
398062306a36Sopenharmony_ci			ret = 0;
398162306a36Sopenharmony_ci		}
398262306a36Sopenharmony_ci		break;
398362306a36Sopenharmony_ci
398462306a36Sopenharmony_ci	case SND_SOC_DAPM_PRE_PMD:
398562306a36Sopenharmony_ci		snd_soc_dapm_widget_for_each_sink_path(w, path) {
398662306a36Sopenharmony_ci			sink = path->sink->priv;
398762306a36Sopenharmony_ci
398862306a36Sopenharmony_ci			snd_soc_dai_digital_mute(sink, 1, SNDRV_PCM_STREAM_PLAYBACK);
398962306a36Sopenharmony_ci			ret = 0;
399062306a36Sopenharmony_ci		}
399162306a36Sopenharmony_ci
399262306a36Sopenharmony_ci		substream->stream = SNDRV_PCM_STREAM_CAPTURE;
399362306a36Sopenharmony_ci		snd_soc_dapm_widget_for_each_source_path(w, path) {
399462306a36Sopenharmony_ci			source = path->source->priv;
399562306a36Sopenharmony_ci			snd_soc_dai_hw_free(source, substream, 0);
399662306a36Sopenharmony_ci		}
399762306a36Sopenharmony_ci
399862306a36Sopenharmony_ci		substream->stream = SNDRV_PCM_STREAM_PLAYBACK;
399962306a36Sopenharmony_ci		snd_soc_dapm_widget_for_each_sink_path(w, path) {
400062306a36Sopenharmony_ci			sink = path->sink->priv;
400162306a36Sopenharmony_ci			snd_soc_dai_hw_free(sink, substream, 0);
400262306a36Sopenharmony_ci		}
400362306a36Sopenharmony_ci
400462306a36Sopenharmony_ci		substream->stream = SNDRV_PCM_STREAM_CAPTURE;
400562306a36Sopenharmony_ci		snd_soc_dapm_widget_for_each_source_path(w, path) {
400662306a36Sopenharmony_ci			source = path->source->priv;
400762306a36Sopenharmony_ci			snd_soc_dai_deactivate(source, substream->stream);
400862306a36Sopenharmony_ci			snd_soc_dai_shutdown(source, substream, 0);
400962306a36Sopenharmony_ci		}
401062306a36Sopenharmony_ci
401162306a36Sopenharmony_ci		substream->stream = SNDRV_PCM_STREAM_PLAYBACK;
401262306a36Sopenharmony_ci		snd_soc_dapm_widget_for_each_sink_path(w, path) {
401362306a36Sopenharmony_ci			sink = path->sink->priv;
401462306a36Sopenharmony_ci			snd_soc_dai_deactivate(sink, substream->stream);
401562306a36Sopenharmony_ci			snd_soc_dai_shutdown(sink, substream, 0);
401662306a36Sopenharmony_ci		}
401762306a36Sopenharmony_ci		break;
401862306a36Sopenharmony_ci
401962306a36Sopenharmony_ci	case SND_SOC_DAPM_POST_PMD:
402062306a36Sopenharmony_ci		kfree(substream->runtime);
402162306a36Sopenharmony_ci		break;
402262306a36Sopenharmony_ci
402362306a36Sopenharmony_ci	default:
402462306a36Sopenharmony_ci		WARN(1, "Unknown event %d\n", event);
402562306a36Sopenharmony_ci		ret = -EINVAL;
402662306a36Sopenharmony_ci	}
402762306a36Sopenharmony_ci
402862306a36Sopenharmony_ciout:
402962306a36Sopenharmony_ci	/* Restore the substream direction */
403062306a36Sopenharmony_ci	substream->stream = saved_stream;
403162306a36Sopenharmony_ci	return ret;
403262306a36Sopenharmony_ci}
403362306a36Sopenharmony_ci
403462306a36Sopenharmony_cistatic int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol,
403562306a36Sopenharmony_ci			  struct snd_ctl_elem_value *ucontrol)
403662306a36Sopenharmony_ci{
403762306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
403862306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = w->priv;
403962306a36Sopenharmony_ci
404062306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = rtd->c2c_params_select;
404162306a36Sopenharmony_ci
404262306a36Sopenharmony_ci	return 0;
404362306a36Sopenharmony_ci}
404462306a36Sopenharmony_ci
404562306a36Sopenharmony_cistatic int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
404662306a36Sopenharmony_ci			  struct snd_ctl_elem_value *ucontrol)
404762306a36Sopenharmony_ci{
404862306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
404962306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = w->priv;
405062306a36Sopenharmony_ci
405162306a36Sopenharmony_ci	/* Can't change the config when widget is already powered */
405262306a36Sopenharmony_ci	if (w->power)
405362306a36Sopenharmony_ci		return -EBUSY;
405462306a36Sopenharmony_ci
405562306a36Sopenharmony_ci	if (ucontrol->value.enumerated.item[0] == rtd->c2c_params_select)
405662306a36Sopenharmony_ci		return 0;
405762306a36Sopenharmony_ci
405862306a36Sopenharmony_ci	if (ucontrol->value.enumerated.item[0] >= rtd->dai_link->num_c2c_params)
405962306a36Sopenharmony_ci		return -EINVAL;
406062306a36Sopenharmony_ci
406162306a36Sopenharmony_ci	rtd->c2c_params_select = ucontrol->value.enumerated.item[0];
406262306a36Sopenharmony_ci
406362306a36Sopenharmony_ci	return 1;
406462306a36Sopenharmony_ci}
406562306a36Sopenharmony_ci
406662306a36Sopenharmony_cistatic void
406762306a36Sopenharmony_cisnd_soc_dapm_free_kcontrol(struct snd_soc_card *card,
406862306a36Sopenharmony_ci			unsigned long *private_value,
406962306a36Sopenharmony_ci			int num_c2c_params,
407062306a36Sopenharmony_ci			const char **w_param_text)
407162306a36Sopenharmony_ci{
407262306a36Sopenharmony_ci	int count;
407362306a36Sopenharmony_ci
407462306a36Sopenharmony_ci	devm_kfree(card->dev, (void *)*private_value);
407562306a36Sopenharmony_ci
407662306a36Sopenharmony_ci	if (!w_param_text)
407762306a36Sopenharmony_ci		return;
407862306a36Sopenharmony_ci
407962306a36Sopenharmony_ci	for (count = 0 ; count < num_c2c_params; count++)
408062306a36Sopenharmony_ci		devm_kfree(card->dev, (void *)w_param_text[count]);
408162306a36Sopenharmony_ci	devm_kfree(card->dev, w_param_text);
408262306a36Sopenharmony_ci}
408362306a36Sopenharmony_ci
408462306a36Sopenharmony_cistatic struct snd_kcontrol_new *
408562306a36Sopenharmony_cisnd_soc_dapm_alloc_kcontrol(struct snd_soc_card *card,
408662306a36Sopenharmony_ci			char *link_name,
408762306a36Sopenharmony_ci			const struct snd_soc_pcm_stream *c2c_params,
408862306a36Sopenharmony_ci			int num_c2c_params, const char **w_param_text,
408962306a36Sopenharmony_ci			unsigned long *private_value)
409062306a36Sopenharmony_ci{
409162306a36Sopenharmony_ci	struct soc_enum w_param_enum[] = {
409262306a36Sopenharmony_ci		SOC_ENUM_SINGLE(0, 0, 0, NULL),
409362306a36Sopenharmony_ci	};
409462306a36Sopenharmony_ci	struct snd_kcontrol_new kcontrol_dai_link[] = {
409562306a36Sopenharmony_ci		SOC_ENUM_EXT(NULL, w_param_enum[0],
409662306a36Sopenharmony_ci			     snd_soc_dapm_dai_link_get,
409762306a36Sopenharmony_ci			     snd_soc_dapm_dai_link_put),
409862306a36Sopenharmony_ci	};
409962306a36Sopenharmony_ci	struct snd_kcontrol_new *kcontrol_news;
410062306a36Sopenharmony_ci	const struct snd_soc_pcm_stream *config = c2c_params;
410162306a36Sopenharmony_ci	int count;
410262306a36Sopenharmony_ci
410362306a36Sopenharmony_ci	for (count = 0 ; count < num_c2c_params; count++) {
410462306a36Sopenharmony_ci		if (!config->stream_name) {
410562306a36Sopenharmony_ci			dev_warn(card->dapm.dev,
410662306a36Sopenharmony_ci				"ASoC: anonymous config %d for dai link %s\n",
410762306a36Sopenharmony_ci				count, link_name);
410862306a36Sopenharmony_ci			w_param_text[count] =
410962306a36Sopenharmony_ci				devm_kasprintf(card->dev, GFP_KERNEL,
411062306a36Sopenharmony_ci					       "Anonymous Configuration %d",
411162306a36Sopenharmony_ci					       count);
411262306a36Sopenharmony_ci		} else {
411362306a36Sopenharmony_ci			w_param_text[count] = devm_kmemdup(card->dev,
411462306a36Sopenharmony_ci						config->stream_name,
411562306a36Sopenharmony_ci						strlen(config->stream_name) + 1,
411662306a36Sopenharmony_ci						GFP_KERNEL);
411762306a36Sopenharmony_ci		}
411862306a36Sopenharmony_ci		if (!w_param_text[count])
411962306a36Sopenharmony_ci			goto outfree_w_param;
412062306a36Sopenharmony_ci		config++;
412162306a36Sopenharmony_ci	}
412262306a36Sopenharmony_ci
412362306a36Sopenharmony_ci	w_param_enum[0].items = num_c2c_params;
412462306a36Sopenharmony_ci	w_param_enum[0].texts = w_param_text;
412562306a36Sopenharmony_ci
412662306a36Sopenharmony_ci	*private_value =
412762306a36Sopenharmony_ci		(unsigned long) devm_kmemdup(card->dev,
412862306a36Sopenharmony_ci			(void *)(kcontrol_dai_link[0].private_value),
412962306a36Sopenharmony_ci			sizeof(struct soc_enum), GFP_KERNEL);
413062306a36Sopenharmony_ci	if (!*private_value) {
413162306a36Sopenharmony_ci		dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
413262306a36Sopenharmony_ci			link_name);
413362306a36Sopenharmony_ci		goto outfree_w_param;
413462306a36Sopenharmony_ci	}
413562306a36Sopenharmony_ci	kcontrol_dai_link[0].private_value = *private_value;
413662306a36Sopenharmony_ci	/* duplicate kcontrol_dai_link on heap so that memory persists */
413762306a36Sopenharmony_ci	kcontrol_news = devm_kmemdup(card->dev, &kcontrol_dai_link[0],
413862306a36Sopenharmony_ci					sizeof(struct snd_kcontrol_new),
413962306a36Sopenharmony_ci					GFP_KERNEL);
414062306a36Sopenharmony_ci	if (!kcontrol_news) {
414162306a36Sopenharmony_ci		dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
414262306a36Sopenharmony_ci			link_name);
414362306a36Sopenharmony_ci		goto outfree_w_param;
414462306a36Sopenharmony_ci	}
414562306a36Sopenharmony_ci	return kcontrol_news;
414662306a36Sopenharmony_ci
414762306a36Sopenharmony_cioutfree_w_param:
414862306a36Sopenharmony_ci	snd_soc_dapm_free_kcontrol(card, private_value, num_c2c_params, w_param_text);
414962306a36Sopenharmony_ci	return NULL;
415062306a36Sopenharmony_ci}
415162306a36Sopenharmony_ci
415262306a36Sopenharmony_cistatic struct snd_soc_dapm_widget *
415362306a36Sopenharmony_cisnd_soc_dapm_new_dai(struct snd_soc_card *card,
415462306a36Sopenharmony_ci		     struct snd_pcm_substream *substream,
415562306a36Sopenharmony_ci		     char *id)
415662306a36Sopenharmony_ci{
415762306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
415862306a36Sopenharmony_ci	struct snd_soc_dapm_widget template;
415962306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
416062306a36Sopenharmony_ci	const struct snd_kcontrol_new *kcontrol_news;
416162306a36Sopenharmony_ci	int num_kcontrols;
416262306a36Sopenharmony_ci	const char **w_param_text;
416362306a36Sopenharmony_ci	unsigned long private_value = 0;
416462306a36Sopenharmony_ci	char *link_name;
416562306a36Sopenharmony_ci	int ret = -ENOMEM;
416662306a36Sopenharmony_ci
416762306a36Sopenharmony_ci	link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
416862306a36Sopenharmony_ci				   rtd->dai_link->name, id);
416962306a36Sopenharmony_ci	if (!link_name)
417062306a36Sopenharmony_ci		goto name_fail;
417162306a36Sopenharmony_ci
417262306a36Sopenharmony_ci	/* allocate memory for control, only in case of multiple configs */
417362306a36Sopenharmony_ci	w_param_text	= NULL;
417462306a36Sopenharmony_ci	kcontrol_news	= NULL;
417562306a36Sopenharmony_ci	num_kcontrols	= 0;
417662306a36Sopenharmony_ci	if (rtd->dai_link->num_c2c_params > 1) {
417762306a36Sopenharmony_ci		w_param_text = devm_kcalloc(card->dev,
417862306a36Sopenharmony_ci					    rtd->dai_link->num_c2c_params,
417962306a36Sopenharmony_ci					    sizeof(char *), GFP_KERNEL);
418062306a36Sopenharmony_ci		if (!w_param_text)
418162306a36Sopenharmony_ci			goto param_fail;
418262306a36Sopenharmony_ci
418362306a36Sopenharmony_ci		num_kcontrols = 1;
418462306a36Sopenharmony_ci		kcontrol_news = snd_soc_dapm_alloc_kcontrol(card, link_name,
418562306a36Sopenharmony_ci							    rtd->dai_link->c2c_params,
418662306a36Sopenharmony_ci							    rtd->dai_link->num_c2c_params,
418762306a36Sopenharmony_ci							    w_param_text, &private_value);
418862306a36Sopenharmony_ci		if (!kcontrol_news)
418962306a36Sopenharmony_ci			goto param_fail;
419062306a36Sopenharmony_ci	}
419162306a36Sopenharmony_ci
419262306a36Sopenharmony_ci	memset(&template, 0, sizeof(template));
419362306a36Sopenharmony_ci	template.reg		= SND_SOC_NOPM;
419462306a36Sopenharmony_ci	template.id		= snd_soc_dapm_dai_link;
419562306a36Sopenharmony_ci	template.name		= link_name;
419662306a36Sopenharmony_ci	template.event		= snd_soc_dai_link_event;
419762306a36Sopenharmony_ci	template.event_flags	= SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
419862306a36Sopenharmony_ci				  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD;
419962306a36Sopenharmony_ci	template.kcontrol_news	= kcontrol_news;
420062306a36Sopenharmony_ci	template.num_kcontrols	= num_kcontrols;
420162306a36Sopenharmony_ci
420262306a36Sopenharmony_ci	dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
420362306a36Sopenharmony_ci
420462306a36Sopenharmony_ci	w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
420562306a36Sopenharmony_ci	if (IS_ERR(w)) {
420662306a36Sopenharmony_ci		ret = PTR_ERR(w);
420762306a36Sopenharmony_ci		goto outfree_kcontrol_news;
420862306a36Sopenharmony_ci	}
420962306a36Sopenharmony_ci
421062306a36Sopenharmony_ci	w->priv = substream;
421162306a36Sopenharmony_ci
421262306a36Sopenharmony_ci	return w;
421362306a36Sopenharmony_ci
421462306a36Sopenharmony_cioutfree_kcontrol_news:
421562306a36Sopenharmony_ci	devm_kfree(card->dev, (void *)template.kcontrol_news);
421662306a36Sopenharmony_ci	snd_soc_dapm_free_kcontrol(card, &private_value,
421762306a36Sopenharmony_ci				   rtd->dai_link->num_c2c_params, w_param_text);
421862306a36Sopenharmony_ciparam_fail:
421962306a36Sopenharmony_ci	devm_kfree(card->dev, link_name);
422062306a36Sopenharmony_ciname_fail:
422162306a36Sopenharmony_ci	dev_err(rtd->dev, "ASoC: Failed to create %s-%s widget: %d\n",
422262306a36Sopenharmony_ci		rtd->dai_link->name, id, ret);
422362306a36Sopenharmony_ci	return ERR_PTR(ret);
422462306a36Sopenharmony_ci}
422562306a36Sopenharmony_ci
422662306a36Sopenharmony_ci/**
422762306a36Sopenharmony_ci * snd_soc_dapm_new_dai_widgets - Create new DAPM widgets
422862306a36Sopenharmony_ci * @dapm: DAPM context
422962306a36Sopenharmony_ci * @dai: parent DAI
423062306a36Sopenharmony_ci *
423162306a36Sopenharmony_ci * Returns 0 on success, error code otherwise.
423262306a36Sopenharmony_ci */
423362306a36Sopenharmony_ciint snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
423462306a36Sopenharmony_ci				 struct snd_soc_dai *dai)
423562306a36Sopenharmony_ci{
423662306a36Sopenharmony_ci	struct snd_soc_dapm_widget template;
423762306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
423862306a36Sopenharmony_ci
423962306a36Sopenharmony_ci	WARN_ON(dapm->dev != dai->dev);
424062306a36Sopenharmony_ci
424162306a36Sopenharmony_ci	memset(&template, 0, sizeof(template));
424262306a36Sopenharmony_ci	template.reg = SND_SOC_NOPM;
424362306a36Sopenharmony_ci
424462306a36Sopenharmony_ci	if (dai->driver->playback.stream_name) {
424562306a36Sopenharmony_ci		template.id = snd_soc_dapm_dai_in;
424662306a36Sopenharmony_ci		template.name = dai->driver->playback.stream_name;
424762306a36Sopenharmony_ci		template.sname = dai->driver->playback.stream_name;
424862306a36Sopenharmony_ci
424962306a36Sopenharmony_ci		dev_dbg(dai->dev, "ASoC: adding %s widget\n",
425062306a36Sopenharmony_ci			template.name);
425162306a36Sopenharmony_ci
425262306a36Sopenharmony_ci		w = snd_soc_dapm_new_control_unlocked(dapm, &template);
425362306a36Sopenharmony_ci		if (IS_ERR(w))
425462306a36Sopenharmony_ci			return PTR_ERR(w);
425562306a36Sopenharmony_ci
425662306a36Sopenharmony_ci		w->priv = dai;
425762306a36Sopenharmony_ci		snd_soc_dai_set_widget_playback(dai, w);
425862306a36Sopenharmony_ci	}
425962306a36Sopenharmony_ci
426062306a36Sopenharmony_ci	if (dai->driver->capture.stream_name) {
426162306a36Sopenharmony_ci		template.id = snd_soc_dapm_dai_out;
426262306a36Sopenharmony_ci		template.name = dai->driver->capture.stream_name;
426362306a36Sopenharmony_ci		template.sname = dai->driver->capture.stream_name;
426462306a36Sopenharmony_ci
426562306a36Sopenharmony_ci		dev_dbg(dai->dev, "ASoC: adding %s widget\n",
426662306a36Sopenharmony_ci			template.name);
426762306a36Sopenharmony_ci
426862306a36Sopenharmony_ci		w = snd_soc_dapm_new_control_unlocked(dapm, &template);
426962306a36Sopenharmony_ci		if (IS_ERR(w))
427062306a36Sopenharmony_ci			return PTR_ERR(w);
427162306a36Sopenharmony_ci
427262306a36Sopenharmony_ci		w->priv = dai;
427362306a36Sopenharmony_ci		snd_soc_dai_set_widget_capture(dai, w);
427462306a36Sopenharmony_ci	}
427562306a36Sopenharmony_ci
427662306a36Sopenharmony_ci	return 0;
427762306a36Sopenharmony_ci}
427862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_new_dai_widgets);
427962306a36Sopenharmony_ci
428062306a36Sopenharmony_ciint snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
428162306a36Sopenharmony_ci{
428262306a36Sopenharmony_ci	struct snd_soc_dapm_widget *dai_w, *w;
428362306a36Sopenharmony_ci	struct snd_soc_dapm_widget *src, *sink;
428462306a36Sopenharmony_ci	struct snd_soc_dai *dai;
428562306a36Sopenharmony_ci
428662306a36Sopenharmony_ci	/* For each DAI widget... */
428762306a36Sopenharmony_ci	for_each_card_widgets(card, dai_w) {
428862306a36Sopenharmony_ci		switch (dai_w->id) {
428962306a36Sopenharmony_ci		case snd_soc_dapm_dai_in:
429062306a36Sopenharmony_ci		case snd_soc_dapm_dai_out:
429162306a36Sopenharmony_ci			break;
429262306a36Sopenharmony_ci		default:
429362306a36Sopenharmony_ci			continue;
429462306a36Sopenharmony_ci		}
429562306a36Sopenharmony_ci
429662306a36Sopenharmony_ci		/* let users know there is no DAI to link */
429762306a36Sopenharmony_ci		if (!dai_w->priv) {
429862306a36Sopenharmony_ci			dev_dbg(card->dev, "dai widget %s has no DAI\n",
429962306a36Sopenharmony_ci				dai_w->name);
430062306a36Sopenharmony_ci			continue;
430162306a36Sopenharmony_ci		}
430262306a36Sopenharmony_ci
430362306a36Sopenharmony_ci		dai = dai_w->priv;
430462306a36Sopenharmony_ci
430562306a36Sopenharmony_ci		/* ...find all widgets with the same stream and link them */
430662306a36Sopenharmony_ci		for_each_card_widgets(card, w) {
430762306a36Sopenharmony_ci			if (w->dapm != dai_w->dapm)
430862306a36Sopenharmony_ci				continue;
430962306a36Sopenharmony_ci
431062306a36Sopenharmony_ci			switch (w->id) {
431162306a36Sopenharmony_ci			case snd_soc_dapm_dai_in:
431262306a36Sopenharmony_ci			case snd_soc_dapm_dai_out:
431362306a36Sopenharmony_ci				continue;
431462306a36Sopenharmony_ci			default:
431562306a36Sopenharmony_ci				break;
431662306a36Sopenharmony_ci			}
431762306a36Sopenharmony_ci
431862306a36Sopenharmony_ci			if (!w->sname || !strstr(w->sname, dai_w->sname))
431962306a36Sopenharmony_ci				continue;
432062306a36Sopenharmony_ci
432162306a36Sopenharmony_ci			if (dai_w->id == snd_soc_dapm_dai_in) {
432262306a36Sopenharmony_ci				src = dai_w;
432362306a36Sopenharmony_ci				sink = w;
432462306a36Sopenharmony_ci			} else {
432562306a36Sopenharmony_ci				src = w;
432662306a36Sopenharmony_ci				sink = dai_w;
432762306a36Sopenharmony_ci			}
432862306a36Sopenharmony_ci			dev_dbg(dai->dev, "%s -> %s\n", src->name, sink->name);
432962306a36Sopenharmony_ci			snd_soc_dapm_add_path(w->dapm, src, sink, NULL, NULL);
433062306a36Sopenharmony_ci		}
433162306a36Sopenharmony_ci	}
433262306a36Sopenharmony_ci
433362306a36Sopenharmony_ci	return 0;
433462306a36Sopenharmony_ci}
433562306a36Sopenharmony_ci
433662306a36Sopenharmony_cistatic void dapm_connect_dai_routes(struct snd_soc_dapm_context *dapm,
433762306a36Sopenharmony_ci				    struct snd_soc_dai *src_dai,
433862306a36Sopenharmony_ci				    struct snd_soc_dapm_widget *src,
433962306a36Sopenharmony_ci				    struct snd_soc_dapm_widget *dai,
434062306a36Sopenharmony_ci				    struct snd_soc_dai *sink_dai,
434162306a36Sopenharmony_ci				    struct snd_soc_dapm_widget *sink)
434262306a36Sopenharmony_ci{
434362306a36Sopenharmony_ci	dev_dbg(dapm->dev, "connected DAI link %s:%s -> %s:%s\n",
434462306a36Sopenharmony_ci		src_dai->component->name, src->name,
434562306a36Sopenharmony_ci		sink_dai->component->name, sink->name);
434662306a36Sopenharmony_ci
434762306a36Sopenharmony_ci	if (dai) {
434862306a36Sopenharmony_ci		snd_soc_dapm_add_path(dapm, src, dai, NULL, NULL);
434962306a36Sopenharmony_ci		src = dai;
435062306a36Sopenharmony_ci	}
435162306a36Sopenharmony_ci
435262306a36Sopenharmony_ci	snd_soc_dapm_add_path(dapm, src, sink, NULL, NULL);
435362306a36Sopenharmony_ci}
435462306a36Sopenharmony_ci
435562306a36Sopenharmony_cistatic void dapm_connect_dai_pair(struct snd_soc_card *card,
435662306a36Sopenharmony_ci				  struct snd_soc_pcm_runtime *rtd,
435762306a36Sopenharmony_ci				  struct snd_soc_dai *codec_dai,
435862306a36Sopenharmony_ci				  struct snd_soc_dai *cpu_dai)
435962306a36Sopenharmony_ci{
436062306a36Sopenharmony_ci	struct snd_soc_dai_link *dai_link = rtd->dai_link;
436162306a36Sopenharmony_ci	struct snd_soc_dapm_widget *codec, *cpu;
436262306a36Sopenharmony_ci	struct snd_soc_dai *src_dai[]		= { cpu_dai,	codec_dai };
436362306a36Sopenharmony_ci	struct snd_soc_dai *sink_dai[]		= { codec_dai,	cpu_dai };
436462306a36Sopenharmony_ci	struct snd_soc_dapm_widget **src[]	= { &cpu,	&codec };
436562306a36Sopenharmony_ci	struct snd_soc_dapm_widget **sink[]	= { &codec,	&cpu };
436662306a36Sopenharmony_ci	char *widget_name[]			= { "playback",	"capture" };
436762306a36Sopenharmony_ci	int stream;
436862306a36Sopenharmony_ci
436962306a36Sopenharmony_ci	for_each_pcm_streams(stream) {
437062306a36Sopenharmony_ci		int stream_cpu, stream_codec;
437162306a36Sopenharmony_ci
437262306a36Sopenharmony_ci		stream_cpu	= snd_soc_get_stream_cpu(dai_link, stream);
437362306a36Sopenharmony_ci		stream_codec	= stream;
437462306a36Sopenharmony_ci
437562306a36Sopenharmony_ci		/* connect BE DAI playback if widgets are valid */
437662306a36Sopenharmony_ci		cpu	= snd_soc_dai_get_widget(cpu_dai,	stream_cpu);
437762306a36Sopenharmony_ci		codec	= snd_soc_dai_get_widget(codec_dai,	stream_codec);
437862306a36Sopenharmony_ci
437962306a36Sopenharmony_ci		if (!cpu || !codec)
438062306a36Sopenharmony_ci			continue;
438162306a36Sopenharmony_ci
438262306a36Sopenharmony_ci		/* special handling for [Codec2Codec] */
438362306a36Sopenharmony_ci		if (dai_link->c2c_params && !rtd->c2c_widget[stream]) {
438462306a36Sopenharmony_ci			struct snd_pcm_substream *substream = rtd->pcm->streams[stream].substream;
438562306a36Sopenharmony_ci			struct snd_soc_dapm_widget *dai = snd_soc_dapm_new_dai(card, substream,
438662306a36Sopenharmony_ci									       widget_name[stream]);
438762306a36Sopenharmony_ci
438862306a36Sopenharmony_ci			if (IS_ERR(dai))
438962306a36Sopenharmony_ci				continue;
439062306a36Sopenharmony_ci
439162306a36Sopenharmony_ci			rtd->c2c_widget[stream] = dai;
439262306a36Sopenharmony_ci		}
439362306a36Sopenharmony_ci
439462306a36Sopenharmony_ci		dapm_connect_dai_routes(&card->dapm, src_dai[stream], *src[stream],
439562306a36Sopenharmony_ci					rtd->c2c_widget[stream],
439662306a36Sopenharmony_ci					sink_dai[stream], *sink[stream]);
439762306a36Sopenharmony_ci	}
439862306a36Sopenharmony_ci}
439962306a36Sopenharmony_ci
440062306a36Sopenharmony_cistatic void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
440162306a36Sopenharmony_ci	int event)
440262306a36Sopenharmony_ci{
440362306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
440462306a36Sopenharmony_ci
440562306a36Sopenharmony_ci	w = snd_soc_dai_get_widget(dai, stream);
440662306a36Sopenharmony_ci
440762306a36Sopenharmony_ci	if (w) {
440862306a36Sopenharmony_ci		unsigned int ep;
440962306a36Sopenharmony_ci
441062306a36Sopenharmony_ci		dapm_mark_dirty(w, "stream event");
441162306a36Sopenharmony_ci
441262306a36Sopenharmony_ci		if (w->id == snd_soc_dapm_dai_in) {
441362306a36Sopenharmony_ci			ep = SND_SOC_DAPM_EP_SOURCE;
441462306a36Sopenharmony_ci			dapm_widget_invalidate_input_paths(w);
441562306a36Sopenharmony_ci		} else {
441662306a36Sopenharmony_ci			ep = SND_SOC_DAPM_EP_SINK;
441762306a36Sopenharmony_ci			dapm_widget_invalidate_output_paths(w);
441862306a36Sopenharmony_ci		}
441962306a36Sopenharmony_ci
442062306a36Sopenharmony_ci		switch (event) {
442162306a36Sopenharmony_ci		case SND_SOC_DAPM_STREAM_START:
442262306a36Sopenharmony_ci			w->active = 1;
442362306a36Sopenharmony_ci			w->is_ep = ep;
442462306a36Sopenharmony_ci			break;
442562306a36Sopenharmony_ci		case SND_SOC_DAPM_STREAM_STOP:
442662306a36Sopenharmony_ci			w->active = 0;
442762306a36Sopenharmony_ci			w->is_ep = 0;
442862306a36Sopenharmony_ci			break;
442962306a36Sopenharmony_ci		case SND_SOC_DAPM_STREAM_SUSPEND:
443062306a36Sopenharmony_ci		case SND_SOC_DAPM_STREAM_RESUME:
443162306a36Sopenharmony_ci		case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
443262306a36Sopenharmony_ci		case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
443362306a36Sopenharmony_ci			break;
443462306a36Sopenharmony_ci		}
443562306a36Sopenharmony_ci	}
443662306a36Sopenharmony_ci}
443762306a36Sopenharmony_ci
443862306a36Sopenharmony_civoid snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
443962306a36Sopenharmony_ci{
444062306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd;
444162306a36Sopenharmony_ci	struct snd_soc_dai *codec_dai;
444262306a36Sopenharmony_ci	int i;
444362306a36Sopenharmony_ci
444462306a36Sopenharmony_ci	/* for each BE DAI link... */
444562306a36Sopenharmony_ci	for_each_card_rtds(card, rtd)  {
444662306a36Sopenharmony_ci		/*
444762306a36Sopenharmony_ci		 * dynamic FE links have no fixed DAI mapping.
444862306a36Sopenharmony_ci		 * CODEC<->CODEC links have no direct connection.
444962306a36Sopenharmony_ci		 */
445062306a36Sopenharmony_ci		if (rtd->dai_link->dynamic)
445162306a36Sopenharmony_ci			continue;
445262306a36Sopenharmony_ci
445362306a36Sopenharmony_ci		if (rtd->dai_link->num_cpus == 1) {
445462306a36Sopenharmony_ci			for_each_rtd_codec_dais(rtd, i, codec_dai)
445562306a36Sopenharmony_ci				dapm_connect_dai_pair(card, rtd, codec_dai,
445662306a36Sopenharmony_ci						      asoc_rtd_to_cpu(rtd, 0));
445762306a36Sopenharmony_ci		} else if (rtd->dai_link->num_codecs == rtd->dai_link->num_cpus) {
445862306a36Sopenharmony_ci			for_each_rtd_codec_dais(rtd, i, codec_dai)
445962306a36Sopenharmony_ci				dapm_connect_dai_pair(card, rtd, codec_dai,
446062306a36Sopenharmony_ci						      asoc_rtd_to_cpu(rtd, i));
446162306a36Sopenharmony_ci		} else if (rtd->dai_link->num_codecs > rtd->dai_link->num_cpus) {
446262306a36Sopenharmony_ci			int cpu_id;
446362306a36Sopenharmony_ci
446462306a36Sopenharmony_ci			if (!rtd->dai_link->codec_ch_maps) {
446562306a36Sopenharmony_ci				dev_err(card->dev, "%s: no codec channel mapping table provided\n",
446662306a36Sopenharmony_ci					__func__);
446762306a36Sopenharmony_ci				continue;
446862306a36Sopenharmony_ci			}
446962306a36Sopenharmony_ci
447062306a36Sopenharmony_ci			for_each_rtd_codec_dais(rtd, i, codec_dai) {
447162306a36Sopenharmony_ci				cpu_id = rtd->dai_link->codec_ch_maps[i].connected_cpu_id;
447262306a36Sopenharmony_ci				if (cpu_id >= rtd->dai_link->num_cpus) {
447362306a36Sopenharmony_ci					dev_err(card->dev,
447462306a36Sopenharmony_ci						"%s: dai_link %s cpu_id %d too large, num_cpus is %d\n",
447562306a36Sopenharmony_ci						__func__, rtd->dai_link->name, cpu_id,
447662306a36Sopenharmony_ci						rtd->dai_link->num_cpus);
447762306a36Sopenharmony_ci					continue;
447862306a36Sopenharmony_ci				}
447962306a36Sopenharmony_ci				dapm_connect_dai_pair(card, rtd, codec_dai,
448062306a36Sopenharmony_ci						      asoc_rtd_to_cpu(rtd, cpu_id));
448162306a36Sopenharmony_ci			}
448262306a36Sopenharmony_ci		} else {
448362306a36Sopenharmony_ci			dev_err(card->dev,
448462306a36Sopenharmony_ci				"%s: codec number %d < cpu number %d is not supported\n",
448562306a36Sopenharmony_ci				__func__, rtd->dai_link->num_codecs, rtd->dai_link->num_cpus);
448662306a36Sopenharmony_ci		}
448762306a36Sopenharmony_ci	}
448862306a36Sopenharmony_ci}
448962306a36Sopenharmony_ci
449062306a36Sopenharmony_cistatic void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
449162306a36Sopenharmony_ci	int event)
449262306a36Sopenharmony_ci{
449362306a36Sopenharmony_ci	struct snd_soc_dai *dai;
449462306a36Sopenharmony_ci	int i;
449562306a36Sopenharmony_ci
449662306a36Sopenharmony_ci	for_each_rtd_dais(rtd, i, dai)
449762306a36Sopenharmony_ci		soc_dapm_dai_stream_event(dai, stream, event);
449862306a36Sopenharmony_ci
449962306a36Sopenharmony_ci	dapm_power_widgets(rtd->card, event);
450062306a36Sopenharmony_ci}
450162306a36Sopenharmony_ci
450262306a36Sopenharmony_ci/**
450362306a36Sopenharmony_ci * snd_soc_dapm_stream_event - send a stream event to the dapm core
450462306a36Sopenharmony_ci * @rtd: PCM runtime data
450562306a36Sopenharmony_ci * @stream: stream name
450662306a36Sopenharmony_ci * @event: stream event
450762306a36Sopenharmony_ci *
450862306a36Sopenharmony_ci * Sends a stream event to the dapm core. The core then makes any
450962306a36Sopenharmony_ci * necessary widget power changes.
451062306a36Sopenharmony_ci *
451162306a36Sopenharmony_ci * Returns 0 for success else error.
451262306a36Sopenharmony_ci */
451362306a36Sopenharmony_civoid snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
451462306a36Sopenharmony_ci			      int event)
451562306a36Sopenharmony_ci{
451662306a36Sopenharmony_ci	struct snd_soc_card *card = rtd->card;
451762306a36Sopenharmony_ci
451862306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(card);
451962306a36Sopenharmony_ci	soc_dapm_stream_event(rtd, stream, event);
452062306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(card);
452162306a36Sopenharmony_ci}
452262306a36Sopenharmony_ci
452362306a36Sopenharmony_civoid snd_soc_dapm_stream_stop(struct snd_soc_pcm_runtime *rtd, int stream)
452462306a36Sopenharmony_ci{
452562306a36Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
452662306a36Sopenharmony_ci		if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
452762306a36Sopenharmony_ci			/* powered down playback stream now */
452862306a36Sopenharmony_ci			snd_soc_dapm_stream_event(rtd,
452962306a36Sopenharmony_ci						  SNDRV_PCM_STREAM_PLAYBACK,
453062306a36Sopenharmony_ci						  SND_SOC_DAPM_STREAM_STOP);
453162306a36Sopenharmony_ci		} else {
453262306a36Sopenharmony_ci			/* start delayed pop wq here for playback streams */
453362306a36Sopenharmony_ci			rtd->pop_wait = 1;
453462306a36Sopenharmony_ci			queue_delayed_work(system_power_efficient_wq,
453562306a36Sopenharmony_ci					   &rtd->delayed_work,
453662306a36Sopenharmony_ci					   msecs_to_jiffies(rtd->pmdown_time));
453762306a36Sopenharmony_ci		}
453862306a36Sopenharmony_ci	} else {
453962306a36Sopenharmony_ci		/* capture streams can be powered down now */
454062306a36Sopenharmony_ci		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
454162306a36Sopenharmony_ci					  SND_SOC_DAPM_STREAM_STOP);
454262306a36Sopenharmony_ci	}
454362306a36Sopenharmony_ci}
454462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_stream_stop);
454562306a36Sopenharmony_ci
454662306a36Sopenharmony_ci/**
454762306a36Sopenharmony_ci * snd_soc_dapm_enable_pin_unlocked - enable pin.
454862306a36Sopenharmony_ci * @dapm: DAPM context
454962306a36Sopenharmony_ci * @pin: pin name
455062306a36Sopenharmony_ci *
455162306a36Sopenharmony_ci * Enables input/output pin and its parents or children widgets iff there is
455262306a36Sopenharmony_ci * a valid audio route and active audio stream.
455362306a36Sopenharmony_ci *
455462306a36Sopenharmony_ci * Requires external locking.
455562306a36Sopenharmony_ci *
455662306a36Sopenharmony_ci * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
455762306a36Sopenharmony_ci * do any widget power switching.
455862306a36Sopenharmony_ci */
455962306a36Sopenharmony_ciint snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
456062306a36Sopenharmony_ci				   const char *pin)
456162306a36Sopenharmony_ci{
456262306a36Sopenharmony_ci	return snd_soc_dapm_set_pin(dapm, pin, 1);
456362306a36Sopenharmony_ci}
456462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked);
456562306a36Sopenharmony_ci
456662306a36Sopenharmony_ci/**
456762306a36Sopenharmony_ci * snd_soc_dapm_enable_pin - enable pin.
456862306a36Sopenharmony_ci * @dapm: DAPM context
456962306a36Sopenharmony_ci * @pin: pin name
457062306a36Sopenharmony_ci *
457162306a36Sopenharmony_ci * Enables input/output pin and its parents or children widgets iff there is
457262306a36Sopenharmony_ci * a valid audio route and active audio stream.
457362306a36Sopenharmony_ci *
457462306a36Sopenharmony_ci * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
457562306a36Sopenharmony_ci * do any widget power switching.
457662306a36Sopenharmony_ci */
457762306a36Sopenharmony_ciint snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
457862306a36Sopenharmony_ci{
457962306a36Sopenharmony_ci	int ret;
458062306a36Sopenharmony_ci
458162306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(dapm);
458262306a36Sopenharmony_ci
458362306a36Sopenharmony_ci	ret = snd_soc_dapm_set_pin(dapm, pin, 1);
458462306a36Sopenharmony_ci
458562306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(dapm);
458662306a36Sopenharmony_ci
458762306a36Sopenharmony_ci	return ret;
458862306a36Sopenharmony_ci}
458962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
459062306a36Sopenharmony_ci
459162306a36Sopenharmony_ci/**
459262306a36Sopenharmony_ci * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled
459362306a36Sopenharmony_ci * @dapm: DAPM context
459462306a36Sopenharmony_ci * @pin: pin name
459562306a36Sopenharmony_ci *
459662306a36Sopenharmony_ci * Enables input/output pin regardless of any other state.  This is
459762306a36Sopenharmony_ci * intended for use with microphone bias supplies used in microphone
459862306a36Sopenharmony_ci * jack detection.
459962306a36Sopenharmony_ci *
460062306a36Sopenharmony_ci * Requires external locking.
460162306a36Sopenharmony_ci *
460262306a36Sopenharmony_ci * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
460362306a36Sopenharmony_ci * do any widget power switching.
460462306a36Sopenharmony_ci */
460562306a36Sopenharmony_ciint snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
460662306a36Sopenharmony_ci					 const char *pin)
460762306a36Sopenharmony_ci{
460862306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
460962306a36Sopenharmony_ci
461062306a36Sopenharmony_ci	if (!w) {
461162306a36Sopenharmony_ci		dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
461262306a36Sopenharmony_ci		return -EINVAL;
461362306a36Sopenharmony_ci	}
461462306a36Sopenharmony_ci
461562306a36Sopenharmony_ci	dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin);
461662306a36Sopenharmony_ci	if (!w->connected) {
461762306a36Sopenharmony_ci		/*
461862306a36Sopenharmony_ci		 * w->force does not affect the number of input or output paths,
461962306a36Sopenharmony_ci		 * so we only have to recheck if w->connected is changed
462062306a36Sopenharmony_ci		 */
462162306a36Sopenharmony_ci		dapm_widget_invalidate_input_paths(w);
462262306a36Sopenharmony_ci		dapm_widget_invalidate_output_paths(w);
462362306a36Sopenharmony_ci		w->connected = 1;
462462306a36Sopenharmony_ci	}
462562306a36Sopenharmony_ci	w->force = 1;
462662306a36Sopenharmony_ci	dapm_mark_dirty(w, "force enable");
462762306a36Sopenharmony_ci
462862306a36Sopenharmony_ci	return 0;
462962306a36Sopenharmony_ci}
463062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked);
463162306a36Sopenharmony_ci
463262306a36Sopenharmony_ci/**
463362306a36Sopenharmony_ci * snd_soc_dapm_force_enable_pin - force a pin to be enabled
463462306a36Sopenharmony_ci * @dapm: DAPM context
463562306a36Sopenharmony_ci * @pin: pin name
463662306a36Sopenharmony_ci *
463762306a36Sopenharmony_ci * Enables input/output pin regardless of any other state.  This is
463862306a36Sopenharmony_ci * intended for use with microphone bias supplies used in microphone
463962306a36Sopenharmony_ci * jack detection.
464062306a36Sopenharmony_ci *
464162306a36Sopenharmony_ci * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
464262306a36Sopenharmony_ci * do any widget power switching.
464362306a36Sopenharmony_ci */
464462306a36Sopenharmony_ciint snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
464562306a36Sopenharmony_ci				  const char *pin)
464662306a36Sopenharmony_ci{
464762306a36Sopenharmony_ci	int ret;
464862306a36Sopenharmony_ci
464962306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(dapm);
465062306a36Sopenharmony_ci
465162306a36Sopenharmony_ci	ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
465262306a36Sopenharmony_ci
465362306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(dapm);
465462306a36Sopenharmony_ci
465562306a36Sopenharmony_ci	return ret;
465662306a36Sopenharmony_ci}
465762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
465862306a36Sopenharmony_ci
465962306a36Sopenharmony_ci/**
466062306a36Sopenharmony_ci * snd_soc_dapm_disable_pin_unlocked - disable pin.
466162306a36Sopenharmony_ci * @dapm: DAPM context
466262306a36Sopenharmony_ci * @pin: pin name
466362306a36Sopenharmony_ci *
466462306a36Sopenharmony_ci * Disables input/output pin and its parents or children widgets.
466562306a36Sopenharmony_ci *
466662306a36Sopenharmony_ci * Requires external locking.
466762306a36Sopenharmony_ci *
466862306a36Sopenharmony_ci * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
466962306a36Sopenharmony_ci * do any widget power switching.
467062306a36Sopenharmony_ci */
467162306a36Sopenharmony_ciint snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
467262306a36Sopenharmony_ci				    const char *pin)
467362306a36Sopenharmony_ci{
467462306a36Sopenharmony_ci	return snd_soc_dapm_set_pin(dapm, pin, 0);
467562306a36Sopenharmony_ci}
467662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked);
467762306a36Sopenharmony_ci
467862306a36Sopenharmony_ci/**
467962306a36Sopenharmony_ci * snd_soc_dapm_disable_pin - disable pin.
468062306a36Sopenharmony_ci * @dapm: DAPM context
468162306a36Sopenharmony_ci * @pin: pin name
468262306a36Sopenharmony_ci *
468362306a36Sopenharmony_ci * Disables input/output pin and its parents or children widgets.
468462306a36Sopenharmony_ci *
468562306a36Sopenharmony_ci * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
468662306a36Sopenharmony_ci * do any widget power switching.
468762306a36Sopenharmony_ci */
468862306a36Sopenharmony_ciint snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
468962306a36Sopenharmony_ci			     const char *pin)
469062306a36Sopenharmony_ci{
469162306a36Sopenharmony_ci	int ret;
469262306a36Sopenharmony_ci
469362306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(dapm);
469462306a36Sopenharmony_ci
469562306a36Sopenharmony_ci	ret = snd_soc_dapm_set_pin(dapm, pin, 0);
469662306a36Sopenharmony_ci
469762306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(dapm);
469862306a36Sopenharmony_ci
469962306a36Sopenharmony_ci	return ret;
470062306a36Sopenharmony_ci}
470162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
470262306a36Sopenharmony_ci
470362306a36Sopenharmony_ci/**
470462306a36Sopenharmony_ci * snd_soc_dapm_nc_pin_unlocked - permanently disable pin.
470562306a36Sopenharmony_ci * @dapm: DAPM context
470662306a36Sopenharmony_ci * @pin: pin name
470762306a36Sopenharmony_ci *
470862306a36Sopenharmony_ci * Marks the specified pin as being not connected, disabling it along
470962306a36Sopenharmony_ci * any parent or child widgets.  At present this is identical to
471062306a36Sopenharmony_ci * snd_soc_dapm_disable_pin() but in future it will be extended to do
471162306a36Sopenharmony_ci * additional things such as disabling controls which only affect
471262306a36Sopenharmony_ci * paths through the pin.
471362306a36Sopenharmony_ci *
471462306a36Sopenharmony_ci * Requires external locking.
471562306a36Sopenharmony_ci *
471662306a36Sopenharmony_ci * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
471762306a36Sopenharmony_ci * do any widget power switching.
471862306a36Sopenharmony_ci */
471962306a36Sopenharmony_ciint snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
472062306a36Sopenharmony_ci			       const char *pin)
472162306a36Sopenharmony_ci{
472262306a36Sopenharmony_ci	return snd_soc_dapm_set_pin(dapm, pin, 0);
472362306a36Sopenharmony_ci}
472462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked);
472562306a36Sopenharmony_ci
472662306a36Sopenharmony_ci/**
472762306a36Sopenharmony_ci * snd_soc_dapm_nc_pin - permanently disable pin.
472862306a36Sopenharmony_ci * @dapm: DAPM context
472962306a36Sopenharmony_ci * @pin: pin name
473062306a36Sopenharmony_ci *
473162306a36Sopenharmony_ci * Marks the specified pin as being not connected, disabling it along
473262306a36Sopenharmony_ci * any parent or child widgets.  At present this is identical to
473362306a36Sopenharmony_ci * snd_soc_dapm_disable_pin() but in future it will be extended to do
473462306a36Sopenharmony_ci * additional things such as disabling controls which only affect
473562306a36Sopenharmony_ci * paths through the pin.
473662306a36Sopenharmony_ci *
473762306a36Sopenharmony_ci * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
473862306a36Sopenharmony_ci * do any widget power switching.
473962306a36Sopenharmony_ci */
474062306a36Sopenharmony_ciint snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
474162306a36Sopenharmony_ci{
474262306a36Sopenharmony_ci	int ret;
474362306a36Sopenharmony_ci
474462306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock(dapm);
474562306a36Sopenharmony_ci
474662306a36Sopenharmony_ci	ret = snd_soc_dapm_set_pin(dapm, pin, 0);
474762306a36Sopenharmony_ci
474862306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(dapm);
474962306a36Sopenharmony_ci
475062306a36Sopenharmony_ci	return ret;
475162306a36Sopenharmony_ci}
475262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
475362306a36Sopenharmony_ci
475462306a36Sopenharmony_ci/**
475562306a36Sopenharmony_ci * snd_soc_dapm_get_pin_status - get audio pin status
475662306a36Sopenharmony_ci * @dapm: DAPM context
475762306a36Sopenharmony_ci * @pin: audio signal pin endpoint (or start point)
475862306a36Sopenharmony_ci *
475962306a36Sopenharmony_ci * Get audio pin status - connected or disconnected.
476062306a36Sopenharmony_ci *
476162306a36Sopenharmony_ci * Returns 1 for connected otherwise 0.
476262306a36Sopenharmony_ci */
476362306a36Sopenharmony_ciint snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
476462306a36Sopenharmony_ci				const char *pin)
476562306a36Sopenharmony_ci{
476662306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
476762306a36Sopenharmony_ci
476862306a36Sopenharmony_ci	if (w)
476962306a36Sopenharmony_ci		return w->connected;
477062306a36Sopenharmony_ci
477162306a36Sopenharmony_ci	return 0;
477262306a36Sopenharmony_ci}
477362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
477462306a36Sopenharmony_ci
477562306a36Sopenharmony_ci/**
477662306a36Sopenharmony_ci * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
477762306a36Sopenharmony_ci * @dapm: DAPM context
477862306a36Sopenharmony_ci * @pin: audio signal pin endpoint (or start point)
477962306a36Sopenharmony_ci *
478062306a36Sopenharmony_ci * Mark the given endpoint or pin as ignoring suspend.  When the
478162306a36Sopenharmony_ci * system is disabled a path between two endpoints flagged as ignoring
478262306a36Sopenharmony_ci * suspend will not be disabled.  The path must already be enabled via
478362306a36Sopenharmony_ci * normal means at suspend time, it will not be turned on if it was not
478462306a36Sopenharmony_ci * already enabled.
478562306a36Sopenharmony_ci */
478662306a36Sopenharmony_ciint snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
478762306a36Sopenharmony_ci				const char *pin)
478862306a36Sopenharmony_ci{
478962306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
479062306a36Sopenharmony_ci
479162306a36Sopenharmony_ci	if (!w) {
479262306a36Sopenharmony_ci		dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
479362306a36Sopenharmony_ci		return -EINVAL;
479462306a36Sopenharmony_ci	}
479562306a36Sopenharmony_ci
479662306a36Sopenharmony_ci	w->ignore_suspend = 1;
479762306a36Sopenharmony_ci
479862306a36Sopenharmony_ci	return 0;
479962306a36Sopenharmony_ci}
480062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
480162306a36Sopenharmony_ci
480262306a36Sopenharmony_ci/**
480362306a36Sopenharmony_ci * snd_soc_dapm_free - free dapm resources
480462306a36Sopenharmony_ci * @dapm: DAPM context
480562306a36Sopenharmony_ci *
480662306a36Sopenharmony_ci * Free all dapm widgets and resources.
480762306a36Sopenharmony_ci */
480862306a36Sopenharmony_civoid snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
480962306a36Sopenharmony_ci{
481062306a36Sopenharmony_ci	dapm_debugfs_cleanup(dapm);
481162306a36Sopenharmony_ci	dapm_free_widgets(dapm);
481262306a36Sopenharmony_ci	list_del(&dapm->list);
481362306a36Sopenharmony_ci}
481462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_free);
481562306a36Sopenharmony_ci
481662306a36Sopenharmony_civoid snd_soc_dapm_init(struct snd_soc_dapm_context *dapm,
481762306a36Sopenharmony_ci		       struct snd_soc_card *card,
481862306a36Sopenharmony_ci		       struct snd_soc_component *component)
481962306a36Sopenharmony_ci{
482062306a36Sopenharmony_ci	dapm->card		= card;
482162306a36Sopenharmony_ci	dapm->component		= component;
482262306a36Sopenharmony_ci	dapm->bias_level	= SND_SOC_BIAS_OFF;
482362306a36Sopenharmony_ci
482462306a36Sopenharmony_ci	if (component) {
482562306a36Sopenharmony_ci		dapm->dev		= component->dev;
482662306a36Sopenharmony_ci		dapm->idle_bias_off	= !component->driver->idle_bias_on;
482762306a36Sopenharmony_ci		dapm->suspend_bias_off	= component->driver->suspend_bias_off;
482862306a36Sopenharmony_ci	} else {
482962306a36Sopenharmony_ci		dapm->dev		= card->dev;
483062306a36Sopenharmony_ci	}
483162306a36Sopenharmony_ci
483262306a36Sopenharmony_ci	INIT_LIST_HEAD(&dapm->list);
483362306a36Sopenharmony_ci	/* see for_each_card_dapms */
483462306a36Sopenharmony_ci	list_add(&dapm->list, &card->dapm_list);
483562306a36Sopenharmony_ci}
483662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_dapm_init);
483762306a36Sopenharmony_ci
483862306a36Sopenharmony_cistatic void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm)
483962306a36Sopenharmony_ci{
484062306a36Sopenharmony_ci	struct snd_soc_card *card = dapm->card;
484162306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
484262306a36Sopenharmony_ci	LIST_HEAD(down_list);
484362306a36Sopenharmony_ci	int powerdown = 0;
484462306a36Sopenharmony_ci
484562306a36Sopenharmony_ci	snd_soc_dapm_mutex_lock_root(card);
484662306a36Sopenharmony_ci
484762306a36Sopenharmony_ci	for_each_card_widgets(dapm->card, w) {
484862306a36Sopenharmony_ci		if (w->dapm != dapm)
484962306a36Sopenharmony_ci			continue;
485062306a36Sopenharmony_ci		if (w->power) {
485162306a36Sopenharmony_ci			dapm_seq_insert(w, &down_list, false);
485262306a36Sopenharmony_ci			w->new_power = 0;
485362306a36Sopenharmony_ci			powerdown = 1;
485462306a36Sopenharmony_ci		}
485562306a36Sopenharmony_ci	}
485662306a36Sopenharmony_ci
485762306a36Sopenharmony_ci	/* If there were no widgets to power down we're already in
485862306a36Sopenharmony_ci	 * standby.
485962306a36Sopenharmony_ci	 */
486062306a36Sopenharmony_ci	if (powerdown) {
486162306a36Sopenharmony_ci		if (dapm->bias_level == SND_SOC_BIAS_ON)
486262306a36Sopenharmony_ci			snd_soc_dapm_set_bias_level(dapm,
486362306a36Sopenharmony_ci						    SND_SOC_BIAS_PREPARE);
486462306a36Sopenharmony_ci		dapm_seq_run(card, &down_list, 0, false);
486562306a36Sopenharmony_ci		if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
486662306a36Sopenharmony_ci			snd_soc_dapm_set_bias_level(dapm,
486762306a36Sopenharmony_ci						    SND_SOC_BIAS_STANDBY);
486862306a36Sopenharmony_ci	}
486962306a36Sopenharmony_ci
487062306a36Sopenharmony_ci	snd_soc_dapm_mutex_unlock(card);
487162306a36Sopenharmony_ci}
487262306a36Sopenharmony_ci
487362306a36Sopenharmony_ci/*
487462306a36Sopenharmony_ci * snd_soc_dapm_shutdown - callback for system shutdown
487562306a36Sopenharmony_ci */
487662306a36Sopenharmony_civoid snd_soc_dapm_shutdown(struct snd_soc_card *card)
487762306a36Sopenharmony_ci{
487862306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm;
487962306a36Sopenharmony_ci
488062306a36Sopenharmony_ci	for_each_card_dapms(card, dapm) {
488162306a36Sopenharmony_ci		if (dapm != &card->dapm) {
488262306a36Sopenharmony_ci			soc_dapm_shutdown_dapm(dapm);
488362306a36Sopenharmony_ci			if (dapm->bias_level == SND_SOC_BIAS_STANDBY)
488462306a36Sopenharmony_ci				snd_soc_dapm_set_bias_level(dapm,
488562306a36Sopenharmony_ci							    SND_SOC_BIAS_OFF);
488662306a36Sopenharmony_ci		}
488762306a36Sopenharmony_ci	}
488862306a36Sopenharmony_ci
488962306a36Sopenharmony_ci	soc_dapm_shutdown_dapm(&card->dapm);
489062306a36Sopenharmony_ci	if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY)
489162306a36Sopenharmony_ci		snd_soc_dapm_set_bias_level(&card->dapm,
489262306a36Sopenharmony_ci					    SND_SOC_BIAS_OFF);
489362306a36Sopenharmony_ci}
489462306a36Sopenharmony_ci
489562306a36Sopenharmony_ci/* Module information */
489662306a36Sopenharmony_ciMODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
489762306a36Sopenharmony_ciMODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
489862306a36Sopenharmony_ciMODULE_LICENSE("GPL");
4899