xref: /kernel/linux/linux-6.6/sound/pci/hda/hda_codec.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Universal Interface for Intel High Definition Audio Codec
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/init.h>
962306a36Sopenharmony_ci#include <linux/delay.h>
1062306a36Sopenharmony_ci#include <linux/slab.h>
1162306a36Sopenharmony_ci#include <linux/mutex.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/pm.h>
1462306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1562306a36Sopenharmony_ci#include <sound/core.h>
1662306a36Sopenharmony_ci#include <sound/hda_codec.h>
1762306a36Sopenharmony_ci#include <sound/asoundef.h>
1862306a36Sopenharmony_ci#include <sound/tlv.h>
1962306a36Sopenharmony_ci#include <sound/initval.h>
2062306a36Sopenharmony_ci#include <sound/jack.h>
2162306a36Sopenharmony_ci#include "hda_local.h"
2262306a36Sopenharmony_ci#include "hda_beep.h"
2362306a36Sopenharmony_ci#include "hda_jack.h"
2462306a36Sopenharmony_ci#include <sound/hda_hwdep.h>
2562306a36Sopenharmony_ci#include <sound/hda_component.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define codec_in_pm(codec)		snd_hdac_is_in_pm(&codec->core)
2862306a36Sopenharmony_ci#define hda_codec_is_power_on(codec)	snd_hdac_is_power_on(&codec->core)
2962306a36Sopenharmony_ci#define codec_has_epss(codec) \
3062306a36Sopenharmony_ci	((codec)->core.power_caps & AC_PWRST_EPSS)
3162306a36Sopenharmony_ci#define codec_has_clkstop(codec) \
3262306a36Sopenharmony_ci	((codec)->core.power_caps & AC_PWRST_CLKSTOP)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/*
3562306a36Sopenharmony_ci * Send and receive a verb - passed to exec_verb override for hdac_device
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_cistatic int codec_exec_verb(struct hdac_device *dev, unsigned int cmd,
3862306a36Sopenharmony_ci			   unsigned int flags, unsigned int *res)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	struct hda_codec *codec = container_of(dev, struct hda_codec, core);
4162306a36Sopenharmony_ci	struct hda_bus *bus = codec->bus;
4262306a36Sopenharmony_ci	int err;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	if (cmd == ~0)
4562306a36Sopenharmony_ci		return -1;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci again:
4862306a36Sopenharmony_ci	snd_hda_power_up_pm(codec);
4962306a36Sopenharmony_ci	mutex_lock(&bus->core.cmd_mutex);
5062306a36Sopenharmony_ci	if (flags & HDA_RW_NO_RESPONSE_FALLBACK)
5162306a36Sopenharmony_ci		bus->no_response_fallback = 1;
5262306a36Sopenharmony_ci	err = snd_hdac_bus_exec_verb_unlocked(&bus->core, codec->core.addr,
5362306a36Sopenharmony_ci					      cmd, res);
5462306a36Sopenharmony_ci	bus->no_response_fallback = 0;
5562306a36Sopenharmony_ci	mutex_unlock(&bus->core.cmd_mutex);
5662306a36Sopenharmony_ci	snd_hda_power_down_pm(codec);
5762306a36Sopenharmony_ci	if (!codec_in_pm(codec) && res && err == -EAGAIN) {
5862306a36Sopenharmony_ci		if (bus->response_reset) {
5962306a36Sopenharmony_ci			codec_dbg(codec,
6062306a36Sopenharmony_ci				  "resetting BUS due to fatal communication error\n");
6162306a36Sopenharmony_ci			snd_hda_bus_reset(bus);
6262306a36Sopenharmony_ci		}
6362306a36Sopenharmony_ci		goto again;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci	/* clear reset-flag when the communication gets recovered */
6662306a36Sopenharmony_ci	if (!err || codec_in_pm(codec))
6762306a36Sopenharmony_ci		bus->response_reset = 0;
6862306a36Sopenharmony_ci	return err;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/**
7262306a36Sopenharmony_ci * snd_hda_sequence_write - sequence writes
7362306a36Sopenharmony_ci * @codec: the HDA codec
7462306a36Sopenharmony_ci * @seq: VERB array to send
7562306a36Sopenharmony_ci *
7662306a36Sopenharmony_ci * Send the commands sequentially from the given array.
7762306a36Sopenharmony_ci * The array must be terminated with NID=0.
7862306a36Sopenharmony_ci */
7962306a36Sopenharmony_civoid snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	for (; seq->nid; seq++)
8262306a36Sopenharmony_ci		snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_sequence_write);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci/* connection list element */
8762306a36Sopenharmony_cistruct hda_conn_list {
8862306a36Sopenharmony_ci	struct list_head list;
8962306a36Sopenharmony_ci	int len;
9062306a36Sopenharmony_ci	hda_nid_t nid;
9162306a36Sopenharmony_ci	hda_nid_t conns[];
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/* look up the cached results */
9562306a36Sopenharmony_cistatic struct hda_conn_list *
9662306a36Sopenharmony_cilookup_conn_list(struct hda_codec *codec, hda_nid_t nid)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct hda_conn_list *p;
9962306a36Sopenharmony_ci	list_for_each_entry(p, &codec->conn_list, list) {
10062306a36Sopenharmony_ci		if (p->nid == nid)
10162306a36Sopenharmony_ci			return p;
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci	return NULL;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic int add_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
10762306a36Sopenharmony_ci			 const hda_nid_t *list)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	struct hda_conn_list *p;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	p = kmalloc(struct_size(p, conns, len), GFP_KERNEL);
11262306a36Sopenharmony_ci	if (!p)
11362306a36Sopenharmony_ci		return -ENOMEM;
11462306a36Sopenharmony_ci	p->len = len;
11562306a36Sopenharmony_ci	p->nid = nid;
11662306a36Sopenharmony_ci	memcpy(p->conns, list, len * sizeof(hda_nid_t));
11762306a36Sopenharmony_ci	list_add(&p->list, &codec->conn_list);
11862306a36Sopenharmony_ci	return 0;
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic void remove_conn_list(struct hda_codec *codec)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	while (!list_empty(&codec->conn_list)) {
12462306a36Sopenharmony_ci		struct hda_conn_list *p;
12562306a36Sopenharmony_ci		p = list_first_entry(&codec->conn_list, typeof(*p), list);
12662306a36Sopenharmony_ci		list_del(&p->list);
12762306a36Sopenharmony_ci		kfree(p);
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/* read the connection and add to the cache */
13262306a36Sopenharmony_cistatic int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	hda_nid_t list[32];
13562306a36Sopenharmony_ci	hda_nid_t *result = list;
13662306a36Sopenharmony_ci	int len;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	len = snd_hda_get_raw_connections(codec, nid, list, ARRAY_SIZE(list));
13962306a36Sopenharmony_ci	if (len == -ENOSPC) {
14062306a36Sopenharmony_ci		len = snd_hda_get_num_raw_conns(codec, nid);
14162306a36Sopenharmony_ci		result = kmalloc_array(len, sizeof(hda_nid_t), GFP_KERNEL);
14262306a36Sopenharmony_ci		if (!result)
14362306a36Sopenharmony_ci			return -ENOMEM;
14462306a36Sopenharmony_ci		len = snd_hda_get_raw_connections(codec, nid, result, len);
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci	if (len >= 0)
14762306a36Sopenharmony_ci		len = snd_hda_override_conn_list(codec, nid, len, result);
14862306a36Sopenharmony_ci	if (result != list)
14962306a36Sopenharmony_ci		kfree(result);
15062306a36Sopenharmony_ci	return len;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci/**
15462306a36Sopenharmony_ci * snd_hda_get_conn_list - get connection list
15562306a36Sopenharmony_ci * @codec: the HDA codec
15662306a36Sopenharmony_ci * @nid: NID to parse
15762306a36Sopenharmony_ci * @listp: the pointer to store NID list
15862306a36Sopenharmony_ci *
15962306a36Sopenharmony_ci * Parses the connection list of the given widget and stores the pointer
16062306a36Sopenharmony_ci * to the list of NIDs.
16162306a36Sopenharmony_ci *
16262306a36Sopenharmony_ci * Returns the number of connections, or a negative error code.
16362306a36Sopenharmony_ci *
16462306a36Sopenharmony_ci * Note that the returned pointer isn't protected against the list
16562306a36Sopenharmony_ci * modification.  If snd_hda_override_conn_list() might be called
16662306a36Sopenharmony_ci * concurrently, protect with a mutex appropriately.
16762306a36Sopenharmony_ci */
16862306a36Sopenharmony_ciint snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
16962306a36Sopenharmony_ci			  const hda_nid_t **listp)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	bool added = false;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	for (;;) {
17462306a36Sopenharmony_ci		int err;
17562306a36Sopenharmony_ci		const struct hda_conn_list *p;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci		/* if the connection-list is already cached, read it */
17862306a36Sopenharmony_ci		p = lookup_conn_list(codec, nid);
17962306a36Sopenharmony_ci		if (p) {
18062306a36Sopenharmony_ci			if (listp)
18162306a36Sopenharmony_ci				*listp = p->conns;
18262306a36Sopenharmony_ci			return p->len;
18362306a36Sopenharmony_ci		}
18462306a36Sopenharmony_ci		if (snd_BUG_ON(added))
18562306a36Sopenharmony_ci			return -EINVAL;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci		err = read_and_add_raw_conns(codec, nid);
18862306a36Sopenharmony_ci		if (err < 0)
18962306a36Sopenharmony_ci			return err;
19062306a36Sopenharmony_ci		added = true;
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_get_conn_list);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci/**
19662306a36Sopenharmony_ci * snd_hda_get_connections - copy connection list
19762306a36Sopenharmony_ci * @codec: the HDA codec
19862306a36Sopenharmony_ci * @nid: NID to parse
19962306a36Sopenharmony_ci * @conn_list: connection list array; when NULL, checks only the size
20062306a36Sopenharmony_ci * @max_conns: max. number of connections to store
20162306a36Sopenharmony_ci *
20262306a36Sopenharmony_ci * Parses the connection list of the given widget and stores the list
20362306a36Sopenharmony_ci * of NIDs.
20462306a36Sopenharmony_ci *
20562306a36Sopenharmony_ci * Returns the number of connections, or a negative error code.
20662306a36Sopenharmony_ci */
20762306a36Sopenharmony_ciint snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
20862306a36Sopenharmony_ci			    hda_nid_t *conn_list, int max_conns)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	const hda_nid_t *list;
21162306a36Sopenharmony_ci	int len = snd_hda_get_conn_list(codec, nid, &list);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if (len > 0 && conn_list) {
21462306a36Sopenharmony_ci		if (len > max_conns) {
21562306a36Sopenharmony_ci			codec_err(codec, "Too many connections %d for NID 0x%x\n",
21662306a36Sopenharmony_ci				   len, nid);
21762306a36Sopenharmony_ci			return -EINVAL;
21862306a36Sopenharmony_ci		}
21962306a36Sopenharmony_ci		memcpy(conn_list, list, len * sizeof(hda_nid_t));
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	return len;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_get_connections);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci/**
22762306a36Sopenharmony_ci * snd_hda_override_conn_list - add/modify the connection-list to cache
22862306a36Sopenharmony_ci * @codec: the HDA codec
22962306a36Sopenharmony_ci * @nid: NID to parse
23062306a36Sopenharmony_ci * @len: number of connection list entries
23162306a36Sopenharmony_ci * @list: the list of connection entries
23262306a36Sopenharmony_ci *
23362306a36Sopenharmony_ci * Add or modify the given connection-list to the cache.  If the corresponding
23462306a36Sopenharmony_ci * cache already exists, invalidate it and append a new one.
23562306a36Sopenharmony_ci *
23662306a36Sopenharmony_ci * Returns zero or a negative error code.
23762306a36Sopenharmony_ci */
23862306a36Sopenharmony_ciint snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
23962306a36Sopenharmony_ci			       const hda_nid_t *list)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct hda_conn_list *p;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	p = lookup_conn_list(codec, nid);
24462306a36Sopenharmony_ci	if (p) {
24562306a36Sopenharmony_ci		list_del(&p->list);
24662306a36Sopenharmony_ci		kfree(p);
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	return add_conn_list(codec, nid, len, list);
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_override_conn_list);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci/**
25462306a36Sopenharmony_ci * snd_hda_get_conn_index - get the connection index of the given NID
25562306a36Sopenharmony_ci * @codec: the HDA codec
25662306a36Sopenharmony_ci * @mux: NID containing the list
25762306a36Sopenharmony_ci * @nid: NID to select
25862306a36Sopenharmony_ci * @recursive: 1 when searching NID recursively, otherwise 0
25962306a36Sopenharmony_ci *
26062306a36Sopenharmony_ci * Parses the connection list of the widget @mux and checks whether the
26162306a36Sopenharmony_ci * widget @nid is present.  If it is, return the connection index.
26262306a36Sopenharmony_ci * Otherwise it returns -1.
26362306a36Sopenharmony_ci */
26462306a36Sopenharmony_ciint snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
26562306a36Sopenharmony_ci			   hda_nid_t nid, int recursive)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	const hda_nid_t *conn;
26862306a36Sopenharmony_ci	int i, nums;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	nums = snd_hda_get_conn_list(codec, mux, &conn);
27162306a36Sopenharmony_ci	for (i = 0; i < nums; i++)
27262306a36Sopenharmony_ci		if (conn[i] == nid)
27362306a36Sopenharmony_ci			return i;
27462306a36Sopenharmony_ci	if (!recursive)
27562306a36Sopenharmony_ci		return -1;
27662306a36Sopenharmony_ci	if (recursive > 10) {
27762306a36Sopenharmony_ci		codec_dbg(codec, "too deep connection for 0x%x\n", nid);
27862306a36Sopenharmony_ci		return -1;
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci	recursive++;
28162306a36Sopenharmony_ci	for (i = 0; i < nums; i++) {
28262306a36Sopenharmony_ci		unsigned int type = get_wcaps_type(get_wcaps(codec, conn[i]));
28362306a36Sopenharmony_ci		if (type == AC_WID_PIN || type == AC_WID_AUD_OUT)
28462306a36Sopenharmony_ci			continue;
28562306a36Sopenharmony_ci		if (snd_hda_get_conn_index(codec, conn[i], nid, recursive) >= 0)
28662306a36Sopenharmony_ci			return i;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci	return -1;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_get_conn_index);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci/**
29362306a36Sopenharmony_ci * snd_hda_get_num_devices - get DEVLIST_LEN parameter of the given widget
29462306a36Sopenharmony_ci *  @codec: the HDA codec
29562306a36Sopenharmony_ci *  @nid: NID of the pin to parse
29662306a36Sopenharmony_ci *
29762306a36Sopenharmony_ci * Get the device entry number on the given widget. This is a feature of
29862306a36Sopenharmony_ci * DP MST audio. Each pin can have several device entries in it.
29962306a36Sopenharmony_ci */
30062306a36Sopenharmony_ciunsigned int snd_hda_get_num_devices(struct hda_codec *codec, hda_nid_t nid)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	unsigned int wcaps = get_wcaps(codec, nid);
30362306a36Sopenharmony_ci	unsigned int parm;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	if (!codec->dp_mst || !(wcaps & AC_WCAP_DIGITAL) ||
30662306a36Sopenharmony_ci	    get_wcaps_type(wcaps) != AC_WID_PIN)
30762306a36Sopenharmony_ci		return 0;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	parm = snd_hdac_read_parm_uncached(&codec->core, nid, AC_PAR_DEVLIST_LEN);
31062306a36Sopenharmony_ci	if (parm == -1)
31162306a36Sopenharmony_ci		parm = 0;
31262306a36Sopenharmony_ci	return parm & AC_DEV_LIST_LEN_MASK;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_get_num_devices);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci/**
31762306a36Sopenharmony_ci * snd_hda_get_devices - copy device list without cache
31862306a36Sopenharmony_ci * @codec: the HDA codec
31962306a36Sopenharmony_ci * @nid: NID of the pin to parse
32062306a36Sopenharmony_ci * @dev_list: device list array
32162306a36Sopenharmony_ci * @max_devices: max. number of devices to store
32262306a36Sopenharmony_ci *
32362306a36Sopenharmony_ci * Copy the device list. This info is dynamic and so not cached.
32462306a36Sopenharmony_ci * Currently called only from hda_proc.c, so not exported.
32562306a36Sopenharmony_ci */
32662306a36Sopenharmony_ciint snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
32762306a36Sopenharmony_ci			u8 *dev_list, int max_devices)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	unsigned int parm;
33062306a36Sopenharmony_ci	int i, dev_len, devices;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	parm = snd_hda_get_num_devices(codec, nid);
33362306a36Sopenharmony_ci	if (!parm)	/* not multi-stream capable */
33462306a36Sopenharmony_ci		return 0;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	dev_len = parm + 1;
33762306a36Sopenharmony_ci	dev_len = dev_len < max_devices ? dev_len : max_devices;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	devices = 0;
34062306a36Sopenharmony_ci	while (devices < dev_len) {
34162306a36Sopenharmony_ci		if (snd_hdac_read(&codec->core, nid,
34262306a36Sopenharmony_ci				  AC_VERB_GET_DEVICE_LIST, devices, &parm))
34362306a36Sopenharmony_ci			break; /* error */
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci		for (i = 0; i < 8; i++) {
34662306a36Sopenharmony_ci			dev_list[devices] = (u8)parm;
34762306a36Sopenharmony_ci			parm >>= 4;
34862306a36Sopenharmony_ci			devices++;
34962306a36Sopenharmony_ci			if (devices >= dev_len)
35062306a36Sopenharmony_ci				break;
35162306a36Sopenharmony_ci		}
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci	return devices;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci/**
35762306a36Sopenharmony_ci * snd_hda_get_dev_select - get device entry select on the pin
35862306a36Sopenharmony_ci * @codec: the HDA codec
35962306a36Sopenharmony_ci * @nid: NID of the pin to get device entry select
36062306a36Sopenharmony_ci *
36162306a36Sopenharmony_ci * Get the devcie entry select on the pin. Return the device entry
36262306a36Sopenharmony_ci * id selected on the pin. Return 0 means the first device entry
36362306a36Sopenharmony_ci * is selected or MST is not supported.
36462306a36Sopenharmony_ci */
36562306a36Sopenharmony_ciint snd_hda_get_dev_select(struct hda_codec *codec, hda_nid_t nid)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	/* not support dp_mst will always return 0, using first dev_entry */
36862306a36Sopenharmony_ci	if (!codec->dp_mst)
36962306a36Sopenharmony_ci		return 0;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DEVICE_SEL, 0);
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_get_dev_select);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci/**
37662306a36Sopenharmony_ci * snd_hda_set_dev_select - set device entry select on the pin
37762306a36Sopenharmony_ci * @codec: the HDA codec
37862306a36Sopenharmony_ci * @nid: NID of the pin to set device entry select
37962306a36Sopenharmony_ci * @dev_id: device entry id to be set
38062306a36Sopenharmony_ci *
38162306a36Sopenharmony_ci * Set the device entry select on the pin nid.
38262306a36Sopenharmony_ci */
38362306a36Sopenharmony_ciint snd_hda_set_dev_select(struct hda_codec *codec, hda_nid_t nid, int dev_id)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	int ret, num_devices;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	/* not support dp_mst will always return 0, using first dev_entry */
38862306a36Sopenharmony_ci	if (!codec->dp_mst)
38962306a36Sopenharmony_ci		return 0;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/* AC_PAR_DEVLIST_LEN is 0 based. */
39262306a36Sopenharmony_ci	num_devices = snd_hda_get_num_devices(codec, nid) + 1;
39362306a36Sopenharmony_ci	/* If Device List Length is 0 (num_device = 1),
39462306a36Sopenharmony_ci	 * the pin is not multi stream capable.
39562306a36Sopenharmony_ci	 * Do nothing in this case.
39662306a36Sopenharmony_ci	 */
39762306a36Sopenharmony_ci	if (num_devices == 1)
39862306a36Sopenharmony_ci		return 0;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	/* Behavior of setting index being equal to or greater than
40162306a36Sopenharmony_ci	 * Device List Length is not predictable
40262306a36Sopenharmony_ci	 */
40362306a36Sopenharmony_ci	if (num_devices <= dev_id)
40462306a36Sopenharmony_ci		return -EINVAL;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	ret = snd_hda_codec_write(codec, nid, 0,
40762306a36Sopenharmony_ci			AC_VERB_SET_DEVICE_SEL, dev_id);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	return ret;
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_set_dev_select);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci/*
41462306a36Sopenharmony_ci * read widget caps for each widget and store in cache
41562306a36Sopenharmony_ci */
41662306a36Sopenharmony_cistatic int read_widget_caps(struct hda_codec *codec, hda_nid_t fg_node)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	int i;
41962306a36Sopenharmony_ci	hda_nid_t nid;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	codec->wcaps = kmalloc_array(codec->core.num_nodes, 4, GFP_KERNEL);
42262306a36Sopenharmony_ci	if (!codec->wcaps)
42362306a36Sopenharmony_ci		return -ENOMEM;
42462306a36Sopenharmony_ci	nid = codec->core.start_nid;
42562306a36Sopenharmony_ci	for (i = 0; i < codec->core.num_nodes; i++, nid++)
42662306a36Sopenharmony_ci		codec->wcaps[i] = snd_hdac_read_parm_uncached(&codec->core,
42762306a36Sopenharmony_ci					nid, AC_PAR_AUDIO_WIDGET_CAP);
42862306a36Sopenharmony_ci	return 0;
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci/* read all pin default configurations and save codec->init_pins */
43262306a36Sopenharmony_cistatic int read_pin_defaults(struct hda_codec *codec)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	hda_nid_t nid;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	for_each_hda_codec_node(nid, codec) {
43762306a36Sopenharmony_ci		struct hda_pincfg *pin;
43862306a36Sopenharmony_ci		unsigned int wcaps = get_wcaps(codec, nid);
43962306a36Sopenharmony_ci		unsigned int wid_type = get_wcaps_type(wcaps);
44062306a36Sopenharmony_ci		if (wid_type != AC_WID_PIN)
44162306a36Sopenharmony_ci			continue;
44262306a36Sopenharmony_ci		pin = snd_array_new(&codec->init_pins);
44362306a36Sopenharmony_ci		if (!pin)
44462306a36Sopenharmony_ci			return -ENOMEM;
44562306a36Sopenharmony_ci		pin->nid = nid;
44662306a36Sopenharmony_ci		pin->cfg = snd_hda_codec_read(codec, nid, 0,
44762306a36Sopenharmony_ci					      AC_VERB_GET_CONFIG_DEFAULT, 0);
44862306a36Sopenharmony_ci		/*
44962306a36Sopenharmony_ci		 * all device entries are the same widget control so far
45062306a36Sopenharmony_ci		 * fixme: if any codec is different, need fix here
45162306a36Sopenharmony_ci		 */
45262306a36Sopenharmony_ci		pin->ctrl = snd_hda_codec_read(codec, nid, 0,
45362306a36Sopenharmony_ci					       AC_VERB_GET_PIN_WIDGET_CONTROL,
45462306a36Sopenharmony_ci					       0);
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci	return 0;
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci/* look up the given pin config list and return the item matching with NID */
46062306a36Sopenharmony_cistatic struct hda_pincfg *look_up_pincfg(struct hda_codec *codec,
46162306a36Sopenharmony_ci					 struct snd_array *array,
46262306a36Sopenharmony_ci					 hda_nid_t nid)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	struct hda_pincfg *pin;
46562306a36Sopenharmony_ci	int i;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	snd_array_for_each(array, i, pin) {
46862306a36Sopenharmony_ci		if (pin->nid == nid)
46962306a36Sopenharmony_ci			return pin;
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci	return NULL;
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci/* set the current pin config value for the given NID.
47562306a36Sopenharmony_ci * the value is cached, and read via snd_hda_codec_get_pincfg()
47662306a36Sopenharmony_ci */
47762306a36Sopenharmony_ciint snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
47862306a36Sopenharmony_ci		       hda_nid_t nid, unsigned int cfg)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	struct hda_pincfg *pin;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	/* the check below may be invalid when pins are added by a fixup
48362306a36Sopenharmony_ci	 * dynamically (e.g. via snd_hda_codec_update_widgets()), so disabled
48462306a36Sopenharmony_ci	 * for now
48562306a36Sopenharmony_ci	 */
48662306a36Sopenharmony_ci	/*
48762306a36Sopenharmony_ci	if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
48862306a36Sopenharmony_ci		return -EINVAL;
48962306a36Sopenharmony_ci	*/
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	pin = look_up_pincfg(codec, list, nid);
49262306a36Sopenharmony_ci	if (!pin) {
49362306a36Sopenharmony_ci		pin = snd_array_new(list);
49462306a36Sopenharmony_ci		if (!pin)
49562306a36Sopenharmony_ci			return -ENOMEM;
49662306a36Sopenharmony_ci		pin->nid = nid;
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci	pin->cfg = cfg;
49962306a36Sopenharmony_ci	return 0;
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci/**
50362306a36Sopenharmony_ci * snd_hda_codec_set_pincfg - Override a pin default configuration
50462306a36Sopenharmony_ci * @codec: the HDA codec
50562306a36Sopenharmony_ci * @nid: NID to set the pin config
50662306a36Sopenharmony_ci * @cfg: the pin default config value
50762306a36Sopenharmony_ci *
50862306a36Sopenharmony_ci * Override a pin default configuration value in the cache.
50962306a36Sopenharmony_ci * This value can be read by snd_hda_codec_get_pincfg() in a higher
51062306a36Sopenharmony_ci * priority than the real hardware value.
51162306a36Sopenharmony_ci */
51262306a36Sopenharmony_ciint snd_hda_codec_set_pincfg(struct hda_codec *codec,
51362306a36Sopenharmony_ci			     hda_nid_t nid, unsigned int cfg)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	return snd_hda_add_pincfg(codec, &codec->driver_pins, nid, cfg);
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_set_pincfg);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci/**
52062306a36Sopenharmony_ci * snd_hda_codec_get_pincfg - Obtain a pin-default configuration
52162306a36Sopenharmony_ci * @codec: the HDA codec
52262306a36Sopenharmony_ci * @nid: NID to get the pin config
52362306a36Sopenharmony_ci *
52462306a36Sopenharmony_ci * Get the current pin config value of the given pin NID.
52562306a36Sopenharmony_ci * If the pincfg value is cached or overridden via sysfs or driver,
52662306a36Sopenharmony_ci * returns the cached value.
52762306a36Sopenharmony_ci */
52862306a36Sopenharmony_ciunsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	struct hda_pincfg *pin;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci#ifdef CONFIG_SND_HDA_RECONFIG
53362306a36Sopenharmony_ci	{
53462306a36Sopenharmony_ci		unsigned int cfg = 0;
53562306a36Sopenharmony_ci		mutex_lock(&codec->user_mutex);
53662306a36Sopenharmony_ci		pin = look_up_pincfg(codec, &codec->user_pins, nid);
53762306a36Sopenharmony_ci		if (pin)
53862306a36Sopenharmony_ci			cfg = pin->cfg;
53962306a36Sopenharmony_ci		mutex_unlock(&codec->user_mutex);
54062306a36Sopenharmony_ci		if (cfg)
54162306a36Sopenharmony_ci			return cfg;
54262306a36Sopenharmony_ci	}
54362306a36Sopenharmony_ci#endif
54462306a36Sopenharmony_ci	pin = look_up_pincfg(codec, &codec->driver_pins, nid);
54562306a36Sopenharmony_ci	if (pin)
54662306a36Sopenharmony_ci		return pin->cfg;
54762306a36Sopenharmony_ci	pin = look_up_pincfg(codec, &codec->init_pins, nid);
54862306a36Sopenharmony_ci	if (pin)
54962306a36Sopenharmony_ci		return pin->cfg;
55062306a36Sopenharmony_ci	return 0;
55162306a36Sopenharmony_ci}
55262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_get_pincfg);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci/**
55562306a36Sopenharmony_ci * snd_hda_codec_set_pin_target - remember the current pinctl target value
55662306a36Sopenharmony_ci * @codec: the HDA codec
55762306a36Sopenharmony_ci * @nid: pin NID
55862306a36Sopenharmony_ci * @val: assigned pinctl value
55962306a36Sopenharmony_ci *
56062306a36Sopenharmony_ci * This function stores the given value to a pinctl target value in the
56162306a36Sopenharmony_ci * pincfg table.  This isn't always as same as the actually written value
56262306a36Sopenharmony_ci * but can be referred at any time via snd_hda_codec_get_pin_target().
56362306a36Sopenharmony_ci */
56462306a36Sopenharmony_ciint snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid,
56562306a36Sopenharmony_ci				 unsigned int val)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	struct hda_pincfg *pin;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	pin = look_up_pincfg(codec, &codec->init_pins, nid);
57062306a36Sopenharmony_ci	if (!pin)
57162306a36Sopenharmony_ci		return -EINVAL;
57262306a36Sopenharmony_ci	pin->target = val;
57362306a36Sopenharmony_ci	return 0;
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_set_pin_target);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci/**
57862306a36Sopenharmony_ci * snd_hda_codec_get_pin_target - return the current pinctl target value
57962306a36Sopenharmony_ci * @codec: the HDA codec
58062306a36Sopenharmony_ci * @nid: pin NID
58162306a36Sopenharmony_ci */
58262306a36Sopenharmony_ciint snd_hda_codec_get_pin_target(struct hda_codec *codec, hda_nid_t nid)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	struct hda_pincfg *pin;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	pin = look_up_pincfg(codec, &codec->init_pins, nid);
58762306a36Sopenharmony_ci	if (!pin)
58862306a36Sopenharmony_ci		return 0;
58962306a36Sopenharmony_ci	return pin->target;
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_get_pin_target);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci/**
59462306a36Sopenharmony_ci * snd_hda_shutup_pins - Shut up all pins
59562306a36Sopenharmony_ci * @codec: the HDA codec
59662306a36Sopenharmony_ci *
59762306a36Sopenharmony_ci * Clear all pin controls to shup up before suspend for avoiding click noise.
59862306a36Sopenharmony_ci * The controls aren't cached so that they can be resumed properly.
59962306a36Sopenharmony_ci */
60062306a36Sopenharmony_civoid snd_hda_shutup_pins(struct hda_codec *codec)
60162306a36Sopenharmony_ci{
60262306a36Sopenharmony_ci	const struct hda_pincfg *pin;
60362306a36Sopenharmony_ci	int i;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	/* don't shut up pins when unloading the driver; otherwise it breaks
60662306a36Sopenharmony_ci	 * the default pin setup at the next load of the driver
60762306a36Sopenharmony_ci	 */
60862306a36Sopenharmony_ci	if (codec->bus->shutdown)
60962306a36Sopenharmony_ci		return;
61062306a36Sopenharmony_ci	snd_array_for_each(&codec->init_pins, i, pin) {
61162306a36Sopenharmony_ci		/* use read here for syncing after issuing each verb */
61262306a36Sopenharmony_ci		snd_hda_codec_read(codec, pin->nid, 0,
61362306a36Sopenharmony_ci				   AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
61462306a36Sopenharmony_ci	}
61562306a36Sopenharmony_ci	codec->pins_shutup = 1;
61662306a36Sopenharmony_ci}
61762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_shutup_pins);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci#ifdef CONFIG_PM
62062306a36Sopenharmony_ci/* Restore the pin controls cleared previously via snd_hda_shutup_pins() */
62162306a36Sopenharmony_cistatic void restore_shutup_pins(struct hda_codec *codec)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	const struct hda_pincfg *pin;
62462306a36Sopenharmony_ci	int i;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	if (!codec->pins_shutup)
62762306a36Sopenharmony_ci		return;
62862306a36Sopenharmony_ci	if (codec->bus->shutdown)
62962306a36Sopenharmony_ci		return;
63062306a36Sopenharmony_ci	snd_array_for_each(&codec->init_pins, i, pin) {
63162306a36Sopenharmony_ci		snd_hda_codec_write(codec, pin->nid, 0,
63262306a36Sopenharmony_ci				    AC_VERB_SET_PIN_WIDGET_CONTROL,
63362306a36Sopenharmony_ci				    pin->ctrl);
63462306a36Sopenharmony_ci	}
63562306a36Sopenharmony_ci	codec->pins_shutup = 0;
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci#endif
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_cistatic void hda_jackpoll_work(struct work_struct *work)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	struct hda_codec *codec =
64262306a36Sopenharmony_ci		container_of(work, struct hda_codec, jackpoll_work.work);
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	/* for non-polling trigger: we need nothing if already powered on */
64562306a36Sopenharmony_ci	if (!codec->jackpoll_interval && snd_hdac_is_power_on(&codec->core))
64662306a36Sopenharmony_ci		return;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	/* the power-up/down sequence triggers the runtime resume */
64962306a36Sopenharmony_ci	snd_hda_power_up_pm(codec);
65062306a36Sopenharmony_ci	/* update jacks manually if polling is required, too */
65162306a36Sopenharmony_ci	if (codec->jackpoll_interval) {
65262306a36Sopenharmony_ci		snd_hda_jack_set_dirty_all(codec);
65362306a36Sopenharmony_ci		snd_hda_jack_poll_all(codec);
65462306a36Sopenharmony_ci	}
65562306a36Sopenharmony_ci	snd_hda_power_down_pm(codec);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	if (!codec->jackpoll_interval)
65862306a36Sopenharmony_ci		return;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	schedule_delayed_work(&codec->jackpoll_work,
66162306a36Sopenharmony_ci			      codec->jackpoll_interval);
66262306a36Sopenharmony_ci}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci/* release all pincfg lists */
66562306a36Sopenharmony_cistatic void free_init_pincfgs(struct hda_codec *codec)
66662306a36Sopenharmony_ci{
66762306a36Sopenharmony_ci	snd_array_free(&codec->driver_pins);
66862306a36Sopenharmony_ci#ifdef CONFIG_SND_HDA_RECONFIG
66962306a36Sopenharmony_ci	snd_array_free(&codec->user_pins);
67062306a36Sopenharmony_ci#endif
67162306a36Sopenharmony_ci	snd_array_free(&codec->init_pins);
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci/*
67562306a36Sopenharmony_ci * audio-converter setup caches
67662306a36Sopenharmony_ci */
67762306a36Sopenharmony_cistruct hda_cvt_setup {
67862306a36Sopenharmony_ci	hda_nid_t nid;
67962306a36Sopenharmony_ci	u8 stream_tag;
68062306a36Sopenharmony_ci	u8 channel_id;
68162306a36Sopenharmony_ci	u16 format_id;
68262306a36Sopenharmony_ci	unsigned char active;	/* cvt is currently used */
68362306a36Sopenharmony_ci	unsigned char dirty;	/* setups should be cleared */
68462306a36Sopenharmony_ci};
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci/* get or create a cache entry for the given audio converter NID */
68762306a36Sopenharmony_cistatic struct hda_cvt_setup *
68862306a36Sopenharmony_ciget_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid)
68962306a36Sopenharmony_ci{
69062306a36Sopenharmony_ci	struct hda_cvt_setup *p;
69162306a36Sopenharmony_ci	int i;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	snd_array_for_each(&codec->cvt_setups, i, p) {
69462306a36Sopenharmony_ci		if (p->nid == nid)
69562306a36Sopenharmony_ci			return p;
69662306a36Sopenharmony_ci	}
69762306a36Sopenharmony_ci	p = snd_array_new(&codec->cvt_setups);
69862306a36Sopenharmony_ci	if (p)
69962306a36Sopenharmony_ci		p->nid = nid;
70062306a36Sopenharmony_ci	return p;
70162306a36Sopenharmony_ci}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci/*
70462306a36Sopenharmony_ci * PCM device
70562306a36Sopenharmony_ci */
70662306a36Sopenharmony_civoid snd_hda_codec_pcm_put(struct hda_pcm *pcm)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	if (refcount_dec_and_test(&pcm->codec->pcm_ref))
70962306a36Sopenharmony_ci		wake_up(&pcm->codec->remove_sleep);
71062306a36Sopenharmony_ci}
71162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_pcm_put);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_cistruct hda_pcm *snd_hda_codec_pcm_new(struct hda_codec *codec,
71462306a36Sopenharmony_ci				      const char *fmt, ...)
71562306a36Sopenharmony_ci{
71662306a36Sopenharmony_ci	struct hda_pcm *pcm;
71762306a36Sopenharmony_ci	va_list args;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
72062306a36Sopenharmony_ci	if (!pcm)
72162306a36Sopenharmony_ci		return NULL;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	pcm->codec = codec;
72462306a36Sopenharmony_ci	va_start(args, fmt);
72562306a36Sopenharmony_ci	pcm->name = kvasprintf(GFP_KERNEL, fmt, args);
72662306a36Sopenharmony_ci	va_end(args);
72762306a36Sopenharmony_ci	if (!pcm->name) {
72862306a36Sopenharmony_ci		kfree(pcm);
72962306a36Sopenharmony_ci		return NULL;
73062306a36Sopenharmony_ci	}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	list_add_tail(&pcm->list, &codec->pcm_list_head);
73362306a36Sopenharmony_ci	refcount_inc(&codec->pcm_ref);
73462306a36Sopenharmony_ci	return pcm;
73562306a36Sopenharmony_ci}
73662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_pcm_new);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci/*
73962306a36Sopenharmony_ci * codec destructor
74062306a36Sopenharmony_ci */
74162306a36Sopenharmony_civoid snd_hda_codec_disconnect_pcms(struct hda_codec *codec)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	struct hda_pcm *pcm;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	list_for_each_entry(pcm, &codec->pcm_list_head, list) {
74662306a36Sopenharmony_ci		if (pcm->disconnected)
74762306a36Sopenharmony_ci			continue;
74862306a36Sopenharmony_ci		if (pcm->pcm)
74962306a36Sopenharmony_ci			snd_device_disconnect(codec->card, pcm->pcm);
75062306a36Sopenharmony_ci		snd_hda_codec_pcm_put(pcm);
75162306a36Sopenharmony_ci		pcm->disconnected = 1;
75262306a36Sopenharmony_ci	}
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic void codec_release_pcms(struct hda_codec *codec)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	struct hda_pcm *pcm, *n;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	list_for_each_entry_safe(pcm, n, &codec->pcm_list_head, list) {
76062306a36Sopenharmony_ci		list_del(&pcm->list);
76162306a36Sopenharmony_ci		if (pcm->pcm)
76262306a36Sopenharmony_ci			snd_device_free(pcm->codec->card, pcm->pcm);
76362306a36Sopenharmony_ci		clear_bit(pcm->device, pcm->codec->bus->pcm_dev_bits);
76462306a36Sopenharmony_ci		kfree(pcm->name);
76562306a36Sopenharmony_ci		kfree(pcm);
76662306a36Sopenharmony_ci	}
76762306a36Sopenharmony_ci}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci/**
77062306a36Sopenharmony_ci * snd_hda_codec_cleanup_for_unbind - Prepare codec for removal
77162306a36Sopenharmony_ci * @codec: codec device to cleanup
77262306a36Sopenharmony_ci */
77362306a36Sopenharmony_civoid snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	if (codec->core.registered) {
77662306a36Sopenharmony_ci		/* pm_runtime_put() is called in snd_hdac_device_exit() */
77762306a36Sopenharmony_ci		pm_runtime_get_noresume(hda_codec_dev(codec));
77862306a36Sopenharmony_ci		pm_runtime_disable(hda_codec_dev(codec));
77962306a36Sopenharmony_ci		codec->core.registered = 0;
78062306a36Sopenharmony_ci	}
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	snd_hda_codec_disconnect_pcms(codec);
78362306a36Sopenharmony_ci	cancel_delayed_work_sync(&codec->jackpoll_work);
78462306a36Sopenharmony_ci	if (!codec->in_freeing)
78562306a36Sopenharmony_ci		snd_hda_ctls_clear(codec);
78662306a36Sopenharmony_ci	codec_release_pcms(codec);
78762306a36Sopenharmony_ci	snd_hda_detach_beep_device(codec);
78862306a36Sopenharmony_ci	memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
78962306a36Sopenharmony_ci	snd_hda_jack_tbl_clear(codec);
79062306a36Sopenharmony_ci	codec->proc_widget_hook = NULL;
79162306a36Sopenharmony_ci	codec->spec = NULL;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	/* free only driver_pins so that init_pins + user_pins are restored */
79462306a36Sopenharmony_ci	snd_array_free(&codec->driver_pins);
79562306a36Sopenharmony_ci	snd_array_free(&codec->cvt_setups);
79662306a36Sopenharmony_ci	snd_array_free(&codec->spdif_out);
79762306a36Sopenharmony_ci	snd_array_free(&codec->verbs);
79862306a36Sopenharmony_ci	codec->follower_dig_outs = NULL;
79962306a36Sopenharmony_ci	codec->spdif_status_reset = 0;
80062306a36Sopenharmony_ci	snd_array_free(&codec->mixers);
80162306a36Sopenharmony_ci	snd_array_free(&codec->nids);
80262306a36Sopenharmony_ci	remove_conn_list(codec);
80362306a36Sopenharmony_ci	snd_hdac_regmap_exit(&codec->core);
80462306a36Sopenharmony_ci	codec->configured = 0;
80562306a36Sopenharmony_ci	refcount_set(&codec->pcm_ref, 1); /* reset refcount */
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_cleanup_for_unbind);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_cistatic unsigned int hda_set_power_state(struct hda_codec *codec,
81062306a36Sopenharmony_ci				unsigned int power_state);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci/* enable/disable display power per codec */
81362306a36Sopenharmony_civoid snd_hda_codec_display_power(struct hda_codec *codec, bool enable)
81462306a36Sopenharmony_ci{
81562306a36Sopenharmony_ci	if (codec->display_power_control)
81662306a36Sopenharmony_ci		snd_hdac_display_power(&codec->bus->core, codec->addr, enable);
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci/**
82062306a36Sopenharmony_ci * snd_hda_codec_register - Finalize codec initialization
82162306a36Sopenharmony_ci * @codec: codec device to register
82262306a36Sopenharmony_ci *
82362306a36Sopenharmony_ci * Also called from hda_bind.c
82462306a36Sopenharmony_ci */
82562306a36Sopenharmony_civoid snd_hda_codec_register(struct hda_codec *codec)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	if (codec->core.registered)
82862306a36Sopenharmony_ci		return;
82962306a36Sopenharmony_ci	if (device_is_registered(hda_codec_dev(codec))) {
83062306a36Sopenharmony_ci		snd_hda_codec_display_power(codec, true);
83162306a36Sopenharmony_ci		pm_runtime_enable(hda_codec_dev(codec));
83262306a36Sopenharmony_ci		/* it was powered up in snd_hda_codec_new(), now all done */
83362306a36Sopenharmony_ci		snd_hda_power_down(codec);
83462306a36Sopenharmony_ci		codec->core.registered = 1;
83562306a36Sopenharmony_ci	}
83662306a36Sopenharmony_ci}
83762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_register);
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_cistatic int snd_hda_codec_dev_register(struct snd_device *device)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	snd_hda_codec_register(device->device_data);
84262306a36Sopenharmony_ci	return 0;
84362306a36Sopenharmony_ci}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci/**
84662306a36Sopenharmony_ci * snd_hda_codec_unregister - Unregister specified codec device
84762306a36Sopenharmony_ci * @codec: codec device to unregister
84862306a36Sopenharmony_ci */
84962306a36Sopenharmony_civoid snd_hda_codec_unregister(struct hda_codec *codec)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	codec->in_freeing = 1;
85262306a36Sopenharmony_ci	/*
85362306a36Sopenharmony_ci	 * snd_hda_codec_device_new() is used by legacy HDA and ASoC driver.
85462306a36Sopenharmony_ci	 * We can't unregister ASoC device since it will be unregistered in
85562306a36Sopenharmony_ci	 * snd_hdac_ext_bus_device_remove().
85662306a36Sopenharmony_ci	 */
85762306a36Sopenharmony_ci	if (codec->core.type == HDA_DEV_LEGACY)
85862306a36Sopenharmony_ci		snd_hdac_device_unregister(&codec->core);
85962306a36Sopenharmony_ci	snd_hda_codec_display_power(codec, false);
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	/*
86262306a36Sopenharmony_ci	 * In the case of ASoC HD-audio bus, the device refcount is released in
86362306a36Sopenharmony_ci	 * snd_hdac_ext_bus_device_remove() explicitly.
86462306a36Sopenharmony_ci	 */
86562306a36Sopenharmony_ci	if (codec->core.type == HDA_DEV_LEGACY)
86662306a36Sopenharmony_ci		put_device(hda_codec_dev(codec));
86762306a36Sopenharmony_ci}
86862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_unregister);
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_cistatic int snd_hda_codec_dev_free(struct snd_device *device)
87162306a36Sopenharmony_ci{
87262306a36Sopenharmony_ci	snd_hda_codec_unregister(device->device_data);
87362306a36Sopenharmony_ci	return 0;
87462306a36Sopenharmony_ci}
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_cistatic void snd_hda_codec_dev_release(struct device *dev)
87762306a36Sopenharmony_ci{
87862306a36Sopenharmony_ci	struct hda_codec *codec = dev_to_hda_codec(dev);
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	free_init_pincfgs(codec);
88162306a36Sopenharmony_ci	snd_hdac_device_exit(&codec->core);
88262306a36Sopenharmony_ci	snd_hda_sysfs_clear(codec);
88362306a36Sopenharmony_ci	kfree(codec->modelname);
88462306a36Sopenharmony_ci	kfree(codec->wcaps);
88562306a36Sopenharmony_ci	kfree(codec);
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci#define DEV_NAME_LEN 31
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci/**
89162306a36Sopenharmony_ci * snd_hda_codec_device_init - allocate HDA codec device
89262306a36Sopenharmony_ci * @bus: codec's parent bus
89362306a36Sopenharmony_ci * @codec_addr: the codec address on the parent bus
89462306a36Sopenharmony_ci * @fmt: format string for the device's name
89562306a36Sopenharmony_ci *
89662306a36Sopenharmony_ci * Returns newly allocated codec device or ERR_PTR() on failure.
89762306a36Sopenharmony_ci */
89862306a36Sopenharmony_cistruct hda_codec *
89962306a36Sopenharmony_cisnd_hda_codec_device_init(struct hda_bus *bus, unsigned int codec_addr,
90062306a36Sopenharmony_ci			  const char *fmt, ...)
90162306a36Sopenharmony_ci{
90262306a36Sopenharmony_ci	va_list vargs;
90362306a36Sopenharmony_ci	char name[DEV_NAME_LEN];
90462306a36Sopenharmony_ci	struct hda_codec *codec;
90562306a36Sopenharmony_ci	int err;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	if (snd_BUG_ON(!bus))
90862306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
90962306a36Sopenharmony_ci	if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS))
91062306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	codec = kzalloc(sizeof(*codec), GFP_KERNEL);
91362306a36Sopenharmony_ci	if (!codec)
91462306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	va_start(vargs, fmt);
91762306a36Sopenharmony_ci	vsprintf(name, fmt, vargs);
91862306a36Sopenharmony_ci	va_end(vargs);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	err = snd_hdac_device_init(&codec->core, &bus->core, name, codec_addr);
92162306a36Sopenharmony_ci	if (err < 0) {
92262306a36Sopenharmony_ci		kfree(codec);
92362306a36Sopenharmony_ci		return ERR_PTR(err);
92462306a36Sopenharmony_ci	}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	codec->bus = bus;
92762306a36Sopenharmony_ci	codec->depop_delay = -1;
92862306a36Sopenharmony_ci	codec->fixup_id = HDA_FIXUP_ID_NOT_SET;
92962306a36Sopenharmony_ci	codec->core.dev.release = snd_hda_codec_dev_release;
93062306a36Sopenharmony_ci	codec->core.type = HDA_DEV_LEGACY;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	mutex_init(&codec->spdif_mutex);
93362306a36Sopenharmony_ci	mutex_init(&codec->control_mutex);
93462306a36Sopenharmony_ci	snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32);
93562306a36Sopenharmony_ci	snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32);
93662306a36Sopenharmony_ci	snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
93762306a36Sopenharmony_ci	snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
93862306a36Sopenharmony_ci	snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
93962306a36Sopenharmony_ci	snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16);
94062306a36Sopenharmony_ci	snd_array_init(&codec->jacktbl, sizeof(struct hda_jack_tbl), 16);
94162306a36Sopenharmony_ci	snd_array_init(&codec->verbs, sizeof(struct hda_verb *), 8);
94262306a36Sopenharmony_ci	INIT_LIST_HEAD(&codec->conn_list);
94362306a36Sopenharmony_ci	INIT_LIST_HEAD(&codec->pcm_list_head);
94462306a36Sopenharmony_ci	INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work);
94562306a36Sopenharmony_ci	refcount_set(&codec->pcm_ref, 1);
94662306a36Sopenharmony_ci	init_waitqueue_head(&codec->remove_sleep);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	return codec;
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_device_init);
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci/**
95362306a36Sopenharmony_ci * snd_hda_codec_new - create a HDA codec
95462306a36Sopenharmony_ci * @bus: the bus to assign
95562306a36Sopenharmony_ci * @card: card for this codec
95662306a36Sopenharmony_ci * @codec_addr: the codec address
95762306a36Sopenharmony_ci * @codecp: the pointer to store the generated codec
95862306a36Sopenharmony_ci *
95962306a36Sopenharmony_ci * Returns 0 if successful, or a negative error code.
96062306a36Sopenharmony_ci */
96162306a36Sopenharmony_ciint snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
96262306a36Sopenharmony_ci		      unsigned int codec_addr, struct hda_codec **codecp)
96362306a36Sopenharmony_ci{
96462306a36Sopenharmony_ci	struct hda_codec *codec;
96562306a36Sopenharmony_ci	int ret;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	codec = snd_hda_codec_device_init(bus, codec_addr, "hdaudioC%dD%d",
96862306a36Sopenharmony_ci					  card->number, codec_addr);
96962306a36Sopenharmony_ci	if (IS_ERR(codec))
97062306a36Sopenharmony_ci		return PTR_ERR(codec);
97162306a36Sopenharmony_ci	*codecp = codec;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	ret = snd_hda_codec_device_new(bus, card, codec_addr, *codecp, true);
97462306a36Sopenharmony_ci	if (ret)
97562306a36Sopenharmony_ci		put_device(hda_codec_dev(*codecp));
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	return ret;
97862306a36Sopenharmony_ci}
97962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_new);
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ciint snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card,
98262306a36Sopenharmony_ci			unsigned int codec_addr, struct hda_codec *codec,
98362306a36Sopenharmony_ci			bool snddev_managed)
98462306a36Sopenharmony_ci{
98562306a36Sopenharmony_ci	char component[31];
98662306a36Sopenharmony_ci	hda_nid_t fg;
98762306a36Sopenharmony_ci	int err;
98862306a36Sopenharmony_ci	static const struct snd_device_ops dev_ops = {
98962306a36Sopenharmony_ci		.dev_register = snd_hda_codec_dev_register,
99062306a36Sopenharmony_ci		.dev_free = snd_hda_codec_dev_free,
99162306a36Sopenharmony_ci	};
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	dev_dbg(card->dev, "%s: entry\n", __func__);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	if (snd_BUG_ON(!bus))
99662306a36Sopenharmony_ci		return -EINVAL;
99762306a36Sopenharmony_ci	if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS))
99862306a36Sopenharmony_ci		return -EINVAL;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	codec->core.exec_verb = codec_exec_verb;
100162306a36Sopenharmony_ci	codec->card = card;
100262306a36Sopenharmony_ci	codec->addr = codec_addr;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci#ifdef CONFIG_PM
100562306a36Sopenharmony_ci	codec->power_jiffies = jiffies;
100662306a36Sopenharmony_ci#endif
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	snd_hda_sysfs_init(codec);
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	if (codec->bus->modelname) {
101162306a36Sopenharmony_ci		codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
101262306a36Sopenharmony_ci		if (!codec->modelname)
101362306a36Sopenharmony_ci			return -ENOMEM;
101462306a36Sopenharmony_ci	}
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	fg = codec->core.afg ? codec->core.afg : codec->core.mfg;
101762306a36Sopenharmony_ci	err = read_widget_caps(codec, fg);
101862306a36Sopenharmony_ci	if (err < 0)
101962306a36Sopenharmony_ci		return err;
102062306a36Sopenharmony_ci	err = read_pin_defaults(codec);
102162306a36Sopenharmony_ci	if (err < 0)
102262306a36Sopenharmony_ci		return err;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	/* power-up all before initialization */
102562306a36Sopenharmony_ci	hda_set_power_state(codec, AC_PWRST_D0);
102662306a36Sopenharmony_ci	codec->core.dev.power.power_state = PMSG_ON;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	snd_hda_codec_proc_new(codec);
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	snd_hda_create_hwdep(codec);
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	sprintf(component, "HDA:%08x,%08x,%08x", codec->core.vendor_id,
103362306a36Sopenharmony_ci		codec->core.subsystem_id, codec->core.revision_id);
103462306a36Sopenharmony_ci	snd_component_add(card, component);
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	if (snddev_managed) {
103762306a36Sopenharmony_ci		/* ASoC features component management instead */
103862306a36Sopenharmony_ci		err = snd_device_new(card, SNDRV_DEV_CODEC, codec, &dev_ops);
103962306a36Sopenharmony_ci		if (err < 0)
104062306a36Sopenharmony_ci			return err;
104162306a36Sopenharmony_ci	}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci#ifdef CONFIG_PM
104462306a36Sopenharmony_ci	/* PM runtime needs to be enabled later after binding codec */
104562306a36Sopenharmony_ci	if (codec->core.dev.power.runtime_auto)
104662306a36Sopenharmony_ci		pm_runtime_forbid(&codec->core.dev);
104762306a36Sopenharmony_ci	else
104862306a36Sopenharmony_ci		/* Keep the usage_count consistent across subsequent probing */
104962306a36Sopenharmony_ci		pm_runtime_get_noresume(&codec->core.dev);
105062306a36Sopenharmony_ci#endif
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	return 0;
105362306a36Sopenharmony_ci}
105462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_device_new);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci/**
105762306a36Sopenharmony_ci * snd_hda_codec_update_widgets - Refresh widget caps and pin defaults
105862306a36Sopenharmony_ci * @codec: the HDA codec
105962306a36Sopenharmony_ci *
106062306a36Sopenharmony_ci * Forcibly refresh the all widget caps and the init pin configurations of
106162306a36Sopenharmony_ci * the given codec.
106262306a36Sopenharmony_ci */
106362306a36Sopenharmony_ciint snd_hda_codec_update_widgets(struct hda_codec *codec)
106462306a36Sopenharmony_ci{
106562306a36Sopenharmony_ci	hda_nid_t fg;
106662306a36Sopenharmony_ci	int err;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	err = snd_hdac_refresh_widgets(&codec->core);
106962306a36Sopenharmony_ci	if (err < 0)
107062306a36Sopenharmony_ci		return err;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	/* Assume the function group node does not change,
107362306a36Sopenharmony_ci	 * only the widget nodes may change.
107462306a36Sopenharmony_ci	 */
107562306a36Sopenharmony_ci	kfree(codec->wcaps);
107662306a36Sopenharmony_ci	fg = codec->core.afg ? codec->core.afg : codec->core.mfg;
107762306a36Sopenharmony_ci	err = read_widget_caps(codec, fg);
107862306a36Sopenharmony_ci	if (err < 0)
107962306a36Sopenharmony_ci		return err;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	snd_array_free(&codec->init_pins);
108262306a36Sopenharmony_ci	err = read_pin_defaults(codec);
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	return err;
108562306a36Sopenharmony_ci}
108662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_update_widgets);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci/* update the stream-id if changed */
108962306a36Sopenharmony_cistatic void update_pcm_stream_id(struct hda_codec *codec,
109062306a36Sopenharmony_ci				 struct hda_cvt_setup *p, hda_nid_t nid,
109162306a36Sopenharmony_ci				 u32 stream_tag, int channel_id)
109262306a36Sopenharmony_ci{
109362306a36Sopenharmony_ci	unsigned int oldval, newval;
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	if (p->stream_tag != stream_tag || p->channel_id != channel_id) {
109662306a36Sopenharmony_ci		oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
109762306a36Sopenharmony_ci		newval = (stream_tag << 4) | channel_id;
109862306a36Sopenharmony_ci		if (oldval != newval)
109962306a36Sopenharmony_ci			snd_hda_codec_write(codec, nid, 0,
110062306a36Sopenharmony_ci					    AC_VERB_SET_CHANNEL_STREAMID,
110162306a36Sopenharmony_ci					    newval);
110262306a36Sopenharmony_ci		p->stream_tag = stream_tag;
110362306a36Sopenharmony_ci		p->channel_id = channel_id;
110462306a36Sopenharmony_ci	}
110562306a36Sopenharmony_ci}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci/* update the format-id if changed */
110862306a36Sopenharmony_cistatic void update_pcm_format(struct hda_codec *codec, struct hda_cvt_setup *p,
110962306a36Sopenharmony_ci			      hda_nid_t nid, int format)
111062306a36Sopenharmony_ci{
111162306a36Sopenharmony_ci	unsigned int oldval;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	if (p->format_id != format) {
111462306a36Sopenharmony_ci		oldval = snd_hda_codec_read(codec, nid, 0,
111562306a36Sopenharmony_ci					    AC_VERB_GET_STREAM_FORMAT, 0);
111662306a36Sopenharmony_ci		if (oldval != format) {
111762306a36Sopenharmony_ci			msleep(1);
111862306a36Sopenharmony_ci			snd_hda_codec_write(codec, nid, 0,
111962306a36Sopenharmony_ci					    AC_VERB_SET_STREAM_FORMAT,
112062306a36Sopenharmony_ci					    format);
112162306a36Sopenharmony_ci		}
112262306a36Sopenharmony_ci		p->format_id = format;
112362306a36Sopenharmony_ci	}
112462306a36Sopenharmony_ci}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci/**
112762306a36Sopenharmony_ci * snd_hda_codec_setup_stream - set up the codec for streaming
112862306a36Sopenharmony_ci * @codec: the CODEC to set up
112962306a36Sopenharmony_ci * @nid: the NID to set up
113062306a36Sopenharmony_ci * @stream_tag: stream tag to pass, it's between 0x1 and 0xf.
113162306a36Sopenharmony_ci * @channel_id: channel id to pass, zero based.
113262306a36Sopenharmony_ci * @format: stream format.
113362306a36Sopenharmony_ci */
113462306a36Sopenharmony_civoid snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
113562306a36Sopenharmony_ci				u32 stream_tag,
113662306a36Sopenharmony_ci				int channel_id, int format)
113762306a36Sopenharmony_ci{
113862306a36Sopenharmony_ci	struct hda_codec *c;
113962306a36Sopenharmony_ci	struct hda_cvt_setup *p;
114062306a36Sopenharmony_ci	int type;
114162306a36Sopenharmony_ci	int i;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	if (!nid)
114462306a36Sopenharmony_ci		return;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	codec_dbg(codec,
114762306a36Sopenharmony_ci		  "hda_codec_setup_stream: NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n",
114862306a36Sopenharmony_ci		  nid, stream_tag, channel_id, format);
114962306a36Sopenharmony_ci	p = get_hda_cvt_setup(codec, nid);
115062306a36Sopenharmony_ci	if (!p)
115162306a36Sopenharmony_ci		return;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	if (codec->patch_ops.stream_pm)
115462306a36Sopenharmony_ci		codec->patch_ops.stream_pm(codec, nid, true);
115562306a36Sopenharmony_ci	if (codec->pcm_format_first)
115662306a36Sopenharmony_ci		update_pcm_format(codec, p, nid, format);
115762306a36Sopenharmony_ci	update_pcm_stream_id(codec, p, nid, stream_tag, channel_id);
115862306a36Sopenharmony_ci	if (!codec->pcm_format_first)
115962306a36Sopenharmony_ci		update_pcm_format(codec, p, nid, format);
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	p->active = 1;
116262306a36Sopenharmony_ci	p->dirty = 0;
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	/* make other inactive cvts with the same stream-tag dirty */
116562306a36Sopenharmony_ci	type = get_wcaps_type(get_wcaps(codec, nid));
116662306a36Sopenharmony_ci	list_for_each_codec(c, codec->bus) {
116762306a36Sopenharmony_ci		snd_array_for_each(&c->cvt_setups, i, p) {
116862306a36Sopenharmony_ci			if (!p->active && p->stream_tag == stream_tag &&
116962306a36Sopenharmony_ci			    get_wcaps_type(get_wcaps(c, p->nid)) == type)
117062306a36Sopenharmony_ci				p->dirty = 1;
117162306a36Sopenharmony_ci		}
117262306a36Sopenharmony_ci	}
117362306a36Sopenharmony_ci}
117462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_setup_stream);
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_cistatic void really_cleanup_stream(struct hda_codec *codec,
117762306a36Sopenharmony_ci				  struct hda_cvt_setup *q);
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci/**
118062306a36Sopenharmony_ci * __snd_hda_codec_cleanup_stream - clean up the codec for closing
118162306a36Sopenharmony_ci * @codec: the CODEC to clean up
118262306a36Sopenharmony_ci * @nid: the NID to clean up
118362306a36Sopenharmony_ci * @do_now: really clean up the stream instead of clearing the active flag
118462306a36Sopenharmony_ci */
118562306a36Sopenharmony_civoid __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid,
118662306a36Sopenharmony_ci				    int do_now)
118762306a36Sopenharmony_ci{
118862306a36Sopenharmony_ci	struct hda_cvt_setup *p;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	if (!nid)
119162306a36Sopenharmony_ci		return;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	if (codec->no_sticky_stream)
119462306a36Sopenharmony_ci		do_now = 1;
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	codec_dbg(codec, "hda_codec_cleanup_stream: NID=0x%x\n", nid);
119762306a36Sopenharmony_ci	p = get_hda_cvt_setup(codec, nid);
119862306a36Sopenharmony_ci	if (p) {
119962306a36Sopenharmony_ci		/* here we just clear the active flag when do_now isn't set;
120062306a36Sopenharmony_ci		 * actual clean-ups will be done later in
120162306a36Sopenharmony_ci		 * purify_inactive_streams() called from snd_hda_codec_prpapre()
120262306a36Sopenharmony_ci		 */
120362306a36Sopenharmony_ci		if (do_now)
120462306a36Sopenharmony_ci			really_cleanup_stream(codec, p);
120562306a36Sopenharmony_ci		else
120662306a36Sopenharmony_ci			p->active = 0;
120762306a36Sopenharmony_ci	}
120862306a36Sopenharmony_ci}
120962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__snd_hda_codec_cleanup_stream);
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_cistatic void really_cleanup_stream(struct hda_codec *codec,
121262306a36Sopenharmony_ci				  struct hda_cvt_setup *q)
121362306a36Sopenharmony_ci{
121462306a36Sopenharmony_ci	hda_nid_t nid = q->nid;
121562306a36Sopenharmony_ci	if (q->stream_tag || q->channel_id)
121662306a36Sopenharmony_ci		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
121762306a36Sopenharmony_ci	if (q->format_id)
121862306a36Sopenharmony_ci		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0
121962306a36Sopenharmony_ci);
122062306a36Sopenharmony_ci	memset(q, 0, sizeof(*q));
122162306a36Sopenharmony_ci	q->nid = nid;
122262306a36Sopenharmony_ci	if (codec->patch_ops.stream_pm)
122362306a36Sopenharmony_ci		codec->patch_ops.stream_pm(codec, nid, false);
122462306a36Sopenharmony_ci}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci/* clean up the all conflicting obsolete streams */
122762306a36Sopenharmony_cistatic void purify_inactive_streams(struct hda_codec *codec)
122862306a36Sopenharmony_ci{
122962306a36Sopenharmony_ci	struct hda_codec *c;
123062306a36Sopenharmony_ci	struct hda_cvt_setup *p;
123162306a36Sopenharmony_ci	int i;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	list_for_each_codec(c, codec->bus) {
123462306a36Sopenharmony_ci		snd_array_for_each(&c->cvt_setups, i, p) {
123562306a36Sopenharmony_ci			if (p->dirty)
123662306a36Sopenharmony_ci				really_cleanup_stream(c, p);
123762306a36Sopenharmony_ci		}
123862306a36Sopenharmony_ci	}
123962306a36Sopenharmony_ci}
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci#ifdef CONFIG_PM
124262306a36Sopenharmony_ci/* clean up all streams; called from suspend */
124362306a36Sopenharmony_cistatic void hda_cleanup_all_streams(struct hda_codec *codec)
124462306a36Sopenharmony_ci{
124562306a36Sopenharmony_ci	struct hda_cvt_setup *p;
124662306a36Sopenharmony_ci	int i;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	snd_array_for_each(&codec->cvt_setups, i, p) {
124962306a36Sopenharmony_ci		if (p->stream_tag)
125062306a36Sopenharmony_ci			really_cleanup_stream(codec, p);
125162306a36Sopenharmony_ci	}
125262306a36Sopenharmony_ci}
125362306a36Sopenharmony_ci#endif
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci/*
125662306a36Sopenharmony_ci * amp access functions
125762306a36Sopenharmony_ci */
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci/**
126062306a36Sopenharmony_ci * query_amp_caps - query AMP capabilities
126162306a36Sopenharmony_ci * @codec: the HD-auio codec
126262306a36Sopenharmony_ci * @nid: the NID to query
126362306a36Sopenharmony_ci * @direction: either #HDA_INPUT or #HDA_OUTPUT
126462306a36Sopenharmony_ci *
126562306a36Sopenharmony_ci * Query AMP capabilities for the given widget and direction.
126662306a36Sopenharmony_ci * Returns the obtained capability bits.
126762306a36Sopenharmony_ci *
126862306a36Sopenharmony_ci * When cap bits have been already read, this doesn't read again but
126962306a36Sopenharmony_ci * returns the cached value.
127062306a36Sopenharmony_ci */
127162306a36Sopenharmony_ciu32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
127262306a36Sopenharmony_ci{
127362306a36Sopenharmony_ci	if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD))
127462306a36Sopenharmony_ci		nid = codec->core.afg;
127562306a36Sopenharmony_ci	return snd_hda_param_read(codec, nid,
127662306a36Sopenharmony_ci				  direction == HDA_OUTPUT ?
127762306a36Sopenharmony_ci				  AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
127862306a36Sopenharmony_ci}
127962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(query_amp_caps);
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci/**
128262306a36Sopenharmony_ci * snd_hda_check_amp_caps - query AMP capabilities
128362306a36Sopenharmony_ci * @codec: the HD-audio codec
128462306a36Sopenharmony_ci * @nid: the NID to query
128562306a36Sopenharmony_ci * @dir: either #HDA_INPUT or #HDA_OUTPUT
128662306a36Sopenharmony_ci * @bits: bit mask to check the result
128762306a36Sopenharmony_ci *
128862306a36Sopenharmony_ci * Check whether the widget has the given amp capability for the direction.
128962306a36Sopenharmony_ci */
129062306a36Sopenharmony_cibool snd_hda_check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
129162306a36Sopenharmony_ci			   int dir, unsigned int bits)
129262306a36Sopenharmony_ci{
129362306a36Sopenharmony_ci	if (!nid)
129462306a36Sopenharmony_ci		return false;
129562306a36Sopenharmony_ci	if (get_wcaps(codec, nid) & (1 << (dir + 1)))
129662306a36Sopenharmony_ci		if (query_amp_caps(codec, nid, dir) & bits)
129762306a36Sopenharmony_ci			return true;
129862306a36Sopenharmony_ci	return false;
129962306a36Sopenharmony_ci}
130062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_check_amp_caps);
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci/**
130362306a36Sopenharmony_ci * snd_hda_override_amp_caps - Override the AMP capabilities
130462306a36Sopenharmony_ci * @codec: the CODEC to clean up
130562306a36Sopenharmony_ci * @nid: the NID to clean up
130662306a36Sopenharmony_ci * @dir: either #HDA_INPUT or #HDA_OUTPUT
130762306a36Sopenharmony_ci * @caps: the capability bits to set
130862306a36Sopenharmony_ci *
130962306a36Sopenharmony_ci * Override the cached AMP caps bits value by the given one.
131062306a36Sopenharmony_ci * This function is useful if the driver needs to adjust the AMP ranges,
131162306a36Sopenharmony_ci * e.g. limit to 0dB, etc.
131262306a36Sopenharmony_ci *
131362306a36Sopenharmony_ci * Returns zero if successful or a negative error code.
131462306a36Sopenharmony_ci */
131562306a36Sopenharmony_ciint snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
131662306a36Sopenharmony_ci			      unsigned int caps)
131762306a36Sopenharmony_ci{
131862306a36Sopenharmony_ci	unsigned int parm;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	snd_hda_override_wcaps(codec, nid,
132162306a36Sopenharmony_ci			       get_wcaps(codec, nid) | AC_WCAP_AMP_OVRD);
132262306a36Sopenharmony_ci	parm = dir == HDA_OUTPUT ? AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP;
132362306a36Sopenharmony_ci	return snd_hdac_override_parm(&codec->core, nid, parm, caps);
132462306a36Sopenharmony_ci}
132562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_override_amp_caps);
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_cistatic unsigned int encode_amp(struct hda_codec *codec, hda_nid_t nid,
132862306a36Sopenharmony_ci			       int ch, int dir, int idx)
132962306a36Sopenharmony_ci{
133062306a36Sopenharmony_ci	unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	/* enable fake mute if no h/w mute but min=mute */
133362306a36Sopenharmony_ci	if ((query_amp_caps(codec, nid, dir) &
133462306a36Sopenharmony_ci	     (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) == AC_AMPCAP_MIN_MUTE)
133562306a36Sopenharmony_ci		cmd |= AC_AMP_FAKE_MUTE;
133662306a36Sopenharmony_ci	return cmd;
133762306a36Sopenharmony_ci}
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci/**
134062306a36Sopenharmony_ci * snd_hda_codec_amp_update - update the AMP mono value
134162306a36Sopenharmony_ci * @codec: HD-audio codec
134262306a36Sopenharmony_ci * @nid: NID to read the AMP value
134362306a36Sopenharmony_ci * @ch: channel to update (0 or 1)
134462306a36Sopenharmony_ci * @dir: #HDA_INPUT or #HDA_OUTPUT
134562306a36Sopenharmony_ci * @idx: the index value (only for input direction)
134662306a36Sopenharmony_ci * @mask: bit mask to set
134762306a36Sopenharmony_ci * @val: the bits value to set
134862306a36Sopenharmony_ci *
134962306a36Sopenharmony_ci * Update the AMP values for the given channel, direction and index.
135062306a36Sopenharmony_ci */
135162306a36Sopenharmony_ciint snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid,
135262306a36Sopenharmony_ci			     int ch, int dir, int idx, int mask, int val)
135362306a36Sopenharmony_ci{
135462306a36Sopenharmony_ci	unsigned int cmd = encode_amp(codec, nid, ch, dir, idx);
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	return snd_hdac_regmap_update_raw(&codec->core, cmd, mask, val);
135762306a36Sopenharmony_ci}
135862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_amp_update);
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci/**
136162306a36Sopenharmony_ci * snd_hda_codec_amp_stereo - update the AMP stereo values
136262306a36Sopenharmony_ci * @codec: HD-audio codec
136362306a36Sopenharmony_ci * @nid: NID to read the AMP value
136462306a36Sopenharmony_ci * @direction: #HDA_INPUT or #HDA_OUTPUT
136562306a36Sopenharmony_ci * @idx: the index value (only for input direction)
136662306a36Sopenharmony_ci * @mask: bit mask to set
136762306a36Sopenharmony_ci * @val: the bits value to set
136862306a36Sopenharmony_ci *
136962306a36Sopenharmony_ci * Update the AMP values like snd_hda_codec_amp_update(), but for a
137062306a36Sopenharmony_ci * stereo widget with the same mask and value.
137162306a36Sopenharmony_ci */
137262306a36Sopenharmony_ciint snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
137362306a36Sopenharmony_ci			     int direction, int idx, int mask, int val)
137462306a36Sopenharmony_ci{
137562306a36Sopenharmony_ci	int ch, ret = 0;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	if (snd_BUG_ON(mask & ~0xff))
137862306a36Sopenharmony_ci		mask &= 0xff;
137962306a36Sopenharmony_ci	for (ch = 0; ch < 2; ch++)
138062306a36Sopenharmony_ci		ret |= snd_hda_codec_amp_update(codec, nid, ch, direction,
138162306a36Sopenharmony_ci						idx, mask, val);
138262306a36Sopenharmony_ci	return ret;
138362306a36Sopenharmony_ci}
138462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_amp_stereo);
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci/**
138762306a36Sopenharmony_ci * snd_hda_codec_amp_init - initialize the AMP value
138862306a36Sopenharmony_ci * @codec: the HDA codec
138962306a36Sopenharmony_ci * @nid: NID to read the AMP value
139062306a36Sopenharmony_ci * @ch: channel (left=0 or right=1)
139162306a36Sopenharmony_ci * @dir: #HDA_INPUT or #HDA_OUTPUT
139262306a36Sopenharmony_ci * @idx: the index value (only for input direction)
139362306a36Sopenharmony_ci * @mask: bit mask to set
139462306a36Sopenharmony_ci * @val: the bits value to set
139562306a36Sopenharmony_ci *
139662306a36Sopenharmony_ci * Works like snd_hda_codec_amp_update() but it writes the value only at
139762306a36Sopenharmony_ci * the first access.  If the amp was already initialized / updated beforehand,
139862306a36Sopenharmony_ci * this does nothing.
139962306a36Sopenharmony_ci */
140062306a36Sopenharmony_ciint snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch,
140162306a36Sopenharmony_ci			   int dir, int idx, int mask, int val)
140262306a36Sopenharmony_ci{
140362306a36Sopenharmony_ci	unsigned int cmd = encode_amp(codec, nid, ch, dir, idx);
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	if (!codec->core.regmap)
140662306a36Sopenharmony_ci		return -EINVAL;
140762306a36Sopenharmony_ci	return snd_hdac_regmap_update_raw_once(&codec->core, cmd, mask, val);
140862306a36Sopenharmony_ci}
140962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_amp_init);
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci/**
141262306a36Sopenharmony_ci * snd_hda_codec_amp_init_stereo - initialize the stereo AMP value
141362306a36Sopenharmony_ci * @codec: the HDA codec
141462306a36Sopenharmony_ci * @nid: NID to read the AMP value
141562306a36Sopenharmony_ci * @dir: #HDA_INPUT or #HDA_OUTPUT
141662306a36Sopenharmony_ci * @idx: the index value (only for input direction)
141762306a36Sopenharmony_ci * @mask: bit mask to set
141862306a36Sopenharmony_ci * @val: the bits value to set
141962306a36Sopenharmony_ci *
142062306a36Sopenharmony_ci * Call snd_hda_codec_amp_init() for both stereo channels.
142162306a36Sopenharmony_ci */
142262306a36Sopenharmony_ciint snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid,
142362306a36Sopenharmony_ci				  int dir, int idx, int mask, int val)
142462306a36Sopenharmony_ci{
142562306a36Sopenharmony_ci	int ch, ret = 0;
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	if (snd_BUG_ON(mask & ~0xff))
142862306a36Sopenharmony_ci		mask &= 0xff;
142962306a36Sopenharmony_ci	for (ch = 0; ch < 2; ch++)
143062306a36Sopenharmony_ci		ret |= snd_hda_codec_amp_init(codec, nid, ch, dir,
143162306a36Sopenharmony_ci					      idx, mask, val);
143262306a36Sopenharmony_ci	return ret;
143362306a36Sopenharmony_ci}
143462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_amp_init_stereo);
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_cistatic u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir,
143762306a36Sopenharmony_ci			     unsigned int ofs)
143862306a36Sopenharmony_ci{
143962306a36Sopenharmony_ci	u32 caps = query_amp_caps(codec, nid, dir);
144062306a36Sopenharmony_ci	/* get num steps */
144162306a36Sopenharmony_ci	caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
144262306a36Sopenharmony_ci	if (ofs < caps)
144362306a36Sopenharmony_ci		caps -= ofs;
144462306a36Sopenharmony_ci	return caps;
144562306a36Sopenharmony_ci}
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci/**
144862306a36Sopenharmony_ci * snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer
144962306a36Sopenharmony_ci * @kcontrol: referred ctl element
145062306a36Sopenharmony_ci * @uinfo: pointer to get/store the data
145162306a36Sopenharmony_ci *
145262306a36Sopenharmony_ci * The control element is supposed to have the private_value field
145362306a36Sopenharmony_ci * set up via HDA_COMPOSE_AMP_VAL*() or related macros.
145462306a36Sopenharmony_ci */
145562306a36Sopenharmony_ciint snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
145662306a36Sopenharmony_ci				  struct snd_ctl_elem_info *uinfo)
145762306a36Sopenharmony_ci{
145862306a36Sopenharmony_ci	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
145962306a36Sopenharmony_ci	u16 nid = get_amp_nid(kcontrol);
146062306a36Sopenharmony_ci	u8 chs = get_amp_channels(kcontrol);
146162306a36Sopenharmony_ci	int dir = get_amp_direction(kcontrol);
146262306a36Sopenharmony_ci	unsigned int ofs = get_amp_offset(kcontrol);
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
146562306a36Sopenharmony_ci	uinfo->count = chs == 3 ? 2 : 1;
146662306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
146762306a36Sopenharmony_ci	uinfo->value.integer.max = get_amp_max_value(codec, nid, dir, ofs);
146862306a36Sopenharmony_ci	if (!uinfo->value.integer.max) {
146962306a36Sopenharmony_ci		codec_warn(codec,
147062306a36Sopenharmony_ci			   "num_steps = 0 for NID=0x%x (ctl = %s)\n",
147162306a36Sopenharmony_ci			   nid, kcontrol->id.name);
147262306a36Sopenharmony_ci		return -EINVAL;
147362306a36Sopenharmony_ci	}
147462306a36Sopenharmony_ci	return 0;
147562306a36Sopenharmony_ci}
147662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_info);
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_cistatic inline unsigned int
148062306a36Sopenharmony_ciread_amp_value(struct hda_codec *codec, hda_nid_t nid,
148162306a36Sopenharmony_ci	       int ch, int dir, int idx, unsigned int ofs)
148262306a36Sopenharmony_ci{
148362306a36Sopenharmony_ci	unsigned int val;
148462306a36Sopenharmony_ci	val = snd_hda_codec_amp_read(codec, nid, ch, dir, idx);
148562306a36Sopenharmony_ci	val &= HDA_AMP_VOLMASK;
148662306a36Sopenharmony_ci	if (val >= ofs)
148762306a36Sopenharmony_ci		val -= ofs;
148862306a36Sopenharmony_ci	else
148962306a36Sopenharmony_ci		val = 0;
149062306a36Sopenharmony_ci	return val;
149162306a36Sopenharmony_ci}
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_cistatic inline int
149462306a36Sopenharmony_ciupdate_amp_value(struct hda_codec *codec, hda_nid_t nid,
149562306a36Sopenharmony_ci		 int ch, int dir, int idx, unsigned int ofs,
149662306a36Sopenharmony_ci		 unsigned int val)
149762306a36Sopenharmony_ci{
149862306a36Sopenharmony_ci	unsigned int maxval;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	if (val > 0)
150162306a36Sopenharmony_ci		val += ofs;
150262306a36Sopenharmony_ci	/* ofs = 0: raw max value */
150362306a36Sopenharmony_ci	maxval = get_amp_max_value(codec, nid, dir, 0);
150462306a36Sopenharmony_ci	if (val > maxval)
150562306a36Sopenharmony_ci		val = maxval;
150662306a36Sopenharmony_ci	return snd_hda_codec_amp_update(codec, nid, ch, dir, idx,
150762306a36Sopenharmony_ci					HDA_AMP_VOLMASK, val);
150862306a36Sopenharmony_ci}
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci/**
151162306a36Sopenharmony_ci * snd_hda_mixer_amp_volume_get - Get callback for a standard AMP mixer volume
151262306a36Sopenharmony_ci * @kcontrol: ctl element
151362306a36Sopenharmony_ci * @ucontrol: pointer to get/store the data
151462306a36Sopenharmony_ci *
151562306a36Sopenharmony_ci * The control element is supposed to have the private_value field
151662306a36Sopenharmony_ci * set up via HDA_COMPOSE_AMP_VAL*() or related macros.
151762306a36Sopenharmony_ci */
151862306a36Sopenharmony_ciint snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
151962306a36Sopenharmony_ci				 struct snd_ctl_elem_value *ucontrol)
152062306a36Sopenharmony_ci{
152162306a36Sopenharmony_ci	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
152262306a36Sopenharmony_ci	hda_nid_t nid = get_amp_nid(kcontrol);
152362306a36Sopenharmony_ci	int chs = get_amp_channels(kcontrol);
152462306a36Sopenharmony_ci	int dir = get_amp_direction(kcontrol);
152562306a36Sopenharmony_ci	int idx = get_amp_index(kcontrol);
152662306a36Sopenharmony_ci	unsigned int ofs = get_amp_offset(kcontrol);
152762306a36Sopenharmony_ci	long *valp = ucontrol->value.integer.value;
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	if (chs & 1)
153062306a36Sopenharmony_ci		*valp++ = read_amp_value(codec, nid, 0, dir, idx, ofs);
153162306a36Sopenharmony_ci	if (chs & 2)
153262306a36Sopenharmony_ci		*valp = read_amp_value(codec, nid, 1, dir, idx, ofs);
153362306a36Sopenharmony_ci	return 0;
153462306a36Sopenharmony_ci}
153562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_get);
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci/**
153862306a36Sopenharmony_ci * snd_hda_mixer_amp_volume_put - Put callback for a standard AMP mixer volume
153962306a36Sopenharmony_ci * @kcontrol: ctl element
154062306a36Sopenharmony_ci * @ucontrol: pointer to get/store the data
154162306a36Sopenharmony_ci *
154262306a36Sopenharmony_ci * The control element is supposed to have the private_value field
154362306a36Sopenharmony_ci * set up via HDA_COMPOSE_AMP_VAL*() or related macros.
154462306a36Sopenharmony_ci */
154562306a36Sopenharmony_ciint snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol,
154662306a36Sopenharmony_ci				 struct snd_ctl_elem_value *ucontrol)
154762306a36Sopenharmony_ci{
154862306a36Sopenharmony_ci	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
154962306a36Sopenharmony_ci	hda_nid_t nid = get_amp_nid(kcontrol);
155062306a36Sopenharmony_ci	int chs = get_amp_channels(kcontrol);
155162306a36Sopenharmony_ci	int dir = get_amp_direction(kcontrol);
155262306a36Sopenharmony_ci	int idx = get_amp_index(kcontrol);
155362306a36Sopenharmony_ci	unsigned int ofs = get_amp_offset(kcontrol);
155462306a36Sopenharmony_ci	long *valp = ucontrol->value.integer.value;
155562306a36Sopenharmony_ci	int change = 0;
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	if (chs & 1) {
155862306a36Sopenharmony_ci		change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp);
155962306a36Sopenharmony_ci		valp++;
156062306a36Sopenharmony_ci	}
156162306a36Sopenharmony_ci	if (chs & 2)
156262306a36Sopenharmony_ci		change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp);
156362306a36Sopenharmony_ci	return change;
156462306a36Sopenharmony_ci}
156562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put);
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci/* inquiry the amp caps and convert to TLV */
156862306a36Sopenharmony_cistatic void get_ctl_amp_tlv(struct snd_kcontrol *kcontrol, unsigned int *tlv)
156962306a36Sopenharmony_ci{
157062306a36Sopenharmony_ci	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
157162306a36Sopenharmony_ci	hda_nid_t nid = get_amp_nid(kcontrol);
157262306a36Sopenharmony_ci	int dir = get_amp_direction(kcontrol);
157362306a36Sopenharmony_ci	unsigned int ofs = get_amp_offset(kcontrol);
157462306a36Sopenharmony_ci	bool min_mute = get_amp_min_mute(kcontrol);
157562306a36Sopenharmony_ci	u32 caps, val1, val2;
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	caps = query_amp_caps(codec, nid, dir);
157862306a36Sopenharmony_ci	val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT;
157962306a36Sopenharmony_ci	val2 = (val2 + 1) * 25;
158062306a36Sopenharmony_ci	val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);
158162306a36Sopenharmony_ci	val1 += ofs;
158262306a36Sopenharmony_ci	val1 = ((int)val1) * ((int)val2);
158362306a36Sopenharmony_ci	if (min_mute || (caps & AC_AMPCAP_MIN_MUTE))
158462306a36Sopenharmony_ci		val2 |= TLV_DB_SCALE_MUTE;
158562306a36Sopenharmony_ci	tlv[SNDRV_CTL_TLVO_TYPE] = SNDRV_CTL_TLVT_DB_SCALE;
158662306a36Sopenharmony_ci	tlv[SNDRV_CTL_TLVO_LEN] = 2 * sizeof(unsigned int);
158762306a36Sopenharmony_ci	tlv[SNDRV_CTL_TLVO_DB_SCALE_MIN] = val1;
158862306a36Sopenharmony_ci	tlv[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] = val2;
158962306a36Sopenharmony_ci}
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci/**
159262306a36Sopenharmony_ci * snd_hda_mixer_amp_tlv - TLV callback for a standard AMP mixer volume
159362306a36Sopenharmony_ci * @kcontrol: ctl element
159462306a36Sopenharmony_ci * @op_flag: operation flag
159562306a36Sopenharmony_ci * @size: byte size of input TLV
159662306a36Sopenharmony_ci * @_tlv: TLV data
159762306a36Sopenharmony_ci *
159862306a36Sopenharmony_ci * The control element is supposed to have the private_value field
159962306a36Sopenharmony_ci * set up via HDA_COMPOSE_AMP_VAL*() or related macros.
160062306a36Sopenharmony_ci */
160162306a36Sopenharmony_ciint snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
160262306a36Sopenharmony_ci			  unsigned int size, unsigned int __user *_tlv)
160362306a36Sopenharmony_ci{
160462306a36Sopenharmony_ci	unsigned int tlv[4];
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	if (size < 4 * sizeof(unsigned int))
160762306a36Sopenharmony_ci		return -ENOMEM;
160862306a36Sopenharmony_ci	get_ctl_amp_tlv(kcontrol, tlv);
160962306a36Sopenharmony_ci	if (copy_to_user(_tlv, tlv, sizeof(tlv)))
161062306a36Sopenharmony_ci		return -EFAULT;
161162306a36Sopenharmony_ci	return 0;
161262306a36Sopenharmony_ci}
161362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_mixer_amp_tlv);
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci/**
161662306a36Sopenharmony_ci * snd_hda_set_vmaster_tlv - Set TLV for a virtual master control
161762306a36Sopenharmony_ci * @codec: HD-audio codec
161862306a36Sopenharmony_ci * @nid: NID of a reference widget
161962306a36Sopenharmony_ci * @dir: #HDA_INPUT or #HDA_OUTPUT
162062306a36Sopenharmony_ci * @tlv: TLV data to be stored, at least 4 elements
162162306a36Sopenharmony_ci *
162262306a36Sopenharmony_ci * Set (static) TLV data for a virtual master volume using the AMP caps
162362306a36Sopenharmony_ci * obtained from the reference NID.
162462306a36Sopenharmony_ci * The volume range is recalculated as if the max volume is 0dB.
162562306a36Sopenharmony_ci */
162662306a36Sopenharmony_civoid snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
162762306a36Sopenharmony_ci			     unsigned int *tlv)
162862306a36Sopenharmony_ci{
162962306a36Sopenharmony_ci	u32 caps;
163062306a36Sopenharmony_ci	int nums, step;
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	caps = query_amp_caps(codec, nid, dir);
163362306a36Sopenharmony_ci	nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
163462306a36Sopenharmony_ci	step = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT;
163562306a36Sopenharmony_ci	step = (step + 1) * 25;
163662306a36Sopenharmony_ci	tlv[SNDRV_CTL_TLVO_TYPE] = SNDRV_CTL_TLVT_DB_SCALE;
163762306a36Sopenharmony_ci	tlv[SNDRV_CTL_TLVO_LEN] = 2 * sizeof(unsigned int);
163862306a36Sopenharmony_ci	tlv[SNDRV_CTL_TLVO_DB_SCALE_MIN] = -nums * step;
163962306a36Sopenharmony_ci	tlv[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] = step;
164062306a36Sopenharmony_ci}
164162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_set_vmaster_tlv);
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci/* find a mixer control element with the given name */
164462306a36Sopenharmony_cistatic struct snd_kcontrol *
164562306a36Sopenharmony_cifind_mixer_ctl(struct hda_codec *codec, const char *name, int dev, int idx)
164662306a36Sopenharmony_ci{
164762306a36Sopenharmony_ci	struct snd_ctl_elem_id id;
164862306a36Sopenharmony_ci	memset(&id, 0, sizeof(id));
164962306a36Sopenharmony_ci	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
165062306a36Sopenharmony_ci	id.device = dev;
165162306a36Sopenharmony_ci	id.index = idx;
165262306a36Sopenharmony_ci	if (snd_BUG_ON(strlen(name) >= sizeof(id.name)))
165362306a36Sopenharmony_ci		return NULL;
165462306a36Sopenharmony_ci	strcpy(id.name, name);
165562306a36Sopenharmony_ci	return snd_ctl_find_id(codec->card, &id);
165662306a36Sopenharmony_ci}
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci/**
165962306a36Sopenharmony_ci * snd_hda_find_mixer_ctl - Find a mixer control element with the given name
166062306a36Sopenharmony_ci * @codec: HD-audio codec
166162306a36Sopenharmony_ci * @name: ctl id name string
166262306a36Sopenharmony_ci *
166362306a36Sopenharmony_ci * Get the control element with the given id string and IFACE_MIXER.
166462306a36Sopenharmony_ci */
166562306a36Sopenharmony_cistruct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
166662306a36Sopenharmony_ci					    const char *name)
166762306a36Sopenharmony_ci{
166862306a36Sopenharmony_ci	return find_mixer_ctl(codec, name, 0, 0);
166962306a36Sopenharmony_ci}
167062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_find_mixer_ctl);
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_cistatic int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name,
167362306a36Sopenharmony_ci				    int start_idx)
167462306a36Sopenharmony_ci{
167562306a36Sopenharmony_ci	int i, idx;
167662306a36Sopenharmony_ci	/* 16 ctlrs should be large enough */
167762306a36Sopenharmony_ci	for (i = 0, idx = start_idx; i < 16; i++, idx++) {
167862306a36Sopenharmony_ci		if (!find_mixer_ctl(codec, name, 0, idx))
167962306a36Sopenharmony_ci			return idx;
168062306a36Sopenharmony_ci	}
168162306a36Sopenharmony_ci	return -EBUSY;
168262306a36Sopenharmony_ci}
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci/**
168562306a36Sopenharmony_ci * snd_hda_ctl_add - Add a control element and assign to the codec
168662306a36Sopenharmony_ci * @codec: HD-audio codec
168762306a36Sopenharmony_ci * @nid: corresponding NID (optional)
168862306a36Sopenharmony_ci * @kctl: the control element to assign
168962306a36Sopenharmony_ci *
169062306a36Sopenharmony_ci * Add the given control element to an array inside the codec instance.
169162306a36Sopenharmony_ci * All control elements belonging to a codec are supposed to be added
169262306a36Sopenharmony_ci * by this function so that a proper clean-up works at the free or
169362306a36Sopenharmony_ci * reconfiguration time.
169462306a36Sopenharmony_ci *
169562306a36Sopenharmony_ci * If non-zero @nid is passed, the NID is assigned to the control element.
169662306a36Sopenharmony_ci * The assignment is shown in the codec proc file.
169762306a36Sopenharmony_ci *
169862306a36Sopenharmony_ci * snd_hda_ctl_add() checks the control subdev id field whether
169962306a36Sopenharmony_ci * #HDA_SUBDEV_NID_FLAG bit is set.  If set (and @nid is zero), the lower
170062306a36Sopenharmony_ci * bits value is taken as the NID to assign. The #HDA_NID_ITEM_AMP bit
170162306a36Sopenharmony_ci * specifies if kctl->private_value is a HDA amplifier value.
170262306a36Sopenharmony_ci */
170362306a36Sopenharmony_ciint snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
170462306a36Sopenharmony_ci		    struct snd_kcontrol *kctl)
170562306a36Sopenharmony_ci{
170662306a36Sopenharmony_ci	int err;
170762306a36Sopenharmony_ci	unsigned short flags = 0;
170862306a36Sopenharmony_ci	struct hda_nid_item *item;
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci	if (kctl->id.subdevice & HDA_SUBDEV_AMP_FLAG) {
171162306a36Sopenharmony_ci		flags |= HDA_NID_ITEM_AMP;
171262306a36Sopenharmony_ci		if (nid == 0)
171362306a36Sopenharmony_ci			nid = get_amp_nid_(kctl->private_value);
171462306a36Sopenharmony_ci	}
171562306a36Sopenharmony_ci	if ((kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) != 0 && nid == 0)
171662306a36Sopenharmony_ci		nid = kctl->id.subdevice & 0xffff;
171762306a36Sopenharmony_ci	if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG))
171862306a36Sopenharmony_ci		kctl->id.subdevice = 0;
171962306a36Sopenharmony_ci	err = snd_ctl_add(codec->card, kctl);
172062306a36Sopenharmony_ci	if (err < 0)
172162306a36Sopenharmony_ci		return err;
172262306a36Sopenharmony_ci	item = snd_array_new(&codec->mixers);
172362306a36Sopenharmony_ci	if (!item)
172462306a36Sopenharmony_ci		return -ENOMEM;
172562306a36Sopenharmony_ci	item->kctl = kctl;
172662306a36Sopenharmony_ci	item->nid = nid;
172762306a36Sopenharmony_ci	item->flags = flags;
172862306a36Sopenharmony_ci	return 0;
172962306a36Sopenharmony_ci}
173062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_ctl_add);
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci/**
173362306a36Sopenharmony_ci * snd_hda_add_nid - Assign a NID to a control element
173462306a36Sopenharmony_ci * @codec: HD-audio codec
173562306a36Sopenharmony_ci * @nid: corresponding NID (optional)
173662306a36Sopenharmony_ci * @kctl: the control element to assign
173762306a36Sopenharmony_ci * @index: index to kctl
173862306a36Sopenharmony_ci *
173962306a36Sopenharmony_ci * Add the given control element to an array inside the codec instance.
174062306a36Sopenharmony_ci * This function is used when #snd_hda_ctl_add cannot be used for 1:1
174162306a36Sopenharmony_ci * NID:KCTL mapping - for example "Capture Source" selector.
174262306a36Sopenharmony_ci */
174362306a36Sopenharmony_ciint snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl,
174462306a36Sopenharmony_ci		    unsigned int index, hda_nid_t nid)
174562306a36Sopenharmony_ci{
174662306a36Sopenharmony_ci	struct hda_nid_item *item;
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	if (nid > 0) {
174962306a36Sopenharmony_ci		item = snd_array_new(&codec->nids);
175062306a36Sopenharmony_ci		if (!item)
175162306a36Sopenharmony_ci			return -ENOMEM;
175262306a36Sopenharmony_ci		item->kctl = kctl;
175362306a36Sopenharmony_ci		item->index = index;
175462306a36Sopenharmony_ci		item->nid = nid;
175562306a36Sopenharmony_ci		return 0;
175662306a36Sopenharmony_ci	}
175762306a36Sopenharmony_ci	codec_err(codec, "no NID for mapping control %s:%d:%d\n",
175862306a36Sopenharmony_ci		  kctl->id.name, kctl->id.index, index);
175962306a36Sopenharmony_ci	return -EINVAL;
176062306a36Sopenharmony_ci}
176162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_add_nid);
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci/**
176462306a36Sopenharmony_ci * snd_hda_ctls_clear - Clear all controls assigned to the given codec
176562306a36Sopenharmony_ci * @codec: HD-audio codec
176662306a36Sopenharmony_ci */
176762306a36Sopenharmony_civoid snd_hda_ctls_clear(struct hda_codec *codec)
176862306a36Sopenharmony_ci{
176962306a36Sopenharmony_ci	int i;
177062306a36Sopenharmony_ci	struct hda_nid_item *items = codec->mixers.list;
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	for (i = 0; i < codec->mixers.used; i++)
177362306a36Sopenharmony_ci		snd_ctl_remove(codec->card, items[i].kctl);
177462306a36Sopenharmony_ci	snd_array_free(&codec->mixers);
177562306a36Sopenharmony_ci	snd_array_free(&codec->nids);
177662306a36Sopenharmony_ci}
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci/**
177962306a36Sopenharmony_ci * snd_hda_lock_devices - pseudo device locking
178062306a36Sopenharmony_ci * @bus: the BUS
178162306a36Sopenharmony_ci *
178262306a36Sopenharmony_ci * toggle card->shutdown to allow/disallow the device access (as a hack)
178362306a36Sopenharmony_ci */
178462306a36Sopenharmony_ciint snd_hda_lock_devices(struct hda_bus *bus)
178562306a36Sopenharmony_ci{
178662306a36Sopenharmony_ci	struct snd_card *card = bus->card;
178762306a36Sopenharmony_ci	struct hda_codec *codec;
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci	spin_lock(&card->files_lock);
179062306a36Sopenharmony_ci	if (card->shutdown)
179162306a36Sopenharmony_ci		goto err_unlock;
179262306a36Sopenharmony_ci	card->shutdown = 1;
179362306a36Sopenharmony_ci	if (!list_empty(&card->ctl_files))
179462306a36Sopenharmony_ci		goto err_clear;
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	list_for_each_codec(codec, bus) {
179762306a36Sopenharmony_ci		struct hda_pcm *cpcm;
179862306a36Sopenharmony_ci		list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
179962306a36Sopenharmony_ci			if (!cpcm->pcm)
180062306a36Sopenharmony_ci				continue;
180162306a36Sopenharmony_ci			if (cpcm->pcm->streams[0].substream_opened ||
180262306a36Sopenharmony_ci			    cpcm->pcm->streams[1].substream_opened)
180362306a36Sopenharmony_ci				goto err_clear;
180462306a36Sopenharmony_ci		}
180562306a36Sopenharmony_ci	}
180662306a36Sopenharmony_ci	spin_unlock(&card->files_lock);
180762306a36Sopenharmony_ci	return 0;
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci err_clear:
181062306a36Sopenharmony_ci	card->shutdown = 0;
181162306a36Sopenharmony_ci err_unlock:
181262306a36Sopenharmony_ci	spin_unlock(&card->files_lock);
181362306a36Sopenharmony_ci	return -EINVAL;
181462306a36Sopenharmony_ci}
181562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_lock_devices);
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci/**
181862306a36Sopenharmony_ci * snd_hda_unlock_devices - pseudo device unlocking
181962306a36Sopenharmony_ci * @bus: the BUS
182062306a36Sopenharmony_ci */
182162306a36Sopenharmony_civoid snd_hda_unlock_devices(struct hda_bus *bus)
182262306a36Sopenharmony_ci{
182362306a36Sopenharmony_ci	struct snd_card *card = bus->card;
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	spin_lock(&card->files_lock);
182662306a36Sopenharmony_ci	card->shutdown = 0;
182762306a36Sopenharmony_ci	spin_unlock(&card->files_lock);
182862306a36Sopenharmony_ci}
182962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_unlock_devices);
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci/**
183262306a36Sopenharmony_ci * snd_hda_codec_reset - Clear all objects assigned to the codec
183362306a36Sopenharmony_ci * @codec: HD-audio codec
183462306a36Sopenharmony_ci *
183562306a36Sopenharmony_ci * This frees the all PCM and control elements assigned to the codec, and
183662306a36Sopenharmony_ci * clears the caches and restores the pin default configurations.
183762306a36Sopenharmony_ci *
183862306a36Sopenharmony_ci * When a device is being used, it returns -EBSY.  If successfully freed,
183962306a36Sopenharmony_ci * returns zero.
184062306a36Sopenharmony_ci */
184162306a36Sopenharmony_ciint snd_hda_codec_reset(struct hda_codec *codec)
184262306a36Sopenharmony_ci{
184362306a36Sopenharmony_ci	struct hda_bus *bus = codec->bus;
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	if (snd_hda_lock_devices(bus) < 0)
184662306a36Sopenharmony_ci		return -EBUSY;
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci	/* OK, let it free */
184962306a36Sopenharmony_ci	device_release_driver(hda_codec_dev(codec));
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	/* allow device access again */
185262306a36Sopenharmony_ci	snd_hda_unlock_devices(bus);
185362306a36Sopenharmony_ci	return 0;
185462306a36Sopenharmony_ci}
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_citypedef int (*map_follower_func_t)(struct hda_codec *, void *, struct snd_kcontrol *);
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci/* apply the function to all matching follower ctls in the mixer list */
185962306a36Sopenharmony_cistatic int map_followers(struct hda_codec *codec, const char * const *followers,
186062306a36Sopenharmony_ci			 const char *suffix, map_follower_func_t func, void *data)
186162306a36Sopenharmony_ci{
186262306a36Sopenharmony_ci	struct hda_nid_item *items;
186362306a36Sopenharmony_ci	const char * const *s;
186462306a36Sopenharmony_ci	int i, err;
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	items = codec->mixers.list;
186762306a36Sopenharmony_ci	for (i = 0; i < codec->mixers.used; i++) {
186862306a36Sopenharmony_ci		struct snd_kcontrol *sctl = items[i].kctl;
186962306a36Sopenharmony_ci		if (!sctl || sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER)
187062306a36Sopenharmony_ci			continue;
187162306a36Sopenharmony_ci		for (s = followers; *s; s++) {
187262306a36Sopenharmony_ci			char tmpname[sizeof(sctl->id.name)];
187362306a36Sopenharmony_ci			const char *name = *s;
187462306a36Sopenharmony_ci			if (suffix) {
187562306a36Sopenharmony_ci				snprintf(tmpname, sizeof(tmpname), "%s %s",
187662306a36Sopenharmony_ci					 name, suffix);
187762306a36Sopenharmony_ci				name = tmpname;
187862306a36Sopenharmony_ci			}
187962306a36Sopenharmony_ci			if (!strcmp(sctl->id.name, name)) {
188062306a36Sopenharmony_ci				err = func(codec, data, sctl);
188162306a36Sopenharmony_ci				if (err)
188262306a36Sopenharmony_ci					return err;
188362306a36Sopenharmony_ci				break;
188462306a36Sopenharmony_ci			}
188562306a36Sopenharmony_ci		}
188662306a36Sopenharmony_ci	}
188762306a36Sopenharmony_ci	return 0;
188862306a36Sopenharmony_ci}
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_cistatic int check_follower_present(struct hda_codec *codec,
189162306a36Sopenharmony_ci				  void *data, struct snd_kcontrol *sctl)
189262306a36Sopenharmony_ci{
189362306a36Sopenharmony_ci	return 1;
189462306a36Sopenharmony_ci}
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci/* call kctl->put with the given value(s) */
189762306a36Sopenharmony_cistatic int put_kctl_with_value(struct snd_kcontrol *kctl, int val)
189862306a36Sopenharmony_ci{
189962306a36Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol;
190062306a36Sopenharmony_ci	ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL);
190162306a36Sopenharmony_ci	if (!ucontrol)
190262306a36Sopenharmony_ci		return -ENOMEM;
190362306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = val;
190462306a36Sopenharmony_ci	ucontrol->value.integer.value[1] = val;
190562306a36Sopenharmony_ci	kctl->put(kctl, ucontrol);
190662306a36Sopenharmony_ci	kfree(ucontrol);
190762306a36Sopenharmony_ci	return 0;
190862306a36Sopenharmony_ci}
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_cistruct follower_init_arg {
191162306a36Sopenharmony_ci	struct hda_codec *codec;
191262306a36Sopenharmony_ci	int step;
191362306a36Sopenharmony_ci};
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci/* initialize the follower volume with 0dB via snd_ctl_apply_vmaster_followers() */
191662306a36Sopenharmony_cistatic int init_follower_0dB(struct snd_kcontrol *follower,
191762306a36Sopenharmony_ci			     struct snd_kcontrol *kctl,
191862306a36Sopenharmony_ci			     void *_arg)
191962306a36Sopenharmony_ci{
192062306a36Sopenharmony_ci	struct follower_init_arg *arg = _arg;
192162306a36Sopenharmony_ci	int _tlv[4];
192262306a36Sopenharmony_ci	const int *tlv = NULL;
192362306a36Sopenharmony_ci	int step;
192462306a36Sopenharmony_ci	int val;
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
192762306a36Sopenharmony_ci		if (kctl->tlv.c != snd_hda_mixer_amp_tlv) {
192862306a36Sopenharmony_ci			codec_err(arg->codec,
192962306a36Sopenharmony_ci				  "Unexpected TLV callback for follower %s:%d\n",
193062306a36Sopenharmony_ci				  kctl->id.name, kctl->id.index);
193162306a36Sopenharmony_ci			return 0; /* ignore */
193262306a36Sopenharmony_ci		}
193362306a36Sopenharmony_ci		get_ctl_amp_tlv(kctl, _tlv);
193462306a36Sopenharmony_ci		tlv = _tlv;
193562306a36Sopenharmony_ci	} else if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_READ)
193662306a36Sopenharmony_ci		tlv = kctl->tlv.p;
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	if (!tlv || tlv[SNDRV_CTL_TLVO_TYPE] != SNDRV_CTL_TLVT_DB_SCALE)
193962306a36Sopenharmony_ci		return 0;
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	step = tlv[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP];
194262306a36Sopenharmony_ci	step &= ~TLV_DB_SCALE_MUTE;
194362306a36Sopenharmony_ci	if (!step)
194462306a36Sopenharmony_ci		return 0;
194562306a36Sopenharmony_ci	if (arg->step && arg->step != step) {
194662306a36Sopenharmony_ci		codec_err(arg->codec,
194762306a36Sopenharmony_ci			  "Mismatching dB step for vmaster follower (%d!=%d)\n",
194862306a36Sopenharmony_ci			  arg->step, step);
194962306a36Sopenharmony_ci		return 0;
195062306a36Sopenharmony_ci	}
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ci	arg->step = step;
195362306a36Sopenharmony_ci	val = -tlv[SNDRV_CTL_TLVO_DB_SCALE_MIN] / step;
195462306a36Sopenharmony_ci	if (val > 0) {
195562306a36Sopenharmony_ci		put_kctl_with_value(follower, val);
195662306a36Sopenharmony_ci		return val;
195762306a36Sopenharmony_ci	}
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	return 0;
196062306a36Sopenharmony_ci}
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci/* unmute the follower via snd_ctl_apply_vmaster_followers() */
196362306a36Sopenharmony_cistatic int init_follower_unmute(struct snd_kcontrol *follower,
196462306a36Sopenharmony_ci				struct snd_kcontrol *kctl,
196562306a36Sopenharmony_ci				void *_arg)
196662306a36Sopenharmony_ci{
196762306a36Sopenharmony_ci	return put_kctl_with_value(follower, 1);
196862306a36Sopenharmony_ci}
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_cistatic int add_follower(struct hda_codec *codec,
197162306a36Sopenharmony_ci			void *data, struct snd_kcontrol *follower)
197262306a36Sopenharmony_ci{
197362306a36Sopenharmony_ci	return snd_ctl_add_follower(data, follower);
197462306a36Sopenharmony_ci}
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci/**
197762306a36Sopenharmony_ci * __snd_hda_add_vmaster - create a virtual master control and add followers
197862306a36Sopenharmony_ci * @codec: HD-audio codec
197962306a36Sopenharmony_ci * @name: vmaster control name
198062306a36Sopenharmony_ci * @tlv: TLV data (optional)
198162306a36Sopenharmony_ci * @followers: follower control names (optional)
198262306a36Sopenharmony_ci * @suffix: suffix string to each follower name (optional)
198362306a36Sopenharmony_ci * @init_follower_vol: initialize followers to unmute/0dB
198462306a36Sopenharmony_ci * @access: kcontrol access rights
198562306a36Sopenharmony_ci * @ctl_ret: store the vmaster kcontrol in return
198662306a36Sopenharmony_ci *
198762306a36Sopenharmony_ci * Create a virtual master control with the given name.  The TLV data
198862306a36Sopenharmony_ci * must be either NULL or a valid data.
198962306a36Sopenharmony_ci *
199062306a36Sopenharmony_ci * @followers is a NULL-terminated array of strings, each of which is a
199162306a36Sopenharmony_ci * follower control name.  All controls with these names are assigned to
199262306a36Sopenharmony_ci * the new virtual master control.
199362306a36Sopenharmony_ci *
199462306a36Sopenharmony_ci * This function returns zero if successful or a negative error code.
199562306a36Sopenharmony_ci */
199662306a36Sopenharmony_ciint __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
199762306a36Sopenharmony_ci			  unsigned int *tlv, const char * const *followers,
199862306a36Sopenharmony_ci			  const char *suffix, bool init_follower_vol,
199962306a36Sopenharmony_ci			  unsigned int access, struct snd_kcontrol **ctl_ret)
200062306a36Sopenharmony_ci{
200162306a36Sopenharmony_ci	struct snd_kcontrol *kctl;
200262306a36Sopenharmony_ci	int err;
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	if (ctl_ret)
200562306a36Sopenharmony_ci		*ctl_ret = NULL;
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci	err = map_followers(codec, followers, suffix, check_follower_present, NULL);
200862306a36Sopenharmony_ci	if (err != 1) {
200962306a36Sopenharmony_ci		codec_dbg(codec, "No follower found for %s\n", name);
201062306a36Sopenharmony_ci		return 0;
201162306a36Sopenharmony_ci	}
201262306a36Sopenharmony_ci	kctl = snd_ctl_make_virtual_master(name, tlv);
201362306a36Sopenharmony_ci	if (!kctl)
201462306a36Sopenharmony_ci		return -ENOMEM;
201562306a36Sopenharmony_ci	kctl->vd[0].access |= access;
201662306a36Sopenharmony_ci	err = snd_hda_ctl_add(codec, 0, kctl);
201762306a36Sopenharmony_ci	if (err < 0)
201862306a36Sopenharmony_ci		return err;
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	err = map_followers(codec, followers, suffix, add_follower, kctl);
202162306a36Sopenharmony_ci	if (err < 0)
202262306a36Sopenharmony_ci		return err;
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci	/* init with master mute & zero volume */
202562306a36Sopenharmony_ci	put_kctl_with_value(kctl, 0);
202662306a36Sopenharmony_ci	if (init_follower_vol) {
202762306a36Sopenharmony_ci		struct follower_init_arg arg = {
202862306a36Sopenharmony_ci			.codec = codec,
202962306a36Sopenharmony_ci			.step = 0,
203062306a36Sopenharmony_ci		};
203162306a36Sopenharmony_ci		snd_ctl_apply_vmaster_followers(kctl,
203262306a36Sopenharmony_ci						tlv ? init_follower_0dB : init_follower_unmute,
203362306a36Sopenharmony_ci						&arg);
203462306a36Sopenharmony_ci	}
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_ci	if (ctl_ret)
203762306a36Sopenharmony_ci		*ctl_ret = kctl;
203862306a36Sopenharmony_ci	return 0;
203962306a36Sopenharmony_ci}
204062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__snd_hda_add_vmaster);
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci/* meta hook to call each driver's vmaster hook */
204362306a36Sopenharmony_cistatic void vmaster_hook(void *private_data, int enabled)
204462306a36Sopenharmony_ci{
204562306a36Sopenharmony_ci	struct hda_vmaster_mute_hook *hook = private_data;
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci	hook->hook(hook->codec, enabled);
204862306a36Sopenharmony_ci}
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_ci/**
205162306a36Sopenharmony_ci * snd_hda_add_vmaster_hook - Add a vmaster hw specific hook
205262306a36Sopenharmony_ci * @codec: the HDA codec
205362306a36Sopenharmony_ci * @hook: the vmaster hook object
205462306a36Sopenharmony_ci *
205562306a36Sopenharmony_ci * Add a hw specific hook (like EAPD) with the given vmaster switch kctl.
205662306a36Sopenharmony_ci */
205762306a36Sopenharmony_ciint snd_hda_add_vmaster_hook(struct hda_codec *codec,
205862306a36Sopenharmony_ci			     struct hda_vmaster_mute_hook *hook)
205962306a36Sopenharmony_ci{
206062306a36Sopenharmony_ci	if (!hook->hook || !hook->sw_kctl)
206162306a36Sopenharmony_ci		return 0;
206262306a36Sopenharmony_ci	hook->codec = codec;
206362306a36Sopenharmony_ci	snd_ctl_add_vmaster_hook(hook->sw_kctl, vmaster_hook, hook);
206462306a36Sopenharmony_ci	return 0;
206562306a36Sopenharmony_ci}
206662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_add_vmaster_hook);
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci/**
206962306a36Sopenharmony_ci * snd_hda_sync_vmaster_hook - Sync vmaster hook
207062306a36Sopenharmony_ci * @hook: the vmaster hook
207162306a36Sopenharmony_ci *
207262306a36Sopenharmony_ci * Call the hook with the current value for synchronization.
207362306a36Sopenharmony_ci * Should be called in init callback.
207462306a36Sopenharmony_ci */
207562306a36Sopenharmony_civoid snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook)
207662306a36Sopenharmony_ci{
207762306a36Sopenharmony_ci	if (!hook->hook || !hook->codec)
207862306a36Sopenharmony_ci		return;
207962306a36Sopenharmony_ci	/* don't call vmaster hook in the destructor since it might have
208062306a36Sopenharmony_ci	 * been already destroyed
208162306a36Sopenharmony_ci	 */
208262306a36Sopenharmony_ci	if (hook->codec->bus->shutdown)
208362306a36Sopenharmony_ci		return;
208462306a36Sopenharmony_ci	snd_ctl_sync_vmaster_hook(hook->sw_kctl);
208562306a36Sopenharmony_ci}
208662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_sync_vmaster_hook);
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci/**
209062306a36Sopenharmony_ci * snd_hda_mixer_amp_switch_info - Info callback for a standard AMP mixer switch
209162306a36Sopenharmony_ci * @kcontrol: referred ctl element
209262306a36Sopenharmony_ci * @uinfo: pointer to get/store the data
209362306a36Sopenharmony_ci *
209462306a36Sopenharmony_ci * The control element is supposed to have the private_value field
209562306a36Sopenharmony_ci * set up via HDA_COMPOSE_AMP_VAL*() or related macros.
209662306a36Sopenharmony_ci */
209762306a36Sopenharmony_ciint snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol,
209862306a36Sopenharmony_ci				  struct snd_ctl_elem_info *uinfo)
209962306a36Sopenharmony_ci{
210062306a36Sopenharmony_ci	int chs = get_amp_channels(kcontrol);
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
210362306a36Sopenharmony_ci	uinfo->count = chs == 3 ? 2 : 1;
210462306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
210562306a36Sopenharmony_ci	uinfo->value.integer.max = 1;
210662306a36Sopenharmony_ci	return 0;
210762306a36Sopenharmony_ci}
210862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_info);
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci/**
211162306a36Sopenharmony_ci * snd_hda_mixer_amp_switch_get - Get callback for a standard AMP mixer switch
211262306a36Sopenharmony_ci * @kcontrol: ctl element
211362306a36Sopenharmony_ci * @ucontrol: pointer to get/store the data
211462306a36Sopenharmony_ci *
211562306a36Sopenharmony_ci * The control element is supposed to have the private_value field
211662306a36Sopenharmony_ci * set up via HDA_COMPOSE_AMP_VAL*() or related macros.
211762306a36Sopenharmony_ci */
211862306a36Sopenharmony_ciint snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol,
211962306a36Sopenharmony_ci				 struct snd_ctl_elem_value *ucontrol)
212062306a36Sopenharmony_ci{
212162306a36Sopenharmony_ci	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
212262306a36Sopenharmony_ci	hda_nid_t nid = get_amp_nid(kcontrol);
212362306a36Sopenharmony_ci	int chs = get_amp_channels(kcontrol);
212462306a36Sopenharmony_ci	int dir = get_amp_direction(kcontrol);
212562306a36Sopenharmony_ci	int idx = get_amp_index(kcontrol);
212662306a36Sopenharmony_ci	long *valp = ucontrol->value.integer.value;
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci	if (chs & 1)
212962306a36Sopenharmony_ci		*valp++ = (snd_hda_codec_amp_read(codec, nid, 0, dir, idx) &
213062306a36Sopenharmony_ci			   HDA_AMP_MUTE) ? 0 : 1;
213162306a36Sopenharmony_ci	if (chs & 2)
213262306a36Sopenharmony_ci		*valp = (snd_hda_codec_amp_read(codec, nid, 1, dir, idx) &
213362306a36Sopenharmony_ci			 HDA_AMP_MUTE) ? 0 : 1;
213462306a36Sopenharmony_ci	return 0;
213562306a36Sopenharmony_ci}
213662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_get);
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci/**
213962306a36Sopenharmony_ci * snd_hda_mixer_amp_switch_put - Put callback for a standard AMP mixer switch
214062306a36Sopenharmony_ci * @kcontrol: ctl element
214162306a36Sopenharmony_ci * @ucontrol: pointer to get/store the data
214262306a36Sopenharmony_ci *
214362306a36Sopenharmony_ci * The control element is supposed to have the private_value field
214462306a36Sopenharmony_ci * set up via HDA_COMPOSE_AMP_VAL*() or related macros.
214562306a36Sopenharmony_ci */
214662306a36Sopenharmony_ciint snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
214762306a36Sopenharmony_ci				 struct snd_ctl_elem_value *ucontrol)
214862306a36Sopenharmony_ci{
214962306a36Sopenharmony_ci	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
215062306a36Sopenharmony_ci	hda_nid_t nid = get_amp_nid(kcontrol);
215162306a36Sopenharmony_ci	int chs = get_amp_channels(kcontrol);
215262306a36Sopenharmony_ci	int dir = get_amp_direction(kcontrol);
215362306a36Sopenharmony_ci	int idx = get_amp_index(kcontrol);
215462306a36Sopenharmony_ci	long *valp = ucontrol->value.integer.value;
215562306a36Sopenharmony_ci	int change = 0;
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	if (chs & 1) {
215862306a36Sopenharmony_ci		change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
215962306a36Sopenharmony_ci						  HDA_AMP_MUTE,
216062306a36Sopenharmony_ci						  *valp ? 0 : HDA_AMP_MUTE);
216162306a36Sopenharmony_ci		valp++;
216262306a36Sopenharmony_ci	}
216362306a36Sopenharmony_ci	if (chs & 2)
216462306a36Sopenharmony_ci		change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
216562306a36Sopenharmony_ci						   HDA_AMP_MUTE,
216662306a36Sopenharmony_ci						   *valp ? 0 : HDA_AMP_MUTE);
216762306a36Sopenharmony_ci	hda_call_check_power_status(codec, nid);
216862306a36Sopenharmony_ci	return change;
216962306a36Sopenharmony_ci}
217062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put);
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci/*
217362306a36Sopenharmony_ci * SPDIF out controls
217462306a36Sopenharmony_ci */
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_cistatic int snd_hda_spdif_mask_info(struct snd_kcontrol *kcontrol,
217762306a36Sopenharmony_ci				   struct snd_ctl_elem_info *uinfo)
217862306a36Sopenharmony_ci{
217962306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
218062306a36Sopenharmony_ci	uinfo->count = 1;
218162306a36Sopenharmony_ci	return 0;
218262306a36Sopenharmony_ci}
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_cistatic int snd_hda_spdif_cmask_get(struct snd_kcontrol *kcontrol,
218562306a36Sopenharmony_ci				   struct snd_ctl_elem_value *ucontrol)
218662306a36Sopenharmony_ci{
218762306a36Sopenharmony_ci	ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL |
218862306a36Sopenharmony_ci					   IEC958_AES0_NONAUDIO |
218962306a36Sopenharmony_ci					   IEC958_AES0_CON_EMPHASIS_5015 |
219062306a36Sopenharmony_ci					   IEC958_AES0_CON_NOT_COPYRIGHT;
219162306a36Sopenharmony_ci	ucontrol->value.iec958.status[1] = IEC958_AES1_CON_CATEGORY |
219262306a36Sopenharmony_ci					   IEC958_AES1_CON_ORIGINAL;
219362306a36Sopenharmony_ci	return 0;
219462306a36Sopenharmony_ci}
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_cistatic int snd_hda_spdif_pmask_get(struct snd_kcontrol *kcontrol,
219762306a36Sopenharmony_ci				   struct snd_ctl_elem_value *ucontrol)
219862306a36Sopenharmony_ci{
219962306a36Sopenharmony_ci	ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL |
220062306a36Sopenharmony_ci					   IEC958_AES0_NONAUDIO |
220162306a36Sopenharmony_ci					   IEC958_AES0_PRO_EMPHASIS_5015;
220262306a36Sopenharmony_ci	return 0;
220362306a36Sopenharmony_ci}
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_cistatic int snd_hda_spdif_default_get(struct snd_kcontrol *kcontrol,
220662306a36Sopenharmony_ci				     struct snd_ctl_elem_value *ucontrol)
220762306a36Sopenharmony_ci{
220862306a36Sopenharmony_ci	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
220962306a36Sopenharmony_ci	int idx = kcontrol->private_value;
221062306a36Sopenharmony_ci	struct hda_spdif_out *spdif;
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci	if (WARN_ON(codec->spdif_out.used <= idx))
221362306a36Sopenharmony_ci		return -EINVAL;
221462306a36Sopenharmony_ci	mutex_lock(&codec->spdif_mutex);
221562306a36Sopenharmony_ci	spdif = snd_array_elem(&codec->spdif_out, idx);
221662306a36Sopenharmony_ci	ucontrol->value.iec958.status[0] = spdif->status & 0xff;
221762306a36Sopenharmony_ci	ucontrol->value.iec958.status[1] = (spdif->status >> 8) & 0xff;
221862306a36Sopenharmony_ci	ucontrol->value.iec958.status[2] = (spdif->status >> 16) & 0xff;
221962306a36Sopenharmony_ci	ucontrol->value.iec958.status[3] = (spdif->status >> 24) & 0xff;
222062306a36Sopenharmony_ci	mutex_unlock(&codec->spdif_mutex);
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	return 0;
222362306a36Sopenharmony_ci}
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci/* convert from SPDIF status bits to HDA SPDIF bits
222662306a36Sopenharmony_ci * bit 0 (DigEn) is always set zero (to be filled later)
222762306a36Sopenharmony_ci */
222862306a36Sopenharmony_cistatic unsigned short convert_from_spdif_status(unsigned int sbits)
222962306a36Sopenharmony_ci{
223062306a36Sopenharmony_ci	unsigned short val = 0;
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci	if (sbits & IEC958_AES0_PROFESSIONAL)
223362306a36Sopenharmony_ci		val |= AC_DIG1_PROFESSIONAL;
223462306a36Sopenharmony_ci	if (sbits & IEC958_AES0_NONAUDIO)
223562306a36Sopenharmony_ci		val |= AC_DIG1_NONAUDIO;
223662306a36Sopenharmony_ci	if (sbits & IEC958_AES0_PROFESSIONAL) {
223762306a36Sopenharmony_ci		if ((sbits & IEC958_AES0_PRO_EMPHASIS) ==
223862306a36Sopenharmony_ci		    IEC958_AES0_PRO_EMPHASIS_5015)
223962306a36Sopenharmony_ci			val |= AC_DIG1_EMPHASIS;
224062306a36Sopenharmony_ci	} else {
224162306a36Sopenharmony_ci		if ((sbits & IEC958_AES0_CON_EMPHASIS) ==
224262306a36Sopenharmony_ci		    IEC958_AES0_CON_EMPHASIS_5015)
224362306a36Sopenharmony_ci			val |= AC_DIG1_EMPHASIS;
224462306a36Sopenharmony_ci		if (!(sbits & IEC958_AES0_CON_NOT_COPYRIGHT))
224562306a36Sopenharmony_ci			val |= AC_DIG1_COPYRIGHT;
224662306a36Sopenharmony_ci		if (sbits & (IEC958_AES1_CON_ORIGINAL << 8))
224762306a36Sopenharmony_ci			val |= AC_DIG1_LEVEL;
224862306a36Sopenharmony_ci		val |= sbits & (IEC958_AES1_CON_CATEGORY << 8);
224962306a36Sopenharmony_ci	}
225062306a36Sopenharmony_ci	return val;
225162306a36Sopenharmony_ci}
225262306a36Sopenharmony_ci
225362306a36Sopenharmony_ci/* convert to SPDIF status bits from HDA SPDIF bits
225462306a36Sopenharmony_ci */
225562306a36Sopenharmony_cistatic unsigned int convert_to_spdif_status(unsigned short val)
225662306a36Sopenharmony_ci{
225762306a36Sopenharmony_ci	unsigned int sbits = 0;
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci	if (val & AC_DIG1_NONAUDIO)
226062306a36Sopenharmony_ci		sbits |= IEC958_AES0_NONAUDIO;
226162306a36Sopenharmony_ci	if (val & AC_DIG1_PROFESSIONAL)
226262306a36Sopenharmony_ci		sbits |= IEC958_AES0_PROFESSIONAL;
226362306a36Sopenharmony_ci	if (sbits & IEC958_AES0_PROFESSIONAL) {
226462306a36Sopenharmony_ci		if (val & AC_DIG1_EMPHASIS)
226562306a36Sopenharmony_ci			sbits |= IEC958_AES0_PRO_EMPHASIS_5015;
226662306a36Sopenharmony_ci	} else {
226762306a36Sopenharmony_ci		if (val & AC_DIG1_EMPHASIS)
226862306a36Sopenharmony_ci			sbits |= IEC958_AES0_CON_EMPHASIS_5015;
226962306a36Sopenharmony_ci		if (!(val & AC_DIG1_COPYRIGHT))
227062306a36Sopenharmony_ci			sbits |= IEC958_AES0_CON_NOT_COPYRIGHT;
227162306a36Sopenharmony_ci		if (val & AC_DIG1_LEVEL)
227262306a36Sopenharmony_ci			sbits |= (IEC958_AES1_CON_ORIGINAL << 8);
227362306a36Sopenharmony_ci		sbits |= val & (0x7f << 8);
227462306a36Sopenharmony_ci	}
227562306a36Sopenharmony_ci	return sbits;
227662306a36Sopenharmony_ci}
227762306a36Sopenharmony_ci
227862306a36Sopenharmony_ci/* set digital convert verbs both for the given NID and its followers */
227962306a36Sopenharmony_cistatic void set_dig_out(struct hda_codec *codec, hda_nid_t nid,
228062306a36Sopenharmony_ci			int mask, int val)
228162306a36Sopenharmony_ci{
228262306a36Sopenharmony_ci	const hda_nid_t *d;
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	snd_hdac_regmap_update(&codec->core, nid, AC_VERB_SET_DIGI_CONVERT_1,
228562306a36Sopenharmony_ci			       mask, val);
228662306a36Sopenharmony_ci	d = codec->follower_dig_outs;
228762306a36Sopenharmony_ci	if (!d)
228862306a36Sopenharmony_ci		return;
228962306a36Sopenharmony_ci	for (; *d; d++)
229062306a36Sopenharmony_ci		snd_hdac_regmap_update(&codec->core, *d,
229162306a36Sopenharmony_ci				       AC_VERB_SET_DIGI_CONVERT_1, mask, val);
229262306a36Sopenharmony_ci}
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_cistatic inline void set_dig_out_convert(struct hda_codec *codec, hda_nid_t nid,
229562306a36Sopenharmony_ci				       int dig1, int dig2)
229662306a36Sopenharmony_ci{
229762306a36Sopenharmony_ci	unsigned int mask = 0;
229862306a36Sopenharmony_ci	unsigned int val = 0;
229962306a36Sopenharmony_ci
230062306a36Sopenharmony_ci	if (dig1 != -1) {
230162306a36Sopenharmony_ci		mask |= 0xff;
230262306a36Sopenharmony_ci		val = dig1;
230362306a36Sopenharmony_ci	}
230462306a36Sopenharmony_ci	if (dig2 != -1) {
230562306a36Sopenharmony_ci		mask |= 0xff00;
230662306a36Sopenharmony_ci		val |= dig2 << 8;
230762306a36Sopenharmony_ci	}
230862306a36Sopenharmony_ci	set_dig_out(codec, nid, mask, val);
230962306a36Sopenharmony_ci}
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_cistatic int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
231262306a36Sopenharmony_ci				     struct snd_ctl_elem_value *ucontrol)
231362306a36Sopenharmony_ci{
231462306a36Sopenharmony_ci	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
231562306a36Sopenharmony_ci	int idx = kcontrol->private_value;
231662306a36Sopenharmony_ci	struct hda_spdif_out *spdif;
231762306a36Sopenharmony_ci	hda_nid_t nid;
231862306a36Sopenharmony_ci	unsigned short val;
231962306a36Sopenharmony_ci	int change;
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci	if (WARN_ON(codec->spdif_out.used <= idx))
232262306a36Sopenharmony_ci		return -EINVAL;
232362306a36Sopenharmony_ci	mutex_lock(&codec->spdif_mutex);
232462306a36Sopenharmony_ci	spdif = snd_array_elem(&codec->spdif_out, idx);
232562306a36Sopenharmony_ci	nid = spdif->nid;
232662306a36Sopenharmony_ci	spdif->status = ucontrol->value.iec958.status[0] |
232762306a36Sopenharmony_ci		((unsigned int)ucontrol->value.iec958.status[1] << 8) |
232862306a36Sopenharmony_ci		((unsigned int)ucontrol->value.iec958.status[2] << 16) |
232962306a36Sopenharmony_ci		((unsigned int)ucontrol->value.iec958.status[3] << 24);
233062306a36Sopenharmony_ci	val = convert_from_spdif_status(spdif->status);
233162306a36Sopenharmony_ci	val |= spdif->ctls & 1;
233262306a36Sopenharmony_ci	change = spdif->ctls != val;
233362306a36Sopenharmony_ci	spdif->ctls = val;
233462306a36Sopenharmony_ci	if (change && nid != (u16)-1)
233562306a36Sopenharmony_ci		set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff);
233662306a36Sopenharmony_ci	mutex_unlock(&codec->spdif_mutex);
233762306a36Sopenharmony_ci	return change;
233862306a36Sopenharmony_ci}
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci#define snd_hda_spdif_out_switch_info	snd_ctl_boolean_mono_info
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_cistatic int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol,
234362306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
234462306a36Sopenharmony_ci{
234562306a36Sopenharmony_ci	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
234662306a36Sopenharmony_ci	int idx = kcontrol->private_value;
234762306a36Sopenharmony_ci	struct hda_spdif_out *spdif;
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_ci	if (WARN_ON(codec->spdif_out.used <= idx))
235062306a36Sopenharmony_ci		return -EINVAL;
235162306a36Sopenharmony_ci	mutex_lock(&codec->spdif_mutex);
235262306a36Sopenharmony_ci	spdif = snd_array_elem(&codec->spdif_out, idx);
235362306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = spdif->ctls & AC_DIG1_ENABLE;
235462306a36Sopenharmony_ci	mutex_unlock(&codec->spdif_mutex);
235562306a36Sopenharmony_ci	return 0;
235662306a36Sopenharmony_ci}
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_cistatic inline void set_spdif_ctls(struct hda_codec *codec, hda_nid_t nid,
235962306a36Sopenharmony_ci				  int dig1, int dig2)
236062306a36Sopenharmony_ci{
236162306a36Sopenharmony_ci	set_dig_out_convert(codec, nid, dig1, dig2);
236262306a36Sopenharmony_ci	/* unmute amp switch (if any) */
236362306a36Sopenharmony_ci	if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
236462306a36Sopenharmony_ci	    (dig1 & AC_DIG1_ENABLE))
236562306a36Sopenharmony_ci		snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
236662306a36Sopenharmony_ci					    HDA_AMP_MUTE, 0);
236762306a36Sopenharmony_ci}
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_cistatic int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
237062306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
237162306a36Sopenharmony_ci{
237262306a36Sopenharmony_ci	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
237362306a36Sopenharmony_ci	int idx = kcontrol->private_value;
237462306a36Sopenharmony_ci	struct hda_spdif_out *spdif;
237562306a36Sopenharmony_ci	hda_nid_t nid;
237662306a36Sopenharmony_ci	unsigned short val;
237762306a36Sopenharmony_ci	int change;
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	if (WARN_ON(codec->spdif_out.used <= idx))
238062306a36Sopenharmony_ci		return -EINVAL;
238162306a36Sopenharmony_ci	mutex_lock(&codec->spdif_mutex);
238262306a36Sopenharmony_ci	spdif = snd_array_elem(&codec->spdif_out, idx);
238362306a36Sopenharmony_ci	nid = spdif->nid;
238462306a36Sopenharmony_ci	val = spdif->ctls & ~AC_DIG1_ENABLE;
238562306a36Sopenharmony_ci	if (ucontrol->value.integer.value[0])
238662306a36Sopenharmony_ci		val |= AC_DIG1_ENABLE;
238762306a36Sopenharmony_ci	change = spdif->ctls != val;
238862306a36Sopenharmony_ci	spdif->ctls = val;
238962306a36Sopenharmony_ci	if (change && nid != (u16)-1)
239062306a36Sopenharmony_ci		set_spdif_ctls(codec, nid, val & 0xff, -1);
239162306a36Sopenharmony_ci	mutex_unlock(&codec->spdif_mutex);
239262306a36Sopenharmony_ci	return change;
239362306a36Sopenharmony_ci}
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_cistatic const struct snd_kcontrol_new dig_mixes[] = {
239662306a36Sopenharmony_ci	{
239762306a36Sopenharmony_ci		.access = SNDRV_CTL_ELEM_ACCESS_READ,
239862306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
239962306a36Sopenharmony_ci		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
240062306a36Sopenharmony_ci		.info = snd_hda_spdif_mask_info,
240162306a36Sopenharmony_ci		.get = snd_hda_spdif_cmask_get,
240262306a36Sopenharmony_ci	},
240362306a36Sopenharmony_ci	{
240462306a36Sopenharmony_ci		.access = SNDRV_CTL_ELEM_ACCESS_READ,
240562306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
240662306a36Sopenharmony_ci		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK),
240762306a36Sopenharmony_ci		.info = snd_hda_spdif_mask_info,
240862306a36Sopenharmony_ci		.get = snd_hda_spdif_pmask_get,
240962306a36Sopenharmony_ci	},
241062306a36Sopenharmony_ci	{
241162306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
241262306a36Sopenharmony_ci		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
241362306a36Sopenharmony_ci		.info = snd_hda_spdif_mask_info,
241462306a36Sopenharmony_ci		.get = snd_hda_spdif_default_get,
241562306a36Sopenharmony_ci		.put = snd_hda_spdif_default_put,
241662306a36Sopenharmony_ci	},
241762306a36Sopenharmony_ci	{
241862306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
241962306a36Sopenharmony_ci		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH),
242062306a36Sopenharmony_ci		.info = snd_hda_spdif_out_switch_info,
242162306a36Sopenharmony_ci		.get = snd_hda_spdif_out_switch_get,
242262306a36Sopenharmony_ci		.put = snd_hda_spdif_out_switch_put,
242362306a36Sopenharmony_ci	},
242462306a36Sopenharmony_ci	{ } /* end */
242562306a36Sopenharmony_ci};
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_ci/**
242862306a36Sopenharmony_ci * snd_hda_create_dig_out_ctls - create Output SPDIF-related controls
242962306a36Sopenharmony_ci * @codec: the HDA codec
243062306a36Sopenharmony_ci * @associated_nid: NID that new ctls associated with
243162306a36Sopenharmony_ci * @cvt_nid: converter NID
243262306a36Sopenharmony_ci * @type: HDA_PCM_TYPE_*
243362306a36Sopenharmony_ci * Creates controls related with the digital output.
243462306a36Sopenharmony_ci * Called from each patch supporting the digital out.
243562306a36Sopenharmony_ci *
243662306a36Sopenharmony_ci * Returns 0 if successful, or a negative error code.
243762306a36Sopenharmony_ci */
243862306a36Sopenharmony_ciint snd_hda_create_dig_out_ctls(struct hda_codec *codec,
243962306a36Sopenharmony_ci				hda_nid_t associated_nid,
244062306a36Sopenharmony_ci				hda_nid_t cvt_nid,
244162306a36Sopenharmony_ci				int type)
244262306a36Sopenharmony_ci{
244362306a36Sopenharmony_ci	int err;
244462306a36Sopenharmony_ci	struct snd_kcontrol *kctl;
244562306a36Sopenharmony_ci	const struct snd_kcontrol_new *dig_mix;
244662306a36Sopenharmony_ci	int idx = 0;
244762306a36Sopenharmony_ci	int val = 0;
244862306a36Sopenharmony_ci	const int spdif_index = 16;
244962306a36Sopenharmony_ci	struct hda_spdif_out *spdif;
245062306a36Sopenharmony_ci	struct hda_bus *bus = codec->bus;
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci	if (bus->primary_dig_out_type == HDA_PCM_TYPE_HDMI &&
245362306a36Sopenharmony_ci	    type == HDA_PCM_TYPE_SPDIF) {
245462306a36Sopenharmony_ci		idx = spdif_index;
245562306a36Sopenharmony_ci	} else if (bus->primary_dig_out_type == HDA_PCM_TYPE_SPDIF &&
245662306a36Sopenharmony_ci		   type == HDA_PCM_TYPE_HDMI) {
245762306a36Sopenharmony_ci		/* suppose a single SPDIF device */
245862306a36Sopenharmony_ci		for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {
245962306a36Sopenharmony_ci			struct snd_ctl_elem_id id;
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci			kctl = find_mixer_ctl(codec, dig_mix->name, 0, 0);
246262306a36Sopenharmony_ci			if (!kctl)
246362306a36Sopenharmony_ci				break;
246462306a36Sopenharmony_ci			id = kctl->id;
246562306a36Sopenharmony_ci			id.index = spdif_index;
246662306a36Sopenharmony_ci			snd_ctl_rename_id(codec->card, &kctl->id, &id);
246762306a36Sopenharmony_ci		}
246862306a36Sopenharmony_ci		bus->primary_dig_out_type = HDA_PCM_TYPE_HDMI;
246962306a36Sopenharmony_ci	}
247062306a36Sopenharmony_ci	if (!bus->primary_dig_out_type)
247162306a36Sopenharmony_ci		bus->primary_dig_out_type = type;
247262306a36Sopenharmony_ci
247362306a36Sopenharmony_ci	idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch", idx);
247462306a36Sopenharmony_ci	if (idx < 0) {
247562306a36Sopenharmony_ci		codec_err(codec, "too many IEC958 outputs\n");
247662306a36Sopenharmony_ci		return -EBUSY;
247762306a36Sopenharmony_ci	}
247862306a36Sopenharmony_ci	spdif = snd_array_new(&codec->spdif_out);
247962306a36Sopenharmony_ci	if (!spdif)
248062306a36Sopenharmony_ci		return -ENOMEM;
248162306a36Sopenharmony_ci	for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {
248262306a36Sopenharmony_ci		kctl = snd_ctl_new1(dig_mix, codec);
248362306a36Sopenharmony_ci		if (!kctl)
248462306a36Sopenharmony_ci			return -ENOMEM;
248562306a36Sopenharmony_ci		kctl->id.index = idx;
248662306a36Sopenharmony_ci		kctl->private_value = codec->spdif_out.used - 1;
248762306a36Sopenharmony_ci		err = snd_hda_ctl_add(codec, associated_nid, kctl);
248862306a36Sopenharmony_ci		if (err < 0)
248962306a36Sopenharmony_ci			return err;
249062306a36Sopenharmony_ci	}
249162306a36Sopenharmony_ci	spdif->nid = cvt_nid;
249262306a36Sopenharmony_ci	snd_hdac_regmap_read(&codec->core, cvt_nid,
249362306a36Sopenharmony_ci			     AC_VERB_GET_DIGI_CONVERT_1, &val);
249462306a36Sopenharmony_ci	spdif->ctls = val;
249562306a36Sopenharmony_ci	spdif->status = convert_to_spdif_status(spdif->ctls);
249662306a36Sopenharmony_ci	return 0;
249762306a36Sopenharmony_ci}
249862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_create_dig_out_ctls);
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_ci/**
250162306a36Sopenharmony_ci * snd_hda_spdif_out_of_nid - get the hda_spdif_out entry from the given NID
250262306a36Sopenharmony_ci * @codec: the HDA codec
250362306a36Sopenharmony_ci * @nid: widget NID
250462306a36Sopenharmony_ci *
250562306a36Sopenharmony_ci * call within spdif_mutex lock
250662306a36Sopenharmony_ci */
250762306a36Sopenharmony_cistruct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
250862306a36Sopenharmony_ci					       hda_nid_t nid)
250962306a36Sopenharmony_ci{
251062306a36Sopenharmony_ci	struct hda_spdif_out *spdif;
251162306a36Sopenharmony_ci	int i;
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_ci	snd_array_for_each(&codec->spdif_out, i, spdif) {
251462306a36Sopenharmony_ci		if (spdif->nid == nid)
251562306a36Sopenharmony_ci			return spdif;
251662306a36Sopenharmony_ci	}
251762306a36Sopenharmony_ci	return NULL;
251862306a36Sopenharmony_ci}
251962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_spdif_out_of_nid);
252062306a36Sopenharmony_ci
252162306a36Sopenharmony_ci/**
252262306a36Sopenharmony_ci * snd_hda_spdif_ctls_unassign - Unassign the given SPDIF ctl
252362306a36Sopenharmony_ci * @codec: the HDA codec
252462306a36Sopenharmony_ci * @idx: the SPDIF ctl index
252562306a36Sopenharmony_ci *
252662306a36Sopenharmony_ci * Unassign the widget from the given SPDIF control.
252762306a36Sopenharmony_ci */
252862306a36Sopenharmony_civoid snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx)
252962306a36Sopenharmony_ci{
253062306a36Sopenharmony_ci	struct hda_spdif_out *spdif;
253162306a36Sopenharmony_ci
253262306a36Sopenharmony_ci	if (WARN_ON(codec->spdif_out.used <= idx))
253362306a36Sopenharmony_ci		return;
253462306a36Sopenharmony_ci	mutex_lock(&codec->spdif_mutex);
253562306a36Sopenharmony_ci	spdif = snd_array_elem(&codec->spdif_out, idx);
253662306a36Sopenharmony_ci	spdif->nid = (u16)-1;
253762306a36Sopenharmony_ci	mutex_unlock(&codec->spdif_mutex);
253862306a36Sopenharmony_ci}
253962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_spdif_ctls_unassign);
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci/**
254262306a36Sopenharmony_ci * snd_hda_spdif_ctls_assign - Assign the SPDIF controls to the given NID
254362306a36Sopenharmony_ci * @codec: the HDA codec
254462306a36Sopenharmony_ci * @idx: the SPDIF ctl idx
254562306a36Sopenharmony_ci * @nid: widget NID
254662306a36Sopenharmony_ci *
254762306a36Sopenharmony_ci * Assign the widget to the SPDIF control with the given index.
254862306a36Sopenharmony_ci */
254962306a36Sopenharmony_civoid snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid)
255062306a36Sopenharmony_ci{
255162306a36Sopenharmony_ci	struct hda_spdif_out *spdif;
255262306a36Sopenharmony_ci	unsigned short val;
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci	if (WARN_ON(codec->spdif_out.used <= idx))
255562306a36Sopenharmony_ci		return;
255662306a36Sopenharmony_ci	mutex_lock(&codec->spdif_mutex);
255762306a36Sopenharmony_ci	spdif = snd_array_elem(&codec->spdif_out, idx);
255862306a36Sopenharmony_ci	if (spdif->nid != nid) {
255962306a36Sopenharmony_ci		spdif->nid = nid;
256062306a36Sopenharmony_ci		val = spdif->ctls;
256162306a36Sopenharmony_ci		set_spdif_ctls(codec, nid, val & 0xff, (val >> 8) & 0xff);
256262306a36Sopenharmony_ci	}
256362306a36Sopenharmony_ci	mutex_unlock(&codec->spdif_mutex);
256462306a36Sopenharmony_ci}
256562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_spdif_ctls_assign);
256662306a36Sopenharmony_ci
256762306a36Sopenharmony_ci/*
256862306a36Sopenharmony_ci * SPDIF sharing with analog output
256962306a36Sopenharmony_ci */
257062306a36Sopenharmony_cistatic int spdif_share_sw_get(struct snd_kcontrol *kcontrol,
257162306a36Sopenharmony_ci			      struct snd_ctl_elem_value *ucontrol)
257262306a36Sopenharmony_ci{
257362306a36Sopenharmony_ci	struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol);
257462306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = mout->share_spdif;
257562306a36Sopenharmony_ci	return 0;
257662306a36Sopenharmony_ci}
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_cistatic int spdif_share_sw_put(struct snd_kcontrol *kcontrol,
257962306a36Sopenharmony_ci			      struct snd_ctl_elem_value *ucontrol)
258062306a36Sopenharmony_ci{
258162306a36Sopenharmony_ci	struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol);
258262306a36Sopenharmony_ci	mout->share_spdif = !!ucontrol->value.integer.value[0];
258362306a36Sopenharmony_ci	return 0;
258462306a36Sopenharmony_ci}
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_cistatic const struct snd_kcontrol_new spdif_share_sw = {
258762306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
258862306a36Sopenharmony_ci	.name = "IEC958 Default PCM Playback Switch",
258962306a36Sopenharmony_ci	.info = snd_ctl_boolean_mono_info,
259062306a36Sopenharmony_ci	.get = spdif_share_sw_get,
259162306a36Sopenharmony_ci	.put = spdif_share_sw_put,
259262306a36Sopenharmony_ci};
259362306a36Sopenharmony_ci
259462306a36Sopenharmony_ci/**
259562306a36Sopenharmony_ci * snd_hda_create_spdif_share_sw - create Default PCM switch
259662306a36Sopenharmony_ci * @codec: the HDA codec
259762306a36Sopenharmony_ci * @mout: multi-out instance
259862306a36Sopenharmony_ci */
259962306a36Sopenharmony_ciint snd_hda_create_spdif_share_sw(struct hda_codec *codec,
260062306a36Sopenharmony_ci				  struct hda_multi_out *mout)
260162306a36Sopenharmony_ci{
260262306a36Sopenharmony_ci	struct snd_kcontrol *kctl;
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ci	if (!mout->dig_out_nid)
260562306a36Sopenharmony_ci		return 0;
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_ci	kctl = snd_ctl_new1(&spdif_share_sw, mout);
260862306a36Sopenharmony_ci	if (!kctl)
260962306a36Sopenharmony_ci		return -ENOMEM;
261062306a36Sopenharmony_ci	/* ATTENTION: here mout is passed as private_data, instead of codec */
261162306a36Sopenharmony_ci	return snd_hda_ctl_add(codec, mout->dig_out_nid, kctl);
261262306a36Sopenharmony_ci}
261362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_create_spdif_share_sw);
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci/*
261662306a36Sopenharmony_ci * SPDIF input
261762306a36Sopenharmony_ci */
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci#define snd_hda_spdif_in_switch_info	snd_hda_spdif_out_switch_info
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_cistatic int snd_hda_spdif_in_switch_get(struct snd_kcontrol *kcontrol,
262262306a36Sopenharmony_ci				       struct snd_ctl_elem_value *ucontrol)
262362306a36Sopenharmony_ci{
262462306a36Sopenharmony_ci	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
262562306a36Sopenharmony_ci
262662306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = codec->spdif_in_enable;
262762306a36Sopenharmony_ci	return 0;
262862306a36Sopenharmony_ci}
262962306a36Sopenharmony_ci
263062306a36Sopenharmony_cistatic int snd_hda_spdif_in_switch_put(struct snd_kcontrol *kcontrol,
263162306a36Sopenharmony_ci				       struct snd_ctl_elem_value *ucontrol)
263262306a36Sopenharmony_ci{
263362306a36Sopenharmony_ci	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
263462306a36Sopenharmony_ci	hda_nid_t nid = kcontrol->private_value;
263562306a36Sopenharmony_ci	unsigned int val = !!ucontrol->value.integer.value[0];
263662306a36Sopenharmony_ci	int change;
263762306a36Sopenharmony_ci
263862306a36Sopenharmony_ci	mutex_lock(&codec->spdif_mutex);
263962306a36Sopenharmony_ci	change = codec->spdif_in_enable != val;
264062306a36Sopenharmony_ci	if (change) {
264162306a36Sopenharmony_ci		codec->spdif_in_enable = val;
264262306a36Sopenharmony_ci		snd_hdac_regmap_write(&codec->core, nid,
264362306a36Sopenharmony_ci				      AC_VERB_SET_DIGI_CONVERT_1, val);
264462306a36Sopenharmony_ci	}
264562306a36Sopenharmony_ci	mutex_unlock(&codec->spdif_mutex);
264662306a36Sopenharmony_ci	return change;
264762306a36Sopenharmony_ci}
264862306a36Sopenharmony_ci
264962306a36Sopenharmony_cistatic int snd_hda_spdif_in_status_get(struct snd_kcontrol *kcontrol,
265062306a36Sopenharmony_ci				       struct snd_ctl_elem_value *ucontrol)
265162306a36Sopenharmony_ci{
265262306a36Sopenharmony_ci	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
265362306a36Sopenharmony_ci	hda_nid_t nid = kcontrol->private_value;
265462306a36Sopenharmony_ci	unsigned int val;
265562306a36Sopenharmony_ci	unsigned int sbits;
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci	snd_hdac_regmap_read(&codec->core, nid,
265862306a36Sopenharmony_ci			     AC_VERB_GET_DIGI_CONVERT_1, &val);
265962306a36Sopenharmony_ci	sbits = convert_to_spdif_status(val);
266062306a36Sopenharmony_ci	ucontrol->value.iec958.status[0] = sbits;
266162306a36Sopenharmony_ci	ucontrol->value.iec958.status[1] = sbits >> 8;
266262306a36Sopenharmony_ci	ucontrol->value.iec958.status[2] = sbits >> 16;
266362306a36Sopenharmony_ci	ucontrol->value.iec958.status[3] = sbits >> 24;
266462306a36Sopenharmony_ci	return 0;
266562306a36Sopenharmony_ci}
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_cistatic const struct snd_kcontrol_new dig_in_ctls[] = {
266862306a36Sopenharmony_ci	{
266962306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
267062306a36Sopenharmony_ci		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, SWITCH),
267162306a36Sopenharmony_ci		.info = snd_hda_spdif_in_switch_info,
267262306a36Sopenharmony_ci		.get = snd_hda_spdif_in_switch_get,
267362306a36Sopenharmony_ci		.put = snd_hda_spdif_in_switch_put,
267462306a36Sopenharmony_ci	},
267562306a36Sopenharmony_ci	{
267662306a36Sopenharmony_ci		.access = SNDRV_CTL_ELEM_ACCESS_READ,
267762306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
267862306a36Sopenharmony_ci		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
267962306a36Sopenharmony_ci		.info = snd_hda_spdif_mask_info,
268062306a36Sopenharmony_ci		.get = snd_hda_spdif_in_status_get,
268162306a36Sopenharmony_ci	},
268262306a36Sopenharmony_ci	{ } /* end */
268362306a36Sopenharmony_ci};
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_ci/**
268662306a36Sopenharmony_ci * snd_hda_create_spdif_in_ctls - create Input SPDIF-related controls
268762306a36Sopenharmony_ci * @codec: the HDA codec
268862306a36Sopenharmony_ci * @nid: audio in widget NID
268962306a36Sopenharmony_ci *
269062306a36Sopenharmony_ci * Creates controls related with the SPDIF input.
269162306a36Sopenharmony_ci * Called from each patch supporting the SPDIF in.
269262306a36Sopenharmony_ci *
269362306a36Sopenharmony_ci * Returns 0 if successful, or a negative error code.
269462306a36Sopenharmony_ci */
269562306a36Sopenharmony_ciint snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
269662306a36Sopenharmony_ci{
269762306a36Sopenharmony_ci	int err;
269862306a36Sopenharmony_ci	struct snd_kcontrol *kctl;
269962306a36Sopenharmony_ci	const struct snd_kcontrol_new *dig_mix;
270062306a36Sopenharmony_ci	int idx;
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_ci	idx = find_empty_mixer_ctl_idx(codec, "IEC958 Capture Switch", 0);
270362306a36Sopenharmony_ci	if (idx < 0) {
270462306a36Sopenharmony_ci		codec_err(codec, "too many IEC958 inputs\n");
270562306a36Sopenharmony_ci		return -EBUSY;
270662306a36Sopenharmony_ci	}
270762306a36Sopenharmony_ci	for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) {
270862306a36Sopenharmony_ci		kctl = snd_ctl_new1(dig_mix, codec);
270962306a36Sopenharmony_ci		if (!kctl)
271062306a36Sopenharmony_ci			return -ENOMEM;
271162306a36Sopenharmony_ci		kctl->private_value = nid;
271262306a36Sopenharmony_ci		err = snd_hda_ctl_add(codec, nid, kctl);
271362306a36Sopenharmony_ci		if (err < 0)
271462306a36Sopenharmony_ci			return err;
271562306a36Sopenharmony_ci	}
271662306a36Sopenharmony_ci	codec->spdif_in_enable =
271762306a36Sopenharmony_ci		snd_hda_codec_read(codec, nid, 0,
271862306a36Sopenharmony_ci				   AC_VERB_GET_DIGI_CONVERT_1, 0) &
271962306a36Sopenharmony_ci		AC_DIG1_ENABLE;
272062306a36Sopenharmony_ci	return 0;
272162306a36Sopenharmony_ci}
272262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_create_spdif_in_ctls);
272362306a36Sopenharmony_ci
272462306a36Sopenharmony_ci/**
272562306a36Sopenharmony_ci * snd_hda_codec_set_power_to_all - Set the power state to all widgets
272662306a36Sopenharmony_ci * @codec: the HDA codec
272762306a36Sopenharmony_ci * @fg: function group (not used now)
272862306a36Sopenharmony_ci * @power_state: the power state to set (AC_PWRST_*)
272962306a36Sopenharmony_ci *
273062306a36Sopenharmony_ci * Set the given power state to all widgets that have the power control.
273162306a36Sopenharmony_ci * If the codec has power_filter set, it evaluates the power state and
273262306a36Sopenharmony_ci * filter out if it's unchanged as D3.
273362306a36Sopenharmony_ci */
273462306a36Sopenharmony_civoid snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
273562306a36Sopenharmony_ci				    unsigned int power_state)
273662306a36Sopenharmony_ci{
273762306a36Sopenharmony_ci	hda_nid_t nid;
273862306a36Sopenharmony_ci
273962306a36Sopenharmony_ci	for_each_hda_codec_node(nid, codec) {
274062306a36Sopenharmony_ci		unsigned int wcaps = get_wcaps(codec, nid);
274162306a36Sopenharmony_ci		unsigned int state = power_state;
274262306a36Sopenharmony_ci		if (!(wcaps & AC_WCAP_POWER))
274362306a36Sopenharmony_ci			continue;
274462306a36Sopenharmony_ci		if (codec->power_filter) {
274562306a36Sopenharmony_ci			state = codec->power_filter(codec, nid, power_state);
274662306a36Sopenharmony_ci			if (state != power_state && power_state == AC_PWRST_D3)
274762306a36Sopenharmony_ci				continue;
274862306a36Sopenharmony_ci		}
274962306a36Sopenharmony_ci		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
275062306a36Sopenharmony_ci				    state);
275162306a36Sopenharmony_ci	}
275262306a36Sopenharmony_ci}
275362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_set_power_to_all);
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_ci/**
275662306a36Sopenharmony_ci * snd_hda_codec_eapd_power_filter - A power filter callback for EAPD
275762306a36Sopenharmony_ci * @codec: the HDA codec
275862306a36Sopenharmony_ci * @nid: widget NID
275962306a36Sopenharmony_ci * @power_state: power state to evalue
276062306a36Sopenharmony_ci *
276162306a36Sopenharmony_ci * Don't power down the widget if it controls eapd and EAPD_BTLENABLE is set.
276262306a36Sopenharmony_ci * This can be used a codec power_filter callback.
276362306a36Sopenharmony_ci */
276462306a36Sopenharmony_ciunsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
276562306a36Sopenharmony_ci					     hda_nid_t nid,
276662306a36Sopenharmony_ci					     unsigned int power_state)
276762306a36Sopenharmony_ci{
276862306a36Sopenharmony_ci	if (nid == codec->core.afg || nid == codec->core.mfg)
276962306a36Sopenharmony_ci		return power_state;
277062306a36Sopenharmony_ci	if (power_state == AC_PWRST_D3 &&
277162306a36Sopenharmony_ci	    get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_PIN &&
277262306a36Sopenharmony_ci	    (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) {
277362306a36Sopenharmony_ci		int eapd = snd_hda_codec_read(codec, nid, 0,
277462306a36Sopenharmony_ci					      AC_VERB_GET_EAPD_BTLENABLE, 0);
277562306a36Sopenharmony_ci		if (eapd & 0x02)
277662306a36Sopenharmony_ci			return AC_PWRST_D0;
277762306a36Sopenharmony_ci	}
277862306a36Sopenharmony_ci	return power_state;
277962306a36Sopenharmony_ci}
278062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_eapd_power_filter);
278162306a36Sopenharmony_ci
278262306a36Sopenharmony_ci/*
278362306a36Sopenharmony_ci * set power state of the codec, and return the power state
278462306a36Sopenharmony_ci */
278562306a36Sopenharmony_cistatic unsigned int hda_set_power_state(struct hda_codec *codec,
278662306a36Sopenharmony_ci					unsigned int power_state)
278762306a36Sopenharmony_ci{
278862306a36Sopenharmony_ci	hda_nid_t fg = codec->core.afg ? codec->core.afg : codec->core.mfg;
278962306a36Sopenharmony_ci	int count;
279062306a36Sopenharmony_ci	unsigned int state;
279162306a36Sopenharmony_ci	int flags = 0;
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_ci	/* this delay seems necessary to avoid click noise at power-down */
279462306a36Sopenharmony_ci	if (power_state == AC_PWRST_D3) {
279562306a36Sopenharmony_ci		if (codec->depop_delay < 0)
279662306a36Sopenharmony_ci			msleep(codec_has_epss(codec) ? 10 : 100);
279762306a36Sopenharmony_ci		else if (codec->depop_delay > 0)
279862306a36Sopenharmony_ci			msleep(codec->depop_delay);
279962306a36Sopenharmony_ci		flags = HDA_RW_NO_RESPONSE_FALLBACK;
280062306a36Sopenharmony_ci	}
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci	/* repeat power states setting at most 10 times*/
280362306a36Sopenharmony_ci	for (count = 0; count < 10; count++) {
280462306a36Sopenharmony_ci		if (codec->patch_ops.set_power_state)
280562306a36Sopenharmony_ci			codec->patch_ops.set_power_state(codec, fg,
280662306a36Sopenharmony_ci							 power_state);
280762306a36Sopenharmony_ci		else {
280862306a36Sopenharmony_ci			state = power_state;
280962306a36Sopenharmony_ci			if (codec->power_filter)
281062306a36Sopenharmony_ci				state = codec->power_filter(codec, fg, state);
281162306a36Sopenharmony_ci			if (state == power_state || power_state != AC_PWRST_D3)
281262306a36Sopenharmony_ci				snd_hda_codec_read(codec, fg, flags,
281362306a36Sopenharmony_ci						   AC_VERB_SET_POWER_STATE,
281462306a36Sopenharmony_ci						   state);
281562306a36Sopenharmony_ci			snd_hda_codec_set_power_to_all(codec, fg, power_state);
281662306a36Sopenharmony_ci		}
281762306a36Sopenharmony_ci		state = snd_hda_sync_power_state(codec, fg, power_state);
281862306a36Sopenharmony_ci		if (!(state & AC_PWRST_ERROR))
281962306a36Sopenharmony_ci			break;
282062306a36Sopenharmony_ci	}
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_ci	return state;
282362306a36Sopenharmony_ci}
282462306a36Sopenharmony_ci
282562306a36Sopenharmony_ci/* sync power states of all widgets;
282662306a36Sopenharmony_ci * this is called at the end of codec parsing
282762306a36Sopenharmony_ci */
282862306a36Sopenharmony_cistatic void sync_power_up_states(struct hda_codec *codec)
282962306a36Sopenharmony_ci{
283062306a36Sopenharmony_ci	hda_nid_t nid;
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_ci	/* don't care if no filter is used */
283362306a36Sopenharmony_ci	if (!codec->power_filter)
283462306a36Sopenharmony_ci		return;
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_ci	for_each_hda_codec_node(nid, codec) {
283762306a36Sopenharmony_ci		unsigned int wcaps = get_wcaps(codec, nid);
283862306a36Sopenharmony_ci		unsigned int target;
283962306a36Sopenharmony_ci		if (!(wcaps & AC_WCAP_POWER))
284062306a36Sopenharmony_ci			continue;
284162306a36Sopenharmony_ci		target = codec->power_filter(codec, nid, AC_PWRST_D0);
284262306a36Sopenharmony_ci		if (target == AC_PWRST_D0)
284362306a36Sopenharmony_ci			continue;
284462306a36Sopenharmony_ci		if (!snd_hda_check_power_state(codec, nid, target))
284562306a36Sopenharmony_ci			snd_hda_codec_write(codec, nid, 0,
284662306a36Sopenharmony_ci					    AC_VERB_SET_POWER_STATE, target);
284762306a36Sopenharmony_ci	}
284862306a36Sopenharmony_ci}
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci#ifdef CONFIG_SND_HDA_RECONFIG
285162306a36Sopenharmony_ci/* execute additional init verbs */
285262306a36Sopenharmony_cistatic void hda_exec_init_verbs(struct hda_codec *codec)
285362306a36Sopenharmony_ci{
285462306a36Sopenharmony_ci	if (codec->init_verbs.list)
285562306a36Sopenharmony_ci		snd_hda_sequence_write(codec, codec->init_verbs.list);
285662306a36Sopenharmony_ci}
285762306a36Sopenharmony_ci#else
285862306a36Sopenharmony_cistatic inline void hda_exec_init_verbs(struct hda_codec *codec) {}
285962306a36Sopenharmony_ci#endif
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci#ifdef CONFIG_PM
286262306a36Sopenharmony_ci/* update the power on/off account with the current jiffies */
286362306a36Sopenharmony_cistatic void update_power_acct(struct hda_codec *codec, bool on)
286462306a36Sopenharmony_ci{
286562306a36Sopenharmony_ci	unsigned long delta = jiffies - codec->power_jiffies;
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_ci	if (on)
286862306a36Sopenharmony_ci		codec->power_on_acct += delta;
286962306a36Sopenharmony_ci	else
287062306a36Sopenharmony_ci		codec->power_off_acct += delta;
287162306a36Sopenharmony_ci	codec->power_jiffies += delta;
287262306a36Sopenharmony_ci}
287362306a36Sopenharmony_ci
287462306a36Sopenharmony_civoid snd_hda_update_power_acct(struct hda_codec *codec)
287562306a36Sopenharmony_ci{
287662306a36Sopenharmony_ci	update_power_acct(codec, hda_codec_is_power_on(codec));
287762306a36Sopenharmony_ci}
287862306a36Sopenharmony_ci
287962306a36Sopenharmony_ci/*
288062306a36Sopenharmony_ci * call suspend and power-down; used both from PM and power-save
288162306a36Sopenharmony_ci * this function returns the power state in the end
288262306a36Sopenharmony_ci */
288362306a36Sopenharmony_cistatic unsigned int hda_call_codec_suspend(struct hda_codec *codec)
288462306a36Sopenharmony_ci{
288562306a36Sopenharmony_ci	unsigned int state;
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci	snd_hdac_enter_pm(&codec->core);
288862306a36Sopenharmony_ci	if (codec->patch_ops.suspend)
288962306a36Sopenharmony_ci		codec->patch_ops.suspend(codec);
289062306a36Sopenharmony_ci	if (!codec->no_stream_clean_at_suspend)
289162306a36Sopenharmony_ci		hda_cleanup_all_streams(codec);
289262306a36Sopenharmony_ci	state = hda_set_power_state(codec, AC_PWRST_D3);
289362306a36Sopenharmony_ci	update_power_acct(codec, true);
289462306a36Sopenharmony_ci	snd_hdac_leave_pm(&codec->core);
289562306a36Sopenharmony_ci	return state;
289662306a36Sopenharmony_ci}
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_ci/*
289962306a36Sopenharmony_ci * kick up codec; used both from PM and power-save
290062306a36Sopenharmony_ci */
290162306a36Sopenharmony_cistatic void hda_call_codec_resume(struct hda_codec *codec)
290262306a36Sopenharmony_ci{
290362306a36Sopenharmony_ci	snd_hdac_enter_pm(&codec->core);
290462306a36Sopenharmony_ci	if (codec->core.regmap)
290562306a36Sopenharmony_ci		regcache_mark_dirty(codec->core.regmap);
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_ci	codec->power_jiffies = jiffies;
290862306a36Sopenharmony_ci
290962306a36Sopenharmony_ci	hda_set_power_state(codec, AC_PWRST_D0);
291062306a36Sopenharmony_ci	restore_shutup_pins(codec);
291162306a36Sopenharmony_ci	hda_exec_init_verbs(codec);
291262306a36Sopenharmony_ci	snd_hda_jack_set_dirty_all(codec);
291362306a36Sopenharmony_ci	if (codec->patch_ops.resume)
291462306a36Sopenharmony_ci		codec->patch_ops.resume(codec);
291562306a36Sopenharmony_ci	else {
291662306a36Sopenharmony_ci		if (codec->patch_ops.init)
291762306a36Sopenharmony_ci			codec->patch_ops.init(codec);
291862306a36Sopenharmony_ci		snd_hda_regmap_sync(codec);
291962306a36Sopenharmony_ci	}
292062306a36Sopenharmony_ci
292162306a36Sopenharmony_ci	if (codec->jackpoll_interval)
292262306a36Sopenharmony_ci		hda_jackpoll_work(&codec->jackpoll_work.work);
292362306a36Sopenharmony_ci	else
292462306a36Sopenharmony_ci		snd_hda_jack_report_sync(codec);
292562306a36Sopenharmony_ci	codec->core.dev.power.power_state = PMSG_ON;
292662306a36Sopenharmony_ci	snd_hdac_leave_pm(&codec->core);
292762306a36Sopenharmony_ci}
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_cistatic int hda_codec_runtime_suspend(struct device *dev)
293062306a36Sopenharmony_ci{
293162306a36Sopenharmony_ci	struct hda_codec *codec = dev_to_hda_codec(dev);
293262306a36Sopenharmony_ci	unsigned int state;
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci	/* Nothing to do if card registration fails and the component driver never probes */
293562306a36Sopenharmony_ci	if (!codec->card)
293662306a36Sopenharmony_ci		return 0;
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci	cancel_delayed_work_sync(&codec->jackpoll_work);
293962306a36Sopenharmony_ci
294062306a36Sopenharmony_ci	state = hda_call_codec_suspend(codec);
294162306a36Sopenharmony_ci	if (codec->link_down_at_suspend ||
294262306a36Sopenharmony_ci	    (codec_has_clkstop(codec) && codec_has_epss(codec) &&
294362306a36Sopenharmony_ci	     (state & AC_PWRST_CLK_STOP_OK)))
294462306a36Sopenharmony_ci		snd_hdac_codec_link_down(&codec->core);
294562306a36Sopenharmony_ci	snd_hda_codec_display_power(codec, false);
294662306a36Sopenharmony_ci
294762306a36Sopenharmony_ci	if (codec->bus->jackpoll_in_suspend &&
294862306a36Sopenharmony_ci		(dev->power.power_state.event != PM_EVENT_SUSPEND))
294962306a36Sopenharmony_ci		schedule_delayed_work(&codec->jackpoll_work,
295062306a36Sopenharmony_ci					codec->jackpoll_interval);
295162306a36Sopenharmony_ci	return 0;
295262306a36Sopenharmony_ci}
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_cistatic int hda_codec_runtime_resume(struct device *dev)
295562306a36Sopenharmony_ci{
295662306a36Sopenharmony_ci	struct hda_codec *codec = dev_to_hda_codec(dev);
295762306a36Sopenharmony_ci
295862306a36Sopenharmony_ci	/* Nothing to do if card registration fails and the component driver never probes */
295962306a36Sopenharmony_ci	if (!codec->card)
296062306a36Sopenharmony_ci		return 0;
296162306a36Sopenharmony_ci
296262306a36Sopenharmony_ci	snd_hda_codec_display_power(codec, true);
296362306a36Sopenharmony_ci	snd_hdac_codec_link_up(&codec->core);
296462306a36Sopenharmony_ci	hda_call_codec_resume(codec);
296562306a36Sopenharmony_ci	pm_runtime_mark_last_busy(dev);
296662306a36Sopenharmony_ci	return 0;
296762306a36Sopenharmony_ci}
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_ci#endif /* CONFIG_PM */
297062306a36Sopenharmony_ci
297162306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
297262306a36Sopenharmony_cistatic int hda_codec_pm_prepare(struct device *dev)
297362306a36Sopenharmony_ci{
297462306a36Sopenharmony_ci	struct hda_codec *codec = dev_to_hda_codec(dev);
297562306a36Sopenharmony_ci
297662306a36Sopenharmony_ci	cancel_delayed_work_sync(&codec->jackpoll_work);
297762306a36Sopenharmony_ci	dev->power.power_state = PMSG_SUSPEND;
297862306a36Sopenharmony_ci	return pm_runtime_suspended(dev);
297962306a36Sopenharmony_ci}
298062306a36Sopenharmony_ci
298162306a36Sopenharmony_cistatic void hda_codec_pm_complete(struct device *dev)
298262306a36Sopenharmony_ci{
298362306a36Sopenharmony_ci	struct hda_codec *codec = dev_to_hda_codec(dev);
298462306a36Sopenharmony_ci
298562306a36Sopenharmony_ci	/* If no other pm-functions are called between prepare() and complete() */
298662306a36Sopenharmony_ci	if (dev->power.power_state.event == PM_EVENT_SUSPEND)
298762306a36Sopenharmony_ci		dev->power.power_state = PMSG_RESUME;
298862306a36Sopenharmony_ci
298962306a36Sopenharmony_ci	if (pm_runtime_suspended(dev) && (codec->jackpoll_interval ||
299062306a36Sopenharmony_ci	    hda_codec_need_resume(codec) || codec->forced_resume))
299162306a36Sopenharmony_ci		pm_request_resume(dev);
299262306a36Sopenharmony_ci}
299362306a36Sopenharmony_ci
299462306a36Sopenharmony_cistatic int hda_codec_pm_suspend(struct device *dev)
299562306a36Sopenharmony_ci{
299662306a36Sopenharmony_ci	dev->power.power_state = PMSG_SUSPEND;
299762306a36Sopenharmony_ci	return pm_runtime_force_suspend(dev);
299862306a36Sopenharmony_ci}
299962306a36Sopenharmony_ci
300062306a36Sopenharmony_cistatic int hda_codec_pm_resume(struct device *dev)
300162306a36Sopenharmony_ci{
300262306a36Sopenharmony_ci	dev->power.power_state = PMSG_RESUME;
300362306a36Sopenharmony_ci	return pm_runtime_force_resume(dev);
300462306a36Sopenharmony_ci}
300562306a36Sopenharmony_ci
300662306a36Sopenharmony_cistatic int hda_codec_pm_freeze(struct device *dev)
300762306a36Sopenharmony_ci{
300862306a36Sopenharmony_ci	struct hda_codec *codec = dev_to_hda_codec(dev);
300962306a36Sopenharmony_ci
301062306a36Sopenharmony_ci	cancel_delayed_work_sync(&codec->jackpoll_work);
301162306a36Sopenharmony_ci	dev->power.power_state = PMSG_FREEZE;
301262306a36Sopenharmony_ci	return pm_runtime_force_suspend(dev);
301362306a36Sopenharmony_ci}
301462306a36Sopenharmony_ci
301562306a36Sopenharmony_cistatic int hda_codec_pm_thaw(struct device *dev)
301662306a36Sopenharmony_ci{
301762306a36Sopenharmony_ci	dev->power.power_state = PMSG_THAW;
301862306a36Sopenharmony_ci	return pm_runtime_force_resume(dev);
301962306a36Sopenharmony_ci}
302062306a36Sopenharmony_ci
302162306a36Sopenharmony_cistatic int hda_codec_pm_restore(struct device *dev)
302262306a36Sopenharmony_ci{
302362306a36Sopenharmony_ci	dev->power.power_state = PMSG_RESTORE;
302462306a36Sopenharmony_ci	return pm_runtime_force_resume(dev);
302562306a36Sopenharmony_ci}
302662306a36Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */
302762306a36Sopenharmony_ci
302862306a36Sopenharmony_ci/* referred in hda_bind.c */
302962306a36Sopenharmony_ciconst struct dev_pm_ops hda_codec_driver_pm = {
303062306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
303162306a36Sopenharmony_ci	.prepare = hda_codec_pm_prepare,
303262306a36Sopenharmony_ci	.complete = hda_codec_pm_complete,
303362306a36Sopenharmony_ci	.suspend = hda_codec_pm_suspend,
303462306a36Sopenharmony_ci	.resume = hda_codec_pm_resume,
303562306a36Sopenharmony_ci	.freeze = hda_codec_pm_freeze,
303662306a36Sopenharmony_ci	.thaw = hda_codec_pm_thaw,
303762306a36Sopenharmony_ci	.poweroff = hda_codec_pm_suspend,
303862306a36Sopenharmony_ci	.restore = hda_codec_pm_restore,
303962306a36Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */
304062306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(hda_codec_runtime_suspend, hda_codec_runtime_resume,
304162306a36Sopenharmony_ci			   NULL)
304262306a36Sopenharmony_ci};
304362306a36Sopenharmony_ci
304462306a36Sopenharmony_ci/* suspend the codec at shutdown; called from driver's shutdown callback */
304562306a36Sopenharmony_civoid snd_hda_codec_shutdown(struct hda_codec *codec)
304662306a36Sopenharmony_ci{
304762306a36Sopenharmony_ci	struct hda_pcm *cpcm;
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_ci	/* Skip the shutdown if codec is not registered */
305062306a36Sopenharmony_ci	if (!codec->core.registered)
305162306a36Sopenharmony_ci		return;
305262306a36Sopenharmony_ci
305362306a36Sopenharmony_ci	cancel_delayed_work_sync(&codec->jackpoll_work);
305462306a36Sopenharmony_ci	list_for_each_entry(cpcm, &codec->pcm_list_head, list)
305562306a36Sopenharmony_ci		snd_pcm_suspend_all(cpcm->pcm);
305662306a36Sopenharmony_ci
305762306a36Sopenharmony_ci	pm_runtime_force_suspend(hda_codec_dev(codec));
305862306a36Sopenharmony_ci	pm_runtime_disable(hda_codec_dev(codec));
305962306a36Sopenharmony_ci}
306062306a36Sopenharmony_ci
306162306a36Sopenharmony_ci/*
306262306a36Sopenharmony_ci * add standard channel maps if not specified
306362306a36Sopenharmony_ci */
306462306a36Sopenharmony_cistatic int add_std_chmaps(struct hda_codec *codec)
306562306a36Sopenharmony_ci{
306662306a36Sopenharmony_ci	struct hda_pcm *pcm;
306762306a36Sopenharmony_ci	int str, err;
306862306a36Sopenharmony_ci
306962306a36Sopenharmony_ci	list_for_each_entry(pcm, &codec->pcm_list_head, list) {
307062306a36Sopenharmony_ci		for (str = 0; str < 2; str++) {
307162306a36Sopenharmony_ci			struct hda_pcm_stream *hinfo = &pcm->stream[str];
307262306a36Sopenharmony_ci			struct snd_pcm_chmap *chmap;
307362306a36Sopenharmony_ci			const struct snd_pcm_chmap_elem *elem;
307462306a36Sopenharmony_ci
307562306a36Sopenharmony_ci			if (!pcm->pcm || pcm->own_chmap || !hinfo->substreams)
307662306a36Sopenharmony_ci				continue;
307762306a36Sopenharmony_ci			elem = hinfo->chmap ? hinfo->chmap : snd_pcm_std_chmaps;
307862306a36Sopenharmony_ci			err = snd_pcm_add_chmap_ctls(pcm->pcm, str, elem,
307962306a36Sopenharmony_ci						     hinfo->channels_max,
308062306a36Sopenharmony_ci						     0, &chmap);
308162306a36Sopenharmony_ci			if (err < 0)
308262306a36Sopenharmony_ci				return err;
308362306a36Sopenharmony_ci			chmap->channel_mask = SND_PCM_CHMAP_MASK_2468;
308462306a36Sopenharmony_ci		}
308562306a36Sopenharmony_ci	}
308662306a36Sopenharmony_ci	return 0;
308762306a36Sopenharmony_ci}
308862306a36Sopenharmony_ci
308962306a36Sopenharmony_ci/* default channel maps for 2.1 speakers;
309062306a36Sopenharmony_ci * since HD-audio supports only stereo, odd number channels are omitted
309162306a36Sopenharmony_ci */
309262306a36Sopenharmony_ciconst struct snd_pcm_chmap_elem snd_pcm_2_1_chmaps[] = {
309362306a36Sopenharmony_ci	{ .channels = 2,
309462306a36Sopenharmony_ci	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
309562306a36Sopenharmony_ci	{ .channels = 4,
309662306a36Sopenharmony_ci	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
309762306a36Sopenharmony_ci		   SNDRV_CHMAP_LFE, SNDRV_CHMAP_LFE } },
309862306a36Sopenharmony_ci	{ }
309962306a36Sopenharmony_ci};
310062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_pcm_2_1_chmaps);
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ciint snd_hda_codec_build_controls(struct hda_codec *codec)
310362306a36Sopenharmony_ci{
310462306a36Sopenharmony_ci	int err = 0;
310562306a36Sopenharmony_ci	hda_exec_init_verbs(codec);
310662306a36Sopenharmony_ci	/* continue to initialize... */
310762306a36Sopenharmony_ci	if (codec->patch_ops.init)
310862306a36Sopenharmony_ci		err = codec->patch_ops.init(codec);
310962306a36Sopenharmony_ci	if (!err && codec->patch_ops.build_controls)
311062306a36Sopenharmony_ci		err = codec->patch_ops.build_controls(codec);
311162306a36Sopenharmony_ci	if (err < 0)
311262306a36Sopenharmony_ci		return err;
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_ci	/* we create chmaps here instead of build_pcms */
311562306a36Sopenharmony_ci	err = add_std_chmaps(codec);
311662306a36Sopenharmony_ci	if (err < 0)
311762306a36Sopenharmony_ci		return err;
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci	if (codec->jackpoll_interval)
312062306a36Sopenharmony_ci		hda_jackpoll_work(&codec->jackpoll_work.work);
312162306a36Sopenharmony_ci	else
312262306a36Sopenharmony_ci		snd_hda_jack_report_sync(codec); /* call at the last init point */
312362306a36Sopenharmony_ci	sync_power_up_states(codec);
312462306a36Sopenharmony_ci	return 0;
312562306a36Sopenharmony_ci}
312662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_build_controls);
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_ci/*
312962306a36Sopenharmony_ci * PCM stuff
313062306a36Sopenharmony_ci */
313162306a36Sopenharmony_cistatic int hda_pcm_default_open_close(struct hda_pcm_stream *hinfo,
313262306a36Sopenharmony_ci				      struct hda_codec *codec,
313362306a36Sopenharmony_ci				      struct snd_pcm_substream *substream)
313462306a36Sopenharmony_ci{
313562306a36Sopenharmony_ci	return 0;
313662306a36Sopenharmony_ci}
313762306a36Sopenharmony_ci
313862306a36Sopenharmony_cistatic int hda_pcm_default_prepare(struct hda_pcm_stream *hinfo,
313962306a36Sopenharmony_ci				   struct hda_codec *codec,
314062306a36Sopenharmony_ci				   unsigned int stream_tag,
314162306a36Sopenharmony_ci				   unsigned int format,
314262306a36Sopenharmony_ci				   struct snd_pcm_substream *substream)
314362306a36Sopenharmony_ci{
314462306a36Sopenharmony_ci	snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
314562306a36Sopenharmony_ci	return 0;
314662306a36Sopenharmony_ci}
314762306a36Sopenharmony_ci
314862306a36Sopenharmony_cistatic int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo,
314962306a36Sopenharmony_ci				   struct hda_codec *codec,
315062306a36Sopenharmony_ci				   struct snd_pcm_substream *substream)
315162306a36Sopenharmony_ci{
315262306a36Sopenharmony_ci	snd_hda_codec_cleanup_stream(codec, hinfo->nid);
315362306a36Sopenharmony_ci	return 0;
315462306a36Sopenharmony_ci}
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_cistatic int set_pcm_default_values(struct hda_codec *codec,
315762306a36Sopenharmony_ci				  struct hda_pcm_stream *info)
315862306a36Sopenharmony_ci{
315962306a36Sopenharmony_ci	int err;
316062306a36Sopenharmony_ci
316162306a36Sopenharmony_ci	/* query support PCM information from the given NID */
316262306a36Sopenharmony_ci	if (info->nid && (!info->rates || !info->formats)) {
316362306a36Sopenharmony_ci		err = snd_hda_query_supported_pcm(codec, info->nid,
316462306a36Sopenharmony_ci				info->rates ? NULL : &info->rates,
316562306a36Sopenharmony_ci				info->formats ? NULL : &info->formats,
316662306a36Sopenharmony_ci				info->maxbps ? NULL : &info->maxbps);
316762306a36Sopenharmony_ci		if (err < 0)
316862306a36Sopenharmony_ci			return err;
316962306a36Sopenharmony_ci	}
317062306a36Sopenharmony_ci	if (info->ops.open == NULL)
317162306a36Sopenharmony_ci		info->ops.open = hda_pcm_default_open_close;
317262306a36Sopenharmony_ci	if (info->ops.close == NULL)
317362306a36Sopenharmony_ci		info->ops.close = hda_pcm_default_open_close;
317462306a36Sopenharmony_ci	if (info->ops.prepare == NULL) {
317562306a36Sopenharmony_ci		if (snd_BUG_ON(!info->nid))
317662306a36Sopenharmony_ci			return -EINVAL;
317762306a36Sopenharmony_ci		info->ops.prepare = hda_pcm_default_prepare;
317862306a36Sopenharmony_ci	}
317962306a36Sopenharmony_ci	if (info->ops.cleanup == NULL) {
318062306a36Sopenharmony_ci		if (snd_BUG_ON(!info->nid))
318162306a36Sopenharmony_ci			return -EINVAL;
318262306a36Sopenharmony_ci		info->ops.cleanup = hda_pcm_default_cleanup;
318362306a36Sopenharmony_ci	}
318462306a36Sopenharmony_ci	return 0;
318562306a36Sopenharmony_ci}
318662306a36Sopenharmony_ci
318762306a36Sopenharmony_ci/*
318862306a36Sopenharmony_ci * codec prepare/cleanup entries
318962306a36Sopenharmony_ci */
319062306a36Sopenharmony_ci/**
319162306a36Sopenharmony_ci * snd_hda_codec_prepare - Prepare a stream
319262306a36Sopenharmony_ci * @codec: the HDA codec
319362306a36Sopenharmony_ci * @hinfo: PCM information
319462306a36Sopenharmony_ci * @stream: stream tag to assign
319562306a36Sopenharmony_ci * @format: format id to assign
319662306a36Sopenharmony_ci * @substream: PCM substream to assign
319762306a36Sopenharmony_ci *
319862306a36Sopenharmony_ci * Calls the prepare callback set by the codec with the given arguments.
319962306a36Sopenharmony_ci * Clean up the inactive streams when successful.
320062306a36Sopenharmony_ci */
320162306a36Sopenharmony_ciint snd_hda_codec_prepare(struct hda_codec *codec,
320262306a36Sopenharmony_ci			  struct hda_pcm_stream *hinfo,
320362306a36Sopenharmony_ci			  unsigned int stream,
320462306a36Sopenharmony_ci			  unsigned int format,
320562306a36Sopenharmony_ci			  struct snd_pcm_substream *substream)
320662306a36Sopenharmony_ci{
320762306a36Sopenharmony_ci	int ret;
320862306a36Sopenharmony_ci	mutex_lock(&codec->bus->prepare_mutex);
320962306a36Sopenharmony_ci	if (hinfo->ops.prepare)
321062306a36Sopenharmony_ci		ret = hinfo->ops.prepare(hinfo, codec, stream, format,
321162306a36Sopenharmony_ci					 substream);
321262306a36Sopenharmony_ci	else
321362306a36Sopenharmony_ci		ret = -ENODEV;
321462306a36Sopenharmony_ci	if (ret >= 0)
321562306a36Sopenharmony_ci		purify_inactive_streams(codec);
321662306a36Sopenharmony_ci	mutex_unlock(&codec->bus->prepare_mutex);
321762306a36Sopenharmony_ci	return ret;
321862306a36Sopenharmony_ci}
321962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_prepare);
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci/**
322262306a36Sopenharmony_ci * snd_hda_codec_cleanup - Clean up stream resources
322362306a36Sopenharmony_ci * @codec: the HDA codec
322462306a36Sopenharmony_ci * @hinfo: PCM information
322562306a36Sopenharmony_ci * @substream: PCM substream
322662306a36Sopenharmony_ci *
322762306a36Sopenharmony_ci * Calls the cleanup callback set by the codec with the given arguments.
322862306a36Sopenharmony_ci */
322962306a36Sopenharmony_civoid snd_hda_codec_cleanup(struct hda_codec *codec,
323062306a36Sopenharmony_ci			   struct hda_pcm_stream *hinfo,
323162306a36Sopenharmony_ci			   struct snd_pcm_substream *substream)
323262306a36Sopenharmony_ci{
323362306a36Sopenharmony_ci	mutex_lock(&codec->bus->prepare_mutex);
323462306a36Sopenharmony_ci	if (hinfo->ops.cleanup)
323562306a36Sopenharmony_ci		hinfo->ops.cleanup(hinfo, codec, substream);
323662306a36Sopenharmony_ci	mutex_unlock(&codec->bus->prepare_mutex);
323762306a36Sopenharmony_ci}
323862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_cleanup);
323962306a36Sopenharmony_ci
324062306a36Sopenharmony_ci/* global */
324162306a36Sopenharmony_ciconst char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = {
324262306a36Sopenharmony_ci	"Audio", "SPDIF", "HDMI", "Modem"
324362306a36Sopenharmony_ci};
324462306a36Sopenharmony_ci
324562306a36Sopenharmony_ci/*
324662306a36Sopenharmony_ci * get the empty PCM device number to assign
324762306a36Sopenharmony_ci */
324862306a36Sopenharmony_cistatic int get_empty_pcm_device(struct hda_bus *bus, unsigned int type)
324962306a36Sopenharmony_ci{
325062306a36Sopenharmony_ci	/* audio device indices; not linear to keep compatibility */
325162306a36Sopenharmony_ci	/* assigned to static slots up to dev#10; if more needed, assign
325262306a36Sopenharmony_ci	 * the later slot dynamically (when CONFIG_SND_DYNAMIC_MINORS=y)
325362306a36Sopenharmony_ci	 */
325462306a36Sopenharmony_ci	static const int audio_idx[HDA_PCM_NTYPES][5] = {
325562306a36Sopenharmony_ci		[HDA_PCM_TYPE_AUDIO] = { 0, 2, 4, 5, -1 },
325662306a36Sopenharmony_ci		[HDA_PCM_TYPE_SPDIF] = { 1, -1 },
325762306a36Sopenharmony_ci		[HDA_PCM_TYPE_HDMI]  = { 3, 7, 8, 9, -1 },
325862306a36Sopenharmony_ci		[HDA_PCM_TYPE_MODEM] = { 6, -1 },
325962306a36Sopenharmony_ci	};
326062306a36Sopenharmony_ci	int i;
326162306a36Sopenharmony_ci
326262306a36Sopenharmony_ci	if (type >= HDA_PCM_NTYPES) {
326362306a36Sopenharmony_ci		dev_err(bus->card->dev, "Invalid PCM type %d\n", type);
326462306a36Sopenharmony_ci		return -EINVAL;
326562306a36Sopenharmony_ci	}
326662306a36Sopenharmony_ci
326762306a36Sopenharmony_ci	for (i = 0; audio_idx[type][i] >= 0; i++) {
326862306a36Sopenharmony_ci#ifndef CONFIG_SND_DYNAMIC_MINORS
326962306a36Sopenharmony_ci		if (audio_idx[type][i] >= 8)
327062306a36Sopenharmony_ci			break;
327162306a36Sopenharmony_ci#endif
327262306a36Sopenharmony_ci		if (!test_and_set_bit(audio_idx[type][i], bus->pcm_dev_bits))
327362306a36Sopenharmony_ci			return audio_idx[type][i];
327462306a36Sopenharmony_ci	}
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_ci#ifdef CONFIG_SND_DYNAMIC_MINORS
327762306a36Sopenharmony_ci	/* non-fixed slots starting from 10 */
327862306a36Sopenharmony_ci	for (i = 10; i < 32; i++) {
327962306a36Sopenharmony_ci		if (!test_and_set_bit(i, bus->pcm_dev_bits))
328062306a36Sopenharmony_ci			return i;
328162306a36Sopenharmony_ci	}
328262306a36Sopenharmony_ci#endif
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_ci	dev_warn(bus->card->dev, "Too many %s devices\n",
328562306a36Sopenharmony_ci		snd_hda_pcm_type_name[type]);
328662306a36Sopenharmony_ci#ifndef CONFIG_SND_DYNAMIC_MINORS
328762306a36Sopenharmony_ci	dev_warn(bus->card->dev,
328862306a36Sopenharmony_ci		 "Consider building the kernel with CONFIG_SND_DYNAMIC_MINORS=y\n");
328962306a36Sopenharmony_ci#endif
329062306a36Sopenharmony_ci	return -EAGAIN;
329162306a36Sopenharmony_ci}
329262306a36Sopenharmony_ci
329362306a36Sopenharmony_ci/* call build_pcms ops of the given codec and set up the default parameters */
329462306a36Sopenharmony_ciint snd_hda_codec_parse_pcms(struct hda_codec *codec)
329562306a36Sopenharmony_ci{
329662306a36Sopenharmony_ci	struct hda_pcm *cpcm;
329762306a36Sopenharmony_ci	int err;
329862306a36Sopenharmony_ci
329962306a36Sopenharmony_ci	if (!list_empty(&codec->pcm_list_head))
330062306a36Sopenharmony_ci		return 0; /* already parsed */
330162306a36Sopenharmony_ci
330262306a36Sopenharmony_ci	if (!codec->patch_ops.build_pcms)
330362306a36Sopenharmony_ci		return 0;
330462306a36Sopenharmony_ci
330562306a36Sopenharmony_ci	err = codec->patch_ops.build_pcms(codec);
330662306a36Sopenharmony_ci	if (err < 0) {
330762306a36Sopenharmony_ci		codec_err(codec, "cannot build PCMs for #%d (error %d)\n",
330862306a36Sopenharmony_ci			  codec->core.addr, err);
330962306a36Sopenharmony_ci		return err;
331062306a36Sopenharmony_ci	}
331162306a36Sopenharmony_ci
331262306a36Sopenharmony_ci	list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
331362306a36Sopenharmony_ci		int stream;
331462306a36Sopenharmony_ci
331562306a36Sopenharmony_ci		for (stream = 0; stream < 2; stream++) {
331662306a36Sopenharmony_ci			struct hda_pcm_stream *info = &cpcm->stream[stream];
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_ci			if (!info->substreams)
331962306a36Sopenharmony_ci				continue;
332062306a36Sopenharmony_ci			err = set_pcm_default_values(codec, info);
332162306a36Sopenharmony_ci			if (err < 0) {
332262306a36Sopenharmony_ci				codec_warn(codec,
332362306a36Sopenharmony_ci					   "fail to setup default for PCM %s\n",
332462306a36Sopenharmony_ci					   cpcm->name);
332562306a36Sopenharmony_ci				return err;
332662306a36Sopenharmony_ci			}
332762306a36Sopenharmony_ci		}
332862306a36Sopenharmony_ci	}
332962306a36Sopenharmony_ci
333062306a36Sopenharmony_ci	return 0;
333162306a36Sopenharmony_ci}
333262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_parse_pcms);
333362306a36Sopenharmony_ci
333462306a36Sopenharmony_ci/* assign all PCMs of the given codec */
333562306a36Sopenharmony_ciint snd_hda_codec_build_pcms(struct hda_codec *codec)
333662306a36Sopenharmony_ci{
333762306a36Sopenharmony_ci	struct hda_bus *bus = codec->bus;
333862306a36Sopenharmony_ci	struct hda_pcm *cpcm;
333962306a36Sopenharmony_ci	int dev, err;
334062306a36Sopenharmony_ci
334162306a36Sopenharmony_ci	err = snd_hda_codec_parse_pcms(codec);
334262306a36Sopenharmony_ci	if (err < 0)
334362306a36Sopenharmony_ci		return err;
334462306a36Sopenharmony_ci
334562306a36Sopenharmony_ci	/* attach a new PCM streams */
334662306a36Sopenharmony_ci	list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
334762306a36Sopenharmony_ci		if (cpcm->pcm)
334862306a36Sopenharmony_ci			continue; /* already attached */
334962306a36Sopenharmony_ci		if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
335062306a36Sopenharmony_ci			continue; /* no substreams assigned */
335162306a36Sopenharmony_ci
335262306a36Sopenharmony_ci		dev = get_empty_pcm_device(bus, cpcm->pcm_type);
335362306a36Sopenharmony_ci		if (dev < 0) {
335462306a36Sopenharmony_ci			cpcm->device = SNDRV_PCM_INVALID_DEVICE;
335562306a36Sopenharmony_ci			continue; /* no fatal error */
335662306a36Sopenharmony_ci		}
335762306a36Sopenharmony_ci		cpcm->device = dev;
335862306a36Sopenharmony_ci		err =  snd_hda_attach_pcm_stream(bus, codec, cpcm);
335962306a36Sopenharmony_ci		if (err < 0) {
336062306a36Sopenharmony_ci			codec_err(codec,
336162306a36Sopenharmony_ci				  "cannot attach PCM stream %d for codec #%d\n",
336262306a36Sopenharmony_ci				  dev, codec->core.addr);
336362306a36Sopenharmony_ci			continue; /* no fatal error */
336462306a36Sopenharmony_ci		}
336562306a36Sopenharmony_ci	}
336662306a36Sopenharmony_ci
336762306a36Sopenharmony_ci	return 0;
336862306a36Sopenharmony_ci}
336962306a36Sopenharmony_ci
337062306a36Sopenharmony_ci/**
337162306a36Sopenharmony_ci * snd_hda_add_new_ctls - create controls from the array
337262306a36Sopenharmony_ci * @codec: the HDA codec
337362306a36Sopenharmony_ci * @knew: the array of struct snd_kcontrol_new
337462306a36Sopenharmony_ci *
337562306a36Sopenharmony_ci * This helper function creates and add new controls in the given array.
337662306a36Sopenharmony_ci * The array must be terminated with an empty entry as terminator.
337762306a36Sopenharmony_ci *
337862306a36Sopenharmony_ci * Returns 0 if successful, or a negative error code.
337962306a36Sopenharmony_ci */
338062306a36Sopenharmony_ciint snd_hda_add_new_ctls(struct hda_codec *codec,
338162306a36Sopenharmony_ci			 const struct snd_kcontrol_new *knew)
338262306a36Sopenharmony_ci{
338362306a36Sopenharmony_ci	int err;
338462306a36Sopenharmony_ci
338562306a36Sopenharmony_ci	for (; knew->name; knew++) {
338662306a36Sopenharmony_ci		struct snd_kcontrol *kctl;
338762306a36Sopenharmony_ci		int addr = 0, idx = 0;
338862306a36Sopenharmony_ci		if (knew->iface == (__force snd_ctl_elem_iface_t)-1)
338962306a36Sopenharmony_ci			continue; /* skip this codec private value */
339062306a36Sopenharmony_ci		for (;;) {
339162306a36Sopenharmony_ci			kctl = snd_ctl_new1(knew, codec);
339262306a36Sopenharmony_ci			if (!kctl)
339362306a36Sopenharmony_ci				return -ENOMEM;
339462306a36Sopenharmony_ci			/* Do not use the id.device field for MIXER elements.
339562306a36Sopenharmony_ci			 * This field is for real device numbers (like PCM) but codecs
339662306a36Sopenharmony_ci			 * are hidden components from the user space view (unrelated
339762306a36Sopenharmony_ci			 * to the mixer element identification).
339862306a36Sopenharmony_ci			 */
339962306a36Sopenharmony_ci			if (addr > 0 && codec->ctl_dev_id)
340062306a36Sopenharmony_ci				kctl->id.device = addr;
340162306a36Sopenharmony_ci			if (idx > 0)
340262306a36Sopenharmony_ci				kctl->id.index = idx;
340362306a36Sopenharmony_ci			err = snd_hda_ctl_add(codec, 0, kctl);
340462306a36Sopenharmony_ci			if (!err)
340562306a36Sopenharmony_ci				break;
340662306a36Sopenharmony_ci			/* try first with another device index corresponding to
340762306a36Sopenharmony_ci			 * the codec addr; if it still fails (or it's the
340862306a36Sopenharmony_ci			 * primary codec), then try another control index
340962306a36Sopenharmony_ci			 */
341062306a36Sopenharmony_ci			if (!addr && codec->core.addr) {
341162306a36Sopenharmony_ci				addr = codec->core.addr;
341262306a36Sopenharmony_ci				if (!codec->ctl_dev_id)
341362306a36Sopenharmony_ci					idx += 10 * addr;
341462306a36Sopenharmony_ci			} else if (!idx && !knew->index) {
341562306a36Sopenharmony_ci				idx = find_empty_mixer_ctl_idx(codec,
341662306a36Sopenharmony_ci							       knew->name, 0);
341762306a36Sopenharmony_ci				if (idx <= 0)
341862306a36Sopenharmony_ci					return err;
341962306a36Sopenharmony_ci			} else
342062306a36Sopenharmony_ci				return err;
342162306a36Sopenharmony_ci		}
342262306a36Sopenharmony_ci	}
342362306a36Sopenharmony_ci	return 0;
342462306a36Sopenharmony_ci}
342562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_add_new_ctls);
342662306a36Sopenharmony_ci
342762306a36Sopenharmony_ci#ifdef CONFIG_PM
342862306a36Sopenharmony_ci/**
342962306a36Sopenharmony_ci * snd_hda_codec_set_power_save - Configure codec's runtime PM
343062306a36Sopenharmony_ci * @codec: codec device to configure
343162306a36Sopenharmony_ci * @delay: autosuspend delay
343262306a36Sopenharmony_ci */
343362306a36Sopenharmony_civoid snd_hda_codec_set_power_save(struct hda_codec *codec, int delay)
343462306a36Sopenharmony_ci{
343562306a36Sopenharmony_ci	struct device *dev = hda_codec_dev(codec);
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_ci	if (delay == 0 && codec->auto_runtime_pm)
343862306a36Sopenharmony_ci		delay = 3000;
343962306a36Sopenharmony_ci
344062306a36Sopenharmony_ci	if (delay > 0) {
344162306a36Sopenharmony_ci		pm_runtime_set_autosuspend_delay(dev, delay);
344262306a36Sopenharmony_ci		pm_runtime_use_autosuspend(dev);
344362306a36Sopenharmony_ci		pm_runtime_allow(dev);
344462306a36Sopenharmony_ci		if (!pm_runtime_suspended(dev))
344562306a36Sopenharmony_ci			pm_runtime_mark_last_busy(dev);
344662306a36Sopenharmony_ci	} else {
344762306a36Sopenharmony_ci		pm_runtime_dont_use_autosuspend(dev);
344862306a36Sopenharmony_ci		pm_runtime_forbid(dev);
344962306a36Sopenharmony_ci	}
345062306a36Sopenharmony_ci}
345162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_set_power_save);
345262306a36Sopenharmony_ci
345362306a36Sopenharmony_ci/**
345462306a36Sopenharmony_ci * snd_hda_set_power_save - reprogram autosuspend for the given delay
345562306a36Sopenharmony_ci * @bus: HD-audio bus
345662306a36Sopenharmony_ci * @delay: autosuspend delay in msec, 0 = off
345762306a36Sopenharmony_ci *
345862306a36Sopenharmony_ci * Synchronize the runtime PM autosuspend state from the power_save option.
345962306a36Sopenharmony_ci */
346062306a36Sopenharmony_civoid snd_hda_set_power_save(struct hda_bus *bus, int delay)
346162306a36Sopenharmony_ci{
346262306a36Sopenharmony_ci	struct hda_codec *c;
346362306a36Sopenharmony_ci
346462306a36Sopenharmony_ci	list_for_each_codec(c, bus)
346562306a36Sopenharmony_ci		snd_hda_codec_set_power_save(c, delay);
346662306a36Sopenharmony_ci}
346762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_set_power_save);
346862306a36Sopenharmony_ci
346962306a36Sopenharmony_ci/**
347062306a36Sopenharmony_ci * snd_hda_check_amp_list_power - Check the amp list and update the power
347162306a36Sopenharmony_ci * @codec: HD-audio codec
347262306a36Sopenharmony_ci * @check: the object containing an AMP list and the status
347362306a36Sopenharmony_ci * @nid: NID to check / update
347462306a36Sopenharmony_ci *
347562306a36Sopenharmony_ci * Check whether the given NID is in the amp list.  If it's in the list,
347662306a36Sopenharmony_ci * check the current AMP status, and update the power-status according
347762306a36Sopenharmony_ci * to the mute status.
347862306a36Sopenharmony_ci *
347962306a36Sopenharmony_ci * This function is supposed to be set or called from the check_power_status
348062306a36Sopenharmony_ci * patch ops.
348162306a36Sopenharmony_ci */
348262306a36Sopenharmony_ciint snd_hda_check_amp_list_power(struct hda_codec *codec,
348362306a36Sopenharmony_ci				 struct hda_loopback_check *check,
348462306a36Sopenharmony_ci				 hda_nid_t nid)
348562306a36Sopenharmony_ci{
348662306a36Sopenharmony_ci	const struct hda_amp_list *p;
348762306a36Sopenharmony_ci	int ch, v;
348862306a36Sopenharmony_ci
348962306a36Sopenharmony_ci	if (!check->amplist)
349062306a36Sopenharmony_ci		return 0;
349162306a36Sopenharmony_ci	for (p = check->amplist; p->nid; p++) {
349262306a36Sopenharmony_ci		if (p->nid == nid)
349362306a36Sopenharmony_ci			break;
349462306a36Sopenharmony_ci	}
349562306a36Sopenharmony_ci	if (!p->nid)
349662306a36Sopenharmony_ci		return 0; /* nothing changed */
349762306a36Sopenharmony_ci
349862306a36Sopenharmony_ci	for (p = check->amplist; p->nid; p++) {
349962306a36Sopenharmony_ci		for (ch = 0; ch < 2; ch++) {
350062306a36Sopenharmony_ci			v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir,
350162306a36Sopenharmony_ci						   p->idx);
350262306a36Sopenharmony_ci			if (!(v & HDA_AMP_MUTE) && v > 0) {
350362306a36Sopenharmony_ci				if (!check->power_on) {
350462306a36Sopenharmony_ci					check->power_on = 1;
350562306a36Sopenharmony_ci					snd_hda_power_up_pm(codec);
350662306a36Sopenharmony_ci				}
350762306a36Sopenharmony_ci				return 1;
350862306a36Sopenharmony_ci			}
350962306a36Sopenharmony_ci		}
351062306a36Sopenharmony_ci	}
351162306a36Sopenharmony_ci	if (check->power_on) {
351262306a36Sopenharmony_ci		check->power_on = 0;
351362306a36Sopenharmony_ci		snd_hda_power_down_pm(codec);
351462306a36Sopenharmony_ci	}
351562306a36Sopenharmony_ci	return 0;
351662306a36Sopenharmony_ci}
351762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_check_amp_list_power);
351862306a36Sopenharmony_ci#endif
351962306a36Sopenharmony_ci
352062306a36Sopenharmony_ci/*
352162306a36Sopenharmony_ci * input MUX helper
352262306a36Sopenharmony_ci */
352362306a36Sopenharmony_ci
352462306a36Sopenharmony_ci/**
352562306a36Sopenharmony_ci * snd_hda_input_mux_info - Info callback helper for the input-mux enum
352662306a36Sopenharmony_ci * @imux: imux helper object
352762306a36Sopenharmony_ci * @uinfo: pointer to get/store the data
352862306a36Sopenharmony_ci */
352962306a36Sopenharmony_ciint snd_hda_input_mux_info(const struct hda_input_mux *imux,
353062306a36Sopenharmony_ci			   struct snd_ctl_elem_info *uinfo)
353162306a36Sopenharmony_ci{
353262306a36Sopenharmony_ci	unsigned int index;
353362306a36Sopenharmony_ci
353462306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
353562306a36Sopenharmony_ci	uinfo->count = 1;
353662306a36Sopenharmony_ci	uinfo->value.enumerated.items = imux->num_items;
353762306a36Sopenharmony_ci	if (!imux->num_items)
353862306a36Sopenharmony_ci		return 0;
353962306a36Sopenharmony_ci	index = uinfo->value.enumerated.item;
354062306a36Sopenharmony_ci	if (index >= imux->num_items)
354162306a36Sopenharmony_ci		index = imux->num_items - 1;
354262306a36Sopenharmony_ci	strcpy(uinfo->value.enumerated.name, imux->items[index].label);
354362306a36Sopenharmony_ci	return 0;
354462306a36Sopenharmony_ci}
354562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_input_mux_info);
354662306a36Sopenharmony_ci
354762306a36Sopenharmony_ci/**
354862306a36Sopenharmony_ci * snd_hda_input_mux_put - Put callback helper for the input-mux enum
354962306a36Sopenharmony_ci * @codec: the HDA codec
355062306a36Sopenharmony_ci * @imux: imux helper object
355162306a36Sopenharmony_ci * @ucontrol: pointer to get/store the data
355262306a36Sopenharmony_ci * @nid: input mux NID
355362306a36Sopenharmony_ci * @cur_val: pointer to get/store the current imux value
355462306a36Sopenharmony_ci */
355562306a36Sopenharmony_ciint snd_hda_input_mux_put(struct hda_codec *codec,
355662306a36Sopenharmony_ci			  const struct hda_input_mux *imux,
355762306a36Sopenharmony_ci			  struct snd_ctl_elem_value *ucontrol,
355862306a36Sopenharmony_ci			  hda_nid_t nid,
355962306a36Sopenharmony_ci			  unsigned int *cur_val)
356062306a36Sopenharmony_ci{
356162306a36Sopenharmony_ci	unsigned int idx;
356262306a36Sopenharmony_ci
356362306a36Sopenharmony_ci	if (!imux->num_items)
356462306a36Sopenharmony_ci		return 0;
356562306a36Sopenharmony_ci	idx = ucontrol->value.enumerated.item[0];
356662306a36Sopenharmony_ci	if (idx >= imux->num_items)
356762306a36Sopenharmony_ci		idx = imux->num_items - 1;
356862306a36Sopenharmony_ci	if (*cur_val == idx)
356962306a36Sopenharmony_ci		return 0;
357062306a36Sopenharmony_ci	snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_CONNECT_SEL,
357162306a36Sopenharmony_ci				  imux->items[idx].index);
357262306a36Sopenharmony_ci	*cur_val = idx;
357362306a36Sopenharmony_ci	return 1;
357462306a36Sopenharmony_ci}
357562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_input_mux_put);
357662306a36Sopenharmony_ci
357762306a36Sopenharmony_ci
357862306a36Sopenharmony_ci/**
357962306a36Sopenharmony_ci * snd_hda_enum_helper_info - Helper for simple enum ctls
358062306a36Sopenharmony_ci * @kcontrol: ctl element
358162306a36Sopenharmony_ci * @uinfo: pointer to get/store the data
358262306a36Sopenharmony_ci * @num_items: number of enum items
358362306a36Sopenharmony_ci * @texts: enum item string array
358462306a36Sopenharmony_ci *
358562306a36Sopenharmony_ci * process kcontrol info callback of a simple string enum array
358662306a36Sopenharmony_ci * when @num_items is 0 or @texts is NULL, assume a boolean enum array
358762306a36Sopenharmony_ci */
358862306a36Sopenharmony_ciint snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol,
358962306a36Sopenharmony_ci			     struct snd_ctl_elem_info *uinfo,
359062306a36Sopenharmony_ci			     int num_items, const char * const *texts)
359162306a36Sopenharmony_ci{
359262306a36Sopenharmony_ci	static const char * const texts_default[] = {
359362306a36Sopenharmony_ci		"Disabled", "Enabled"
359462306a36Sopenharmony_ci	};
359562306a36Sopenharmony_ci
359662306a36Sopenharmony_ci	if (!texts || !num_items) {
359762306a36Sopenharmony_ci		num_items = 2;
359862306a36Sopenharmony_ci		texts = texts_default;
359962306a36Sopenharmony_ci	}
360062306a36Sopenharmony_ci
360162306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, num_items, texts);
360262306a36Sopenharmony_ci}
360362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_enum_helper_info);
360462306a36Sopenharmony_ci
360562306a36Sopenharmony_ci/*
360662306a36Sopenharmony_ci * Multi-channel / digital-out PCM helper functions
360762306a36Sopenharmony_ci */
360862306a36Sopenharmony_ci
360962306a36Sopenharmony_ci/* setup SPDIF output stream */
361062306a36Sopenharmony_cistatic void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
361162306a36Sopenharmony_ci				 unsigned int stream_tag, unsigned int format)
361262306a36Sopenharmony_ci{
361362306a36Sopenharmony_ci	struct hda_spdif_out *spdif;
361462306a36Sopenharmony_ci	unsigned int curr_fmt;
361562306a36Sopenharmony_ci	bool reset;
361662306a36Sopenharmony_ci
361762306a36Sopenharmony_ci	spdif = snd_hda_spdif_out_of_nid(codec, nid);
361862306a36Sopenharmony_ci	/* Add sanity check to pass klockwork check.
361962306a36Sopenharmony_ci	 * This should never happen.
362062306a36Sopenharmony_ci	 */
362162306a36Sopenharmony_ci	if (WARN_ON(spdif == NULL))
362262306a36Sopenharmony_ci		return;
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_ci	curr_fmt = snd_hda_codec_read(codec, nid, 0,
362562306a36Sopenharmony_ci				      AC_VERB_GET_STREAM_FORMAT, 0);
362662306a36Sopenharmony_ci	reset = codec->spdif_status_reset &&
362762306a36Sopenharmony_ci		(spdif->ctls & AC_DIG1_ENABLE) &&
362862306a36Sopenharmony_ci		curr_fmt != format;
362962306a36Sopenharmony_ci
363062306a36Sopenharmony_ci	/* turn off SPDIF if needed; otherwise the IEC958 bits won't be
363162306a36Sopenharmony_ci	   updated */
363262306a36Sopenharmony_ci	if (reset)
363362306a36Sopenharmony_ci		set_dig_out_convert(codec, nid,
363462306a36Sopenharmony_ci				    spdif->ctls & ~AC_DIG1_ENABLE & 0xff,
363562306a36Sopenharmony_ci				    -1);
363662306a36Sopenharmony_ci	snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
363762306a36Sopenharmony_ci	if (codec->follower_dig_outs) {
363862306a36Sopenharmony_ci		const hda_nid_t *d;
363962306a36Sopenharmony_ci		for (d = codec->follower_dig_outs; *d; d++)
364062306a36Sopenharmony_ci			snd_hda_codec_setup_stream(codec, *d, stream_tag, 0,
364162306a36Sopenharmony_ci						   format);
364262306a36Sopenharmony_ci	}
364362306a36Sopenharmony_ci	/* turn on again (if needed) */
364462306a36Sopenharmony_ci	if (reset)
364562306a36Sopenharmony_ci		set_dig_out_convert(codec, nid,
364662306a36Sopenharmony_ci				    spdif->ctls & 0xff, -1);
364762306a36Sopenharmony_ci}
364862306a36Sopenharmony_ci
364962306a36Sopenharmony_cistatic void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)
365062306a36Sopenharmony_ci{
365162306a36Sopenharmony_ci	snd_hda_codec_cleanup_stream(codec, nid);
365262306a36Sopenharmony_ci	if (codec->follower_dig_outs) {
365362306a36Sopenharmony_ci		const hda_nid_t *d;
365462306a36Sopenharmony_ci		for (d = codec->follower_dig_outs; *d; d++)
365562306a36Sopenharmony_ci			snd_hda_codec_cleanup_stream(codec, *d);
365662306a36Sopenharmony_ci	}
365762306a36Sopenharmony_ci}
365862306a36Sopenharmony_ci
365962306a36Sopenharmony_ci/**
366062306a36Sopenharmony_ci * snd_hda_multi_out_dig_open - open the digital out in the exclusive mode
366162306a36Sopenharmony_ci * @codec: the HDA codec
366262306a36Sopenharmony_ci * @mout: hda_multi_out object
366362306a36Sopenharmony_ci */
366462306a36Sopenharmony_ciint snd_hda_multi_out_dig_open(struct hda_codec *codec,
366562306a36Sopenharmony_ci			       struct hda_multi_out *mout)
366662306a36Sopenharmony_ci{
366762306a36Sopenharmony_ci	mutex_lock(&codec->spdif_mutex);
366862306a36Sopenharmony_ci	if (mout->dig_out_used == HDA_DIG_ANALOG_DUP)
366962306a36Sopenharmony_ci		/* already opened as analog dup; reset it once */
367062306a36Sopenharmony_ci		cleanup_dig_out_stream(codec, mout->dig_out_nid);
367162306a36Sopenharmony_ci	mout->dig_out_used = HDA_DIG_EXCLUSIVE;
367262306a36Sopenharmony_ci	mutex_unlock(&codec->spdif_mutex);
367362306a36Sopenharmony_ci	return 0;
367462306a36Sopenharmony_ci}
367562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_open);
367662306a36Sopenharmony_ci
367762306a36Sopenharmony_ci/**
367862306a36Sopenharmony_ci * snd_hda_multi_out_dig_prepare - prepare the digital out stream
367962306a36Sopenharmony_ci * @codec: the HDA codec
368062306a36Sopenharmony_ci * @mout: hda_multi_out object
368162306a36Sopenharmony_ci * @stream_tag: stream tag to assign
368262306a36Sopenharmony_ci * @format: format id to assign
368362306a36Sopenharmony_ci * @substream: PCM substream to assign
368462306a36Sopenharmony_ci */
368562306a36Sopenharmony_ciint snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
368662306a36Sopenharmony_ci				  struct hda_multi_out *mout,
368762306a36Sopenharmony_ci				  unsigned int stream_tag,
368862306a36Sopenharmony_ci				  unsigned int format,
368962306a36Sopenharmony_ci				  struct snd_pcm_substream *substream)
369062306a36Sopenharmony_ci{
369162306a36Sopenharmony_ci	mutex_lock(&codec->spdif_mutex);
369262306a36Sopenharmony_ci	setup_dig_out_stream(codec, mout->dig_out_nid, stream_tag, format);
369362306a36Sopenharmony_ci	mutex_unlock(&codec->spdif_mutex);
369462306a36Sopenharmony_ci	return 0;
369562306a36Sopenharmony_ci}
369662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_prepare);
369762306a36Sopenharmony_ci
369862306a36Sopenharmony_ci/**
369962306a36Sopenharmony_ci * snd_hda_multi_out_dig_cleanup - clean-up the digital out stream
370062306a36Sopenharmony_ci * @codec: the HDA codec
370162306a36Sopenharmony_ci * @mout: hda_multi_out object
370262306a36Sopenharmony_ci */
370362306a36Sopenharmony_ciint snd_hda_multi_out_dig_cleanup(struct hda_codec *codec,
370462306a36Sopenharmony_ci				  struct hda_multi_out *mout)
370562306a36Sopenharmony_ci{
370662306a36Sopenharmony_ci	mutex_lock(&codec->spdif_mutex);
370762306a36Sopenharmony_ci	cleanup_dig_out_stream(codec, mout->dig_out_nid);
370862306a36Sopenharmony_ci	mutex_unlock(&codec->spdif_mutex);
370962306a36Sopenharmony_ci	return 0;
371062306a36Sopenharmony_ci}
371162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_cleanup);
371262306a36Sopenharmony_ci
371362306a36Sopenharmony_ci/**
371462306a36Sopenharmony_ci * snd_hda_multi_out_dig_close - release the digital out stream
371562306a36Sopenharmony_ci * @codec: the HDA codec
371662306a36Sopenharmony_ci * @mout: hda_multi_out object
371762306a36Sopenharmony_ci */
371862306a36Sopenharmony_ciint snd_hda_multi_out_dig_close(struct hda_codec *codec,
371962306a36Sopenharmony_ci				struct hda_multi_out *mout)
372062306a36Sopenharmony_ci{
372162306a36Sopenharmony_ci	mutex_lock(&codec->spdif_mutex);
372262306a36Sopenharmony_ci	mout->dig_out_used = 0;
372362306a36Sopenharmony_ci	mutex_unlock(&codec->spdif_mutex);
372462306a36Sopenharmony_ci	return 0;
372562306a36Sopenharmony_ci}
372662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_close);
372762306a36Sopenharmony_ci
372862306a36Sopenharmony_ci/**
372962306a36Sopenharmony_ci * snd_hda_multi_out_analog_open - open analog outputs
373062306a36Sopenharmony_ci * @codec: the HDA codec
373162306a36Sopenharmony_ci * @mout: hda_multi_out object
373262306a36Sopenharmony_ci * @substream: PCM substream to assign
373362306a36Sopenharmony_ci * @hinfo: PCM information to assign
373462306a36Sopenharmony_ci *
373562306a36Sopenharmony_ci * Open analog outputs and set up the hw-constraints.
373662306a36Sopenharmony_ci * If the digital outputs can be opened as follower, open the digital
373762306a36Sopenharmony_ci * outputs, too.
373862306a36Sopenharmony_ci */
373962306a36Sopenharmony_ciint snd_hda_multi_out_analog_open(struct hda_codec *codec,
374062306a36Sopenharmony_ci				  struct hda_multi_out *mout,
374162306a36Sopenharmony_ci				  struct snd_pcm_substream *substream,
374262306a36Sopenharmony_ci				  struct hda_pcm_stream *hinfo)
374362306a36Sopenharmony_ci{
374462306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
374562306a36Sopenharmony_ci	runtime->hw.channels_max = mout->max_channels;
374662306a36Sopenharmony_ci	if (mout->dig_out_nid) {
374762306a36Sopenharmony_ci		if (!mout->analog_rates) {
374862306a36Sopenharmony_ci			mout->analog_rates = hinfo->rates;
374962306a36Sopenharmony_ci			mout->analog_formats = hinfo->formats;
375062306a36Sopenharmony_ci			mout->analog_maxbps = hinfo->maxbps;
375162306a36Sopenharmony_ci		} else {
375262306a36Sopenharmony_ci			runtime->hw.rates = mout->analog_rates;
375362306a36Sopenharmony_ci			runtime->hw.formats = mout->analog_formats;
375462306a36Sopenharmony_ci			hinfo->maxbps = mout->analog_maxbps;
375562306a36Sopenharmony_ci		}
375662306a36Sopenharmony_ci		if (!mout->spdif_rates) {
375762306a36Sopenharmony_ci			snd_hda_query_supported_pcm(codec, mout->dig_out_nid,
375862306a36Sopenharmony_ci						    &mout->spdif_rates,
375962306a36Sopenharmony_ci						    &mout->spdif_formats,
376062306a36Sopenharmony_ci						    &mout->spdif_maxbps);
376162306a36Sopenharmony_ci		}
376262306a36Sopenharmony_ci		mutex_lock(&codec->spdif_mutex);
376362306a36Sopenharmony_ci		if (mout->share_spdif) {
376462306a36Sopenharmony_ci			if ((runtime->hw.rates & mout->spdif_rates) &&
376562306a36Sopenharmony_ci			    (runtime->hw.formats & mout->spdif_formats)) {
376662306a36Sopenharmony_ci				runtime->hw.rates &= mout->spdif_rates;
376762306a36Sopenharmony_ci				runtime->hw.formats &= mout->spdif_formats;
376862306a36Sopenharmony_ci				if (mout->spdif_maxbps < hinfo->maxbps)
376962306a36Sopenharmony_ci					hinfo->maxbps = mout->spdif_maxbps;
377062306a36Sopenharmony_ci			} else {
377162306a36Sopenharmony_ci				mout->share_spdif = 0;
377262306a36Sopenharmony_ci				/* FIXME: need notify? */
377362306a36Sopenharmony_ci			}
377462306a36Sopenharmony_ci		}
377562306a36Sopenharmony_ci		mutex_unlock(&codec->spdif_mutex);
377662306a36Sopenharmony_ci	}
377762306a36Sopenharmony_ci	return snd_pcm_hw_constraint_step(substream->runtime, 0,
377862306a36Sopenharmony_ci					  SNDRV_PCM_HW_PARAM_CHANNELS, 2);
377962306a36Sopenharmony_ci}
378062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_open);
378162306a36Sopenharmony_ci
378262306a36Sopenharmony_ci/**
378362306a36Sopenharmony_ci * snd_hda_multi_out_analog_prepare - Preapre the analog outputs.
378462306a36Sopenharmony_ci * @codec: the HDA codec
378562306a36Sopenharmony_ci * @mout: hda_multi_out object
378662306a36Sopenharmony_ci * @stream_tag: stream tag to assign
378762306a36Sopenharmony_ci * @format: format id to assign
378862306a36Sopenharmony_ci * @substream: PCM substream to assign
378962306a36Sopenharmony_ci *
379062306a36Sopenharmony_ci * Set up the i/o for analog out.
379162306a36Sopenharmony_ci * When the digital out is available, copy the front out to digital out, too.
379262306a36Sopenharmony_ci */
379362306a36Sopenharmony_ciint snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
379462306a36Sopenharmony_ci				     struct hda_multi_out *mout,
379562306a36Sopenharmony_ci				     unsigned int stream_tag,
379662306a36Sopenharmony_ci				     unsigned int format,
379762306a36Sopenharmony_ci				     struct snd_pcm_substream *substream)
379862306a36Sopenharmony_ci{
379962306a36Sopenharmony_ci	const hda_nid_t *nids = mout->dac_nids;
380062306a36Sopenharmony_ci	int chs = substream->runtime->channels;
380162306a36Sopenharmony_ci	struct hda_spdif_out *spdif;
380262306a36Sopenharmony_ci	int i;
380362306a36Sopenharmony_ci
380462306a36Sopenharmony_ci	mutex_lock(&codec->spdif_mutex);
380562306a36Sopenharmony_ci	spdif = snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid);
380662306a36Sopenharmony_ci	if (mout->dig_out_nid && mout->share_spdif &&
380762306a36Sopenharmony_ci	    mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
380862306a36Sopenharmony_ci		if (chs == 2 && spdif != NULL &&
380962306a36Sopenharmony_ci		    snd_hda_is_supported_format(codec, mout->dig_out_nid,
381062306a36Sopenharmony_ci						format) &&
381162306a36Sopenharmony_ci		    !(spdif->status & IEC958_AES0_NONAUDIO)) {
381262306a36Sopenharmony_ci			mout->dig_out_used = HDA_DIG_ANALOG_DUP;
381362306a36Sopenharmony_ci			setup_dig_out_stream(codec, mout->dig_out_nid,
381462306a36Sopenharmony_ci					     stream_tag, format);
381562306a36Sopenharmony_ci		} else {
381662306a36Sopenharmony_ci			mout->dig_out_used = 0;
381762306a36Sopenharmony_ci			cleanup_dig_out_stream(codec, mout->dig_out_nid);
381862306a36Sopenharmony_ci		}
381962306a36Sopenharmony_ci	}
382062306a36Sopenharmony_ci	mutex_unlock(&codec->spdif_mutex);
382162306a36Sopenharmony_ci
382262306a36Sopenharmony_ci	/* front */
382362306a36Sopenharmony_ci	snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag,
382462306a36Sopenharmony_ci				   0, format);
382562306a36Sopenharmony_ci	if (!mout->no_share_stream &&
382662306a36Sopenharmony_ci	    mout->hp_nid && mout->hp_nid != nids[HDA_FRONT])
382762306a36Sopenharmony_ci		/* headphone out will just decode front left/right (stereo) */
382862306a36Sopenharmony_ci		snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag,
382962306a36Sopenharmony_ci					   0, format);
383062306a36Sopenharmony_ci	/* extra outputs copied from front */
383162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mout->hp_out_nid); i++)
383262306a36Sopenharmony_ci		if (!mout->no_share_stream && mout->hp_out_nid[i])
383362306a36Sopenharmony_ci			snd_hda_codec_setup_stream(codec,
383462306a36Sopenharmony_ci						   mout->hp_out_nid[i],
383562306a36Sopenharmony_ci						   stream_tag, 0, format);
383662306a36Sopenharmony_ci
383762306a36Sopenharmony_ci	/* surrounds */
383862306a36Sopenharmony_ci	for (i = 1; i < mout->num_dacs; i++) {
383962306a36Sopenharmony_ci		if (chs >= (i + 1) * 2) /* independent out */
384062306a36Sopenharmony_ci			snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
384162306a36Sopenharmony_ci						   i * 2, format);
384262306a36Sopenharmony_ci		else if (!mout->no_share_stream) /* copy front */
384362306a36Sopenharmony_ci			snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
384462306a36Sopenharmony_ci						   0, format);
384562306a36Sopenharmony_ci	}
384662306a36Sopenharmony_ci
384762306a36Sopenharmony_ci	/* extra surrounds */
384862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) {
384962306a36Sopenharmony_ci		int ch = 0;
385062306a36Sopenharmony_ci		if (!mout->extra_out_nid[i])
385162306a36Sopenharmony_ci			break;
385262306a36Sopenharmony_ci		if (chs >= (i + 1) * 2)
385362306a36Sopenharmony_ci			ch = i * 2;
385462306a36Sopenharmony_ci		else if (!mout->no_share_stream)
385562306a36Sopenharmony_ci			break;
385662306a36Sopenharmony_ci		snd_hda_codec_setup_stream(codec, mout->extra_out_nid[i],
385762306a36Sopenharmony_ci					   stream_tag, ch, format);
385862306a36Sopenharmony_ci	}
385962306a36Sopenharmony_ci
386062306a36Sopenharmony_ci	return 0;
386162306a36Sopenharmony_ci}
386262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_prepare);
386362306a36Sopenharmony_ci
386462306a36Sopenharmony_ci/**
386562306a36Sopenharmony_ci * snd_hda_multi_out_analog_cleanup - clean up the setting for analog out
386662306a36Sopenharmony_ci * @codec: the HDA codec
386762306a36Sopenharmony_ci * @mout: hda_multi_out object
386862306a36Sopenharmony_ci */
386962306a36Sopenharmony_ciint snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
387062306a36Sopenharmony_ci				     struct hda_multi_out *mout)
387162306a36Sopenharmony_ci{
387262306a36Sopenharmony_ci	const hda_nid_t *nids = mout->dac_nids;
387362306a36Sopenharmony_ci	int i;
387462306a36Sopenharmony_ci
387562306a36Sopenharmony_ci	for (i = 0; i < mout->num_dacs; i++)
387662306a36Sopenharmony_ci		snd_hda_codec_cleanup_stream(codec, nids[i]);
387762306a36Sopenharmony_ci	if (mout->hp_nid)
387862306a36Sopenharmony_ci		snd_hda_codec_cleanup_stream(codec, mout->hp_nid);
387962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mout->hp_out_nid); i++)
388062306a36Sopenharmony_ci		if (mout->hp_out_nid[i])
388162306a36Sopenharmony_ci			snd_hda_codec_cleanup_stream(codec,
388262306a36Sopenharmony_ci						     mout->hp_out_nid[i]);
388362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
388462306a36Sopenharmony_ci		if (mout->extra_out_nid[i])
388562306a36Sopenharmony_ci			snd_hda_codec_cleanup_stream(codec,
388662306a36Sopenharmony_ci						     mout->extra_out_nid[i]);
388762306a36Sopenharmony_ci	mutex_lock(&codec->spdif_mutex);
388862306a36Sopenharmony_ci	if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
388962306a36Sopenharmony_ci		cleanup_dig_out_stream(codec, mout->dig_out_nid);
389062306a36Sopenharmony_ci		mout->dig_out_used = 0;
389162306a36Sopenharmony_ci	}
389262306a36Sopenharmony_ci	mutex_unlock(&codec->spdif_mutex);
389362306a36Sopenharmony_ci	return 0;
389462306a36Sopenharmony_ci}
389562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_cleanup);
389662306a36Sopenharmony_ci
389762306a36Sopenharmony_ci/**
389862306a36Sopenharmony_ci * snd_hda_get_default_vref - Get the default (mic) VREF pin bits
389962306a36Sopenharmony_ci * @codec: the HDA codec
390062306a36Sopenharmony_ci * @pin: referred pin NID
390162306a36Sopenharmony_ci *
390262306a36Sopenharmony_ci * Guess the suitable VREF pin bits to be set as the pin-control value.
390362306a36Sopenharmony_ci * Note: the function doesn't set the AC_PINCTL_IN_EN bit.
390462306a36Sopenharmony_ci */
390562306a36Sopenharmony_ciunsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin)
390662306a36Sopenharmony_ci{
390762306a36Sopenharmony_ci	unsigned int pincap;
390862306a36Sopenharmony_ci	unsigned int oldval;
390962306a36Sopenharmony_ci	oldval = snd_hda_codec_read(codec, pin, 0,
391062306a36Sopenharmony_ci				    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
391162306a36Sopenharmony_ci	pincap = snd_hda_query_pin_caps(codec, pin);
391262306a36Sopenharmony_ci	pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
391362306a36Sopenharmony_ci	/* Exception: if the default pin setup is vref50, we give it priority */
391462306a36Sopenharmony_ci	if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
391562306a36Sopenharmony_ci		return AC_PINCTL_VREF_80;
391662306a36Sopenharmony_ci	else if (pincap & AC_PINCAP_VREF_50)
391762306a36Sopenharmony_ci		return AC_PINCTL_VREF_50;
391862306a36Sopenharmony_ci	else if (pincap & AC_PINCAP_VREF_100)
391962306a36Sopenharmony_ci		return AC_PINCTL_VREF_100;
392062306a36Sopenharmony_ci	else if (pincap & AC_PINCAP_VREF_GRD)
392162306a36Sopenharmony_ci		return AC_PINCTL_VREF_GRD;
392262306a36Sopenharmony_ci	return AC_PINCTL_VREF_HIZ;
392362306a36Sopenharmony_ci}
392462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_get_default_vref);
392562306a36Sopenharmony_ci
392662306a36Sopenharmony_ci/**
392762306a36Sopenharmony_ci * snd_hda_correct_pin_ctl - correct the pin ctl value for matching with the pin cap
392862306a36Sopenharmony_ci * @codec: the HDA codec
392962306a36Sopenharmony_ci * @pin: referred pin NID
393062306a36Sopenharmony_ci * @val: pin ctl value to audit
393162306a36Sopenharmony_ci */
393262306a36Sopenharmony_ciunsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec,
393362306a36Sopenharmony_ci				     hda_nid_t pin, unsigned int val)
393462306a36Sopenharmony_ci{
393562306a36Sopenharmony_ci	static const unsigned int cap_lists[][2] = {
393662306a36Sopenharmony_ci		{ AC_PINCTL_VREF_100, AC_PINCAP_VREF_100 },
393762306a36Sopenharmony_ci		{ AC_PINCTL_VREF_80, AC_PINCAP_VREF_80 },
393862306a36Sopenharmony_ci		{ AC_PINCTL_VREF_50, AC_PINCAP_VREF_50 },
393962306a36Sopenharmony_ci		{ AC_PINCTL_VREF_GRD, AC_PINCAP_VREF_GRD },
394062306a36Sopenharmony_ci	};
394162306a36Sopenharmony_ci	unsigned int cap;
394262306a36Sopenharmony_ci
394362306a36Sopenharmony_ci	if (!val)
394462306a36Sopenharmony_ci		return 0;
394562306a36Sopenharmony_ci	cap = snd_hda_query_pin_caps(codec, pin);
394662306a36Sopenharmony_ci	if (!cap)
394762306a36Sopenharmony_ci		return val; /* don't know what to do... */
394862306a36Sopenharmony_ci
394962306a36Sopenharmony_ci	if (val & AC_PINCTL_OUT_EN) {
395062306a36Sopenharmony_ci		if (!(cap & AC_PINCAP_OUT))
395162306a36Sopenharmony_ci			val &= ~(AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
395262306a36Sopenharmony_ci		else if ((val & AC_PINCTL_HP_EN) && !(cap & AC_PINCAP_HP_DRV))
395362306a36Sopenharmony_ci			val &= ~AC_PINCTL_HP_EN;
395462306a36Sopenharmony_ci	}
395562306a36Sopenharmony_ci
395662306a36Sopenharmony_ci	if (val & AC_PINCTL_IN_EN) {
395762306a36Sopenharmony_ci		if (!(cap & AC_PINCAP_IN))
395862306a36Sopenharmony_ci			val &= ~(AC_PINCTL_IN_EN | AC_PINCTL_VREFEN);
395962306a36Sopenharmony_ci		else {
396062306a36Sopenharmony_ci			unsigned int vcap, vref;
396162306a36Sopenharmony_ci			int i;
396262306a36Sopenharmony_ci			vcap = (cap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
396362306a36Sopenharmony_ci			vref = val & AC_PINCTL_VREFEN;
396462306a36Sopenharmony_ci			for (i = 0; i < ARRAY_SIZE(cap_lists); i++) {
396562306a36Sopenharmony_ci				if (vref == cap_lists[i][0] &&
396662306a36Sopenharmony_ci				    !(vcap & cap_lists[i][1])) {
396762306a36Sopenharmony_ci					if (i == ARRAY_SIZE(cap_lists) - 1)
396862306a36Sopenharmony_ci						vref = AC_PINCTL_VREF_HIZ;
396962306a36Sopenharmony_ci					else
397062306a36Sopenharmony_ci						vref = cap_lists[i + 1][0];
397162306a36Sopenharmony_ci				}
397262306a36Sopenharmony_ci			}
397362306a36Sopenharmony_ci			val &= ~AC_PINCTL_VREFEN;
397462306a36Sopenharmony_ci			val |= vref;
397562306a36Sopenharmony_ci		}
397662306a36Sopenharmony_ci	}
397762306a36Sopenharmony_ci
397862306a36Sopenharmony_ci	return val;
397962306a36Sopenharmony_ci}
398062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_correct_pin_ctl);
398162306a36Sopenharmony_ci
398262306a36Sopenharmony_ci/**
398362306a36Sopenharmony_ci * _snd_hda_set_pin_ctl - Helper to set pin ctl value
398462306a36Sopenharmony_ci * @codec: the HDA codec
398562306a36Sopenharmony_ci * @pin: referred pin NID
398662306a36Sopenharmony_ci * @val: pin control value to set
398762306a36Sopenharmony_ci * @cached: access over codec pinctl cache or direct write
398862306a36Sopenharmony_ci *
398962306a36Sopenharmony_ci * This function is a helper to set a pin ctl value more safely.
399062306a36Sopenharmony_ci * It corrects the pin ctl value via snd_hda_correct_pin_ctl(), stores the
399162306a36Sopenharmony_ci * value in pin target array via snd_hda_codec_set_pin_target(), then
399262306a36Sopenharmony_ci * actually writes the value via either snd_hda_codec_write_cache() or
399362306a36Sopenharmony_ci * snd_hda_codec_write() depending on @cached flag.
399462306a36Sopenharmony_ci */
399562306a36Sopenharmony_ciint _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
399662306a36Sopenharmony_ci			 unsigned int val, bool cached)
399762306a36Sopenharmony_ci{
399862306a36Sopenharmony_ci	val = snd_hda_correct_pin_ctl(codec, pin, val);
399962306a36Sopenharmony_ci	snd_hda_codec_set_pin_target(codec, pin, val);
400062306a36Sopenharmony_ci	if (cached)
400162306a36Sopenharmony_ci		return snd_hda_codec_write_cache(codec, pin, 0,
400262306a36Sopenharmony_ci				AC_VERB_SET_PIN_WIDGET_CONTROL, val);
400362306a36Sopenharmony_ci	else
400462306a36Sopenharmony_ci		return snd_hda_codec_write(codec, pin, 0,
400562306a36Sopenharmony_ci					   AC_VERB_SET_PIN_WIDGET_CONTROL, val);
400662306a36Sopenharmony_ci}
400762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(_snd_hda_set_pin_ctl);
400862306a36Sopenharmony_ci
400962306a36Sopenharmony_ci/**
401062306a36Sopenharmony_ci * snd_hda_add_imux_item - Add an item to input_mux
401162306a36Sopenharmony_ci * @codec: the HDA codec
401262306a36Sopenharmony_ci * @imux: imux helper object
401362306a36Sopenharmony_ci * @label: the name of imux item to assign
401462306a36Sopenharmony_ci * @index: index number of imux item to assign
401562306a36Sopenharmony_ci * @type_idx: pointer to store the resultant label index
401662306a36Sopenharmony_ci *
401762306a36Sopenharmony_ci * When the same label is used already in the existing items, the number
401862306a36Sopenharmony_ci * suffix is appended to the label.  This label index number is stored
401962306a36Sopenharmony_ci * to type_idx when non-NULL pointer is given.
402062306a36Sopenharmony_ci */
402162306a36Sopenharmony_ciint snd_hda_add_imux_item(struct hda_codec *codec,
402262306a36Sopenharmony_ci			  struct hda_input_mux *imux, const char *label,
402362306a36Sopenharmony_ci			  int index, int *type_idx)
402462306a36Sopenharmony_ci{
402562306a36Sopenharmony_ci	int i, label_idx = 0;
402662306a36Sopenharmony_ci	if (imux->num_items >= HDA_MAX_NUM_INPUTS) {
402762306a36Sopenharmony_ci		codec_err(codec, "hda_codec: Too many imux items!\n");
402862306a36Sopenharmony_ci		return -EINVAL;
402962306a36Sopenharmony_ci	}
403062306a36Sopenharmony_ci	for (i = 0; i < imux->num_items; i++) {
403162306a36Sopenharmony_ci		if (!strncmp(label, imux->items[i].label, strlen(label)))
403262306a36Sopenharmony_ci			label_idx++;
403362306a36Sopenharmony_ci	}
403462306a36Sopenharmony_ci	if (type_idx)
403562306a36Sopenharmony_ci		*type_idx = label_idx;
403662306a36Sopenharmony_ci	if (label_idx > 0)
403762306a36Sopenharmony_ci		snprintf(imux->items[imux->num_items].label,
403862306a36Sopenharmony_ci			 sizeof(imux->items[imux->num_items].label),
403962306a36Sopenharmony_ci			 "%s %d", label, label_idx);
404062306a36Sopenharmony_ci	else
404162306a36Sopenharmony_ci		strscpy(imux->items[imux->num_items].label, label,
404262306a36Sopenharmony_ci			sizeof(imux->items[imux->num_items].label));
404362306a36Sopenharmony_ci	imux->items[imux->num_items].index = index;
404462306a36Sopenharmony_ci	imux->num_items++;
404562306a36Sopenharmony_ci	return 0;
404662306a36Sopenharmony_ci}
404762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_add_imux_item);
404862306a36Sopenharmony_ci
404962306a36Sopenharmony_ci/**
405062306a36Sopenharmony_ci * snd_hda_bus_reset_codecs - Reset the bus
405162306a36Sopenharmony_ci * @bus: HD-audio bus
405262306a36Sopenharmony_ci */
405362306a36Sopenharmony_civoid snd_hda_bus_reset_codecs(struct hda_bus *bus)
405462306a36Sopenharmony_ci{
405562306a36Sopenharmony_ci	struct hda_codec *codec;
405662306a36Sopenharmony_ci
405762306a36Sopenharmony_ci	list_for_each_codec(codec, bus) {
405862306a36Sopenharmony_ci		/* FIXME: maybe a better way needed for forced reset */
405962306a36Sopenharmony_ci		if (current_work() != &codec->jackpoll_work.work)
406062306a36Sopenharmony_ci			cancel_delayed_work_sync(&codec->jackpoll_work);
406162306a36Sopenharmony_ci#ifdef CONFIG_PM
406262306a36Sopenharmony_ci		if (hda_codec_is_power_on(codec)) {
406362306a36Sopenharmony_ci			hda_call_codec_suspend(codec);
406462306a36Sopenharmony_ci			hda_call_codec_resume(codec);
406562306a36Sopenharmony_ci		}
406662306a36Sopenharmony_ci#endif
406762306a36Sopenharmony_ci	}
406862306a36Sopenharmony_ci}
406962306a36Sopenharmony_ci
407062306a36Sopenharmony_ci/**
407162306a36Sopenharmony_ci * snd_print_pcm_bits - Print the supported PCM fmt bits to the string buffer
407262306a36Sopenharmony_ci * @pcm: PCM caps bits
407362306a36Sopenharmony_ci * @buf: the string buffer to write
407462306a36Sopenharmony_ci * @buflen: the max buffer length
407562306a36Sopenharmony_ci *
407662306a36Sopenharmony_ci * used by hda_proc.c and hda_eld.c
407762306a36Sopenharmony_ci */
407862306a36Sopenharmony_civoid snd_print_pcm_bits(int pcm, char *buf, int buflen)
407962306a36Sopenharmony_ci{
408062306a36Sopenharmony_ci	static const unsigned int bits[] = { 8, 16, 20, 24, 32 };
408162306a36Sopenharmony_ci	int i, j;
408262306a36Sopenharmony_ci
408362306a36Sopenharmony_ci	for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++)
408462306a36Sopenharmony_ci		if (pcm & (AC_SUPPCM_BITS_8 << i))
408562306a36Sopenharmony_ci			j += scnprintf(buf + j, buflen - j,  " %d", bits[i]);
408662306a36Sopenharmony_ci
408762306a36Sopenharmony_ci	buf[j] = '\0'; /* necessary when j == 0 */
408862306a36Sopenharmony_ci}
408962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_print_pcm_bits);
409062306a36Sopenharmony_ci
409162306a36Sopenharmony_ciMODULE_DESCRIPTION("HDA codec core");
409262306a36Sopenharmony_ciMODULE_LICENSE("GPL");
4093