xref: /openbmc/linux/sound/pci/hda/hda_generic.c (revision 117688a9)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Universal Interface for Intel High Definition Audio Codec
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Generic widget tree parser
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  *  This driver is free software; you can redistribute it and/or modify
91da177e4SLinus Torvalds  *  it under the terms of the GNU General Public License as published by
101da177e4SLinus Torvalds  *  the Free Software Foundation; either version 2 of the License, or
111da177e4SLinus Torvalds  *  (at your option) any later version.
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  *  This driver is distributed in the hope that it will be useful,
141da177e4SLinus Torvalds  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
151da177e4SLinus Torvalds  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
161da177e4SLinus Torvalds  *  GNU General Public License for more details.
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  *  You should have received a copy of the GNU General Public License
191da177e4SLinus Torvalds  *  along with this program; if not, write to the Free Software
201da177e4SLinus Torvalds  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
211da177e4SLinus Torvalds  */
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds #include <linux/init.h>
241da177e4SLinus Torvalds #include <linux/slab.h>
25d81a6d71SPaul Gortmaker #include <linux/export.h>
26352f7f91STakashi Iwai #include <linux/sort.h>
27f873e536STakashi Iwai #include <linux/ctype.h>
28f873e536STakashi Iwai #include <linux/string.h>
291da177e4SLinus Torvalds #include <sound/core.h>
30352f7f91STakashi Iwai #include <sound/jack.h>
311da177e4SLinus Torvalds #include "hda_codec.h"
321da177e4SLinus Torvalds #include "hda_local.h"
33352f7f91STakashi Iwai #include "hda_auto_parser.h"
34352f7f91STakashi Iwai #include "hda_jack.h"
35352f7f91STakashi Iwai #include "hda_generic.h"
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds 
38352f7f91STakashi Iwai /* initialize hda_gen_spec struct */
39352f7f91STakashi Iwai int snd_hda_gen_spec_init(struct hda_gen_spec *spec)
401da177e4SLinus Torvalds {
41352f7f91STakashi Iwai 	snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
42352f7f91STakashi Iwai 	snd_array_init(&spec->bind_ctls, sizeof(struct hda_bind_ctls *), 8);
43352f7f91STakashi Iwai 	snd_array_init(&spec->paths, sizeof(struct nid_path), 8);
4438cf6f1aSTakashi Iwai 	mutex_init(&spec->pcm_mutex);
45352f7f91STakashi Iwai 	return 0;
46352f7f91STakashi Iwai }
47352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_spec_init);
481da177e4SLinus Torvalds 
4912c93df6STakashi Iwai struct snd_kcontrol_new *
5012c93df6STakashi Iwai snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
51352f7f91STakashi Iwai 		     const struct snd_kcontrol_new *temp)
52352f7f91STakashi Iwai {
53352f7f91STakashi Iwai 	struct snd_kcontrol_new *knew = snd_array_new(&spec->kctls);
54352f7f91STakashi Iwai 	if (!knew)
55352f7f91STakashi Iwai 		return NULL;
56352f7f91STakashi Iwai 	*knew = *temp;
57352f7f91STakashi Iwai 	if (name)
58352f7f91STakashi Iwai 		knew->name = kstrdup(name, GFP_KERNEL);
59352f7f91STakashi Iwai 	else if (knew->name)
60352f7f91STakashi Iwai 		knew->name = kstrdup(knew->name, GFP_KERNEL);
61352f7f91STakashi Iwai 	if (!knew->name)
62352f7f91STakashi Iwai 		return NULL;
63352f7f91STakashi Iwai 	return knew;
64352f7f91STakashi Iwai }
6512c93df6STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_add_kctl);
66352f7f91STakashi Iwai 
67352f7f91STakashi Iwai static void free_kctls(struct hda_gen_spec *spec)
68352f7f91STakashi Iwai {
69352f7f91STakashi Iwai 	if (spec->kctls.list) {
70352f7f91STakashi Iwai 		struct snd_kcontrol_new *kctl = spec->kctls.list;
71352f7f91STakashi Iwai 		int i;
72352f7f91STakashi Iwai 		for (i = 0; i < spec->kctls.used; i++)
73352f7f91STakashi Iwai 			kfree(kctl[i].name);
74352f7f91STakashi Iwai 	}
75352f7f91STakashi Iwai 	snd_array_free(&spec->kctls);
76352f7f91STakashi Iwai }
77352f7f91STakashi Iwai 
78352f7f91STakashi Iwai static struct hda_bind_ctls *new_bind_ctl(struct hda_codec *codec,
79352f7f91STakashi Iwai 					  unsigned int nums,
80352f7f91STakashi Iwai 					  struct hda_ctl_ops *ops)
81352f7f91STakashi Iwai {
82352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
83352f7f91STakashi Iwai 	struct hda_bind_ctls **ctlp, *ctl;
84352f7f91STakashi Iwai 	ctlp = snd_array_new(&spec->bind_ctls);
85352f7f91STakashi Iwai 	if (!ctlp)
86352f7f91STakashi Iwai 		return NULL;
87352f7f91STakashi Iwai 	ctl = kzalloc(sizeof(*ctl) + sizeof(long) * (nums + 1), GFP_KERNEL);
88352f7f91STakashi Iwai 	*ctlp = ctl;
89352f7f91STakashi Iwai 	if (ctl)
90352f7f91STakashi Iwai 		ctl->ops = ops;
91352f7f91STakashi Iwai 	return ctl;
92352f7f91STakashi Iwai }
93352f7f91STakashi Iwai 
94352f7f91STakashi Iwai static void free_bind_ctls(struct hda_gen_spec *spec)
95352f7f91STakashi Iwai {
96352f7f91STakashi Iwai 	if (spec->bind_ctls.list) {
97352f7f91STakashi Iwai 		struct hda_bind_ctls **ctl = spec->bind_ctls.list;
98352f7f91STakashi Iwai 		int i;
99352f7f91STakashi Iwai 		for (i = 0; i < spec->bind_ctls.used; i++)
100352f7f91STakashi Iwai 			kfree(ctl[i]);
101352f7f91STakashi Iwai 	}
102352f7f91STakashi Iwai 	snd_array_free(&spec->bind_ctls);
103352f7f91STakashi Iwai }
104352f7f91STakashi Iwai 
105352f7f91STakashi Iwai void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
106352f7f91STakashi Iwai {
1071da177e4SLinus Torvalds 	if (!spec)
1081da177e4SLinus Torvalds 		return;
109352f7f91STakashi Iwai 	free_kctls(spec);
110352f7f91STakashi Iwai 	free_bind_ctls(spec);
111352f7f91STakashi Iwai 	snd_array_free(&spec->paths);
1121da177e4SLinus Torvalds }
113352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_spec_free);
1141da177e4SLinus Torvalds 
1151da177e4SLinus Torvalds /*
116352f7f91STakashi Iwai  * parsing paths
1171da177e4SLinus Torvalds  */
1181da177e4SLinus Torvalds 
119f5172a7eSTakashi Iwai static struct nid_path *get_nid_path(struct hda_codec *codec,
120f5172a7eSTakashi Iwai 				     hda_nid_t from_nid, hda_nid_t to_nid,
121f5172a7eSTakashi Iwai 				     int with_aa_mix)
1221da177e4SLinus Torvalds {
123352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
124352f7f91STakashi Iwai 	int i;
1251da177e4SLinus Torvalds 
126352f7f91STakashi Iwai 	for (i = 0; i < spec->paths.used; i++) {
127352f7f91STakashi Iwai 		struct nid_path *path = snd_array_elem(&spec->paths, i);
128352f7f91STakashi Iwai 		if (path->depth <= 0)
129352f7f91STakashi Iwai 			continue;
130352f7f91STakashi Iwai 		if ((!from_nid || path->path[0] == from_nid) &&
131f5172a7eSTakashi Iwai 		    (!to_nid || path->path[path->depth - 1] == to_nid)) {
132f5172a7eSTakashi Iwai 			if (with_aa_mix == HDA_PARSE_ALL ||
133f5172a7eSTakashi Iwai 			    path->with_aa_mix == with_aa_mix)
134352f7f91STakashi Iwai 				return path;
1351da177e4SLinus Torvalds 		}
136f5172a7eSTakashi Iwai 	}
1371da177e4SLinus Torvalds 	return NULL;
1381da177e4SLinus Torvalds }
139f5172a7eSTakashi Iwai 
140f5172a7eSTakashi Iwai /* get the path between the given NIDs;
141f5172a7eSTakashi Iwai  * passing 0 to either @pin or @dac behaves as a wildcard
142f5172a7eSTakashi Iwai  */
143f5172a7eSTakashi Iwai struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
144f5172a7eSTakashi Iwai 				      hda_nid_t from_nid, hda_nid_t to_nid)
145f5172a7eSTakashi Iwai {
146f5172a7eSTakashi Iwai 	return get_nid_path(codec, from_nid, to_nid, HDA_PARSE_ALL);
147f5172a7eSTakashi Iwai }
148352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_nid_path);
1491da177e4SLinus Torvalds 
150196c1766STakashi Iwai /* get the index number corresponding to the path instance;
151196c1766STakashi Iwai  * the index starts from 1, for easier checking the invalid value
152196c1766STakashi Iwai  */
153196c1766STakashi Iwai int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path)
154196c1766STakashi Iwai {
155196c1766STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
156196c1766STakashi Iwai 	struct nid_path *array = spec->paths.list;
157196c1766STakashi Iwai 	ssize_t idx;
158196c1766STakashi Iwai 
159196c1766STakashi Iwai 	if (!spec->paths.used)
160196c1766STakashi Iwai 		return 0;
161196c1766STakashi Iwai 	idx = path - array;
162196c1766STakashi Iwai 	if (idx < 0 || idx >= spec->paths.used)
163196c1766STakashi Iwai 		return 0;
164196c1766STakashi Iwai 	return idx + 1;
165196c1766STakashi Iwai }
166196c1766STakashi Iwai 
167196c1766STakashi Iwai /* get the path instance corresponding to the given index number */
168196c1766STakashi Iwai struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx)
169196c1766STakashi Iwai {
170196c1766STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
171196c1766STakashi Iwai 
172196c1766STakashi Iwai 	if (idx <= 0 || idx > spec->paths.used)
173196c1766STakashi Iwai 		return NULL;
174196c1766STakashi Iwai 	return snd_array_elem(&spec->paths, idx - 1);
175196c1766STakashi Iwai }
176196c1766STakashi Iwai 
177352f7f91STakashi Iwai /* check whether the given DAC is already found in any existing paths */
178352f7f91STakashi Iwai static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
1791da177e4SLinus Torvalds {
180352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
181352f7f91STakashi Iwai 	int i;
182352f7f91STakashi Iwai 
183352f7f91STakashi Iwai 	for (i = 0; i < spec->paths.used; i++) {
184352f7f91STakashi Iwai 		struct nid_path *path = snd_array_elem(&spec->paths, i);
185352f7f91STakashi Iwai 		if (path->path[0] == nid)
186352f7f91STakashi Iwai 			return true;
187352f7f91STakashi Iwai 	}
188352f7f91STakashi Iwai 	return false;
1891da177e4SLinus Torvalds }
1901da177e4SLinus Torvalds 
191352f7f91STakashi Iwai /* check whether the given two widgets can be connected */
192352f7f91STakashi Iwai static bool is_reachable_path(struct hda_codec *codec,
193352f7f91STakashi Iwai 			      hda_nid_t from_nid, hda_nid_t to_nid)
1941da177e4SLinus Torvalds {
195352f7f91STakashi Iwai 	if (!from_nid || !to_nid)
196352f7f91STakashi Iwai 		return false;
197352f7f91STakashi Iwai 	return snd_hda_get_conn_index(codec, to_nid, from_nid, true) >= 0;
1981da177e4SLinus Torvalds }
1991da177e4SLinus Torvalds 
200352f7f91STakashi Iwai /* nid, dir and idx */
201352f7f91STakashi Iwai #define AMP_VAL_COMPARE_MASK	(0xffff | (1U << 18) | (0x0f << 19))
202352f7f91STakashi Iwai 
203352f7f91STakashi Iwai /* check whether the given ctl is already assigned in any path elements */
204352f7f91STakashi Iwai static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type)
2051da177e4SLinus Torvalds {
206352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
207352f7f91STakashi Iwai 	int i;
208352f7f91STakashi Iwai 
209352f7f91STakashi Iwai 	val &= AMP_VAL_COMPARE_MASK;
210352f7f91STakashi Iwai 	for (i = 0; i < spec->paths.used; i++) {
211352f7f91STakashi Iwai 		struct nid_path *path = snd_array_elem(&spec->paths, i);
212352f7f91STakashi Iwai 		if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val)
213352f7f91STakashi Iwai 			return true;
214352f7f91STakashi Iwai 	}
215352f7f91STakashi Iwai 	return false;
2161da177e4SLinus Torvalds }
2171da177e4SLinus Torvalds 
218352f7f91STakashi Iwai /* check whether a control with the given (nid, dir, idx) was assigned */
219352f7f91STakashi Iwai static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid,
220cb53c626STakashi Iwai 			      int dir, int idx)
221cb53c626STakashi Iwai {
222352f7f91STakashi Iwai 	unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
223352f7f91STakashi Iwai 	return is_ctl_used(codec, val, NID_PATH_VOL_CTL) ||
224352f7f91STakashi Iwai 		is_ctl_used(codec, val, NID_PATH_MUTE_CTL);
225cb53c626STakashi Iwai }
226352f7f91STakashi Iwai 
2270c8c0f56STakashi Iwai static void print_nid_path(const char *pfx, struct nid_path *path)
2280c8c0f56STakashi Iwai {
2290c8c0f56STakashi Iwai 	char buf[40];
2300c8c0f56STakashi Iwai 	int i;
2310c8c0f56STakashi Iwai 
2320c8c0f56STakashi Iwai 
2330c8c0f56STakashi Iwai 	buf[0] = 0;
2340c8c0f56STakashi Iwai 	for (i = 0; i < path->depth; i++) {
2350c8c0f56STakashi Iwai 		char tmp[4];
2360c8c0f56STakashi Iwai 		sprintf(tmp, ":%02x", path->path[i]);
2370c8c0f56STakashi Iwai 		strlcat(buf, tmp, sizeof(buf));
2380c8c0f56STakashi Iwai 	}
2390c8c0f56STakashi Iwai 	snd_printdd("%s path: depth=%d %s\n", pfx, path->depth, buf);
2400c8c0f56STakashi Iwai }
2410c8c0f56STakashi Iwai 
242352f7f91STakashi Iwai /* called recursively */
243352f7f91STakashi Iwai static bool __parse_nid_path(struct hda_codec *codec,
244352f7f91STakashi Iwai 			     hda_nid_t from_nid, hda_nid_t to_nid,
245352f7f91STakashi Iwai 			     int with_aa_mix, struct nid_path *path, int depth)
246352f7f91STakashi Iwai {
247352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
248ee8e765bSTakashi Iwai 	const hda_nid_t *conn;
249352f7f91STakashi Iwai 	int i, nums;
250352f7f91STakashi Iwai 
251352f7f91STakashi Iwai 	if (to_nid == spec->mixer_nid) {
2524ac0eefaSTakashi Iwai 		if (with_aa_mix == HDA_PARSE_NO_AAMIX)
253352f7f91STakashi Iwai 			return false;
2544ac0eefaSTakashi Iwai 		with_aa_mix = HDA_PARSE_ALL; /* mark aa-mix is included */
255352f7f91STakashi Iwai 	}
256352f7f91STakashi Iwai 
257ee8e765bSTakashi Iwai 	nums = snd_hda_get_conn_list(codec, to_nid, &conn);
258352f7f91STakashi Iwai 	for (i = 0; i < nums; i++) {
259352f7f91STakashi Iwai 		if (conn[i] != from_nid) {
260352f7f91STakashi Iwai 			/* special case: when from_nid is 0,
261352f7f91STakashi Iwai 			 * try to find an empty DAC
262352f7f91STakashi Iwai 			 */
263352f7f91STakashi Iwai 			if (from_nid ||
264352f7f91STakashi Iwai 			    get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT ||
265352f7f91STakashi Iwai 			    is_dac_already_used(codec, conn[i]))
266352f7f91STakashi Iwai 				continue;
267352f7f91STakashi Iwai 		}
268352f7f91STakashi Iwai 		/* aa-mix is requested but not included? */
2694ac0eefaSTakashi Iwai 		if (!(spec->mixer_nid && with_aa_mix == HDA_PARSE_ONLY_AAMIX))
270352f7f91STakashi Iwai 			goto found;
271352f7f91STakashi Iwai 	}
272352f7f91STakashi Iwai 	if (depth >= MAX_NID_PATH_DEPTH)
273352f7f91STakashi Iwai 		return false;
274352f7f91STakashi Iwai 	for (i = 0; i < nums; i++) {
275352f7f91STakashi Iwai 		unsigned int type;
276352f7f91STakashi Iwai 		type = get_wcaps_type(get_wcaps(codec, conn[i]));
277352f7f91STakashi Iwai 		if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN ||
278352f7f91STakashi Iwai 		    type == AC_WID_PIN)
279352f7f91STakashi Iwai 			continue;
280352f7f91STakashi Iwai 		if (__parse_nid_path(codec, from_nid, conn[i],
281352f7f91STakashi Iwai 				     with_aa_mix, path, depth + 1))
282352f7f91STakashi Iwai 			goto found;
283352f7f91STakashi Iwai 	}
284352f7f91STakashi Iwai 	return false;
285352f7f91STakashi Iwai 
286352f7f91STakashi Iwai  found:
287352f7f91STakashi Iwai 	path->path[path->depth] = conn[i];
288f5172a7eSTakashi Iwai 	if (conn[i] == spec->mixer_nid)
289f5172a7eSTakashi Iwai 		path->with_aa_mix = true;
290352f7f91STakashi Iwai 	path->idx[path->depth + 1] = i;
291352f7f91STakashi Iwai 	if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX)
292352f7f91STakashi Iwai 		path->multi[path->depth + 1] = 1;
293352f7f91STakashi Iwai 	path->depth++;
294352f7f91STakashi Iwai 	return true;
295352f7f91STakashi Iwai }
296352f7f91STakashi Iwai 
297352f7f91STakashi Iwai /* parse the widget path from the given nid to the target nid;
298352f7f91STakashi Iwai  * when @from_nid is 0, try to find an empty DAC;
2994ac0eefaSTakashi Iwai  * when @with_aa_mix is HDA_PARSE_NO_AAMIX, paths with spec->mixer_nid are
3004ac0eefaSTakashi Iwai  * excluded, only the paths that don't go through the mixer will be chosen.
3014ac0eefaSTakashi Iwai  * when @with_aa_mix is HDA_PARSE_ONLY_AAMIX, only the paths going through
3024ac0eefaSTakashi Iwai  * spec->mixer_nid will be chosen.
3034ac0eefaSTakashi Iwai  * when @with_aa_mix is HDA_PARSE_ALL, no special handling about mixer widget.
304352f7f91STakashi Iwai  */
305352f7f91STakashi Iwai bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
306352f7f91STakashi Iwai 			    hda_nid_t to_nid, int with_aa_mix,
307352f7f91STakashi Iwai 			    struct nid_path *path)
308352f7f91STakashi Iwai {
309352f7f91STakashi Iwai 	if (__parse_nid_path(codec, from_nid, to_nid, with_aa_mix, path, 1)) {
310352f7f91STakashi Iwai 		path->path[path->depth] = to_nid;
311352f7f91STakashi Iwai 		path->depth++;
312352f7f91STakashi Iwai 		return true;
313352f7f91STakashi Iwai 	}
314352f7f91STakashi Iwai 	return false;
315352f7f91STakashi Iwai }
316352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_parse_nid_path);
317352f7f91STakashi Iwai 
318352f7f91STakashi Iwai /*
319352f7f91STakashi Iwai  * parse the path between the given NIDs and add to the path list.
320352f7f91STakashi Iwai  * if no valid path is found, return NULL
321352f7f91STakashi Iwai  */
322352f7f91STakashi Iwai struct nid_path *
323352f7f91STakashi Iwai snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
324352f7f91STakashi Iwai 		     hda_nid_t to_nid, int with_aa_mix)
325352f7f91STakashi Iwai {
326352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
327352f7f91STakashi Iwai 	struct nid_path *path;
328352f7f91STakashi Iwai 
329352f7f91STakashi Iwai 	if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid))
330352f7f91STakashi Iwai 		return NULL;
331352f7f91STakashi Iwai 
332f5172a7eSTakashi Iwai 	/* check whether the path has been already added */
333f5172a7eSTakashi Iwai 	path = get_nid_path(codec, from_nid, to_nid, with_aa_mix);
334f5172a7eSTakashi Iwai 	if (path)
335f5172a7eSTakashi Iwai 		return path;
336f5172a7eSTakashi Iwai 
337352f7f91STakashi Iwai 	path = snd_array_new(&spec->paths);
338352f7f91STakashi Iwai 	if (!path)
339352f7f91STakashi Iwai 		return NULL;
340352f7f91STakashi Iwai 	memset(path, 0, sizeof(*path));
341352f7f91STakashi Iwai 	if (snd_hda_parse_nid_path(codec, from_nid, to_nid, with_aa_mix, path))
342352f7f91STakashi Iwai 		return path;
343352f7f91STakashi Iwai 	/* push back */
344352f7f91STakashi Iwai 	spec->paths.used--;
345352f7f91STakashi Iwai 	return NULL;
346352f7f91STakashi Iwai }
347352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_add_new_path);
348352f7f91STakashi Iwai 
349352f7f91STakashi Iwai /* look for an empty DAC slot */
350352f7f91STakashi Iwai static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin,
351352f7f91STakashi Iwai 			      bool is_digital)
352352f7f91STakashi Iwai {
353352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
354352f7f91STakashi Iwai 	bool cap_digital;
355352f7f91STakashi Iwai 	int i;
356352f7f91STakashi Iwai 
357352f7f91STakashi Iwai 	for (i = 0; i < spec->num_all_dacs; i++) {
358352f7f91STakashi Iwai 		hda_nid_t nid = spec->all_dacs[i];
359352f7f91STakashi Iwai 		if (!nid || is_dac_already_used(codec, nid))
360352f7f91STakashi Iwai 			continue;
361352f7f91STakashi Iwai 		cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL);
362352f7f91STakashi Iwai 		if (is_digital != cap_digital)
363352f7f91STakashi Iwai 			continue;
364352f7f91STakashi Iwai 		if (is_reachable_path(codec, nid, pin))
365352f7f91STakashi Iwai 			return nid;
366352f7f91STakashi Iwai 	}
367352f7f91STakashi Iwai 	return 0;
368352f7f91STakashi Iwai }
369352f7f91STakashi Iwai 
370352f7f91STakashi Iwai /* replace the channels in the composed amp value with the given number */
371352f7f91STakashi Iwai static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs)
372352f7f91STakashi Iwai {
373352f7f91STakashi Iwai 	val &= ~(0x3U << 16);
374352f7f91STakashi Iwai 	val |= chs << 16;
375352f7f91STakashi Iwai 	return val;
376352f7f91STakashi Iwai }
377352f7f91STakashi Iwai 
378352f7f91STakashi Iwai /* check whether the widget has the given amp capability for the direction */
379352f7f91STakashi Iwai static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
380352f7f91STakashi Iwai 			   int dir, unsigned int bits)
381352f7f91STakashi Iwai {
382352f7f91STakashi Iwai 	if (!nid)
383352f7f91STakashi Iwai 		return false;
384352f7f91STakashi Iwai 	if (get_wcaps(codec, nid) & (1 << (dir + 1)))
385352f7f91STakashi Iwai 		if (query_amp_caps(codec, nid, dir) & bits)
386352f7f91STakashi Iwai 			return true;
387352f7f91STakashi Iwai 	return false;
388352f7f91STakashi Iwai }
389352f7f91STakashi Iwai 
390352f7f91STakashi Iwai #define nid_has_mute(codec, nid, dir) \
391352f7f91STakashi Iwai 	check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE)
392352f7f91STakashi Iwai #define nid_has_volume(codec, nid, dir) \
393352f7f91STakashi Iwai 	check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS)
394352f7f91STakashi Iwai 
395352f7f91STakashi Iwai /* look for a widget suitable for assigning a mute switch in the path */
396352f7f91STakashi Iwai static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec,
397352f7f91STakashi Iwai 				       struct nid_path *path)
398352f7f91STakashi Iwai {
399352f7f91STakashi Iwai 	int i;
400352f7f91STakashi Iwai 
401352f7f91STakashi Iwai 	for (i = path->depth - 1; i >= 0; i--) {
402352f7f91STakashi Iwai 		if (nid_has_mute(codec, path->path[i], HDA_OUTPUT))
403352f7f91STakashi Iwai 			return path->path[i];
404352f7f91STakashi Iwai 		if (i != path->depth - 1 && i != 0 &&
405352f7f91STakashi Iwai 		    nid_has_mute(codec, path->path[i], HDA_INPUT))
406352f7f91STakashi Iwai 			return path->path[i];
407352f7f91STakashi Iwai 	}
408352f7f91STakashi Iwai 	return 0;
409352f7f91STakashi Iwai }
410352f7f91STakashi Iwai 
411352f7f91STakashi Iwai /* look for a widget suitable for assigning a volume ctl in the path */
412352f7f91STakashi Iwai static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec,
413352f7f91STakashi Iwai 				      struct nid_path *path)
414352f7f91STakashi Iwai {
415352f7f91STakashi Iwai 	int i;
416352f7f91STakashi Iwai 
417352f7f91STakashi Iwai 	for (i = path->depth - 1; i >= 0; i--) {
418352f7f91STakashi Iwai 		if (nid_has_volume(codec, path->path[i], HDA_OUTPUT))
419352f7f91STakashi Iwai 			return path->path[i];
420352f7f91STakashi Iwai 	}
421352f7f91STakashi Iwai 	return 0;
422352f7f91STakashi Iwai }
423352f7f91STakashi Iwai 
424352f7f91STakashi Iwai /*
425352f7f91STakashi Iwai  * path activation / deactivation
426352f7f91STakashi Iwai  */
427352f7f91STakashi Iwai 
428352f7f91STakashi Iwai /* can have the amp-in capability? */
429352f7f91STakashi Iwai static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx)
430352f7f91STakashi Iwai {
431352f7f91STakashi Iwai 	hda_nid_t nid = path->path[idx];
432352f7f91STakashi Iwai 	unsigned int caps = get_wcaps(codec, nid);
433352f7f91STakashi Iwai 	unsigned int type = get_wcaps_type(caps);
434352f7f91STakashi Iwai 
435352f7f91STakashi Iwai 	if (!(caps & AC_WCAP_IN_AMP))
436352f7f91STakashi Iwai 		return false;
437352f7f91STakashi Iwai 	if (type == AC_WID_PIN && idx > 0) /* only for input pins */
438352f7f91STakashi Iwai 		return false;
439352f7f91STakashi Iwai 	return true;
440352f7f91STakashi Iwai }
441352f7f91STakashi Iwai 
442352f7f91STakashi Iwai /* can have the amp-out capability? */
443352f7f91STakashi Iwai static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx)
444352f7f91STakashi Iwai {
445352f7f91STakashi Iwai 	hda_nid_t nid = path->path[idx];
446352f7f91STakashi Iwai 	unsigned int caps = get_wcaps(codec, nid);
447352f7f91STakashi Iwai 	unsigned int type = get_wcaps_type(caps);
448352f7f91STakashi Iwai 
449352f7f91STakashi Iwai 	if (!(caps & AC_WCAP_OUT_AMP))
450352f7f91STakashi Iwai 		return false;
451352f7f91STakashi Iwai 	if (type == AC_WID_PIN && !idx) /* only for output pins */
452352f7f91STakashi Iwai 		return false;
453352f7f91STakashi Iwai 	return true;
454352f7f91STakashi Iwai }
455352f7f91STakashi Iwai 
456352f7f91STakashi Iwai /* check whether the given (nid,dir,idx) is active */
457352f7f91STakashi Iwai static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid,
458352f7f91STakashi Iwai 			  unsigned int idx, unsigned int dir)
459352f7f91STakashi Iwai {
460352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
461352f7f91STakashi Iwai 	int i, n;
462352f7f91STakashi Iwai 
463352f7f91STakashi Iwai 	for (n = 0; n < spec->paths.used; n++) {
464352f7f91STakashi Iwai 		struct nid_path *path = snd_array_elem(&spec->paths, n);
465352f7f91STakashi Iwai 		if (!path->active)
466352f7f91STakashi Iwai 			continue;
467352f7f91STakashi Iwai 		for (i = 0; i < path->depth; i++) {
468352f7f91STakashi Iwai 			if (path->path[i] == nid) {
469352f7f91STakashi Iwai 				if (dir == HDA_OUTPUT || path->idx[i] == idx)
470352f7f91STakashi Iwai 					return true;
471352f7f91STakashi Iwai 				break;
472352f7f91STakashi Iwai 			}
473352f7f91STakashi Iwai 		}
474352f7f91STakashi Iwai 	}
475352f7f91STakashi Iwai 	return false;
476352f7f91STakashi Iwai }
477352f7f91STakashi Iwai 
478352f7f91STakashi Iwai /* get the default amp value for the target state */
479352f7f91STakashi Iwai static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid,
480352f7f91STakashi Iwai 				   int dir, bool enable)
481352f7f91STakashi Iwai {
482352f7f91STakashi Iwai 	unsigned int caps;
483352f7f91STakashi Iwai 	unsigned int val = 0;
484352f7f91STakashi Iwai 
485352f7f91STakashi Iwai 	caps = query_amp_caps(codec, nid, dir);
486352f7f91STakashi Iwai 	if (caps & AC_AMPCAP_NUM_STEPS) {
487352f7f91STakashi Iwai 		/* set to 0dB */
488352f7f91STakashi Iwai 		if (enable)
489352f7f91STakashi Iwai 			val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
490352f7f91STakashi Iwai 	}
491352f7f91STakashi Iwai 	if (caps & AC_AMPCAP_MUTE) {
492352f7f91STakashi Iwai 		if (!enable)
493352f7f91STakashi Iwai 			val |= HDA_AMP_MUTE;
494352f7f91STakashi Iwai 	}
495352f7f91STakashi Iwai 	return val;
496352f7f91STakashi Iwai }
497352f7f91STakashi Iwai 
498352f7f91STakashi Iwai /* initialize the amp value (only at the first time) */
499352f7f91STakashi Iwai static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
500352f7f91STakashi Iwai {
501352f7f91STakashi Iwai 	int val = get_amp_val_to_activate(codec, nid, dir, false);
502352f7f91STakashi Iwai 	snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
503352f7f91STakashi Iwai }
504352f7f91STakashi Iwai 
505352f7f91STakashi Iwai static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir,
506352f7f91STakashi Iwai 			 int idx, bool enable)
507352f7f91STakashi Iwai {
508352f7f91STakashi Iwai 	int val;
509352f7f91STakashi Iwai 	if (is_ctl_associated(codec, nid, dir, idx) ||
510985803caSTakashi Iwai 	    (!enable && is_active_nid(codec, nid, dir, idx)))
511352f7f91STakashi Iwai 		return;
512352f7f91STakashi Iwai 	val = get_amp_val_to_activate(codec, nid, dir, enable);
513352f7f91STakashi Iwai 	snd_hda_codec_amp_stereo(codec, nid, dir, idx, 0xff, val);
514352f7f91STakashi Iwai }
515352f7f91STakashi Iwai 
516352f7f91STakashi Iwai static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
517352f7f91STakashi Iwai 			     int i, bool enable)
518352f7f91STakashi Iwai {
519352f7f91STakashi Iwai 	hda_nid_t nid = path->path[i];
520352f7f91STakashi Iwai 	init_amp(codec, nid, HDA_OUTPUT, 0);
521352f7f91STakashi Iwai 	activate_amp(codec, nid, HDA_OUTPUT, 0, enable);
522352f7f91STakashi Iwai }
523352f7f91STakashi Iwai 
524352f7f91STakashi Iwai static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
525352f7f91STakashi Iwai 			    int i, bool enable, bool add_aamix)
526352f7f91STakashi Iwai {
527352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
528ee8e765bSTakashi Iwai 	const hda_nid_t *conn;
529352f7f91STakashi Iwai 	int n, nums, idx;
530352f7f91STakashi Iwai 	int type;
531352f7f91STakashi Iwai 	hda_nid_t nid = path->path[i];
532352f7f91STakashi Iwai 
533ee8e765bSTakashi Iwai 	nums = snd_hda_get_conn_list(codec, nid, &conn);
534352f7f91STakashi Iwai 	type = get_wcaps_type(get_wcaps(codec, nid));
535352f7f91STakashi Iwai 	if (type == AC_WID_PIN ||
536352f7f91STakashi Iwai 	    (type == AC_WID_AUD_IN && codec->single_adc_amp)) {
537352f7f91STakashi Iwai 		nums = 1;
538352f7f91STakashi Iwai 		idx = 0;
539352f7f91STakashi Iwai 	} else
540352f7f91STakashi Iwai 		idx = path->idx[i];
541352f7f91STakashi Iwai 
542352f7f91STakashi Iwai 	for (n = 0; n < nums; n++)
543352f7f91STakashi Iwai 		init_amp(codec, nid, HDA_INPUT, n);
544352f7f91STakashi Iwai 
545352f7f91STakashi Iwai 	if (is_ctl_associated(codec, nid, HDA_INPUT, idx))
546352f7f91STakashi Iwai 		return;
547352f7f91STakashi Iwai 
548352f7f91STakashi Iwai 	/* here is a little bit tricky in comparison with activate_amp_out();
549352f7f91STakashi Iwai 	 * when aa-mixer is available, we need to enable the path as well
550352f7f91STakashi Iwai 	 */
551352f7f91STakashi Iwai 	for (n = 0; n < nums; n++) {
552352f7f91STakashi Iwai 		if (n != idx && (!add_aamix || conn[n] != spec->mixer_nid))
553352f7f91STakashi Iwai 			continue;
554352f7f91STakashi Iwai 		activate_amp(codec, nid, HDA_INPUT, n, enable);
555352f7f91STakashi Iwai 	}
556352f7f91STakashi Iwai }
557352f7f91STakashi Iwai 
558352f7f91STakashi Iwai /* activate or deactivate the given path
559352f7f91STakashi Iwai  * if @add_aamix is set, enable the input from aa-mix NID as well (if any)
560352f7f91STakashi Iwai  */
561352f7f91STakashi Iwai void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
562352f7f91STakashi Iwai 			   bool enable, bool add_aamix)
563352f7f91STakashi Iwai {
564352f7f91STakashi Iwai 	int i;
565352f7f91STakashi Iwai 
566352f7f91STakashi Iwai 	if (!enable)
567352f7f91STakashi Iwai 		path->active = false;
568352f7f91STakashi Iwai 
569352f7f91STakashi Iwai 	for (i = path->depth - 1; i >= 0; i--) {
570352f7f91STakashi Iwai 		if (enable && path->multi[i])
571352f7f91STakashi Iwai 			snd_hda_codec_write_cache(codec, path->path[i], 0,
572352f7f91STakashi Iwai 					    AC_VERB_SET_CONNECT_SEL,
573352f7f91STakashi Iwai 					    path->idx[i]);
574352f7f91STakashi Iwai 		if (has_amp_in(codec, path, i))
575352f7f91STakashi Iwai 			activate_amp_in(codec, path, i, enable, add_aamix);
576352f7f91STakashi Iwai 		if (has_amp_out(codec, path, i))
577352f7f91STakashi Iwai 			activate_amp_out(codec, path, i, enable);
578352f7f91STakashi Iwai 	}
579352f7f91STakashi Iwai 
580352f7f91STakashi Iwai 	if (enable)
581352f7f91STakashi Iwai 		path->active = true;
582352f7f91STakashi Iwai }
583352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_activate_path);
584352f7f91STakashi Iwai 
585d5a9f1bbSTakashi Iwai /* turn on/off EAPD on the given pin */
586d5a9f1bbSTakashi Iwai static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable)
587d5a9f1bbSTakashi Iwai {
588d5a9f1bbSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
589d5a9f1bbSTakashi Iwai 	if (spec->own_eapd_ctl ||
590d5a9f1bbSTakashi Iwai 	    !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD))
591d5a9f1bbSTakashi Iwai 		return;
592ecac3ed1STakashi Iwai 	if (codec->inv_eapd)
593ecac3ed1STakashi Iwai 		enable = !enable;
594d5a9f1bbSTakashi Iwai 	snd_hda_codec_update_cache(codec, pin, 0,
595d5a9f1bbSTakashi Iwai 				   AC_VERB_SET_EAPD_BTLENABLE,
596d5a9f1bbSTakashi Iwai 				   enable ? 0x02 : 0x00);
597d5a9f1bbSTakashi Iwai }
598d5a9f1bbSTakashi Iwai 
599352f7f91STakashi Iwai 
600352f7f91STakashi Iwai /*
601352f7f91STakashi Iwai  * Helper functions for creating mixer ctl elements
602352f7f91STakashi Iwai  */
603352f7f91STakashi Iwai 
604352f7f91STakashi Iwai enum {
605352f7f91STakashi Iwai 	HDA_CTL_WIDGET_VOL,
606352f7f91STakashi Iwai 	HDA_CTL_WIDGET_MUTE,
607352f7f91STakashi Iwai 	HDA_CTL_BIND_MUTE,
608352f7f91STakashi Iwai 	HDA_CTL_BIND_VOL,
609352f7f91STakashi Iwai 	HDA_CTL_BIND_SW,
610352f7f91STakashi Iwai };
611352f7f91STakashi Iwai static const struct snd_kcontrol_new control_templates[] = {
612352f7f91STakashi Iwai 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
613352f7f91STakashi Iwai 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
614352f7f91STakashi Iwai 	HDA_BIND_MUTE(NULL, 0, 0, 0),
615352f7f91STakashi Iwai 	HDA_BIND_VOL(NULL, 0),
616352f7f91STakashi Iwai 	HDA_BIND_SW(NULL, 0),
617352f7f91STakashi Iwai };
618352f7f91STakashi Iwai 
619352f7f91STakashi Iwai /* add dynamic controls from template */
620352f7f91STakashi Iwai static int add_control(struct hda_gen_spec *spec, int type, const char *name,
621352f7f91STakashi Iwai 		       int cidx, unsigned long val)
622352f7f91STakashi Iwai {
623352f7f91STakashi Iwai 	struct snd_kcontrol_new *knew;
624352f7f91STakashi Iwai 
62512c93df6STakashi Iwai 	knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]);
626352f7f91STakashi Iwai 	if (!knew)
627352f7f91STakashi Iwai 		return -ENOMEM;
628352f7f91STakashi Iwai 	knew->index = cidx;
629352f7f91STakashi Iwai 	if (get_amp_nid_(val))
630352f7f91STakashi Iwai 		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
631352f7f91STakashi Iwai 	knew->private_value = val;
632352f7f91STakashi Iwai 	return 0;
633352f7f91STakashi Iwai }
634352f7f91STakashi Iwai 
635352f7f91STakashi Iwai static int add_control_with_pfx(struct hda_gen_spec *spec, int type,
636352f7f91STakashi Iwai 				const char *pfx, const char *dir,
637352f7f91STakashi Iwai 				const char *sfx, int cidx, unsigned long val)
638352f7f91STakashi Iwai {
639352f7f91STakashi Iwai 	char name[32];
640352f7f91STakashi Iwai 	snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
641352f7f91STakashi Iwai 	return add_control(spec, type, name, cidx, val);
642352f7f91STakashi Iwai }
643352f7f91STakashi Iwai 
644352f7f91STakashi Iwai #define add_pb_vol_ctrl(spec, type, pfx, val)			\
645352f7f91STakashi Iwai 	add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
646352f7f91STakashi Iwai #define add_pb_sw_ctrl(spec, type, pfx, val)			\
647352f7f91STakashi Iwai 	add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
648352f7f91STakashi Iwai #define __add_pb_vol_ctrl(spec, type, pfx, cidx, val)			\
649352f7f91STakashi Iwai 	add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
650352f7f91STakashi Iwai #define __add_pb_sw_ctrl(spec, type, pfx, cidx, val)			\
651352f7f91STakashi Iwai 	add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
652352f7f91STakashi Iwai 
653352f7f91STakashi Iwai static int add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx,
654352f7f91STakashi Iwai 		       unsigned int chs, struct nid_path *path)
655352f7f91STakashi Iwai {
656352f7f91STakashi Iwai 	unsigned int val;
657352f7f91STakashi Iwai 	if (!path)
658352f7f91STakashi Iwai 		return 0;
659352f7f91STakashi Iwai 	val = path->ctls[NID_PATH_VOL_CTL];
660352f7f91STakashi Iwai 	if (!val)
661352f7f91STakashi Iwai 		return 0;
662352f7f91STakashi Iwai 	val = amp_val_replace_channels(val, chs);
663352f7f91STakashi Iwai 	return __add_pb_vol_ctrl(codec->spec, HDA_CTL_WIDGET_VOL, pfx, cidx, val);
664352f7f91STakashi Iwai }
665352f7f91STakashi Iwai 
666352f7f91STakashi Iwai /* return the channel bits suitable for the given path->ctls[] */
667352f7f91STakashi Iwai static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path,
668352f7f91STakashi Iwai 			       int type)
669352f7f91STakashi Iwai {
670352f7f91STakashi Iwai 	int chs = 1; /* mono (left only) */
671352f7f91STakashi Iwai 	if (path) {
672352f7f91STakashi Iwai 		hda_nid_t nid = get_amp_nid_(path->ctls[type]);
673352f7f91STakashi Iwai 		if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO))
674352f7f91STakashi Iwai 			chs = 3; /* stereo */
675352f7f91STakashi Iwai 	}
676352f7f91STakashi Iwai 	return chs;
677352f7f91STakashi Iwai }
678352f7f91STakashi Iwai 
679352f7f91STakashi Iwai static int add_stereo_vol(struct hda_codec *codec, const char *pfx, int cidx,
680352f7f91STakashi Iwai 			  struct nid_path *path)
681352f7f91STakashi Iwai {
682352f7f91STakashi Iwai 	int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL);
683352f7f91STakashi Iwai 	return add_vol_ctl(codec, pfx, cidx, chs, path);
684352f7f91STakashi Iwai }
685352f7f91STakashi Iwai 
686352f7f91STakashi Iwai /* create a mute-switch for the given mixer widget;
687352f7f91STakashi Iwai  * if it has multiple sources (e.g. DAC and loopback), create a bind-mute
688352f7f91STakashi Iwai  */
689352f7f91STakashi Iwai static int add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx,
690352f7f91STakashi Iwai 		      unsigned int chs, struct nid_path *path)
691352f7f91STakashi Iwai {
692352f7f91STakashi Iwai 	unsigned int val;
693352f7f91STakashi Iwai 	int type = HDA_CTL_WIDGET_MUTE;
694352f7f91STakashi Iwai 
695352f7f91STakashi Iwai 	if (!path)
696352f7f91STakashi Iwai 		return 0;
697352f7f91STakashi Iwai 	val = path->ctls[NID_PATH_MUTE_CTL];
698352f7f91STakashi Iwai 	if (!val)
699352f7f91STakashi Iwai 		return 0;
700352f7f91STakashi Iwai 	val = amp_val_replace_channels(val, chs);
701352f7f91STakashi Iwai 	if (get_amp_direction_(val) == HDA_INPUT) {
702352f7f91STakashi Iwai 		hda_nid_t nid = get_amp_nid_(val);
703352f7f91STakashi Iwai 		int nums = snd_hda_get_num_conns(codec, nid);
704352f7f91STakashi Iwai 		if (nums > 1) {
705352f7f91STakashi Iwai 			type = HDA_CTL_BIND_MUTE;
706352f7f91STakashi Iwai 			val |= nums << 19;
707352f7f91STakashi Iwai 		}
708352f7f91STakashi Iwai 	}
709352f7f91STakashi Iwai 	return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
710352f7f91STakashi Iwai }
711352f7f91STakashi Iwai 
712352f7f91STakashi Iwai static int add_stereo_sw(struct hda_codec *codec, const char *pfx,
713352f7f91STakashi Iwai 				  int cidx, struct nid_path *path)
714352f7f91STakashi Iwai {
715352f7f91STakashi Iwai 	int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL);
716352f7f91STakashi Iwai 	return add_sw_ctl(codec, pfx, cidx, chs, path);
717352f7f91STakashi Iwai }
718352f7f91STakashi Iwai 
719352f7f91STakashi Iwai static const char * const channel_name[4] = {
720352f7f91STakashi Iwai 	"Front", "Surround", "CLFE", "Side"
721352f7f91STakashi Iwai };
722352f7f91STakashi Iwai 
723352f7f91STakashi Iwai /* give some appropriate ctl name prefix for the given line out channel */
724352f7f91STakashi Iwai static const char *get_line_out_pfx(struct hda_gen_spec *spec, int ch,
725352f7f91STakashi Iwai 				    bool can_be_master, int *index)
726352f7f91STakashi Iwai {
727352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
728352f7f91STakashi Iwai 
729352f7f91STakashi Iwai 	*index = 0;
730352f7f91STakashi Iwai 	if (cfg->line_outs == 1 && !spec->multi_ios &&
731352f7f91STakashi Iwai 	    !cfg->hp_outs && !cfg->speaker_outs && can_be_master)
732352f7f91STakashi Iwai 		return spec->vmaster_mute.hook ? "PCM" : "Master";
733352f7f91STakashi Iwai 
734352f7f91STakashi Iwai 	/* if there is really a single DAC used in the whole output paths,
735352f7f91STakashi Iwai 	 * use it master (or "PCM" if a vmaster hook is present)
736352f7f91STakashi Iwai 	 */
737352f7f91STakashi Iwai 	if (spec->multiout.num_dacs == 1 && !spec->mixer_nid &&
738352f7f91STakashi Iwai 	    !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0])
739352f7f91STakashi Iwai 		return spec->vmaster_mute.hook ? "PCM" : "Master";
740352f7f91STakashi Iwai 
741352f7f91STakashi Iwai 	switch (cfg->line_out_type) {
742352f7f91STakashi Iwai 	case AUTO_PIN_SPEAKER_OUT:
743352f7f91STakashi Iwai 		if (cfg->line_outs == 1)
744352f7f91STakashi Iwai 			return "Speaker";
745352f7f91STakashi Iwai 		if (cfg->line_outs == 2)
746352f7f91STakashi Iwai 			return ch ? "Bass Speaker" : "Speaker";
747352f7f91STakashi Iwai 		break;
748352f7f91STakashi Iwai 	case AUTO_PIN_HP_OUT:
749352f7f91STakashi Iwai 		/* for multi-io case, only the primary out */
750352f7f91STakashi Iwai 		if (ch && spec->multi_ios)
751352f7f91STakashi Iwai 			break;
752352f7f91STakashi Iwai 		*index = ch;
753352f7f91STakashi Iwai 		return "Headphone";
754352f7f91STakashi Iwai 	default:
755352f7f91STakashi Iwai 		if (cfg->line_outs == 1 && !spec->multi_ios)
756352f7f91STakashi Iwai 			return "PCM";
757352f7f91STakashi Iwai 		break;
758352f7f91STakashi Iwai 	}
759352f7f91STakashi Iwai 	if (ch >= ARRAY_SIZE(channel_name)) {
760352f7f91STakashi Iwai 		snd_BUG();
761352f7f91STakashi Iwai 		return "PCM";
762352f7f91STakashi Iwai 	}
763352f7f91STakashi Iwai 
764352f7f91STakashi Iwai 	return channel_name[ch];
765352f7f91STakashi Iwai }
766352f7f91STakashi Iwai 
767352f7f91STakashi Iwai /*
768352f7f91STakashi Iwai  * Parse output paths
769352f7f91STakashi Iwai  */
770352f7f91STakashi Iwai 
771352f7f91STakashi Iwai /* badness definition */
772352f7f91STakashi Iwai enum {
773352f7f91STakashi Iwai 	/* No primary DAC is found for the main output */
774352f7f91STakashi Iwai 	BAD_NO_PRIMARY_DAC = 0x10000,
775352f7f91STakashi Iwai 	/* No DAC is found for the extra output */
776352f7f91STakashi Iwai 	BAD_NO_DAC = 0x4000,
777352f7f91STakashi Iwai 	/* No possible multi-ios */
778352f7f91STakashi Iwai 	BAD_MULTI_IO = 0x103,
779352f7f91STakashi Iwai 	/* No individual DAC for extra output */
780352f7f91STakashi Iwai 	BAD_NO_EXTRA_DAC = 0x102,
781352f7f91STakashi Iwai 	/* No individual DAC for extra surrounds */
782352f7f91STakashi Iwai 	BAD_NO_EXTRA_SURR_DAC = 0x101,
783352f7f91STakashi Iwai 	/* Primary DAC shared with main surrounds */
784352f7f91STakashi Iwai 	BAD_SHARED_SURROUND = 0x100,
785352f7f91STakashi Iwai 	/* Primary DAC shared with main CLFE */
786352f7f91STakashi Iwai 	BAD_SHARED_CLFE = 0x10,
787352f7f91STakashi Iwai 	/* Primary DAC shared with extra surrounds */
788352f7f91STakashi Iwai 	BAD_SHARED_EXTRA_SURROUND = 0x10,
789352f7f91STakashi Iwai 	/* Volume widget is shared */
790352f7f91STakashi Iwai 	BAD_SHARED_VOL = 0x10,
791352f7f91STakashi Iwai };
792352f7f91STakashi Iwai 
793352f7f91STakashi Iwai /* look for widgets in the path between the given NIDs appropriate for
794352f7f91STakashi Iwai  * volume and mute controls, and assign the values to ctls[].
795352f7f91STakashi Iwai  *
796352f7f91STakashi Iwai  * When no appropriate widget is found in the path, the badness value
797352f7f91STakashi Iwai  * is incremented depending on the situation.  The function returns the
798352f7f91STakashi Iwai  * total badness for both volume and mute controls.
799352f7f91STakashi Iwai  */
800352f7f91STakashi Iwai static int assign_out_path_ctls(struct hda_codec *codec, hda_nid_t pin,
801352f7f91STakashi Iwai 				hda_nid_t dac)
802352f7f91STakashi Iwai {
803352f7f91STakashi Iwai 	struct nid_path *path = snd_hda_get_nid_path(codec, dac, pin);
804352f7f91STakashi Iwai 	hda_nid_t nid;
805352f7f91STakashi Iwai 	unsigned int val;
806352f7f91STakashi Iwai 	int badness = 0;
807352f7f91STakashi Iwai 
808352f7f91STakashi Iwai 	if (!path)
809352f7f91STakashi Iwai 		return BAD_SHARED_VOL * 2;
810352f7f91STakashi Iwai 	nid = look_for_out_vol_nid(codec, path);
811352f7f91STakashi Iwai 	if (nid) {
812352f7f91STakashi Iwai 		val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
813352f7f91STakashi Iwai 		if (is_ctl_used(codec, val, NID_PATH_VOL_CTL))
814352f7f91STakashi Iwai 			badness += BAD_SHARED_VOL;
815352f7f91STakashi Iwai 		else
816352f7f91STakashi Iwai 			path->ctls[NID_PATH_VOL_CTL] = val;
817352f7f91STakashi Iwai 	} else
818352f7f91STakashi Iwai 		badness += BAD_SHARED_VOL;
819352f7f91STakashi Iwai 	nid = look_for_out_mute_nid(codec, path);
820352f7f91STakashi Iwai 	if (nid) {
821352f7f91STakashi Iwai 		unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid));
822352f7f91STakashi Iwai 		if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT ||
823352f7f91STakashi Iwai 		    nid_has_mute(codec, nid, HDA_OUTPUT))
824352f7f91STakashi Iwai 			val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
825352f7f91STakashi Iwai 		else
826352f7f91STakashi Iwai 			val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT);
827352f7f91STakashi Iwai 		if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL))
828352f7f91STakashi Iwai 			badness += BAD_SHARED_VOL;
829352f7f91STakashi Iwai 		else
830352f7f91STakashi Iwai 			path->ctls[NID_PATH_MUTE_CTL] = val;
831352f7f91STakashi Iwai 	} else
832352f7f91STakashi Iwai 		badness += BAD_SHARED_VOL;
833352f7f91STakashi Iwai 	return badness;
834352f7f91STakashi Iwai }
835352f7f91STakashi Iwai 
836352f7f91STakashi Iwai struct badness_table {
837352f7f91STakashi Iwai 	int no_primary_dac;	/* no primary DAC */
838352f7f91STakashi Iwai 	int no_dac;		/* no secondary DACs */
839352f7f91STakashi Iwai 	int shared_primary;	/* primary DAC is shared with main output */
840352f7f91STakashi Iwai 	int shared_surr;	/* secondary DAC shared with main or primary */
841352f7f91STakashi Iwai 	int shared_clfe;	/* third DAC shared with main or primary */
842352f7f91STakashi Iwai 	int shared_surr_main;	/* secondary DAC sahred with main/DAC0 */
843352f7f91STakashi Iwai };
844352f7f91STakashi Iwai 
845352f7f91STakashi Iwai static struct badness_table main_out_badness = {
846352f7f91STakashi Iwai 	.no_primary_dac = BAD_NO_PRIMARY_DAC,
847352f7f91STakashi Iwai 	.no_dac = BAD_NO_DAC,
848352f7f91STakashi Iwai 	.shared_primary = BAD_NO_PRIMARY_DAC,
849352f7f91STakashi Iwai 	.shared_surr = BAD_SHARED_SURROUND,
850352f7f91STakashi Iwai 	.shared_clfe = BAD_SHARED_CLFE,
851352f7f91STakashi Iwai 	.shared_surr_main = BAD_SHARED_SURROUND,
852352f7f91STakashi Iwai };
853352f7f91STakashi Iwai 
854352f7f91STakashi Iwai static struct badness_table extra_out_badness = {
855352f7f91STakashi Iwai 	.no_primary_dac = BAD_NO_DAC,
856352f7f91STakashi Iwai 	.no_dac = BAD_NO_DAC,
857352f7f91STakashi Iwai 	.shared_primary = BAD_NO_EXTRA_DAC,
858352f7f91STakashi Iwai 	.shared_surr = BAD_SHARED_EXTRA_SURROUND,
859352f7f91STakashi Iwai 	.shared_clfe = BAD_SHARED_EXTRA_SURROUND,
860352f7f91STakashi Iwai 	.shared_surr_main = BAD_NO_EXTRA_SURR_DAC,
861352f7f91STakashi Iwai };
862352f7f91STakashi Iwai 
863352f7f91STakashi Iwai /* try to assign DACs to pins and return the resultant badness */
864352f7f91STakashi Iwai static int try_assign_dacs(struct hda_codec *codec, int num_outs,
865352f7f91STakashi Iwai 			   const hda_nid_t *pins, hda_nid_t *dacs,
866196c1766STakashi Iwai 			   int *path_idx,
867352f7f91STakashi Iwai 			   const struct badness_table *bad)
868352f7f91STakashi Iwai {
869352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
870352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
871352f7f91STakashi Iwai 	int i, j;
872352f7f91STakashi Iwai 	int badness = 0;
873352f7f91STakashi Iwai 	hda_nid_t dac;
874352f7f91STakashi Iwai 
875352f7f91STakashi Iwai 	if (!num_outs)
876352f7f91STakashi Iwai 		return 0;
877352f7f91STakashi Iwai 
878352f7f91STakashi Iwai 	for (i = 0; i < num_outs; i++) {
8790c8c0f56STakashi Iwai 		struct nid_path *path;
880352f7f91STakashi Iwai 		hda_nid_t pin = pins[i];
8811e0b5286STakashi Iwai 
8821e0b5286STakashi Iwai 		if (dacs[i]) {
8831e0b5286STakashi Iwai 			badness += assign_out_path_ctls(codec, pin, dacs[i]);
8841e0b5286STakashi Iwai 			continue;
8851e0b5286STakashi Iwai 		}
8861e0b5286STakashi Iwai 
887352f7f91STakashi Iwai 		dacs[i] = look_for_dac(codec, pin, false);
888352f7f91STakashi Iwai 		if (!dacs[i] && !i) {
889352f7f91STakashi Iwai 			for (j = 1; j < num_outs; j++) {
890352f7f91STakashi Iwai 				if (is_reachable_path(codec, dacs[j], pin)) {
891352f7f91STakashi Iwai 					dacs[0] = dacs[j];
892352f7f91STakashi Iwai 					dacs[j] = 0;
893196c1766STakashi Iwai 					path_idx[j] = 0;
894352f7f91STakashi Iwai 					break;
895352f7f91STakashi Iwai 				}
896352f7f91STakashi Iwai 			}
897352f7f91STakashi Iwai 		}
898352f7f91STakashi Iwai 		dac = dacs[i];
899352f7f91STakashi Iwai 		if (!dac) {
900352f7f91STakashi Iwai 			if (is_reachable_path(codec, dacs[0], pin))
901352f7f91STakashi Iwai 				dac = dacs[0];
902352f7f91STakashi Iwai 			else if (cfg->line_outs > i &&
903352f7f91STakashi Iwai 				 is_reachable_path(codec, spec->private_dac_nids[i], pin))
904352f7f91STakashi Iwai 				dac = spec->private_dac_nids[i];
905352f7f91STakashi Iwai 			if (dac) {
906352f7f91STakashi Iwai 				if (!i)
907352f7f91STakashi Iwai 					badness += bad->shared_primary;
908352f7f91STakashi Iwai 				else if (i == 1)
909352f7f91STakashi Iwai 					badness += bad->shared_surr;
910352f7f91STakashi Iwai 				else
911352f7f91STakashi Iwai 					badness += bad->shared_clfe;
912352f7f91STakashi Iwai 			} else if (is_reachable_path(codec, spec->private_dac_nids[0], pin)) {
913352f7f91STakashi Iwai 				dac = spec->private_dac_nids[0];
914352f7f91STakashi Iwai 				badness += bad->shared_surr_main;
915352f7f91STakashi Iwai 			} else if (!i)
916352f7f91STakashi Iwai 				badness += bad->no_primary_dac;
917352f7f91STakashi Iwai 			else
918352f7f91STakashi Iwai 				badness += bad->no_dac;
919352f7f91STakashi Iwai 		}
9204ac0eefaSTakashi Iwai 		path = snd_hda_add_new_path(codec, dac, pin, HDA_PARSE_NO_AAMIX);
921117688a9STakashi Iwai 		if (!path && !i && spec->mixer_nid) {
922b3a8c745STakashi Iwai 			/* try with aamix */
923b3a8c745STakashi Iwai 			path = snd_hda_add_new_path(codec, dac, pin, HDA_PARSE_ALL);
924b3a8c745STakashi Iwai 		}
9250c8c0f56STakashi Iwai 		if (!path)
926352f7f91STakashi Iwai 			dac = dacs[i] = 0;
927e1284af7STakashi Iwai 		else {
9280c8c0f56STakashi Iwai 			print_nid_path("output", path);
929e1284af7STakashi Iwai 			path->active = true;
930196c1766STakashi Iwai 			path_idx[i] = snd_hda_get_path_idx(codec, path);
931e1284af7STakashi Iwai 		}
932352f7f91STakashi Iwai 		if (dac)
933352f7f91STakashi Iwai 			badness += assign_out_path_ctls(codec, pin, dac);
934352f7f91STakashi Iwai 	}
935352f7f91STakashi Iwai 
936352f7f91STakashi Iwai 	return badness;
937352f7f91STakashi Iwai }
938352f7f91STakashi Iwai 
939352f7f91STakashi Iwai /* return NID if the given pin has only a single connection to a certain DAC */
940352f7f91STakashi Iwai static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
941352f7f91STakashi Iwai {
942352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
943352f7f91STakashi Iwai 	int i;
944352f7f91STakashi Iwai 	hda_nid_t nid_found = 0;
945352f7f91STakashi Iwai 
946352f7f91STakashi Iwai 	for (i = 0; i < spec->num_all_dacs; i++) {
947352f7f91STakashi Iwai 		hda_nid_t nid = spec->all_dacs[i];
948352f7f91STakashi Iwai 		if (!nid || is_dac_already_used(codec, nid))
949352f7f91STakashi Iwai 			continue;
950352f7f91STakashi Iwai 		if (is_reachable_path(codec, nid, pin)) {
951352f7f91STakashi Iwai 			if (nid_found)
952352f7f91STakashi Iwai 				return 0;
953352f7f91STakashi Iwai 			nid_found = nid;
954352f7f91STakashi Iwai 		}
955352f7f91STakashi Iwai 	}
956352f7f91STakashi Iwai 	return nid_found;
957352f7f91STakashi Iwai }
958352f7f91STakashi Iwai 
959352f7f91STakashi Iwai /* check whether the given pin can be a multi-io pin */
960352f7f91STakashi Iwai static bool can_be_multiio_pin(struct hda_codec *codec,
961352f7f91STakashi Iwai 			       unsigned int location, hda_nid_t nid)
962352f7f91STakashi Iwai {
963352f7f91STakashi Iwai 	unsigned int defcfg, caps;
964352f7f91STakashi Iwai 
965352f7f91STakashi Iwai 	defcfg = snd_hda_codec_get_pincfg(codec, nid);
966352f7f91STakashi Iwai 	if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
967352f7f91STakashi Iwai 		return false;
968352f7f91STakashi Iwai 	if (location && get_defcfg_location(defcfg) != location)
969352f7f91STakashi Iwai 		return false;
970352f7f91STakashi Iwai 	caps = snd_hda_query_pin_caps(codec, nid);
971352f7f91STakashi Iwai 	if (!(caps & AC_PINCAP_OUT))
972352f7f91STakashi Iwai 		return false;
973352f7f91STakashi Iwai 	return true;
974352f7f91STakashi Iwai }
975352f7f91STakashi Iwai 
976e22aab7dSTakashi Iwai /* count the number of input pins that are capable to be multi-io */
977e22aab7dSTakashi Iwai static int count_multiio_pins(struct hda_codec *codec, hda_nid_t reference_pin)
978e22aab7dSTakashi Iwai {
979e22aab7dSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
980e22aab7dSTakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
981e22aab7dSTakashi Iwai 	unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
982e22aab7dSTakashi Iwai 	unsigned int location = get_defcfg_location(defcfg);
983e22aab7dSTakashi Iwai 	int type, i;
984e22aab7dSTakashi Iwai 	int num_pins = 0;
985e22aab7dSTakashi Iwai 
986e22aab7dSTakashi Iwai 	for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
987e22aab7dSTakashi Iwai 		for (i = 0; i < cfg->num_inputs; i++) {
988e22aab7dSTakashi Iwai 			if (cfg->inputs[i].type != type)
989e22aab7dSTakashi Iwai 				continue;
990e22aab7dSTakashi Iwai 			if (can_be_multiio_pin(codec, location,
991e22aab7dSTakashi Iwai 					       cfg->inputs[i].pin))
992e22aab7dSTakashi Iwai 				num_pins++;
993e22aab7dSTakashi Iwai 		}
994e22aab7dSTakashi Iwai 	}
995e22aab7dSTakashi Iwai 	return num_pins;
996e22aab7dSTakashi Iwai }
997e22aab7dSTakashi Iwai 
998352f7f91STakashi Iwai /*
999352f7f91STakashi Iwai  * multi-io helper
1000352f7f91STakashi Iwai  *
1001352f7f91STakashi Iwai  * When hardwired is set, try to fill ony hardwired pins, and returns
1002352f7f91STakashi Iwai  * zero if any pins are filled, non-zero if nothing found.
1003352f7f91STakashi Iwai  * When hardwired is off, try to fill possible input pins, and returns
1004352f7f91STakashi Iwai  * the badness value.
1005352f7f91STakashi Iwai  */
1006352f7f91STakashi Iwai static int fill_multi_ios(struct hda_codec *codec,
1007352f7f91STakashi Iwai 			  hda_nid_t reference_pin,
1008e22aab7dSTakashi Iwai 			  bool hardwired)
1009352f7f91STakashi Iwai {
1010352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1011352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
1012e22aab7dSTakashi Iwai 	int type, i, j, num_pins, old_pins;
1013352f7f91STakashi Iwai 	unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
1014352f7f91STakashi Iwai 	unsigned int location = get_defcfg_location(defcfg);
1015352f7f91STakashi Iwai 	int badness = 0;
1016352f7f91STakashi Iwai 
1017352f7f91STakashi Iwai 	old_pins = spec->multi_ios;
1018352f7f91STakashi Iwai 	if (old_pins >= 2)
1019352f7f91STakashi Iwai 		goto end_fill;
1020352f7f91STakashi Iwai 
1021e22aab7dSTakashi Iwai 	num_pins = count_multiio_pins(codec, reference_pin);
1022352f7f91STakashi Iwai 	if (num_pins < 2)
1023352f7f91STakashi Iwai 		goto end_fill;
1024352f7f91STakashi Iwai 
1025352f7f91STakashi Iwai 	for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
1026352f7f91STakashi Iwai 		for (i = 0; i < cfg->num_inputs; i++) {
10270c8c0f56STakashi Iwai 			struct nid_path *path;
1028352f7f91STakashi Iwai 			hda_nid_t nid = cfg->inputs[i].pin;
1029352f7f91STakashi Iwai 			hda_nid_t dac = 0;
1030352f7f91STakashi Iwai 
1031352f7f91STakashi Iwai 			if (cfg->inputs[i].type != type)
1032352f7f91STakashi Iwai 				continue;
1033352f7f91STakashi Iwai 			if (!can_be_multiio_pin(codec, location, nid))
1034352f7f91STakashi Iwai 				continue;
1035352f7f91STakashi Iwai 			for (j = 0; j < spec->multi_ios; j++) {
1036352f7f91STakashi Iwai 				if (nid == spec->multi_io[j].pin)
1037352f7f91STakashi Iwai 					break;
1038352f7f91STakashi Iwai 			}
1039352f7f91STakashi Iwai 			if (j < spec->multi_ios)
1040352f7f91STakashi Iwai 				continue;
1041352f7f91STakashi Iwai 
1042352f7f91STakashi Iwai 			if (hardwired)
1043352f7f91STakashi Iwai 				dac = get_dac_if_single(codec, nid);
1044352f7f91STakashi Iwai 			else if (!dac)
1045352f7f91STakashi Iwai 				dac = look_for_dac(codec, nid, false);
1046352f7f91STakashi Iwai 			if (!dac) {
1047352f7f91STakashi Iwai 				badness++;
1048352f7f91STakashi Iwai 				continue;
1049352f7f91STakashi Iwai 			}
10504ac0eefaSTakashi Iwai 			path = snd_hda_add_new_path(codec, dac, nid, HDA_PARSE_NO_AAMIX);
10510c8c0f56STakashi Iwai 			if (!path) {
1052352f7f91STakashi Iwai 				badness++;
1053352f7f91STakashi Iwai 				continue;
1054352f7f91STakashi Iwai 			}
10550c8c0f56STakashi Iwai 			print_nid_path("multiio", path);
1056352f7f91STakashi Iwai 			spec->multi_io[spec->multi_ios].pin = nid;
1057352f7f91STakashi Iwai 			spec->multi_io[spec->multi_ios].dac = dac;
1058196c1766STakashi Iwai 			spec->out_paths[cfg->line_outs + spec->multi_ios] =
1059196c1766STakashi Iwai 				snd_hda_get_path_idx(codec, path);
1060352f7f91STakashi Iwai 			spec->multi_ios++;
1061352f7f91STakashi Iwai 			if (spec->multi_ios >= 2)
1062352f7f91STakashi Iwai 				break;
1063352f7f91STakashi Iwai 		}
1064352f7f91STakashi Iwai 	}
1065352f7f91STakashi Iwai  end_fill:
1066352f7f91STakashi Iwai 	if (badness)
1067352f7f91STakashi Iwai 		badness = BAD_MULTI_IO;
1068352f7f91STakashi Iwai 	if (old_pins == spec->multi_ios) {
1069352f7f91STakashi Iwai 		if (hardwired)
1070352f7f91STakashi Iwai 			return 1; /* nothing found */
1071352f7f91STakashi Iwai 		else
1072352f7f91STakashi Iwai 			return badness; /* no badness if nothing found */
1073352f7f91STakashi Iwai 	}
1074352f7f91STakashi Iwai 	if (!hardwired && spec->multi_ios < 2) {
1075352f7f91STakashi Iwai 		/* cancel newly assigned paths */
1076352f7f91STakashi Iwai 		spec->paths.used -= spec->multi_ios - old_pins;
1077352f7f91STakashi Iwai 		spec->multi_ios = old_pins;
1078352f7f91STakashi Iwai 		return badness;
1079352f7f91STakashi Iwai 	}
1080352f7f91STakashi Iwai 
1081352f7f91STakashi Iwai 	/* assign volume and mute controls */
1082352f7f91STakashi Iwai 	for (i = old_pins; i < spec->multi_ios; i++)
1083352f7f91STakashi Iwai 		badness += assign_out_path_ctls(codec, spec->multi_io[i].pin,
1084352f7f91STakashi Iwai 						spec->multi_io[i].dac);
1085352f7f91STakashi Iwai 
1086352f7f91STakashi Iwai 	return badness;
1087352f7f91STakashi Iwai }
1088352f7f91STakashi Iwai 
1089352f7f91STakashi Iwai /* map DACs for all pins in the list if they are single connections */
1090352f7f91STakashi Iwai static bool map_singles(struct hda_codec *codec, int outs,
1091196c1766STakashi Iwai 			const hda_nid_t *pins, hda_nid_t *dacs, int *path_idx)
1092352f7f91STakashi Iwai {
1093b3a8c745STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1094352f7f91STakashi Iwai 	int i;
1095352f7f91STakashi Iwai 	bool found = false;
1096352f7f91STakashi Iwai 	for (i = 0; i < outs; i++) {
10970c8c0f56STakashi Iwai 		struct nid_path *path;
1098352f7f91STakashi Iwai 		hda_nid_t dac;
1099352f7f91STakashi Iwai 		if (dacs[i])
1100352f7f91STakashi Iwai 			continue;
1101352f7f91STakashi Iwai 		dac = get_dac_if_single(codec, pins[i]);
1102352f7f91STakashi Iwai 		if (!dac)
1103352f7f91STakashi Iwai 			continue;
11044ac0eefaSTakashi Iwai 		path = snd_hda_add_new_path(codec, dac, pins[i], HDA_PARSE_NO_AAMIX);
1105117688a9STakashi Iwai 		if (!path && !i && spec->mixer_nid)
1106b3a8c745STakashi Iwai 			path = snd_hda_add_new_path(codec, dac, pins[i], HDA_PARSE_ALL);
11070c8c0f56STakashi Iwai 		if (path) {
1108352f7f91STakashi Iwai 			dacs[i] = dac;
1109352f7f91STakashi Iwai 			found = true;
11100c8c0f56STakashi Iwai 			print_nid_path("output", path);
1111e1284af7STakashi Iwai 			path->active = true;
1112196c1766STakashi Iwai 			path_idx[i] = snd_hda_get_path_idx(codec, path);
1113352f7f91STakashi Iwai 		}
1114352f7f91STakashi Iwai 	}
1115352f7f91STakashi Iwai 	return found;
1116352f7f91STakashi Iwai }
1117352f7f91STakashi Iwai 
1118352f7f91STakashi Iwai /* fill in the dac_nids table from the parsed pin configuration */
1119352f7f91STakashi Iwai static int fill_and_eval_dacs(struct hda_codec *codec,
1120352f7f91STakashi Iwai 			      bool fill_hardwired,
1121352f7f91STakashi Iwai 			      bool fill_mio_first)
1122352f7f91STakashi Iwai {
1123352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1124352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
1125352f7f91STakashi Iwai 	int i, err, badness;
1126352f7f91STakashi Iwai 
1127352f7f91STakashi Iwai 	/* set num_dacs once to full for look_for_dac() */
1128352f7f91STakashi Iwai 	spec->multiout.num_dacs = cfg->line_outs;
1129352f7f91STakashi Iwai 	spec->multiout.dac_nids = spec->private_dac_nids;
1130352f7f91STakashi Iwai 	memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
1131352f7f91STakashi Iwai 	memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid));
1132352f7f91STakashi Iwai 	memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid));
1133352f7f91STakashi Iwai 	spec->multi_ios = 0;
1134352f7f91STakashi Iwai 	snd_array_free(&spec->paths);
1135352f7f91STakashi Iwai 	badness = 0;
1136352f7f91STakashi Iwai 
1137352f7f91STakashi Iwai 	/* fill hard-wired DACs first */
1138352f7f91STakashi Iwai 	if (fill_hardwired) {
1139352f7f91STakashi Iwai 		bool mapped;
1140352f7f91STakashi Iwai 		do {
1141352f7f91STakashi Iwai 			mapped = map_singles(codec, cfg->line_outs,
1142352f7f91STakashi Iwai 					     cfg->line_out_pins,
1143196c1766STakashi Iwai 					     spec->private_dac_nids,
1144196c1766STakashi Iwai 					     spec->out_paths);
1145352f7f91STakashi Iwai 			mapped |= map_singles(codec, cfg->hp_outs,
1146352f7f91STakashi Iwai 					      cfg->hp_pins,
1147196c1766STakashi Iwai 					      spec->multiout.hp_out_nid,
1148196c1766STakashi Iwai 					      spec->hp_paths);
1149352f7f91STakashi Iwai 			mapped |= map_singles(codec, cfg->speaker_outs,
1150352f7f91STakashi Iwai 					      cfg->speaker_pins,
1151196c1766STakashi Iwai 					      spec->multiout.extra_out_nid,
1152196c1766STakashi Iwai 					      spec->speaker_paths);
1153352f7f91STakashi Iwai 			if (fill_mio_first && cfg->line_outs == 1 &&
1154352f7f91STakashi Iwai 			    cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1155e22aab7dSTakashi Iwai 				err = fill_multi_ios(codec, cfg->line_out_pins[0], true);
1156352f7f91STakashi Iwai 				if (!err)
1157352f7f91STakashi Iwai 					mapped = true;
1158352f7f91STakashi Iwai 			}
1159352f7f91STakashi Iwai 		} while (mapped);
1160352f7f91STakashi Iwai 	}
1161352f7f91STakashi Iwai 
1162352f7f91STakashi Iwai 	badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins,
1163196c1766STakashi Iwai 				   spec->private_dac_nids, spec->out_paths,
1164352f7f91STakashi Iwai 				   &main_out_badness);
1165352f7f91STakashi Iwai 
1166352f7f91STakashi Iwai 	/* re-count num_dacs and squash invalid entries */
1167352f7f91STakashi Iwai 	spec->multiout.num_dacs = 0;
1168352f7f91STakashi Iwai 	for (i = 0; i < cfg->line_outs; i++) {
1169352f7f91STakashi Iwai 		if (spec->private_dac_nids[i])
1170352f7f91STakashi Iwai 			spec->multiout.num_dacs++;
1171352f7f91STakashi Iwai 		else {
1172352f7f91STakashi Iwai 			memmove(spec->private_dac_nids + i,
1173352f7f91STakashi Iwai 				spec->private_dac_nids + i + 1,
1174352f7f91STakashi Iwai 				sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
1175352f7f91STakashi Iwai 			spec->private_dac_nids[cfg->line_outs - 1] = 0;
1176352f7f91STakashi Iwai 		}
1177352f7f91STakashi Iwai 	}
1178352f7f91STakashi Iwai 
1179352f7f91STakashi Iwai 	if (fill_mio_first &&
1180352f7f91STakashi Iwai 	    cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1181352f7f91STakashi Iwai 		/* try to fill multi-io first */
1182e22aab7dSTakashi Iwai 		err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
1183352f7f91STakashi Iwai 		if (err < 0)
1184352f7f91STakashi Iwai 			return err;
1185352f7f91STakashi Iwai 		/* we don't count badness at this stage yet */
1186352f7f91STakashi Iwai 	}
1187352f7f91STakashi Iwai 
1188352f7f91STakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
1189352f7f91STakashi Iwai 		err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins,
1190352f7f91STakashi Iwai 				      spec->multiout.hp_out_nid,
1191196c1766STakashi Iwai 				      spec->hp_paths,
1192352f7f91STakashi Iwai 				      &extra_out_badness);
1193352f7f91STakashi Iwai 		if (err < 0)
1194352f7f91STakashi Iwai 			return err;
1195352f7f91STakashi Iwai 		badness += err;
1196352f7f91STakashi Iwai 	}
1197352f7f91STakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1198352f7f91STakashi Iwai 		err = try_assign_dacs(codec, cfg->speaker_outs,
1199352f7f91STakashi Iwai 				      cfg->speaker_pins,
1200352f7f91STakashi Iwai 				      spec->multiout.extra_out_nid,
1201196c1766STakashi Iwai 				      spec->speaker_paths,
1202352f7f91STakashi Iwai 				      &extra_out_badness);
1203352f7f91STakashi Iwai 		if (err < 0)
1204352f7f91STakashi Iwai 			return err;
1205352f7f91STakashi Iwai 		badness += err;
1206352f7f91STakashi Iwai 	}
1207352f7f91STakashi Iwai 	if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1208e22aab7dSTakashi Iwai 		err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
1209352f7f91STakashi Iwai 		if (err < 0)
1210352f7f91STakashi Iwai 			return err;
1211352f7f91STakashi Iwai 		badness += err;
1212352f7f91STakashi Iwai 	}
1213e22aab7dSTakashi Iwai 
1214e22aab7dSTakashi Iwai 	if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
1215e22aab7dSTakashi Iwai 		if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2)
1216e22aab7dSTakashi Iwai 			spec->multi_ios = 1; /* give badness */
1217352f7f91STakashi Iwai 
1218352f7f91STakashi Iwai 	if (spec->multi_ios == 2) {
1219352f7f91STakashi Iwai 		for (i = 0; i < 2; i++)
1220352f7f91STakashi Iwai 			spec->private_dac_nids[spec->multiout.num_dacs++] =
1221352f7f91STakashi Iwai 				spec->multi_io[i].dac;
1222352f7f91STakashi Iwai 		spec->ext_channel_count = 2;
1223352f7f91STakashi Iwai 	} else if (spec->multi_ios) {
1224352f7f91STakashi Iwai 		spec->multi_ios = 0;
1225352f7f91STakashi Iwai 		badness += BAD_MULTI_IO;
1226352f7f91STakashi Iwai 	}
1227352f7f91STakashi Iwai 
1228352f7f91STakashi Iwai 	return badness;
1229352f7f91STakashi Iwai }
1230352f7f91STakashi Iwai 
1231352f7f91STakashi Iwai #define DEBUG_BADNESS
1232352f7f91STakashi Iwai 
1233352f7f91STakashi Iwai #ifdef DEBUG_BADNESS
1234352f7f91STakashi Iwai #define debug_badness	snd_printdd
1235352f7f91STakashi Iwai #else
1236352f7f91STakashi Iwai #define debug_badness(...)
1237352f7f91STakashi Iwai #endif
1238352f7f91STakashi Iwai 
1239352f7f91STakashi Iwai static void debug_show_configs(struct hda_gen_spec *spec, struct auto_pin_cfg *cfg)
1240352f7f91STakashi Iwai {
1241352f7f91STakashi Iwai 	debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
1242352f7f91STakashi Iwai 		      cfg->line_out_pins[0], cfg->line_out_pins[1],
1243708122e8STakashi Iwai 		      cfg->line_out_pins[2], cfg->line_out_pins[3],
1244352f7f91STakashi Iwai 		      spec->multiout.dac_nids[0],
1245352f7f91STakashi Iwai 		      spec->multiout.dac_nids[1],
1246352f7f91STakashi Iwai 		      spec->multiout.dac_nids[2],
1247352f7f91STakashi Iwai 		      spec->multiout.dac_nids[3]);
1248352f7f91STakashi Iwai 	if (spec->multi_ios > 0)
1249352f7f91STakashi Iwai 		debug_badness("multi_ios(%d) = %x/%x : %x/%x\n",
1250352f7f91STakashi Iwai 			      spec->multi_ios,
1251352f7f91STakashi Iwai 			      spec->multi_io[0].pin, spec->multi_io[1].pin,
1252352f7f91STakashi Iwai 			      spec->multi_io[0].dac, spec->multi_io[1].dac);
1253352f7f91STakashi Iwai 	debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
1254352f7f91STakashi Iwai 		      cfg->hp_pins[0], cfg->hp_pins[1],
1255708122e8STakashi Iwai 		      cfg->hp_pins[2], cfg->hp_pins[3],
1256352f7f91STakashi Iwai 		      spec->multiout.hp_out_nid[0],
1257352f7f91STakashi Iwai 		      spec->multiout.hp_out_nid[1],
1258352f7f91STakashi Iwai 		      spec->multiout.hp_out_nid[2],
1259352f7f91STakashi Iwai 		      spec->multiout.hp_out_nid[3]);
1260352f7f91STakashi Iwai 	debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
1261352f7f91STakashi Iwai 		      cfg->speaker_pins[0], cfg->speaker_pins[1],
1262352f7f91STakashi Iwai 		      cfg->speaker_pins[2], cfg->speaker_pins[3],
1263352f7f91STakashi Iwai 		      spec->multiout.extra_out_nid[0],
1264352f7f91STakashi Iwai 		      spec->multiout.extra_out_nid[1],
1265352f7f91STakashi Iwai 		      spec->multiout.extra_out_nid[2],
1266352f7f91STakashi Iwai 		      spec->multiout.extra_out_nid[3]);
1267352f7f91STakashi Iwai }
1268352f7f91STakashi Iwai 
1269352f7f91STakashi Iwai /* find all available DACs of the codec */
1270352f7f91STakashi Iwai static void fill_all_dac_nids(struct hda_codec *codec)
1271352f7f91STakashi Iwai {
1272352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1273352f7f91STakashi Iwai 	int i;
1274352f7f91STakashi Iwai 	hda_nid_t nid = codec->start_nid;
1275352f7f91STakashi Iwai 
1276352f7f91STakashi Iwai 	spec->num_all_dacs = 0;
1277352f7f91STakashi Iwai 	memset(spec->all_dacs, 0, sizeof(spec->all_dacs));
1278352f7f91STakashi Iwai 	for (i = 0; i < codec->num_nodes; i++, nid++) {
1279352f7f91STakashi Iwai 		if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT)
1280352f7f91STakashi Iwai 			continue;
1281352f7f91STakashi Iwai 		if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) {
1282352f7f91STakashi Iwai 			snd_printk(KERN_ERR "hda: Too many DACs!\n");
1283352f7f91STakashi Iwai 			break;
1284352f7f91STakashi Iwai 		}
1285352f7f91STakashi Iwai 		spec->all_dacs[spec->num_all_dacs++] = nid;
1286352f7f91STakashi Iwai 	}
1287352f7f91STakashi Iwai }
1288352f7f91STakashi Iwai 
1289352f7f91STakashi Iwai static int parse_output_paths(struct hda_codec *codec)
1290352f7f91STakashi Iwai {
1291352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1292352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
1293352f7f91STakashi Iwai 	struct auto_pin_cfg *best_cfg;
1294352f7f91STakashi Iwai 	int best_badness = INT_MAX;
1295352f7f91STakashi Iwai 	int badness;
1296352f7f91STakashi Iwai 	bool fill_hardwired = true, fill_mio_first = true;
1297352f7f91STakashi Iwai 	bool best_wired = true, best_mio = true;
1298352f7f91STakashi Iwai 	bool hp_spk_swapped = false;
1299352f7f91STakashi Iwai 
1300352f7f91STakashi Iwai 	fill_all_dac_nids(codec);
1301352f7f91STakashi Iwai 
1302352f7f91STakashi Iwai 	best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL);
1303352f7f91STakashi Iwai 	if (!best_cfg)
1304352f7f91STakashi Iwai 		return -ENOMEM;
1305352f7f91STakashi Iwai 	*best_cfg = *cfg;
1306352f7f91STakashi Iwai 
1307352f7f91STakashi Iwai 	for (;;) {
1308352f7f91STakashi Iwai 		badness = fill_and_eval_dacs(codec, fill_hardwired,
1309352f7f91STakashi Iwai 					     fill_mio_first);
1310352f7f91STakashi Iwai 		if (badness < 0) {
1311352f7f91STakashi Iwai 			kfree(best_cfg);
1312352f7f91STakashi Iwai 			return badness;
1313352f7f91STakashi Iwai 		}
1314352f7f91STakashi Iwai 		debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n",
1315352f7f91STakashi Iwai 			      cfg->line_out_type, fill_hardwired, fill_mio_first,
1316352f7f91STakashi Iwai 			      badness);
1317352f7f91STakashi Iwai 		debug_show_configs(spec, cfg);
1318352f7f91STakashi Iwai 		if (badness < best_badness) {
1319352f7f91STakashi Iwai 			best_badness = badness;
1320352f7f91STakashi Iwai 			*best_cfg = *cfg;
1321352f7f91STakashi Iwai 			best_wired = fill_hardwired;
1322352f7f91STakashi Iwai 			best_mio = fill_mio_first;
1323352f7f91STakashi Iwai 		}
1324352f7f91STakashi Iwai 		if (!badness)
1325352f7f91STakashi Iwai 			break;
1326352f7f91STakashi Iwai 		fill_mio_first = !fill_mio_first;
1327352f7f91STakashi Iwai 		if (!fill_mio_first)
1328352f7f91STakashi Iwai 			continue;
1329352f7f91STakashi Iwai 		fill_hardwired = !fill_hardwired;
1330352f7f91STakashi Iwai 		if (!fill_hardwired)
1331352f7f91STakashi Iwai 			continue;
1332352f7f91STakashi Iwai 		if (hp_spk_swapped)
1333352f7f91STakashi Iwai 			break;
1334352f7f91STakashi Iwai 		hp_spk_swapped = true;
1335352f7f91STakashi Iwai 		if (cfg->speaker_outs > 0 &&
1336352f7f91STakashi Iwai 		    cfg->line_out_type == AUTO_PIN_HP_OUT) {
1337352f7f91STakashi Iwai 			cfg->hp_outs = cfg->line_outs;
1338352f7f91STakashi Iwai 			memcpy(cfg->hp_pins, cfg->line_out_pins,
1339352f7f91STakashi Iwai 			       sizeof(cfg->hp_pins));
1340352f7f91STakashi Iwai 			cfg->line_outs = cfg->speaker_outs;
1341352f7f91STakashi Iwai 			memcpy(cfg->line_out_pins, cfg->speaker_pins,
1342352f7f91STakashi Iwai 			       sizeof(cfg->speaker_pins));
1343352f7f91STakashi Iwai 			cfg->speaker_outs = 0;
1344352f7f91STakashi Iwai 			memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
1345352f7f91STakashi Iwai 			cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
1346352f7f91STakashi Iwai 			fill_hardwired = true;
1347352f7f91STakashi Iwai 			continue;
1348352f7f91STakashi Iwai 		}
1349352f7f91STakashi Iwai 		if (cfg->hp_outs > 0 &&
1350352f7f91STakashi Iwai 		    cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
1351352f7f91STakashi Iwai 			cfg->speaker_outs = cfg->line_outs;
1352352f7f91STakashi Iwai 			memcpy(cfg->speaker_pins, cfg->line_out_pins,
1353352f7f91STakashi Iwai 			       sizeof(cfg->speaker_pins));
1354352f7f91STakashi Iwai 			cfg->line_outs = cfg->hp_outs;
1355352f7f91STakashi Iwai 			memcpy(cfg->line_out_pins, cfg->hp_pins,
1356352f7f91STakashi Iwai 			       sizeof(cfg->hp_pins));
1357352f7f91STakashi Iwai 			cfg->hp_outs = 0;
1358352f7f91STakashi Iwai 			memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
1359352f7f91STakashi Iwai 			cfg->line_out_type = AUTO_PIN_HP_OUT;
1360352f7f91STakashi Iwai 			fill_hardwired = true;
1361352f7f91STakashi Iwai 			continue;
1362352f7f91STakashi Iwai 		}
1363352f7f91STakashi Iwai 		break;
1364352f7f91STakashi Iwai 	}
1365352f7f91STakashi Iwai 
1366352f7f91STakashi Iwai 	if (badness) {
13670c8c0f56STakashi Iwai 		debug_badness("==> restoring best_cfg\n");
1368352f7f91STakashi Iwai 		*cfg = *best_cfg;
1369352f7f91STakashi Iwai 		fill_and_eval_dacs(codec, best_wired, best_mio);
1370352f7f91STakashi Iwai 	}
1371352f7f91STakashi Iwai 	debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n",
1372352f7f91STakashi Iwai 		      cfg->line_out_type, best_wired, best_mio);
1373352f7f91STakashi Iwai 	debug_show_configs(spec, cfg);
1374352f7f91STakashi Iwai 
1375352f7f91STakashi Iwai 	if (cfg->line_out_pins[0]) {
1376352f7f91STakashi Iwai 		struct nid_path *path;
1377196c1766STakashi Iwai 		path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]);
1378352f7f91STakashi Iwai 		if (path)
1379352f7f91STakashi Iwai 			spec->vmaster_nid = look_for_out_vol_nid(codec, path);
1380352f7f91STakashi Iwai 	}
1381352f7f91STakashi Iwai 
1382352f7f91STakashi Iwai 	kfree(best_cfg);
1383352f7f91STakashi Iwai 	return 0;
1384352f7f91STakashi Iwai }
1385352f7f91STakashi Iwai 
1386352f7f91STakashi Iwai /* add playback controls from the parsed DAC table */
1387352f7f91STakashi Iwai static int create_multi_out_ctls(struct hda_codec *codec,
1388352f7f91STakashi Iwai 				 const struct auto_pin_cfg *cfg)
1389352f7f91STakashi Iwai {
1390352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1391352f7f91STakashi Iwai 	int i, err, noutputs;
1392352f7f91STakashi Iwai 
1393352f7f91STakashi Iwai 	noutputs = cfg->line_outs;
1394352f7f91STakashi Iwai 	if (spec->multi_ios > 0 && cfg->line_outs < 3)
1395352f7f91STakashi Iwai 		noutputs += spec->multi_ios;
1396352f7f91STakashi Iwai 
1397352f7f91STakashi Iwai 	for (i = 0; i < noutputs; i++) {
1398352f7f91STakashi Iwai 		const char *name;
1399352f7f91STakashi Iwai 		int index;
1400196c1766STakashi Iwai 		hda_nid_t dac;
1401352f7f91STakashi Iwai 		struct nid_path *path;
1402352f7f91STakashi Iwai 
1403352f7f91STakashi Iwai 		dac = spec->multiout.dac_nids[i];
1404352f7f91STakashi Iwai 		if (!dac)
1405352f7f91STakashi Iwai 			continue;
1406352f7f91STakashi Iwai 		if (i >= cfg->line_outs) {
1407352f7f91STakashi Iwai 			index = 0;
1408352f7f91STakashi Iwai 			name = channel_name[i];
1409352f7f91STakashi Iwai 		} else {
1410352f7f91STakashi Iwai 			name = get_line_out_pfx(spec, i, true, &index);
1411352f7f91STakashi Iwai 		}
1412352f7f91STakashi Iwai 
1413196c1766STakashi Iwai 		path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]);
1414352f7f91STakashi Iwai 		if (!path)
1415352f7f91STakashi Iwai 			continue;
1416352f7f91STakashi Iwai 		if (!name || !strcmp(name, "CLFE")) {
1417352f7f91STakashi Iwai 			/* Center/LFE */
1418352f7f91STakashi Iwai 			err = add_vol_ctl(codec, "Center", 0, 1, path);
1419352f7f91STakashi Iwai 			if (err < 0)
1420352f7f91STakashi Iwai 				return err;
1421352f7f91STakashi Iwai 			err = add_vol_ctl(codec, "LFE", 0, 2, path);
1422352f7f91STakashi Iwai 			if (err < 0)
1423352f7f91STakashi Iwai 				return err;
1424352f7f91STakashi Iwai 			err = add_sw_ctl(codec, "Center", 0, 1, path);
1425352f7f91STakashi Iwai 			if (err < 0)
1426352f7f91STakashi Iwai 				return err;
1427352f7f91STakashi Iwai 			err = add_sw_ctl(codec, "LFE", 0, 2, path);
1428352f7f91STakashi Iwai 			if (err < 0)
1429352f7f91STakashi Iwai 				return err;
1430352f7f91STakashi Iwai 		} else {
1431352f7f91STakashi Iwai 			err = add_stereo_vol(codec, name, index, path);
1432352f7f91STakashi Iwai 			if (err < 0)
1433352f7f91STakashi Iwai 				return err;
1434352f7f91STakashi Iwai 			err = add_stereo_sw(codec, name, index, path);
1435352f7f91STakashi Iwai 			if (err < 0)
1436352f7f91STakashi Iwai 				return err;
1437352f7f91STakashi Iwai 		}
1438352f7f91STakashi Iwai 	}
1439352f7f91STakashi Iwai 	return 0;
1440352f7f91STakashi Iwai }
1441352f7f91STakashi Iwai 
1442352f7f91STakashi Iwai static int create_extra_out(struct hda_codec *codec, hda_nid_t pin,
1443196c1766STakashi Iwai 			    hda_nid_t dac, int path_idx,
1444196c1766STakashi Iwai 			    const char *pfx, int cidx)
1445352f7f91STakashi Iwai {
1446352f7f91STakashi Iwai 	struct nid_path *path;
1447352f7f91STakashi Iwai 	int err;
1448352f7f91STakashi Iwai 
1449196c1766STakashi Iwai 	path = snd_hda_get_path_from_idx(codec, path_idx);
1450352f7f91STakashi Iwai 	if (!path)
1451352f7f91STakashi Iwai 		return 0;
1452352f7f91STakashi Iwai 	/* bind volume control will be created in the case of dac = 0 */
1453352f7f91STakashi Iwai 	if (dac) {
1454352f7f91STakashi Iwai 		err = add_stereo_vol(codec, pfx, cidx, path);
1455352f7f91STakashi Iwai 		if (err < 0)
1456352f7f91STakashi Iwai 			return err;
1457352f7f91STakashi Iwai 	}
1458352f7f91STakashi Iwai 	err = add_stereo_sw(codec, pfx, cidx, path);
1459352f7f91STakashi Iwai 	if (err < 0)
1460352f7f91STakashi Iwai 		return err;
1461352f7f91STakashi Iwai 	return 0;
1462352f7f91STakashi Iwai }
1463352f7f91STakashi Iwai 
1464352f7f91STakashi Iwai /* add playback controls for speaker and HP outputs */
1465352f7f91STakashi Iwai static int create_extra_outs(struct hda_codec *codec, int num_pins,
1466352f7f91STakashi Iwai 			     const hda_nid_t *pins, const hda_nid_t *dacs,
1467196c1766STakashi Iwai 			     const int *paths, const char *pfx)
1468352f7f91STakashi Iwai {
1469352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1470352f7f91STakashi Iwai 	struct hda_bind_ctls *ctl;
1471352f7f91STakashi Iwai 	char name[32];
1472352f7f91STakashi Iwai 	int i, n, err;
1473352f7f91STakashi Iwai 
1474352f7f91STakashi Iwai 	if (!num_pins || !pins[0])
1475352f7f91STakashi Iwai 		return 0;
1476352f7f91STakashi Iwai 
1477352f7f91STakashi Iwai 	if (num_pins == 1) {
1478352f7f91STakashi Iwai 		hda_nid_t dac = *dacs;
1479352f7f91STakashi Iwai 		if (!dac)
1480352f7f91STakashi Iwai 			dac = spec->multiout.dac_nids[0];
1481196c1766STakashi Iwai 		return create_extra_out(codec, *pins, dac, paths[0], pfx, 0);
1482352f7f91STakashi Iwai 	}
1483352f7f91STakashi Iwai 
1484352f7f91STakashi Iwai 	for (i = 0; i < num_pins; i++) {
1485352f7f91STakashi Iwai 		hda_nid_t dac;
1486352f7f91STakashi Iwai 		if (dacs[num_pins - 1])
1487352f7f91STakashi Iwai 			dac = dacs[i]; /* with individual volumes */
1488352f7f91STakashi Iwai 		else
1489352f7f91STakashi Iwai 			dac = 0;
1490352f7f91STakashi Iwai 		if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) {
1491196c1766STakashi Iwai 			err = create_extra_out(codec, pins[i], dac, paths[i],
1492352f7f91STakashi Iwai 					       "Bass Speaker", 0);
1493352f7f91STakashi Iwai 		} else if (num_pins >= 3) {
1494352f7f91STakashi Iwai 			snprintf(name, sizeof(name), "%s %s",
1495352f7f91STakashi Iwai 				 pfx, channel_name[i]);
1496196c1766STakashi Iwai 			err = create_extra_out(codec, pins[i], dac, paths[i],
1497196c1766STakashi Iwai 					       name, 0);
1498352f7f91STakashi Iwai 		} else {
1499196c1766STakashi Iwai 			err = create_extra_out(codec, pins[i], dac, paths[i],
1500196c1766STakashi Iwai 					       pfx, i);
1501352f7f91STakashi Iwai 		}
1502352f7f91STakashi Iwai 		if (err < 0)
1503352f7f91STakashi Iwai 			return err;
1504352f7f91STakashi Iwai 	}
1505352f7f91STakashi Iwai 	if (dacs[num_pins - 1])
1506352f7f91STakashi Iwai 		return 0;
1507352f7f91STakashi Iwai 
1508352f7f91STakashi Iwai 	/* Let's create a bind-controls for volumes */
1509352f7f91STakashi Iwai 	ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_vol);
1510352f7f91STakashi Iwai 	if (!ctl)
1511352f7f91STakashi Iwai 		return -ENOMEM;
1512352f7f91STakashi Iwai 	n = 0;
1513352f7f91STakashi Iwai 	for (i = 0; i < num_pins; i++) {
1514352f7f91STakashi Iwai 		hda_nid_t vol;
1515352f7f91STakashi Iwai 		struct nid_path *path;
1516352f7f91STakashi Iwai 		if (!pins[i] || !dacs[i])
1517352f7f91STakashi Iwai 			continue;
1518196c1766STakashi Iwai 		path = snd_hda_get_path_from_idx(codec, paths[i]);
1519352f7f91STakashi Iwai 		if (!path)
1520352f7f91STakashi Iwai 			continue;
1521352f7f91STakashi Iwai 		vol = look_for_out_vol_nid(codec, path);
1522352f7f91STakashi Iwai 		if (vol)
1523352f7f91STakashi Iwai 			ctl->values[n++] =
1524352f7f91STakashi Iwai 				HDA_COMPOSE_AMP_VAL(vol, 3, 0, HDA_OUTPUT);
1525352f7f91STakashi Iwai 	}
1526352f7f91STakashi Iwai 	if (n) {
1527352f7f91STakashi Iwai 		snprintf(name, sizeof(name), "%s Playback Volume", pfx);
1528352f7f91STakashi Iwai 		err = add_control(spec, HDA_CTL_BIND_VOL, name, 0, (long)ctl);
1529352f7f91STakashi Iwai 		if (err < 0)
1530352f7f91STakashi Iwai 			return err;
1531352f7f91STakashi Iwai 	}
1532352f7f91STakashi Iwai 	return 0;
1533352f7f91STakashi Iwai }
1534352f7f91STakashi Iwai 
1535352f7f91STakashi Iwai static int create_hp_out_ctls(struct hda_codec *codec)
1536352f7f91STakashi Iwai {
1537352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1538352f7f91STakashi Iwai 	return create_extra_outs(codec, spec->autocfg.hp_outs,
1539352f7f91STakashi Iwai 				 spec->autocfg.hp_pins,
1540352f7f91STakashi Iwai 				 spec->multiout.hp_out_nid,
1541196c1766STakashi Iwai 				 spec->hp_paths,
1542352f7f91STakashi Iwai 				 "Headphone");
1543352f7f91STakashi Iwai }
1544352f7f91STakashi Iwai 
1545352f7f91STakashi Iwai static int create_speaker_out_ctls(struct hda_codec *codec)
1546352f7f91STakashi Iwai {
1547352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1548352f7f91STakashi Iwai 	return create_extra_outs(codec, spec->autocfg.speaker_outs,
1549352f7f91STakashi Iwai 				 spec->autocfg.speaker_pins,
1550352f7f91STakashi Iwai 				 spec->multiout.extra_out_nid,
1551196c1766STakashi Iwai 				 spec->speaker_paths,
1552352f7f91STakashi Iwai 				 "Speaker");
1553352f7f91STakashi Iwai }
1554352f7f91STakashi Iwai 
1555352f7f91STakashi Iwai /*
155638cf6f1aSTakashi Iwai  * independent HP controls
155738cf6f1aSTakashi Iwai  */
155838cf6f1aSTakashi Iwai 
155938cf6f1aSTakashi Iwai static int indep_hp_info(struct snd_kcontrol *kcontrol,
156038cf6f1aSTakashi Iwai 			 struct snd_ctl_elem_info *uinfo)
156138cf6f1aSTakashi Iwai {
156238cf6f1aSTakashi Iwai 	return snd_hda_enum_bool_helper_info(kcontrol, uinfo);
156338cf6f1aSTakashi Iwai }
156438cf6f1aSTakashi Iwai 
156538cf6f1aSTakashi Iwai static int indep_hp_get(struct snd_kcontrol *kcontrol,
156638cf6f1aSTakashi Iwai 			struct snd_ctl_elem_value *ucontrol)
156738cf6f1aSTakashi Iwai {
156838cf6f1aSTakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
156938cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
157038cf6f1aSTakashi Iwai 	ucontrol->value.enumerated.item[0] = spec->indep_hp_enabled;
157138cf6f1aSTakashi Iwai 	return 0;
157238cf6f1aSTakashi Iwai }
157338cf6f1aSTakashi Iwai 
157438cf6f1aSTakashi Iwai static int indep_hp_put(struct snd_kcontrol *kcontrol,
157538cf6f1aSTakashi Iwai 			struct snd_ctl_elem_value *ucontrol)
157638cf6f1aSTakashi Iwai {
157738cf6f1aSTakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
157838cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
157938cf6f1aSTakashi Iwai 	unsigned int select = ucontrol->value.enumerated.item[0];
158038cf6f1aSTakashi Iwai 	int ret = 0;
158138cf6f1aSTakashi Iwai 
158238cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
158338cf6f1aSTakashi Iwai 	if (spec->active_streams) {
158438cf6f1aSTakashi Iwai 		ret = -EBUSY;
158538cf6f1aSTakashi Iwai 		goto unlock;
158638cf6f1aSTakashi Iwai 	}
158738cf6f1aSTakashi Iwai 
158838cf6f1aSTakashi Iwai 	if (spec->indep_hp_enabled != select) {
158938cf6f1aSTakashi Iwai 		spec->indep_hp_enabled = select;
159038cf6f1aSTakashi Iwai 		if (spec->indep_hp_enabled)
159138cf6f1aSTakashi Iwai 			spec->multiout.hp_out_nid[0] = 0;
159238cf6f1aSTakashi Iwai 		else
159338cf6f1aSTakashi Iwai 			spec->multiout.hp_out_nid[0] = spec->alt_dac_nid;
159438cf6f1aSTakashi Iwai 		ret = 1;
159538cf6f1aSTakashi Iwai 	}
159638cf6f1aSTakashi Iwai  unlock:
159738cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
159838cf6f1aSTakashi Iwai 	return ret;
159938cf6f1aSTakashi Iwai }
160038cf6f1aSTakashi Iwai 
160138cf6f1aSTakashi Iwai static const struct snd_kcontrol_new indep_hp_ctl = {
160238cf6f1aSTakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
160338cf6f1aSTakashi Iwai 	.name = "Independent HP",
160438cf6f1aSTakashi Iwai 	.info = indep_hp_info,
160538cf6f1aSTakashi Iwai 	.get = indep_hp_get,
160638cf6f1aSTakashi Iwai 	.put = indep_hp_put,
160738cf6f1aSTakashi Iwai };
160838cf6f1aSTakashi Iwai 
160938cf6f1aSTakashi Iwai 
161038cf6f1aSTakashi Iwai static int create_indep_hp_ctls(struct hda_codec *codec)
161138cf6f1aSTakashi Iwai {
161238cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
161338cf6f1aSTakashi Iwai 
161438cf6f1aSTakashi Iwai 	if (!spec->indep_hp)
161538cf6f1aSTakashi Iwai 		return 0;
161638cf6f1aSTakashi Iwai 	if (!spec->multiout.hp_out_nid[0]) {
161738cf6f1aSTakashi Iwai 		spec->indep_hp = 0;
161838cf6f1aSTakashi Iwai 		return 0;
161938cf6f1aSTakashi Iwai 	}
162038cf6f1aSTakashi Iwai 
162138cf6f1aSTakashi Iwai 	spec->indep_hp_enabled = false;
162238cf6f1aSTakashi Iwai 	spec->alt_dac_nid = spec->multiout.hp_out_nid[0];
162338cf6f1aSTakashi Iwai 	if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl))
162438cf6f1aSTakashi Iwai 		return -ENOMEM;
162538cf6f1aSTakashi Iwai 	return 0;
162638cf6f1aSTakashi Iwai }
162738cf6f1aSTakashi Iwai 
162838cf6f1aSTakashi Iwai /*
1629352f7f91STakashi Iwai  * channel mode enum control
1630352f7f91STakashi Iwai  */
1631352f7f91STakashi Iwai 
1632352f7f91STakashi Iwai static int ch_mode_info(struct snd_kcontrol *kcontrol,
1633352f7f91STakashi Iwai 			struct snd_ctl_elem_info *uinfo)
1634352f7f91STakashi Iwai {
1635352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1636352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1637352f7f91STakashi Iwai 
1638352f7f91STakashi Iwai 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1639352f7f91STakashi Iwai 	uinfo->count = 1;
1640352f7f91STakashi Iwai 	uinfo->value.enumerated.items = spec->multi_ios + 1;
1641352f7f91STakashi Iwai 	if (uinfo->value.enumerated.item > spec->multi_ios)
1642352f7f91STakashi Iwai 		uinfo->value.enumerated.item = spec->multi_ios;
1643352f7f91STakashi Iwai 	sprintf(uinfo->value.enumerated.name, "%dch",
1644352f7f91STakashi Iwai 		(uinfo->value.enumerated.item + 1) * 2);
1645352f7f91STakashi Iwai 	return 0;
1646352f7f91STakashi Iwai }
1647352f7f91STakashi Iwai 
1648352f7f91STakashi Iwai static int ch_mode_get(struct snd_kcontrol *kcontrol,
1649352f7f91STakashi Iwai 		       struct snd_ctl_elem_value *ucontrol)
1650352f7f91STakashi Iwai {
1651352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1652352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1653352f7f91STakashi Iwai 	ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2;
1654352f7f91STakashi Iwai 	return 0;
1655352f7f91STakashi Iwai }
1656352f7f91STakashi Iwai 
1657196c1766STakashi Iwai static inline struct nid_path *
1658196c1766STakashi Iwai get_multiio_path(struct hda_codec *codec, int idx)
1659196c1766STakashi Iwai {
1660196c1766STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1661196c1766STakashi Iwai 	return snd_hda_get_path_from_idx(codec,
1662196c1766STakashi Iwai 		spec->out_paths[spec->autocfg.line_outs + idx]);
1663196c1766STakashi Iwai }
1664196c1766STakashi Iwai 
1665352f7f91STakashi Iwai static int set_multi_io(struct hda_codec *codec, int idx, bool output)
1666352f7f91STakashi Iwai {
1667352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1668352f7f91STakashi Iwai 	hda_nid_t nid = spec->multi_io[idx].pin;
1669352f7f91STakashi Iwai 	struct nid_path *path;
1670352f7f91STakashi Iwai 
1671196c1766STakashi Iwai 	path = get_multiio_path(codec, idx);
1672352f7f91STakashi Iwai 	if (!path)
1673352f7f91STakashi Iwai 		return -EINVAL;
1674352f7f91STakashi Iwai 
1675352f7f91STakashi Iwai 	if (path->active == output)
1676352f7f91STakashi Iwai 		return 0;
1677352f7f91STakashi Iwai 
1678352f7f91STakashi Iwai 	if (output) {
1679352f7f91STakashi Iwai 		snd_hda_set_pin_ctl_cache(codec, nid, PIN_OUT);
1680352f7f91STakashi Iwai 		snd_hda_activate_path(codec, path, true, true);
1681d5a9f1bbSTakashi Iwai 		set_pin_eapd(codec, nid, true);
1682352f7f91STakashi Iwai 	} else {
1683d5a9f1bbSTakashi Iwai 		set_pin_eapd(codec, nid, false);
1684352f7f91STakashi Iwai 		snd_hda_activate_path(codec, path, false, true);
1685352f7f91STakashi Iwai 		snd_hda_set_pin_ctl_cache(codec, nid,
1686352f7f91STakashi Iwai 					  spec->multi_io[idx].ctl_in);
1687352f7f91STakashi Iwai 	}
1688352f7f91STakashi Iwai 	return 0;
1689352f7f91STakashi Iwai }
1690352f7f91STakashi Iwai 
1691352f7f91STakashi Iwai static int ch_mode_put(struct snd_kcontrol *kcontrol,
1692352f7f91STakashi Iwai 		       struct snd_ctl_elem_value *ucontrol)
1693352f7f91STakashi Iwai {
1694352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1695352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1696352f7f91STakashi Iwai 	int i, ch;
1697352f7f91STakashi Iwai 
1698352f7f91STakashi Iwai 	ch = ucontrol->value.enumerated.item[0];
1699352f7f91STakashi Iwai 	if (ch < 0 || ch > spec->multi_ios)
1700352f7f91STakashi Iwai 		return -EINVAL;
1701352f7f91STakashi Iwai 	if (ch == (spec->ext_channel_count - 1) / 2)
1702352f7f91STakashi Iwai 		return 0;
1703352f7f91STakashi Iwai 	spec->ext_channel_count = (ch + 1) * 2;
1704352f7f91STakashi Iwai 	for (i = 0; i < spec->multi_ios; i++)
1705352f7f91STakashi Iwai 		set_multi_io(codec, i, i < ch);
1706352f7f91STakashi Iwai 	spec->multiout.max_channels = max(spec->ext_channel_count,
1707352f7f91STakashi Iwai 					  spec->const_channel_count);
1708352f7f91STakashi Iwai 	if (spec->need_dac_fix)
1709352f7f91STakashi Iwai 		spec->multiout.num_dacs = spec->multiout.max_channels / 2;
1710352f7f91STakashi Iwai 	return 1;
1711352f7f91STakashi Iwai }
1712352f7f91STakashi Iwai 
1713352f7f91STakashi Iwai static const struct snd_kcontrol_new channel_mode_enum = {
1714352f7f91STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1715352f7f91STakashi Iwai 	.name = "Channel Mode",
1716352f7f91STakashi Iwai 	.info = ch_mode_info,
1717352f7f91STakashi Iwai 	.get = ch_mode_get,
1718352f7f91STakashi Iwai 	.put = ch_mode_put,
1719352f7f91STakashi Iwai };
1720352f7f91STakashi Iwai 
1721352f7f91STakashi Iwai static int create_multi_channel_mode(struct hda_codec *codec)
1722352f7f91STakashi Iwai {
1723352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1724352f7f91STakashi Iwai 
1725352f7f91STakashi Iwai 	if (spec->multi_ios > 0) {
172612c93df6STakashi Iwai 		if (!snd_hda_gen_add_kctl(spec, NULL, &channel_mode_enum))
1727352f7f91STakashi Iwai 			return -ENOMEM;
1728352f7f91STakashi Iwai 	}
1729352f7f91STakashi Iwai 	return 0;
1730352f7f91STakashi Iwai }
1731352f7f91STakashi Iwai 
1732352f7f91STakashi Iwai /*
1733352f7f91STakashi Iwai  * shared headphone/mic handling
1734352f7f91STakashi Iwai  */
1735352f7f91STakashi Iwai 
1736352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec);
1737352f7f91STakashi Iwai 
1738352f7f91STakashi Iwai /* for shared I/O, change the pin-control accordingly */
1739352f7f91STakashi Iwai static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic)
1740352f7f91STakashi Iwai {
1741352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1742352f7f91STakashi Iwai 	unsigned int val;
1743352f7f91STakashi Iwai 	hda_nid_t pin = spec->autocfg.inputs[1].pin;
1744352f7f91STakashi Iwai 	/* NOTE: this assumes that there are only two inputs, the
1745352f7f91STakashi Iwai 	 * first is the real internal mic and the second is HP/mic jack.
1746352f7f91STakashi Iwai 	 */
1747352f7f91STakashi Iwai 
1748352f7f91STakashi Iwai 	val = snd_hda_get_default_vref(codec, pin);
1749352f7f91STakashi Iwai 
1750352f7f91STakashi Iwai 	/* This pin does not have vref caps - let's enable vref on pin 0x18
1751352f7f91STakashi Iwai 	   instead, as suggested by Realtek */
1752352f7f91STakashi Iwai 	if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) {
1753352f7f91STakashi Iwai 		const hda_nid_t vref_pin = spec->shared_mic_vref_pin;
1754352f7f91STakashi Iwai 		unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin);
1755352f7f91STakashi Iwai 		if (vref_val != AC_PINCTL_VREF_HIZ)
17567594aa33STakashi Iwai 			snd_hda_set_pin_ctl_cache(codec, vref_pin,
17577594aa33STakashi Iwai 					PIN_IN | (set_as_mic ? vref_val : 0));
1758352f7f91STakashi Iwai 	}
1759352f7f91STakashi Iwai 
1760352f7f91STakashi Iwai 	val = set_as_mic ? val | PIN_IN : PIN_HP;
17617594aa33STakashi Iwai 	snd_hda_set_pin_ctl_cache(codec, pin, val);
1762352f7f91STakashi Iwai 
1763352f7f91STakashi Iwai 	spec->automute_speaker = !set_as_mic;
1764352f7f91STakashi Iwai 	call_update_outputs(codec);
1765352f7f91STakashi Iwai }
1766352f7f91STakashi Iwai 
1767352f7f91STakashi Iwai /* create a shared input with the headphone out */
1768352f7f91STakashi Iwai static int create_shared_input(struct hda_codec *codec)
1769352f7f91STakashi Iwai {
1770352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1771352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
1772352f7f91STakashi Iwai 	unsigned int defcfg;
1773352f7f91STakashi Iwai 	hda_nid_t nid;
1774352f7f91STakashi Iwai 
1775352f7f91STakashi Iwai 	/* only one internal input pin? */
1776352f7f91STakashi Iwai 	if (cfg->num_inputs != 1)
1777352f7f91STakashi Iwai 		return 0;
1778352f7f91STakashi Iwai 	defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin);
1779352f7f91STakashi Iwai 	if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT)
1780352f7f91STakashi Iwai 		return 0;
1781352f7f91STakashi Iwai 
1782352f7f91STakashi Iwai 	if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
1783352f7f91STakashi Iwai 		nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */
1784352f7f91STakashi Iwai 	else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT)
1785352f7f91STakashi Iwai 		nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */
1786352f7f91STakashi Iwai 	else
1787352f7f91STakashi Iwai 		return 0; /* both not available */
1788352f7f91STakashi Iwai 
1789352f7f91STakashi Iwai 	if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN))
1790352f7f91STakashi Iwai 		return 0; /* no input */
1791352f7f91STakashi Iwai 
1792352f7f91STakashi Iwai 	cfg->inputs[1].pin = nid;
1793352f7f91STakashi Iwai 	cfg->inputs[1].type = AUTO_PIN_MIC;
1794352f7f91STakashi Iwai 	cfg->num_inputs = 2;
1795352f7f91STakashi Iwai 	spec->shared_mic_hp = 1;
1796352f7f91STakashi Iwai 	snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid);
1797352f7f91STakashi Iwai 	return 0;
1798352f7f91STakashi Iwai }
1799352f7f91STakashi Iwai 
1800352f7f91STakashi Iwai 
1801352f7f91STakashi Iwai /*
1802352f7f91STakashi Iwai  * Parse input paths
1803352f7f91STakashi Iwai  */
1804352f7f91STakashi Iwai 
1805352f7f91STakashi Iwai #ifdef CONFIG_PM
1806352f7f91STakashi Iwai /* add the powersave loopback-list entry */
1807352f7f91STakashi Iwai static void add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx)
1808352f7f91STakashi Iwai {
1809352f7f91STakashi Iwai 	struct hda_amp_list *list;
1810352f7f91STakashi Iwai 
1811352f7f91STakashi Iwai 	if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1)
1812352f7f91STakashi Iwai 		return;
1813352f7f91STakashi Iwai 	list = spec->loopback_list + spec->num_loopbacks;
1814352f7f91STakashi Iwai 	list->nid = mix;
1815352f7f91STakashi Iwai 	list->dir = HDA_INPUT;
1816352f7f91STakashi Iwai 	list->idx = idx;
1817352f7f91STakashi Iwai 	spec->num_loopbacks++;
1818cb53c626STakashi Iwai 	spec->loopback.amplist = spec->loopback_list;
1819cb53c626STakashi Iwai }
1820cb53c626STakashi Iwai #else
1821352f7f91STakashi Iwai #define add_loopback_list(spec, mix, idx) /* NOP */
1822cb53c626STakashi Iwai #endif
1823cb53c626STakashi Iwai 
1824352f7f91STakashi Iwai /* create input playback/capture controls for the given pin */
1825196c1766STakashi Iwai static int new_analog_input(struct hda_codec *codec, int input_idx,
1826196c1766STakashi Iwai 			    hda_nid_t pin, const char *ctlname, int ctlidx,
1827352f7f91STakashi Iwai 			    hda_nid_t mix_nid)
18281da177e4SLinus Torvalds {
1829352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1830352f7f91STakashi Iwai 	struct nid_path *path;
1831352f7f91STakashi Iwai 	unsigned int val;
1832352f7f91STakashi Iwai 	int err, idx;
18331da177e4SLinus Torvalds 
1834352f7f91STakashi Iwai 	if (!nid_has_volume(codec, mix_nid, HDA_INPUT) &&
1835352f7f91STakashi Iwai 	    !nid_has_mute(codec, mix_nid, HDA_INPUT))
1836352f7f91STakashi Iwai 		return 0; /* no need for analog loopback */
1837352f7f91STakashi Iwai 
18384ac0eefaSTakashi Iwai 	path = snd_hda_add_new_path(codec, pin, mix_nid, HDA_PARSE_ALL);
1839352f7f91STakashi Iwai 	if (!path)
1840352f7f91STakashi Iwai 		return -EINVAL;
18410c8c0f56STakashi Iwai 	print_nid_path("loopback", path);
1842196c1766STakashi Iwai 	spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path);
1843352f7f91STakashi Iwai 
1844352f7f91STakashi Iwai 	idx = path->idx[path->depth - 1];
1845352f7f91STakashi Iwai 	if (nid_has_volume(codec, mix_nid, HDA_INPUT)) {
1846352f7f91STakashi Iwai 		val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
1847352f7f91STakashi Iwai 		err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, val);
1848d13bd412STakashi Iwai 		if (err < 0)
18491da177e4SLinus Torvalds 			return err;
1850352f7f91STakashi Iwai 		path->ctls[NID_PATH_VOL_CTL] = val;
18511da177e4SLinus Torvalds 	}
18521da177e4SLinus Torvalds 
1853352f7f91STakashi Iwai 	if (nid_has_mute(codec, mix_nid, HDA_INPUT)) {
1854352f7f91STakashi Iwai 		val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
1855352f7f91STakashi Iwai 		err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, val);
1856d13bd412STakashi Iwai 		if (err < 0)
18571da177e4SLinus Torvalds 			return err;
1858352f7f91STakashi Iwai 		path->ctls[NID_PATH_MUTE_CTL] = val;
18591da177e4SLinus Torvalds 	}
18601da177e4SLinus Torvalds 
1861352f7f91STakashi Iwai 	path->active = true;
1862352f7f91STakashi Iwai 	add_loopback_list(spec, mix_nid, idx);
1863352f7f91STakashi Iwai 	return 0;
18641da177e4SLinus Torvalds }
18651da177e4SLinus Torvalds 
1866352f7f91STakashi Iwai static int is_input_pin(struct hda_codec *codec, hda_nid_t nid)
18671da177e4SLinus Torvalds {
1868352f7f91STakashi Iwai 	unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
1869352f7f91STakashi Iwai 	return (pincap & AC_PINCAP_IN) != 0;
1870352f7f91STakashi Iwai }
1871352f7f91STakashi Iwai 
1872352f7f91STakashi Iwai /* Parse the codec tree and retrieve ADCs */
1873352f7f91STakashi Iwai static int fill_adc_nids(struct hda_codec *codec)
1874352f7f91STakashi Iwai {
1875352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1876352f7f91STakashi Iwai 	hda_nid_t nid;
1877352f7f91STakashi Iwai 	hda_nid_t *adc_nids = spec->adc_nids;
1878352f7f91STakashi Iwai 	int max_nums = ARRAY_SIZE(spec->adc_nids);
1879352f7f91STakashi Iwai 	int i, nums = 0;
1880352f7f91STakashi Iwai 
1881352f7f91STakashi Iwai 	nid = codec->start_nid;
1882352f7f91STakashi Iwai 	for (i = 0; i < codec->num_nodes; i++, nid++) {
1883352f7f91STakashi Iwai 		unsigned int caps = get_wcaps(codec, nid);
1884352f7f91STakashi Iwai 		int type = get_wcaps_type(caps);
1885352f7f91STakashi Iwai 
1886352f7f91STakashi Iwai 		if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL))
1887352f7f91STakashi Iwai 			continue;
1888352f7f91STakashi Iwai 		adc_nids[nums] = nid;
1889352f7f91STakashi Iwai 		if (++nums >= max_nums)
1890352f7f91STakashi Iwai 			break;
1891352f7f91STakashi Iwai 	}
1892352f7f91STakashi Iwai 	spec->num_adc_nids = nums;
1893352f7f91STakashi Iwai 	return nums;
1894352f7f91STakashi Iwai }
1895352f7f91STakashi Iwai 
1896352f7f91STakashi Iwai /* filter out invalid adc_nids that don't give all active input pins;
1897352f7f91STakashi Iwai  * if needed, check whether dynamic ADC-switching is available
1898352f7f91STakashi Iwai  */
1899352f7f91STakashi Iwai static int check_dyn_adc_switch(struct hda_codec *codec)
1900352f7f91STakashi Iwai {
1901352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1902352f7f91STakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
1903352f7f91STakashi Iwai 	hda_nid_t adc_nids[ARRAY_SIZE(spec->adc_nids)];
1904352f7f91STakashi Iwai 	int i, n, nums;
1905352f7f91STakashi Iwai 	hda_nid_t pin, adc;
1906352f7f91STakashi Iwai 
1907352f7f91STakashi Iwai  again:
1908352f7f91STakashi Iwai 	nums = 0;
1909352f7f91STakashi Iwai 	for (n = 0; n < spec->num_adc_nids; n++) {
1910352f7f91STakashi Iwai 		adc = spec->adc_nids[n];
1911352f7f91STakashi Iwai 		for (i = 0; i < imux->num_items; i++) {
1912352f7f91STakashi Iwai 			pin = spec->imux_pins[i];
1913352f7f91STakashi Iwai 			if (!is_reachable_path(codec, pin, adc))
1914352f7f91STakashi Iwai 				break;
1915352f7f91STakashi Iwai 		}
1916352f7f91STakashi Iwai 		if (i >= imux->num_items)
1917352f7f91STakashi Iwai 			adc_nids[nums++] = adc;
1918352f7f91STakashi Iwai 	}
1919352f7f91STakashi Iwai 
1920352f7f91STakashi Iwai 	if (!nums) {
1921352f7f91STakashi Iwai 		if (spec->shared_mic_hp) {
1922352f7f91STakashi Iwai 			spec->shared_mic_hp = 0;
1923352f7f91STakashi Iwai 			imux->num_items = 1;
1924352f7f91STakashi Iwai 			goto again;
1925352f7f91STakashi Iwai 		}
1926352f7f91STakashi Iwai 
1927352f7f91STakashi Iwai 		/* check whether ADC-switch is possible */
1928352f7f91STakashi Iwai 		for (i = 0; i < imux->num_items; i++) {
1929352f7f91STakashi Iwai 			pin = spec->imux_pins[i];
1930352f7f91STakashi Iwai 			for (n = 0; n < spec->num_adc_nids; n++) {
1931352f7f91STakashi Iwai 				adc = spec->adc_nids[n];
1932352f7f91STakashi Iwai 				if (is_reachable_path(codec, pin, adc)) {
1933352f7f91STakashi Iwai 					spec->dyn_adc_idx[i] = n;
1934352f7f91STakashi Iwai 					break;
1935352f7f91STakashi Iwai 				}
1936352f7f91STakashi Iwai 			}
1937352f7f91STakashi Iwai 		}
1938352f7f91STakashi Iwai 
1939352f7f91STakashi Iwai 		snd_printdd("hda-codec: enabling ADC switching\n");
1940352f7f91STakashi Iwai 		spec->dyn_adc_switch = 1;
1941352f7f91STakashi Iwai 	} else if (nums != spec->num_adc_nids) {
1942352f7f91STakashi Iwai 		memcpy(spec->adc_nids, adc_nids, nums * sizeof(hda_nid_t));
1943352f7f91STakashi Iwai 		spec->num_adc_nids = nums;
1944352f7f91STakashi Iwai 	}
1945352f7f91STakashi Iwai 
1946352f7f91STakashi Iwai 	if (imux->num_items == 1 || spec->shared_mic_hp) {
1947352f7f91STakashi Iwai 		snd_printdd("hda-codec: reducing to a single ADC\n");
1948352f7f91STakashi Iwai 		spec->num_adc_nids = 1; /* reduce to a single ADC */
1949352f7f91STakashi Iwai 	}
1950352f7f91STakashi Iwai 
1951352f7f91STakashi Iwai 	/* single index for individual volumes ctls */
1952352f7f91STakashi Iwai 	if (!spec->dyn_adc_switch && spec->multi_cap_vol)
1953352f7f91STakashi Iwai 		spec->num_adc_nids = 1;
1954352f7f91STakashi Iwai 
19551da177e4SLinus Torvalds 	return 0;
19561da177e4SLinus Torvalds }
19571da177e4SLinus Torvalds 
19581da177e4SLinus Torvalds /*
1959352f7f91STakashi Iwai  * create playback/capture controls for input pins
19601da177e4SLinus Torvalds  */
1961352f7f91STakashi Iwai static int create_input_ctls(struct hda_codec *codec)
1962a7da6ce5STakashi Iwai {
1963352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1964352f7f91STakashi Iwai 	const struct auto_pin_cfg *cfg = &spec->autocfg;
1965352f7f91STakashi Iwai 	hda_nid_t mixer = spec->mixer_nid;
1966352f7f91STakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
1967352f7f91STakashi Iwai 	int num_adcs;
1968352f7f91STakashi Iwai 	int i, c, err, type_idx = 0;
1969352f7f91STakashi Iwai 	const char *prev_label = NULL;
1970a7da6ce5STakashi Iwai 
1971352f7f91STakashi Iwai 	num_adcs = fill_adc_nids(codec);
1972352f7f91STakashi Iwai 	if (num_adcs < 0)
1973352f7f91STakashi Iwai 		return 0;
1974352f7f91STakashi Iwai 
1975352f7f91STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
1976352f7f91STakashi Iwai 		hda_nid_t pin;
1977352f7f91STakashi Iwai 		const char *label;
1978352f7f91STakashi Iwai 		bool imux_added;
1979352f7f91STakashi Iwai 
1980352f7f91STakashi Iwai 		pin = cfg->inputs[i].pin;
1981352f7f91STakashi Iwai 		if (!is_input_pin(codec, pin))
1982352f7f91STakashi Iwai 			continue;
1983352f7f91STakashi Iwai 
1984352f7f91STakashi Iwai 		label = hda_get_autocfg_input_label(codec, cfg, i);
1985352f7f91STakashi Iwai 		if (spec->shared_mic_hp && !strcmp(label, "Misc"))
1986352f7f91STakashi Iwai 			label = "Headphone Mic";
1987352f7f91STakashi Iwai 		if (prev_label && !strcmp(label, prev_label))
1988352f7f91STakashi Iwai 			type_idx++;
1989352f7f91STakashi Iwai 		else
1990352f7f91STakashi Iwai 			type_idx = 0;
1991352f7f91STakashi Iwai 		prev_label = label;
1992352f7f91STakashi Iwai 
1993352f7f91STakashi Iwai 		if (mixer) {
1994352f7f91STakashi Iwai 			if (is_reachable_path(codec, pin, mixer)) {
1995196c1766STakashi Iwai 				err = new_analog_input(codec, i, pin,
1996352f7f91STakashi Iwai 						       label, type_idx, mixer);
1997a7da6ce5STakashi Iwai 				if (err < 0)
1998a7da6ce5STakashi Iwai 					return err;
1999a7da6ce5STakashi Iwai 			}
2000352f7f91STakashi Iwai 		}
2001352f7f91STakashi Iwai 
2002352f7f91STakashi Iwai 		imux_added = false;
2003352f7f91STakashi Iwai 		for (c = 0; c < num_adcs; c++) {
2004352f7f91STakashi Iwai 			struct nid_path *path;
2005352f7f91STakashi Iwai 			hda_nid_t adc = spec->adc_nids[c];
2006352f7f91STakashi Iwai 
2007352f7f91STakashi Iwai 			if (!is_reachable_path(codec, pin, adc))
2008352f7f91STakashi Iwai 				continue;
2009352f7f91STakashi Iwai 			path = snd_array_new(&spec->paths);
2010352f7f91STakashi Iwai 			if (!path)
2011352f7f91STakashi Iwai 				return -ENOMEM;
2012352f7f91STakashi Iwai 			memset(path, 0, sizeof(*path));
20134ac0eefaSTakashi Iwai 			if (!snd_hda_parse_nid_path(codec, pin, adc, HDA_PARSE_ALL, path)) {
2014352f7f91STakashi Iwai 				snd_printd(KERN_ERR
2015352f7f91STakashi Iwai 					   "invalid input path 0x%x -> 0x%x\n",
2016352f7f91STakashi Iwai 					   pin, adc);
2017352f7f91STakashi Iwai 				spec->paths.used--;
2018352f7f91STakashi Iwai 				continue;
2019352f7f91STakashi Iwai 			}
20200c8c0f56STakashi Iwai 			print_nid_path("input", path);
2021352f7f91STakashi Iwai 
2022352f7f91STakashi Iwai 			if (!imux_added) {
2023352f7f91STakashi Iwai 				spec->imux_pins[imux->num_items] = pin;
2024352f7f91STakashi Iwai 				snd_hda_add_imux_item(imux, label,
2025352f7f91STakashi Iwai 						      imux->num_items, NULL);
2026352f7f91STakashi Iwai 				imux_added = true;
2027352f7f91STakashi Iwai 			}
2028352f7f91STakashi Iwai 		}
2029352f7f91STakashi Iwai 	}
2030352f7f91STakashi Iwai 
2031a7da6ce5STakashi Iwai 	return 0;
2032a7da6ce5STakashi Iwai }
2033a7da6ce5STakashi Iwai 
20341da177e4SLinus Torvalds 
2035352f7f91STakashi Iwai /*
2036352f7f91STakashi Iwai  * input source mux
2037352f7f91STakashi Iwai  */
2038352f7f91STakashi Iwai 
2039352f7f91STakashi Iwai /* get the ADC NID corresponding to the given index */
2040352f7f91STakashi Iwai static hda_nid_t get_adc_nid(struct hda_codec *codec, int adc_idx, int imux_idx)
2041352f7f91STakashi Iwai {
2042352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2043352f7f91STakashi Iwai 	if (spec->dyn_adc_switch)
2044352f7f91STakashi Iwai 		adc_idx = spec->dyn_adc_idx[imux_idx];
2045352f7f91STakashi Iwai 	return spec->adc_nids[adc_idx];
204697ec558aSTakashi Iwai }
2047352f7f91STakashi Iwai 
2048352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
2049352f7f91STakashi Iwai 		      unsigned int idx);
2050352f7f91STakashi Iwai 
2051352f7f91STakashi Iwai static int mux_enum_info(struct snd_kcontrol *kcontrol,
2052352f7f91STakashi Iwai 			 struct snd_ctl_elem_info *uinfo)
2053352f7f91STakashi Iwai {
2054352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2055352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2056352f7f91STakashi Iwai 	return snd_hda_input_mux_info(&spec->input_mux, uinfo);
2057352f7f91STakashi Iwai }
2058352f7f91STakashi Iwai 
2059352f7f91STakashi Iwai static int mux_enum_get(struct snd_kcontrol *kcontrol,
2060352f7f91STakashi Iwai 			struct snd_ctl_elem_value *ucontrol)
2061352f7f91STakashi Iwai {
2062352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2063352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2064352f7f91STakashi Iwai 	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2065352f7f91STakashi Iwai 
2066352f7f91STakashi Iwai 	ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
20671da177e4SLinus Torvalds 	return 0;
20681da177e4SLinus Torvalds }
20691da177e4SLinus Torvalds 
2070352f7f91STakashi Iwai static int mux_enum_put(struct snd_kcontrol *kcontrol,
2071352f7f91STakashi Iwai 			    struct snd_ctl_elem_value *ucontrol)
20721da177e4SLinus Torvalds {
2073352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2074352f7f91STakashi Iwai 	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2075352f7f91STakashi Iwai 	return mux_select(codec, adc_idx,
2076352f7f91STakashi Iwai 			  ucontrol->value.enumerated.item[0]);
2077352f7f91STakashi Iwai }
2078352f7f91STakashi Iwai 
2079352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_src_temp = {
20801da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2081352f7f91STakashi Iwai 	.name = "Input Source",
2082352f7f91STakashi Iwai 	.info = mux_enum_info,
2083352f7f91STakashi Iwai 	.get = mux_enum_get,
2084352f7f91STakashi Iwai 	.put = mux_enum_put,
20851da177e4SLinus Torvalds };
2086071c73adSTakashi Iwai 
208747d46abbSTakashi Iwai /*
208847d46abbSTakashi Iwai  * capture volume and capture switch ctls
208947d46abbSTakashi Iwai  */
209047d46abbSTakashi Iwai 
2091352f7f91STakashi Iwai typedef int (*put_call_t)(struct snd_kcontrol *kcontrol,
2092352f7f91STakashi Iwai 			  struct snd_ctl_elem_value *ucontrol);
2093071c73adSTakashi Iwai 
209447d46abbSTakashi Iwai /* call the given amp update function for all amps in the imux list at once */
2095352f7f91STakashi Iwai static int cap_put_caller(struct snd_kcontrol *kcontrol,
2096352f7f91STakashi Iwai 			  struct snd_ctl_elem_value *ucontrol,
2097352f7f91STakashi Iwai 			  put_call_t func, int type)
2098352f7f91STakashi Iwai {
2099352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2100352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2101352f7f91STakashi Iwai 	const struct hda_input_mux *imux;
2102352f7f91STakashi Iwai 	struct nid_path *path;
2103352f7f91STakashi Iwai 	int i, adc_idx, err = 0;
2104071c73adSTakashi Iwai 
2105352f7f91STakashi Iwai 	imux = &spec->input_mux;
2106352f7f91STakashi Iwai 	adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2107352f7f91STakashi Iwai 	mutex_lock(&codec->control_mutex);
210847d46abbSTakashi Iwai 	/* we use the cache-only update at first since multiple input paths
210947d46abbSTakashi Iwai 	 * may shared the same amp; by updating only caches, the redundant
211047d46abbSTakashi Iwai 	 * writes to hardware can be reduced.
211147d46abbSTakashi Iwai 	 */
2112352f7f91STakashi Iwai 	codec->cached_write = 1;
2113352f7f91STakashi Iwai 	for (i = 0; i < imux->num_items; i++) {
2114352f7f91STakashi Iwai 		path = snd_hda_get_nid_path(codec, spec->imux_pins[i],
2115352f7f91STakashi Iwai 					    get_adc_nid(codec, adc_idx, i));
2116352f7f91STakashi Iwai 		if (!path->ctls[type])
2117352f7f91STakashi Iwai 			continue;
2118352f7f91STakashi Iwai 		kcontrol->private_value = path->ctls[type];
2119352f7f91STakashi Iwai 		err = func(kcontrol, ucontrol);
2120352f7f91STakashi Iwai 		if (err < 0)
2121352f7f91STakashi Iwai 			goto error;
2122352f7f91STakashi Iwai 	}
2123352f7f91STakashi Iwai  error:
2124352f7f91STakashi Iwai 	codec->cached_write = 0;
2125352f7f91STakashi Iwai 	mutex_unlock(&codec->control_mutex);
212647d46abbSTakashi Iwai 	snd_hda_codec_flush_amp_cache(codec); /* flush the updates */
2127352f7f91STakashi Iwai 	if (err >= 0 && spec->cap_sync_hook)
2128352f7f91STakashi Iwai 		spec->cap_sync_hook(codec);
2129352f7f91STakashi Iwai 	return err;
2130352f7f91STakashi Iwai }
2131352f7f91STakashi Iwai 
2132352f7f91STakashi Iwai /* capture volume ctl callbacks */
2133352f7f91STakashi Iwai #define cap_vol_info		snd_hda_mixer_amp_volume_info
2134352f7f91STakashi Iwai #define cap_vol_get		snd_hda_mixer_amp_volume_get
2135352f7f91STakashi Iwai #define cap_vol_tlv		snd_hda_mixer_amp_tlv
2136352f7f91STakashi Iwai 
2137352f7f91STakashi Iwai static int cap_vol_put(struct snd_kcontrol *kcontrol,
2138352f7f91STakashi Iwai 		       struct snd_ctl_elem_value *ucontrol)
2139352f7f91STakashi Iwai {
2140352f7f91STakashi Iwai 	return cap_put_caller(kcontrol, ucontrol,
2141352f7f91STakashi Iwai 			      snd_hda_mixer_amp_volume_put,
2142352f7f91STakashi Iwai 			      NID_PATH_VOL_CTL);
2143352f7f91STakashi Iwai }
2144352f7f91STakashi Iwai 
2145352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_vol_temp = {
2146352f7f91STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2147352f7f91STakashi Iwai 	.name = "Capture Volume",
2148352f7f91STakashi Iwai 	.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
2149352f7f91STakashi Iwai 		   SNDRV_CTL_ELEM_ACCESS_TLV_READ |
2150352f7f91STakashi Iwai 		   SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK),
2151352f7f91STakashi Iwai 	.info = cap_vol_info,
2152352f7f91STakashi Iwai 	.get = cap_vol_get,
2153352f7f91STakashi Iwai 	.put = cap_vol_put,
2154352f7f91STakashi Iwai 	.tlv = { .c = cap_vol_tlv },
2155352f7f91STakashi Iwai };
2156352f7f91STakashi Iwai 
2157352f7f91STakashi Iwai /* capture switch ctl callbacks */
2158352f7f91STakashi Iwai #define cap_sw_info		snd_ctl_boolean_stereo_info
2159352f7f91STakashi Iwai #define cap_sw_get		snd_hda_mixer_amp_switch_get
2160352f7f91STakashi Iwai 
2161352f7f91STakashi Iwai static int cap_sw_put(struct snd_kcontrol *kcontrol,
2162352f7f91STakashi Iwai 		      struct snd_ctl_elem_value *ucontrol)
2163352f7f91STakashi Iwai {
2164352f7f91STakashi Iwai 	return cap_put_caller(kcontrol, ucontrol,
2165352f7f91STakashi Iwai 			      snd_hda_mixer_amp_switch_put,
2166352f7f91STakashi Iwai 			      NID_PATH_MUTE_CTL);
2167352f7f91STakashi Iwai }
2168352f7f91STakashi Iwai 
2169352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_sw_temp = {
2170352f7f91STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2171352f7f91STakashi Iwai 	.name = "Capture Switch",
2172352f7f91STakashi Iwai 	.info = cap_sw_info,
2173352f7f91STakashi Iwai 	.get = cap_sw_get,
2174352f7f91STakashi Iwai 	.put = cap_sw_put,
2175352f7f91STakashi Iwai };
2176352f7f91STakashi Iwai 
2177352f7f91STakashi Iwai static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path)
2178352f7f91STakashi Iwai {
2179352f7f91STakashi Iwai 	hda_nid_t nid;
2180352f7f91STakashi Iwai 	int i, depth;
2181352f7f91STakashi Iwai 
2182352f7f91STakashi Iwai 	path->ctls[NID_PATH_VOL_CTL] = path->ctls[NID_PATH_MUTE_CTL] = 0;
2183352f7f91STakashi Iwai 	for (depth = 0; depth < 3; depth++) {
2184352f7f91STakashi Iwai 		if (depth >= path->depth)
2185352f7f91STakashi Iwai 			return -EINVAL;
2186352f7f91STakashi Iwai 		i = path->depth - depth - 1;
2187352f7f91STakashi Iwai 		nid = path->path[i];
2188352f7f91STakashi Iwai 		if (!path->ctls[NID_PATH_VOL_CTL]) {
2189352f7f91STakashi Iwai 			if (nid_has_volume(codec, nid, HDA_OUTPUT))
2190352f7f91STakashi Iwai 				path->ctls[NID_PATH_VOL_CTL] =
2191352f7f91STakashi Iwai 					HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
2192352f7f91STakashi Iwai 			else if (nid_has_volume(codec, nid, HDA_INPUT)) {
2193352f7f91STakashi Iwai 				int idx = path->idx[i];
2194352f7f91STakashi Iwai 				if (!depth && codec->single_adc_amp)
2195352f7f91STakashi Iwai 					idx = 0;
2196352f7f91STakashi Iwai 				path->ctls[NID_PATH_VOL_CTL] =
2197352f7f91STakashi Iwai 					HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT);
2198352f7f91STakashi Iwai 			}
2199352f7f91STakashi Iwai 		}
2200352f7f91STakashi Iwai 		if (!path->ctls[NID_PATH_MUTE_CTL]) {
2201352f7f91STakashi Iwai 			if (nid_has_mute(codec, nid, HDA_OUTPUT))
2202352f7f91STakashi Iwai 				path->ctls[NID_PATH_MUTE_CTL] =
2203352f7f91STakashi Iwai 					HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
2204352f7f91STakashi Iwai 			else if (nid_has_mute(codec, nid, HDA_INPUT)) {
2205352f7f91STakashi Iwai 				int idx = path->idx[i];
2206352f7f91STakashi Iwai 				if (!depth && codec->single_adc_amp)
2207352f7f91STakashi Iwai 					idx = 0;
2208352f7f91STakashi Iwai 				path->ctls[NID_PATH_MUTE_CTL] =
2209352f7f91STakashi Iwai 					HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT);
2210352f7f91STakashi Iwai 			}
2211352f7f91STakashi Iwai 		}
2212352f7f91STakashi Iwai 	}
2213352f7f91STakashi Iwai 	return 0;
2214352f7f91STakashi Iwai }
2215352f7f91STakashi Iwai 
2216352f7f91STakashi Iwai static bool is_inv_dmic_pin(struct hda_codec *codec, hda_nid_t nid)
2217352f7f91STakashi Iwai {
2218352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2219352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
2220352f7f91STakashi Iwai 	unsigned int val;
2221352f7f91STakashi Iwai 	int i;
2222352f7f91STakashi Iwai 
2223352f7f91STakashi Iwai 	if (!spec->inv_dmic_split)
2224352f7f91STakashi Iwai 		return false;
2225352f7f91STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
2226352f7f91STakashi Iwai 		if (cfg->inputs[i].pin != nid)
2227352f7f91STakashi Iwai 			continue;
2228352f7f91STakashi Iwai 		if (cfg->inputs[i].type != AUTO_PIN_MIC)
2229352f7f91STakashi Iwai 			return false;
2230352f7f91STakashi Iwai 		val = snd_hda_codec_get_pincfg(codec, nid);
2231352f7f91STakashi Iwai 		return snd_hda_get_input_pin_attr(val) == INPUT_PIN_ATTR_INT;
2232352f7f91STakashi Iwai 	}
2233352f7f91STakashi Iwai 	return false;
2234352f7f91STakashi Iwai }
2235352f7f91STakashi Iwai 
2236352f7f91STakashi Iwai static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
2237352f7f91STakashi Iwai 			      int idx, bool is_switch, unsigned int ctl,
2238352f7f91STakashi Iwai 			      bool inv_dmic)
2239352f7f91STakashi Iwai {
2240352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2241352f7f91STakashi Iwai 	char tmpname[44];
2242352f7f91STakashi Iwai 	int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL;
2243352f7f91STakashi Iwai 	const char *sfx = is_switch ? "Switch" : "Volume";
2244352f7f91STakashi Iwai 	unsigned int chs = inv_dmic ? 1 : 3;
2245352f7f91STakashi Iwai 	int err;
2246352f7f91STakashi Iwai 
2247352f7f91STakashi Iwai 	if (!ctl)
2248352f7f91STakashi Iwai 		return 0;
2249352f7f91STakashi Iwai 
2250352f7f91STakashi Iwai 	if (label)
2251352f7f91STakashi Iwai 		snprintf(tmpname, sizeof(tmpname),
2252352f7f91STakashi Iwai 			 "%s Capture %s", label, sfx);
2253352f7f91STakashi Iwai 	else
2254352f7f91STakashi Iwai 		snprintf(tmpname, sizeof(tmpname),
2255352f7f91STakashi Iwai 			 "Capture %s", sfx);
2256352f7f91STakashi Iwai 	err = add_control(spec, type, tmpname, idx,
2257352f7f91STakashi Iwai 			  amp_val_replace_channels(ctl, chs));
2258352f7f91STakashi Iwai 	if (err < 0 || !inv_dmic)
2259352f7f91STakashi Iwai 		return err;
2260352f7f91STakashi Iwai 
2261352f7f91STakashi Iwai 	/* Make independent right kcontrol */
2262352f7f91STakashi Iwai 	if (label)
2263352f7f91STakashi Iwai 		snprintf(tmpname, sizeof(tmpname),
2264352f7f91STakashi Iwai 			 "Inverted %s Capture %s", label, sfx);
2265352f7f91STakashi Iwai 	else
2266352f7f91STakashi Iwai 		snprintf(tmpname, sizeof(tmpname),
2267352f7f91STakashi Iwai 			 "Inverted Capture %s", sfx);
2268352f7f91STakashi Iwai 	return add_control(spec, type, tmpname, idx,
2269352f7f91STakashi Iwai 			   amp_val_replace_channels(ctl, 2));
2270352f7f91STakashi Iwai }
2271352f7f91STakashi Iwai 
2272352f7f91STakashi Iwai /* create single (and simple) capture volume and switch controls */
2273352f7f91STakashi Iwai static int create_single_cap_vol_ctl(struct hda_codec *codec, int idx,
2274352f7f91STakashi Iwai 				     unsigned int vol_ctl, unsigned int sw_ctl,
2275352f7f91STakashi Iwai 				     bool inv_dmic)
2276352f7f91STakashi Iwai {
2277352f7f91STakashi Iwai 	int err;
2278352f7f91STakashi Iwai 	err = add_single_cap_ctl(codec, NULL, idx, false, vol_ctl, inv_dmic);
2279352f7f91STakashi Iwai 	if (err < 0)
2280352f7f91STakashi Iwai 		return err;
2281352f7f91STakashi Iwai 	err = add_single_cap_ctl(codec, NULL, idx, true, sw_ctl, inv_dmic);
2282071c73adSTakashi Iwai 	if (err < 0)
2283071c73adSTakashi Iwai 		return err;
2284071c73adSTakashi Iwai 	return 0;
22851da177e4SLinus Torvalds }
2286071c73adSTakashi Iwai 
2287352f7f91STakashi Iwai /* create bound capture volume and switch controls */
2288352f7f91STakashi Iwai static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx,
2289352f7f91STakashi Iwai 				   unsigned int vol_ctl, unsigned int sw_ctl)
2290352f7f91STakashi Iwai {
2291352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2292352f7f91STakashi Iwai 	struct snd_kcontrol_new *knew;
2293352f7f91STakashi Iwai 
2294352f7f91STakashi Iwai 	if (vol_ctl) {
229512c93df6STakashi Iwai 		knew = snd_hda_gen_add_kctl(spec, NULL, &cap_vol_temp);
2296352f7f91STakashi Iwai 		if (!knew)
2297352f7f91STakashi Iwai 			return -ENOMEM;
2298352f7f91STakashi Iwai 		knew->index = idx;
2299352f7f91STakashi Iwai 		knew->private_value = vol_ctl;
2300352f7f91STakashi Iwai 		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
2301352f7f91STakashi Iwai 	}
2302352f7f91STakashi Iwai 	if (sw_ctl) {
230312c93df6STakashi Iwai 		knew = snd_hda_gen_add_kctl(spec, NULL, &cap_sw_temp);
2304352f7f91STakashi Iwai 		if (!knew)
2305352f7f91STakashi Iwai 			return -ENOMEM;
2306352f7f91STakashi Iwai 		knew->index = idx;
2307352f7f91STakashi Iwai 		knew->private_value = sw_ctl;
2308352f7f91STakashi Iwai 		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
2309352f7f91STakashi Iwai 	}
2310352f7f91STakashi Iwai 	return 0;
2311352f7f91STakashi Iwai }
2312352f7f91STakashi Iwai 
2313352f7f91STakashi Iwai /* return the vol ctl when used first in the imux list */
2314352f7f91STakashi Iwai static unsigned int get_first_cap_ctl(struct hda_codec *codec, int idx, int type)
2315352f7f91STakashi Iwai {
2316352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2317352f7f91STakashi Iwai 	struct nid_path *path;
2318352f7f91STakashi Iwai 	unsigned int ctl;
2319352f7f91STakashi Iwai 	int i;
2320352f7f91STakashi Iwai 
2321352f7f91STakashi Iwai 	path = snd_hda_get_nid_path(codec, spec->imux_pins[idx],
2322352f7f91STakashi Iwai 				    get_adc_nid(codec, 0, idx));
2323352f7f91STakashi Iwai 	if (!path)
2324352f7f91STakashi Iwai 		return 0;
2325352f7f91STakashi Iwai 	ctl = path->ctls[type];
2326352f7f91STakashi Iwai 	if (!ctl)
2327352f7f91STakashi Iwai 		return 0;
2328352f7f91STakashi Iwai 	for (i = 0; i < idx - 1; i++) {
2329352f7f91STakashi Iwai 		path = snd_hda_get_nid_path(codec, spec->imux_pins[i],
2330352f7f91STakashi Iwai 					    get_adc_nid(codec, 0, i));
2331352f7f91STakashi Iwai 		if (path && path->ctls[type] == ctl)
2332352f7f91STakashi Iwai 			return 0;
2333352f7f91STakashi Iwai 	}
2334352f7f91STakashi Iwai 	return ctl;
2335352f7f91STakashi Iwai }
2336352f7f91STakashi Iwai 
2337352f7f91STakashi Iwai /* create individual capture volume and switch controls per input */
2338352f7f91STakashi Iwai static int create_multi_cap_vol_ctl(struct hda_codec *codec)
2339352f7f91STakashi Iwai {
2340352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2341352f7f91STakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
2342352f7f91STakashi Iwai 	int i, err, type, type_idx = 0;
2343352f7f91STakashi Iwai 	const char *prev_label = NULL;
2344352f7f91STakashi Iwai 
2345352f7f91STakashi Iwai 	for (i = 0; i < imux->num_items; i++) {
2346352f7f91STakashi Iwai 		const char *label;
2347352f7f91STakashi Iwai 		bool inv_dmic;
2348352f7f91STakashi Iwai 		label = hda_get_autocfg_input_label(codec, &spec->autocfg, i);
2349352f7f91STakashi Iwai 		if (prev_label && !strcmp(label, prev_label))
2350352f7f91STakashi Iwai 			type_idx++;
2351352f7f91STakashi Iwai 		else
2352352f7f91STakashi Iwai 			type_idx = 0;
2353352f7f91STakashi Iwai 		prev_label = label;
2354352f7f91STakashi Iwai 		inv_dmic = is_inv_dmic_pin(codec, spec->imux_pins[i]);
2355352f7f91STakashi Iwai 
2356352f7f91STakashi Iwai 		for (type = 0; type < 2; type++) {
2357352f7f91STakashi Iwai 			err = add_single_cap_ctl(codec, label, type_idx, type,
2358352f7f91STakashi Iwai 						 get_first_cap_ctl(codec, i, type),
2359352f7f91STakashi Iwai 						 inv_dmic);
2360d13bd412STakashi Iwai 			if (err < 0)
2361071c73adSTakashi Iwai 				return err;
2362352f7f91STakashi Iwai 		}
2363352f7f91STakashi Iwai 	}
2364071c73adSTakashi Iwai 	return 0;
2365352f7f91STakashi Iwai }
2366071c73adSTakashi Iwai 
2367352f7f91STakashi Iwai static int create_capture_mixers(struct hda_codec *codec)
2368352f7f91STakashi Iwai {
2369352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2370352f7f91STakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
2371352f7f91STakashi Iwai 	int i, n, nums, err;
2372352f7f91STakashi Iwai 
2373352f7f91STakashi Iwai 	if (spec->dyn_adc_switch)
2374352f7f91STakashi Iwai 		nums = 1;
2375352f7f91STakashi Iwai 	else
2376352f7f91STakashi Iwai 		nums = spec->num_adc_nids;
2377352f7f91STakashi Iwai 
2378352f7f91STakashi Iwai 	if (!spec->auto_mic && imux->num_items > 1) {
2379352f7f91STakashi Iwai 		struct snd_kcontrol_new *knew;
2380624d914dSTakashi Iwai 		const char *name;
2381624d914dSTakashi Iwai 		name = nums > 1 ? "Input Source" : "Capture Source";
2382624d914dSTakashi Iwai 		knew = snd_hda_gen_add_kctl(spec, name, &cap_src_temp);
2383352f7f91STakashi Iwai 		if (!knew)
2384352f7f91STakashi Iwai 			return -ENOMEM;
2385352f7f91STakashi Iwai 		knew->count = nums;
2386352f7f91STakashi Iwai 	}
2387352f7f91STakashi Iwai 
2388352f7f91STakashi Iwai 	for (n = 0; n < nums; n++) {
2389352f7f91STakashi Iwai 		bool multi = false;
2390352f7f91STakashi Iwai 		bool inv_dmic = false;
2391352f7f91STakashi Iwai 		int vol, sw;
2392352f7f91STakashi Iwai 
2393352f7f91STakashi Iwai 		vol = sw = 0;
2394352f7f91STakashi Iwai 		for (i = 0; i < imux->num_items; i++) {
2395352f7f91STakashi Iwai 			struct nid_path *path;
2396352f7f91STakashi Iwai 			path = snd_hda_get_nid_path(codec, spec->imux_pins[i],
2397352f7f91STakashi Iwai 						    get_adc_nid(codec, n, i));
2398352f7f91STakashi Iwai 			if (!path)
2399352f7f91STakashi Iwai 				continue;
2400352f7f91STakashi Iwai 			parse_capvol_in_path(codec, path);
2401352f7f91STakashi Iwai 			if (!vol)
2402352f7f91STakashi Iwai 				vol = path->ctls[NID_PATH_VOL_CTL];
2403352f7f91STakashi Iwai 			else if (vol != path->ctls[NID_PATH_VOL_CTL])
2404352f7f91STakashi Iwai 				multi = true;
2405352f7f91STakashi Iwai 			if (!sw)
2406352f7f91STakashi Iwai 				sw = path->ctls[NID_PATH_MUTE_CTL];
2407352f7f91STakashi Iwai 			else if (sw != path->ctls[NID_PATH_MUTE_CTL])
2408352f7f91STakashi Iwai 				multi = true;
2409352f7f91STakashi Iwai 			if (is_inv_dmic_pin(codec, spec->imux_pins[i]))
2410352f7f91STakashi Iwai 				inv_dmic = true;
2411352f7f91STakashi Iwai 		}
2412352f7f91STakashi Iwai 
2413352f7f91STakashi Iwai 		if (!multi)
2414352f7f91STakashi Iwai 			err = create_single_cap_vol_ctl(codec, n, vol, sw,
2415352f7f91STakashi Iwai 							inv_dmic);
2416352f7f91STakashi Iwai 		else if (!spec->multi_cap_vol)
2417352f7f91STakashi Iwai 			err = create_bind_cap_vol_ctl(codec, n, vol, sw);
2418352f7f91STakashi Iwai 		else
2419352f7f91STakashi Iwai 			err = create_multi_cap_vol_ctl(codec);
2420d13bd412STakashi Iwai 		if (err < 0)
2421071c73adSTakashi Iwai 			return err;
2422071c73adSTakashi Iwai 	}
2423071c73adSTakashi Iwai 
24241da177e4SLinus Torvalds 	return 0;
24251da177e4SLinus Torvalds }
24261da177e4SLinus Torvalds 
2427352f7f91STakashi Iwai /*
2428352f7f91STakashi Iwai  * add mic boosts if needed
2429352f7f91STakashi Iwai  */
2430352f7f91STakashi Iwai static int parse_mic_boost(struct hda_codec *codec)
2431352f7f91STakashi Iwai {
2432352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2433352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
2434352f7f91STakashi Iwai 	int i, err;
2435352f7f91STakashi Iwai 	int type_idx = 0;
2436352f7f91STakashi Iwai 	hda_nid_t nid;
2437352f7f91STakashi Iwai 	const char *prev_label = NULL;
2438352f7f91STakashi Iwai 
2439352f7f91STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
2440352f7f91STakashi Iwai 		if (cfg->inputs[i].type > AUTO_PIN_MIC)
2441352f7f91STakashi Iwai 			break;
2442352f7f91STakashi Iwai 		nid = cfg->inputs[i].pin;
2443352f7f91STakashi Iwai 		if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
2444352f7f91STakashi Iwai 			const char *label;
2445352f7f91STakashi Iwai 			char boost_label[32];
2446352f7f91STakashi Iwai 			struct nid_path *path;
2447352f7f91STakashi Iwai 			unsigned int val;
2448352f7f91STakashi Iwai 
2449352f7f91STakashi Iwai 			label = hda_get_autocfg_input_label(codec, cfg, i);
2450352f7f91STakashi Iwai 			if (spec->shared_mic_hp && !strcmp(label, "Misc"))
2451352f7f91STakashi Iwai 				label = "Headphone Mic";
2452352f7f91STakashi Iwai 			if (prev_label && !strcmp(label, prev_label))
2453352f7f91STakashi Iwai 				type_idx++;
2454352f7f91STakashi Iwai 			else
2455352f7f91STakashi Iwai 				type_idx = 0;
2456352f7f91STakashi Iwai 			prev_label = label;
2457352f7f91STakashi Iwai 
2458352f7f91STakashi Iwai 			snprintf(boost_label, sizeof(boost_label),
2459352f7f91STakashi Iwai 				 "%s Boost Volume", label);
2460352f7f91STakashi Iwai 			val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT);
2461352f7f91STakashi Iwai 			err = add_control(spec, HDA_CTL_WIDGET_VOL,
2462352f7f91STakashi Iwai 					  boost_label, type_idx, val);
2463352f7f91STakashi Iwai 			if (err < 0)
2464352f7f91STakashi Iwai 				return err;
2465352f7f91STakashi Iwai 
2466352f7f91STakashi Iwai 			path = snd_hda_get_nid_path(codec, nid, 0);
2467352f7f91STakashi Iwai 			if (path)
2468352f7f91STakashi Iwai 				path->ctls[NID_PATH_BOOST_CTL] = val;
2469352f7f91STakashi Iwai 		}
2470352f7f91STakashi Iwai 	}
2471352f7f91STakashi Iwai 	return 0;
2472352f7f91STakashi Iwai }
2473352f7f91STakashi Iwai 
2474352f7f91STakashi Iwai /*
2475352f7f91STakashi Iwai  * parse digital I/Os and set up NIDs in BIOS auto-parse mode
2476352f7f91STakashi Iwai  */
2477352f7f91STakashi Iwai static void parse_digital(struct hda_codec *codec)
2478352f7f91STakashi Iwai {
2479352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
24800c8c0f56STakashi Iwai 	struct nid_path *path;
2481352f7f91STakashi Iwai 	int i, nums;
2482352f7f91STakashi Iwai 	hda_nid_t dig_nid;
2483352f7f91STakashi Iwai 
2484352f7f91STakashi Iwai 	/* support multiple SPDIFs; the secondary is set up as a slave */
2485352f7f91STakashi Iwai 	nums = 0;
2486352f7f91STakashi Iwai 	for (i = 0; i < spec->autocfg.dig_outs; i++) {
2487352f7f91STakashi Iwai 		hda_nid_t pin = spec->autocfg.dig_out_pins[i];
2488352f7f91STakashi Iwai 		dig_nid = look_for_dac(codec, pin, true);
2489352f7f91STakashi Iwai 		if (!dig_nid)
2490352f7f91STakashi Iwai 			continue;
24914ac0eefaSTakashi Iwai 		path = snd_hda_add_new_path(codec, dig_nid, pin, HDA_PARSE_ALL);
24920c8c0f56STakashi Iwai 		if (!path)
2493352f7f91STakashi Iwai 			continue;
24940c8c0f56STakashi Iwai 		print_nid_path("digout", path);
2495e1284af7STakashi Iwai 		path->active = true;
2496196c1766STakashi Iwai 		spec->digout_paths[i] = snd_hda_get_path_idx(codec, path);
2497352f7f91STakashi Iwai 		if (!nums) {
2498352f7f91STakashi Iwai 			spec->multiout.dig_out_nid = dig_nid;
2499352f7f91STakashi Iwai 			spec->dig_out_type = spec->autocfg.dig_out_type[0];
2500352f7f91STakashi Iwai 		} else {
2501352f7f91STakashi Iwai 			spec->multiout.slave_dig_outs = spec->slave_dig_outs;
2502352f7f91STakashi Iwai 			if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
2503352f7f91STakashi Iwai 			break;
2504352f7f91STakashi Iwai 			spec->slave_dig_outs[nums - 1] = dig_nid;
2505352f7f91STakashi Iwai 		}
2506352f7f91STakashi Iwai 		nums++;
2507352f7f91STakashi Iwai 	}
2508352f7f91STakashi Iwai 
2509352f7f91STakashi Iwai 	if (spec->autocfg.dig_in_pin) {
2510352f7f91STakashi Iwai 		dig_nid = codec->start_nid;
2511352f7f91STakashi Iwai 		for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
2512352f7f91STakashi Iwai 			unsigned int wcaps = get_wcaps(codec, dig_nid);
2513352f7f91STakashi Iwai 			if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
2514352f7f91STakashi Iwai 				continue;
2515352f7f91STakashi Iwai 			if (!(wcaps & AC_WCAP_DIGITAL))
2516352f7f91STakashi Iwai 				continue;
2517352f7f91STakashi Iwai 			path = snd_hda_add_new_path(codec,
2518352f7f91STakashi Iwai 						    spec->autocfg.dig_in_pin,
25194ac0eefaSTakashi Iwai 						    dig_nid, HDA_PARSE_ALL);
2520352f7f91STakashi Iwai 			if (path) {
25210c8c0f56STakashi Iwai 				print_nid_path("digin", path);
2522352f7f91STakashi Iwai 				path->active = true;
2523352f7f91STakashi Iwai 				spec->dig_in_nid = dig_nid;
25242430d7b7STakashi Iwai 				spec->digin_path = snd_hda_get_path_idx(codec, path);
2525352f7f91STakashi Iwai 				break;
2526352f7f91STakashi Iwai 			}
2527352f7f91STakashi Iwai 		}
2528352f7f91STakashi Iwai 	}
2529352f7f91STakashi Iwai }
2530352f7f91STakashi Iwai 
25311da177e4SLinus Torvalds 
25321da177e4SLinus Torvalds /*
2533352f7f91STakashi Iwai  * input MUX handling
25341da177e4SLinus Torvalds  */
25351da177e4SLinus Torvalds 
2536352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur);
2537352f7f91STakashi Iwai 
2538352f7f91STakashi Iwai /* select the given imux item; either unmute exclusively or select the route */
2539352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
2540352f7f91STakashi Iwai 		      unsigned int idx)
2541352f7f91STakashi Iwai {
2542352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2543352f7f91STakashi Iwai 	const struct hda_input_mux *imux;
2544352f7f91STakashi Iwai 	struct nid_path *path;
2545352f7f91STakashi Iwai 
2546352f7f91STakashi Iwai 	imux = &spec->input_mux;
2547352f7f91STakashi Iwai 	if (!imux->num_items)
25481da177e4SLinus Torvalds 		return 0;
25491da177e4SLinus Torvalds 
2550352f7f91STakashi Iwai 	if (idx >= imux->num_items)
2551352f7f91STakashi Iwai 		idx = imux->num_items - 1;
2552352f7f91STakashi Iwai 	if (spec->cur_mux[adc_idx] == idx)
2553352f7f91STakashi Iwai 		return 0;
2554352f7f91STakashi Iwai 
2555352f7f91STakashi Iwai 	path = snd_hda_get_nid_path(codec,
2556352f7f91STakashi Iwai 				    spec->imux_pins[spec->cur_mux[adc_idx]],
2557352f7f91STakashi Iwai 				    spec->adc_nids[adc_idx]);
2558352f7f91STakashi Iwai 	if (!path)
2559352f7f91STakashi Iwai 		return 0;
2560352f7f91STakashi Iwai 	if (path->active)
2561352f7f91STakashi Iwai 		snd_hda_activate_path(codec, path, false, false);
2562352f7f91STakashi Iwai 
2563352f7f91STakashi Iwai 	spec->cur_mux[adc_idx] = idx;
2564352f7f91STakashi Iwai 
2565352f7f91STakashi Iwai 	if (spec->shared_mic_hp)
2566352f7f91STakashi Iwai 		update_shared_mic_hp(codec, spec->cur_mux[adc_idx]);
2567352f7f91STakashi Iwai 
2568352f7f91STakashi Iwai 	if (spec->dyn_adc_switch)
2569352f7f91STakashi Iwai 		dyn_adc_pcm_resetup(codec, idx);
2570352f7f91STakashi Iwai 
2571352f7f91STakashi Iwai 	path = snd_hda_get_nid_path(codec, spec->imux_pins[idx],
2572352f7f91STakashi Iwai 				    get_adc_nid(codec, adc_idx, idx));
2573352f7f91STakashi Iwai 	if (!path)
2574352f7f91STakashi Iwai 		return 0;
2575352f7f91STakashi Iwai 	if (path->active)
2576352f7f91STakashi Iwai 		return 0;
2577352f7f91STakashi Iwai 	snd_hda_activate_path(codec, path, true, false);
2578352f7f91STakashi Iwai 	if (spec->cap_sync_hook)
2579352f7f91STakashi Iwai 		spec->cap_sync_hook(codec);
25801da177e4SLinus Torvalds 	return 1;
25811da177e4SLinus Torvalds }
25821da177e4SLinus Torvalds 
25831da177e4SLinus Torvalds 
25841da177e4SLinus Torvalds /*
2585352f7f91STakashi Iwai  * Jack detections for HP auto-mute and mic-switch
25861da177e4SLinus Torvalds  */
2587352f7f91STakashi Iwai 
2588352f7f91STakashi Iwai /* check each pin in the given array; returns true if any of them is plugged */
2589352f7f91STakashi Iwai static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
25901da177e4SLinus Torvalds {
2591352f7f91STakashi Iwai 	int i, present = 0;
25921da177e4SLinus Torvalds 
2593352f7f91STakashi Iwai 	for (i = 0; i < num_pins; i++) {
2594352f7f91STakashi Iwai 		hda_nid_t nid = pins[i];
2595352f7f91STakashi Iwai 		if (!nid)
2596352f7f91STakashi Iwai 			break;
2597352f7f91STakashi Iwai 		present |= snd_hda_jack_detect(codec, nid);
25981da177e4SLinus Torvalds 	}
2599352f7f91STakashi Iwai 	return present;
26001da177e4SLinus Torvalds }
26011da177e4SLinus Torvalds 
2602352f7f91STakashi Iwai /* standard HP/line-out auto-mute helper */
2603352f7f91STakashi Iwai static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
2604352f7f91STakashi Iwai 			bool mute, bool hp_out)
26051da177e4SLinus Torvalds {
2606352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2607352f7f91STakashi Iwai 	unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT);
2608352f7f91STakashi Iwai 	int i;
26091da177e4SLinus Torvalds 
2610352f7f91STakashi Iwai 	for (i = 0; i < num_pins; i++) {
2611352f7f91STakashi Iwai 		hda_nid_t nid = pins[i];
2612352f7f91STakashi Iwai 		unsigned int val;
2613352f7f91STakashi Iwai 		if (!nid)
2614352f7f91STakashi Iwai 			break;
2615352f7f91STakashi Iwai 		/* don't reset VREF value in case it's controlling
2616352f7f91STakashi Iwai 		 * the amp (see alc861_fixup_asus_amp_vref_0f())
2617352f7f91STakashi Iwai 		 */
2618352f7f91STakashi Iwai 		if (spec->keep_vref_in_automute) {
2619352f7f91STakashi Iwai 			val = snd_hda_codec_read(codec, nid, 0,
2620352f7f91STakashi Iwai 					AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2621352f7f91STakashi Iwai 			val &= ~PIN_HP;
2622352f7f91STakashi Iwai 		} else
2623352f7f91STakashi Iwai 			val = 0;
2624352f7f91STakashi Iwai 		val |= pin_bits;
26257594aa33STakashi Iwai 		snd_hda_set_pin_ctl_cache(codec, nid, val);
2626d5a9f1bbSTakashi Iwai 		set_pin_eapd(codec, nid, !mute);
2627352f7f91STakashi Iwai 	}
2628352f7f91STakashi Iwai }
26291da177e4SLinus Torvalds 
2630352f7f91STakashi Iwai /* Toggle outputs muting */
26315d550e15STakashi Iwai void snd_hda_gen_update_outputs(struct hda_codec *codec)
2632352f7f91STakashi Iwai {
2633352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2634352f7f91STakashi Iwai 	int on;
2635352f7f91STakashi Iwai 
2636352f7f91STakashi Iwai 	/* Control HP pins/amps depending on master_mute state;
2637352f7f91STakashi Iwai 	 * in general, HP pins/amps control should be enabled in all cases,
2638352f7f91STakashi Iwai 	 * but currently set only for master_mute, just to be safe
2639352f7f91STakashi Iwai 	 */
2640352f7f91STakashi Iwai 	if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */
2641352f7f91STakashi Iwai 		do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
2642352f7f91STakashi Iwai 		    spec->autocfg.hp_pins, spec->master_mute, true);
2643352f7f91STakashi Iwai 
2644352f7f91STakashi Iwai 	if (!spec->automute_speaker)
2645352f7f91STakashi Iwai 		on = 0;
2646352f7f91STakashi Iwai 	else
2647352f7f91STakashi Iwai 		on = spec->hp_jack_present | spec->line_jack_present;
2648352f7f91STakashi Iwai 	on |= spec->master_mute;
2649352f7f91STakashi Iwai 	do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
2650352f7f91STakashi Iwai 		    spec->autocfg.speaker_pins, on, false);
2651352f7f91STakashi Iwai 
2652352f7f91STakashi Iwai 	/* toggle line-out mutes if needed, too */
2653352f7f91STakashi Iwai 	/* if LO is a copy of either HP or Speaker, don't need to handle it */
2654352f7f91STakashi Iwai 	if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
2655352f7f91STakashi Iwai 	    spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
2656352f7f91STakashi Iwai 		return;
2657352f7f91STakashi Iwai 	if (!spec->automute_lo)
2658352f7f91STakashi Iwai 		on = 0;
2659352f7f91STakashi Iwai 	else
2660352f7f91STakashi Iwai 		on = spec->hp_jack_present;
2661352f7f91STakashi Iwai 	on |= spec->master_mute;
2662352f7f91STakashi Iwai 	do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
2663352f7f91STakashi Iwai 		    spec->autocfg.line_out_pins, on, false);
2664352f7f91STakashi Iwai }
26655d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs);
2666352f7f91STakashi Iwai 
2667352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec)
2668352f7f91STakashi Iwai {
2669352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2670352f7f91STakashi Iwai 	if (spec->automute_hook)
2671352f7f91STakashi Iwai 		spec->automute_hook(codec);
2672352f7f91STakashi Iwai 	else
26735d550e15STakashi Iwai 		snd_hda_gen_update_outputs(codec);
2674352f7f91STakashi Iwai }
2675352f7f91STakashi Iwai 
2676352f7f91STakashi Iwai /* standard HP-automute helper */
26775d550e15STakashi Iwai void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
2678352f7f91STakashi Iwai {
2679352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2680352f7f91STakashi Iwai 
2681352f7f91STakashi Iwai 	spec->hp_jack_present =
2682352f7f91STakashi Iwai 		detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
2683352f7f91STakashi Iwai 			     spec->autocfg.hp_pins);
2684352f7f91STakashi Iwai 	if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo))
2685352f7f91STakashi Iwai 		return;
2686352f7f91STakashi Iwai 	call_update_outputs(codec);
2687352f7f91STakashi Iwai }
26885d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_hp_automute);
2689352f7f91STakashi Iwai 
2690352f7f91STakashi Iwai /* standard line-out-automute helper */
26915d550e15STakashi Iwai void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
2692352f7f91STakashi Iwai {
2693352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2694352f7f91STakashi Iwai 
2695352f7f91STakashi Iwai 	if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
2696352f7f91STakashi Iwai 		return;
2697352f7f91STakashi Iwai 	/* check LO jack only when it's different from HP */
2698352f7f91STakashi Iwai 	if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0])
2699352f7f91STakashi Iwai 		return;
2700352f7f91STakashi Iwai 
2701352f7f91STakashi Iwai 	spec->line_jack_present =
2702352f7f91STakashi Iwai 		detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
2703352f7f91STakashi Iwai 			     spec->autocfg.line_out_pins);
2704352f7f91STakashi Iwai 	if (!spec->automute_speaker || !spec->detect_lo)
2705352f7f91STakashi Iwai 		return;
2706352f7f91STakashi Iwai 	call_update_outputs(codec);
2707352f7f91STakashi Iwai }
27085d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_line_automute);
2709352f7f91STakashi Iwai 
2710352f7f91STakashi Iwai /* standard mic auto-switch helper */
27115d550e15STakashi Iwai void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *jack)
2712352f7f91STakashi Iwai {
2713352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2714352f7f91STakashi Iwai 	int i;
2715352f7f91STakashi Iwai 
2716352f7f91STakashi Iwai 	if (!spec->auto_mic)
2717352f7f91STakashi Iwai 		return;
2718352f7f91STakashi Iwai 
2719352f7f91STakashi Iwai 	for (i = spec->am_num_entries - 1; i > 0; i--) {
2720352f7f91STakashi Iwai 		if (snd_hda_jack_detect(codec, spec->am_entry[i].pin)) {
2721352f7f91STakashi Iwai 			mux_select(codec, 0, spec->am_entry[i].idx);
2722352f7f91STakashi Iwai 			return;
2723352f7f91STakashi Iwai 		}
2724352f7f91STakashi Iwai 	}
2725352f7f91STakashi Iwai 	mux_select(codec, 0, spec->am_entry[0].idx);
27261da177e4SLinus Torvalds }
27275d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_mic_autoswitch);
27281da177e4SLinus Torvalds 
27291da177e4SLinus Torvalds /*
2730352f7f91STakashi Iwai  * Auto-Mute mode mixer enum support
27311da177e4SLinus Torvalds  */
2732352f7f91STakashi Iwai static int automute_mode_info(struct snd_kcontrol *kcontrol,
2733352f7f91STakashi Iwai 			      struct snd_ctl_elem_info *uinfo)
2734352f7f91STakashi Iwai {
2735352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2736352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2737352f7f91STakashi Iwai 	static const char * const texts3[] = {
2738352f7f91STakashi Iwai 		"Disabled", "Speaker Only", "Line Out+Speaker"
27391da177e4SLinus Torvalds 	};
27401da177e4SLinus Torvalds 
2741352f7f91STakashi Iwai 	if (spec->automute_speaker_possible && spec->automute_lo_possible)
2742352f7f91STakashi Iwai 		return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
2743352f7f91STakashi Iwai 	return snd_hda_enum_bool_helper_info(kcontrol, uinfo);
2744352f7f91STakashi Iwai }
2745352f7f91STakashi Iwai 
2746352f7f91STakashi Iwai static int automute_mode_get(struct snd_kcontrol *kcontrol,
2747352f7f91STakashi Iwai 			     struct snd_ctl_elem_value *ucontrol)
2748352f7f91STakashi Iwai {
2749352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2750352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2751352f7f91STakashi Iwai 	unsigned int val = 0;
2752352f7f91STakashi Iwai 	if (spec->automute_speaker)
2753352f7f91STakashi Iwai 		val++;
2754352f7f91STakashi Iwai 	if (spec->automute_lo)
2755352f7f91STakashi Iwai 		val++;
2756352f7f91STakashi Iwai 
2757352f7f91STakashi Iwai 	ucontrol->value.enumerated.item[0] = val;
2758352f7f91STakashi Iwai 	return 0;
2759352f7f91STakashi Iwai }
2760352f7f91STakashi Iwai 
2761352f7f91STakashi Iwai static int automute_mode_put(struct snd_kcontrol *kcontrol,
2762352f7f91STakashi Iwai 			     struct snd_ctl_elem_value *ucontrol)
2763352f7f91STakashi Iwai {
2764352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2765352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2766352f7f91STakashi Iwai 
2767352f7f91STakashi Iwai 	switch (ucontrol->value.enumerated.item[0]) {
2768352f7f91STakashi Iwai 	case 0:
2769352f7f91STakashi Iwai 		if (!spec->automute_speaker && !spec->automute_lo)
2770352f7f91STakashi Iwai 			return 0;
2771352f7f91STakashi Iwai 		spec->automute_speaker = 0;
2772352f7f91STakashi Iwai 		spec->automute_lo = 0;
2773352f7f91STakashi Iwai 		break;
2774352f7f91STakashi Iwai 	case 1:
2775352f7f91STakashi Iwai 		if (spec->automute_speaker_possible) {
2776352f7f91STakashi Iwai 			if (!spec->automute_lo && spec->automute_speaker)
2777352f7f91STakashi Iwai 				return 0;
2778352f7f91STakashi Iwai 			spec->automute_speaker = 1;
2779352f7f91STakashi Iwai 			spec->automute_lo = 0;
2780352f7f91STakashi Iwai 		} else if (spec->automute_lo_possible) {
2781352f7f91STakashi Iwai 			if (spec->automute_lo)
2782352f7f91STakashi Iwai 				return 0;
2783352f7f91STakashi Iwai 			spec->automute_lo = 1;
2784352f7f91STakashi Iwai 		} else
2785352f7f91STakashi Iwai 			return -EINVAL;
2786352f7f91STakashi Iwai 		break;
2787352f7f91STakashi Iwai 	case 2:
2788352f7f91STakashi Iwai 		if (!spec->automute_lo_possible || !spec->automute_speaker_possible)
2789352f7f91STakashi Iwai 			return -EINVAL;
2790352f7f91STakashi Iwai 		if (spec->automute_speaker && spec->automute_lo)
2791352f7f91STakashi Iwai 			return 0;
2792352f7f91STakashi Iwai 		spec->automute_speaker = 1;
2793352f7f91STakashi Iwai 		spec->automute_lo = 1;
2794352f7f91STakashi Iwai 		break;
2795352f7f91STakashi Iwai 	default:
2796352f7f91STakashi Iwai 		return -EINVAL;
2797352f7f91STakashi Iwai 	}
2798352f7f91STakashi Iwai 	call_update_outputs(codec);
2799352f7f91STakashi Iwai 	return 1;
2800352f7f91STakashi Iwai }
2801352f7f91STakashi Iwai 
2802352f7f91STakashi Iwai static const struct snd_kcontrol_new automute_mode_enum = {
2803352f7f91STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2804352f7f91STakashi Iwai 	.name = "Auto-Mute Mode",
2805352f7f91STakashi Iwai 	.info = automute_mode_info,
2806352f7f91STakashi Iwai 	.get = automute_mode_get,
2807352f7f91STakashi Iwai 	.put = automute_mode_put,
2808352f7f91STakashi Iwai };
2809352f7f91STakashi Iwai 
2810352f7f91STakashi Iwai static int add_automute_mode_enum(struct hda_codec *codec)
2811352f7f91STakashi Iwai {
2812352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2813352f7f91STakashi Iwai 
281412c93df6STakashi Iwai 	if (!snd_hda_gen_add_kctl(spec, NULL, &automute_mode_enum))
2815352f7f91STakashi Iwai 		return -ENOMEM;
2816352f7f91STakashi Iwai 	return 0;
2817352f7f91STakashi Iwai }
2818352f7f91STakashi Iwai 
2819352f7f91STakashi Iwai /*
2820352f7f91STakashi Iwai  * Check the availability of HP/line-out auto-mute;
2821352f7f91STakashi Iwai  * Set up appropriately if really supported
2822352f7f91STakashi Iwai  */
2823352f7f91STakashi Iwai static int check_auto_mute_availability(struct hda_codec *codec)
2824352f7f91STakashi Iwai {
2825352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2826352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
2827352f7f91STakashi Iwai 	int present = 0;
2828352f7f91STakashi Iwai 	int i, err;
2829352f7f91STakashi Iwai 
2830352f7f91STakashi Iwai 	if (cfg->hp_pins[0])
2831352f7f91STakashi Iwai 		present++;
2832352f7f91STakashi Iwai 	if (cfg->line_out_pins[0])
2833352f7f91STakashi Iwai 		present++;
2834352f7f91STakashi Iwai 	if (cfg->speaker_pins[0])
2835352f7f91STakashi Iwai 		present++;
2836352f7f91STakashi Iwai 	if (present < 2) /* need two different output types */
2837352f7f91STakashi Iwai 		return 0;
2838352f7f91STakashi Iwai 
2839352f7f91STakashi Iwai 	if (!cfg->speaker_pins[0] &&
2840352f7f91STakashi Iwai 	    cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
2841352f7f91STakashi Iwai 		memcpy(cfg->speaker_pins, cfg->line_out_pins,
2842352f7f91STakashi Iwai 		       sizeof(cfg->speaker_pins));
2843352f7f91STakashi Iwai 		cfg->speaker_outs = cfg->line_outs;
2844352f7f91STakashi Iwai 	}
2845352f7f91STakashi Iwai 
2846352f7f91STakashi Iwai 	if (!cfg->hp_pins[0] &&
2847352f7f91STakashi Iwai 	    cfg->line_out_type == AUTO_PIN_HP_OUT) {
2848352f7f91STakashi Iwai 		memcpy(cfg->hp_pins, cfg->line_out_pins,
2849352f7f91STakashi Iwai 		       sizeof(cfg->hp_pins));
2850352f7f91STakashi Iwai 		cfg->hp_outs = cfg->line_outs;
2851352f7f91STakashi Iwai 	}
2852352f7f91STakashi Iwai 
2853352f7f91STakashi Iwai 	for (i = 0; i < cfg->hp_outs; i++) {
2854352f7f91STakashi Iwai 		hda_nid_t nid = cfg->hp_pins[i];
2855352f7f91STakashi Iwai 		if (!is_jack_detectable(codec, nid))
2856352f7f91STakashi Iwai 			continue;
2857352f7f91STakashi Iwai 		snd_printdd("hda-codec: Enable HP auto-muting on NID 0x%x\n",
2858352f7f91STakashi Iwai 			    nid);
2859352f7f91STakashi Iwai 		snd_hda_jack_detect_enable_callback(codec, nid, HDA_GEN_HP_EVENT,
28602e03e952STakashi Iwai 						    spec->hp_automute_hook ?
28612e03e952STakashi Iwai 						    spec->hp_automute_hook :
28625d550e15STakashi Iwai 						    snd_hda_gen_hp_automute);
2863352f7f91STakashi Iwai 		spec->detect_hp = 1;
2864352f7f91STakashi Iwai 	}
2865352f7f91STakashi Iwai 
2866352f7f91STakashi Iwai 	if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) {
2867352f7f91STakashi Iwai 		if (cfg->speaker_outs)
2868352f7f91STakashi Iwai 			for (i = 0; i < cfg->line_outs; i++) {
2869352f7f91STakashi Iwai 				hda_nid_t nid = cfg->line_out_pins[i];
2870352f7f91STakashi Iwai 				if (!is_jack_detectable(codec, nid))
2871352f7f91STakashi Iwai 					continue;
2872352f7f91STakashi Iwai 				snd_printdd("hda-codec: Enable Line-Out auto-muting on NID 0x%x\n", nid);
2873352f7f91STakashi Iwai 				snd_hda_jack_detect_enable_callback(codec, nid,
2874352f7f91STakashi Iwai 								    HDA_GEN_FRONT_EVENT,
28752e03e952STakashi Iwai 								    spec->line_automute_hook ?
28762e03e952STakashi Iwai 								    spec->line_automute_hook :
28775d550e15STakashi Iwai 								    snd_hda_gen_line_automute);
2878352f7f91STakashi Iwai 				spec->detect_lo = 1;
2879352f7f91STakashi Iwai 			}
2880352f7f91STakashi Iwai 		spec->automute_lo_possible = spec->detect_hp;
2881352f7f91STakashi Iwai 	}
2882352f7f91STakashi Iwai 
2883352f7f91STakashi Iwai 	spec->automute_speaker_possible = cfg->speaker_outs &&
2884352f7f91STakashi Iwai 		(spec->detect_hp || spec->detect_lo);
2885352f7f91STakashi Iwai 
2886352f7f91STakashi Iwai 	spec->automute_lo = spec->automute_lo_possible;
2887352f7f91STakashi Iwai 	spec->automute_speaker = spec->automute_speaker_possible;
2888352f7f91STakashi Iwai 
2889352f7f91STakashi Iwai 	if (spec->automute_speaker_possible || spec->automute_lo_possible) {
2890352f7f91STakashi Iwai 		/* create a control for automute mode */
2891352f7f91STakashi Iwai 		err = add_automute_mode_enum(codec);
2892352f7f91STakashi Iwai 		if (err < 0)
2893352f7f91STakashi Iwai 			return err;
2894352f7f91STakashi Iwai 	}
2895352f7f91STakashi Iwai 	return 0;
2896352f7f91STakashi Iwai }
2897352f7f91STakashi Iwai 
2898352f7f91STakashi Iwai /* return the position of NID in the list, or -1 if not found */
2899352f7f91STakashi Iwai static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
2900352f7f91STakashi Iwai {
2901352f7f91STakashi Iwai 	int i;
2902352f7f91STakashi Iwai 	for (i = 0; i < nums; i++)
2903352f7f91STakashi Iwai 		if (list[i] == nid)
2904352f7f91STakashi Iwai 			return i;
2905352f7f91STakashi Iwai 	return -1;
2906352f7f91STakashi Iwai }
2907352f7f91STakashi Iwai 
2908352f7f91STakashi Iwai /* check whether all auto-mic pins are valid; setup indices if OK */
2909352f7f91STakashi Iwai static bool auto_mic_check_imux(struct hda_codec *codec)
2910352f7f91STakashi Iwai {
2911352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2912352f7f91STakashi Iwai 	const struct hda_input_mux *imux;
2913352f7f91STakashi Iwai 	int i;
2914352f7f91STakashi Iwai 
2915352f7f91STakashi Iwai 	imux = &spec->input_mux;
2916352f7f91STakashi Iwai 	for (i = 0; i < spec->am_num_entries; i++) {
2917352f7f91STakashi Iwai 		spec->am_entry[i].idx =
2918352f7f91STakashi Iwai 			find_idx_in_nid_list(spec->am_entry[i].pin,
2919352f7f91STakashi Iwai 					     spec->imux_pins, imux->num_items);
2920352f7f91STakashi Iwai 		if (spec->am_entry[i].idx < 0)
2921352f7f91STakashi Iwai 			return false; /* no corresponding imux */
2922352f7f91STakashi Iwai 	}
2923352f7f91STakashi Iwai 
2924352f7f91STakashi Iwai 	/* we don't need the jack detection for the first pin */
2925352f7f91STakashi Iwai 	for (i = 1; i < spec->am_num_entries; i++)
2926352f7f91STakashi Iwai 		snd_hda_jack_detect_enable_callback(codec,
2927352f7f91STakashi Iwai 						    spec->am_entry[i].pin,
2928352f7f91STakashi Iwai 						    HDA_GEN_MIC_EVENT,
29292e03e952STakashi Iwai 						    spec->mic_autoswitch_hook ?
29302e03e952STakashi Iwai 						    spec->mic_autoswitch_hook :
29315d550e15STakashi Iwai 						    snd_hda_gen_mic_autoswitch);
2932352f7f91STakashi Iwai 	return true;
2933352f7f91STakashi Iwai }
2934352f7f91STakashi Iwai 
2935352f7f91STakashi Iwai static int compare_attr(const void *ap, const void *bp)
2936352f7f91STakashi Iwai {
2937352f7f91STakashi Iwai 	const struct automic_entry *a = ap;
2938352f7f91STakashi Iwai 	const struct automic_entry *b = bp;
2939352f7f91STakashi Iwai 	return (int)(a->attr - b->attr);
2940352f7f91STakashi Iwai }
2941352f7f91STakashi Iwai 
2942352f7f91STakashi Iwai /*
2943352f7f91STakashi Iwai  * Check the availability of auto-mic switch;
2944352f7f91STakashi Iwai  * Set up if really supported
2945352f7f91STakashi Iwai  */
2946352f7f91STakashi Iwai static int check_auto_mic_availability(struct hda_codec *codec)
2947352f7f91STakashi Iwai {
2948352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2949352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
2950352f7f91STakashi Iwai 	unsigned int types;
2951352f7f91STakashi Iwai 	int i, num_pins;
2952352f7f91STakashi Iwai 
2953352f7f91STakashi Iwai 	types = 0;
2954352f7f91STakashi Iwai 	num_pins = 0;
2955352f7f91STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
2956352f7f91STakashi Iwai 		hda_nid_t nid = cfg->inputs[i].pin;
2957352f7f91STakashi Iwai 		unsigned int attr;
2958352f7f91STakashi Iwai 		attr = snd_hda_codec_get_pincfg(codec, nid);
2959352f7f91STakashi Iwai 		attr = snd_hda_get_input_pin_attr(attr);
2960352f7f91STakashi Iwai 		if (types & (1 << attr))
2961352f7f91STakashi Iwai 			return 0; /* already occupied */
2962352f7f91STakashi Iwai 		switch (attr) {
2963352f7f91STakashi Iwai 		case INPUT_PIN_ATTR_INT:
2964352f7f91STakashi Iwai 			if (cfg->inputs[i].type != AUTO_PIN_MIC)
2965352f7f91STakashi Iwai 				return 0; /* invalid type */
2966352f7f91STakashi Iwai 			break;
2967352f7f91STakashi Iwai 		case INPUT_PIN_ATTR_UNUSED:
2968352f7f91STakashi Iwai 			return 0; /* invalid entry */
2969352f7f91STakashi Iwai 		default:
2970352f7f91STakashi Iwai 			if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
2971352f7f91STakashi Iwai 				return 0; /* invalid type */
2972352f7f91STakashi Iwai 			if (!spec->line_in_auto_switch &&
2973352f7f91STakashi Iwai 			    cfg->inputs[i].type != AUTO_PIN_MIC)
2974352f7f91STakashi Iwai 				return 0; /* only mic is allowed */
2975352f7f91STakashi Iwai 			if (!is_jack_detectable(codec, nid))
2976352f7f91STakashi Iwai 				return 0; /* no unsol support */
2977352f7f91STakashi Iwai 			break;
2978352f7f91STakashi Iwai 		}
2979352f7f91STakashi Iwai 		if (num_pins >= MAX_AUTO_MIC_PINS)
2980352f7f91STakashi Iwai 			return 0;
2981352f7f91STakashi Iwai 		types |= (1 << attr);
2982352f7f91STakashi Iwai 		spec->am_entry[num_pins].pin = nid;
2983352f7f91STakashi Iwai 		spec->am_entry[num_pins].attr = attr;
2984352f7f91STakashi Iwai 		num_pins++;
2985352f7f91STakashi Iwai 	}
2986352f7f91STakashi Iwai 
2987352f7f91STakashi Iwai 	if (num_pins < 2)
2988352f7f91STakashi Iwai 		return 0;
2989352f7f91STakashi Iwai 
2990352f7f91STakashi Iwai 	spec->am_num_entries = num_pins;
2991352f7f91STakashi Iwai 	/* sort the am_entry in the order of attr so that the pin with a
2992352f7f91STakashi Iwai 	 * higher attr will be selected when the jack is plugged.
2993352f7f91STakashi Iwai 	 */
2994352f7f91STakashi Iwai 	sort(spec->am_entry, num_pins, sizeof(spec->am_entry[0]),
2995352f7f91STakashi Iwai 	     compare_attr, NULL);
2996352f7f91STakashi Iwai 
2997352f7f91STakashi Iwai 	if (!auto_mic_check_imux(codec))
2998352f7f91STakashi Iwai 		return 0;
2999352f7f91STakashi Iwai 
3000352f7f91STakashi Iwai 	spec->auto_mic = 1;
3001352f7f91STakashi Iwai 	spec->num_adc_nids = 1;
3002352f7f91STakashi Iwai 	spec->cur_mux[0] = spec->am_entry[0].idx;
3003352f7f91STakashi Iwai 	snd_printdd("hda-codec: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
3004352f7f91STakashi Iwai 		    spec->am_entry[0].pin,
3005352f7f91STakashi Iwai 		    spec->am_entry[1].pin,
3006352f7f91STakashi Iwai 		    spec->am_entry[2].pin);
3007352f7f91STakashi Iwai 
3008352f7f91STakashi Iwai 	return 0;
3009352f7f91STakashi Iwai }
3010352f7f91STakashi Iwai 
3011352f7f91STakashi Iwai 
30129eb413e5STakashi Iwai /*
30139eb413e5STakashi Iwai  * Parse the given BIOS configuration and set up the hda_gen_spec
30149eb413e5STakashi Iwai  *
30159eb413e5STakashi Iwai  * return 1 if successful, 0 if the proper config is not found,
3016352f7f91STakashi Iwai  * or a negative error code
3017352f7f91STakashi Iwai  */
3018352f7f91STakashi Iwai int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
30199eb413e5STakashi Iwai 				  struct auto_pin_cfg *cfg)
3020352f7f91STakashi Iwai {
3021352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3022352f7f91STakashi Iwai 	int err;
3023352f7f91STakashi Iwai 
30249eb413e5STakashi Iwai 	if (cfg != &spec->autocfg) {
30259eb413e5STakashi Iwai 		spec->autocfg = *cfg;
30269eb413e5STakashi Iwai 		cfg = &spec->autocfg;
30279eb413e5STakashi Iwai 	}
30289eb413e5STakashi Iwai 
3029352f7f91STakashi Iwai 	if (!cfg->line_outs) {
3030352f7f91STakashi Iwai 		if (cfg->dig_outs || cfg->dig_in_pin) {
3031352f7f91STakashi Iwai 			spec->multiout.max_channels = 2;
3032352f7f91STakashi Iwai 			spec->no_analog = 1;
3033352f7f91STakashi Iwai 			goto dig_only;
3034352f7f91STakashi Iwai 		}
3035352f7f91STakashi Iwai 		return 0; /* can't find valid BIOS pin config */
3036352f7f91STakashi Iwai 	}
3037352f7f91STakashi Iwai 
3038352f7f91STakashi Iwai 	if (!spec->no_primary_hp &&
3039352f7f91STakashi Iwai 	    cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
3040352f7f91STakashi Iwai 	    cfg->line_outs <= cfg->hp_outs) {
3041352f7f91STakashi Iwai 		/* use HP as primary out */
3042352f7f91STakashi Iwai 		cfg->speaker_outs = cfg->line_outs;
3043352f7f91STakashi Iwai 		memcpy(cfg->speaker_pins, cfg->line_out_pins,
3044352f7f91STakashi Iwai 		       sizeof(cfg->speaker_pins));
3045352f7f91STakashi Iwai 		cfg->line_outs = cfg->hp_outs;
3046352f7f91STakashi Iwai 		memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins));
3047352f7f91STakashi Iwai 		cfg->hp_outs = 0;
3048352f7f91STakashi Iwai 		memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
3049352f7f91STakashi Iwai 		cfg->line_out_type = AUTO_PIN_HP_OUT;
3050352f7f91STakashi Iwai 	}
3051352f7f91STakashi Iwai 
3052352f7f91STakashi Iwai 	err = parse_output_paths(codec);
3053352f7f91STakashi Iwai 	if (err < 0)
3054352f7f91STakashi Iwai 		return err;
3055352f7f91STakashi Iwai 	err = create_multi_channel_mode(codec);
3056352f7f91STakashi Iwai 	if (err < 0)
3057352f7f91STakashi Iwai 		return err;
3058352f7f91STakashi Iwai 	err = create_multi_out_ctls(codec, cfg);
3059352f7f91STakashi Iwai 	if (err < 0)
3060352f7f91STakashi Iwai 		return err;
3061352f7f91STakashi Iwai 	err = create_hp_out_ctls(codec);
3062352f7f91STakashi Iwai 	if (err < 0)
3063352f7f91STakashi Iwai 		return err;
3064352f7f91STakashi Iwai 	err = create_speaker_out_ctls(codec);
3065352f7f91STakashi Iwai 	if (err < 0)
3066352f7f91STakashi Iwai 		return err;
306738cf6f1aSTakashi Iwai 	err = create_indep_hp_ctls(codec);
306838cf6f1aSTakashi Iwai 	if (err < 0)
306938cf6f1aSTakashi Iwai 		return err;
3070352f7f91STakashi Iwai 	err = create_shared_input(codec);
3071352f7f91STakashi Iwai 	if (err < 0)
3072352f7f91STakashi Iwai 		return err;
3073352f7f91STakashi Iwai 	err = create_input_ctls(codec);
3074352f7f91STakashi Iwai 	if (err < 0)
3075352f7f91STakashi Iwai 		return err;
3076352f7f91STakashi Iwai 
3077352f7f91STakashi Iwai 	/* check the multiple speaker pins */
3078352f7f91STakashi Iwai 	if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
3079352f7f91STakashi Iwai 		spec->const_channel_count = cfg->line_outs * 2;
3080352f7f91STakashi Iwai 	else
3081352f7f91STakashi Iwai 		spec->const_channel_count = cfg->speaker_outs * 2;
3082352f7f91STakashi Iwai 
3083352f7f91STakashi Iwai 	if (spec->multi_ios > 0)
3084352f7f91STakashi Iwai 		spec->multiout.max_channels = max(spec->ext_channel_count,
3085352f7f91STakashi Iwai 						  spec->const_channel_count);
3086352f7f91STakashi Iwai 	else
3087352f7f91STakashi Iwai 		spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3088352f7f91STakashi Iwai 
3089352f7f91STakashi Iwai 	err = check_auto_mute_availability(codec);
3090352f7f91STakashi Iwai 	if (err < 0)
3091352f7f91STakashi Iwai 		return err;
3092352f7f91STakashi Iwai 
3093352f7f91STakashi Iwai 	err = check_dyn_adc_switch(codec);
3094352f7f91STakashi Iwai 	if (err < 0)
3095352f7f91STakashi Iwai 		return err;
3096352f7f91STakashi Iwai 
3097352f7f91STakashi Iwai 	if (!spec->shared_mic_hp) {
3098352f7f91STakashi Iwai 		err = check_auto_mic_availability(codec);
3099352f7f91STakashi Iwai 		if (err < 0)
3100352f7f91STakashi Iwai 			return err;
3101352f7f91STakashi Iwai 	}
3102352f7f91STakashi Iwai 
3103352f7f91STakashi Iwai 	err = create_capture_mixers(codec);
3104352f7f91STakashi Iwai 	if (err < 0)
3105352f7f91STakashi Iwai 		return err;
3106352f7f91STakashi Iwai 
3107352f7f91STakashi Iwai 	err = parse_mic_boost(codec);
3108352f7f91STakashi Iwai 	if (err < 0)
3109352f7f91STakashi Iwai 		return err;
3110352f7f91STakashi Iwai 
3111352f7f91STakashi Iwai  dig_only:
3112352f7f91STakashi Iwai 	parse_digital(codec);
3113352f7f91STakashi Iwai 
3114352f7f91STakashi Iwai 	return 1;
3115352f7f91STakashi Iwai }
3116352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_parse_auto_config);
3117352f7f91STakashi Iwai 
3118352f7f91STakashi Iwai 
3119352f7f91STakashi Iwai /*
3120352f7f91STakashi Iwai  * Build control elements
3121352f7f91STakashi Iwai  */
3122352f7f91STakashi Iwai 
3123352f7f91STakashi Iwai /* slave controls for virtual master */
3124352f7f91STakashi Iwai static const char * const slave_pfxs[] = {
3125352f7f91STakashi Iwai 	"Front", "Surround", "Center", "LFE", "Side",
3126352f7f91STakashi Iwai 	"Headphone", "Speaker", "Mono", "Line Out",
3127352f7f91STakashi Iwai 	"CLFE", "Bass Speaker", "PCM",
3128352f7f91STakashi Iwai 	NULL,
3129352f7f91STakashi Iwai };
3130352f7f91STakashi Iwai 
3131352f7f91STakashi Iwai int snd_hda_gen_build_controls(struct hda_codec *codec)
3132352f7f91STakashi Iwai {
3133352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3134352f7f91STakashi Iwai 	int err;
3135352f7f91STakashi Iwai 
313636502d02STakashi Iwai 	if (spec->kctls.used) {
3137352f7f91STakashi Iwai 		err = snd_hda_add_new_ctls(codec, spec->kctls.list);
3138352f7f91STakashi Iwai 		if (err < 0)
3139352f7f91STakashi Iwai 			return err;
314036502d02STakashi Iwai 	}
3141352f7f91STakashi Iwai 
3142352f7f91STakashi Iwai 	if (spec->multiout.dig_out_nid) {
3143352f7f91STakashi Iwai 		err = snd_hda_create_dig_out_ctls(codec,
3144352f7f91STakashi Iwai 						  spec->multiout.dig_out_nid,
3145352f7f91STakashi Iwai 						  spec->multiout.dig_out_nid,
3146352f7f91STakashi Iwai 						  spec->pcm_rec[1].pcm_type);
3147352f7f91STakashi Iwai 		if (err < 0)
3148352f7f91STakashi Iwai 			return err;
3149352f7f91STakashi Iwai 		if (!spec->no_analog) {
3150352f7f91STakashi Iwai 			err = snd_hda_create_spdif_share_sw(codec,
3151352f7f91STakashi Iwai 							    &spec->multiout);
3152352f7f91STakashi Iwai 			if (err < 0)
3153352f7f91STakashi Iwai 				return err;
3154352f7f91STakashi Iwai 			spec->multiout.share_spdif = 1;
3155352f7f91STakashi Iwai 		}
3156352f7f91STakashi Iwai 	}
3157352f7f91STakashi Iwai 	if (spec->dig_in_nid) {
3158352f7f91STakashi Iwai 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
3159352f7f91STakashi Iwai 		if (err < 0)
3160352f7f91STakashi Iwai 			return err;
3161352f7f91STakashi Iwai 	}
3162352f7f91STakashi Iwai 
3163352f7f91STakashi Iwai 	/* if we have no master control, let's create it */
3164352f7f91STakashi Iwai 	if (!spec->no_analog &&
3165352f7f91STakashi Iwai 	    !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
3166352f7f91STakashi Iwai 		unsigned int vmaster_tlv[4];
3167352f7f91STakashi Iwai 		snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
3168352f7f91STakashi Iwai 					HDA_OUTPUT, vmaster_tlv);
3169352f7f91STakashi Iwai 		err = snd_hda_add_vmaster(codec, "Master Playback Volume",
3170352f7f91STakashi Iwai 					  vmaster_tlv, slave_pfxs,
3171352f7f91STakashi Iwai 					  "Playback Volume");
3172352f7f91STakashi Iwai 		if (err < 0)
3173352f7f91STakashi Iwai 			return err;
3174352f7f91STakashi Iwai 	}
3175352f7f91STakashi Iwai 	if (!spec->no_analog &&
3176352f7f91STakashi Iwai 	    !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
3177352f7f91STakashi Iwai 		err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
3178352f7f91STakashi Iwai 					    NULL, slave_pfxs,
3179352f7f91STakashi Iwai 					    "Playback Switch",
3180352f7f91STakashi Iwai 					    true, &spec->vmaster_mute.sw_kctl);
3181352f7f91STakashi Iwai 		if (err < 0)
3182352f7f91STakashi Iwai 			return err;
3183352f7f91STakashi Iwai 		if (spec->vmaster_mute.hook)
3184fd25a97aSTakashi Iwai 			snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute,
3185fd25a97aSTakashi Iwai 						 spec->vmaster_mute_enum);
3186352f7f91STakashi Iwai 	}
3187352f7f91STakashi Iwai 
3188352f7f91STakashi Iwai 	free_kctls(spec); /* no longer needed */
3189352f7f91STakashi Iwai 
3190352f7f91STakashi Iwai 	if (spec->shared_mic_hp) {
3191352f7f91STakashi Iwai 		int err;
3192352f7f91STakashi Iwai 		int nid = spec->autocfg.inputs[1].pin;
3193352f7f91STakashi Iwai 		err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0);
3194352f7f91STakashi Iwai 		if (err < 0)
3195352f7f91STakashi Iwai 			return err;
3196352f7f91STakashi Iwai 		err = snd_hda_jack_detect_enable(codec, nid, 0);
3197352f7f91STakashi Iwai 		if (err < 0)
3198352f7f91STakashi Iwai 			return err;
3199352f7f91STakashi Iwai 	}
3200352f7f91STakashi Iwai 
3201352f7f91STakashi Iwai 	err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
3202352f7f91STakashi Iwai 	if (err < 0)
3203352f7f91STakashi Iwai 		return err;
3204352f7f91STakashi Iwai 
3205352f7f91STakashi Iwai 	return 0;
3206352f7f91STakashi Iwai }
3207352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_controls);
3208352f7f91STakashi Iwai 
3209352f7f91STakashi Iwai 
3210352f7f91STakashi Iwai /*
3211352f7f91STakashi Iwai  * PCM definitions
3212352f7f91STakashi Iwai  */
3213352f7f91STakashi Iwai 
3214352f7f91STakashi Iwai /*
3215352f7f91STakashi Iwai  * Analog playback callbacks
3216352f7f91STakashi Iwai  */
3217352f7f91STakashi Iwai static int playback_pcm_open(struct hda_pcm_stream *hinfo,
3218352f7f91STakashi Iwai 			     struct hda_codec *codec,
3219352f7f91STakashi Iwai 			     struct snd_pcm_substream *substream)
3220352f7f91STakashi Iwai {
3221352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
322238cf6f1aSTakashi Iwai 	int err;
322338cf6f1aSTakashi Iwai 
322438cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
322538cf6f1aSTakashi Iwai 	err = snd_hda_multi_out_analog_open(codec,
322638cf6f1aSTakashi Iwai 					    &spec->multiout, substream,
3227352f7f91STakashi Iwai 					     hinfo);
322838cf6f1aSTakashi Iwai 	if (!err)
322938cf6f1aSTakashi Iwai 		spec->active_streams |= 1 << STREAM_MULTI_OUT;
323038cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
323138cf6f1aSTakashi Iwai 	return err;
3232352f7f91STakashi Iwai }
3233352f7f91STakashi Iwai 
3234352f7f91STakashi Iwai static int playback_pcm_prepare(struct hda_pcm_stream *hinfo,
323597ec558aSTakashi Iwai 				struct hda_codec *codec,
323697ec558aSTakashi Iwai 				unsigned int stream_tag,
323797ec558aSTakashi Iwai 				unsigned int format,
323897ec558aSTakashi Iwai 				struct snd_pcm_substream *substream)
323997ec558aSTakashi Iwai {
3240352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3241352f7f91STakashi Iwai 	return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
3242352f7f91STakashi Iwai 						stream_tag, format, substream);
3243352f7f91STakashi Iwai }
324497ec558aSTakashi Iwai 
3245352f7f91STakashi Iwai static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3246352f7f91STakashi Iwai 				struct hda_codec *codec,
3247352f7f91STakashi Iwai 				struct snd_pcm_substream *substream)
3248352f7f91STakashi Iwai {
3249352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3250352f7f91STakashi Iwai 	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
3251352f7f91STakashi Iwai }
3252352f7f91STakashi Iwai 
325338cf6f1aSTakashi Iwai static int playback_pcm_close(struct hda_pcm_stream *hinfo,
325438cf6f1aSTakashi Iwai 			      struct hda_codec *codec,
325538cf6f1aSTakashi Iwai 			      struct snd_pcm_substream *substream)
325638cf6f1aSTakashi Iwai {
325738cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
325838cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
325938cf6f1aSTakashi Iwai 	spec->active_streams &= ~(1 << STREAM_MULTI_OUT);
326038cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
326138cf6f1aSTakashi Iwai 	return 0;
326238cf6f1aSTakashi Iwai }
326338cf6f1aSTakashi Iwai 
326438cf6f1aSTakashi Iwai static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo,
326538cf6f1aSTakashi Iwai 				 struct hda_codec *codec,
326638cf6f1aSTakashi Iwai 				 struct snd_pcm_substream *substream)
326738cf6f1aSTakashi Iwai {
326838cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
326938cf6f1aSTakashi Iwai 	int err = 0;
327038cf6f1aSTakashi Iwai 
327138cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
327238cf6f1aSTakashi Iwai 	if (!spec->indep_hp_enabled)
327338cf6f1aSTakashi Iwai 		err = -EBUSY;
327438cf6f1aSTakashi Iwai 	else
327538cf6f1aSTakashi Iwai 		spec->active_streams |= 1 << STREAM_INDEP_HP;
327638cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
327738cf6f1aSTakashi Iwai 	return err;
327838cf6f1aSTakashi Iwai }
327938cf6f1aSTakashi Iwai 
328038cf6f1aSTakashi Iwai static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo,
328138cf6f1aSTakashi Iwai 				  struct hda_codec *codec,
328238cf6f1aSTakashi Iwai 				  struct snd_pcm_substream *substream)
328338cf6f1aSTakashi Iwai {
328438cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
328538cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
328638cf6f1aSTakashi Iwai 	spec->active_streams &= ~(1 << STREAM_INDEP_HP);
328738cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
328838cf6f1aSTakashi Iwai 	return 0;
328938cf6f1aSTakashi Iwai }
329038cf6f1aSTakashi Iwai 
3291352f7f91STakashi Iwai /*
3292352f7f91STakashi Iwai  * Digital out
3293352f7f91STakashi Iwai  */
3294352f7f91STakashi Iwai static int dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
3295352f7f91STakashi Iwai 				 struct hda_codec *codec,
3296352f7f91STakashi Iwai 				 struct snd_pcm_substream *substream)
3297352f7f91STakashi Iwai {
3298352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3299352f7f91STakashi Iwai 	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
3300352f7f91STakashi Iwai }
3301352f7f91STakashi Iwai 
3302352f7f91STakashi Iwai static int dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3303352f7f91STakashi Iwai 				    struct hda_codec *codec,
3304352f7f91STakashi Iwai 				    unsigned int stream_tag,
3305352f7f91STakashi Iwai 				    unsigned int format,
3306352f7f91STakashi Iwai 				    struct snd_pcm_substream *substream)
3307352f7f91STakashi Iwai {
3308352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3309352f7f91STakashi Iwai 	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
3310352f7f91STakashi Iwai 					     stream_tag, format, substream);
3311352f7f91STakashi Iwai }
3312352f7f91STakashi Iwai 
3313352f7f91STakashi Iwai static int dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3314352f7f91STakashi Iwai 				    struct hda_codec *codec,
3315352f7f91STakashi Iwai 				    struct snd_pcm_substream *substream)
3316352f7f91STakashi Iwai {
3317352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3318352f7f91STakashi Iwai 	return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
3319352f7f91STakashi Iwai }
3320352f7f91STakashi Iwai 
3321352f7f91STakashi Iwai static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
3322352f7f91STakashi Iwai 				  struct hda_codec *codec,
3323352f7f91STakashi Iwai 				  struct snd_pcm_substream *substream)
3324352f7f91STakashi Iwai {
3325352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3326352f7f91STakashi Iwai 	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
3327352f7f91STakashi Iwai }
3328352f7f91STakashi Iwai 
3329352f7f91STakashi Iwai /*
3330352f7f91STakashi Iwai  * Analog capture
3331352f7f91STakashi Iwai  */
3332352f7f91STakashi Iwai static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
3333352f7f91STakashi Iwai 				   struct hda_codec *codec,
3334352f7f91STakashi Iwai 				   unsigned int stream_tag,
3335352f7f91STakashi Iwai 				   unsigned int format,
3336352f7f91STakashi Iwai 				   struct snd_pcm_substream *substream)
3337352f7f91STakashi Iwai {
3338352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3339352f7f91STakashi Iwai 
3340352f7f91STakashi Iwai 	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
334197ec558aSTakashi Iwai 				   stream_tag, 0, format);
334297ec558aSTakashi Iwai 	return 0;
334397ec558aSTakashi Iwai }
334497ec558aSTakashi Iwai 
3345352f7f91STakashi Iwai static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
334697ec558aSTakashi Iwai 				   struct hda_codec *codec,
334797ec558aSTakashi Iwai 				   struct snd_pcm_substream *substream)
334897ec558aSTakashi Iwai {
3349352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
335097ec558aSTakashi Iwai 
3351352f7f91STakashi Iwai 	snd_hda_codec_cleanup_stream(codec,
3352352f7f91STakashi Iwai 				     spec->adc_nids[substream->number + 1]);
335397ec558aSTakashi Iwai 	return 0;
335497ec558aSTakashi Iwai }
335597ec558aSTakashi Iwai 
3356352f7f91STakashi Iwai /*
3357352f7f91STakashi Iwai  */
3358352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_playback = {
3359352f7f91STakashi Iwai 	.substreams = 1,
3360352f7f91STakashi Iwai 	.channels_min = 2,
3361352f7f91STakashi Iwai 	.channels_max = 8,
3362352f7f91STakashi Iwai 	/* NID is set in build_pcms */
3363352f7f91STakashi Iwai 	.ops = {
3364352f7f91STakashi Iwai 		.open = playback_pcm_open,
336538cf6f1aSTakashi Iwai 		.close = playback_pcm_close,
3366352f7f91STakashi Iwai 		.prepare = playback_pcm_prepare,
3367352f7f91STakashi Iwai 		.cleanup = playback_pcm_cleanup
3368352f7f91STakashi Iwai 	},
3369352f7f91STakashi Iwai };
3370352f7f91STakashi Iwai 
3371352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_capture = {
3372352f7f91STakashi Iwai 	.substreams = 1,
3373352f7f91STakashi Iwai 	.channels_min = 2,
3374352f7f91STakashi Iwai 	.channels_max = 2,
3375352f7f91STakashi Iwai 	/* NID is set in build_pcms */
3376352f7f91STakashi Iwai };
3377352f7f91STakashi Iwai 
3378352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_playback = {
3379352f7f91STakashi Iwai 	.substreams = 1,
3380352f7f91STakashi Iwai 	.channels_min = 2,
3381352f7f91STakashi Iwai 	.channels_max = 2,
3382352f7f91STakashi Iwai 	/* NID is set in build_pcms */
338338cf6f1aSTakashi Iwai 	.ops = {
338438cf6f1aSTakashi Iwai 		.open = alt_playback_pcm_open,
338538cf6f1aSTakashi Iwai 		.close = alt_playback_pcm_close
338638cf6f1aSTakashi Iwai 	},
3387352f7f91STakashi Iwai };
3388352f7f91STakashi Iwai 
3389352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_capture = {
3390352f7f91STakashi Iwai 	.substreams = 2, /* can be overridden */
3391352f7f91STakashi Iwai 	.channels_min = 2,
3392352f7f91STakashi Iwai 	.channels_max = 2,
3393352f7f91STakashi Iwai 	/* NID is set in build_pcms */
3394352f7f91STakashi Iwai 	.ops = {
3395352f7f91STakashi Iwai 		.prepare = alt_capture_pcm_prepare,
3396352f7f91STakashi Iwai 		.cleanup = alt_capture_pcm_cleanup
3397352f7f91STakashi Iwai 	},
3398352f7f91STakashi Iwai };
3399352f7f91STakashi Iwai 
3400352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_playback = {
3401352f7f91STakashi Iwai 	.substreams = 1,
3402352f7f91STakashi Iwai 	.channels_min = 2,
3403352f7f91STakashi Iwai 	.channels_max = 2,
3404352f7f91STakashi Iwai 	/* NID is set in build_pcms */
3405352f7f91STakashi Iwai 	.ops = {
3406352f7f91STakashi Iwai 		.open = dig_playback_pcm_open,
3407352f7f91STakashi Iwai 		.close = dig_playback_pcm_close,
3408352f7f91STakashi Iwai 		.prepare = dig_playback_pcm_prepare,
3409352f7f91STakashi Iwai 		.cleanup = dig_playback_pcm_cleanup
3410352f7f91STakashi Iwai 	},
3411352f7f91STakashi Iwai };
3412352f7f91STakashi Iwai 
3413352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_capture = {
3414352f7f91STakashi Iwai 	.substreams = 1,
3415352f7f91STakashi Iwai 	.channels_min = 2,
3416352f7f91STakashi Iwai 	.channels_max = 2,
3417352f7f91STakashi Iwai 	/* NID is set in build_pcms */
3418352f7f91STakashi Iwai };
3419352f7f91STakashi Iwai 
3420352f7f91STakashi Iwai /* Used by build_pcms to flag that a PCM has no playback stream */
3421352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_null_stream = {
3422352f7f91STakashi Iwai 	.substreams = 0,
3423352f7f91STakashi Iwai 	.channels_min = 0,
3424352f7f91STakashi Iwai 	.channels_max = 0,
3425352f7f91STakashi Iwai };
3426352f7f91STakashi Iwai 
3427352f7f91STakashi Iwai /*
3428352f7f91STakashi Iwai  * dynamic changing ADC PCM streams
3429352f7f91STakashi Iwai  */
3430352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur)
34311da177e4SLinus Torvalds {
3432352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3433352f7f91STakashi Iwai 	hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]];
34341da177e4SLinus Torvalds 
3435352f7f91STakashi Iwai 	if (spec->cur_adc && spec->cur_adc != new_adc) {
3436352f7f91STakashi Iwai 		/* stream is running, let's swap the current ADC */
3437352f7f91STakashi Iwai 		__snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
3438352f7f91STakashi Iwai 		spec->cur_adc = new_adc;
3439352f7f91STakashi Iwai 		snd_hda_codec_setup_stream(codec, new_adc,
3440352f7f91STakashi Iwai 					   spec->cur_adc_stream_tag, 0,
3441352f7f91STakashi Iwai 					   spec->cur_adc_format);
3442352f7f91STakashi Iwai 		return true;
3443352f7f91STakashi Iwai 	}
3444352f7f91STakashi Iwai 	return false;
3445352f7f91STakashi Iwai }
3446352f7f91STakashi Iwai 
3447352f7f91STakashi Iwai /* analog capture with dynamic dual-adc changes */
3448352f7f91STakashi Iwai static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
3449352f7f91STakashi Iwai 				       struct hda_codec *codec,
3450352f7f91STakashi Iwai 				       unsigned int stream_tag,
3451352f7f91STakashi Iwai 				       unsigned int format,
3452352f7f91STakashi Iwai 				       struct snd_pcm_substream *substream)
3453352f7f91STakashi Iwai {
3454352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3455352f7f91STakashi Iwai 	spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]];
3456352f7f91STakashi Iwai 	spec->cur_adc_stream_tag = stream_tag;
3457352f7f91STakashi Iwai 	spec->cur_adc_format = format;
3458352f7f91STakashi Iwai 	snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
34591da177e4SLinus Torvalds 	return 0;
34601da177e4SLinus Torvalds }
34611da177e4SLinus Torvalds 
3462352f7f91STakashi Iwai static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
3463352f7f91STakashi Iwai 				       struct hda_codec *codec,
3464352f7f91STakashi Iwai 				       struct snd_pcm_substream *substream)
3465352f7f91STakashi Iwai {
3466352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3467352f7f91STakashi Iwai 	snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
3468352f7f91STakashi Iwai 	spec->cur_adc = 0;
3469352f7f91STakashi Iwai 	return 0;
3470352f7f91STakashi Iwai }
3471352f7f91STakashi Iwai 
3472352f7f91STakashi Iwai static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = {
3473352f7f91STakashi Iwai 	.substreams = 1,
3474352f7f91STakashi Iwai 	.channels_min = 2,
3475352f7f91STakashi Iwai 	.channels_max = 2,
3476352f7f91STakashi Iwai 	.nid = 0, /* fill later */
3477352f7f91STakashi Iwai 	.ops = {
3478352f7f91STakashi Iwai 		.prepare = dyn_adc_capture_pcm_prepare,
3479352f7f91STakashi Iwai 		.cleanup = dyn_adc_capture_pcm_cleanup
3480352f7f91STakashi Iwai 	},
3481352f7f91STakashi Iwai };
3482352f7f91STakashi Iwai 
3483f873e536STakashi Iwai static void fill_pcm_stream_name(char *str, size_t len, const char *sfx,
3484f873e536STakashi Iwai 				 const char *chip_name)
3485f873e536STakashi Iwai {
3486f873e536STakashi Iwai 	char *p;
3487f873e536STakashi Iwai 
3488f873e536STakashi Iwai 	if (*str)
3489f873e536STakashi Iwai 		return;
3490f873e536STakashi Iwai 	strlcpy(str, chip_name, len);
3491f873e536STakashi Iwai 
3492f873e536STakashi Iwai 	/* drop non-alnum chars after a space */
3493f873e536STakashi Iwai 	for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) {
3494f873e536STakashi Iwai 		if (!isalnum(p[1])) {
3495f873e536STakashi Iwai 			*p = 0;
3496f873e536STakashi Iwai 			break;
3497f873e536STakashi Iwai 		}
3498f873e536STakashi Iwai 	}
3499f873e536STakashi Iwai 	strlcat(str, sfx, len);
3500f873e536STakashi Iwai }
3501f873e536STakashi Iwai 
3502352f7f91STakashi Iwai /* build PCM streams based on the parsed results */
3503352f7f91STakashi Iwai int snd_hda_gen_build_pcms(struct hda_codec *codec)
3504352f7f91STakashi Iwai {
3505352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3506352f7f91STakashi Iwai 	struct hda_pcm *info = spec->pcm_rec;
3507352f7f91STakashi Iwai 	const struct hda_pcm_stream *p;
3508352f7f91STakashi Iwai 	bool have_multi_adcs;
3509352f7f91STakashi Iwai 
35101da177e4SLinus Torvalds 	codec->num_pcms = 1;
35111da177e4SLinus Torvalds 	codec->pcm_info = info;
35121da177e4SLinus Torvalds 
3513352f7f91STakashi Iwai 	if (spec->no_analog)
3514352f7f91STakashi Iwai 		goto skip_analog;
3515352f7f91STakashi Iwai 
3516f873e536STakashi Iwai 	fill_pcm_stream_name(spec->stream_name_analog,
3517f873e536STakashi Iwai 			     sizeof(spec->stream_name_analog),
3518f873e536STakashi Iwai 			     " Analog", codec->chip_name);
3519352f7f91STakashi Iwai 	info->name = spec->stream_name_analog;
3520352f7f91STakashi Iwai 
3521352f7f91STakashi Iwai 	if (spec->multiout.num_dacs > 0) {
3522352f7f91STakashi Iwai 		p = spec->stream_analog_playback;
3523352f7f91STakashi Iwai 		if (!p)
3524352f7f91STakashi Iwai 			p = &pcm_analog_playback;
3525352f7f91STakashi Iwai 		info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
3526352f7f91STakashi Iwai 		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
3527352f7f91STakashi Iwai 		info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
3528352f7f91STakashi Iwai 			spec->multiout.max_channels;
3529352f7f91STakashi Iwai 		if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
3530352f7f91STakashi Iwai 		    spec->autocfg.line_outs == 2)
3531352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap =
3532352f7f91STakashi Iwai 				snd_pcm_2_1_chmaps;
3533352f7f91STakashi Iwai 	}
3534352f7f91STakashi Iwai 	if (spec->num_adc_nids) {
3535352f7f91STakashi Iwai 		p = spec->stream_analog_capture;
3536352f7f91STakashi Iwai 		if (!p) {
3537352f7f91STakashi Iwai 			if (spec->dyn_adc_switch)
3538352f7f91STakashi Iwai 				p = &dyn_adc_pcm_analog_capture;
3539352f7f91STakashi Iwai 			else
3540352f7f91STakashi Iwai 				p = &pcm_analog_capture;
3541352f7f91STakashi Iwai 		}
3542352f7f91STakashi Iwai 		info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
3543352f7f91STakashi Iwai 		info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
3544352f7f91STakashi Iwai 	}
3545352f7f91STakashi Iwai 
3546352f7f91STakashi Iwai  skip_analog:
3547352f7f91STakashi Iwai 	/* SPDIF for stream index #1 */
3548352f7f91STakashi Iwai 	if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
3549f873e536STakashi Iwai 		fill_pcm_stream_name(spec->stream_name_digital,
3550352f7f91STakashi Iwai 				     sizeof(spec->stream_name_digital),
3551f873e536STakashi Iwai 				     " Digital", codec->chip_name);
3552352f7f91STakashi Iwai 		codec->num_pcms = 2;
3553352f7f91STakashi Iwai 		codec->slave_dig_outs = spec->multiout.slave_dig_outs;
3554352f7f91STakashi Iwai 		info = spec->pcm_rec + 1;
3555352f7f91STakashi Iwai 		info->name = spec->stream_name_digital;
3556352f7f91STakashi Iwai 		if (spec->dig_out_type)
3557352f7f91STakashi Iwai 			info->pcm_type = spec->dig_out_type;
3558352f7f91STakashi Iwai 		else
3559352f7f91STakashi Iwai 			info->pcm_type = HDA_PCM_TYPE_SPDIF;
3560352f7f91STakashi Iwai 		if (spec->multiout.dig_out_nid) {
3561352f7f91STakashi Iwai 			p = spec->stream_digital_playback;
3562352f7f91STakashi Iwai 			if (!p)
3563352f7f91STakashi Iwai 				p = &pcm_digital_playback;
3564352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
3565352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
3566352f7f91STakashi Iwai 		}
3567352f7f91STakashi Iwai 		if (spec->dig_in_nid) {
3568352f7f91STakashi Iwai 			p = spec->stream_digital_capture;
3569352f7f91STakashi Iwai 			if (!p)
3570352f7f91STakashi Iwai 				p = &pcm_digital_capture;
3571352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
3572352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
3573352f7f91STakashi Iwai 		}
3574352f7f91STakashi Iwai 	}
3575352f7f91STakashi Iwai 
3576352f7f91STakashi Iwai 	if (spec->no_analog)
3577352f7f91STakashi Iwai 		return 0;
3578352f7f91STakashi Iwai 
3579352f7f91STakashi Iwai 	/* If the use of more than one ADC is requested for the current
3580352f7f91STakashi Iwai 	 * model, configure a second analog capture-only PCM.
3581352f7f91STakashi Iwai 	 */
3582352f7f91STakashi Iwai 	have_multi_adcs = (spec->num_adc_nids > 1) &&
3583352f7f91STakashi Iwai 		!spec->dyn_adc_switch && !spec->auto_mic;
3584352f7f91STakashi Iwai 	/* Additional Analaog capture for index #2 */
3585352f7f91STakashi Iwai 	if (spec->alt_dac_nid || have_multi_adcs) {
3586352f7f91STakashi Iwai 		codec->num_pcms = 3;
3587352f7f91STakashi Iwai 		info = spec->pcm_rec + 2;
3588352f7f91STakashi Iwai 		info->name = spec->stream_name_analog;
3589352f7f91STakashi Iwai 		if (spec->alt_dac_nid) {
3590352f7f91STakashi Iwai 			p = spec->stream_analog_alt_playback;
3591352f7f91STakashi Iwai 			if (!p)
3592352f7f91STakashi Iwai 				p = &pcm_analog_alt_playback;
3593352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
3594352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
3595352f7f91STakashi Iwai 				spec->alt_dac_nid;
3596352f7f91STakashi Iwai 		} else {
3597352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3598352f7f91STakashi Iwai 				pcm_null_stream;
3599352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
3600352f7f91STakashi Iwai 		}
3601352f7f91STakashi Iwai 		if (have_multi_adcs) {
3602352f7f91STakashi Iwai 			p = spec->stream_analog_alt_capture;
3603352f7f91STakashi Iwai 			if (!p)
3604352f7f91STakashi Iwai 				p = &pcm_analog_alt_capture;
3605352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
3606352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
3607352f7f91STakashi Iwai 				spec->adc_nids[1];
3608352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
3609352f7f91STakashi Iwai 				spec->num_adc_nids - 1;
3610352f7f91STakashi Iwai 		} else {
3611352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3612352f7f91STakashi Iwai 				pcm_null_stream;
3613352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
3614352f7f91STakashi Iwai 		}
36151da177e4SLinus Torvalds 	}
36161da177e4SLinus Torvalds 
36171da177e4SLinus Torvalds 	return 0;
36181da177e4SLinus Torvalds }
3619352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_pcms);
3620352f7f91STakashi Iwai 
3621352f7f91STakashi Iwai 
3622352f7f91STakashi Iwai /*
3623352f7f91STakashi Iwai  * Standard auto-parser initializations
3624352f7f91STakashi Iwai  */
3625352f7f91STakashi Iwai 
3626352f7f91STakashi Iwai /* configure the path from the given dac to the pin as the proper output */
3627352f7f91STakashi Iwai static void set_output_and_unmute(struct hda_codec *codec, hda_nid_t pin,
3628196c1766STakashi Iwai 				  int pin_type, int path_idx)
3629352f7f91STakashi Iwai {
3630352f7f91STakashi Iwai 	struct nid_path *path;
3631352f7f91STakashi Iwai 
3632352f7f91STakashi Iwai 	snd_hda_set_pin_ctl_cache(codec, pin, pin_type);
3633196c1766STakashi Iwai 	path = snd_hda_get_path_from_idx(codec, path_idx);
3634352f7f91STakashi Iwai 	if (!path)
3635352f7f91STakashi Iwai 		return;
3636e1284af7STakashi Iwai 	snd_hda_activate_path(codec, path, path->active, true);
3637e1284af7STakashi Iwai 	set_pin_eapd(codec, pin, path->active);
3638352f7f91STakashi Iwai }
3639352f7f91STakashi Iwai 
3640352f7f91STakashi Iwai /* initialize primary output paths */
3641352f7f91STakashi Iwai static void init_multi_out(struct hda_codec *codec)
3642352f7f91STakashi Iwai {
3643352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3644196c1766STakashi Iwai 	hda_nid_t nid;
3645352f7f91STakashi Iwai 	int pin_type;
3646352f7f91STakashi Iwai 	int i;
3647352f7f91STakashi Iwai 
3648352f7f91STakashi Iwai 	if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
3649352f7f91STakashi Iwai 		pin_type = PIN_HP;
3650352f7f91STakashi Iwai 	else
3651352f7f91STakashi Iwai 		pin_type = PIN_OUT;
3652352f7f91STakashi Iwai 
365364049c81STakashi Iwai 	for (i = 0; i < spec->autocfg.line_outs; i++) {
365464049c81STakashi Iwai 		nid = spec->autocfg.line_out_pins[i];
3655196c1766STakashi Iwai 		if (nid)
3656196c1766STakashi Iwai 			set_output_and_unmute(codec, nid, pin_type,
3657196c1766STakashi Iwai 					      spec->out_paths[i]);
3658352f7f91STakashi Iwai 	}
3659352f7f91STakashi Iwai }
3660352f7f91STakashi Iwai 
3661db23fd19STakashi Iwai 
3662db23fd19STakashi Iwai static void __init_extra_out(struct hda_codec *codec, int num_outs,
3663196c1766STakashi Iwai 			     hda_nid_t *pins, int *paths, int type)
3664352f7f91STakashi Iwai {
3665352f7f91STakashi Iwai 	int i;
3666196c1766STakashi Iwai 	hda_nid_t pin;
3667352f7f91STakashi Iwai 
3668db23fd19STakashi Iwai 	for (i = 0; i < num_outs; i++) {
3669db23fd19STakashi Iwai 		pin = pins[i];
3670352f7f91STakashi Iwai 		if (!pin)
3671352f7f91STakashi Iwai 			break;
3672196c1766STakashi Iwai 		set_output_and_unmute(codec, pin, type, paths[i]);
3673352f7f91STakashi Iwai 	}
3674352f7f91STakashi Iwai }
3675db23fd19STakashi Iwai 
3676db23fd19STakashi Iwai /* initialize hp and speaker paths */
3677db23fd19STakashi Iwai static void init_extra_out(struct hda_codec *codec)
3678db23fd19STakashi Iwai {
3679db23fd19STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3680db23fd19STakashi Iwai 
3681db23fd19STakashi Iwai 	if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT)
3682db23fd19STakashi Iwai 		__init_extra_out(codec, spec->autocfg.hp_outs,
3683db23fd19STakashi Iwai 				 spec->autocfg.hp_pins,
3684196c1766STakashi Iwai 				 spec->hp_paths, PIN_HP);
3685db23fd19STakashi Iwai 	if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT)
3686db23fd19STakashi Iwai 		__init_extra_out(codec, spec->autocfg.speaker_outs,
3687db23fd19STakashi Iwai 				 spec->autocfg.speaker_pins,
3688196c1766STakashi Iwai 				 spec->speaker_paths, PIN_OUT);
3689352f7f91STakashi Iwai }
3690352f7f91STakashi Iwai 
3691352f7f91STakashi Iwai /* initialize multi-io paths */
3692352f7f91STakashi Iwai static void init_multi_io(struct hda_codec *codec)
3693352f7f91STakashi Iwai {
3694352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3695352f7f91STakashi Iwai 	int i;
3696352f7f91STakashi Iwai 
3697352f7f91STakashi Iwai 	for (i = 0; i < spec->multi_ios; i++) {
3698352f7f91STakashi Iwai 		hda_nid_t pin = spec->multi_io[i].pin;
3699352f7f91STakashi Iwai 		struct nid_path *path;
3700196c1766STakashi Iwai 		path = get_multiio_path(codec, i);
3701352f7f91STakashi Iwai 		if (!path)
3702352f7f91STakashi Iwai 			continue;
3703352f7f91STakashi Iwai 		if (!spec->multi_io[i].ctl_in)
3704352f7f91STakashi Iwai 			spec->multi_io[i].ctl_in =
3705352f7f91STakashi Iwai 				snd_hda_codec_update_cache(codec, pin, 0,
3706352f7f91STakashi Iwai 					   AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3707352f7f91STakashi Iwai 		snd_hda_activate_path(codec, path, path->active, true);
3708352f7f91STakashi Iwai 	}
3709352f7f91STakashi Iwai }
3710352f7f91STakashi Iwai 
3711352f7f91STakashi Iwai /* set up the input pin config, depending on the given auto-pin type */
3712352f7f91STakashi Iwai static void set_input_pin(struct hda_codec *codec, hda_nid_t nid,
3713352f7f91STakashi Iwai 			  int auto_pin_type)
3714352f7f91STakashi Iwai {
3715352f7f91STakashi Iwai 	unsigned int val = PIN_IN;
3716352f7f91STakashi Iwai 	if (auto_pin_type == AUTO_PIN_MIC)
3717352f7f91STakashi Iwai 		val |= snd_hda_get_default_vref(codec, nid);
37187594aa33STakashi Iwai 	snd_hda_set_pin_ctl_cache(codec, nid, val);
3719352f7f91STakashi Iwai }
3720352f7f91STakashi Iwai 
3721352f7f91STakashi Iwai /* set up input pins and loopback paths */
3722352f7f91STakashi Iwai static void init_analog_input(struct hda_codec *codec)
3723352f7f91STakashi Iwai {
3724352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3725352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
3726352f7f91STakashi Iwai 	int i;
3727352f7f91STakashi Iwai 
3728352f7f91STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
3729352f7f91STakashi Iwai 		hda_nid_t nid = cfg->inputs[i].pin;
3730352f7f91STakashi Iwai 		if (is_input_pin(codec, nid))
3731352f7f91STakashi Iwai 			set_input_pin(codec, nid, cfg->inputs[i].type);
3732352f7f91STakashi Iwai 
3733352f7f91STakashi Iwai 		/* init loopback inputs */
3734352f7f91STakashi Iwai 		if (spec->mixer_nid) {
3735352f7f91STakashi Iwai 			struct nid_path *path;
3736196c1766STakashi Iwai 			path = snd_hda_get_path_from_idx(codec, spec->loopback_paths[i]);
3737352f7f91STakashi Iwai 			if (path)
3738352f7f91STakashi Iwai 				snd_hda_activate_path(codec, path,
3739352f7f91STakashi Iwai 						      path->active, false);
3740352f7f91STakashi Iwai 		}
3741352f7f91STakashi Iwai 	}
3742352f7f91STakashi Iwai }
3743352f7f91STakashi Iwai 
3744352f7f91STakashi Iwai /* initialize ADC paths */
3745352f7f91STakashi Iwai static void init_input_src(struct hda_codec *codec)
3746352f7f91STakashi Iwai {
3747352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3748352f7f91STakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
3749352f7f91STakashi Iwai 	struct nid_path *path;
3750352f7f91STakashi Iwai 	int i, c, nums;
3751352f7f91STakashi Iwai 
3752352f7f91STakashi Iwai 	if (spec->dyn_adc_switch)
3753352f7f91STakashi Iwai 		nums = 1;
3754352f7f91STakashi Iwai 	else
3755352f7f91STakashi Iwai 		nums = spec->num_adc_nids;
3756352f7f91STakashi Iwai 
3757352f7f91STakashi Iwai 	for (c = 0; c < nums; c++) {
3758352f7f91STakashi Iwai 		for (i = 0; i < imux->num_items; i++) {
3759352f7f91STakashi Iwai 			path = snd_hda_get_nid_path(codec, spec->imux_pins[i],
3760352f7f91STakashi Iwai 						    get_adc_nid(codec, c, i));
3761352f7f91STakashi Iwai 			if (path) {
3762352f7f91STakashi Iwai 				bool active = path->active;
3763352f7f91STakashi Iwai 				if (i == spec->cur_mux[c])
3764352f7f91STakashi Iwai 					active = true;
3765352f7f91STakashi Iwai 				snd_hda_activate_path(codec, path, active, false);
3766352f7f91STakashi Iwai 			}
3767352f7f91STakashi Iwai 		}
3768352f7f91STakashi Iwai 	}
3769352f7f91STakashi Iwai 
3770352f7f91STakashi Iwai 	if (spec->shared_mic_hp)
3771352f7f91STakashi Iwai 		update_shared_mic_hp(codec, spec->cur_mux[0]);
3772352f7f91STakashi Iwai 
3773352f7f91STakashi Iwai 	if (spec->cap_sync_hook)
3774352f7f91STakashi Iwai 		spec->cap_sync_hook(codec);
3775352f7f91STakashi Iwai }
3776352f7f91STakashi Iwai 
3777352f7f91STakashi Iwai /* set right pin controls for digital I/O */
3778352f7f91STakashi Iwai static void init_digital(struct hda_codec *codec)
3779352f7f91STakashi Iwai {
3780352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3781352f7f91STakashi Iwai 	int i;
3782352f7f91STakashi Iwai 	hda_nid_t pin;
3783352f7f91STakashi Iwai 
3784352f7f91STakashi Iwai 	for (i = 0; i < spec->autocfg.dig_outs; i++) {
3785352f7f91STakashi Iwai 		pin = spec->autocfg.dig_out_pins[i];
3786352f7f91STakashi Iwai 		if (!pin)
3787352f7f91STakashi Iwai 			continue;
3788196c1766STakashi Iwai 		set_output_and_unmute(codec, pin, PIN_OUT,
3789196c1766STakashi Iwai 				      spec->digout_paths[i]);
3790352f7f91STakashi Iwai 	}
3791352f7f91STakashi Iwai 	pin = spec->autocfg.dig_in_pin;
37922430d7b7STakashi Iwai 	if (pin) {
37932430d7b7STakashi Iwai 		struct nid_path *path;
37947594aa33STakashi Iwai 		snd_hda_set_pin_ctl_cache(codec, pin, PIN_IN);
37952430d7b7STakashi Iwai 		path = snd_hda_get_path_from_idx(codec, spec->digin_path);
37962430d7b7STakashi Iwai 		if (path)
37972430d7b7STakashi Iwai 			snd_hda_activate_path(codec, path, path->active, false);
37982430d7b7STakashi Iwai 	}
3799352f7f91STakashi Iwai }
3800352f7f91STakashi Iwai 
3801973e4972STakashi Iwai /* clear unsol-event tags on unused pins; Conexant codecs seem to leave
3802973e4972STakashi Iwai  * invalid unsol tags by some reason
3803973e4972STakashi Iwai  */
3804973e4972STakashi Iwai static void clear_unsol_on_unused_pins(struct hda_codec *codec)
3805973e4972STakashi Iwai {
3806973e4972STakashi Iwai 	int i;
3807973e4972STakashi Iwai 
3808973e4972STakashi Iwai 	for (i = 0; i < codec->init_pins.used; i++) {
3809973e4972STakashi Iwai 		struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
3810973e4972STakashi Iwai 		hda_nid_t nid = pin->nid;
3811973e4972STakashi Iwai 		if (is_jack_detectable(codec, nid) &&
3812973e4972STakashi Iwai 		    !snd_hda_jack_tbl_get(codec, nid))
3813973e4972STakashi Iwai 			snd_hda_codec_update_cache(codec, nid, 0,
3814973e4972STakashi Iwai 					AC_VERB_SET_UNSOLICITED_ENABLE, 0);
3815973e4972STakashi Iwai 	}
3816973e4972STakashi Iwai }
3817973e4972STakashi Iwai 
3818352f7f91STakashi Iwai int snd_hda_gen_init(struct hda_codec *codec)
3819352f7f91STakashi Iwai {
3820352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3821352f7f91STakashi Iwai 
3822352f7f91STakashi Iwai 	if (spec->init_hook)
3823352f7f91STakashi Iwai 		spec->init_hook(codec);
3824352f7f91STakashi Iwai 
3825352f7f91STakashi Iwai 	snd_hda_apply_verbs(codec);
3826352f7f91STakashi Iwai 
38273bbcd274STakashi Iwai 	codec->cached_write = 1;
38283bbcd274STakashi Iwai 
3829352f7f91STakashi Iwai 	init_multi_out(codec);
3830352f7f91STakashi Iwai 	init_extra_out(codec);
3831352f7f91STakashi Iwai 	init_multi_io(codec);
3832352f7f91STakashi Iwai 	init_analog_input(codec);
3833352f7f91STakashi Iwai 	init_input_src(codec);
3834352f7f91STakashi Iwai 	init_digital(codec);
3835352f7f91STakashi Iwai 
3836973e4972STakashi Iwai 	clear_unsol_on_unused_pins(codec);
3837973e4972STakashi Iwai 
3838352f7f91STakashi Iwai 	/* call init functions of standard auto-mute helpers */
38395d550e15STakashi Iwai 	snd_hda_gen_hp_automute(codec, NULL);
38405d550e15STakashi Iwai 	snd_hda_gen_line_automute(codec, NULL);
38415d550e15STakashi Iwai 	snd_hda_gen_mic_autoswitch(codec, NULL);
3842352f7f91STakashi Iwai 
38433bbcd274STakashi Iwai 	snd_hda_codec_flush_amp_cache(codec);
38443bbcd274STakashi Iwai 	snd_hda_codec_flush_cmd_cache(codec);
38453bbcd274STakashi Iwai 
3846352f7f91STakashi Iwai 	if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook)
3847352f7f91STakashi Iwai 		snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
3848352f7f91STakashi Iwai 
3849352f7f91STakashi Iwai 	hda_call_check_power_status(codec, 0x01);
3850352f7f91STakashi Iwai 	return 0;
3851352f7f91STakashi Iwai }
3852352f7f91STakashi Iwai EXPORT_SYMBOL(snd_hda_gen_init);
3853352f7f91STakashi Iwai 
3854352f7f91STakashi Iwai 
3855352f7f91STakashi Iwai /*
3856352f7f91STakashi Iwai  * the generic codec support
3857352f7f91STakashi Iwai  */
38581da177e4SLinus Torvalds 
385983012a7cSTakashi Iwai #ifdef CONFIG_PM
3860cb53c626STakashi Iwai static int generic_check_power_status(struct hda_codec *codec, hda_nid_t nid)
3861cb53c626STakashi Iwai {
3862352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3863cb53c626STakashi Iwai 	return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
3864cb53c626STakashi Iwai }
3865cb53c626STakashi Iwai #endif
3866cb53c626STakashi Iwai 
3867352f7f91STakashi Iwai static void generic_free(struct hda_codec *codec)
3868352f7f91STakashi Iwai {
3869352f7f91STakashi Iwai 	snd_hda_gen_spec_free(codec->spec);
3870352f7f91STakashi Iwai 	kfree(codec->spec);
3871352f7f91STakashi Iwai 	codec->spec = NULL;
3872352f7f91STakashi Iwai }
38731da177e4SLinus Torvalds 
3874352f7f91STakashi Iwai static const struct hda_codec_ops generic_patch_ops = {
3875352f7f91STakashi Iwai 	.build_controls = snd_hda_gen_build_controls,
3876352f7f91STakashi Iwai 	.build_pcms = snd_hda_gen_build_pcms,
3877352f7f91STakashi Iwai 	.init = snd_hda_gen_init,
3878352f7f91STakashi Iwai 	.free = generic_free,
3879352f7f91STakashi Iwai 	.unsol_event = snd_hda_jack_unsol_event,
388083012a7cSTakashi Iwai #ifdef CONFIG_PM
3881cb53c626STakashi Iwai 	.check_power_status = generic_check_power_status,
3882cb53c626STakashi Iwai #endif
38831da177e4SLinus Torvalds };
38841da177e4SLinus Torvalds 
38851da177e4SLinus Torvalds int snd_hda_parse_generic_codec(struct hda_codec *codec)
38861da177e4SLinus Torvalds {
3887352f7f91STakashi Iwai 	struct hda_gen_spec *spec;
38881da177e4SLinus Torvalds 	int err;
38891da177e4SLinus Torvalds 
3890e560d8d8STakashi Iwai 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3891352f7f91STakashi Iwai 	if (!spec)
38921da177e4SLinus Torvalds 		return -ENOMEM;
3893352f7f91STakashi Iwai 	snd_hda_gen_spec_init(spec);
38941da177e4SLinus Torvalds 	codec->spec = spec;
38951da177e4SLinus Torvalds 
38969eb413e5STakashi Iwai 	err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0);
38979eb413e5STakashi Iwai 	if (err < 0)
38989eb413e5STakashi Iwai 		return err;
38999eb413e5STakashi Iwai 
39009eb413e5STakashi Iwai 	err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg);
3901352f7f91STakashi Iwai 	if (err < 0)
39021da177e4SLinus Torvalds 		goto error;
39031da177e4SLinus Torvalds 
39041da177e4SLinus Torvalds 	codec->patch_ops = generic_patch_ops;
39051da177e4SLinus Torvalds 	return 0;
39061da177e4SLinus Torvalds 
39071da177e4SLinus Torvalds error:
3908352f7f91STakashi Iwai 	generic_free(codec);
39091da177e4SLinus Torvalds 	return err;
39101da177e4SLinus Torvalds }
39111289e9e8STakashi Iwai EXPORT_SYMBOL(snd_hda_parse_generic_codec);
3912