xref: /openbmc/linux/sound/pci/hda/hda_generic.c (revision a365fed9)
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->paths, sizeof(struct nid_path), 8);
4338cf6f1aSTakashi Iwai 	mutex_init(&spec->pcm_mutex);
44352f7f91STakashi Iwai 	return 0;
45352f7f91STakashi Iwai }
46352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_spec_init);
471da177e4SLinus Torvalds 
4812c93df6STakashi Iwai struct snd_kcontrol_new *
4912c93df6STakashi Iwai snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
50352f7f91STakashi Iwai 		     const struct snd_kcontrol_new *temp)
51352f7f91STakashi Iwai {
52352f7f91STakashi Iwai 	struct snd_kcontrol_new *knew = snd_array_new(&spec->kctls);
53352f7f91STakashi Iwai 	if (!knew)
54352f7f91STakashi Iwai 		return NULL;
55352f7f91STakashi Iwai 	*knew = *temp;
56352f7f91STakashi Iwai 	if (name)
57352f7f91STakashi Iwai 		knew->name = kstrdup(name, GFP_KERNEL);
58352f7f91STakashi Iwai 	else if (knew->name)
59352f7f91STakashi Iwai 		knew->name = kstrdup(knew->name, GFP_KERNEL);
60352f7f91STakashi Iwai 	if (!knew->name)
61352f7f91STakashi Iwai 		return NULL;
62352f7f91STakashi Iwai 	return knew;
63352f7f91STakashi Iwai }
6412c93df6STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_add_kctl);
65352f7f91STakashi Iwai 
66352f7f91STakashi Iwai static void free_kctls(struct hda_gen_spec *spec)
67352f7f91STakashi Iwai {
68352f7f91STakashi Iwai 	if (spec->kctls.list) {
69352f7f91STakashi Iwai 		struct snd_kcontrol_new *kctl = spec->kctls.list;
70352f7f91STakashi Iwai 		int i;
71352f7f91STakashi Iwai 		for (i = 0; i < spec->kctls.used; i++)
72352f7f91STakashi Iwai 			kfree(kctl[i].name);
73352f7f91STakashi Iwai 	}
74352f7f91STakashi Iwai 	snd_array_free(&spec->kctls);
75352f7f91STakashi Iwai }
76352f7f91STakashi Iwai 
77352f7f91STakashi Iwai void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
78352f7f91STakashi Iwai {
791da177e4SLinus Torvalds 	if (!spec)
801da177e4SLinus Torvalds 		return;
81352f7f91STakashi Iwai 	free_kctls(spec);
82352f7f91STakashi Iwai 	snd_array_free(&spec->paths);
831da177e4SLinus Torvalds }
84352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_spec_free);
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds /*
872c12c30dSTakashi Iwai  * pin control value accesses
882c12c30dSTakashi Iwai  */
892c12c30dSTakashi Iwai 
902c12c30dSTakashi Iwai #define update_pin_ctl(codec, pin, val) \
912c12c30dSTakashi Iwai 	snd_hda_codec_update_cache(codec, pin, 0, \
922c12c30dSTakashi Iwai 				   AC_VERB_SET_PIN_WIDGET_CONTROL, val)
932c12c30dSTakashi Iwai 
942c12c30dSTakashi Iwai /* restore the pinctl based on the cached value */
952c12c30dSTakashi Iwai static inline void restore_pin_ctl(struct hda_codec *codec, hda_nid_t pin)
962c12c30dSTakashi Iwai {
972c12c30dSTakashi Iwai 	update_pin_ctl(codec, pin, snd_hda_codec_get_pin_target(codec, pin));
982c12c30dSTakashi Iwai }
992c12c30dSTakashi Iwai 
1002c12c30dSTakashi Iwai /* set the pinctl target value and write it if requested */
1012c12c30dSTakashi Iwai static void set_pin_target(struct hda_codec *codec, hda_nid_t pin,
1022c12c30dSTakashi Iwai 			   unsigned int val, bool do_write)
1032c12c30dSTakashi Iwai {
1042c12c30dSTakashi Iwai 	if (!pin)
1052c12c30dSTakashi Iwai 		return;
1062c12c30dSTakashi Iwai 	val = snd_hda_correct_pin_ctl(codec, pin, val);
1072c12c30dSTakashi Iwai 	snd_hda_codec_set_pin_target(codec, pin, val);
1082c12c30dSTakashi Iwai 	if (do_write)
1092c12c30dSTakashi Iwai 		update_pin_ctl(codec, pin, val);
1102c12c30dSTakashi Iwai }
1112c12c30dSTakashi Iwai 
1122c12c30dSTakashi Iwai /* set pinctl target values for all given pins */
1132c12c30dSTakashi Iwai static void set_pin_targets(struct hda_codec *codec, int num_pins,
1142c12c30dSTakashi Iwai 			    hda_nid_t *pins, unsigned int val)
1152c12c30dSTakashi Iwai {
1162c12c30dSTakashi Iwai 	int i;
1172c12c30dSTakashi Iwai 	for (i = 0; i < num_pins; i++)
1182c12c30dSTakashi Iwai 		set_pin_target(codec, pins[i], val, false);
1192c12c30dSTakashi Iwai }
1202c12c30dSTakashi Iwai 
1212c12c30dSTakashi Iwai /*
122352f7f91STakashi Iwai  * parsing paths
1231da177e4SLinus Torvalds  */
1241da177e4SLinus Torvalds 
1253ca529d3STakashi Iwai /* return the position of NID in the list, or -1 if not found */
1263ca529d3STakashi Iwai static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
1273ca529d3STakashi Iwai {
1283ca529d3STakashi Iwai 	int i;
1293ca529d3STakashi Iwai 	for (i = 0; i < nums; i++)
1303ca529d3STakashi Iwai 		if (list[i] == nid)
1313ca529d3STakashi Iwai 			return i;
1323ca529d3STakashi Iwai 	return -1;
1333ca529d3STakashi Iwai }
1343ca529d3STakashi Iwai 
1353ca529d3STakashi Iwai /* return true if the given NID is contained in the path */
1363ca529d3STakashi Iwai static bool is_nid_contained(struct nid_path *path, hda_nid_t nid)
1373ca529d3STakashi Iwai {
1383ca529d3STakashi Iwai 	return find_idx_in_nid_list(nid, path->path, path->depth) >= 0;
1393ca529d3STakashi Iwai }
1403ca529d3STakashi Iwai 
141f5172a7eSTakashi Iwai static struct nid_path *get_nid_path(struct hda_codec *codec,
142f5172a7eSTakashi Iwai 				     hda_nid_t from_nid, hda_nid_t to_nid,
1433ca529d3STakashi Iwai 				     int anchor_nid)
1441da177e4SLinus Torvalds {
145352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
146352f7f91STakashi Iwai 	int i;
1471da177e4SLinus Torvalds 
148352f7f91STakashi Iwai 	for (i = 0; i < spec->paths.used; i++) {
149352f7f91STakashi Iwai 		struct nid_path *path = snd_array_elem(&spec->paths, i);
150352f7f91STakashi Iwai 		if (path->depth <= 0)
151352f7f91STakashi Iwai 			continue;
152352f7f91STakashi Iwai 		if ((!from_nid || path->path[0] == from_nid) &&
153f5172a7eSTakashi Iwai 		    (!to_nid || path->path[path->depth - 1] == to_nid)) {
1543ca529d3STakashi Iwai 			if (!anchor_nid ||
1553ca529d3STakashi Iwai 			    (anchor_nid > 0 && is_nid_contained(path, anchor_nid)) ||
1563ca529d3STakashi Iwai 			    (anchor_nid < 0 && !is_nid_contained(path, anchor_nid)))
157352f7f91STakashi Iwai 				return path;
1581da177e4SLinus Torvalds 		}
159f5172a7eSTakashi Iwai 	}
1601da177e4SLinus Torvalds 	return NULL;
1611da177e4SLinus Torvalds }
162f5172a7eSTakashi Iwai 
163f5172a7eSTakashi Iwai /* get the path between the given NIDs;
164f5172a7eSTakashi Iwai  * passing 0 to either @pin or @dac behaves as a wildcard
165f5172a7eSTakashi Iwai  */
166f5172a7eSTakashi Iwai struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
167f5172a7eSTakashi Iwai 				      hda_nid_t from_nid, hda_nid_t to_nid)
168f5172a7eSTakashi Iwai {
1693ca529d3STakashi Iwai 	return get_nid_path(codec, from_nid, to_nid, 0);
170f5172a7eSTakashi Iwai }
171352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_nid_path);
1721da177e4SLinus Torvalds 
173196c1766STakashi Iwai /* get the index number corresponding to the path instance;
174196c1766STakashi Iwai  * the index starts from 1, for easier checking the invalid value
175196c1766STakashi Iwai  */
176196c1766STakashi Iwai int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path)
177196c1766STakashi Iwai {
178196c1766STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
179196c1766STakashi Iwai 	struct nid_path *array = spec->paths.list;
180196c1766STakashi Iwai 	ssize_t idx;
181196c1766STakashi Iwai 
182196c1766STakashi Iwai 	if (!spec->paths.used)
183196c1766STakashi Iwai 		return 0;
184196c1766STakashi Iwai 	idx = path - array;
185196c1766STakashi Iwai 	if (idx < 0 || idx >= spec->paths.used)
186196c1766STakashi Iwai 		return 0;
187196c1766STakashi Iwai 	return idx + 1;
188196c1766STakashi Iwai }
189196c1766STakashi Iwai 
190196c1766STakashi Iwai /* get the path instance corresponding to the given index number */
191196c1766STakashi Iwai struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx)
192196c1766STakashi Iwai {
193196c1766STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
194196c1766STakashi Iwai 
195196c1766STakashi Iwai 	if (idx <= 0 || idx > spec->paths.used)
196196c1766STakashi Iwai 		return NULL;
197196c1766STakashi Iwai 	return snd_array_elem(&spec->paths, idx - 1);
198196c1766STakashi Iwai }
199196c1766STakashi Iwai 
200352f7f91STakashi Iwai /* check whether the given DAC is already found in any existing paths */
201352f7f91STakashi Iwai static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
2021da177e4SLinus Torvalds {
203352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
204352f7f91STakashi Iwai 	int i;
205352f7f91STakashi Iwai 
206352f7f91STakashi Iwai 	for (i = 0; i < spec->paths.used; i++) {
207352f7f91STakashi Iwai 		struct nid_path *path = snd_array_elem(&spec->paths, i);
208352f7f91STakashi Iwai 		if (path->path[0] == nid)
209352f7f91STakashi Iwai 			return true;
210352f7f91STakashi Iwai 	}
211352f7f91STakashi Iwai 	return false;
2121da177e4SLinus Torvalds }
2131da177e4SLinus Torvalds 
214352f7f91STakashi Iwai /* check whether the given two widgets can be connected */
215352f7f91STakashi Iwai static bool is_reachable_path(struct hda_codec *codec,
216352f7f91STakashi Iwai 			      hda_nid_t from_nid, hda_nid_t to_nid)
2171da177e4SLinus Torvalds {
218352f7f91STakashi Iwai 	if (!from_nid || !to_nid)
219352f7f91STakashi Iwai 		return false;
220352f7f91STakashi Iwai 	return snd_hda_get_conn_index(codec, to_nid, from_nid, true) >= 0;
2211da177e4SLinus Torvalds }
2221da177e4SLinus Torvalds 
223352f7f91STakashi Iwai /* nid, dir and idx */
224352f7f91STakashi Iwai #define AMP_VAL_COMPARE_MASK	(0xffff | (1U << 18) | (0x0f << 19))
225352f7f91STakashi Iwai 
226352f7f91STakashi Iwai /* check whether the given ctl is already assigned in any path elements */
227352f7f91STakashi Iwai static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type)
2281da177e4SLinus Torvalds {
229352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
230352f7f91STakashi Iwai 	int i;
231352f7f91STakashi Iwai 
232352f7f91STakashi Iwai 	val &= AMP_VAL_COMPARE_MASK;
233352f7f91STakashi Iwai 	for (i = 0; i < spec->paths.used; i++) {
234352f7f91STakashi Iwai 		struct nid_path *path = snd_array_elem(&spec->paths, i);
235352f7f91STakashi Iwai 		if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val)
236352f7f91STakashi Iwai 			return true;
237352f7f91STakashi Iwai 	}
238352f7f91STakashi Iwai 	return false;
2391da177e4SLinus Torvalds }
2401da177e4SLinus Torvalds 
241352f7f91STakashi Iwai /* check whether a control with the given (nid, dir, idx) was assigned */
242352f7f91STakashi Iwai static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid,
243cb53c626STakashi Iwai 			      int dir, int idx)
244cb53c626STakashi Iwai {
245352f7f91STakashi Iwai 	unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
246352f7f91STakashi Iwai 	return is_ctl_used(codec, val, NID_PATH_VOL_CTL) ||
247352f7f91STakashi Iwai 		is_ctl_used(codec, val, NID_PATH_MUTE_CTL);
248cb53c626STakashi Iwai }
249352f7f91STakashi Iwai 
2500c8c0f56STakashi Iwai static void print_nid_path(const char *pfx, struct nid_path *path)
2510c8c0f56STakashi Iwai {
2520c8c0f56STakashi Iwai 	char buf[40];
2530c8c0f56STakashi Iwai 	int i;
2540c8c0f56STakashi Iwai 
2550c8c0f56STakashi Iwai 
2560c8c0f56STakashi Iwai 	buf[0] = 0;
2570c8c0f56STakashi Iwai 	for (i = 0; i < path->depth; i++) {
2580c8c0f56STakashi Iwai 		char tmp[4];
2590c8c0f56STakashi Iwai 		sprintf(tmp, ":%02x", path->path[i]);
2600c8c0f56STakashi Iwai 		strlcat(buf, tmp, sizeof(buf));
2610c8c0f56STakashi Iwai 	}
2620c8c0f56STakashi Iwai 	snd_printdd("%s path: depth=%d %s\n", pfx, path->depth, buf);
2630c8c0f56STakashi Iwai }
2640c8c0f56STakashi Iwai 
265352f7f91STakashi Iwai /* called recursively */
266352f7f91STakashi Iwai static bool __parse_nid_path(struct hda_codec *codec,
267352f7f91STakashi Iwai 			     hda_nid_t from_nid, hda_nid_t to_nid,
2683ca529d3STakashi Iwai 			     int anchor_nid, struct nid_path *path,
2693ca529d3STakashi Iwai 			     int depth)
270352f7f91STakashi Iwai {
271ee8e765bSTakashi Iwai 	const hda_nid_t *conn;
272352f7f91STakashi Iwai 	int i, nums;
273352f7f91STakashi Iwai 
2743ca529d3STakashi Iwai 	if (to_nid == anchor_nid)
2753ca529d3STakashi Iwai 		anchor_nid = 0; /* anchor passed */
2763ca529d3STakashi Iwai 	else if (to_nid == (hda_nid_t)(-anchor_nid))
2773ca529d3STakashi Iwai 		return false; /* hit the exclusive nid */
278352f7f91STakashi Iwai 
279ee8e765bSTakashi Iwai 	nums = snd_hda_get_conn_list(codec, to_nid, &conn);
280352f7f91STakashi Iwai 	for (i = 0; i < nums; i++) {
281352f7f91STakashi Iwai 		if (conn[i] != from_nid) {
282352f7f91STakashi Iwai 			/* special case: when from_nid is 0,
283352f7f91STakashi Iwai 			 * try to find an empty DAC
284352f7f91STakashi Iwai 			 */
285352f7f91STakashi Iwai 			if (from_nid ||
286352f7f91STakashi Iwai 			    get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT ||
287352f7f91STakashi Iwai 			    is_dac_already_used(codec, conn[i]))
288352f7f91STakashi Iwai 				continue;
289352f7f91STakashi Iwai 		}
2903ca529d3STakashi Iwai 		/* anchor is not requested or already passed? */
2913ca529d3STakashi Iwai 		if (anchor_nid <= 0)
292352f7f91STakashi Iwai 			goto found;
293352f7f91STakashi Iwai 	}
294352f7f91STakashi Iwai 	if (depth >= MAX_NID_PATH_DEPTH)
295352f7f91STakashi Iwai 		return false;
296352f7f91STakashi Iwai 	for (i = 0; i < nums; i++) {
297352f7f91STakashi Iwai 		unsigned int type;
298352f7f91STakashi Iwai 		type = get_wcaps_type(get_wcaps(codec, conn[i]));
299352f7f91STakashi Iwai 		if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN ||
300352f7f91STakashi Iwai 		    type == AC_WID_PIN)
301352f7f91STakashi Iwai 			continue;
302352f7f91STakashi Iwai 		if (__parse_nid_path(codec, from_nid, conn[i],
3033ca529d3STakashi Iwai 				     anchor_nid, path, depth + 1))
304352f7f91STakashi Iwai 			goto found;
305352f7f91STakashi Iwai 	}
306352f7f91STakashi Iwai 	return false;
307352f7f91STakashi Iwai 
308352f7f91STakashi Iwai  found:
309352f7f91STakashi Iwai 	path->path[path->depth] = conn[i];
310352f7f91STakashi Iwai 	path->idx[path->depth + 1] = i;
311352f7f91STakashi Iwai 	if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX)
312352f7f91STakashi Iwai 		path->multi[path->depth + 1] = 1;
313352f7f91STakashi Iwai 	path->depth++;
314352f7f91STakashi Iwai 	return true;
315352f7f91STakashi Iwai }
316352f7f91STakashi Iwai 
317352f7f91STakashi Iwai /* parse the widget path from the given nid to the target nid;
318352f7f91STakashi Iwai  * when @from_nid is 0, try to find an empty DAC;
3193ca529d3STakashi Iwai  * when @anchor_nid is set to a positive value, only paths through the widget
3203ca529d3STakashi Iwai  * with the given value are evaluated.
3213ca529d3STakashi Iwai  * when @anchor_nid is set to a negative value, paths through the widget
3223ca529d3STakashi Iwai  * with the negative of given value are excluded, only other paths are chosen.
3233ca529d3STakashi Iwai  * when @anchor_nid is zero, no special handling about path selection.
324352f7f91STakashi Iwai  */
325352f7f91STakashi Iwai bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
3263ca529d3STakashi Iwai 			    hda_nid_t to_nid, int anchor_nid,
327352f7f91STakashi Iwai 			    struct nid_path *path)
328352f7f91STakashi Iwai {
3293ca529d3STakashi Iwai 	if (__parse_nid_path(codec, from_nid, to_nid, anchor_nid, path, 1)) {
330352f7f91STakashi Iwai 		path->path[path->depth] = to_nid;
331352f7f91STakashi Iwai 		path->depth++;
332352f7f91STakashi Iwai 		return true;
333352f7f91STakashi Iwai 	}
334352f7f91STakashi Iwai 	return false;
335352f7f91STakashi Iwai }
336352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_parse_nid_path);
337352f7f91STakashi Iwai 
338352f7f91STakashi Iwai /*
339352f7f91STakashi Iwai  * parse the path between the given NIDs and add to the path list.
340352f7f91STakashi Iwai  * if no valid path is found, return NULL
341352f7f91STakashi Iwai  */
342352f7f91STakashi Iwai struct nid_path *
343352f7f91STakashi Iwai snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
3443ca529d3STakashi Iwai 		     hda_nid_t to_nid, int anchor_nid)
345352f7f91STakashi Iwai {
346352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
347352f7f91STakashi Iwai 	struct nid_path *path;
348352f7f91STakashi Iwai 
349352f7f91STakashi Iwai 	if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid))
350352f7f91STakashi Iwai 		return NULL;
351352f7f91STakashi Iwai 
352f5172a7eSTakashi Iwai 	/* check whether the path has been already added */
3533ca529d3STakashi Iwai 	path = get_nid_path(codec, from_nid, to_nid, anchor_nid);
354f5172a7eSTakashi Iwai 	if (path)
355f5172a7eSTakashi Iwai 		return path;
356f5172a7eSTakashi Iwai 
357352f7f91STakashi Iwai 	path = snd_array_new(&spec->paths);
358352f7f91STakashi Iwai 	if (!path)
359352f7f91STakashi Iwai 		return NULL;
360352f7f91STakashi Iwai 	memset(path, 0, sizeof(*path));
3613ca529d3STakashi Iwai 	if (snd_hda_parse_nid_path(codec, from_nid, to_nid, anchor_nid, path))
362352f7f91STakashi Iwai 		return path;
363352f7f91STakashi Iwai 	/* push back */
364352f7f91STakashi Iwai 	spec->paths.used--;
365352f7f91STakashi Iwai 	return NULL;
366352f7f91STakashi Iwai }
367352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_add_new_path);
368352f7f91STakashi Iwai 
369980428ceSTakashi Iwai /* clear the given path as invalid so that it won't be picked up later */
370980428ceSTakashi Iwai static void invalidate_nid_path(struct hda_codec *codec, int idx)
371980428ceSTakashi Iwai {
372980428ceSTakashi Iwai 	struct nid_path *path = snd_hda_get_path_from_idx(codec, idx);
373980428ceSTakashi Iwai 	if (!path)
374980428ceSTakashi Iwai 		return;
375980428ceSTakashi Iwai 	memset(path, 0, sizeof(*path));
376980428ceSTakashi Iwai }
377980428ceSTakashi Iwai 
378352f7f91STakashi Iwai /* look for an empty DAC slot */
379352f7f91STakashi Iwai static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin,
380352f7f91STakashi Iwai 			      bool is_digital)
381352f7f91STakashi Iwai {
382352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
383352f7f91STakashi Iwai 	bool cap_digital;
384352f7f91STakashi Iwai 	int i;
385352f7f91STakashi Iwai 
386352f7f91STakashi Iwai 	for (i = 0; i < spec->num_all_dacs; i++) {
387352f7f91STakashi Iwai 		hda_nid_t nid = spec->all_dacs[i];
388352f7f91STakashi Iwai 		if (!nid || is_dac_already_used(codec, nid))
389352f7f91STakashi Iwai 			continue;
390352f7f91STakashi Iwai 		cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL);
391352f7f91STakashi Iwai 		if (is_digital != cap_digital)
392352f7f91STakashi Iwai 			continue;
393352f7f91STakashi Iwai 		if (is_reachable_path(codec, nid, pin))
394352f7f91STakashi Iwai 			return nid;
395352f7f91STakashi Iwai 	}
396352f7f91STakashi Iwai 	return 0;
397352f7f91STakashi Iwai }
398352f7f91STakashi Iwai 
399352f7f91STakashi Iwai /* replace the channels in the composed amp value with the given number */
400352f7f91STakashi Iwai static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs)
401352f7f91STakashi Iwai {
402352f7f91STakashi Iwai 	val &= ~(0x3U << 16);
403352f7f91STakashi Iwai 	val |= chs << 16;
404352f7f91STakashi Iwai 	return val;
405352f7f91STakashi Iwai }
406352f7f91STakashi Iwai 
407352f7f91STakashi Iwai /* check whether the widget has the given amp capability for the direction */
408352f7f91STakashi Iwai static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
409352f7f91STakashi Iwai 			   int dir, unsigned int bits)
410352f7f91STakashi Iwai {
411352f7f91STakashi Iwai 	if (!nid)
412352f7f91STakashi Iwai 		return false;
413352f7f91STakashi Iwai 	if (get_wcaps(codec, nid) & (1 << (dir + 1)))
414352f7f91STakashi Iwai 		if (query_amp_caps(codec, nid, dir) & bits)
415352f7f91STakashi Iwai 			return true;
416352f7f91STakashi Iwai 	return false;
417352f7f91STakashi Iwai }
418352f7f91STakashi Iwai 
419352f7f91STakashi Iwai #define nid_has_mute(codec, nid, dir) \
420352f7f91STakashi Iwai 	check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE)
421352f7f91STakashi Iwai #define nid_has_volume(codec, nid, dir) \
422352f7f91STakashi Iwai 	check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS)
423352f7f91STakashi Iwai 
424352f7f91STakashi Iwai /* look for a widget suitable for assigning a mute switch in the path */
425352f7f91STakashi Iwai static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec,
426352f7f91STakashi Iwai 				       struct nid_path *path)
427352f7f91STakashi Iwai {
428352f7f91STakashi Iwai 	int i;
429352f7f91STakashi Iwai 
430352f7f91STakashi Iwai 	for (i = path->depth - 1; i >= 0; i--) {
431352f7f91STakashi Iwai 		if (nid_has_mute(codec, path->path[i], HDA_OUTPUT))
432352f7f91STakashi Iwai 			return path->path[i];
433352f7f91STakashi Iwai 		if (i != path->depth - 1 && i != 0 &&
434352f7f91STakashi Iwai 		    nid_has_mute(codec, path->path[i], HDA_INPUT))
435352f7f91STakashi Iwai 			return path->path[i];
436352f7f91STakashi Iwai 	}
437352f7f91STakashi Iwai 	return 0;
438352f7f91STakashi Iwai }
439352f7f91STakashi Iwai 
440352f7f91STakashi Iwai /* look for a widget suitable for assigning a volume ctl in the path */
441352f7f91STakashi Iwai static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec,
442352f7f91STakashi Iwai 				      struct nid_path *path)
443352f7f91STakashi Iwai {
444352f7f91STakashi Iwai 	int i;
445352f7f91STakashi Iwai 
446352f7f91STakashi Iwai 	for (i = path->depth - 1; i >= 0; i--) {
447352f7f91STakashi Iwai 		if (nid_has_volume(codec, path->path[i], HDA_OUTPUT))
448352f7f91STakashi Iwai 			return path->path[i];
449352f7f91STakashi Iwai 	}
450352f7f91STakashi Iwai 	return 0;
451352f7f91STakashi Iwai }
452352f7f91STakashi Iwai 
453352f7f91STakashi Iwai /*
454352f7f91STakashi Iwai  * path activation / deactivation
455352f7f91STakashi Iwai  */
456352f7f91STakashi Iwai 
457352f7f91STakashi Iwai /* can have the amp-in capability? */
458352f7f91STakashi Iwai static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx)
459352f7f91STakashi Iwai {
460352f7f91STakashi Iwai 	hda_nid_t nid = path->path[idx];
461352f7f91STakashi Iwai 	unsigned int caps = get_wcaps(codec, nid);
462352f7f91STakashi Iwai 	unsigned int type = get_wcaps_type(caps);
463352f7f91STakashi Iwai 
464352f7f91STakashi Iwai 	if (!(caps & AC_WCAP_IN_AMP))
465352f7f91STakashi Iwai 		return false;
466352f7f91STakashi Iwai 	if (type == AC_WID_PIN && idx > 0) /* only for input pins */
467352f7f91STakashi Iwai 		return false;
468352f7f91STakashi Iwai 	return true;
469352f7f91STakashi Iwai }
470352f7f91STakashi Iwai 
471352f7f91STakashi Iwai /* can have the amp-out capability? */
472352f7f91STakashi Iwai static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx)
473352f7f91STakashi Iwai {
474352f7f91STakashi Iwai 	hda_nid_t nid = path->path[idx];
475352f7f91STakashi Iwai 	unsigned int caps = get_wcaps(codec, nid);
476352f7f91STakashi Iwai 	unsigned int type = get_wcaps_type(caps);
477352f7f91STakashi Iwai 
478352f7f91STakashi Iwai 	if (!(caps & AC_WCAP_OUT_AMP))
479352f7f91STakashi Iwai 		return false;
480352f7f91STakashi Iwai 	if (type == AC_WID_PIN && !idx) /* only for output pins */
481352f7f91STakashi Iwai 		return false;
482352f7f91STakashi Iwai 	return true;
483352f7f91STakashi Iwai }
484352f7f91STakashi Iwai 
485352f7f91STakashi Iwai /* check whether the given (nid,dir,idx) is active */
486352f7f91STakashi Iwai static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid,
487352f7f91STakashi Iwai 			  unsigned int idx, unsigned int dir)
488352f7f91STakashi Iwai {
489352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
490352f7f91STakashi Iwai 	int i, n;
491352f7f91STakashi Iwai 
492352f7f91STakashi Iwai 	for (n = 0; n < spec->paths.used; n++) {
493352f7f91STakashi Iwai 		struct nid_path *path = snd_array_elem(&spec->paths, n);
494352f7f91STakashi Iwai 		if (!path->active)
495352f7f91STakashi Iwai 			continue;
496352f7f91STakashi Iwai 		for (i = 0; i < path->depth; i++) {
497352f7f91STakashi Iwai 			if (path->path[i] == nid) {
498352f7f91STakashi Iwai 				if (dir == HDA_OUTPUT || path->idx[i] == idx)
499352f7f91STakashi Iwai 					return true;
500352f7f91STakashi Iwai 				break;
501352f7f91STakashi Iwai 			}
502352f7f91STakashi Iwai 		}
503352f7f91STakashi Iwai 	}
504352f7f91STakashi Iwai 	return false;
505352f7f91STakashi Iwai }
506352f7f91STakashi Iwai 
507352f7f91STakashi Iwai /* get the default amp value for the target state */
508352f7f91STakashi Iwai static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid,
509352f7f91STakashi Iwai 				   int dir, bool enable)
510352f7f91STakashi Iwai {
511352f7f91STakashi Iwai 	unsigned int caps;
512352f7f91STakashi Iwai 	unsigned int val = 0;
513352f7f91STakashi Iwai 
514352f7f91STakashi Iwai 	caps = query_amp_caps(codec, nid, dir);
515352f7f91STakashi Iwai 	if (caps & AC_AMPCAP_NUM_STEPS) {
516352f7f91STakashi Iwai 		/* set to 0dB */
517352f7f91STakashi Iwai 		if (enable)
518352f7f91STakashi Iwai 			val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
519352f7f91STakashi Iwai 	}
520352f7f91STakashi Iwai 	if (caps & AC_AMPCAP_MUTE) {
521352f7f91STakashi Iwai 		if (!enable)
522352f7f91STakashi Iwai 			val |= HDA_AMP_MUTE;
523352f7f91STakashi Iwai 	}
524352f7f91STakashi Iwai 	return val;
525352f7f91STakashi Iwai }
526352f7f91STakashi Iwai 
527352f7f91STakashi Iwai /* initialize the amp value (only at the first time) */
528352f7f91STakashi Iwai static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
529352f7f91STakashi Iwai {
530352f7f91STakashi Iwai 	int val = get_amp_val_to_activate(codec, nid, dir, false);
531352f7f91STakashi Iwai 	snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
532352f7f91STakashi Iwai }
533352f7f91STakashi Iwai 
534352f7f91STakashi Iwai static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir,
535352f7f91STakashi Iwai 			 int idx, bool enable)
536352f7f91STakashi Iwai {
537352f7f91STakashi Iwai 	int val;
538352f7f91STakashi Iwai 	if (is_ctl_associated(codec, nid, dir, idx) ||
539985803caSTakashi Iwai 	    (!enable && is_active_nid(codec, nid, dir, idx)))
540352f7f91STakashi Iwai 		return;
541352f7f91STakashi Iwai 	val = get_amp_val_to_activate(codec, nid, dir, enable);
542352f7f91STakashi Iwai 	snd_hda_codec_amp_stereo(codec, nid, dir, idx, 0xff, val);
543352f7f91STakashi Iwai }
544352f7f91STakashi Iwai 
545352f7f91STakashi Iwai static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
546352f7f91STakashi Iwai 			     int i, bool enable)
547352f7f91STakashi Iwai {
548352f7f91STakashi Iwai 	hda_nid_t nid = path->path[i];
549352f7f91STakashi Iwai 	init_amp(codec, nid, HDA_OUTPUT, 0);
550352f7f91STakashi Iwai 	activate_amp(codec, nid, HDA_OUTPUT, 0, enable);
551352f7f91STakashi Iwai }
552352f7f91STakashi Iwai 
553352f7f91STakashi Iwai static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
554352f7f91STakashi Iwai 			    int i, bool enable, bool add_aamix)
555352f7f91STakashi Iwai {
556352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
557ee8e765bSTakashi Iwai 	const hda_nid_t *conn;
558352f7f91STakashi Iwai 	int n, nums, idx;
559352f7f91STakashi Iwai 	int type;
560352f7f91STakashi Iwai 	hda_nid_t nid = path->path[i];
561352f7f91STakashi Iwai 
562ee8e765bSTakashi Iwai 	nums = snd_hda_get_conn_list(codec, nid, &conn);
563352f7f91STakashi Iwai 	type = get_wcaps_type(get_wcaps(codec, nid));
564352f7f91STakashi Iwai 	if (type == AC_WID_PIN ||
565352f7f91STakashi Iwai 	    (type == AC_WID_AUD_IN && codec->single_adc_amp)) {
566352f7f91STakashi Iwai 		nums = 1;
567352f7f91STakashi Iwai 		idx = 0;
568352f7f91STakashi Iwai 	} else
569352f7f91STakashi Iwai 		idx = path->idx[i];
570352f7f91STakashi Iwai 
571352f7f91STakashi Iwai 	for (n = 0; n < nums; n++)
572352f7f91STakashi Iwai 		init_amp(codec, nid, HDA_INPUT, n);
573352f7f91STakashi Iwai 
574352f7f91STakashi Iwai 	if (is_ctl_associated(codec, nid, HDA_INPUT, idx))
575352f7f91STakashi Iwai 		return;
576352f7f91STakashi Iwai 
577352f7f91STakashi Iwai 	/* here is a little bit tricky in comparison with activate_amp_out();
578352f7f91STakashi Iwai 	 * when aa-mixer is available, we need to enable the path as well
579352f7f91STakashi Iwai 	 */
580352f7f91STakashi Iwai 	for (n = 0; n < nums; n++) {
581352f7f91STakashi Iwai 		if (n != idx && (!add_aamix || conn[n] != spec->mixer_nid))
582352f7f91STakashi Iwai 			continue;
583352f7f91STakashi Iwai 		activate_amp(codec, nid, HDA_INPUT, n, enable);
584352f7f91STakashi Iwai 	}
585352f7f91STakashi Iwai }
586352f7f91STakashi Iwai 
587352f7f91STakashi Iwai /* activate or deactivate the given path
588352f7f91STakashi Iwai  * if @add_aamix is set, enable the input from aa-mix NID as well (if any)
589352f7f91STakashi Iwai  */
590352f7f91STakashi Iwai void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
591352f7f91STakashi Iwai 			   bool enable, bool add_aamix)
592352f7f91STakashi Iwai {
593352f7f91STakashi Iwai 	int i;
594352f7f91STakashi Iwai 
595352f7f91STakashi Iwai 	if (!enable)
596352f7f91STakashi Iwai 		path->active = false;
597352f7f91STakashi Iwai 
598352f7f91STakashi Iwai 	for (i = path->depth - 1; i >= 0; i--) {
599352f7f91STakashi Iwai 		if (enable && path->multi[i])
600352f7f91STakashi Iwai 			snd_hda_codec_write_cache(codec, path->path[i], 0,
601352f7f91STakashi Iwai 					    AC_VERB_SET_CONNECT_SEL,
602352f7f91STakashi Iwai 					    path->idx[i]);
603352f7f91STakashi Iwai 		if (has_amp_in(codec, path, i))
604352f7f91STakashi Iwai 			activate_amp_in(codec, path, i, enable, add_aamix);
605352f7f91STakashi Iwai 		if (has_amp_out(codec, path, i))
606352f7f91STakashi Iwai 			activate_amp_out(codec, path, i, enable);
607352f7f91STakashi Iwai 	}
608352f7f91STakashi Iwai 
609352f7f91STakashi Iwai 	if (enable)
610352f7f91STakashi Iwai 		path->active = true;
611352f7f91STakashi Iwai }
612352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_activate_path);
613352f7f91STakashi Iwai 
614d5a9f1bbSTakashi Iwai /* turn on/off EAPD on the given pin */
615d5a9f1bbSTakashi Iwai static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable)
616d5a9f1bbSTakashi Iwai {
617d5a9f1bbSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
618d5a9f1bbSTakashi Iwai 	if (spec->own_eapd_ctl ||
619d5a9f1bbSTakashi Iwai 	    !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD))
620d5a9f1bbSTakashi Iwai 		return;
621ecac3ed1STakashi Iwai 	if (codec->inv_eapd)
622ecac3ed1STakashi Iwai 		enable = !enable;
623d5a9f1bbSTakashi Iwai 	snd_hda_codec_update_cache(codec, pin, 0,
624d5a9f1bbSTakashi Iwai 				   AC_VERB_SET_EAPD_BTLENABLE,
625d5a9f1bbSTakashi Iwai 				   enable ? 0x02 : 0x00);
626d5a9f1bbSTakashi Iwai }
627d5a9f1bbSTakashi Iwai 
628352f7f91STakashi Iwai 
629352f7f91STakashi Iwai /*
630352f7f91STakashi Iwai  * Helper functions for creating mixer ctl elements
631352f7f91STakashi Iwai  */
632352f7f91STakashi Iwai 
633352f7f91STakashi Iwai enum {
634352f7f91STakashi Iwai 	HDA_CTL_WIDGET_VOL,
635352f7f91STakashi Iwai 	HDA_CTL_WIDGET_MUTE,
636352f7f91STakashi Iwai 	HDA_CTL_BIND_MUTE,
637352f7f91STakashi Iwai };
638352f7f91STakashi Iwai static const struct snd_kcontrol_new control_templates[] = {
639352f7f91STakashi Iwai 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
640352f7f91STakashi Iwai 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
641352f7f91STakashi Iwai 	HDA_BIND_MUTE(NULL, 0, 0, 0),
642352f7f91STakashi Iwai };
643352f7f91STakashi Iwai 
644352f7f91STakashi Iwai /* add dynamic controls from template */
645352f7f91STakashi Iwai static int add_control(struct hda_gen_spec *spec, int type, const char *name,
646352f7f91STakashi Iwai 		       int cidx, unsigned long val)
647352f7f91STakashi Iwai {
648352f7f91STakashi Iwai 	struct snd_kcontrol_new *knew;
649352f7f91STakashi Iwai 
65012c93df6STakashi Iwai 	knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]);
651352f7f91STakashi Iwai 	if (!knew)
652352f7f91STakashi Iwai 		return -ENOMEM;
653352f7f91STakashi Iwai 	knew->index = cidx;
654352f7f91STakashi Iwai 	if (get_amp_nid_(val))
655352f7f91STakashi Iwai 		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
656352f7f91STakashi Iwai 	knew->private_value = val;
657352f7f91STakashi Iwai 	return 0;
658352f7f91STakashi Iwai }
659352f7f91STakashi Iwai 
660352f7f91STakashi Iwai static int add_control_with_pfx(struct hda_gen_spec *spec, int type,
661352f7f91STakashi Iwai 				const char *pfx, const char *dir,
662352f7f91STakashi Iwai 				const char *sfx, int cidx, unsigned long val)
663352f7f91STakashi Iwai {
664352f7f91STakashi Iwai 	char name[32];
665352f7f91STakashi Iwai 	snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
666352f7f91STakashi Iwai 	return add_control(spec, type, name, cidx, val);
667352f7f91STakashi Iwai }
668352f7f91STakashi Iwai 
669352f7f91STakashi Iwai #define add_pb_vol_ctrl(spec, type, pfx, val)			\
670352f7f91STakashi Iwai 	add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
671352f7f91STakashi Iwai #define add_pb_sw_ctrl(spec, type, pfx, val)			\
672352f7f91STakashi Iwai 	add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
673352f7f91STakashi Iwai #define __add_pb_vol_ctrl(spec, type, pfx, cidx, val)			\
674352f7f91STakashi Iwai 	add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
675352f7f91STakashi Iwai #define __add_pb_sw_ctrl(spec, type, pfx, cidx, val)			\
676352f7f91STakashi Iwai 	add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
677352f7f91STakashi Iwai 
678352f7f91STakashi Iwai static int add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx,
679352f7f91STakashi Iwai 		       unsigned int chs, struct nid_path *path)
680352f7f91STakashi Iwai {
681352f7f91STakashi Iwai 	unsigned int val;
682352f7f91STakashi Iwai 	if (!path)
683352f7f91STakashi Iwai 		return 0;
684352f7f91STakashi Iwai 	val = path->ctls[NID_PATH_VOL_CTL];
685352f7f91STakashi Iwai 	if (!val)
686352f7f91STakashi Iwai 		return 0;
687352f7f91STakashi Iwai 	val = amp_val_replace_channels(val, chs);
688352f7f91STakashi Iwai 	return __add_pb_vol_ctrl(codec->spec, HDA_CTL_WIDGET_VOL, pfx, cidx, val);
689352f7f91STakashi Iwai }
690352f7f91STakashi Iwai 
691352f7f91STakashi Iwai /* return the channel bits suitable for the given path->ctls[] */
692352f7f91STakashi Iwai static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path,
693352f7f91STakashi Iwai 			       int type)
694352f7f91STakashi Iwai {
695352f7f91STakashi Iwai 	int chs = 1; /* mono (left only) */
696352f7f91STakashi Iwai 	if (path) {
697352f7f91STakashi Iwai 		hda_nid_t nid = get_amp_nid_(path->ctls[type]);
698352f7f91STakashi Iwai 		if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO))
699352f7f91STakashi Iwai 			chs = 3; /* stereo */
700352f7f91STakashi Iwai 	}
701352f7f91STakashi Iwai 	return chs;
702352f7f91STakashi Iwai }
703352f7f91STakashi Iwai 
704352f7f91STakashi Iwai static int add_stereo_vol(struct hda_codec *codec, const char *pfx, int cidx,
705352f7f91STakashi Iwai 			  struct nid_path *path)
706352f7f91STakashi Iwai {
707352f7f91STakashi Iwai 	int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL);
708352f7f91STakashi Iwai 	return add_vol_ctl(codec, pfx, cidx, chs, path);
709352f7f91STakashi Iwai }
710352f7f91STakashi Iwai 
711352f7f91STakashi Iwai /* create a mute-switch for the given mixer widget;
712352f7f91STakashi Iwai  * if it has multiple sources (e.g. DAC and loopback), create a bind-mute
713352f7f91STakashi Iwai  */
714352f7f91STakashi Iwai static int add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx,
715352f7f91STakashi Iwai 		      unsigned int chs, struct nid_path *path)
716352f7f91STakashi Iwai {
717352f7f91STakashi Iwai 	unsigned int val;
718352f7f91STakashi Iwai 	int type = HDA_CTL_WIDGET_MUTE;
719352f7f91STakashi Iwai 
720352f7f91STakashi Iwai 	if (!path)
721352f7f91STakashi Iwai 		return 0;
722352f7f91STakashi Iwai 	val = path->ctls[NID_PATH_MUTE_CTL];
723352f7f91STakashi Iwai 	if (!val)
724352f7f91STakashi Iwai 		return 0;
725352f7f91STakashi Iwai 	val = amp_val_replace_channels(val, chs);
726352f7f91STakashi Iwai 	if (get_amp_direction_(val) == HDA_INPUT) {
727352f7f91STakashi Iwai 		hda_nid_t nid = get_amp_nid_(val);
728352f7f91STakashi Iwai 		int nums = snd_hda_get_num_conns(codec, nid);
729352f7f91STakashi Iwai 		if (nums > 1) {
730352f7f91STakashi Iwai 			type = HDA_CTL_BIND_MUTE;
731352f7f91STakashi Iwai 			val |= nums << 19;
732352f7f91STakashi Iwai 		}
733352f7f91STakashi Iwai 	}
734352f7f91STakashi Iwai 	return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
735352f7f91STakashi Iwai }
736352f7f91STakashi Iwai 
737352f7f91STakashi Iwai static int add_stereo_sw(struct hda_codec *codec, const char *pfx,
738352f7f91STakashi Iwai 				  int cidx, struct nid_path *path)
739352f7f91STakashi Iwai {
740352f7f91STakashi Iwai 	int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL);
741352f7f91STakashi Iwai 	return add_sw_ctl(codec, pfx, cidx, chs, path);
742352f7f91STakashi Iwai }
743352f7f91STakashi Iwai 
744352f7f91STakashi Iwai static const char * const channel_name[4] = {
745352f7f91STakashi Iwai 	"Front", "Surround", "CLFE", "Side"
746352f7f91STakashi Iwai };
747352f7f91STakashi Iwai 
748352f7f91STakashi Iwai /* give some appropriate ctl name prefix for the given line out channel */
749352f7f91STakashi Iwai static const char *get_line_out_pfx(struct hda_gen_spec *spec, int ch,
750352f7f91STakashi Iwai 				    bool can_be_master, int *index)
751352f7f91STakashi Iwai {
752352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
753352f7f91STakashi Iwai 
754352f7f91STakashi Iwai 	*index = 0;
755352f7f91STakashi Iwai 	if (cfg->line_outs == 1 && !spec->multi_ios &&
756352f7f91STakashi Iwai 	    !cfg->hp_outs && !cfg->speaker_outs && can_be_master)
757352f7f91STakashi Iwai 		return spec->vmaster_mute.hook ? "PCM" : "Master";
758352f7f91STakashi Iwai 
759352f7f91STakashi Iwai 	/* if there is really a single DAC used in the whole output paths,
760352f7f91STakashi Iwai 	 * use it master (or "PCM" if a vmaster hook is present)
761352f7f91STakashi Iwai 	 */
762352f7f91STakashi Iwai 	if (spec->multiout.num_dacs == 1 && !spec->mixer_nid &&
763352f7f91STakashi Iwai 	    !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0])
764352f7f91STakashi Iwai 		return spec->vmaster_mute.hook ? "PCM" : "Master";
765352f7f91STakashi Iwai 
766352f7f91STakashi Iwai 	switch (cfg->line_out_type) {
767352f7f91STakashi Iwai 	case AUTO_PIN_SPEAKER_OUT:
768352f7f91STakashi Iwai 		if (cfg->line_outs == 1)
769352f7f91STakashi Iwai 			return "Speaker";
770352f7f91STakashi Iwai 		if (cfg->line_outs == 2)
771352f7f91STakashi Iwai 			return ch ? "Bass Speaker" : "Speaker";
772352f7f91STakashi Iwai 		break;
773352f7f91STakashi Iwai 	case AUTO_PIN_HP_OUT:
774352f7f91STakashi Iwai 		/* for multi-io case, only the primary out */
775352f7f91STakashi Iwai 		if (ch && spec->multi_ios)
776352f7f91STakashi Iwai 			break;
777352f7f91STakashi Iwai 		*index = ch;
778352f7f91STakashi Iwai 		return "Headphone";
779352f7f91STakashi Iwai 	default:
780352f7f91STakashi Iwai 		if (cfg->line_outs == 1 && !spec->multi_ios)
781352f7f91STakashi Iwai 			return "PCM";
782352f7f91STakashi Iwai 		break;
783352f7f91STakashi Iwai 	}
784352f7f91STakashi Iwai 	if (ch >= ARRAY_SIZE(channel_name)) {
785352f7f91STakashi Iwai 		snd_BUG();
786352f7f91STakashi Iwai 		return "PCM";
787352f7f91STakashi Iwai 	}
788352f7f91STakashi Iwai 
789352f7f91STakashi Iwai 	return channel_name[ch];
790352f7f91STakashi Iwai }
791352f7f91STakashi Iwai 
792352f7f91STakashi Iwai /*
793352f7f91STakashi Iwai  * Parse output paths
794352f7f91STakashi Iwai  */
795352f7f91STakashi Iwai 
796352f7f91STakashi Iwai /* badness definition */
797352f7f91STakashi Iwai enum {
798352f7f91STakashi Iwai 	/* No primary DAC is found for the main output */
799352f7f91STakashi Iwai 	BAD_NO_PRIMARY_DAC = 0x10000,
800352f7f91STakashi Iwai 	/* No DAC is found for the extra output */
801352f7f91STakashi Iwai 	BAD_NO_DAC = 0x4000,
802352f7f91STakashi Iwai 	/* No possible multi-ios */
803352f7f91STakashi Iwai 	BAD_MULTI_IO = 0x103,
804352f7f91STakashi Iwai 	/* No individual DAC for extra output */
805352f7f91STakashi Iwai 	BAD_NO_EXTRA_DAC = 0x102,
806352f7f91STakashi Iwai 	/* No individual DAC for extra surrounds */
807352f7f91STakashi Iwai 	BAD_NO_EXTRA_SURR_DAC = 0x101,
808352f7f91STakashi Iwai 	/* Primary DAC shared with main surrounds */
809352f7f91STakashi Iwai 	BAD_SHARED_SURROUND = 0x100,
810352f7f91STakashi Iwai 	/* Primary DAC shared with main CLFE */
811352f7f91STakashi Iwai 	BAD_SHARED_CLFE = 0x10,
812352f7f91STakashi Iwai 	/* Primary DAC shared with extra surrounds */
813352f7f91STakashi Iwai 	BAD_SHARED_EXTRA_SURROUND = 0x10,
814352f7f91STakashi Iwai 	/* Volume widget is shared */
815352f7f91STakashi Iwai 	BAD_SHARED_VOL = 0x10,
816352f7f91STakashi Iwai };
817352f7f91STakashi Iwai 
8180e614dd0STakashi Iwai /* look for widgets in the given path which are appropriate for
819352f7f91STakashi Iwai  * volume and mute controls, and assign the values to ctls[].
820352f7f91STakashi Iwai  *
821352f7f91STakashi Iwai  * When no appropriate widget is found in the path, the badness value
822352f7f91STakashi Iwai  * is incremented depending on the situation.  The function returns the
823352f7f91STakashi Iwai  * total badness for both volume and mute controls.
824352f7f91STakashi Iwai  */
8250e614dd0STakashi Iwai static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path)
826352f7f91STakashi Iwai {
827352f7f91STakashi Iwai 	hda_nid_t nid;
828352f7f91STakashi Iwai 	unsigned int val;
829352f7f91STakashi Iwai 	int badness = 0;
830352f7f91STakashi Iwai 
831352f7f91STakashi Iwai 	if (!path)
832352f7f91STakashi Iwai 		return BAD_SHARED_VOL * 2;
8330e614dd0STakashi Iwai 
8340e614dd0STakashi Iwai 	if (path->ctls[NID_PATH_VOL_CTL] ||
8350e614dd0STakashi Iwai 	    path->ctls[NID_PATH_MUTE_CTL])
8360e614dd0STakashi Iwai 		return 0; /* already evaluated */
8370e614dd0STakashi Iwai 
838352f7f91STakashi Iwai 	nid = look_for_out_vol_nid(codec, path);
839352f7f91STakashi Iwai 	if (nid) {
840352f7f91STakashi Iwai 		val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
841352f7f91STakashi Iwai 		if (is_ctl_used(codec, val, NID_PATH_VOL_CTL))
842352f7f91STakashi Iwai 			badness += BAD_SHARED_VOL;
843352f7f91STakashi Iwai 		else
844352f7f91STakashi Iwai 			path->ctls[NID_PATH_VOL_CTL] = val;
845352f7f91STakashi Iwai 	} else
846352f7f91STakashi Iwai 		badness += BAD_SHARED_VOL;
847352f7f91STakashi Iwai 	nid = look_for_out_mute_nid(codec, path);
848352f7f91STakashi Iwai 	if (nid) {
849352f7f91STakashi Iwai 		unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid));
850352f7f91STakashi Iwai 		if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT ||
851352f7f91STakashi Iwai 		    nid_has_mute(codec, nid, HDA_OUTPUT))
852352f7f91STakashi Iwai 			val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
853352f7f91STakashi Iwai 		else
854352f7f91STakashi Iwai 			val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT);
855352f7f91STakashi Iwai 		if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL))
856352f7f91STakashi Iwai 			badness += BAD_SHARED_VOL;
857352f7f91STakashi Iwai 		else
858352f7f91STakashi Iwai 			path->ctls[NID_PATH_MUTE_CTL] = val;
859352f7f91STakashi Iwai 	} else
860352f7f91STakashi Iwai 		badness += BAD_SHARED_VOL;
861352f7f91STakashi Iwai 	return badness;
862352f7f91STakashi Iwai }
863352f7f91STakashi Iwai 
864352f7f91STakashi Iwai struct badness_table {
865352f7f91STakashi Iwai 	int no_primary_dac;	/* no primary DAC */
866352f7f91STakashi Iwai 	int no_dac;		/* no secondary DACs */
867352f7f91STakashi Iwai 	int shared_primary;	/* primary DAC is shared with main output */
868352f7f91STakashi Iwai 	int shared_surr;	/* secondary DAC shared with main or primary */
869352f7f91STakashi Iwai 	int shared_clfe;	/* third DAC shared with main or primary */
870352f7f91STakashi Iwai 	int shared_surr_main;	/* secondary DAC sahred with main/DAC0 */
871352f7f91STakashi Iwai };
872352f7f91STakashi Iwai 
873352f7f91STakashi Iwai static struct badness_table main_out_badness = {
874352f7f91STakashi Iwai 	.no_primary_dac = BAD_NO_PRIMARY_DAC,
875352f7f91STakashi Iwai 	.no_dac = BAD_NO_DAC,
876352f7f91STakashi Iwai 	.shared_primary = BAD_NO_PRIMARY_DAC,
877352f7f91STakashi Iwai 	.shared_surr = BAD_SHARED_SURROUND,
878352f7f91STakashi Iwai 	.shared_clfe = BAD_SHARED_CLFE,
879352f7f91STakashi Iwai 	.shared_surr_main = BAD_SHARED_SURROUND,
880352f7f91STakashi Iwai };
881352f7f91STakashi Iwai 
882352f7f91STakashi Iwai static struct badness_table extra_out_badness = {
883352f7f91STakashi Iwai 	.no_primary_dac = BAD_NO_DAC,
884352f7f91STakashi Iwai 	.no_dac = BAD_NO_DAC,
885352f7f91STakashi Iwai 	.shared_primary = BAD_NO_EXTRA_DAC,
886352f7f91STakashi Iwai 	.shared_surr = BAD_SHARED_EXTRA_SURROUND,
887352f7f91STakashi Iwai 	.shared_clfe = BAD_SHARED_EXTRA_SURROUND,
888352f7f91STakashi Iwai 	.shared_surr_main = BAD_NO_EXTRA_SURR_DAC,
889352f7f91STakashi Iwai };
890352f7f91STakashi Iwai 
8917385df61STakashi Iwai /* get the DAC of the primary output corresponding to the given array index */
8927385df61STakashi Iwai static hda_nid_t get_primary_out(struct hda_codec *codec, int idx)
8937385df61STakashi Iwai {
8947385df61STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
8957385df61STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
8967385df61STakashi Iwai 
8977385df61STakashi Iwai 	if (cfg->line_outs > idx)
8987385df61STakashi Iwai 		return spec->private_dac_nids[idx];
8997385df61STakashi Iwai 	idx -= cfg->line_outs;
9007385df61STakashi Iwai 	if (spec->multi_ios > idx)
9017385df61STakashi Iwai 		return spec->multi_io[idx].dac;
9027385df61STakashi Iwai 	return 0;
9037385df61STakashi Iwai }
9047385df61STakashi Iwai 
9057385df61STakashi Iwai /* return the DAC if it's reachable, otherwise zero */
9067385df61STakashi Iwai static inline hda_nid_t try_dac(struct hda_codec *codec,
9077385df61STakashi Iwai 				hda_nid_t dac, hda_nid_t pin)
9087385df61STakashi Iwai {
9097385df61STakashi Iwai 	return is_reachable_path(codec, dac, pin) ? dac : 0;
9107385df61STakashi Iwai }
9117385df61STakashi Iwai 
912352f7f91STakashi Iwai /* try to assign DACs to pins and return the resultant badness */
913352f7f91STakashi Iwai static int try_assign_dacs(struct hda_codec *codec, int num_outs,
914352f7f91STakashi Iwai 			   const hda_nid_t *pins, hda_nid_t *dacs,
915196c1766STakashi Iwai 			   int *path_idx,
916352f7f91STakashi Iwai 			   const struct badness_table *bad)
917352f7f91STakashi Iwai {
918352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
919352f7f91STakashi Iwai 	int i, j;
920352f7f91STakashi Iwai 	int badness = 0;
921352f7f91STakashi Iwai 	hda_nid_t dac;
922352f7f91STakashi Iwai 
923352f7f91STakashi Iwai 	if (!num_outs)
924352f7f91STakashi Iwai 		return 0;
925352f7f91STakashi Iwai 
926352f7f91STakashi Iwai 	for (i = 0; i < num_outs; i++) {
9270c8c0f56STakashi Iwai 		struct nid_path *path;
928352f7f91STakashi Iwai 		hda_nid_t pin = pins[i];
9291e0b5286STakashi Iwai 
9300e614dd0STakashi Iwai 		path = snd_hda_get_path_from_idx(codec, path_idx[i]);
9310e614dd0STakashi Iwai 		if (path) {
9320e614dd0STakashi Iwai 			badness += assign_out_path_ctls(codec, path);
9331e0b5286STakashi Iwai 			continue;
9341e0b5286STakashi Iwai 		}
9351e0b5286STakashi Iwai 
936352f7f91STakashi Iwai 		dacs[i] = look_for_dac(codec, pin, false);
937352f7f91STakashi Iwai 		if (!dacs[i] && !i) {
938980428ceSTakashi Iwai 			/* try to steal the DAC of surrounds for the front */
939352f7f91STakashi Iwai 			for (j = 1; j < num_outs; j++) {
940352f7f91STakashi Iwai 				if (is_reachable_path(codec, dacs[j], pin)) {
941352f7f91STakashi Iwai 					dacs[0] = dacs[j];
942352f7f91STakashi Iwai 					dacs[j] = 0;
943980428ceSTakashi Iwai 					invalidate_nid_path(codec, path_idx[j]);
944196c1766STakashi Iwai 					path_idx[j] = 0;
945352f7f91STakashi Iwai 					break;
946352f7f91STakashi Iwai 				}
947352f7f91STakashi Iwai 			}
948352f7f91STakashi Iwai 		}
949352f7f91STakashi Iwai 		dac = dacs[i];
950352f7f91STakashi Iwai 		if (!dac) {
9517385df61STakashi Iwai 			if (num_outs > 2)
9527385df61STakashi Iwai 				dac = try_dac(codec, get_primary_out(codec, i), pin);
9537385df61STakashi Iwai 			if (!dac)
9547385df61STakashi Iwai 				dac = try_dac(codec, dacs[0], pin);
9557385df61STakashi Iwai 			if (!dac)
9567385df61STakashi Iwai 				dac = try_dac(codec, get_primary_out(codec, i), pin);
957352f7f91STakashi Iwai 			if (dac) {
958352f7f91STakashi Iwai 				if (!i)
959352f7f91STakashi Iwai 					badness += bad->shared_primary;
960352f7f91STakashi Iwai 				else if (i == 1)
961352f7f91STakashi Iwai 					badness += bad->shared_surr;
962352f7f91STakashi Iwai 				else
963352f7f91STakashi Iwai 					badness += bad->shared_clfe;
964352f7f91STakashi Iwai 			} else if (is_reachable_path(codec, spec->private_dac_nids[0], pin)) {
965352f7f91STakashi Iwai 				dac = spec->private_dac_nids[0];
966352f7f91STakashi Iwai 				badness += bad->shared_surr_main;
967352f7f91STakashi Iwai 			} else if (!i)
968352f7f91STakashi Iwai 				badness += bad->no_primary_dac;
969352f7f91STakashi Iwai 			else
970352f7f91STakashi Iwai 				badness += bad->no_dac;
971352f7f91STakashi Iwai 		}
9723ca529d3STakashi Iwai 		path = snd_hda_add_new_path(codec, dac, pin, -spec->mixer_nid);
973117688a9STakashi Iwai 		if (!path && !i && spec->mixer_nid) {
974b3a8c745STakashi Iwai 			/* try with aamix */
9753ca529d3STakashi Iwai 			path = snd_hda_add_new_path(codec, dac, pin, 0);
976b3a8c745STakashi Iwai 		}
9770c8c0f56STakashi Iwai 		if (!path)
978352f7f91STakashi Iwai 			dac = dacs[i] = 0;
979e1284af7STakashi Iwai 		else {
9800c8c0f56STakashi Iwai 			print_nid_path("output", path);
981e1284af7STakashi Iwai 			path->active = true;
982196c1766STakashi Iwai 			path_idx[i] = snd_hda_get_path_idx(codec, path);
9830e614dd0STakashi Iwai 			badness += assign_out_path_ctls(codec, path);
984e1284af7STakashi Iwai 		}
985352f7f91STakashi Iwai 	}
986352f7f91STakashi Iwai 
987352f7f91STakashi Iwai 	return badness;
988352f7f91STakashi Iwai }
989352f7f91STakashi Iwai 
990352f7f91STakashi Iwai /* return NID if the given pin has only a single connection to a certain DAC */
991352f7f91STakashi Iwai static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
992352f7f91STakashi Iwai {
993352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
994352f7f91STakashi Iwai 	int i;
995352f7f91STakashi Iwai 	hda_nid_t nid_found = 0;
996352f7f91STakashi Iwai 
997352f7f91STakashi Iwai 	for (i = 0; i < spec->num_all_dacs; i++) {
998352f7f91STakashi Iwai 		hda_nid_t nid = spec->all_dacs[i];
999352f7f91STakashi Iwai 		if (!nid || is_dac_already_used(codec, nid))
1000352f7f91STakashi Iwai 			continue;
1001352f7f91STakashi Iwai 		if (is_reachable_path(codec, nid, pin)) {
1002352f7f91STakashi Iwai 			if (nid_found)
1003352f7f91STakashi Iwai 				return 0;
1004352f7f91STakashi Iwai 			nid_found = nid;
1005352f7f91STakashi Iwai 		}
1006352f7f91STakashi Iwai 	}
1007352f7f91STakashi Iwai 	return nid_found;
1008352f7f91STakashi Iwai }
1009352f7f91STakashi Iwai 
1010352f7f91STakashi Iwai /* check whether the given pin can be a multi-io pin */
1011352f7f91STakashi Iwai static bool can_be_multiio_pin(struct hda_codec *codec,
1012352f7f91STakashi Iwai 			       unsigned int location, hda_nid_t nid)
1013352f7f91STakashi Iwai {
1014352f7f91STakashi Iwai 	unsigned int defcfg, caps;
1015352f7f91STakashi Iwai 
1016352f7f91STakashi Iwai 	defcfg = snd_hda_codec_get_pincfg(codec, nid);
1017352f7f91STakashi Iwai 	if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
1018352f7f91STakashi Iwai 		return false;
1019352f7f91STakashi Iwai 	if (location && get_defcfg_location(defcfg) != location)
1020352f7f91STakashi Iwai 		return false;
1021352f7f91STakashi Iwai 	caps = snd_hda_query_pin_caps(codec, nid);
1022352f7f91STakashi Iwai 	if (!(caps & AC_PINCAP_OUT))
1023352f7f91STakashi Iwai 		return false;
1024352f7f91STakashi Iwai 	return true;
1025352f7f91STakashi Iwai }
1026352f7f91STakashi Iwai 
1027e22aab7dSTakashi Iwai /* count the number of input pins that are capable to be multi-io */
1028e22aab7dSTakashi Iwai static int count_multiio_pins(struct hda_codec *codec, hda_nid_t reference_pin)
1029e22aab7dSTakashi Iwai {
1030e22aab7dSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1031e22aab7dSTakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
1032e22aab7dSTakashi Iwai 	unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
1033e22aab7dSTakashi Iwai 	unsigned int location = get_defcfg_location(defcfg);
1034e22aab7dSTakashi Iwai 	int type, i;
1035e22aab7dSTakashi Iwai 	int num_pins = 0;
1036e22aab7dSTakashi Iwai 
1037e22aab7dSTakashi Iwai 	for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
1038e22aab7dSTakashi Iwai 		for (i = 0; i < cfg->num_inputs; i++) {
1039e22aab7dSTakashi Iwai 			if (cfg->inputs[i].type != type)
1040e22aab7dSTakashi Iwai 				continue;
1041e22aab7dSTakashi Iwai 			if (can_be_multiio_pin(codec, location,
1042e22aab7dSTakashi Iwai 					       cfg->inputs[i].pin))
1043e22aab7dSTakashi Iwai 				num_pins++;
1044e22aab7dSTakashi Iwai 		}
1045e22aab7dSTakashi Iwai 	}
1046e22aab7dSTakashi Iwai 	return num_pins;
1047e22aab7dSTakashi Iwai }
1048e22aab7dSTakashi Iwai 
1049352f7f91STakashi Iwai /*
1050352f7f91STakashi Iwai  * multi-io helper
1051352f7f91STakashi Iwai  *
1052352f7f91STakashi Iwai  * When hardwired is set, try to fill ony hardwired pins, and returns
1053352f7f91STakashi Iwai  * zero if any pins are filled, non-zero if nothing found.
1054352f7f91STakashi Iwai  * When hardwired is off, try to fill possible input pins, and returns
1055352f7f91STakashi Iwai  * the badness value.
1056352f7f91STakashi Iwai  */
1057352f7f91STakashi Iwai static int fill_multi_ios(struct hda_codec *codec,
1058352f7f91STakashi Iwai 			  hda_nid_t reference_pin,
1059e22aab7dSTakashi Iwai 			  bool hardwired)
1060352f7f91STakashi Iwai {
1061352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1062352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
1063e22aab7dSTakashi Iwai 	int type, i, j, num_pins, old_pins;
1064352f7f91STakashi Iwai 	unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
1065352f7f91STakashi Iwai 	unsigned int location = get_defcfg_location(defcfg);
1066352f7f91STakashi Iwai 	int badness = 0;
10670e614dd0STakashi Iwai 	struct nid_path *path;
1068352f7f91STakashi Iwai 
1069352f7f91STakashi Iwai 	old_pins = spec->multi_ios;
1070352f7f91STakashi Iwai 	if (old_pins >= 2)
1071352f7f91STakashi Iwai 		goto end_fill;
1072352f7f91STakashi Iwai 
1073e22aab7dSTakashi Iwai 	num_pins = count_multiio_pins(codec, reference_pin);
1074352f7f91STakashi Iwai 	if (num_pins < 2)
1075352f7f91STakashi Iwai 		goto end_fill;
1076352f7f91STakashi Iwai 
1077352f7f91STakashi Iwai 	for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
1078352f7f91STakashi Iwai 		for (i = 0; i < cfg->num_inputs; i++) {
1079352f7f91STakashi Iwai 			hda_nid_t nid = cfg->inputs[i].pin;
1080352f7f91STakashi Iwai 			hda_nid_t dac = 0;
1081352f7f91STakashi Iwai 
1082352f7f91STakashi Iwai 			if (cfg->inputs[i].type != type)
1083352f7f91STakashi Iwai 				continue;
1084352f7f91STakashi Iwai 			if (!can_be_multiio_pin(codec, location, nid))
1085352f7f91STakashi Iwai 				continue;
1086352f7f91STakashi Iwai 			for (j = 0; j < spec->multi_ios; j++) {
1087352f7f91STakashi Iwai 				if (nid == spec->multi_io[j].pin)
1088352f7f91STakashi Iwai 					break;
1089352f7f91STakashi Iwai 			}
1090352f7f91STakashi Iwai 			if (j < spec->multi_ios)
1091352f7f91STakashi Iwai 				continue;
1092352f7f91STakashi Iwai 
1093352f7f91STakashi Iwai 			if (hardwired)
1094352f7f91STakashi Iwai 				dac = get_dac_if_single(codec, nid);
1095352f7f91STakashi Iwai 			else if (!dac)
1096352f7f91STakashi Iwai 				dac = look_for_dac(codec, nid, false);
1097352f7f91STakashi Iwai 			if (!dac) {
1098352f7f91STakashi Iwai 				badness++;
1099352f7f91STakashi Iwai 				continue;
1100352f7f91STakashi Iwai 			}
11013ca529d3STakashi Iwai 			path = snd_hda_add_new_path(codec, dac, nid,
11023ca529d3STakashi Iwai 						    -spec->mixer_nid);
11030c8c0f56STakashi Iwai 			if (!path) {
1104352f7f91STakashi Iwai 				badness++;
1105352f7f91STakashi Iwai 				continue;
1106352f7f91STakashi Iwai 			}
11070c8c0f56STakashi Iwai 			print_nid_path("multiio", path);
1108352f7f91STakashi Iwai 			spec->multi_io[spec->multi_ios].pin = nid;
1109352f7f91STakashi Iwai 			spec->multi_io[spec->multi_ios].dac = dac;
1110196c1766STakashi Iwai 			spec->out_paths[cfg->line_outs + spec->multi_ios] =
1111196c1766STakashi Iwai 				snd_hda_get_path_idx(codec, path);
1112352f7f91STakashi Iwai 			spec->multi_ios++;
1113352f7f91STakashi Iwai 			if (spec->multi_ios >= 2)
1114352f7f91STakashi Iwai 				break;
1115352f7f91STakashi Iwai 		}
1116352f7f91STakashi Iwai 	}
1117352f7f91STakashi Iwai  end_fill:
1118352f7f91STakashi Iwai 	if (badness)
1119352f7f91STakashi Iwai 		badness = BAD_MULTI_IO;
1120352f7f91STakashi Iwai 	if (old_pins == spec->multi_ios) {
1121352f7f91STakashi Iwai 		if (hardwired)
1122352f7f91STakashi Iwai 			return 1; /* nothing found */
1123352f7f91STakashi Iwai 		else
1124352f7f91STakashi Iwai 			return badness; /* no badness if nothing found */
1125352f7f91STakashi Iwai 	}
1126352f7f91STakashi Iwai 	if (!hardwired && spec->multi_ios < 2) {
1127352f7f91STakashi Iwai 		/* cancel newly assigned paths */
1128352f7f91STakashi Iwai 		spec->paths.used -= spec->multi_ios - old_pins;
1129352f7f91STakashi Iwai 		spec->multi_ios = old_pins;
1130352f7f91STakashi Iwai 		return badness;
1131352f7f91STakashi Iwai 	}
1132352f7f91STakashi Iwai 
1133352f7f91STakashi Iwai 	/* assign volume and mute controls */
11340e614dd0STakashi Iwai 	for (i = old_pins; i < spec->multi_ios; i++) {
11350e614dd0STakashi Iwai 		path = snd_hda_get_path_from_idx(codec, spec->out_paths[cfg->line_outs + i]);
11360e614dd0STakashi Iwai 		badness += assign_out_path_ctls(codec, path);
11370e614dd0STakashi Iwai 	}
1138352f7f91STakashi Iwai 
1139352f7f91STakashi Iwai 	return badness;
1140352f7f91STakashi Iwai }
1141352f7f91STakashi Iwai 
1142352f7f91STakashi Iwai /* map DACs for all pins in the list if they are single connections */
1143352f7f91STakashi Iwai static bool map_singles(struct hda_codec *codec, int outs,
1144196c1766STakashi Iwai 			const hda_nid_t *pins, hda_nid_t *dacs, int *path_idx)
1145352f7f91STakashi Iwai {
1146b3a8c745STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1147352f7f91STakashi Iwai 	int i;
1148352f7f91STakashi Iwai 	bool found = false;
1149352f7f91STakashi Iwai 	for (i = 0; i < outs; i++) {
11500c8c0f56STakashi Iwai 		struct nid_path *path;
1151352f7f91STakashi Iwai 		hda_nid_t dac;
1152352f7f91STakashi Iwai 		if (dacs[i])
1153352f7f91STakashi Iwai 			continue;
1154352f7f91STakashi Iwai 		dac = get_dac_if_single(codec, pins[i]);
1155352f7f91STakashi Iwai 		if (!dac)
1156352f7f91STakashi Iwai 			continue;
11573ca529d3STakashi Iwai 		path = snd_hda_add_new_path(codec, dac, pins[i],
11583ca529d3STakashi Iwai 					    -spec->mixer_nid);
1159117688a9STakashi Iwai 		if (!path && !i && spec->mixer_nid)
11603ca529d3STakashi Iwai 			path = snd_hda_add_new_path(codec, dac, pins[i], 0);
11610c8c0f56STakashi Iwai 		if (path) {
1162352f7f91STakashi Iwai 			dacs[i] = dac;
1163352f7f91STakashi Iwai 			found = true;
11640c8c0f56STakashi Iwai 			print_nid_path("output", path);
1165e1284af7STakashi Iwai 			path->active = true;
1166196c1766STakashi Iwai 			path_idx[i] = snd_hda_get_path_idx(codec, path);
1167352f7f91STakashi Iwai 		}
1168352f7f91STakashi Iwai 	}
1169352f7f91STakashi Iwai 	return found;
1170352f7f91STakashi Iwai }
1171352f7f91STakashi Iwai 
1172c30aa7b2STakashi Iwai /* create a new path including aamix if available, and return its index */
1173c30aa7b2STakashi Iwai static int check_aamix_out_path(struct hda_codec *codec, int path_idx)
1174c30aa7b2STakashi Iwai {
11753ca529d3STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1176c30aa7b2STakashi Iwai 	struct nid_path *path;
1177c30aa7b2STakashi Iwai 
1178c30aa7b2STakashi Iwai 	path = snd_hda_get_path_from_idx(codec, path_idx);
11793ca529d3STakashi Iwai 	if (!path || !path->depth ||
11803ca529d3STakashi Iwai 	    is_nid_contained(path, spec->mixer_nid))
1181c30aa7b2STakashi Iwai 		return 0;
1182c30aa7b2STakashi Iwai 	path = snd_hda_add_new_path(codec, path->path[0],
1183c30aa7b2STakashi Iwai 				    path->path[path->depth - 1],
11843ca529d3STakashi Iwai 				    spec->mixer_nid);
1185c30aa7b2STakashi Iwai 	if (!path)
1186c30aa7b2STakashi Iwai 		return 0;
1187c30aa7b2STakashi Iwai 	print_nid_path("output-aamix", path);
1188c30aa7b2STakashi Iwai 	path->active = false; /* unused as default */
1189c30aa7b2STakashi Iwai 	return snd_hda_get_path_idx(codec, path);
1190c30aa7b2STakashi Iwai }
1191c30aa7b2STakashi Iwai 
1192a07a949bSTakashi Iwai /* fill the empty entries in the dac array for speaker/hp with the
1193a07a949bSTakashi Iwai  * shared dac pointed by the paths
1194a07a949bSTakashi Iwai  */
1195a07a949bSTakashi Iwai static void refill_shared_dacs(struct hda_codec *codec, int num_outs,
1196a07a949bSTakashi Iwai 			       hda_nid_t *dacs, int *path_idx)
1197a07a949bSTakashi Iwai {
1198a07a949bSTakashi Iwai 	struct nid_path *path;
1199a07a949bSTakashi Iwai 	int i;
1200a07a949bSTakashi Iwai 
1201a07a949bSTakashi Iwai 	for (i = 0; i < num_outs; i++) {
1202a07a949bSTakashi Iwai 		if (dacs[i])
1203a07a949bSTakashi Iwai 			continue;
1204a07a949bSTakashi Iwai 		path = snd_hda_get_path_from_idx(codec, path_idx[i]);
1205a07a949bSTakashi Iwai 		if (!path)
1206a07a949bSTakashi Iwai 			continue;
1207a07a949bSTakashi Iwai 		dacs[i] = path->path[0];
1208a07a949bSTakashi Iwai 	}
1209a07a949bSTakashi Iwai }
1210a07a949bSTakashi Iwai 
1211352f7f91STakashi Iwai /* fill in the dac_nids table from the parsed pin configuration */
1212352f7f91STakashi Iwai static int fill_and_eval_dacs(struct hda_codec *codec,
1213352f7f91STakashi Iwai 			      bool fill_hardwired,
1214352f7f91STakashi Iwai 			      bool fill_mio_first)
1215352f7f91STakashi Iwai {
1216352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1217352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
1218352f7f91STakashi Iwai 	int i, err, badness;
1219352f7f91STakashi Iwai 
1220352f7f91STakashi Iwai 	/* set num_dacs once to full for look_for_dac() */
1221352f7f91STakashi Iwai 	spec->multiout.num_dacs = cfg->line_outs;
1222352f7f91STakashi Iwai 	spec->multiout.dac_nids = spec->private_dac_nids;
1223352f7f91STakashi Iwai 	memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
1224352f7f91STakashi Iwai 	memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid));
1225352f7f91STakashi Iwai 	memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid));
1226352f7f91STakashi Iwai 	spec->multi_ios = 0;
1227352f7f91STakashi Iwai 	snd_array_free(&spec->paths);
1228cd5be3f9STakashi Iwai 
1229cd5be3f9STakashi Iwai 	/* clear path indices */
1230cd5be3f9STakashi Iwai 	memset(spec->out_paths, 0, sizeof(spec->out_paths));
1231cd5be3f9STakashi Iwai 	memset(spec->hp_paths, 0, sizeof(spec->hp_paths));
1232cd5be3f9STakashi Iwai 	memset(spec->speaker_paths, 0, sizeof(spec->speaker_paths));
1233cd5be3f9STakashi Iwai 	memset(spec->aamix_out_paths, 0, sizeof(spec->aamix_out_paths));
1234cd5be3f9STakashi Iwai 	memset(spec->digout_paths, 0, sizeof(spec->digout_paths));
1235c697b716STakashi Iwai 	memset(spec->input_paths, 0, sizeof(spec->input_paths));
1236cd5be3f9STakashi Iwai 	memset(spec->loopback_paths, 0, sizeof(spec->loopback_paths));
1237cd5be3f9STakashi Iwai 	memset(&spec->digin_path, 0, sizeof(spec->digin_path));
1238cd5be3f9STakashi Iwai 
1239352f7f91STakashi Iwai 	badness = 0;
1240352f7f91STakashi Iwai 
1241352f7f91STakashi Iwai 	/* fill hard-wired DACs first */
1242352f7f91STakashi Iwai 	if (fill_hardwired) {
1243352f7f91STakashi Iwai 		bool mapped;
1244352f7f91STakashi Iwai 		do {
1245352f7f91STakashi Iwai 			mapped = map_singles(codec, cfg->line_outs,
1246352f7f91STakashi Iwai 					     cfg->line_out_pins,
1247196c1766STakashi Iwai 					     spec->private_dac_nids,
1248196c1766STakashi Iwai 					     spec->out_paths);
1249352f7f91STakashi Iwai 			mapped |= map_singles(codec, cfg->hp_outs,
1250352f7f91STakashi Iwai 					      cfg->hp_pins,
1251196c1766STakashi Iwai 					      spec->multiout.hp_out_nid,
1252196c1766STakashi Iwai 					      spec->hp_paths);
1253352f7f91STakashi Iwai 			mapped |= map_singles(codec, cfg->speaker_outs,
1254352f7f91STakashi Iwai 					      cfg->speaker_pins,
1255196c1766STakashi Iwai 					      spec->multiout.extra_out_nid,
1256196c1766STakashi Iwai 					      spec->speaker_paths);
1257352f7f91STakashi Iwai 			if (fill_mio_first && cfg->line_outs == 1 &&
1258352f7f91STakashi Iwai 			    cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1259e22aab7dSTakashi Iwai 				err = fill_multi_ios(codec, cfg->line_out_pins[0], true);
1260352f7f91STakashi Iwai 				if (!err)
1261352f7f91STakashi Iwai 					mapped = true;
1262352f7f91STakashi Iwai 			}
1263352f7f91STakashi Iwai 		} while (mapped);
1264352f7f91STakashi Iwai 	}
1265352f7f91STakashi Iwai 
1266352f7f91STakashi Iwai 	badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins,
1267196c1766STakashi Iwai 				   spec->private_dac_nids, spec->out_paths,
1268352f7f91STakashi Iwai 				   &main_out_badness);
1269352f7f91STakashi Iwai 
1270352f7f91STakashi Iwai 	if (fill_mio_first &&
1271352f7f91STakashi Iwai 	    cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1272352f7f91STakashi Iwai 		/* try to fill multi-io first */
1273e22aab7dSTakashi Iwai 		err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
1274352f7f91STakashi Iwai 		if (err < 0)
1275352f7f91STakashi Iwai 			return err;
1276352f7f91STakashi Iwai 		/* we don't count badness at this stage yet */
1277352f7f91STakashi Iwai 	}
1278352f7f91STakashi Iwai 
1279352f7f91STakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
1280352f7f91STakashi Iwai 		err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins,
1281352f7f91STakashi Iwai 				      spec->multiout.hp_out_nid,
1282196c1766STakashi Iwai 				      spec->hp_paths,
1283352f7f91STakashi Iwai 				      &extra_out_badness);
1284352f7f91STakashi Iwai 		if (err < 0)
1285352f7f91STakashi Iwai 			return err;
1286352f7f91STakashi Iwai 		badness += err;
1287352f7f91STakashi Iwai 	}
1288352f7f91STakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1289352f7f91STakashi Iwai 		err = try_assign_dacs(codec, cfg->speaker_outs,
1290352f7f91STakashi Iwai 				      cfg->speaker_pins,
1291352f7f91STakashi Iwai 				      spec->multiout.extra_out_nid,
1292196c1766STakashi Iwai 				      spec->speaker_paths,
1293352f7f91STakashi Iwai 				      &extra_out_badness);
1294352f7f91STakashi Iwai 		if (err < 0)
1295352f7f91STakashi Iwai 			return err;
1296352f7f91STakashi Iwai 		badness += err;
1297352f7f91STakashi Iwai 	}
1298352f7f91STakashi Iwai 	if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1299e22aab7dSTakashi Iwai 		err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
1300352f7f91STakashi Iwai 		if (err < 0)
1301352f7f91STakashi Iwai 			return err;
1302352f7f91STakashi Iwai 		badness += err;
1303352f7f91STakashi Iwai 	}
1304e22aab7dSTakashi Iwai 
1305c30aa7b2STakashi Iwai 	if (spec->mixer_nid) {
1306c30aa7b2STakashi Iwai 		spec->aamix_out_paths[0] =
1307c30aa7b2STakashi Iwai 			check_aamix_out_path(codec, spec->out_paths[0]);
1308c30aa7b2STakashi Iwai 		if (cfg->line_out_type != AUTO_PIN_HP_OUT)
1309c30aa7b2STakashi Iwai 			spec->aamix_out_paths[1] =
1310c30aa7b2STakashi Iwai 				check_aamix_out_path(codec, spec->hp_paths[0]);
1311c30aa7b2STakashi Iwai 		if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
1312c30aa7b2STakashi Iwai 			spec->aamix_out_paths[2] =
1313c30aa7b2STakashi Iwai 				check_aamix_out_path(codec, spec->speaker_paths[0]);
1314c30aa7b2STakashi Iwai 	}
1315c30aa7b2STakashi Iwai 
1316e22aab7dSTakashi Iwai 	if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
1317e22aab7dSTakashi Iwai 		if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2)
1318e22aab7dSTakashi Iwai 			spec->multi_ios = 1; /* give badness */
1319352f7f91STakashi Iwai 
1320a07a949bSTakashi Iwai 	/* re-count num_dacs and squash invalid entries */
1321a07a949bSTakashi Iwai 	spec->multiout.num_dacs = 0;
1322a07a949bSTakashi Iwai 	for (i = 0; i < cfg->line_outs; i++) {
1323a07a949bSTakashi Iwai 		if (spec->private_dac_nids[i])
1324a07a949bSTakashi Iwai 			spec->multiout.num_dacs++;
1325a07a949bSTakashi Iwai 		else {
1326a07a949bSTakashi Iwai 			memmove(spec->private_dac_nids + i,
1327a07a949bSTakashi Iwai 				spec->private_dac_nids + i + 1,
1328a07a949bSTakashi Iwai 				sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
1329a07a949bSTakashi Iwai 			spec->private_dac_nids[cfg->line_outs - 1] = 0;
1330a07a949bSTakashi Iwai 		}
1331a07a949bSTakashi Iwai 	}
1332a07a949bSTakashi Iwai 
1333a07a949bSTakashi Iwai 	spec->ext_channel_count = spec->min_channel_count =
1334a07a949bSTakashi Iwai 		spec->multiout.num_dacs;
1335a07a949bSTakashi Iwai 
1336352f7f91STakashi Iwai 	if (spec->multi_ios == 2) {
1337352f7f91STakashi Iwai 		for (i = 0; i < 2; i++)
1338352f7f91STakashi Iwai 			spec->private_dac_nids[spec->multiout.num_dacs++] =
1339352f7f91STakashi Iwai 				spec->multi_io[i].dac;
1340352f7f91STakashi Iwai 	} else if (spec->multi_ios) {
1341352f7f91STakashi Iwai 		spec->multi_ios = 0;
1342352f7f91STakashi Iwai 		badness += BAD_MULTI_IO;
1343352f7f91STakashi Iwai 	}
1344352f7f91STakashi Iwai 
1345a07a949bSTakashi Iwai 	/* re-fill the shared DAC for speaker / headphone */
1346a07a949bSTakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
1347a07a949bSTakashi Iwai 		refill_shared_dacs(codec, cfg->hp_outs,
1348a07a949bSTakashi Iwai 				   spec->multiout.hp_out_nid,
1349a07a949bSTakashi Iwai 				   spec->hp_paths);
1350a07a949bSTakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
1351a07a949bSTakashi Iwai 		refill_shared_dacs(codec, cfg->speaker_outs,
1352a07a949bSTakashi Iwai 				   spec->multiout.extra_out_nid,
1353a07a949bSTakashi Iwai 				   spec->speaker_paths);
1354a07a949bSTakashi Iwai 
13552c12c30dSTakashi Iwai 	/* set initial pinctl targets */
13562c12c30dSTakashi Iwai 	set_pin_targets(codec, cfg->line_outs, cfg->line_out_pins,
13572c12c30dSTakashi Iwai 			cfg->line_out_type == AUTO_PIN_HP_OUT ? PIN_HP : PIN_OUT);
13582c12c30dSTakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
13592c12c30dSTakashi Iwai 		set_pin_targets(codec, cfg->hp_outs, cfg->hp_pins, PIN_HP);
13602c12c30dSTakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
13612c12c30dSTakashi Iwai 		set_pin_targets(codec, cfg->speaker_outs,
13622c12c30dSTakashi Iwai 				cfg->speaker_pins, PIN_OUT);
13632c12c30dSTakashi Iwai 
1364352f7f91STakashi Iwai 	return badness;
1365352f7f91STakashi Iwai }
1366352f7f91STakashi Iwai 
1367352f7f91STakashi Iwai #define DEBUG_BADNESS
1368352f7f91STakashi Iwai 
1369352f7f91STakashi Iwai #ifdef DEBUG_BADNESS
1370352f7f91STakashi Iwai #define debug_badness	snd_printdd
1371352f7f91STakashi Iwai #else
1372352f7f91STakashi Iwai #define debug_badness(...)
1373352f7f91STakashi Iwai #endif
1374352f7f91STakashi Iwai 
1375352f7f91STakashi Iwai static void debug_show_configs(struct hda_gen_spec *spec, struct auto_pin_cfg *cfg)
1376352f7f91STakashi Iwai {
1377352f7f91STakashi Iwai 	debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
1378352f7f91STakashi Iwai 		      cfg->line_out_pins[0], cfg->line_out_pins[1],
1379708122e8STakashi Iwai 		      cfg->line_out_pins[2], cfg->line_out_pins[3],
1380352f7f91STakashi Iwai 		      spec->multiout.dac_nids[0],
1381352f7f91STakashi Iwai 		      spec->multiout.dac_nids[1],
1382352f7f91STakashi Iwai 		      spec->multiout.dac_nids[2],
1383352f7f91STakashi Iwai 		      spec->multiout.dac_nids[3]);
1384352f7f91STakashi Iwai 	if (spec->multi_ios > 0)
1385352f7f91STakashi Iwai 		debug_badness("multi_ios(%d) = %x/%x : %x/%x\n",
1386352f7f91STakashi Iwai 			      spec->multi_ios,
1387352f7f91STakashi Iwai 			      spec->multi_io[0].pin, spec->multi_io[1].pin,
1388352f7f91STakashi Iwai 			      spec->multi_io[0].dac, spec->multi_io[1].dac);
1389352f7f91STakashi Iwai 	debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
1390352f7f91STakashi Iwai 		      cfg->hp_pins[0], cfg->hp_pins[1],
1391708122e8STakashi Iwai 		      cfg->hp_pins[2], cfg->hp_pins[3],
1392352f7f91STakashi Iwai 		      spec->multiout.hp_out_nid[0],
1393352f7f91STakashi Iwai 		      spec->multiout.hp_out_nid[1],
1394352f7f91STakashi Iwai 		      spec->multiout.hp_out_nid[2],
1395352f7f91STakashi Iwai 		      spec->multiout.hp_out_nid[3]);
1396352f7f91STakashi Iwai 	debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
1397352f7f91STakashi Iwai 		      cfg->speaker_pins[0], cfg->speaker_pins[1],
1398352f7f91STakashi Iwai 		      cfg->speaker_pins[2], cfg->speaker_pins[3],
1399352f7f91STakashi Iwai 		      spec->multiout.extra_out_nid[0],
1400352f7f91STakashi Iwai 		      spec->multiout.extra_out_nid[1],
1401352f7f91STakashi Iwai 		      spec->multiout.extra_out_nid[2],
1402352f7f91STakashi Iwai 		      spec->multiout.extra_out_nid[3]);
1403352f7f91STakashi Iwai }
1404352f7f91STakashi Iwai 
1405352f7f91STakashi Iwai /* find all available DACs of the codec */
1406352f7f91STakashi Iwai static void fill_all_dac_nids(struct hda_codec *codec)
1407352f7f91STakashi Iwai {
1408352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1409352f7f91STakashi Iwai 	int i;
1410352f7f91STakashi Iwai 	hda_nid_t nid = codec->start_nid;
1411352f7f91STakashi Iwai 
1412352f7f91STakashi Iwai 	spec->num_all_dacs = 0;
1413352f7f91STakashi Iwai 	memset(spec->all_dacs, 0, sizeof(spec->all_dacs));
1414352f7f91STakashi Iwai 	for (i = 0; i < codec->num_nodes; i++, nid++) {
1415352f7f91STakashi Iwai 		if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT)
1416352f7f91STakashi Iwai 			continue;
1417352f7f91STakashi Iwai 		if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) {
1418352f7f91STakashi Iwai 			snd_printk(KERN_ERR "hda: Too many DACs!\n");
1419352f7f91STakashi Iwai 			break;
1420352f7f91STakashi Iwai 		}
1421352f7f91STakashi Iwai 		spec->all_dacs[spec->num_all_dacs++] = nid;
1422352f7f91STakashi Iwai 	}
1423352f7f91STakashi Iwai }
1424352f7f91STakashi Iwai 
1425352f7f91STakashi Iwai static int parse_output_paths(struct hda_codec *codec)
1426352f7f91STakashi Iwai {
1427352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1428352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
1429352f7f91STakashi Iwai 	struct auto_pin_cfg *best_cfg;
1430352f7f91STakashi Iwai 	int best_badness = INT_MAX;
1431352f7f91STakashi Iwai 	int badness;
1432352f7f91STakashi Iwai 	bool fill_hardwired = true, fill_mio_first = true;
1433352f7f91STakashi Iwai 	bool best_wired = true, best_mio = true;
1434352f7f91STakashi Iwai 	bool hp_spk_swapped = false;
1435352f7f91STakashi Iwai 
1436352f7f91STakashi Iwai 	fill_all_dac_nids(codec);
1437352f7f91STakashi Iwai 
1438352f7f91STakashi Iwai 	best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL);
1439352f7f91STakashi Iwai 	if (!best_cfg)
1440352f7f91STakashi Iwai 		return -ENOMEM;
1441352f7f91STakashi Iwai 	*best_cfg = *cfg;
1442352f7f91STakashi Iwai 
1443352f7f91STakashi Iwai 	for (;;) {
1444352f7f91STakashi Iwai 		badness = fill_and_eval_dacs(codec, fill_hardwired,
1445352f7f91STakashi Iwai 					     fill_mio_first);
1446352f7f91STakashi Iwai 		if (badness < 0) {
1447352f7f91STakashi Iwai 			kfree(best_cfg);
1448352f7f91STakashi Iwai 			return badness;
1449352f7f91STakashi Iwai 		}
1450352f7f91STakashi Iwai 		debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n",
1451352f7f91STakashi Iwai 			      cfg->line_out_type, fill_hardwired, fill_mio_first,
1452352f7f91STakashi Iwai 			      badness);
1453352f7f91STakashi Iwai 		debug_show_configs(spec, cfg);
1454352f7f91STakashi Iwai 		if (badness < best_badness) {
1455352f7f91STakashi Iwai 			best_badness = badness;
1456352f7f91STakashi Iwai 			*best_cfg = *cfg;
1457352f7f91STakashi Iwai 			best_wired = fill_hardwired;
1458352f7f91STakashi Iwai 			best_mio = fill_mio_first;
1459352f7f91STakashi Iwai 		}
1460352f7f91STakashi Iwai 		if (!badness)
1461352f7f91STakashi Iwai 			break;
1462352f7f91STakashi Iwai 		fill_mio_first = !fill_mio_first;
1463352f7f91STakashi Iwai 		if (!fill_mio_first)
1464352f7f91STakashi Iwai 			continue;
1465352f7f91STakashi Iwai 		fill_hardwired = !fill_hardwired;
1466352f7f91STakashi Iwai 		if (!fill_hardwired)
1467352f7f91STakashi Iwai 			continue;
1468352f7f91STakashi Iwai 		if (hp_spk_swapped)
1469352f7f91STakashi Iwai 			break;
1470352f7f91STakashi Iwai 		hp_spk_swapped = true;
1471352f7f91STakashi Iwai 		if (cfg->speaker_outs > 0 &&
1472352f7f91STakashi Iwai 		    cfg->line_out_type == AUTO_PIN_HP_OUT) {
1473352f7f91STakashi Iwai 			cfg->hp_outs = cfg->line_outs;
1474352f7f91STakashi Iwai 			memcpy(cfg->hp_pins, cfg->line_out_pins,
1475352f7f91STakashi Iwai 			       sizeof(cfg->hp_pins));
1476352f7f91STakashi Iwai 			cfg->line_outs = cfg->speaker_outs;
1477352f7f91STakashi Iwai 			memcpy(cfg->line_out_pins, cfg->speaker_pins,
1478352f7f91STakashi Iwai 			       sizeof(cfg->speaker_pins));
1479352f7f91STakashi Iwai 			cfg->speaker_outs = 0;
1480352f7f91STakashi Iwai 			memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
1481352f7f91STakashi Iwai 			cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
1482352f7f91STakashi Iwai 			fill_hardwired = true;
1483352f7f91STakashi Iwai 			continue;
1484352f7f91STakashi Iwai 		}
1485352f7f91STakashi Iwai 		if (cfg->hp_outs > 0 &&
1486352f7f91STakashi Iwai 		    cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
1487352f7f91STakashi Iwai 			cfg->speaker_outs = cfg->line_outs;
1488352f7f91STakashi Iwai 			memcpy(cfg->speaker_pins, cfg->line_out_pins,
1489352f7f91STakashi Iwai 			       sizeof(cfg->speaker_pins));
1490352f7f91STakashi Iwai 			cfg->line_outs = cfg->hp_outs;
1491352f7f91STakashi Iwai 			memcpy(cfg->line_out_pins, cfg->hp_pins,
1492352f7f91STakashi Iwai 			       sizeof(cfg->hp_pins));
1493352f7f91STakashi Iwai 			cfg->hp_outs = 0;
1494352f7f91STakashi Iwai 			memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
1495352f7f91STakashi Iwai 			cfg->line_out_type = AUTO_PIN_HP_OUT;
1496352f7f91STakashi Iwai 			fill_hardwired = true;
1497352f7f91STakashi Iwai 			continue;
1498352f7f91STakashi Iwai 		}
1499352f7f91STakashi Iwai 		break;
1500352f7f91STakashi Iwai 	}
1501352f7f91STakashi Iwai 
1502352f7f91STakashi Iwai 	if (badness) {
15030c8c0f56STakashi Iwai 		debug_badness("==> restoring best_cfg\n");
1504352f7f91STakashi Iwai 		*cfg = *best_cfg;
1505352f7f91STakashi Iwai 		fill_and_eval_dacs(codec, best_wired, best_mio);
1506352f7f91STakashi Iwai 	}
1507352f7f91STakashi Iwai 	debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n",
1508352f7f91STakashi Iwai 		      cfg->line_out_type, best_wired, best_mio);
1509352f7f91STakashi Iwai 	debug_show_configs(spec, cfg);
1510352f7f91STakashi Iwai 
1511352f7f91STakashi Iwai 	if (cfg->line_out_pins[0]) {
1512352f7f91STakashi Iwai 		struct nid_path *path;
1513196c1766STakashi Iwai 		path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]);
1514352f7f91STakashi Iwai 		if (path)
1515352f7f91STakashi Iwai 			spec->vmaster_nid = look_for_out_vol_nid(codec, path);
1516352f7f91STakashi Iwai 	}
1517352f7f91STakashi Iwai 
1518352f7f91STakashi Iwai 	kfree(best_cfg);
1519352f7f91STakashi Iwai 	return 0;
1520352f7f91STakashi Iwai }
1521352f7f91STakashi Iwai 
1522352f7f91STakashi Iwai /* add playback controls from the parsed DAC table */
1523352f7f91STakashi Iwai static int create_multi_out_ctls(struct hda_codec *codec,
1524352f7f91STakashi Iwai 				 const struct auto_pin_cfg *cfg)
1525352f7f91STakashi Iwai {
1526352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1527352f7f91STakashi Iwai 	int i, err, noutputs;
1528352f7f91STakashi Iwai 
1529352f7f91STakashi Iwai 	noutputs = cfg->line_outs;
1530352f7f91STakashi Iwai 	if (spec->multi_ios > 0 && cfg->line_outs < 3)
1531352f7f91STakashi Iwai 		noutputs += spec->multi_ios;
1532352f7f91STakashi Iwai 
1533352f7f91STakashi Iwai 	for (i = 0; i < noutputs; i++) {
1534352f7f91STakashi Iwai 		const char *name;
1535352f7f91STakashi Iwai 		int index;
1536352f7f91STakashi Iwai 		struct nid_path *path;
1537352f7f91STakashi Iwai 
1538352f7f91STakashi Iwai 		if (i >= cfg->line_outs) {
1539352f7f91STakashi Iwai 			index = 0;
1540352f7f91STakashi Iwai 			name = channel_name[i];
1541352f7f91STakashi Iwai 		} else {
1542352f7f91STakashi Iwai 			name = get_line_out_pfx(spec, i, true, &index);
1543352f7f91STakashi Iwai 		}
1544352f7f91STakashi Iwai 
1545196c1766STakashi Iwai 		path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]);
1546352f7f91STakashi Iwai 		if (!path)
1547352f7f91STakashi Iwai 			continue;
1548352f7f91STakashi Iwai 		if (!name || !strcmp(name, "CLFE")) {
1549352f7f91STakashi Iwai 			/* Center/LFE */
1550352f7f91STakashi Iwai 			err = add_vol_ctl(codec, "Center", 0, 1, path);
1551352f7f91STakashi Iwai 			if (err < 0)
1552352f7f91STakashi Iwai 				return err;
1553352f7f91STakashi Iwai 			err = add_vol_ctl(codec, "LFE", 0, 2, path);
1554352f7f91STakashi Iwai 			if (err < 0)
1555352f7f91STakashi Iwai 				return err;
1556352f7f91STakashi Iwai 			err = add_sw_ctl(codec, "Center", 0, 1, path);
1557352f7f91STakashi Iwai 			if (err < 0)
1558352f7f91STakashi Iwai 				return err;
1559352f7f91STakashi Iwai 			err = add_sw_ctl(codec, "LFE", 0, 2, path);
1560352f7f91STakashi Iwai 			if (err < 0)
1561352f7f91STakashi Iwai 				return err;
1562352f7f91STakashi Iwai 		} else {
1563352f7f91STakashi Iwai 			err = add_stereo_vol(codec, name, index, path);
1564352f7f91STakashi Iwai 			if (err < 0)
1565352f7f91STakashi Iwai 				return err;
1566352f7f91STakashi Iwai 			err = add_stereo_sw(codec, name, index, path);
1567352f7f91STakashi Iwai 			if (err < 0)
1568352f7f91STakashi Iwai 				return err;
1569352f7f91STakashi Iwai 		}
1570352f7f91STakashi Iwai 	}
1571352f7f91STakashi Iwai 	return 0;
1572352f7f91STakashi Iwai }
1573352f7f91STakashi Iwai 
1574c2c80383STakashi Iwai static int create_extra_out(struct hda_codec *codec, int path_idx,
1575196c1766STakashi Iwai 			    const char *pfx, int cidx)
1576352f7f91STakashi Iwai {
1577352f7f91STakashi Iwai 	struct nid_path *path;
1578352f7f91STakashi Iwai 	int err;
1579352f7f91STakashi Iwai 
1580196c1766STakashi Iwai 	path = snd_hda_get_path_from_idx(codec, path_idx);
1581352f7f91STakashi Iwai 	if (!path)
1582352f7f91STakashi Iwai 		return 0;
1583352f7f91STakashi Iwai 	err = add_stereo_vol(codec, pfx, cidx, path);
1584352f7f91STakashi Iwai 	if (err < 0)
1585352f7f91STakashi Iwai 		return err;
1586352f7f91STakashi Iwai 	err = add_stereo_sw(codec, pfx, cidx, path);
1587352f7f91STakashi Iwai 	if (err < 0)
1588352f7f91STakashi Iwai 		return err;
1589352f7f91STakashi Iwai 	return 0;
1590352f7f91STakashi Iwai }
1591352f7f91STakashi Iwai 
1592352f7f91STakashi Iwai /* add playback controls for speaker and HP outputs */
1593352f7f91STakashi Iwai static int create_extra_outs(struct hda_codec *codec, int num_pins,
1594196c1766STakashi Iwai 			     const int *paths, const char *pfx)
1595352f7f91STakashi Iwai {
1596c2c80383STakashi Iwai 	int i;
1597352f7f91STakashi Iwai 
1598352f7f91STakashi Iwai 	for (i = 0; i < num_pins; i++) {
1599c2c80383STakashi Iwai 		const char *name;
1600c2c80383STakashi Iwai 		char tmp[44];
1601c2c80383STakashi Iwai 		int err, idx = 0;
1602c2c80383STakashi Iwai 
1603c2c80383STakashi Iwai 		if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker"))
1604c2c80383STakashi Iwai 			name = "Bass Speaker";
1605c2c80383STakashi Iwai 		else if (num_pins >= 3) {
1606c2c80383STakashi Iwai 			snprintf(tmp, sizeof(tmp), "%s %s",
1607352f7f91STakashi Iwai 				 pfx, channel_name[i]);
1608c2c80383STakashi Iwai 			name = tmp;
1609352f7f91STakashi Iwai 		} else {
1610c2c80383STakashi Iwai 			name = pfx;
1611c2c80383STakashi Iwai 			idx = i;
1612352f7f91STakashi Iwai 		}
1613c2c80383STakashi Iwai 		err = create_extra_out(codec, paths[i], name, idx);
1614352f7f91STakashi Iwai 		if (err < 0)
1615352f7f91STakashi Iwai 			return err;
1616352f7f91STakashi Iwai 	}
1617352f7f91STakashi Iwai 	return 0;
1618352f7f91STakashi Iwai }
1619352f7f91STakashi Iwai 
1620352f7f91STakashi Iwai static int create_hp_out_ctls(struct hda_codec *codec)
1621352f7f91STakashi Iwai {
1622352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1623352f7f91STakashi Iwai 	return create_extra_outs(codec, spec->autocfg.hp_outs,
1624196c1766STakashi Iwai 				 spec->hp_paths,
1625352f7f91STakashi Iwai 				 "Headphone");
1626352f7f91STakashi Iwai }
1627352f7f91STakashi Iwai 
1628352f7f91STakashi Iwai static int create_speaker_out_ctls(struct hda_codec *codec)
1629352f7f91STakashi Iwai {
1630352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1631352f7f91STakashi Iwai 	return create_extra_outs(codec, spec->autocfg.speaker_outs,
1632196c1766STakashi Iwai 				 spec->speaker_paths,
1633352f7f91STakashi Iwai 				 "Speaker");
1634352f7f91STakashi Iwai }
1635352f7f91STakashi Iwai 
1636352f7f91STakashi Iwai /*
163738cf6f1aSTakashi Iwai  * independent HP controls
163838cf6f1aSTakashi Iwai  */
163938cf6f1aSTakashi Iwai 
164038cf6f1aSTakashi Iwai static int indep_hp_info(struct snd_kcontrol *kcontrol,
164138cf6f1aSTakashi Iwai 			 struct snd_ctl_elem_info *uinfo)
164238cf6f1aSTakashi Iwai {
164338cf6f1aSTakashi Iwai 	return snd_hda_enum_bool_helper_info(kcontrol, uinfo);
164438cf6f1aSTakashi Iwai }
164538cf6f1aSTakashi Iwai 
164638cf6f1aSTakashi Iwai static int indep_hp_get(struct snd_kcontrol *kcontrol,
164738cf6f1aSTakashi Iwai 			struct snd_ctl_elem_value *ucontrol)
164838cf6f1aSTakashi Iwai {
164938cf6f1aSTakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
165038cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
165138cf6f1aSTakashi Iwai 	ucontrol->value.enumerated.item[0] = spec->indep_hp_enabled;
165238cf6f1aSTakashi Iwai 	return 0;
165338cf6f1aSTakashi Iwai }
165438cf6f1aSTakashi Iwai 
165538cf6f1aSTakashi Iwai static int indep_hp_put(struct snd_kcontrol *kcontrol,
165638cf6f1aSTakashi Iwai 			struct snd_ctl_elem_value *ucontrol)
165738cf6f1aSTakashi Iwai {
165838cf6f1aSTakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
165938cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
166038cf6f1aSTakashi Iwai 	unsigned int select = ucontrol->value.enumerated.item[0];
166138cf6f1aSTakashi Iwai 	int ret = 0;
166238cf6f1aSTakashi Iwai 
166338cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
166438cf6f1aSTakashi Iwai 	if (spec->active_streams) {
166538cf6f1aSTakashi Iwai 		ret = -EBUSY;
166638cf6f1aSTakashi Iwai 		goto unlock;
166738cf6f1aSTakashi Iwai 	}
166838cf6f1aSTakashi Iwai 
166938cf6f1aSTakashi Iwai 	if (spec->indep_hp_enabled != select) {
167038cf6f1aSTakashi Iwai 		spec->indep_hp_enabled = select;
167138cf6f1aSTakashi Iwai 		if (spec->indep_hp_enabled)
167238cf6f1aSTakashi Iwai 			spec->multiout.hp_out_nid[0] = 0;
167338cf6f1aSTakashi Iwai 		else
167438cf6f1aSTakashi Iwai 			spec->multiout.hp_out_nid[0] = spec->alt_dac_nid;
167538cf6f1aSTakashi Iwai 		ret = 1;
167638cf6f1aSTakashi Iwai 	}
167738cf6f1aSTakashi Iwai  unlock:
167838cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
167938cf6f1aSTakashi Iwai 	return ret;
168038cf6f1aSTakashi Iwai }
168138cf6f1aSTakashi Iwai 
168238cf6f1aSTakashi Iwai static const struct snd_kcontrol_new indep_hp_ctl = {
168338cf6f1aSTakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
168438cf6f1aSTakashi Iwai 	.name = "Independent HP",
168538cf6f1aSTakashi Iwai 	.info = indep_hp_info,
168638cf6f1aSTakashi Iwai 	.get = indep_hp_get,
168738cf6f1aSTakashi Iwai 	.put = indep_hp_put,
168838cf6f1aSTakashi Iwai };
168938cf6f1aSTakashi Iwai 
169038cf6f1aSTakashi Iwai 
169138cf6f1aSTakashi Iwai static int create_indep_hp_ctls(struct hda_codec *codec)
169238cf6f1aSTakashi Iwai {
169338cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
169438cf6f1aSTakashi Iwai 
169538cf6f1aSTakashi Iwai 	if (!spec->indep_hp)
169638cf6f1aSTakashi Iwai 		return 0;
169738cf6f1aSTakashi Iwai 	if (!spec->multiout.hp_out_nid[0]) {
169838cf6f1aSTakashi Iwai 		spec->indep_hp = 0;
169938cf6f1aSTakashi Iwai 		return 0;
170038cf6f1aSTakashi Iwai 	}
170138cf6f1aSTakashi Iwai 
170238cf6f1aSTakashi Iwai 	spec->indep_hp_enabled = false;
170338cf6f1aSTakashi Iwai 	spec->alt_dac_nid = spec->multiout.hp_out_nid[0];
170438cf6f1aSTakashi Iwai 	if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl))
170538cf6f1aSTakashi Iwai 		return -ENOMEM;
170638cf6f1aSTakashi Iwai 	return 0;
170738cf6f1aSTakashi Iwai }
170838cf6f1aSTakashi Iwai 
170938cf6f1aSTakashi Iwai /*
1710352f7f91STakashi Iwai  * channel mode enum control
1711352f7f91STakashi Iwai  */
1712352f7f91STakashi Iwai 
1713352f7f91STakashi Iwai static int ch_mode_info(struct snd_kcontrol *kcontrol,
1714352f7f91STakashi Iwai 			struct snd_ctl_elem_info *uinfo)
1715352f7f91STakashi Iwai {
1716352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1717352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1718a07a949bSTakashi Iwai 	int chs;
1719352f7f91STakashi Iwai 
1720352f7f91STakashi Iwai 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1721352f7f91STakashi Iwai 	uinfo->count = 1;
1722352f7f91STakashi Iwai 	uinfo->value.enumerated.items = spec->multi_ios + 1;
1723352f7f91STakashi Iwai 	if (uinfo->value.enumerated.item > spec->multi_ios)
1724352f7f91STakashi Iwai 		uinfo->value.enumerated.item = spec->multi_ios;
1725a07a949bSTakashi Iwai 	chs = uinfo->value.enumerated.item * 2 + spec->min_channel_count;
1726a07a949bSTakashi Iwai 	sprintf(uinfo->value.enumerated.name, "%dch", chs);
1727352f7f91STakashi Iwai 	return 0;
1728352f7f91STakashi Iwai }
1729352f7f91STakashi Iwai 
1730352f7f91STakashi Iwai static int ch_mode_get(struct snd_kcontrol *kcontrol,
1731352f7f91STakashi Iwai 		       struct snd_ctl_elem_value *ucontrol)
1732352f7f91STakashi Iwai {
1733352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1734352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1735a07a949bSTakashi Iwai 	ucontrol->value.enumerated.item[0] =
1736a07a949bSTakashi Iwai 		(spec->ext_channel_count - spec->min_channel_count) / 2;
1737352f7f91STakashi Iwai 	return 0;
1738352f7f91STakashi Iwai }
1739352f7f91STakashi Iwai 
1740196c1766STakashi Iwai static inline struct nid_path *
1741196c1766STakashi Iwai get_multiio_path(struct hda_codec *codec, int idx)
1742196c1766STakashi Iwai {
1743196c1766STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1744196c1766STakashi Iwai 	return snd_hda_get_path_from_idx(codec,
1745196c1766STakashi Iwai 		spec->out_paths[spec->autocfg.line_outs + idx]);
1746196c1766STakashi Iwai }
1747196c1766STakashi Iwai 
1748352f7f91STakashi Iwai static int set_multi_io(struct hda_codec *codec, int idx, bool output)
1749352f7f91STakashi Iwai {
1750352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1751352f7f91STakashi Iwai 	hda_nid_t nid = spec->multi_io[idx].pin;
1752352f7f91STakashi Iwai 	struct nid_path *path;
1753352f7f91STakashi Iwai 
1754196c1766STakashi Iwai 	path = get_multiio_path(codec, idx);
1755352f7f91STakashi Iwai 	if (!path)
1756352f7f91STakashi Iwai 		return -EINVAL;
1757352f7f91STakashi Iwai 
1758352f7f91STakashi Iwai 	if (path->active == output)
1759352f7f91STakashi Iwai 		return 0;
1760352f7f91STakashi Iwai 
1761352f7f91STakashi Iwai 	if (output) {
17622c12c30dSTakashi Iwai 		set_pin_target(codec, nid, PIN_OUT, true);
1763352f7f91STakashi Iwai 		snd_hda_activate_path(codec, path, true, true);
1764d5a9f1bbSTakashi Iwai 		set_pin_eapd(codec, nid, true);
1765352f7f91STakashi Iwai 	} else {
1766d5a9f1bbSTakashi Iwai 		set_pin_eapd(codec, nid, false);
1767352f7f91STakashi Iwai 		snd_hda_activate_path(codec, path, false, true);
17682c12c30dSTakashi Iwai 		set_pin_target(codec, nid, spec->multi_io[idx].ctl_in, true);
1769352f7f91STakashi Iwai 	}
1770a365fed9STakashi Iwai 
1771a365fed9STakashi Iwai 	/* update jack retasking in case it modifies any of them */
1772a365fed9STakashi Iwai 	snd_hda_gen_hp_automute(codec, NULL);
1773a365fed9STakashi Iwai 	snd_hda_gen_line_automute(codec, NULL);
1774a365fed9STakashi Iwai 	snd_hda_gen_mic_autoswitch(codec, NULL);
1775a365fed9STakashi Iwai 
1776352f7f91STakashi Iwai 	return 0;
1777352f7f91STakashi Iwai }
1778352f7f91STakashi Iwai 
1779352f7f91STakashi Iwai static int ch_mode_put(struct snd_kcontrol *kcontrol,
1780352f7f91STakashi Iwai 		       struct snd_ctl_elem_value *ucontrol)
1781352f7f91STakashi Iwai {
1782352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1783352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1784352f7f91STakashi Iwai 	int i, ch;
1785352f7f91STakashi Iwai 
1786352f7f91STakashi Iwai 	ch = ucontrol->value.enumerated.item[0];
1787352f7f91STakashi Iwai 	if (ch < 0 || ch > spec->multi_ios)
1788352f7f91STakashi Iwai 		return -EINVAL;
1789a07a949bSTakashi Iwai 	if (ch == (spec->ext_channel_count - spec->min_channel_count) / 2)
1790352f7f91STakashi Iwai 		return 0;
1791a07a949bSTakashi Iwai 	spec->ext_channel_count = ch * 2 + spec->min_channel_count;
1792352f7f91STakashi Iwai 	for (i = 0; i < spec->multi_ios; i++)
1793352f7f91STakashi Iwai 		set_multi_io(codec, i, i < ch);
1794352f7f91STakashi Iwai 	spec->multiout.max_channels = max(spec->ext_channel_count,
1795352f7f91STakashi Iwai 					  spec->const_channel_count);
1796352f7f91STakashi Iwai 	if (spec->need_dac_fix)
1797352f7f91STakashi Iwai 		spec->multiout.num_dacs = spec->multiout.max_channels / 2;
1798352f7f91STakashi Iwai 	return 1;
1799352f7f91STakashi Iwai }
1800352f7f91STakashi Iwai 
1801352f7f91STakashi Iwai static const struct snd_kcontrol_new channel_mode_enum = {
1802352f7f91STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1803352f7f91STakashi Iwai 	.name = "Channel Mode",
1804352f7f91STakashi Iwai 	.info = ch_mode_info,
1805352f7f91STakashi Iwai 	.get = ch_mode_get,
1806352f7f91STakashi Iwai 	.put = ch_mode_put,
1807352f7f91STakashi Iwai };
1808352f7f91STakashi Iwai 
1809352f7f91STakashi Iwai static int create_multi_channel_mode(struct hda_codec *codec)
1810352f7f91STakashi Iwai {
1811352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1812352f7f91STakashi Iwai 
1813352f7f91STakashi Iwai 	if (spec->multi_ios > 0) {
181412c93df6STakashi Iwai 		if (!snd_hda_gen_add_kctl(spec, NULL, &channel_mode_enum))
1815352f7f91STakashi Iwai 			return -ENOMEM;
1816352f7f91STakashi Iwai 	}
1817352f7f91STakashi Iwai 	return 0;
1818352f7f91STakashi Iwai }
1819352f7f91STakashi Iwai 
1820352f7f91STakashi Iwai /*
1821c30aa7b2STakashi Iwai  * aamix loopback enable/disable switch
1822c30aa7b2STakashi Iwai  */
1823c30aa7b2STakashi Iwai 
1824c30aa7b2STakashi Iwai #define loopback_mixing_info	indep_hp_info
1825c30aa7b2STakashi Iwai 
1826c30aa7b2STakashi Iwai static int loopback_mixing_get(struct snd_kcontrol *kcontrol,
1827c30aa7b2STakashi Iwai 			       struct snd_ctl_elem_value *ucontrol)
1828c30aa7b2STakashi Iwai {
1829c30aa7b2STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1830c30aa7b2STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1831c30aa7b2STakashi Iwai 	ucontrol->value.enumerated.item[0] = spec->aamix_mode;
1832c30aa7b2STakashi Iwai 	return 0;
1833c30aa7b2STakashi Iwai }
1834c30aa7b2STakashi Iwai 
1835c30aa7b2STakashi Iwai static void update_aamix_paths(struct hda_codec *codec, bool do_mix,
1836c30aa7b2STakashi Iwai 			       int nomix_path_idx, int mix_path_idx)
1837c30aa7b2STakashi Iwai {
1838c30aa7b2STakashi Iwai 	struct nid_path *nomix_path, *mix_path;
1839c30aa7b2STakashi Iwai 
1840c30aa7b2STakashi Iwai 	nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx);
1841c30aa7b2STakashi Iwai 	mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx);
1842c30aa7b2STakashi Iwai 	if (!nomix_path || !mix_path)
1843c30aa7b2STakashi Iwai 		return;
1844c30aa7b2STakashi Iwai 	if (do_mix) {
1845c30aa7b2STakashi Iwai 		snd_hda_activate_path(codec, nomix_path, false, true);
1846c30aa7b2STakashi Iwai 		snd_hda_activate_path(codec, mix_path, true, true);
1847c30aa7b2STakashi Iwai 	} else {
1848c30aa7b2STakashi Iwai 		snd_hda_activate_path(codec, mix_path, false, true);
1849c30aa7b2STakashi Iwai 		snd_hda_activate_path(codec, nomix_path, true, true);
1850c30aa7b2STakashi Iwai 	}
1851c30aa7b2STakashi Iwai }
1852c30aa7b2STakashi Iwai 
1853c30aa7b2STakashi Iwai static int loopback_mixing_put(struct snd_kcontrol *kcontrol,
1854c30aa7b2STakashi Iwai 			       struct snd_ctl_elem_value *ucontrol)
1855c30aa7b2STakashi Iwai {
1856c30aa7b2STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1857c30aa7b2STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1858c30aa7b2STakashi Iwai 	unsigned int val = ucontrol->value.enumerated.item[0];
1859c30aa7b2STakashi Iwai 
1860c30aa7b2STakashi Iwai 	if (val == spec->aamix_mode)
1861c30aa7b2STakashi Iwai 		return 0;
1862c30aa7b2STakashi Iwai 	spec->aamix_mode = val;
1863c30aa7b2STakashi Iwai 	update_aamix_paths(codec, val, spec->out_paths[0],
1864c30aa7b2STakashi Iwai 			   spec->aamix_out_paths[0]);
1865c30aa7b2STakashi Iwai 	update_aamix_paths(codec, val, spec->hp_paths[0],
1866c30aa7b2STakashi Iwai 			   spec->aamix_out_paths[1]);
1867c30aa7b2STakashi Iwai 	update_aamix_paths(codec, val, spec->speaker_paths[0],
1868c30aa7b2STakashi Iwai 			   spec->aamix_out_paths[2]);
1869c30aa7b2STakashi Iwai 	return 1;
1870c30aa7b2STakashi Iwai }
1871c30aa7b2STakashi Iwai 
1872c30aa7b2STakashi Iwai static const struct snd_kcontrol_new loopback_mixing_enum = {
1873c30aa7b2STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1874c30aa7b2STakashi Iwai 	.name = "Loopback Mixing",
1875c30aa7b2STakashi Iwai 	.info = loopback_mixing_info,
1876c30aa7b2STakashi Iwai 	.get = loopback_mixing_get,
1877c30aa7b2STakashi Iwai 	.put = loopback_mixing_put,
1878c30aa7b2STakashi Iwai };
1879c30aa7b2STakashi Iwai 
1880c30aa7b2STakashi Iwai static int create_loopback_mixing_ctl(struct hda_codec *codec)
1881c30aa7b2STakashi Iwai {
1882c30aa7b2STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1883c30aa7b2STakashi Iwai 
1884c30aa7b2STakashi Iwai 	if (!spec->mixer_nid)
1885c30aa7b2STakashi Iwai 		return 0;
1886c30aa7b2STakashi Iwai 	if (!(spec->aamix_out_paths[0] || spec->aamix_out_paths[1] ||
1887c30aa7b2STakashi Iwai 	      spec->aamix_out_paths[2]))
1888c30aa7b2STakashi Iwai 		return 0;
1889c30aa7b2STakashi Iwai 	if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum))
1890c30aa7b2STakashi Iwai 		return -ENOMEM;
1891c30aa7b2STakashi Iwai 	return 0;
1892c30aa7b2STakashi Iwai }
1893c30aa7b2STakashi Iwai 
1894c30aa7b2STakashi Iwai /*
1895352f7f91STakashi Iwai  * shared headphone/mic handling
1896352f7f91STakashi Iwai  */
1897352f7f91STakashi Iwai 
1898352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec);
1899352f7f91STakashi Iwai 
1900352f7f91STakashi Iwai /* for shared I/O, change the pin-control accordingly */
1901352f7f91STakashi Iwai static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic)
1902352f7f91STakashi Iwai {
1903352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1904352f7f91STakashi Iwai 	unsigned int val;
1905352f7f91STakashi Iwai 	hda_nid_t pin = spec->autocfg.inputs[1].pin;
1906352f7f91STakashi Iwai 	/* NOTE: this assumes that there are only two inputs, the
1907352f7f91STakashi Iwai 	 * first is the real internal mic and the second is HP/mic jack.
1908352f7f91STakashi Iwai 	 */
1909352f7f91STakashi Iwai 
1910352f7f91STakashi Iwai 	val = snd_hda_get_default_vref(codec, pin);
1911352f7f91STakashi Iwai 
1912352f7f91STakashi Iwai 	/* This pin does not have vref caps - let's enable vref on pin 0x18
1913352f7f91STakashi Iwai 	   instead, as suggested by Realtek */
1914352f7f91STakashi Iwai 	if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) {
1915352f7f91STakashi Iwai 		const hda_nid_t vref_pin = spec->shared_mic_vref_pin;
1916352f7f91STakashi Iwai 		unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin);
1917352f7f91STakashi Iwai 		if (vref_val != AC_PINCTL_VREF_HIZ)
19187594aa33STakashi Iwai 			snd_hda_set_pin_ctl_cache(codec, vref_pin,
19197594aa33STakashi Iwai 					PIN_IN | (set_as_mic ? vref_val : 0));
1920352f7f91STakashi Iwai 	}
1921352f7f91STakashi Iwai 
1922352f7f91STakashi Iwai 	val = set_as_mic ? val | PIN_IN : PIN_HP;
19232c12c30dSTakashi Iwai 	set_pin_target(codec, pin, val, true);
1924352f7f91STakashi Iwai 
1925352f7f91STakashi Iwai 	spec->automute_speaker = !set_as_mic;
1926352f7f91STakashi Iwai 	call_update_outputs(codec);
1927352f7f91STakashi Iwai }
1928352f7f91STakashi Iwai 
1929352f7f91STakashi Iwai /* create a shared input with the headphone out */
1930352f7f91STakashi Iwai static int create_shared_input(struct hda_codec *codec)
1931352f7f91STakashi Iwai {
1932352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1933352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
1934352f7f91STakashi Iwai 	unsigned int defcfg;
1935352f7f91STakashi Iwai 	hda_nid_t nid;
1936352f7f91STakashi Iwai 
1937352f7f91STakashi Iwai 	/* only one internal input pin? */
1938352f7f91STakashi Iwai 	if (cfg->num_inputs != 1)
1939352f7f91STakashi Iwai 		return 0;
1940352f7f91STakashi Iwai 	defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin);
1941352f7f91STakashi Iwai 	if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT)
1942352f7f91STakashi Iwai 		return 0;
1943352f7f91STakashi Iwai 
1944352f7f91STakashi Iwai 	if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
1945352f7f91STakashi Iwai 		nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */
1946352f7f91STakashi Iwai 	else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT)
1947352f7f91STakashi Iwai 		nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */
1948352f7f91STakashi Iwai 	else
1949352f7f91STakashi Iwai 		return 0; /* both not available */
1950352f7f91STakashi Iwai 
1951352f7f91STakashi Iwai 	if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN))
1952352f7f91STakashi Iwai 		return 0; /* no input */
1953352f7f91STakashi Iwai 
1954352f7f91STakashi Iwai 	cfg->inputs[1].pin = nid;
1955352f7f91STakashi Iwai 	cfg->inputs[1].type = AUTO_PIN_MIC;
1956352f7f91STakashi Iwai 	cfg->num_inputs = 2;
1957352f7f91STakashi Iwai 	spec->shared_mic_hp = 1;
1958352f7f91STakashi Iwai 	snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid);
1959352f7f91STakashi Iwai 	return 0;
1960352f7f91STakashi Iwai }
1961352f7f91STakashi Iwai 
1962352f7f91STakashi Iwai 
1963352f7f91STakashi Iwai /*
1964352f7f91STakashi Iwai  * Parse input paths
1965352f7f91STakashi Iwai  */
1966352f7f91STakashi Iwai 
1967352f7f91STakashi Iwai #ifdef CONFIG_PM
1968352f7f91STakashi Iwai /* add the powersave loopback-list entry */
1969352f7f91STakashi Iwai static void add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx)
1970352f7f91STakashi Iwai {
1971352f7f91STakashi Iwai 	struct hda_amp_list *list;
1972352f7f91STakashi Iwai 
1973352f7f91STakashi Iwai 	if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1)
1974352f7f91STakashi Iwai 		return;
1975352f7f91STakashi Iwai 	list = spec->loopback_list + spec->num_loopbacks;
1976352f7f91STakashi Iwai 	list->nid = mix;
1977352f7f91STakashi Iwai 	list->dir = HDA_INPUT;
1978352f7f91STakashi Iwai 	list->idx = idx;
1979352f7f91STakashi Iwai 	spec->num_loopbacks++;
1980cb53c626STakashi Iwai 	spec->loopback.amplist = spec->loopback_list;
1981cb53c626STakashi Iwai }
1982cb53c626STakashi Iwai #else
1983352f7f91STakashi Iwai #define add_loopback_list(spec, mix, idx) /* NOP */
1984cb53c626STakashi Iwai #endif
1985cb53c626STakashi Iwai 
1986352f7f91STakashi Iwai /* create input playback/capture controls for the given pin */
1987196c1766STakashi Iwai static int new_analog_input(struct hda_codec *codec, int input_idx,
1988196c1766STakashi Iwai 			    hda_nid_t pin, const char *ctlname, int ctlidx,
1989352f7f91STakashi Iwai 			    hda_nid_t mix_nid)
19901da177e4SLinus Torvalds {
1991352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
1992352f7f91STakashi Iwai 	struct nid_path *path;
1993352f7f91STakashi Iwai 	unsigned int val;
1994352f7f91STakashi Iwai 	int err, idx;
19951da177e4SLinus Torvalds 
1996352f7f91STakashi Iwai 	if (!nid_has_volume(codec, mix_nid, HDA_INPUT) &&
1997352f7f91STakashi Iwai 	    !nid_has_mute(codec, mix_nid, HDA_INPUT))
1998352f7f91STakashi Iwai 		return 0; /* no need for analog loopback */
1999352f7f91STakashi Iwai 
20003ca529d3STakashi Iwai 	path = snd_hda_add_new_path(codec, pin, mix_nid, 0);
2001352f7f91STakashi Iwai 	if (!path)
2002352f7f91STakashi Iwai 		return -EINVAL;
20030c8c0f56STakashi Iwai 	print_nid_path("loopback", path);
2004196c1766STakashi Iwai 	spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path);
2005352f7f91STakashi Iwai 
2006352f7f91STakashi Iwai 	idx = path->idx[path->depth - 1];
2007352f7f91STakashi Iwai 	if (nid_has_volume(codec, mix_nid, HDA_INPUT)) {
2008352f7f91STakashi Iwai 		val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
2009352f7f91STakashi Iwai 		err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, val);
2010d13bd412STakashi Iwai 		if (err < 0)
20111da177e4SLinus Torvalds 			return err;
2012352f7f91STakashi Iwai 		path->ctls[NID_PATH_VOL_CTL] = val;
20131da177e4SLinus Torvalds 	}
20141da177e4SLinus Torvalds 
2015352f7f91STakashi Iwai 	if (nid_has_mute(codec, mix_nid, HDA_INPUT)) {
2016352f7f91STakashi Iwai 		val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
2017352f7f91STakashi Iwai 		err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, val);
2018d13bd412STakashi Iwai 		if (err < 0)
20191da177e4SLinus Torvalds 			return err;
2020352f7f91STakashi Iwai 		path->ctls[NID_PATH_MUTE_CTL] = val;
20211da177e4SLinus Torvalds 	}
20221da177e4SLinus Torvalds 
2023352f7f91STakashi Iwai 	path->active = true;
2024352f7f91STakashi Iwai 	add_loopback_list(spec, mix_nid, idx);
2025352f7f91STakashi Iwai 	return 0;
20261da177e4SLinus Torvalds }
20271da177e4SLinus Torvalds 
2028352f7f91STakashi Iwai static int is_input_pin(struct hda_codec *codec, hda_nid_t nid)
20291da177e4SLinus Torvalds {
2030352f7f91STakashi Iwai 	unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
2031352f7f91STakashi Iwai 	return (pincap & AC_PINCAP_IN) != 0;
2032352f7f91STakashi Iwai }
2033352f7f91STakashi Iwai 
2034352f7f91STakashi Iwai /* Parse the codec tree and retrieve ADCs */
2035352f7f91STakashi Iwai static int fill_adc_nids(struct hda_codec *codec)
2036352f7f91STakashi Iwai {
2037352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2038352f7f91STakashi Iwai 	hda_nid_t nid;
2039352f7f91STakashi Iwai 	hda_nid_t *adc_nids = spec->adc_nids;
2040352f7f91STakashi Iwai 	int max_nums = ARRAY_SIZE(spec->adc_nids);
2041352f7f91STakashi Iwai 	int i, nums = 0;
2042352f7f91STakashi Iwai 
2043352f7f91STakashi Iwai 	nid = codec->start_nid;
2044352f7f91STakashi Iwai 	for (i = 0; i < codec->num_nodes; i++, nid++) {
2045352f7f91STakashi Iwai 		unsigned int caps = get_wcaps(codec, nid);
2046352f7f91STakashi Iwai 		int type = get_wcaps_type(caps);
2047352f7f91STakashi Iwai 
2048352f7f91STakashi Iwai 		if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL))
2049352f7f91STakashi Iwai 			continue;
2050352f7f91STakashi Iwai 		adc_nids[nums] = nid;
2051352f7f91STakashi Iwai 		if (++nums >= max_nums)
2052352f7f91STakashi Iwai 			break;
2053352f7f91STakashi Iwai 	}
2054352f7f91STakashi Iwai 	spec->num_adc_nids = nums;
2055352f7f91STakashi Iwai 	return nums;
2056352f7f91STakashi Iwai }
2057352f7f91STakashi Iwai 
2058352f7f91STakashi Iwai /* filter out invalid adc_nids that don't give all active input pins;
2059352f7f91STakashi Iwai  * if needed, check whether dynamic ADC-switching is available
2060352f7f91STakashi Iwai  */
2061352f7f91STakashi Iwai static int check_dyn_adc_switch(struct hda_codec *codec)
2062352f7f91STakashi Iwai {
2063352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2064352f7f91STakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
20653a65bcdcSTakashi Iwai 	unsigned int ok_bits;
2066352f7f91STakashi Iwai 	int i, n, nums;
2067352f7f91STakashi Iwai 
2068352f7f91STakashi Iwai  again:
2069352f7f91STakashi Iwai 	nums = 0;
20703a65bcdcSTakashi Iwai 	ok_bits = 0;
2071352f7f91STakashi Iwai 	for (n = 0; n < spec->num_adc_nids; n++) {
2072352f7f91STakashi Iwai 		for (i = 0; i < imux->num_items; i++) {
20733a65bcdcSTakashi Iwai 			if (!spec->input_paths[i][n])
2074352f7f91STakashi Iwai 				break;
2075352f7f91STakashi Iwai 		}
20763a65bcdcSTakashi Iwai 		if (i >= imux->num_items) {
20773a65bcdcSTakashi Iwai 			ok_bits |= (1 << n);
20783a65bcdcSTakashi Iwai 			nums++;
20793a65bcdcSTakashi Iwai 		}
2080352f7f91STakashi Iwai 	}
2081352f7f91STakashi Iwai 
20823a65bcdcSTakashi Iwai 	if (!ok_bits) {
2083352f7f91STakashi Iwai 		if (spec->shared_mic_hp) {
2084352f7f91STakashi Iwai 			spec->shared_mic_hp = 0;
2085352f7f91STakashi Iwai 			imux->num_items = 1;
2086352f7f91STakashi Iwai 			goto again;
2087352f7f91STakashi Iwai 		}
2088352f7f91STakashi Iwai 
2089352f7f91STakashi Iwai 		/* check whether ADC-switch is possible */
2090352f7f91STakashi Iwai 		for (i = 0; i < imux->num_items; i++) {
2091352f7f91STakashi Iwai 			for (n = 0; n < spec->num_adc_nids; n++) {
20923a65bcdcSTakashi Iwai 				if (spec->input_paths[i][n]) {
2093352f7f91STakashi Iwai 					spec->dyn_adc_idx[i] = n;
2094352f7f91STakashi Iwai 					break;
2095352f7f91STakashi Iwai 				}
2096352f7f91STakashi Iwai 			}
2097352f7f91STakashi Iwai 		}
2098352f7f91STakashi Iwai 
2099352f7f91STakashi Iwai 		snd_printdd("hda-codec: enabling ADC switching\n");
2100352f7f91STakashi Iwai 		spec->dyn_adc_switch = 1;
2101352f7f91STakashi Iwai 	} else if (nums != spec->num_adc_nids) {
21023a65bcdcSTakashi Iwai 		/* shrink the invalid adcs and input paths */
21033a65bcdcSTakashi Iwai 		nums = 0;
21043a65bcdcSTakashi Iwai 		for (n = 0; n < spec->num_adc_nids; n++) {
21053a65bcdcSTakashi Iwai 			if (!(ok_bits & (1 << n)))
21063a65bcdcSTakashi Iwai 				continue;
21073a65bcdcSTakashi Iwai 			if (n != nums) {
21083a65bcdcSTakashi Iwai 				spec->adc_nids[nums] = spec->adc_nids[n];
2109980428ceSTakashi Iwai 				for (i = 0; i < imux->num_items; i++) {
2110980428ceSTakashi Iwai 					invalidate_nid_path(codec,
2111980428ceSTakashi Iwai 						spec->input_paths[i][nums]);
21123a65bcdcSTakashi Iwai 					spec->input_paths[i][nums] =
21133a65bcdcSTakashi Iwai 						spec->input_paths[i][n];
21143a65bcdcSTakashi Iwai 				}
2115980428ceSTakashi Iwai 			}
21163a65bcdcSTakashi Iwai 			nums++;
21173a65bcdcSTakashi Iwai 		}
2118352f7f91STakashi Iwai 		spec->num_adc_nids = nums;
2119352f7f91STakashi Iwai 	}
2120352f7f91STakashi Iwai 
2121352f7f91STakashi Iwai 	if (imux->num_items == 1 || spec->shared_mic_hp) {
2122352f7f91STakashi Iwai 		snd_printdd("hda-codec: reducing to a single ADC\n");
2123352f7f91STakashi Iwai 		spec->num_adc_nids = 1; /* reduce to a single ADC */
2124352f7f91STakashi Iwai 	}
2125352f7f91STakashi Iwai 
2126352f7f91STakashi Iwai 	/* single index for individual volumes ctls */
2127352f7f91STakashi Iwai 	if (!spec->dyn_adc_switch && spec->multi_cap_vol)
2128352f7f91STakashi Iwai 		spec->num_adc_nids = 1;
2129352f7f91STakashi Iwai 
21301da177e4SLinus Torvalds 	return 0;
21311da177e4SLinus Torvalds }
21321da177e4SLinus Torvalds 
2133f3fc0b0bSTakashi Iwai /* parse capture source paths from the given pin and create imux items */
2134f3fc0b0bSTakashi Iwai static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin,
2135f3fc0b0bSTakashi Iwai 				int num_adcs, const char *label, int anchor)
2136f3fc0b0bSTakashi Iwai {
2137f3fc0b0bSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2138f3fc0b0bSTakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
2139f3fc0b0bSTakashi Iwai 	int imux_idx = imux->num_items;
2140f3fc0b0bSTakashi Iwai 	bool imux_added = false;
2141f3fc0b0bSTakashi Iwai 	int c;
2142f3fc0b0bSTakashi Iwai 
2143f3fc0b0bSTakashi Iwai 	for (c = 0; c < num_adcs; c++) {
2144f3fc0b0bSTakashi Iwai 		struct nid_path *path;
2145f3fc0b0bSTakashi Iwai 		hda_nid_t adc = spec->adc_nids[c];
2146f3fc0b0bSTakashi Iwai 
2147f3fc0b0bSTakashi Iwai 		if (!is_reachable_path(codec, pin, adc))
2148f3fc0b0bSTakashi Iwai 			continue;
2149f3fc0b0bSTakashi Iwai 		path = snd_hda_add_new_path(codec, pin, adc, anchor);
2150f3fc0b0bSTakashi Iwai 		if (!path)
2151f3fc0b0bSTakashi Iwai 			continue;
2152f3fc0b0bSTakashi Iwai 		print_nid_path("input", path);
2153f3fc0b0bSTakashi Iwai 		spec->input_paths[imux_idx][c] =
2154f3fc0b0bSTakashi Iwai 			snd_hda_get_path_idx(codec, path);
2155f3fc0b0bSTakashi Iwai 
2156f3fc0b0bSTakashi Iwai 		if (!imux_added) {
2157f3fc0b0bSTakashi Iwai 			spec->imux_pins[imux->num_items] = pin;
2158f3fc0b0bSTakashi Iwai 			snd_hda_add_imux_item(imux, label,
2159f3fc0b0bSTakashi Iwai 					      imux->num_items, NULL);
2160f3fc0b0bSTakashi Iwai 			imux_added = true;
2161f3fc0b0bSTakashi Iwai 		}
2162f3fc0b0bSTakashi Iwai 	}
2163f3fc0b0bSTakashi Iwai 
2164f3fc0b0bSTakashi Iwai 	return 0;
2165f3fc0b0bSTakashi Iwai }
2166f3fc0b0bSTakashi Iwai 
21671da177e4SLinus Torvalds /*
2168352f7f91STakashi Iwai  * create playback/capture controls for input pins
21691da177e4SLinus Torvalds  */
2170352f7f91STakashi Iwai static int create_input_ctls(struct hda_codec *codec)
2171a7da6ce5STakashi Iwai {
2172352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2173352f7f91STakashi Iwai 	const struct auto_pin_cfg *cfg = &spec->autocfg;
2174352f7f91STakashi Iwai 	hda_nid_t mixer = spec->mixer_nid;
2175352f7f91STakashi Iwai 	int num_adcs;
2176f3fc0b0bSTakashi Iwai 	int i, err, type_idx = 0;
2177352f7f91STakashi Iwai 	const char *prev_label = NULL;
21782c12c30dSTakashi Iwai 	unsigned int val;
2179a7da6ce5STakashi Iwai 
2180352f7f91STakashi Iwai 	num_adcs = fill_adc_nids(codec);
2181352f7f91STakashi Iwai 	if (num_adcs < 0)
2182352f7f91STakashi Iwai 		return 0;
2183352f7f91STakashi Iwai 
2184352f7f91STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
2185352f7f91STakashi Iwai 		hda_nid_t pin;
2186352f7f91STakashi Iwai 		const char *label;
2187352f7f91STakashi Iwai 
2188352f7f91STakashi Iwai 		pin = cfg->inputs[i].pin;
2189352f7f91STakashi Iwai 		if (!is_input_pin(codec, pin))
2190352f7f91STakashi Iwai 			continue;
2191352f7f91STakashi Iwai 
2192352f7f91STakashi Iwai 		label = hda_get_autocfg_input_label(codec, cfg, i);
2193352f7f91STakashi Iwai 		if (prev_label && !strcmp(label, prev_label))
2194352f7f91STakashi Iwai 			type_idx++;
2195352f7f91STakashi Iwai 		else
2196352f7f91STakashi Iwai 			type_idx = 0;
2197352f7f91STakashi Iwai 		prev_label = label;
2198352f7f91STakashi Iwai 
21992c12c30dSTakashi Iwai 		val = PIN_IN;
22002c12c30dSTakashi Iwai 		if (cfg->inputs[i].type == AUTO_PIN_MIC)
22012c12c30dSTakashi Iwai 			val |= snd_hda_get_default_vref(codec, pin);
22022c12c30dSTakashi Iwai 		set_pin_target(codec, pin, val, false);
22032c12c30dSTakashi Iwai 
2204352f7f91STakashi Iwai 		if (mixer) {
2205352f7f91STakashi Iwai 			if (is_reachable_path(codec, pin, mixer)) {
2206196c1766STakashi Iwai 				err = new_analog_input(codec, i, pin,
2207352f7f91STakashi Iwai 						       label, type_idx, mixer);
2208a7da6ce5STakashi Iwai 				if (err < 0)
2209a7da6ce5STakashi Iwai 					return err;
2210a7da6ce5STakashi Iwai 			}
2211352f7f91STakashi Iwai 		}
2212352f7f91STakashi Iwai 
2213f3fc0b0bSTakashi Iwai 		err = parse_capture_source(codec, pin, num_adcs, label, -mixer);
2214f3fc0b0bSTakashi Iwai 		if (err < 0)
2215f3fc0b0bSTakashi Iwai 			return err;
2216352f7f91STakashi Iwai 	}
2217f3fc0b0bSTakashi Iwai 
2218f3fc0b0bSTakashi Iwai 	if (mixer && spec->add_stereo_mix_input) {
2219f3fc0b0bSTakashi Iwai 		err = parse_capture_source(codec, mixer, num_adcs,
2220f3fc0b0bSTakashi Iwai 					   "Stereo Mix", 0);
2221f3fc0b0bSTakashi Iwai 		if (err < 0)
2222f3fc0b0bSTakashi Iwai 			return err;
2223352f7f91STakashi Iwai 	}
2224352f7f91STakashi Iwai 
2225a7da6ce5STakashi Iwai 	return 0;
2226a7da6ce5STakashi Iwai }
2227a7da6ce5STakashi Iwai 
22281da177e4SLinus Torvalds 
2229352f7f91STakashi Iwai /*
2230352f7f91STakashi Iwai  * input source mux
2231352f7f91STakashi Iwai  */
2232352f7f91STakashi Iwai 
2233c697b716STakashi Iwai /* get the input path specified by the given adc and imux indices */
2234c697b716STakashi Iwai static struct nid_path *get_input_path(struct hda_codec *codec, int adc_idx, int imux_idx)
2235352f7f91STakashi Iwai {
2236352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2237352f7f91STakashi Iwai 	if (spec->dyn_adc_switch)
2238352f7f91STakashi Iwai 		adc_idx = spec->dyn_adc_idx[imux_idx];
2239c697b716STakashi Iwai 	return snd_hda_get_path_from_idx(codec, spec->input_paths[imux_idx][adc_idx]);
224097ec558aSTakashi Iwai }
2241352f7f91STakashi Iwai 
2242352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
2243352f7f91STakashi Iwai 		      unsigned int idx);
2244352f7f91STakashi Iwai 
2245352f7f91STakashi Iwai static int mux_enum_info(struct snd_kcontrol *kcontrol,
2246352f7f91STakashi Iwai 			 struct snd_ctl_elem_info *uinfo)
2247352f7f91STakashi Iwai {
2248352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2249352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2250352f7f91STakashi Iwai 	return snd_hda_input_mux_info(&spec->input_mux, uinfo);
2251352f7f91STakashi Iwai }
2252352f7f91STakashi Iwai 
2253352f7f91STakashi Iwai static int mux_enum_get(struct snd_kcontrol *kcontrol,
2254352f7f91STakashi Iwai 			struct snd_ctl_elem_value *ucontrol)
2255352f7f91STakashi Iwai {
2256352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2257352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2258352f7f91STakashi Iwai 	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2259352f7f91STakashi Iwai 
2260352f7f91STakashi Iwai 	ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
22611da177e4SLinus Torvalds 	return 0;
22621da177e4SLinus Torvalds }
22631da177e4SLinus Torvalds 
2264352f7f91STakashi Iwai static int mux_enum_put(struct snd_kcontrol *kcontrol,
2265352f7f91STakashi Iwai 			    struct snd_ctl_elem_value *ucontrol)
22661da177e4SLinus Torvalds {
2267352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2268352f7f91STakashi Iwai 	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2269352f7f91STakashi Iwai 	return mux_select(codec, adc_idx,
2270352f7f91STakashi Iwai 			  ucontrol->value.enumerated.item[0]);
2271352f7f91STakashi Iwai }
2272352f7f91STakashi Iwai 
2273352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_src_temp = {
22741da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2275352f7f91STakashi Iwai 	.name = "Input Source",
2276352f7f91STakashi Iwai 	.info = mux_enum_info,
2277352f7f91STakashi Iwai 	.get = mux_enum_get,
2278352f7f91STakashi Iwai 	.put = mux_enum_put,
22791da177e4SLinus Torvalds };
2280071c73adSTakashi Iwai 
228147d46abbSTakashi Iwai /*
228247d46abbSTakashi Iwai  * capture volume and capture switch ctls
228347d46abbSTakashi Iwai  */
228447d46abbSTakashi Iwai 
2285352f7f91STakashi Iwai typedef int (*put_call_t)(struct snd_kcontrol *kcontrol,
2286352f7f91STakashi Iwai 			  struct snd_ctl_elem_value *ucontrol);
2287071c73adSTakashi Iwai 
228847d46abbSTakashi Iwai /* call the given amp update function for all amps in the imux list at once */
2289352f7f91STakashi Iwai static int cap_put_caller(struct snd_kcontrol *kcontrol,
2290352f7f91STakashi Iwai 			  struct snd_ctl_elem_value *ucontrol,
2291352f7f91STakashi Iwai 			  put_call_t func, int type)
2292352f7f91STakashi Iwai {
2293352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2294352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2295352f7f91STakashi Iwai 	const struct hda_input_mux *imux;
2296352f7f91STakashi Iwai 	struct nid_path *path;
2297352f7f91STakashi Iwai 	int i, adc_idx, err = 0;
2298071c73adSTakashi Iwai 
2299352f7f91STakashi Iwai 	imux = &spec->input_mux;
2300352f7f91STakashi Iwai 	adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2301352f7f91STakashi Iwai 	mutex_lock(&codec->control_mutex);
230247d46abbSTakashi Iwai 	/* we use the cache-only update at first since multiple input paths
230347d46abbSTakashi Iwai 	 * may shared the same amp; by updating only caches, the redundant
230447d46abbSTakashi Iwai 	 * writes to hardware can be reduced.
230547d46abbSTakashi Iwai 	 */
2306352f7f91STakashi Iwai 	codec->cached_write = 1;
2307352f7f91STakashi Iwai 	for (i = 0; i < imux->num_items; i++) {
2308c697b716STakashi Iwai 		path = get_input_path(codec, adc_idx, i);
2309c697b716STakashi Iwai 		if (!path || !path->ctls[type])
2310352f7f91STakashi Iwai 			continue;
2311352f7f91STakashi Iwai 		kcontrol->private_value = path->ctls[type];
2312352f7f91STakashi Iwai 		err = func(kcontrol, ucontrol);
2313352f7f91STakashi Iwai 		if (err < 0)
2314352f7f91STakashi Iwai 			goto error;
2315352f7f91STakashi Iwai 	}
2316352f7f91STakashi Iwai  error:
2317352f7f91STakashi Iwai 	codec->cached_write = 0;
2318352f7f91STakashi Iwai 	mutex_unlock(&codec->control_mutex);
231947d46abbSTakashi Iwai 	snd_hda_codec_flush_amp_cache(codec); /* flush the updates */
2320352f7f91STakashi Iwai 	if (err >= 0 && spec->cap_sync_hook)
2321352f7f91STakashi Iwai 		spec->cap_sync_hook(codec);
2322352f7f91STakashi Iwai 	return err;
2323352f7f91STakashi Iwai }
2324352f7f91STakashi Iwai 
2325352f7f91STakashi Iwai /* capture volume ctl callbacks */
2326352f7f91STakashi Iwai #define cap_vol_info		snd_hda_mixer_amp_volume_info
2327352f7f91STakashi Iwai #define cap_vol_get		snd_hda_mixer_amp_volume_get
2328352f7f91STakashi Iwai #define cap_vol_tlv		snd_hda_mixer_amp_tlv
2329352f7f91STakashi Iwai 
2330352f7f91STakashi Iwai static int cap_vol_put(struct snd_kcontrol *kcontrol,
2331352f7f91STakashi Iwai 		       struct snd_ctl_elem_value *ucontrol)
2332352f7f91STakashi Iwai {
2333352f7f91STakashi Iwai 	return cap_put_caller(kcontrol, ucontrol,
2334352f7f91STakashi Iwai 			      snd_hda_mixer_amp_volume_put,
2335352f7f91STakashi Iwai 			      NID_PATH_VOL_CTL);
2336352f7f91STakashi Iwai }
2337352f7f91STakashi Iwai 
2338352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_vol_temp = {
2339352f7f91STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2340352f7f91STakashi Iwai 	.name = "Capture Volume",
2341352f7f91STakashi Iwai 	.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
2342352f7f91STakashi Iwai 		   SNDRV_CTL_ELEM_ACCESS_TLV_READ |
2343352f7f91STakashi Iwai 		   SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK),
2344352f7f91STakashi Iwai 	.info = cap_vol_info,
2345352f7f91STakashi Iwai 	.get = cap_vol_get,
2346352f7f91STakashi Iwai 	.put = cap_vol_put,
2347352f7f91STakashi Iwai 	.tlv = { .c = cap_vol_tlv },
2348352f7f91STakashi Iwai };
2349352f7f91STakashi Iwai 
2350352f7f91STakashi Iwai /* capture switch ctl callbacks */
2351352f7f91STakashi Iwai #define cap_sw_info		snd_ctl_boolean_stereo_info
2352352f7f91STakashi Iwai #define cap_sw_get		snd_hda_mixer_amp_switch_get
2353352f7f91STakashi Iwai 
2354352f7f91STakashi Iwai static int cap_sw_put(struct snd_kcontrol *kcontrol,
2355352f7f91STakashi Iwai 		      struct snd_ctl_elem_value *ucontrol)
2356352f7f91STakashi Iwai {
2357352f7f91STakashi Iwai 	return cap_put_caller(kcontrol, ucontrol,
2358352f7f91STakashi Iwai 			      snd_hda_mixer_amp_switch_put,
2359352f7f91STakashi Iwai 			      NID_PATH_MUTE_CTL);
2360352f7f91STakashi Iwai }
2361352f7f91STakashi Iwai 
2362352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_sw_temp = {
2363352f7f91STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2364352f7f91STakashi Iwai 	.name = "Capture Switch",
2365352f7f91STakashi Iwai 	.info = cap_sw_info,
2366352f7f91STakashi Iwai 	.get = cap_sw_get,
2367352f7f91STakashi Iwai 	.put = cap_sw_put,
2368352f7f91STakashi Iwai };
2369352f7f91STakashi Iwai 
2370352f7f91STakashi Iwai static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path)
2371352f7f91STakashi Iwai {
2372352f7f91STakashi Iwai 	hda_nid_t nid;
2373352f7f91STakashi Iwai 	int i, depth;
2374352f7f91STakashi Iwai 
2375352f7f91STakashi Iwai 	path->ctls[NID_PATH_VOL_CTL] = path->ctls[NID_PATH_MUTE_CTL] = 0;
2376352f7f91STakashi Iwai 	for (depth = 0; depth < 3; depth++) {
2377352f7f91STakashi Iwai 		if (depth >= path->depth)
2378352f7f91STakashi Iwai 			return -EINVAL;
2379352f7f91STakashi Iwai 		i = path->depth - depth - 1;
2380352f7f91STakashi Iwai 		nid = path->path[i];
2381352f7f91STakashi Iwai 		if (!path->ctls[NID_PATH_VOL_CTL]) {
2382352f7f91STakashi Iwai 			if (nid_has_volume(codec, nid, HDA_OUTPUT))
2383352f7f91STakashi Iwai 				path->ctls[NID_PATH_VOL_CTL] =
2384352f7f91STakashi Iwai 					HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
2385352f7f91STakashi Iwai 			else if (nid_has_volume(codec, nid, HDA_INPUT)) {
2386352f7f91STakashi Iwai 				int idx = path->idx[i];
2387352f7f91STakashi Iwai 				if (!depth && codec->single_adc_amp)
2388352f7f91STakashi Iwai 					idx = 0;
2389352f7f91STakashi Iwai 				path->ctls[NID_PATH_VOL_CTL] =
2390352f7f91STakashi Iwai 					HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT);
2391352f7f91STakashi Iwai 			}
2392352f7f91STakashi Iwai 		}
2393352f7f91STakashi Iwai 		if (!path->ctls[NID_PATH_MUTE_CTL]) {
2394352f7f91STakashi Iwai 			if (nid_has_mute(codec, nid, HDA_OUTPUT))
2395352f7f91STakashi Iwai 				path->ctls[NID_PATH_MUTE_CTL] =
2396352f7f91STakashi Iwai 					HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
2397352f7f91STakashi Iwai 			else if (nid_has_mute(codec, nid, HDA_INPUT)) {
2398352f7f91STakashi Iwai 				int idx = path->idx[i];
2399352f7f91STakashi Iwai 				if (!depth && codec->single_adc_amp)
2400352f7f91STakashi Iwai 					idx = 0;
2401352f7f91STakashi Iwai 				path->ctls[NID_PATH_MUTE_CTL] =
2402352f7f91STakashi Iwai 					HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT);
2403352f7f91STakashi Iwai 			}
2404352f7f91STakashi Iwai 		}
2405352f7f91STakashi Iwai 	}
2406352f7f91STakashi Iwai 	return 0;
2407352f7f91STakashi Iwai }
2408352f7f91STakashi Iwai 
2409352f7f91STakashi Iwai static bool is_inv_dmic_pin(struct hda_codec *codec, hda_nid_t nid)
2410352f7f91STakashi Iwai {
2411352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2412352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
2413352f7f91STakashi Iwai 	unsigned int val;
2414352f7f91STakashi Iwai 	int i;
2415352f7f91STakashi Iwai 
2416352f7f91STakashi Iwai 	if (!spec->inv_dmic_split)
2417352f7f91STakashi Iwai 		return false;
2418352f7f91STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
2419352f7f91STakashi Iwai 		if (cfg->inputs[i].pin != nid)
2420352f7f91STakashi Iwai 			continue;
2421352f7f91STakashi Iwai 		if (cfg->inputs[i].type != AUTO_PIN_MIC)
2422352f7f91STakashi Iwai 			return false;
2423352f7f91STakashi Iwai 		val = snd_hda_codec_get_pincfg(codec, nid);
2424352f7f91STakashi Iwai 		return snd_hda_get_input_pin_attr(val) == INPUT_PIN_ATTR_INT;
2425352f7f91STakashi Iwai 	}
2426352f7f91STakashi Iwai 	return false;
2427352f7f91STakashi Iwai }
2428352f7f91STakashi Iwai 
2429352f7f91STakashi Iwai static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
2430352f7f91STakashi Iwai 			      int idx, bool is_switch, unsigned int ctl,
2431352f7f91STakashi Iwai 			      bool inv_dmic)
2432352f7f91STakashi Iwai {
2433352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2434352f7f91STakashi Iwai 	char tmpname[44];
2435352f7f91STakashi Iwai 	int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL;
2436352f7f91STakashi Iwai 	const char *sfx = is_switch ? "Switch" : "Volume";
2437352f7f91STakashi Iwai 	unsigned int chs = inv_dmic ? 1 : 3;
2438352f7f91STakashi Iwai 	int err;
2439352f7f91STakashi Iwai 
2440352f7f91STakashi Iwai 	if (!ctl)
2441352f7f91STakashi Iwai 		return 0;
2442352f7f91STakashi Iwai 
2443352f7f91STakashi Iwai 	if (label)
2444352f7f91STakashi Iwai 		snprintf(tmpname, sizeof(tmpname),
2445352f7f91STakashi Iwai 			 "%s Capture %s", label, sfx);
2446352f7f91STakashi Iwai 	else
2447352f7f91STakashi Iwai 		snprintf(tmpname, sizeof(tmpname),
2448352f7f91STakashi Iwai 			 "Capture %s", sfx);
2449352f7f91STakashi Iwai 	err = add_control(spec, type, tmpname, idx,
2450352f7f91STakashi Iwai 			  amp_val_replace_channels(ctl, chs));
2451352f7f91STakashi Iwai 	if (err < 0 || !inv_dmic)
2452352f7f91STakashi Iwai 		return err;
2453352f7f91STakashi Iwai 
2454352f7f91STakashi Iwai 	/* Make independent right kcontrol */
2455352f7f91STakashi Iwai 	if (label)
2456352f7f91STakashi Iwai 		snprintf(tmpname, sizeof(tmpname),
2457352f7f91STakashi Iwai 			 "Inverted %s Capture %s", label, sfx);
2458352f7f91STakashi Iwai 	else
2459352f7f91STakashi Iwai 		snprintf(tmpname, sizeof(tmpname),
2460352f7f91STakashi Iwai 			 "Inverted Capture %s", sfx);
2461352f7f91STakashi Iwai 	return add_control(spec, type, tmpname, idx,
2462352f7f91STakashi Iwai 			   amp_val_replace_channels(ctl, 2));
2463352f7f91STakashi Iwai }
2464352f7f91STakashi Iwai 
2465352f7f91STakashi Iwai /* create single (and simple) capture volume and switch controls */
2466352f7f91STakashi Iwai static int create_single_cap_vol_ctl(struct hda_codec *codec, int idx,
2467352f7f91STakashi Iwai 				     unsigned int vol_ctl, unsigned int sw_ctl,
2468352f7f91STakashi Iwai 				     bool inv_dmic)
2469352f7f91STakashi Iwai {
2470352f7f91STakashi Iwai 	int err;
2471352f7f91STakashi Iwai 	err = add_single_cap_ctl(codec, NULL, idx, false, vol_ctl, inv_dmic);
2472352f7f91STakashi Iwai 	if (err < 0)
2473352f7f91STakashi Iwai 		return err;
2474352f7f91STakashi Iwai 	err = add_single_cap_ctl(codec, NULL, idx, true, sw_ctl, inv_dmic);
2475071c73adSTakashi Iwai 	if (err < 0)
2476071c73adSTakashi Iwai 		return err;
2477071c73adSTakashi Iwai 	return 0;
24781da177e4SLinus Torvalds }
2479071c73adSTakashi Iwai 
2480352f7f91STakashi Iwai /* create bound capture volume and switch controls */
2481352f7f91STakashi Iwai static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx,
2482352f7f91STakashi Iwai 				   unsigned int vol_ctl, unsigned int sw_ctl)
2483352f7f91STakashi Iwai {
2484352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2485352f7f91STakashi Iwai 	struct snd_kcontrol_new *knew;
2486352f7f91STakashi Iwai 
2487352f7f91STakashi Iwai 	if (vol_ctl) {
248812c93df6STakashi Iwai 		knew = snd_hda_gen_add_kctl(spec, NULL, &cap_vol_temp);
2489352f7f91STakashi Iwai 		if (!knew)
2490352f7f91STakashi Iwai 			return -ENOMEM;
2491352f7f91STakashi Iwai 		knew->index = idx;
2492352f7f91STakashi Iwai 		knew->private_value = vol_ctl;
2493352f7f91STakashi Iwai 		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
2494352f7f91STakashi Iwai 	}
2495352f7f91STakashi Iwai 	if (sw_ctl) {
249612c93df6STakashi Iwai 		knew = snd_hda_gen_add_kctl(spec, NULL, &cap_sw_temp);
2497352f7f91STakashi Iwai 		if (!knew)
2498352f7f91STakashi Iwai 			return -ENOMEM;
2499352f7f91STakashi Iwai 		knew->index = idx;
2500352f7f91STakashi Iwai 		knew->private_value = sw_ctl;
2501352f7f91STakashi Iwai 		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
2502352f7f91STakashi Iwai 	}
2503352f7f91STakashi Iwai 	return 0;
2504352f7f91STakashi Iwai }
2505352f7f91STakashi Iwai 
2506352f7f91STakashi Iwai /* return the vol ctl when used first in the imux list */
2507352f7f91STakashi Iwai static unsigned int get_first_cap_ctl(struct hda_codec *codec, int idx, int type)
2508352f7f91STakashi Iwai {
2509352f7f91STakashi Iwai 	struct nid_path *path;
2510352f7f91STakashi Iwai 	unsigned int ctl;
2511352f7f91STakashi Iwai 	int i;
2512352f7f91STakashi Iwai 
2513c697b716STakashi Iwai 	path = get_input_path(codec, 0, idx);
2514352f7f91STakashi Iwai 	if (!path)
2515352f7f91STakashi Iwai 		return 0;
2516352f7f91STakashi Iwai 	ctl = path->ctls[type];
2517352f7f91STakashi Iwai 	if (!ctl)
2518352f7f91STakashi Iwai 		return 0;
2519352f7f91STakashi Iwai 	for (i = 0; i < idx - 1; i++) {
2520c697b716STakashi Iwai 		path = get_input_path(codec, 0, i);
2521352f7f91STakashi Iwai 		if (path && path->ctls[type] == ctl)
2522352f7f91STakashi Iwai 			return 0;
2523352f7f91STakashi Iwai 	}
2524352f7f91STakashi Iwai 	return ctl;
2525352f7f91STakashi Iwai }
2526352f7f91STakashi Iwai 
2527352f7f91STakashi Iwai /* create individual capture volume and switch controls per input */
2528352f7f91STakashi Iwai static int create_multi_cap_vol_ctl(struct hda_codec *codec)
2529352f7f91STakashi Iwai {
2530352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2531352f7f91STakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
2532352f7f91STakashi Iwai 	int i, err, type, type_idx = 0;
2533352f7f91STakashi Iwai 	const char *prev_label = NULL;
2534352f7f91STakashi Iwai 
2535352f7f91STakashi Iwai 	for (i = 0; i < imux->num_items; i++) {
2536352f7f91STakashi Iwai 		const char *label;
2537352f7f91STakashi Iwai 		bool inv_dmic;
2538352f7f91STakashi Iwai 		label = hda_get_autocfg_input_label(codec, &spec->autocfg, i);
2539352f7f91STakashi Iwai 		if (prev_label && !strcmp(label, prev_label))
2540352f7f91STakashi Iwai 			type_idx++;
2541352f7f91STakashi Iwai 		else
2542352f7f91STakashi Iwai 			type_idx = 0;
2543352f7f91STakashi Iwai 		prev_label = label;
2544352f7f91STakashi Iwai 		inv_dmic = is_inv_dmic_pin(codec, spec->imux_pins[i]);
2545352f7f91STakashi Iwai 
2546352f7f91STakashi Iwai 		for (type = 0; type < 2; type++) {
2547352f7f91STakashi Iwai 			err = add_single_cap_ctl(codec, label, type_idx, type,
2548352f7f91STakashi Iwai 						 get_first_cap_ctl(codec, i, type),
2549352f7f91STakashi Iwai 						 inv_dmic);
2550d13bd412STakashi Iwai 			if (err < 0)
2551071c73adSTakashi Iwai 				return err;
2552352f7f91STakashi Iwai 		}
2553352f7f91STakashi Iwai 	}
2554071c73adSTakashi Iwai 	return 0;
2555352f7f91STakashi Iwai }
2556071c73adSTakashi Iwai 
2557352f7f91STakashi Iwai static int create_capture_mixers(struct hda_codec *codec)
2558352f7f91STakashi Iwai {
2559352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2560352f7f91STakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
2561352f7f91STakashi Iwai 	int i, n, nums, err;
2562352f7f91STakashi Iwai 
2563352f7f91STakashi Iwai 	if (spec->dyn_adc_switch)
2564352f7f91STakashi Iwai 		nums = 1;
2565352f7f91STakashi Iwai 	else
2566352f7f91STakashi Iwai 		nums = spec->num_adc_nids;
2567352f7f91STakashi Iwai 
2568352f7f91STakashi Iwai 	if (!spec->auto_mic && imux->num_items > 1) {
2569352f7f91STakashi Iwai 		struct snd_kcontrol_new *knew;
2570624d914dSTakashi Iwai 		const char *name;
2571624d914dSTakashi Iwai 		name = nums > 1 ? "Input Source" : "Capture Source";
2572624d914dSTakashi Iwai 		knew = snd_hda_gen_add_kctl(spec, name, &cap_src_temp);
2573352f7f91STakashi Iwai 		if (!knew)
2574352f7f91STakashi Iwai 			return -ENOMEM;
2575352f7f91STakashi Iwai 		knew->count = nums;
2576352f7f91STakashi Iwai 	}
2577352f7f91STakashi Iwai 
2578352f7f91STakashi Iwai 	for (n = 0; n < nums; n++) {
2579352f7f91STakashi Iwai 		bool multi = false;
2580352f7f91STakashi Iwai 		bool inv_dmic = false;
2581352f7f91STakashi Iwai 		int vol, sw;
2582352f7f91STakashi Iwai 
2583352f7f91STakashi Iwai 		vol = sw = 0;
2584352f7f91STakashi Iwai 		for (i = 0; i < imux->num_items; i++) {
2585352f7f91STakashi Iwai 			struct nid_path *path;
2586c697b716STakashi Iwai 			path = get_input_path(codec, n, i);
2587352f7f91STakashi Iwai 			if (!path)
2588352f7f91STakashi Iwai 				continue;
2589352f7f91STakashi Iwai 			parse_capvol_in_path(codec, path);
2590352f7f91STakashi Iwai 			if (!vol)
2591352f7f91STakashi Iwai 				vol = path->ctls[NID_PATH_VOL_CTL];
2592352f7f91STakashi Iwai 			else if (vol != path->ctls[NID_PATH_VOL_CTL])
2593352f7f91STakashi Iwai 				multi = true;
2594352f7f91STakashi Iwai 			if (!sw)
2595352f7f91STakashi Iwai 				sw = path->ctls[NID_PATH_MUTE_CTL];
2596352f7f91STakashi Iwai 			else if (sw != path->ctls[NID_PATH_MUTE_CTL])
2597352f7f91STakashi Iwai 				multi = true;
2598352f7f91STakashi Iwai 			if (is_inv_dmic_pin(codec, spec->imux_pins[i]))
2599352f7f91STakashi Iwai 				inv_dmic = true;
2600352f7f91STakashi Iwai 		}
2601352f7f91STakashi Iwai 
2602352f7f91STakashi Iwai 		if (!multi)
2603352f7f91STakashi Iwai 			err = create_single_cap_vol_ctl(codec, n, vol, sw,
2604352f7f91STakashi Iwai 							inv_dmic);
2605352f7f91STakashi Iwai 		else if (!spec->multi_cap_vol)
2606352f7f91STakashi Iwai 			err = create_bind_cap_vol_ctl(codec, n, vol, sw);
2607352f7f91STakashi Iwai 		else
2608352f7f91STakashi Iwai 			err = create_multi_cap_vol_ctl(codec);
2609d13bd412STakashi Iwai 		if (err < 0)
2610071c73adSTakashi Iwai 			return err;
2611071c73adSTakashi Iwai 	}
2612071c73adSTakashi Iwai 
26131da177e4SLinus Torvalds 	return 0;
26141da177e4SLinus Torvalds }
26151da177e4SLinus Torvalds 
2616352f7f91STakashi Iwai /*
2617352f7f91STakashi Iwai  * add mic boosts if needed
2618352f7f91STakashi Iwai  */
2619352f7f91STakashi Iwai static int parse_mic_boost(struct hda_codec *codec)
2620352f7f91STakashi Iwai {
2621352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2622352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
2623352f7f91STakashi Iwai 	int i, err;
2624352f7f91STakashi Iwai 	int type_idx = 0;
2625352f7f91STakashi Iwai 	hda_nid_t nid;
2626352f7f91STakashi Iwai 	const char *prev_label = NULL;
2627352f7f91STakashi Iwai 
2628352f7f91STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
2629352f7f91STakashi Iwai 		if (cfg->inputs[i].type > AUTO_PIN_MIC)
2630352f7f91STakashi Iwai 			break;
2631352f7f91STakashi Iwai 		nid = cfg->inputs[i].pin;
2632352f7f91STakashi Iwai 		if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
2633352f7f91STakashi Iwai 			const char *label;
26345abd4888STakashi Iwai 			char boost_label[44];
2635352f7f91STakashi Iwai 			struct nid_path *path;
2636352f7f91STakashi Iwai 			unsigned int val;
2637352f7f91STakashi Iwai 
2638352f7f91STakashi Iwai 			label = hda_get_autocfg_input_label(codec, cfg, i);
2639352f7f91STakashi Iwai 			if (prev_label && !strcmp(label, prev_label))
2640352f7f91STakashi Iwai 				type_idx++;
2641352f7f91STakashi Iwai 			else
2642352f7f91STakashi Iwai 				type_idx = 0;
2643352f7f91STakashi Iwai 			prev_label = label;
2644352f7f91STakashi Iwai 
2645352f7f91STakashi Iwai 			snprintf(boost_label, sizeof(boost_label),
2646352f7f91STakashi Iwai 				 "%s Boost Volume", label);
2647352f7f91STakashi Iwai 			val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT);
2648352f7f91STakashi Iwai 			err = add_control(spec, HDA_CTL_WIDGET_VOL,
2649352f7f91STakashi Iwai 					  boost_label, type_idx, val);
2650352f7f91STakashi Iwai 			if (err < 0)
2651352f7f91STakashi Iwai 				return err;
2652352f7f91STakashi Iwai 
2653352f7f91STakashi Iwai 			path = snd_hda_get_nid_path(codec, nid, 0);
2654352f7f91STakashi Iwai 			if (path)
2655352f7f91STakashi Iwai 				path->ctls[NID_PATH_BOOST_CTL] = val;
2656352f7f91STakashi Iwai 		}
2657352f7f91STakashi Iwai 	}
2658352f7f91STakashi Iwai 	return 0;
2659352f7f91STakashi Iwai }
2660352f7f91STakashi Iwai 
2661352f7f91STakashi Iwai /*
2662352f7f91STakashi Iwai  * parse digital I/Os and set up NIDs in BIOS auto-parse mode
2663352f7f91STakashi Iwai  */
2664352f7f91STakashi Iwai static void parse_digital(struct hda_codec *codec)
2665352f7f91STakashi Iwai {
2666352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
26670c8c0f56STakashi Iwai 	struct nid_path *path;
2668352f7f91STakashi Iwai 	int i, nums;
26692c12c30dSTakashi Iwai 	hda_nid_t dig_nid, pin;
2670352f7f91STakashi Iwai 
2671352f7f91STakashi Iwai 	/* support multiple SPDIFs; the secondary is set up as a slave */
2672352f7f91STakashi Iwai 	nums = 0;
2673352f7f91STakashi Iwai 	for (i = 0; i < spec->autocfg.dig_outs; i++) {
26742c12c30dSTakashi Iwai 		pin = spec->autocfg.dig_out_pins[i];
2675352f7f91STakashi Iwai 		dig_nid = look_for_dac(codec, pin, true);
2676352f7f91STakashi Iwai 		if (!dig_nid)
2677352f7f91STakashi Iwai 			continue;
26783ca529d3STakashi Iwai 		path = snd_hda_add_new_path(codec, dig_nid, pin, 0);
26790c8c0f56STakashi Iwai 		if (!path)
2680352f7f91STakashi Iwai 			continue;
26810c8c0f56STakashi Iwai 		print_nid_path("digout", path);
2682e1284af7STakashi Iwai 		path->active = true;
2683196c1766STakashi Iwai 		spec->digout_paths[i] = snd_hda_get_path_idx(codec, path);
26842c12c30dSTakashi Iwai 		set_pin_target(codec, pin, PIN_OUT, false);
2685352f7f91STakashi Iwai 		if (!nums) {
2686352f7f91STakashi Iwai 			spec->multiout.dig_out_nid = dig_nid;
2687352f7f91STakashi Iwai 			spec->dig_out_type = spec->autocfg.dig_out_type[0];
2688352f7f91STakashi Iwai 		} else {
2689352f7f91STakashi Iwai 			spec->multiout.slave_dig_outs = spec->slave_dig_outs;
2690352f7f91STakashi Iwai 			if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
2691352f7f91STakashi Iwai 			break;
2692352f7f91STakashi Iwai 			spec->slave_dig_outs[nums - 1] = dig_nid;
2693352f7f91STakashi Iwai 		}
2694352f7f91STakashi Iwai 		nums++;
2695352f7f91STakashi Iwai 	}
2696352f7f91STakashi Iwai 
2697352f7f91STakashi Iwai 	if (spec->autocfg.dig_in_pin) {
26982c12c30dSTakashi Iwai 		pin = spec->autocfg.dig_in_pin;
2699352f7f91STakashi Iwai 		dig_nid = codec->start_nid;
2700352f7f91STakashi Iwai 		for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
2701352f7f91STakashi Iwai 			unsigned int wcaps = get_wcaps(codec, dig_nid);
2702352f7f91STakashi Iwai 			if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
2703352f7f91STakashi Iwai 				continue;
2704352f7f91STakashi Iwai 			if (!(wcaps & AC_WCAP_DIGITAL))
2705352f7f91STakashi Iwai 				continue;
27062c12c30dSTakashi Iwai 			path = snd_hda_add_new_path(codec, pin, dig_nid, 0);
2707352f7f91STakashi Iwai 			if (path) {
27080c8c0f56STakashi Iwai 				print_nid_path("digin", path);
2709352f7f91STakashi Iwai 				path->active = true;
2710352f7f91STakashi Iwai 				spec->dig_in_nid = dig_nid;
27112430d7b7STakashi Iwai 				spec->digin_path = snd_hda_get_path_idx(codec, path);
27122c12c30dSTakashi Iwai 				set_pin_target(codec, pin, PIN_IN, false);
2713352f7f91STakashi Iwai 				break;
2714352f7f91STakashi Iwai 			}
2715352f7f91STakashi Iwai 		}
2716352f7f91STakashi Iwai 	}
2717352f7f91STakashi Iwai }
2718352f7f91STakashi Iwai 
27191da177e4SLinus Torvalds 
27201da177e4SLinus Torvalds /*
2721352f7f91STakashi Iwai  * input MUX handling
27221da177e4SLinus Torvalds  */
27231da177e4SLinus Torvalds 
2724352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur);
2725352f7f91STakashi Iwai 
2726352f7f91STakashi Iwai /* select the given imux item; either unmute exclusively or select the route */
2727352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
2728352f7f91STakashi Iwai 		      unsigned int idx)
2729352f7f91STakashi Iwai {
2730352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2731352f7f91STakashi Iwai 	const struct hda_input_mux *imux;
2732352f7f91STakashi Iwai 	struct nid_path *path;
2733352f7f91STakashi Iwai 
2734352f7f91STakashi Iwai 	imux = &spec->input_mux;
2735352f7f91STakashi Iwai 	if (!imux->num_items)
27361da177e4SLinus Torvalds 		return 0;
27371da177e4SLinus Torvalds 
2738352f7f91STakashi Iwai 	if (idx >= imux->num_items)
2739352f7f91STakashi Iwai 		idx = imux->num_items - 1;
2740352f7f91STakashi Iwai 	if (spec->cur_mux[adc_idx] == idx)
2741352f7f91STakashi Iwai 		return 0;
2742352f7f91STakashi Iwai 
2743c697b716STakashi Iwai 	path = get_input_path(codec, adc_idx, spec->cur_mux[adc_idx]);
2744352f7f91STakashi Iwai 	if (!path)
2745352f7f91STakashi Iwai 		return 0;
2746352f7f91STakashi Iwai 	if (path->active)
2747352f7f91STakashi Iwai 		snd_hda_activate_path(codec, path, false, false);
2748352f7f91STakashi Iwai 
2749352f7f91STakashi Iwai 	spec->cur_mux[adc_idx] = idx;
2750352f7f91STakashi Iwai 
2751352f7f91STakashi Iwai 	if (spec->shared_mic_hp)
2752352f7f91STakashi Iwai 		update_shared_mic_hp(codec, spec->cur_mux[adc_idx]);
2753352f7f91STakashi Iwai 
2754352f7f91STakashi Iwai 	if (spec->dyn_adc_switch)
2755352f7f91STakashi Iwai 		dyn_adc_pcm_resetup(codec, idx);
2756352f7f91STakashi Iwai 
2757c697b716STakashi Iwai 	path = get_input_path(codec, adc_idx, idx);
2758352f7f91STakashi Iwai 	if (!path)
2759352f7f91STakashi Iwai 		return 0;
2760352f7f91STakashi Iwai 	if (path->active)
2761352f7f91STakashi Iwai 		return 0;
2762352f7f91STakashi Iwai 	snd_hda_activate_path(codec, path, true, false);
2763352f7f91STakashi Iwai 	if (spec->cap_sync_hook)
2764352f7f91STakashi Iwai 		spec->cap_sync_hook(codec);
27651da177e4SLinus Torvalds 	return 1;
27661da177e4SLinus Torvalds }
27671da177e4SLinus Torvalds 
27681da177e4SLinus Torvalds 
27691da177e4SLinus Torvalds /*
2770352f7f91STakashi Iwai  * Jack detections for HP auto-mute and mic-switch
27711da177e4SLinus Torvalds  */
2772352f7f91STakashi Iwai 
2773352f7f91STakashi Iwai /* check each pin in the given array; returns true if any of them is plugged */
2774352f7f91STakashi Iwai static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
27751da177e4SLinus Torvalds {
2776352f7f91STakashi Iwai 	int i, present = 0;
27771da177e4SLinus Torvalds 
2778352f7f91STakashi Iwai 	for (i = 0; i < num_pins; i++) {
2779352f7f91STakashi Iwai 		hda_nid_t nid = pins[i];
2780352f7f91STakashi Iwai 		if (!nid)
2781352f7f91STakashi Iwai 			break;
27820b4df931STakashi Iwai 		/* don't detect pins retasked as inputs */
27830b4df931STakashi Iwai 		if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN)
27840b4df931STakashi Iwai 			continue;
2785352f7f91STakashi Iwai 		present |= snd_hda_jack_detect(codec, nid);
27861da177e4SLinus Torvalds 	}
2787352f7f91STakashi Iwai 	return present;
27881da177e4SLinus Torvalds }
27891da177e4SLinus Torvalds 
2790352f7f91STakashi Iwai /* standard HP/line-out auto-mute helper */
2791352f7f91STakashi Iwai static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
27922c12c30dSTakashi Iwai 			bool mute)
27931da177e4SLinus Torvalds {
2794352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2795352f7f91STakashi Iwai 	int i;
27961da177e4SLinus Torvalds 
2797352f7f91STakashi Iwai 	for (i = 0; i < num_pins; i++) {
2798352f7f91STakashi Iwai 		hda_nid_t nid = pins[i];
2799352f7f91STakashi Iwai 		unsigned int val;
2800352f7f91STakashi Iwai 		if (!nid)
2801352f7f91STakashi Iwai 			break;
2802352f7f91STakashi Iwai 		/* don't reset VREF value in case it's controlling
2803352f7f91STakashi Iwai 		 * the amp (see alc861_fixup_asus_amp_vref_0f())
2804352f7f91STakashi Iwai 		 */
28052c12c30dSTakashi Iwai 		if (spec->keep_vref_in_automute)
28062c12c30dSTakashi Iwai 			val = snd_hda_codec_get_pin_target(codec, nid) & ~PIN_HP;
28072c12c30dSTakashi Iwai 		else
2808352f7f91STakashi Iwai 			val = 0;
28092c12c30dSTakashi Iwai 		if (!mute)
28102c12c30dSTakashi Iwai 			val |= snd_hda_codec_get_pin_target(codec, nid);
28112c12c30dSTakashi Iwai 		/* here we call update_pin_ctl() so that the pinctl is changed
28122c12c30dSTakashi Iwai 		 * without changing the pinctl target value;
28132c12c30dSTakashi Iwai 		 * the original target value will be still referred at the
28142c12c30dSTakashi Iwai 		 * init / resume again
28152c12c30dSTakashi Iwai 		 */
28162c12c30dSTakashi Iwai 		update_pin_ctl(codec, nid, val);
2817d5a9f1bbSTakashi Iwai 		set_pin_eapd(codec, nid, !mute);
2818352f7f91STakashi Iwai 	}
2819352f7f91STakashi Iwai }
28201da177e4SLinus Torvalds 
2821352f7f91STakashi Iwai /* Toggle outputs muting */
28225d550e15STakashi Iwai void snd_hda_gen_update_outputs(struct hda_codec *codec)
2823352f7f91STakashi Iwai {
2824352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2825352f7f91STakashi Iwai 	int on;
2826352f7f91STakashi Iwai 
2827352f7f91STakashi Iwai 	/* Control HP pins/amps depending on master_mute state;
2828352f7f91STakashi Iwai 	 * in general, HP pins/amps control should be enabled in all cases,
2829352f7f91STakashi Iwai 	 * but currently set only for master_mute, just to be safe
2830352f7f91STakashi Iwai 	 */
2831352f7f91STakashi Iwai 	if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */
2832352f7f91STakashi Iwai 		do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
28332c12c30dSTakashi Iwai 		    spec->autocfg.hp_pins, spec->master_mute);
2834352f7f91STakashi Iwai 
2835352f7f91STakashi Iwai 	if (!spec->automute_speaker)
2836352f7f91STakashi Iwai 		on = 0;
2837352f7f91STakashi Iwai 	else
2838352f7f91STakashi Iwai 		on = spec->hp_jack_present | spec->line_jack_present;
2839352f7f91STakashi Iwai 	on |= spec->master_mute;
2840352f7f91STakashi Iwai 	do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
28412c12c30dSTakashi Iwai 		    spec->autocfg.speaker_pins, on);
2842352f7f91STakashi Iwai 
2843352f7f91STakashi Iwai 	/* toggle line-out mutes if needed, too */
2844352f7f91STakashi Iwai 	/* if LO is a copy of either HP or Speaker, don't need to handle it */
2845352f7f91STakashi Iwai 	if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
2846352f7f91STakashi Iwai 	    spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
2847352f7f91STakashi Iwai 		return;
2848352f7f91STakashi Iwai 	if (!spec->automute_lo)
2849352f7f91STakashi Iwai 		on = 0;
2850352f7f91STakashi Iwai 	else
2851352f7f91STakashi Iwai 		on = spec->hp_jack_present;
2852352f7f91STakashi Iwai 	on |= spec->master_mute;
2853352f7f91STakashi Iwai 	do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
28542c12c30dSTakashi Iwai 		    spec->autocfg.line_out_pins, on);
2855352f7f91STakashi Iwai }
28565d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs);
2857352f7f91STakashi Iwai 
2858352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec)
2859352f7f91STakashi Iwai {
2860352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2861352f7f91STakashi Iwai 	if (spec->automute_hook)
2862352f7f91STakashi Iwai 		spec->automute_hook(codec);
2863352f7f91STakashi Iwai 	else
28645d550e15STakashi Iwai 		snd_hda_gen_update_outputs(codec);
2865352f7f91STakashi Iwai }
2866352f7f91STakashi Iwai 
2867352f7f91STakashi Iwai /* standard HP-automute helper */
28685d550e15STakashi Iwai void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
2869352f7f91STakashi Iwai {
2870352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2871352f7f91STakashi Iwai 
2872352f7f91STakashi Iwai 	spec->hp_jack_present =
2873352f7f91STakashi Iwai 		detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
2874352f7f91STakashi Iwai 			     spec->autocfg.hp_pins);
2875352f7f91STakashi Iwai 	if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo))
2876352f7f91STakashi Iwai 		return;
2877352f7f91STakashi Iwai 	call_update_outputs(codec);
2878352f7f91STakashi Iwai }
28795d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_hp_automute);
2880352f7f91STakashi Iwai 
2881352f7f91STakashi Iwai /* standard line-out-automute helper */
28825d550e15STakashi Iwai void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
2883352f7f91STakashi Iwai {
2884352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2885352f7f91STakashi Iwai 
2886352f7f91STakashi Iwai 	if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
2887352f7f91STakashi Iwai 		return;
2888352f7f91STakashi Iwai 	/* check LO jack only when it's different from HP */
2889352f7f91STakashi Iwai 	if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0])
2890352f7f91STakashi Iwai 		return;
2891352f7f91STakashi Iwai 
2892352f7f91STakashi Iwai 	spec->line_jack_present =
2893352f7f91STakashi Iwai 		detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
2894352f7f91STakashi Iwai 			     spec->autocfg.line_out_pins);
2895352f7f91STakashi Iwai 	if (!spec->automute_speaker || !spec->detect_lo)
2896352f7f91STakashi Iwai 		return;
2897352f7f91STakashi Iwai 	call_update_outputs(codec);
2898352f7f91STakashi Iwai }
28995d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_line_automute);
2900352f7f91STakashi Iwai 
2901352f7f91STakashi Iwai /* standard mic auto-switch helper */
29025d550e15STakashi Iwai void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *jack)
2903352f7f91STakashi Iwai {
2904352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2905352f7f91STakashi Iwai 	int i;
2906352f7f91STakashi Iwai 
2907352f7f91STakashi Iwai 	if (!spec->auto_mic)
2908352f7f91STakashi Iwai 		return;
2909352f7f91STakashi Iwai 
2910352f7f91STakashi Iwai 	for (i = spec->am_num_entries - 1; i > 0; i--) {
29110b4df931STakashi Iwai 		hda_nid_t pin = spec->am_entry[i].pin;
29120b4df931STakashi Iwai 		/* don't detect pins retasked as outputs */
29130b4df931STakashi Iwai 		if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN)
29140b4df931STakashi Iwai 			continue;
29150b4df931STakashi Iwai 		if (snd_hda_jack_detect(codec, pin)) {
2916352f7f91STakashi Iwai 			mux_select(codec, 0, spec->am_entry[i].idx);
2917352f7f91STakashi Iwai 			return;
2918352f7f91STakashi Iwai 		}
2919352f7f91STakashi Iwai 	}
2920352f7f91STakashi Iwai 	mux_select(codec, 0, spec->am_entry[0].idx);
29211da177e4SLinus Torvalds }
29225d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_mic_autoswitch);
29231da177e4SLinus Torvalds 
29241da177e4SLinus Torvalds /*
2925352f7f91STakashi Iwai  * Auto-Mute mode mixer enum support
29261da177e4SLinus Torvalds  */
2927352f7f91STakashi Iwai static int automute_mode_info(struct snd_kcontrol *kcontrol,
2928352f7f91STakashi Iwai 			      struct snd_ctl_elem_info *uinfo)
2929352f7f91STakashi Iwai {
2930352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2931352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2932352f7f91STakashi Iwai 	static const char * const texts3[] = {
2933352f7f91STakashi Iwai 		"Disabled", "Speaker Only", "Line Out+Speaker"
29341da177e4SLinus Torvalds 	};
29351da177e4SLinus Torvalds 
2936352f7f91STakashi Iwai 	if (spec->automute_speaker_possible && spec->automute_lo_possible)
2937352f7f91STakashi Iwai 		return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
2938352f7f91STakashi Iwai 	return snd_hda_enum_bool_helper_info(kcontrol, uinfo);
2939352f7f91STakashi Iwai }
2940352f7f91STakashi Iwai 
2941352f7f91STakashi Iwai static int automute_mode_get(struct snd_kcontrol *kcontrol,
2942352f7f91STakashi Iwai 			     struct snd_ctl_elem_value *ucontrol)
2943352f7f91STakashi Iwai {
2944352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2945352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2946352f7f91STakashi Iwai 	unsigned int val = 0;
2947352f7f91STakashi Iwai 	if (spec->automute_speaker)
2948352f7f91STakashi Iwai 		val++;
2949352f7f91STakashi Iwai 	if (spec->automute_lo)
2950352f7f91STakashi Iwai 		val++;
2951352f7f91STakashi Iwai 
2952352f7f91STakashi Iwai 	ucontrol->value.enumerated.item[0] = val;
2953352f7f91STakashi Iwai 	return 0;
2954352f7f91STakashi Iwai }
2955352f7f91STakashi Iwai 
2956352f7f91STakashi Iwai static int automute_mode_put(struct snd_kcontrol *kcontrol,
2957352f7f91STakashi Iwai 			     struct snd_ctl_elem_value *ucontrol)
2958352f7f91STakashi Iwai {
2959352f7f91STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2960352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
2961352f7f91STakashi Iwai 
2962352f7f91STakashi Iwai 	switch (ucontrol->value.enumerated.item[0]) {
2963352f7f91STakashi Iwai 	case 0:
2964352f7f91STakashi Iwai 		if (!spec->automute_speaker && !spec->automute_lo)
2965352f7f91STakashi Iwai 			return 0;
2966352f7f91STakashi Iwai 		spec->automute_speaker = 0;
2967352f7f91STakashi Iwai 		spec->automute_lo = 0;
2968352f7f91STakashi Iwai 		break;
2969352f7f91STakashi Iwai 	case 1:
2970352f7f91STakashi Iwai 		if (spec->automute_speaker_possible) {
2971352f7f91STakashi Iwai 			if (!spec->automute_lo && spec->automute_speaker)
2972352f7f91STakashi Iwai 				return 0;
2973352f7f91STakashi Iwai 			spec->automute_speaker = 1;
2974352f7f91STakashi Iwai 			spec->automute_lo = 0;
2975352f7f91STakashi Iwai 		} else if (spec->automute_lo_possible) {
2976352f7f91STakashi Iwai 			if (spec->automute_lo)
2977352f7f91STakashi Iwai 				return 0;
2978352f7f91STakashi Iwai 			spec->automute_lo = 1;
2979352f7f91STakashi Iwai 		} else
2980352f7f91STakashi Iwai 			return -EINVAL;
2981352f7f91STakashi Iwai 		break;
2982352f7f91STakashi Iwai 	case 2:
2983352f7f91STakashi Iwai 		if (!spec->automute_lo_possible || !spec->automute_speaker_possible)
2984352f7f91STakashi Iwai 			return -EINVAL;
2985352f7f91STakashi Iwai 		if (spec->automute_speaker && spec->automute_lo)
2986352f7f91STakashi Iwai 			return 0;
2987352f7f91STakashi Iwai 		spec->automute_speaker = 1;
2988352f7f91STakashi Iwai 		spec->automute_lo = 1;
2989352f7f91STakashi Iwai 		break;
2990352f7f91STakashi Iwai 	default:
2991352f7f91STakashi Iwai 		return -EINVAL;
2992352f7f91STakashi Iwai 	}
2993352f7f91STakashi Iwai 	call_update_outputs(codec);
2994352f7f91STakashi Iwai 	return 1;
2995352f7f91STakashi Iwai }
2996352f7f91STakashi Iwai 
2997352f7f91STakashi Iwai static const struct snd_kcontrol_new automute_mode_enum = {
2998352f7f91STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2999352f7f91STakashi Iwai 	.name = "Auto-Mute Mode",
3000352f7f91STakashi Iwai 	.info = automute_mode_info,
3001352f7f91STakashi Iwai 	.get = automute_mode_get,
3002352f7f91STakashi Iwai 	.put = automute_mode_put,
3003352f7f91STakashi Iwai };
3004352f7f91STakashi Iwai 
3005352f7f91STakashi Iwai static int add_automute_mode_enum(struct hda_codec *codec)
3006352f7f91STakashi Iwai {
3007352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3008352f7f91STakashi Iwai 
300912c93df6STakashi Iwai 	if (!snd_hda_gen_add_kctl(spec, NULL, &automute_mode_enum))
3010352f7f91STakashi Iwai 		return -ENOMEM;
3011352f7f91STakashi Iwai 	return 0;
3012352f7f91STakashi Iwai }
3013352f7f91STakashi Iwai 
3014352f7f91STakashi Iwai /*
3015352f7f91STakashi Iwai  * Check the availability of HP/line-out auto-mute;
3016352f7f91STakashi Iwai  * Set up appropriately if really supported
3017352f7f91STakashi Iwai  */
3018352f7f91STakashi Iwai static int check_auto_mute_availability(struct hda_codec *codec)
3019352f7f91STakashi Iwai {
3020352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3021352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
3022352f7f91STakashi Iwai 	int present = 0;
3023352f7f91STakashi Iwai 	int i, err;
3024352f7f91STakashi Iwai 
3025352f7f91STakashi Iwai 	if (cfg->hp_pins[0])
3026352f7f91STakashi Iwai 		present++;
3027352f7f91STakashi Iwai 	if (cfg->line_out_pins[0])
3028352f7f91STakashi Iwai 		present++;
3029352f7f91STakashi Iwai 	if (cfg->speaker_pins[0])
3030352f7f91STakashi Iwai 		present++;
3031352f7f91STakashi Iwai 	if (present < 2) /* need two different output types */
3032352f7f91STakashi Iwai 		return 0;
3033352f7f91STakashi Iwai 
3034352f7f91STakashi Iwai 	if (!cfg->speaker_pins[0] &&
3035352f7f91STakashi Iwai 	    cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
3036352f7f91STakashi Iwai 		memcpy(cfg->speaker_pins, cfg->line_out_pins,
3037352f7f91STakashi Iwai 		       sizeof(cfg->speaker_pins));
3038352f7f91STakashi Iwai 		cfg->speaker_outs = cfg->line_outs;
3039352f7f91STakashi Iwai 	}
3040352f7f91STakashi Iwai 
3041352f7f91STakashi Iwai 	if (!cfg->hp_pins[0] &&
3042352f7f91STakashi Iwai 	    cfg->line_out_type == AUTO_PIN_HP_OUT) {
3043352f7f91STakashi Iwai 		memcpy(cfg->hp_pins, cfg->line_out_pins,
3044352f7f91STakashi Iwai 		       sizeof(cfg->hp_pins));
3045352f7f91STakashi Iwai 		cfg->hp_outs = cfg->line_outs;
3046352f7f91STakashi Iwai 	}
3047352f7f91STakashi Iwai 
3048352f7f91STakashi Iwai 	for (i = 0; i < cfg->hp_outs; i++) {
3049352f7f91STakashi Iwai 		hda_nid_t nid = cfg->hp_pins[i];
3050352f7f91STakashi Iwai 		if (!is_jack_detectable(codec, nid))
3051352f7f91STakashi Iwai 			continue;
3052352f7f91STakashi Iwai 		snd_printdd("hda-codec: Enable HP auto-muting on NID 0x%x\n",
3053352f7f91STakashi Iwai 			    nid);
3054352f7f91STakashi Iwai 		snd_hda_jack_detect_enable_callback(codec, nid, HDA_GEN_HP_EVENT,
30552e03e952STakashi Iwai 						    spec->hp_automute_hook ?
30562e03e952STakashi Iwai 						    spec->hp_automute_hook :
30575d550e15STakashi Iwai 						    snd_hda_gen_hp_automute);
3058352f7f91STakashi Iwai 		spec->detect_hp = 1;
3059352f7f91STakashi Iwai 	}
3060352f7f91STakashi Iwai 
3061352f7f91STakashi Iwai 	if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) {
3062352f7f91STakashi Iwai 		if (cfg->speaker_outs)
3063352f7f91STakashi Iwai 			for (i = 0; i < cfg->line_outs; i++) {
3064352f7f91STakashi Iwai 				hda_nid_t nid = cfg->line_out_pins[i];
3065352f7f91STakashi Iwai 				if (!is_jack_detectable(codec, nid))
3066352f7f91STakashi Iwai 					continue;
3067352f7f91STakashi Iwai 				snd_printdd("hda-codec: Enable Line-Out auto-muting on NID 0x%x\n", nid);
3068352f7f91STakashi Iwai 				snd_hda_jack_detect_enable_callback(codec, nid,
3069352f7f91STakashi Iwai 								    HDA_GEN_FRONT_EVENT,
30702e03e952STakashi Iwai 								    spec->line_automute_hook ?
30712e03e952STakashi Iwai 								    spec->line_automute_hook :
30725d550e15STakashi Iwai 								    snd_hda_gen_line_automute);
3073352f7f91STakashi Iwai 				spec->detect_lo = 1;
3074352f7f91STakashi Iwai 			}
3075352f7f91STakashi Iwai 		spec->automute_lo_possible = spec->detect_hp;
3076352f7f91STakashi Iwai 	}
3077352f7f91STakashi Iwai 
3078352f7f91STakashi Iwai 	spec->automute_speaker_possible = cfg->speaker_outs &&
3079352f7f91STakashi Iwai 		(spec->detect_hp || spec->detect_lo);
3080352f7f91STakashi Iwai 
3081352f7f91STakashi Iwai 	spec->automute_lo = spec->automute_lo_possible;
3082352f7f91STakashi Iwai 	spec->automute_speaker = spec->automute_speaker_possible;
3083352f7f91STakashi Iwai 
3084352f7f91STakashi Iwai 	if (spec->automute_speaker_possible || spec->automute_lo_possible) {
3085352f7f91STakashi Iwai 		/* create a control for automute mode */
3086352f7f91STakashi Iwai 		err = add_automute_mode_enum(codec);
3087352f7f91STakashi Iwai 		if (err < 0)
3088352f7f91STakashi Iwai 			return err;
3089352f7f91STakashi Iwai 	}
3090352f7f91STakashi Iwai 	return 0;
3091352f7f91STakashi Iwai }
3092352f7f91STakashi Iwai 
3093352f7f91STakashi Iwai /* check whether all auto-mic pins are valid; setup indices if OK */
3094352f7f91STakashi Iwai static bool auto_mic_check_imux(struct hda_codec *codec)
3095352f7f91STakashi Iwai {
3096352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3097352f7f91STakashi Iwai 	const struct hda_input_mux *imux;
3098352f7f91STakashi Iwai 	int i;
3099352f7f91STakashi Iwai 
3100352f7f91STakashi Iwai 	imux = &spec->input_mux;
3101352f7f91STakashi Iwai 	for (i = 0; i < spec->am_num_entries; i++) {
3102352f7f91STakashi Iwai 		spec->am_entry[i].idx =
3103352f7f91STakashi Iwai 			find_idx_in_nid_list(spec->am_entry[i].pin,
3104352f7f91STakashi Iwai 					     spec->imux_pins, imux->num_items);
3105352f7f91STakashi Iwai 		if (spec->am_entry[i].idx < 0)
3106352f7f91STakashi Iwai 			return false; /* no corresponding imux */
3107352f7f91STakashi Iwai 	}
3108352f7f91STakashi Iwai 
3109352f7f91STakashi Iwai 	/* we don't need the jack detection for the first pin */
3110352f7f91STakashi Iwai 	for (i = 1; i < spec->am_num_entries; i++)
3111352f7f91STakashi Iwai 		snd_hda_jack_detect_enable_callback(codec,
3112352f7f91STakashi Iwai 						    spec->am_entry[i].pin,
3113352f7f91STakashi Iwai 						    HDA_GEN_MIC_EVENT,
31142e03e952STakashi Iwai 						    spec->mic_autoswitch_hook ?
31152e03e952STakashi Iwai 						    spec->mic_autoswitch_hook :
31165d550e15STakashi Iwai 						    snd_hda_gen_mic_autoswitch);
3117352f7f91STakashi Iwai 	return true;
3118352f7f91STakashi Iwai }
3119352f7f91STakashi Iwai 
3120352f7f91STakashi Iwai static int compare_attr(const void *ap, const void *bp)
3121352f7f91STakashi Iwai {
3122352f7f91STakashi Iwai 	const struct automic_entry *a = ap;
3123352f7f91STakashi Iwai 	const struct automic_entry *b = bp;
3124352f7f91STakashi Iwai 	return (int)(a->attr - b->attr);
3125352f7f91STakashi Iwai }
3126352f7f91STakashi Iwai 
3127352f7f91STakashi Iwai /*
3128352f7f91STakashi Iwai  * Check the availability of auto-mic switch;
3129352f7f91STakashi Iwai  * Set up if really supported
3130352f7f91STakashi Iwai  */
3131352f7f91STakashi Iwai static int check_auto_mic_availability(struct hda_codec *codec)
3132352f7f91STakashi Iwai {
3133352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3134352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
3135352f7f91STakashi Iwai 	unsigned int types;
3136352f7f91STakashi Iwai 	int i, num_pins;
3137352f7f91STakashi Iwai 
3138d12daf6fSTakashi Iwai 	if (spec->suppress_auto_mic)
3139d12daf6fSTakashi Iwai 		return 0;
3140d12daf6fSTakashi Iwai 
3141352f7f91STakashi Iwai 	types = 0;
3142352f7f91STakashi Iwai 	num_pins = 0;
3143352f7f91STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
3144352f7f91STakashi Iwai 		hda_nid_t nid = cfg->inputs[i].pin;
3145352f7f91STakashi Iwai 		unsigned int attr;
3146352f7f91STakashi Iwai 		attr = snd_hda_codec_get_pincfg(codec, nid);
3147352f7f91STakashi Iwai 		attr = snd_hda_get_input_pin_attr(attr);
3148352f7f91STakashi Iwai 		if (types & (1 << attr))
3149352f7f91STakashi Iwai 			return 0; /* already occupied */
3150352f7f91STakashi Iwai 		switch (attr) {
3151352f7f91STakashi Iwai 		case INPUT_PIN_ATTR_INT:
3152352f7f91STakashi Iwai 			if (cfg->inputs[i].type != AUTO_PIN_MIC)
3153352f7f91STakashi Iwai 				return 0; /* invalid type */
3154352f7f91STakashi Iwai 			break;
3155352f7f91STakashi Iwai 		case INPUT_PIN_ATTR_UNUSED:
3156352f7f91STakashi Iwai 			return 0; /* invalid entry */
3157352f7f91STakashi Iwai 		default:
3158352f7f91STakashi Iwai 			if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
3159352f7f91STakashi Iwai 				return 0; /* invalid type */
3160352f7f91STakashi Iwai 			if (!spec->line_in_auto_switch &&
3161352f7f91STakashi Iwai 			    cfg->inputs[i].type != AUTO_PIN_MIC)
3162352f7f91STakashi Iwai 				return 0; /* only mic is allowed */
3163352f7f91STakashi Iwai 			if (!is_jack_detectable(codec, nid))
3164352f7f91STakashi Iwai 				return 0; /* no unsol support */
3165352f7f91STakashi Iwai 			break;
3166352f7f91STakashi Iwai 		}
3167352f7f91STakashi Iwai 		if (num_pins >= MAX_AUTO_MIC_PINS)
3168352f7f91STakashi Iwai 			return 0;
3169352f7f91STakashi Iwai 		types |= (1 << attr);
3170352f7f91STakashi Iwai 		spec->am_entry[num_pins].pin = nid;
3171352f7f91STakashi Iwai 		spec->am_entry[num_pins].attr = attr;
3172352f7f91STakashi Iwai 		num_pins++;
3173352f7f91STakashi Iwai 	}
3174352f7f91STakashi Iwai 
3175352f7f91STakashi Iwai 	if (num_pins < 2)
3176352f7f91STakashi Iwai 		return 0;
3177352f7f91STakashi Iwai 
3178352f7f91STakashi Iwai 	spec->am_num_entries = num_pins;
3179352f7f91STakashi Iwai 	/* sort the am_entry in the order of attr so that the pin with a
3180352f7f91STakashi Iwai 	 * higher attr will be selected when the jack is plugged.
3181352f7f91STakashi Iwai 	 */
3182352f7f91STakashi Iwai 	sort(spec->am_entry, num_pins, sizeof(spec->am_entry[0]),
3183352f7f91STakashi Iwai 	     compare_attr, NULL);
3184352f7f91STakashi Iwai 
3185352f7f91STakashi Iwai 	if (!auto_mic_check_imux(codec))
3186352f7f91STakashi Iwai 		return 0;
3187352f7f91STakashi Iwai 
3188352f7f91STakashi Iwai 	spec->auto_mic = 1;
3189352f7f91STakashi Iwai 	spec->num_adc_nids = 1;
3190352f7f91STakashi Iwai 	spec->cur_mux[0] = spec->am_entry[0].idx;
3191352f7f91STakashi Iwai 	snd_printdd("hda-codec: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
3192352f7f91STakashi Iwai 		    spec->am_entry[0].pin,
3193352f7f91STakashi Iwai 		    spec->am_entry[1].pin,
3194352f7f91STakashi Iwai 		    spec->am_entry[2].pin);
3195352f7f91STakashi Iwai 
3196352f7f91STakashi Iwai 	return 0;
3197352f7f91STakashi Iwai }
3198352f7f91STakashi Iwai 
3199352f7f91STakashi Iwai 
32009eb413e5STakashi Iwai /*
32019eb413e5STakashi Iwai  * Parse the given BIOS configuration and set up the hda_gen_spec
32029eb413e5STakashi Iwai  *
32039eb413e5STakashi Iwai  * return 1 if successful, 0 if the proper config is not found,
3204352f7f91STakashi Iwai  * or a negative error code
3205352f7f91STakashi Iwai  */
3206352f7f91STakashi Iwai int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
32079eb413e5STakashi Iwai 				  struct auto_pin_cfg *cfg)
3208352f7f91STakashi Iwai {
3209352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3210352f7f91STakashi Iwai 	int err;
3211352f7f91STakashi Iwai 
32129eb413e5STakashi Iwai 	if (cfg != &spec->autocfg) {
32139eb413e5STakashi Iwai 		spec->autocfg = *cfg;
32149eb413e5STakashi Iwai 		cfg = &spec->autocfg;
32159eb413e5STakashi Iwai 	}
32169eb413e5STakashi Iwai 
3217352f7f91STakashi Iwai 	if (!cfg->line_outs) {
3218352f7f91STakashi Iwai 		if (cfg->dig_outs || cfg->dig_in_pin) {
3219352f7f91STakashi Iwai 			spec->multiout.max_channels = 2;
3220352f7f91STakashi Iwai 			spec->no_analog = 1;
3221352f7f91STakashi Iwai 			goto dig_only;
3222352f7f91STakashi Iwai 		}
3223352f7f91STakashi Iwai 		return 0; /* can't find valid BIOS pin config */
3224352f7f91STakashi Iwai 	}
3225352f7f91STakashi Iwai 
3226352f7f91STakashi Iwai 	if (!spec->no_primary_hp &&
3227352f7f91STakashi Iwai 	    cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
3228352f7f91STakashi Iwai 	    cfg->line_outs <= cfg->hp_outs) {
3229352f7f91STakashi Iwai 		/* use HP as primary out */
3230352f7f91STakashi Iwai 		cfg->speaker_outs = cfg->line_outs;
3231352f7f91STakashi Iwai 		memcpy(cfg->speaker_pins, cfg->line_out_pins,
3232352f7f91STakashi Iwai 		       sizeof(cfg->speaker_pins));
3233352f7f91STakashi Iwai 		cfg->line_outs = cfg->hp_outs;
3234352f7f91STakashi Iwai 		memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins));
3235352f7f91STakashi Iwai 		cfg->hp_outs = 0;
3236352f7f91STakashi Iwai 		memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
3237352f7f91STakashi Iwai 		cfg->line_out_type = AUTO_PIN_HP_OUT;
3238352f7f91STakashi Iwai 	}
3239352f7f91STakashi Iwai 
3240352f7f91STakashi Iwai 	err = parse_output_paths(codec);
3241352f7f91STakashi Iwai 	if (err < 0)
3242352f7f91STakashi Iwai 		return err;
3243352f7f91STakashi Iwai 	err = create_multi_channel_mode(codec);
3244352f7f91STakashi Iwai 	if (err < 0)
3245352f7f91STakashi Iwai 		return err;
3246352f7f91STakashi Iwai 	err = create_multi_out_ctls(codec, cfg);
3247352f7f91STakashi Iwai 	if (err < 0)
3248352f7f91STakashi Iwai 		return err;
3249352f7f91STakashi Iwai 	err = create_hp_out_ctls(codec);
3250352f7f91STakashi Iwai 	if (err < 0)
3251352f7f91STakashi Iwai 		return err;
3252352f7f91STakashi Iwai 	err = create_speaker_out_ctls(codec);
3253352f7f91STakashi Iwai 	if (err < 0)
3254352f7f91STakashi Iwai 		return err;
325538cf6f1aSTakashi Iwai 	err = create_indep_hp_ctls(codec);
325638cf6f1aSTakashi Iwai 	if (err < 0)
325738cf6f1aSTakashi Iwai 		return err;
3258c30aa7b2STakashi Iwai 	err = create_loopback_mixing_ctl(codec);
3259c30aa7b2STakashi Iwai 	if (err < 0)
3260c30aa7b2STakashi Iwai 		return err;
3261352f7f91STakashi Iwai 	err = create_shared_input(codec);
3262352f7f91STakashi Iwai 	if (err < 0)
3263352f7f91STakashi Iwai 		return err;
3264352f7f91STakashi Iwai 	err = create_input_ctls(codec);
3265352f7f91STakashi Iwai 	if (err < 0)
3266352f7f91STakashi Iwai 		return err;
3267352f7f91STakashi Iwai 
3268a07a949bSTakashi Iwai 	spec->const_channel_count = spec->ext_channel_count;
3269a07a949bSTakashi Iwai 	/* check the multiple speaker and headphone pins */
3270a07a949bSTakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
3271a07a949bSTakashi Iwai 		spec->const_channel_count = max(spec->const_channel_count,
3272a07a949bSTakashi Iwai 						cfg->speaker_outs * 2);
3273a07a949bSTakashi Iwai 	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
3274a07a949bSTakashi Iwai 		spec->const_channel_count = max(spec->const_channel_count,
3275a07a949bSTakashi Iwai 						cfg->hp_outs * 2);
3276352f7f91STakashi Iwai 	spec->multiout.max_channels = max(spec->ext_channel_count,
3277352f7f91STakashi Iwai 					  spec->const_channel_count);
3278352f7f91STakashi Iwai 
3279352f7f91STakashi Iwai 	err = check_auto_mute_availability(codec);
3280352f7f91STakashi Iwai 	if (err < 0)
3281352f7f91STakashi Iwai 		return err;
3282352f7f91STakashi Iwai 
3283352f7f91STakashi Iwai 	err = check_dyn_adc_switch(codec);
3284352f7f91STakashi Iwai 	if (err < 0)
3285352f7f91STakashi Iwai 		return err;
3286352f7f91STakashi Iwai 
3287352f7f91STakashi Iwai 	if (!spec->shared_mic_hp) {
3288352f7f91STakashi Iwai 		err = check_auto_mic_availability(codec);
3289352f7f91STakashi Iwai 		if (err < 0)
3290352f7f91STakashi Iwai 			return err;
3291352f7f91STakashi Iwai 	}
3292352f7f91STakashi Iwai 
3293352f7f91STakashi Iwai 	err = create_capture_mixers(codec);
3294352f7f91STakashi Iwai 	if (err < 0)
3295352f7f91STakashi Iwai 		return err;
3296352f7f91STakashi Iwai 
3297352f7f91STakashi Iwai 	err = parse_mic_boost(codec);
3298352f7f91STakashi Iwai 	if (err < 0)
3299352f7f91STakashi Iwai 		return err;
3300352f7f91STakashi Iwai 
3301352f7f91STakashi Iwai  dig_only:
3302352f7f91STakashi Iwai 	parse_digital(codec);
3303352f7f91STakashi Iwai 
3304352f7f91STakashi Iwai 	return 1;
3305352f7f91STakashi Iwai }
3306352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_parse_auto_config);
3307352f7f91STakashi Iwai 
3308352f7f91STakashi Iwai 
3309352f7f91STakashi Iwai /*
3310352f7f91STakashi Iwai  * Build control elements
3311352f7f91STakashi Iwai  */
3312352f7f91STakashi Iwai 
3313352f7f91STakashi Iwai /* slave controls for virtual master */
3314352f7f91STakashi Iwai static const char * const slave_pfxs[] = {
3315352f7f91STakashi Iwai 	"Front", "Surround", "Center", "LFE", "Side",
3316352f7f91STakashi Iwai 	"Headphone", "Speaker", "Mono", "Line Out",
3317352f7f91STakashi Iwai 	"CLFE", "Bass Speaker", "PCM",
3318ee79c69aSTakashi Iwai 	"Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side",
3319ee79c69aSTakashi Iwai 	"Headphone Front", "Headphone Surround", "Headphone CLFE",
3320ee79c69aSTakashi Iwai 	"Headphone Side",
3321352f7f91STakashi Iwai 	NULL,
3322352f7f91STakashi Iwai };
3323352f7f91STakashi Iwai 
3324352f7f91STakashi Iwai int snd_hda_gen_build_controls(struct hda_codec *codec)
3325352f7f91STakashi Iwai {
3326352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3327352f7f91STakashi Iwai 	int err;
3328352f7f91STakashi Iwai 
332936502d02STakashi Iwai 	if (spec->kctls.used) {
3330352f7f91STakashi Iwai 		err = snd_hda_add_new_ctls(codec, spec->kctls.list);
3331352f7f91STakashi Iwai 		if (err < 0)
3332352f7f91STakashi Iwai 			return err;
333336502d02STakashi Iwai 	}
3334352f7f91STakashi Iwai 
3335352f7f91STakashi Iwai 	if (spec->multiout.dig_out_nid) {
3336352f7f91STakashi Iwai 		err = snd_hda_create_dig_out_ctls(codec,
3337352f7f91STakashi Iwai 						  spec->multiout.dig_out_nid,
3338352f7f91STakashi Iwai 						  spec->multiout.dig_out_nid,
3339352f7f91STakashi Iwai 						  spec->pcm_rec[1].pcm_type);
3340352f7f91STakashi Iwai 		if (err < 0)
3341352f7f91STakashi Iwai 			return err;
3342352f7f91STakashi Iwai 		if (!spec->no_analog) {
3343352f7f91STakashi Iwai 			err = snd_hda_create_spdif_share_sw(codec,
3344352f7f91STakashi Iwai 							    &spec->multiout);
3345352f7f91STakashi Iwai 			if (err < 0)
3346352f7f91STakashi Iwai 				return err;
3347352f7f91STakashi Iwai 			spec->multiout.share_spdif = 1;
3348352f7f91STakashi Iwai 		}
3349352f7f91STakashi Iwai 	}
3350352f7f91STakashi Iwai 	if (spec->dig_in_nid) {
3351352f7f91STakashi Iwai 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
3352352f7f91STakashi Iwai 		if (err < 0)
3353352f7f91STakashi Iwai 			return err;
3354352f7f91STakashi Iwai 	}
3355352f7f91STakashi Iwai 
3356352f7f91STakashi Iwai 	/* if we have no master control, let's create it */
3357352f7f91STakashi Iwai 	if (!spec->no_analog &&
3358352f7f91STakashi Iwai 	    !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
3359352f7f91STakashi Iwai 		unsigned int vmaster_tlv[4];
3360352f7f91STakashi Iwai 		snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
3361352f7f91STakashi Iwai 					HDA_OUTPUT, vmaster_tlv);
3362352f7f91STakashi Iwai 		err = snd_hda_add_vmaster(codec, "Master Playback Volume",
3363352f7f91STakashi Iwai 					  vmaster_tlv, slave_pfxs,
3364352f7f91STakashi Iwai 					  "Playback Volume");
3365352f7f91STakashi Iwai 		if (err < 0)
3366352f7f91STakashi Iwai 			return err;
3367352f7f91STakashi Iwai 	}
3368352f7f91STakashi Iwai 	if (!spec->no_analog &&
3369352f7f91STakashi Iwai 	    !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
3370352f7f91STakashi Iwai 		err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
3371352f7f91STakashi Iwai 					    NULL, slave_pfxs,
3372352f7f91STakashi Iwai 					    "Playback Switch",
3373352f7f91STakashi Iwai 					    true, &spec->vmaster_mute.sw_kctl);
3374352f7f91STakashi Iwai 		if (err < 0)
3375352f7f91STakashi Iwai 			return err;
3376352f7f91STakashi Iwai 		if (spec->vmaster_mute.hook)
3377fd25a97aSTakashi Iwai 			snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute,
3378fd25a97aSTakashi Iwai 						 spec->vmaster_mute_enum);
3379352f7f91STakashi Iwai 	}
3380352f7f91STakashi Iwai 
3381352f7f91STakashi Iwai 	free_kctls(spec); /* no longer needed */
3382352f7f91STakashi Iwai 
3383352f7f91STakashi Iwai 	if (spec->shared_mic_hp) {
3384352f7f91STakashi Iwai 		int err;
3385352f7f91STakashi Iwai 		int nid = spec->autocfg.inputs[1].pin;
3386352f7f91STakashi Iwai 		err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0);
3387352f7f91STakashi Iwai 		if (err < 0)
3388352f7f91STakashi Iwai 			return err;
3389352f7f91STakashi Iwai 		err = snd_hda_jack_detect_enable(codec, nid, 0);
3390352f7f91STakashi Iwai 		if (err < 0)
3391352f7f91STakashi Iwai 			return err;
3392352f7f91STakashi Iwai 	}
3393352f7f91STakashi Iwai 
3394352f7f91STakashi Iwai 	err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
3395352f7f91STakashi Iwai 	if (err < 0)
3396352f7f91STakashi Iwai 		return err;
3397352f7f91STakashi Iwai 
3398352f7f91STakashi Iwai 	return 0;
3399352f7f91STakashi Iwai }
3400352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_controls);
3401352f7f91STakashi Iwai 
3402352f7f91STakashi Iwai 
3403352f7f91STakashi Iwai /*
3404352f7f91STakashi Iwai  * PCM definitions
3405352f7f91STakashi Iwai  */
3406352f7f91STakashi Iwai 
3407e6b85f3cSTakashi Iwai static void call_pcm_playback_hook(struct hda_pcm_stream *hinfo,
3408e6b85f3cSTakashi Iwai 				   struct hda_codec *codec,
3409e6b85f3cSTakashi Iwai 				   struct snd_pcm_substream *substream,
3410e6b85f3cSTakashi Iwai 				   int action)
3411e6b85f3cSTakashi Iwai {
3412e6b85f3cSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3413e6b85f3cSTakashi Iwai 	if (spec->pcm_playback_hook)
3414e6b85f3cSTakashi Iwai 		spec->pcm_playback_hook(hinfo, codec, substream, action);
3415e6b85f3cSTakashi Iwai }
3416e6b85f3cSTakashi Iwai 
3417352f7f91STakashi Iwai /*
3418352f7f91STakashi Iwai  * Analog playback callbacks
3419352f7f91STakashi Iwai  */
3420352f7f91STakashi Iwai static int playback_pcm_open(struct hda_pcm_stream *hinfo,
3421352f7f91STakashi Iwai 			     struct hda_codec *codec,
3422352f7f91STakashi Iwai 			     struct snd_pcm_substream *substream)
3423352f7f91STakashi Iwai {
3424352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
342538cf6f1aSTakashi Iwai 	int err;
342638cf6f1aSTakashi Iwai 
342738cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
342838cf6f1aSTakashi Iwai 	err = snd_hda_multi_out_analog_open(codec,
342938cf6f1aSTakashi Iwai 					    &spec->multiout, substream,
3430352f7f91STakashi Iwai 					     hinfo);
3431e6b85f3cSTakashi Iwai 	if (!err) {
343238cf6f1aSTakashi Iwai 		spec->active_streams |= 1 << STREAM_MULTI_OUT;
3433e6b85f3cSTakashi Iwai 		call_pcm_playback_hook(hinfo, codec, substream,
3434e6b85f3cSTakashi Iwai 				       HDA_GEN_PCM_ACT_OPEN);
3435e6b85f3cSTakashi Iwai 	}
343638cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
343738cf6f1aSTakashi Iwai 	return err;
3438352f7f91STakashi Iwai }
3439352f7f91STakashi Iwai 
3440352f7f91STakashi Iwai static int playback_pcm_prepare(struct hda_pcm_stream *hinfo,
344197ec558aSTakashi Iwai 				struct hda_codec *codec,
344297ec558aSTakashi Iwai 				unsigned int stream_tag,
344397ec558aSTakashi Iwai 				unsigned int format,
344497ec558aSTakashi Iwai 				struct snd_pcm_substream *substream)
344597ec558aSTakashi Iwai {
3446352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3447e6b85f3cSTakashi Iwai 	int err;
3448e6b85f3cSTakashi Iwai 
3449e6b85f3cSTakashi Iwai 	err = snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
3450352f7f91STakashi Iwai 					       stream_tag, format, substream);
3451e6b85f3cSTakashi Iwai 	if (!err)
3452e6b85f3cSTakashi Iwai 		call_pcm_playback_hook(hinfo, codec, substream,
3453e6b85f3cSTakashi Iwai 				       HDA_GEN_PCM_ACT_PREPARE);
3454e6b85f3cSTakashi Iwai 	return err;
3455352f7f91STakashi Iwai }
345697ec558aSTakashi Iwai 
3457352f7f91STakashi Iwai static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3458352f7f91STakashi Iwai 				struct hda_codec *codec,
3459352f7f91STakashi Iwai 				struct snd_pcm_substream *substream)
3460352f7f91STakashi Iwai {
3461352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3462e6b85f3cSTakashi Iwai 	int err;
3463e6b85f3cSTakashi Iwai 
3464e6b85f3cSTakashi Iwai 	err = snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
3465e6b85f3cSTakashi Iwai 	if (!err)
3466e6b85f3cSTakashi Iwai 		call_pcm_playback_hook(hinfo, codec, substream,
3467e6b85f3cSTakashi Iwai 				       HDA_GEN_PCM_ACT_CLEANUP);
3468e6b85f3cSTakashi Iwai 	return err;
3469352f7f91STakashi Iwai }
3470352f7f91STakashi Iwai 
347138cf6f1aSTakashi Iwai static int playback_pcm_close(struct hda_pcm_stream *hinfo,
347238cf6f1aSTakashi Iwai 			      struct hda_codec *codec,
347338cf6f1aSTakashi Iwai 			      struct snd_pcm_substream *substream)
347438cf6f1aSTakashi Iwai {
347538cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
347638cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
347738cf6f1aSTakashi Iwai 	spec->active_streams &= ~(1 << STREAM_MULTI_OUT);
3478e6b85f3cSTakashi Iwai 	call_pcm_playback_hook(hinfo, codec, substream,
3479e6b85f3cSTakashi Iwai 			       HDA_GEN_PCM_ACT_CLOSE);
348038cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
348138cf6f1aSTakashi Iwai 	return 0;
348238cf6f1aSTakashi Iwai }
348338cf6f1aSTakashi Iwai 
348438cf6f1aSTakashi Iwai static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo,
348538cf6f1aSTakashi Iwai 				 struct hda_codec *codec,
348638cf6f1aSTakashi Iwai 				 struct snd_pcm_substream *substream)
348738cf6f1aSTakashi Iwai {
348838cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
348938cf6f1aSTakashi Iwai 	int err = 0;
349038cf6f1aSTakashi Iwai 
349138cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
349238cf6f1aSTakashi Iwai 	if (!spec->indep_hp_enabled)
349338cf6f1aSTakashi Iwai 		err = -EBUSY;
349438cf6f1aSTakashi Iwai 	else
349538cf6f1aSTakashi Iwai 		spec->active_streams |= 1 << STREAM_INDEP_HP;
3496e6b85f3cSTakashi Iwai 	call_pcm_playback_hook(hinfo, codec, substream,
3497e6b85f3cSTakashi Iwai 			       HDA_GEN_PCM_ACT_OPEN);
349838cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
349938cf6f1aSTakashi Iwai 	return err;
350038cf6f1aSTakashi Iwai }
350138cf6f1aSTakashi Iwai 
350238cf6f1aSTakashi Iwai static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo,
350338cf6f1aSTakashi Iwai 				  struct hda_codec *codec,
350438cf6f1aSTakashi Iwai 				  struct snd_pcm_substream *substream)
350538cf6f1aSTakashi Iwai {
350638cf6f1aSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
350738cf6f1aSTakashi Iwai 	mutex_lock(&spec->pcm_mutex);
350838cf6f1aSTakashi Iwai 	spec->active_streams &= ~(1 << STREAM_INDEP_HP);
3509e6b85f3cSTakashi Iwai 	call_pcm_playback_hook(hinfo, codec, substream,
3510e6b85f3cSTakashi Iwai 			       HDA_GEN_PCM_ACT_CLOSE);
351138cf6f1aSTakashi Iwai 	mutex_unlock(&spec->pcm_mutex);
351238cf6f1aSTakashi Iwai 	return 0;
351338cf6f1aSTakashi Iwai }
351438cf6f1aSTakashi Iwai 
3515e6b85f3cSTakashi Iwai static int alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3516e6b85f3cSTakashi Iwai 				    struct hda_codec *codec,
3517e6b85f3cSTakashi Iwai 				    unsigned int stream_tag,
3518e6b85f3cSTakashi Iwai 				    unsigned int format,
3519e6b85f3cSTakashi Iwai 				    struct snd_pcm_substream *substream)
3520e6b85f3cSTakashi Iwai {
3521e6b85f3cSTakashi Iwai 	snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
3522e6b85f3cSTakashi Iwai 	call_pcm_playback_hook(hinfo, codec, substream,
3523e6b85f3cSTakashi Iwai 			       HDA_GEN_PCM_ACT_PREPARE);
3524e6b85f3cSTakashi Iwai 	return 0;
3525e6b85f3cSTakashi Iwai }
3526e6b85f3cSTakashi Iwai 
3527e6b85f3cSTakashi Iwai static int alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3528e6b85f3cSTakashi Iwai 				    struct hda_codec *codec,
3529e6b85f3cSTakashi Iwai 				    struct snd_pcm_substream *substream)
3530e6b85f3cSTakashi Iwai {
3531e6b85f3cSTakashi Iwai 	snd_hda_codec_cleanup_stream(codec, hinfo->nid);
3532e6b85f3cSTakashi Iwai 	call_pcm_playback_hook(hinfo, codec, substream,
3533e6b85f3cSTakashi Iwai 			       HDA_GEN_PCM_ACT_CLEANUP);
3534e6b85f3cSTakashi Iwai 	return 0;
3535e6b85f3cSTakashi Iwai }
3536e6b85f3cSTakashi Iwai 
3537352f7f91STakashi Iwai /*
3538352f7f91STakashi Iwai  * Digital out
3539352f7f91STakashi Iwai  */
3540352f7f91STakashi Iwai static int dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
3541352f7f91STakashi Iwai 				 struct hda_codec *codec,
3542352f7f91STakashi Iwai 				 struct snd_pcm_substream *substream)
3543352f7f91STakashi Iwai {
3544352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3545352f7f91STakashi Iwai 	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
3546352f7f91STakashi Iwai }
3547352f7f91STakashi Iwai 
3548352f7f91STakashi Iwai static int dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3549352f7f91STakashi Iwai 				    struct hda_codec *codec,
3550352f7f91STakashi Iwai 				    unsigned int stream_tag,
3551352f7f91STakashi Iwai 				    unsigned int format,
3552352f7f91STakashi Iwai 				    struct snd_pcm_substream *substream)
3553352f7f91STakashi Iwai {
3554352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3555352f7f91STakashi Iwai 	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
3556352f7f91STakashi Iwai 					     stream_tag, format, substream);
3557352f7f91STakashi Iwai }
3558352f7f91STakashi Iwai 
3559352f7f91STakashi Iwai static int dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3560352f7f91STakashi Iwai 				    struct hda_codec *codec,
3561352f7f91STakashi Iwai 				    struct snd_pcm_substream *substream)
3562352f7f91STakashi Iwai {
3563352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3564352f7f91STakashi Iwai 	return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
3565352f7f91STakashi Iwai }
3566352f7f91STakashi Iwai 
3567352f7f91STakashi Iwai static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
3568352f7f91STakashi Iwai 				  struct hda_codec *codec,
3569352f7f91STakashi Iwai 				  struct snd_pcm_substream *substream)
3570352f7f91STakashi Iwai {
3571352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3572352f7f91STakashi Iwai 	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
3573352f7f91STakashi Iwai }
3574352f7f91STakashi Iwai 
3575352f7f91STakashi Iwai /*
3576352f7f91STakashi Iwai  * Analog capture
3577352f7f91STakashi Iwai  */
3578352f7f91STakashi Iwai static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
3579352f7f91STakashi Iwai 				   struct hda_codec *codec,
3580352f7f91STakashi Iwai 				   unsigned int stream_tag,
3581352f7f91STakashi Iwai 				   unsigned int format,
3582352f7f91STakashi Iwai 				   struct snd_pcm_substream *substream)
3583352f7f91STakashi Iwai {
3584352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3585352f7f91STakashi Iwai 
3586352f7f91STakashi Iwai 	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
358797ec558aSTakashi Iwai 				   stream_tag, 0, format);
358897ec558aSTakashi Iwai 	return 0;
358997ec558aSTakashi Iwai }
359097ec558aSTakashi Iwai 
3591352f7f91STakashi Iwai static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
359297ec558aSTakashi Iwai 				   struct hda_codec *codec,
359397ec558aSTakashi Iwai 				   struct snd_pcm_substream *substream)
359497ec558aSTakashi Iwai {
3595352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
359697ec558aSTakashi Iwai 
3597352f7f91STakashi Iwai 	snd_hda_codec_cleanup_stream(codec,
3598352f7f91STakashi Iwai 				     spec->adc_nids[substream->number + 1]);
359997ec558aSTakashi Iwai 	return 0;
360097ec558aSTakashi Iwai }
360197ec558aSTakashi Iwai 
3602352f7f91STakashi Iwai /*
3603352f7f91STakashi Iwai  */
3604352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_playback = {
3605352f7f91STakashi Iwai 	.substreams = 1,
3606352f7f91STakashi Iwai 	.channels_min = 2,
3607352f7f91STakashi Iwai 	.channels_max = 8,
3608352f7f91STakashi Iwai 	/* NID is set in build_pcms */
3609352f7f91STakashi Iwai 	.ops = {
3610352f7f91STakashi Iwai 		.open = playback_pcm_open,
361138cf6f1aSTakashi Iwai 		.close = playback_pcm_close,
3612352f7f91STakashi Iwai 		.prepare = playback_pcm_prepare,
3613352f7f91STakashi Iwai 		.cleanup = playback_pcm_cleanup
3614352f7f91STakashi Iwai 	},
3615352f7f91STakashi Iwai };
3616352f7f91STakashi Iwai 
3617352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_capture = {
3618352f7f91STakashi Iwai 	.substreams = 1,
3619352f7f91STakashi Iwai 	.channels_min = 2,
3620352f7f91STakashi Iwai 	.channels_max = 2,
3621352f7f91STakashi Iwai 	/* NID is set in build_pcms */
3622352f7f91STakashi Iwai };
3623352f7f91STakashi Iwai 
3624352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_playback = {
3625352f7f91STakashi Iwai 	.substreams = 1,
3626352f7f91STakashi Iwai 	.channels_min = 2,
3627352f7f91STakashi Iwai 	.channels_max = 2,
3628352f7f91STakashi Iwai 	/* NID is set in build_pcms */
362938cf6f1aSTakashi Iwai 	.ops = {
363038cf6f1aSTakashi Iwai 		.open = alt_playback_pcm_open,
3631e6b85f3cSTakashi Iwai 		.close = alt_playback_pcm_close,
3632e6b85f3cSTakashi Iwai 		.prepare = alt_playback_pcm_prepare,
3633e6b85f3cSTakashi Iwai 		.cleanup = alt_playback_pcm_cleanup
363438cf6f1aSTakashi Iwai 	},
3635352f7f91STakashi Iwai };
3636352f7f91STakashi Iwai 
3637352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_capture = {
3638352f7f91STakashi Iwai 	.substreams = 2, /* can be overridden */
3639352f7f91STakashi Iwai 	.channels_min = 2,
3640352f7f91STakashi Iwai 	.channels_max = 2,
3641352f7f91STakashi Iwai 	/* NID is set in build_pcms */
3642352f7f91STakashi Iwai 	.ops = {
3643352f7f91STakashi Iwai 		.prepare = alt_capture_pcm_prepare,
3644352f7f91STakashi Iwai 		.cleanup = alt_capture_pcm_cleanup
3645352f7f91STakashi Iwai 	},
3646352f7f91STakashi Iwai };
3647352f7f91STakashi Iwai 
3648352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_playback = {
3649352f7f91STakashi Iwai 	.substreams = 1,
3650352f7f91STakashi Iwai 	.channels_min = 2,
3651352f7f91STakashi Iwai 	.channels_max = 2,
3652352f7f91STakashi Iwai 	/* NID is set in build_pcms */
3653352f7f91STakashi Iwai 	.ops = {
3654352f7f91STakashi Iwai 		.open = dig_playback_pcm_open,
3655352f7f91STakashi Iwai 		.close = dig_playback_pcm_close,
3656352f7f91STakashi Iwai 		.prepare = dig_playback_pcm_prepare,
3657352f7f91STakashi Iwai 		.cleanup = dig_playback_pcm_cleanup
3658352f7f91STakashi Iwai 	},
3659352f7f91STakashi Iwai };
3660352f7f91STakashi Iwai 
3661352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_capture = {
3662352f7f91STakashi Iwai 	.substreams = 1,
3663352f7f91STakashi Iwai 	.channels_min = 2,
3664352f7f91STakashi Iwai 	.channels_max = 2,
3665352f7f91STakashi Iwai 	/* NID is set in build_pcms */
3666352f7f91STakashi Iwai };
3667352f7f91STakashi Iwai 
3668352f7f91STakashi Iwai /* Used by build_pcms to flag that a PCM has no playback stream */
3669352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_null_stream = {
3670352f7f91STakashi Iwai 	.substreams = 0,
3671352f7f91STakashi Iwai 	.channels_min = 0,
3672352f7f91STakashi Iwai 	.channels_max = 0,
3673352f7f91STakashi Iwai };
3674352f7f91STakashi Iwai 
3675352f7f91STakashi Iwai /*
3676352f7f91STakashi Iwai  * dynamic changing ADC PCM streams
3677352f7f91STakashi Iwai  */
3678352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur)
36791da177e4SLinus Torvalds {
3680352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3681352f7f91STakashi Iwai 	hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]];
36821da177e4SLinus Torvalds 
3683352f7f91STakashi Iwai 	if (spec->cur_adc && spec->cur_adc != new_adc) {
3684352f7f91STakashi Iwai 		/* stream is running, let's swap the current ADC */
3685352f7f91STakashi Iwai 		__snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
3686352f7f91STakashi Iwai 		spec->cur_adc = new_adc;
3687352f7f91STakashi Iwai 		snd_hda_codec_setup_stream(codec, new_adc,
3688352f7f91STakashi Iwai 					   spec->cur_adc_stream_tag, 0,
3689352f7f91STakashi Iwai 					   spec->cur_adc_format);
3690352f7f91STakashi Iwai 		return true;
3691352f7f91STakashi Iwai 	}
3692352f7f91STakashi Iwai 	return false;
3693352f7f91STakashi Iwai }
3694352f7f91STakashi Iwai 
3695352f7f91STakashi Iwai /* analog capture with dynamic dual-adc changes */
3696352f7f91STakashi Iwai static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
3697352f7f91STakashi Iwai 				       struct hda_codec *codec,
3698352f7f91STakashi Iwai 				       unsigned int stream_tag,
3699352f7f91STakashi Iwai 				       unsigned int format,
3700352f7f91STakashi Iwai 				       struct snd_pcm_substream *substream)
3701352f7f91STakashi Iwai {
3702352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3703352f7f91STakashi Iwai 	spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]];
3704352f7f91STakashi Iwai 	spec->cur_adc_stream_tag = stream_tag;
3705352f7f91STakashi Iwai 	spec->cur_adc_format = format;
3706352f7f91STakashi Iwai 	snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
37071da177e4SLinus Torvalds 	return 0;
37081da177e4SLinus Torvalds }
37091da177e4SLinus Torvalds 
3710352f7f91STakashi Iwai static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
3711352f7f91STakashi Iwai 				       struct hda_codec *codec,
3712352f7f91STakashi Iwai 				       struct snd_pcm_substream *substream)
3713352f7f91STakashi Iwai {
3714352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3715352f7f91STakashi Iwai 	snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
3716352f7f91STakashi Iwai 	spec->cur_adc = 0;
3717352f7f91STakashi Iwai 	return 0;
3718352f7f91STakashi Iwai }
3719352f7f91STakashi Iwai 
3720352f7f91STakashi Iwai static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = {
3721352f7f91STakashi Iwai 	.substreams = 1,
3722352f7f91STakashi Iwai 	.channels_min = 2,
3723352f7f91STakashi Iwai 	.channels_max = 2,
3724352f7f91STakashi Iwai 	.nid = 0, /* fill later */
3725352f7f91STakashi Iwai 	.ops = {
3726352f7f91STakashi Iwai 		.prepare = dyn_adc_capture_pcm_prepare,
3727352f7f91STakashi Iwai 		.cleanup = dyn_adc_capture_pcm_cleanup
3728352f7f91STakashi Iwai 	},
3729352f7f91STakashi Iwai };
3730352f7f91STakashi Iwai 
3731f873e536STakashi Iwai static void fill_pcm_stream_name(char *str, size_t len, const char *sfx,
3732f873e536STakashi Iwai 				 const char *chip_name)
3733f873e536STakashi Iwai {
3734f873e536STakashi Iwai 	char *p;
3735f873e536STakashi Iwai 
3736f873e536STakashi Iwai 	if (*str)
3737f873e536STakashi Iwai 		return;
3738f873e536STakashi Iwai 	strlcpy(str, chip_name, len);
3739f873e536STakashi Iwai 
3740f873e536STakashi Iwai 	/* drop non-alnum chars after a space */
3741f873e536STakashi Iwai 	for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) {
3742f873e536STakashi Iwai 		if (!isalnum(p[1])) {
3743f873e536STakashi Iwai 			*p = 0;
3744f873e536STakashi Iwai 			break;
3745f873e536STakashi Iwai 		}
3746f873e536STakashi Iwai 	}
3747f873e536STakashi Iwai 	strlcat(str, sfx, len);
3748f873e536STakashi Iwai }
3749f873e536STakashi Iwai 
3750352f7f91STakashi Iwai /* build PCM streams based on the parsed results */
3751352f7f91STakashi Iwai int snd_hda_gen_build_pcms(struct hda_codec *codec)
3752352f7f91STakashi Iwai {
3753352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3754352f7f91STakashi Iwai 	struct hda_pcm *info = spec->pcm_rec;
3755352f7f91STakashi Iwai 	const struct hda_pcm_stream *p;
3756352f7f91STakashi Iwai 	bool have_multi_adcs;
3757352f7f91STakashi Iwai 
37581da177e4SLinus Torvalds 	codec->num_pcms = 1;
37591da177e4SLinus Torvalds 	codec->pcm_info = info;
37601da177e4SLinus Torvalds 
3761352f7f91STakashi Iwai 	if (spec->no_analog)
3762352f7f91STakashi Iwai 		goto skip_analog;
3763352f7f91STakashi Iwai 
3764f873e536STakashi Iwai 	fill_pcm_stream_name(spec->stream_name_analog,
3765f873e536STakashi Iwai 			     sizeof(spec->stream_name_analog),
3766f873e536STakashi Iwai 			     " Analog", codec->chip_name);
3767352f7f91STakashi Iwai 	info->name = spec->stream_name_analog;
3768352f7f91STakashi Iwai 
3769352f7f91STakashi Iwai 	if (spec->multiout.num_dacs > 0) {
3770352f7f91STakashi Iwai 		p = spec->stream_analog_playback;
3771352f7f91STakashi Iwai 		if (!p)
3772352f7f91STakashi Iwai 			p = &pcm_analog_playback;
3773352f7f91STakashi Iwai 		info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
3774352f7f91STakashi Iwai 		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
3775352f7f91STakashi Iwai 		info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
3776352f7f91STakashi Iwai 			spec->multiout.max_channels;
3777352f7f91STakashi Iwai 		if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
3778352f7f91STakashi Iwai 		    spec->autocfg.line_outs == 2)
3779352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap =
3780352f7f91STakashi Iwai 				snd_pcm_2_1_chmaps;
3781352f7f91STakashi Iwai 	}
3782352f7f91STakashi Iwai 	if (spec->num_adc_nids) {
3783352f7f91STakashi Iwai 		p = spec->stream_analog_capture;
3784352f7f91STakashi Iwai 		if (!p) {
3785352f7f91STakashi Iwai 			if (spec->dyn_adc_switch)
3786352f7f91STakashi Iwai 				p = &dyn_adc_pcm_analog_capture;
3787352f7f91STakashi Iwai 			else
3788352f7f91STakashi Iwai 				p = &pcm_analog_capture;
3789352f7f91STakashi Iwai 		}
3790352f7f91STakashi Iwai 		info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
3791352f7f91STakashi Iwai 		info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
3792352f7f91STakashi Iwai 	}
3793352f7f91STakashi Iwai 
3794352f7f91STakashi Iwai  skip_analog:
3795352f7f91STakashi Iwai 	/* SPDIF for stream index #1 */
3796352f7f91STakashi Iwai 	if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
3797f873e536STakashi Iwai 		fill_pcm_stream_name(spec->stream_name_digital,
3798352f7f91STakashi Iwai 				     sizeof(spec->stream_name_digital),
3799f873e536STakashi Iwai 				     " Digital", codec->chip_name);
3800352f7f91STakashi Iwai 		codec->num_pcms = 2;
3801352f7f91STakashi Iwai 		codec->slave_dig_outs = spec->multiout.slave_dig_outs;
3802352f7f91STakashi Iwai 		info = spec->pcm_rec + 1;
3803352f7f91STakashi Iwai 		info->name = spec->stream_name_digital;
3804352f7f91STakashi Iwai 		if (spec->dig_out_type)
3805352f7f91STakashi Iwai 			info->pcm_type = spec->dig_out_type;
3806352f7f91STakashi Iwai 		else
3807352f7f91STakashi Iwai 			info->pcm_type = HDA_PCM_TYPE_SPDIF;
3808352f7f91STakashi Iwai 		if (spec->multiout.dig_out_nid) {
3809352f7f91STakashi Iwai 			p = spec->stream_digital_playback;
3810352f7f91STakashi Iwai 			if (!p)
3811352f7f91STakashi Iwai 				p = &pcm_digital_playback;
3812352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
3813352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
3814352f7f91STakashi Iwai 		}
3815352f7f91STakashi Iwai 		if (spec->dig_in_nid) {
3816352f7f91STakashi Iwai 			p = spec->stream_digital_capture;
3817352f7f91STakashi Iwai 			if (!p)
3818352f7f91STakashi Iwai 				p = &pcm_digital_capture;
3819352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
3820352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
3821352f7f91STakashi Iwai 		}
3822352f7f91STakashi Iwai 	}
3823352f7f91STakashi Iwai 
3824352f7f91STakashi Iwai 	if (spec->no_analog)
3825352f7f91STakashi Iwai 		return 0;
3826352f7f91STakashi Iwai 
3827352f7f91STakashi Iwai 	/* If the use of more than one ADC is requested for the current
3828352f7f91STakashi Iwai 	 * model, configure a second analog capture-only PCM.
3829352f7f91STakashi Iwai 	 */
3830352f7f91STakashi Iwai 	have_multi_adcs = (spec->num_adc_nids > 1) &&
3831352f7f91STakashi Iwai 		!spec->dyn_adc_switch && !spec->auto_mic;
3832352f7f91STakashi Iwai 	/* Additional Analaog capture for index #2 */
3833352f7f91STakashi Iwai 	if (spec->alt_dac_nid || have_multi_adcs) {
3834352f7f91STakashi Iwai 		codec->num_pcms = 3;
3835352f7f91STakashi Iwai 		info = spec->pcm_rec + 2;
3836352f7f91STakashi Iwai 		info->name = spec->stream_name_analog;
3837352f7f91STakashi Iwai 		if (spec->alt_dac_nid) {
3838352f7f91STakashi Iwai 			p = spec->stream_analog_alt_playback;
3839352f7f91STakashi Iwai 			if (!p)
3840352f7f91STakashi Iwai 				p = &pcm_analog_alt_playback;
3841352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
3842352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
3843352f7f91STakashi Iwai 				spec->alt_dac_nid;
3844352f7f91STakashi Iwai 		} else {
3845352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3846352f7f91STakashi Iwai 				pcm_null_stream;
3847352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
3848352f7f91STakashi Iwai 		}
3849352f7f91STakashi Iwai 		if (have_multi_adcs) {
3850352f7f91STakashi Iwai 			p = spec->stream_analog_alt_capture;
3851352f7f91STakashi Iwai 			if (!p)
3852352f7f91STakashi Iwai 				p = &pcm_analog_alt_capture;
3853352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
3854352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
3855352f7f91STakashi Iwai 				spec->adc_nids[1];
3856352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
3857352f7f91STakashi Iwai 				spec->num_adc_nids - 1;
3858352f7f91STakashi Iwai 		} else {
3859352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3860352f7f91STakashi Iwai 				pcm_null_stream;
3861352f7f91STakashi Iwai 			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
3862352f7f91STakashi Iwai 		}
38631da177e4SLinus Torvalds 	}
38641da177e4SLinus Torvalds 
38651da177e4SLinus Torvalds 	return 0;
38661da177e4SLinus Torvalds }
3867352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_pcms);
3868352f7f91STakashi Iwai 
3869352f7f91STakashi Iwai 
3870352f7f91STakashi Iwai /*
3871352f7f91STakashi Iwai  * Standard auto-parser initializations
3872352f7f91STakashi Iwai  */
3873352f7f91STakashi Iwai 
3874d4156930STakashi Iwai /* configure the given path as a proper output */
38752c12c30dSTakashi Iwai static void set_output_and_unmute(struct hda_codec *codec, int path_idx)
3876352f7f91STakashi Iwai {
3877352f7f91STakashi Iwai 	struct nid_path *path;
3878d4156930STakashi Iwai 	hda_nid_t pin;
3879352f7f91STakashi Iwai 
3880196c1766STakashi Iwai 	path = snd_hda_get_path_from_idx(codec, path_idx);
3881d4156930STakashi Iwai 	if (!path || !path->depth)
3882352f7f91STakashi Iwai 		return;
3883d4156930STakashi Iwai 	pin = path->path[path->depth - 1];
38842c12c30dSTakashi Iwai 	restore_pin_ctl(codec, pin);
3885e1284af7STakashi Iwai 	snd_hda_activate_path(codec, path, path->active, true);
3886e1284af7STakashi Iwai 	set_pin_eapd(codec, pin, path->active);
3887352f7f91STakashi Iwai }
3888352f7f91STakashi Iwai 
3889352f7f91STakashi Iwai /* initialize primary output paths */
3890352f7f91STakashi Iwai static void init_multi_out(struct hda_codec *codec)
3891352f7f91STakashi Iwai {
3892352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3893352f7f91STakashi Iwai 	int i;
3894352f7f91STakashi Iwai 
3895d4156930STakashi Iwai 	for (i = 0; i < spec->autocfg.line_outs; i++)
38962c12c30dSTakashi Iwai 		set_output_and_unmute(codec, spec->out_paths[i]);
3897352f7f91STakashi Iwai }
3898352f7f91STakashi Iwai 
3899db23fd19STakashi Iwai 
39002c12c30dSTakashi Iwai static void __init_extra_out(struct hda_codec *codec, int num_outs, int *paths)
3901352f7f91STakashi Iwai {
3902352f7f91STakashi Iwai 	int i;
3903352f7f91STakashi Iwai 
3904d4156930STakashi Iwai 	for (i = 0; i < num_outs; i++)
39052c12c30dSTakashi Iwai 		set_output_and_unmute(codec, paths[i]);
3906352f7f91STakashi Iwai }
3907db23fd19STakashi Iwai 
3908db23fd19STakashi Iwai /* initialize hp and speaker paths */
3909db23fd19STakashi Iwai static void init_extra_out(struct hda_codec *codec)
3910db23fd19STakashi Iwai {
3911db23fd19STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3912db23fd19STakashi Iwai 
3913db23fd19STakashi Iwai 	if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT)
39142c12c30dSTakashi Iwai 		__init_extra_out(codec, spec->autocfg.hp_outs, spec->hp_paths);
3915db23fd19STakashi Iwai 	if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT)
3916db23fd19STakashi Iwai 		__init_extra_out(codec, spec->autocfg.speaker_outs,
39172c12c30dSTakashi Iwai 				 spec->speaker_paths);
3918352f7f91STakashi Iwai }
3919352f7f91STakashi Iwai 
3920352f7f91STakashi Iwai /* initialize multi-io paths */
3921352f7f91STakashi Iwai static void init_multi_io(struct hda_codec *codec)
3922352f7f91STakashi Iwai {
3923352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3924352f7f91STakashi Iwai 	int i;
3925352f7f91STakashi Iwai 
3926352f7f91STakashi Iwai 	for (i = 0; i < spec->multi_ios; i++) {
3927352f7f91STakashi Iwai 		hda_nid_t pin = spec->multi_io[i].pin;
3928352f7f91STakashi Iwai 		struct nid_path *path;
3929196c1766STakashi Iwai 		path = get_multiio_path(codec, i);
3930352f7f91STakashi Iwai 		if (!path)
3931352f7f91STakashi Iwai 			continue;
3932352f7f91STakashi Iwai 		if (!spec->multi_io[i].ctl_in)
3933352f7f91STakashi Iwai 			spec->multi_io[i].ctl_in =
39342c12c30dSTakashi Iwai 				snd_hda_codec_get_pin_target(codec, pin);
3935352f7f91STakashi Iwai 		snd_hda_activate_path(codec, path, path->active, true);
3936352f7f91STakashi Iwai 	}
3937352f7f91STakashi Iwai }
3938352f7f91STakashi Iwai 
3939352f7f91STakashi Iwai /* set up input pins and loopback paths */
3940352f7f91STakashi Iwai static void init_analog_input(struct hda_codec *codec)
3941352f7f91STakashi Iwai {
3942352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3943352f7f91STakashi Iwai 	struct auto_pin_cfg *cfg = &spec->autocfg;
3944352f7f91STakashi Iwai 	int i;
3945352f7f91STakashi Iwai 
3946352f7f91STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
3947352f7f91STakashi Iwai 		hda_nid_t nid = cfg->inputs[i].pin;
3948352f7f91STakashi Iwai 		if (is_input_pin(codec, nid))
39492c12c30dSTakashi Iwai 			restore_pin_ctl(codec, nid);
3950352f7f91STakashi Iwai 
3951352f7f91STakashi Iwai 		/* init loopback inputs */
3952352f7f91STakashi Iwai 		if (spec->mixer_nid) {
3953352f7f91STakashi Iwai 			struct nid_path *path;
3954196c1766STakashi Iwai 			path = snd_hda_get_path_from_idx(codec, spec->loopback_paths[i]);
3955352f7f91STakashi Iwai 			if (path)
3956352f7f91STakashi Iwai 				snd_hda_activate_path(codec, path,
3957352f7f91STakashi Iwai 						      path->active, false);
3958352f7f91STakashi Iwai 		}
3959352f7f91STakashi Iwai 	}
3960352f7f91STakashi Iwai }
3961352f7f91STakashi Iwai 
3962352f7f91STakashi Iwai /* initialize ADC paths */
3963352f7f91STakashi Iwai static void init_input_src(struct hda_codec *codec)
3964352f7f91STakashi Iwai {
3965352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3966352f7f91STakashi Iwai 	struct hda_input_mux *imux = &spec->input_mux;
3967352f7f91STakashi Iwai 	struct nid_path *path;
3968352f7f91STakashi Iwai 	int i, c, nums;
3969352f7f91STakashi Iwai 
3970352f7f91STakashi Iwai 	if (spec->dyn_adc_switch)
3971352f7f91STakashi Iwai 		nums = 1;
3972352f7f91STakashi Iwai 	else
3973352f7f91STakashi Iwai 		nums = spec->num_adc_nids;
3974352f7f91STakashi Iwai 
3975352f7f91STakashi Iwai 	for (c = 0; c < nums; c++) {
3976352f7f91STakashi Iwai 		for (i = 0; i < imux->num_items; i++) {
3977c697b716STakashi Iwai 			path = get_input_path(codec, c, i);
3978352f7f91STakashi Iwai 			if (path) {
3979352f7f91STakashi Iwai 				bool active = path->active;
3980352f7f91STakashi Iwai 				if (i == spec->cur_mux[c])
3981352f7f91STakashi Iwai 					active = true;
3982352f7f91STakashi Iwai 				snd_hda_activate_path(codec, path, active, false);
3983352f7f91STakashi Iwai 			}
3984352f7f91STakashi Iwai 		}
3985352f7f91STakashi Iwai 	}
3986352f7f91STakashi Iwai 
3987352f7f91STakashi Iwai 	if (spec->shared_mic_hp)
3988352f7f91STakashi Iwai 		update_shared_mic_hp(codec, spec->cur_mux[0]);
3989352f7f91STakashi Iwai 
3990352f7f91STakashi Iwai 	if (spec->cap_sync_hook)
3991352f7f91STakashi Iwai 		spec->cap_sync_hook(codec);
3992352f7f91STakashi Iwai }
3993352f7f91STakashi Iwai 
3994352f7f91STakashi Iwai /* set right pin controls for digital I/O */
3995352f7f91STakashi Iwai static void init_digital(struct hda_codec *codec)
3996352f7f91STakashi Iwai {
3997352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
3998352f7f91STakashi Iwai 	int i;
3999352f7f91STakashi Iwai 	hda_nid_t pin;
4000352f7f91STakashi Iwai 
4001d4156930STakashi Iwai 	for (i = 0; i < spec->autocfg.dig_outs; i++)
40022c12c30dSTakashi Iwai 		set_output_and_unmute(codec, spec->digout_paths[i]);
4003352f7f91STakashi Iwai 	pin = spec->autocfg.dig_in_pin;
40042430d7b7STakashi Iwai 	if (pin) {
40052430d7b7STakashi Iwai 		struct nid_path *path;
40062c12c30dSTakashi Iwai 		restore_pin_ctl(codec, pin);
40072430d7b7STakashi Iwai 		path = snd_hda_get_path_from_idx(codec, spec->digin_path);
40082430d7b7STakashi Iwai 		if (path)
40092430d7b7STakashi Iwai 			snd_hda_activate_path(codec, path, path->active, false);
40102430d7b7STakashi Iwai 	}
4011352f7f91STakashi Iwai }
4012352f7f91STakashi Iwai 
4013973e4972STakashi Iwai /* clear unsol-event tags on unused pins; Conexant codecs seem to leave
4014973e4972STakashi Iwai  * invalid unsol tags by some reason
4015973e4972STakashi Iwai  */
4016973e4972STakashi Iwai static void clear_unsol_on_unused_pins(struct hda_codec *codec)
4017973e4972STakashi Iwai {
4018973e4972STakashi Iwai 	int i;
4019973e4972STakashi Iwai 
4020973e4972STakashi Iwai 	for (i = 0; i < codec->init_pins.used; i++) {
4021973e4972STakashi Iwai 		struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
4022973e4972STakashi Iwai 		hda_nid_t nid = pin->nid;
4023973e4972STakashi Iwai 		if (is_jack_detectable(codec, nid) &&
4024973e4972STakashi Iwai 		    !snd_hda_jack_tbl_get(codec, nid))
4025973e4972STakashi Iwai 			snd_hda_codec_update_cache(codec, nid, 0,
4026973e4972STakashi Iwai 					AC_VERB_SET_UNSOLICITED_ENABLE, 0);
4027973e4972STakashi Iwai 	}
4028973e4972STakashi Iwai }
4029973e4972STakashi Iwai 
40305187ac16STakashi Iwai /*
40315187ac16STakashi Iwai  * initialize the generic spec;
40325187ac16STakashi Iwai  * this can be put as patch_ops.init function
40335187ac16STakashi Iwai  */
4034352f7f91STakashi Iwai int snd_hda_gen_init(struct hda_codec *codec)
4035352f7f91STakashi Iwai {
4036352f7f91STakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4037352f7f91STakashi Iwai 
4038352f7f91STakashi Iwai 	if (spec->init_hook)
4039352f7f91STakashi Iwai 		spec->init_hook(codec);
4040352f7f91STakashi Iwai 
4041352f7f91STakashi Iwai 	snd_hda_apply_verbs(codec);
4042352f7f91STakashi Iwai 
40433bbcd274STakashi Iwai 	codec->cached_write = 1;
40443bbcd274STakashi Iwai 
4045352f7f91STakashi Iwai 	init_multi_out(codec);
4046352f7f91STakashi Iwai 	init_extra_out(codec);
4047352f7f91STakashi Iwai 	init_multi_io(codec);
4048352f7f91STakashi Iwai 	init_analog_input(codec);
4049352f7f91STakashi Iwai 	init_input_src(codec);
4050352f7f91STakashi Iwai 	init_digital(codec);
4051352f7f91STakashi Iwai 
4052973e4972STakashi Iwai 	clear_unsol_on_unused_pins(codec);
4053973e4972STakashi Iwai 
4054352f7f91STakashi Iwai 	/* call init functions of standard auto-mute helpers */
40555d550e15STakashi Iwai 	snd_hda_gen_hp_automute(codec, NULL);
40565d550e15STakashi Iwai 	snd_hda_gen_line_automute(codec, NULL);
40575d550e15STakashi Iwai 	snd_hda_gen_mic_autoswitch(codec, NULL);
4058352f7f91STakashi Iwai 
40593bbcd274STakashi Iwai 	snd_hda_codec_flush_amp_cache(codec);
40603bbcd274STakashi Iwai 	snd_hda_codec_flush_cmd_cache(codec);
40613bbcd274STakashi Iwai 
4062352f7f91STakashi Iwai 	if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook)
4063352f7f91STakashi Iwai 		snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
4064352f7f91STakashi Iwai 
4065352f7f91STakashi Iwai 	hda_call_check_power_status(codec, 0x01);
4066352f7f91STakashi Iwai 	return 0;
4067352f7f91STakashi Iwai }
4068fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_init);
4069fce52a3bSTakashi Iwai 
40705187ac16STakashi Iwai /*
40715187ac16STakashi Iwai  * free the generic spec;
40725187ac16STakashi Iwai  * this can be put as patch_ops.free function
40735187ac16STakashi Iwai  */
4074fce52a3bSTakashi Iwai void snd_hda_gen_free(struct hda_codec *codec)
4075fce52a3bSTakashi Iwai {
4076fce52a3bSTakashi Iwai 	snd_hda_gen_spec_free(codec->spec);
4077fce52a3bSTakashi Iwai 	kfree(codec->spec);
4078fce52a3bSTakashi Iwai 	codec->spec = NULL;
4079fce52a3bSTakashi Iwai }
4080fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_free);
4081fce52a3bSTakashi Iwai 
4082fce52a3bSTakashi Iwai #ifdef CONFIG_PM
40835187ac16STakashi Iwai /*
40845187ac16STakashi Iwai  * check the loopback power save state;
40855187ac16STakashi Iwai  * this can be put as patch_ops.check_power_status function
40865187ac16STakashi Iwai  */
4087fce52a3bSTakashi Iwai int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid)
4088fce52a3bSTakashi Iwai {
4089fce52a3bSTakashi Iwai 	struct hda_gen_spec *spec = codec->spec;
4090fce52a3bSTakashi Iwai 	return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
4091fce52a3bSTakashi Iwai }
4092fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_check_power_status);
4093fce52a3bSTakashi Iwai #endif
4094352f7f91STakashi Iwai 
4095352f7f91STakashi Iwai 
4096352f7f91STakashi Iwai /*
4097352f7f91STakashi Iwai  * the generic codec support
4098352f7f91STakashi Iwai  */
40991da177e4SLinus Torvalds 
4100352f7f91STakashi Iwai static const struct hda_codec_ops generic_patch_ops = {
4101352f7f91STakashi Iwai 	.build_controls = snd_hda_gen_build_controls,
4102352f7f91STakashi Iwai 	.build_pcms = snd_hda_gen_build_pcms,
4103352f7f91STakashi Iwai 	.init = snd_hda_gen_init,
4104fce52a3bSTakashi Iwai 	.free = snd_hda_gen_free,
4105352f7f91STakashi Iwai 	.unsol_event = snd_hda_jack_unsol_event,
410683012a7cSTakashi Iwai #ifdef CONFIG_PM
4107fce52a3bSTakashi Iwai 	.check_power_status = snd_hda_gen_check_power_status,
4108cb53c626STakashi Iwai #endif
41091da177e4SLinus Torvalds };
41101da177e4SLinus Torvalds 
41111da177e4SLinus Torvalds int snd_hda_parse_generic_codec(struct hda_codec *codec)
41121da177e4SLinus Torvalds {
4113352f7f91STakashi Iwai 	struct hda_gen_spec *spec;
41141da177e4SLinus Torvalds 	int err;
41151da177e4SLinus Torvalds 
4116e560d8d8STakashi Iwai 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4117352f7f91STakashi Iwai 	if (!spec)
41181da177e4SLinus Torvalds 		return -ENOMEM;
4119352f7f91STakashi Iwai 	snd_hda_gen_spec_init(spec);
41201da177e4SLinus Torvalds 	codec->spec = spec;
41211da177e4SLinus Torvalds 
41229eb413e5STakashi Iwai 	err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0);
41239eb413e5STakashi Iwai 	if (err < 0)
41249eb413e5STakashi Iwai 		return err;
41259eb413e5STakashi Iwai 
41269eb413e5STakashi Iwai 	err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg);
4127352f7f91STakashi Iwai 	if (err < 0)
41281da177e4SLinus Torvalds 		goto error;
41291da177e4SLinus Torvalds 
41301da177e4SLinus Torvalds 	codec->patch_ops = generic_patch_ops;
41311da177e4SLinus Torvalds 	return 0;
41321da177e4SLinus Torvalds 
41331da177e4SLinus Torvalds error:
4134fce52a3bSTakashi Iwai 	snd_hda_gen_free(codec);
41351da177e4SLinus Torvalds 	return err;
41361da177e4SLinus Torvalds }
4137fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_parse_generic_codec);
4138