1d0fa1179SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Universal Interface for Intel High Definition Audio Codec
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Generic widget tree parser
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
81da177e4SLinus Torvalds */
91da177e4SLinus Torvalds
101da177e4SLinus Torvalds #include <linux/init.h>
111da177e4SLinus Torvalds #include <linux/slab.h>
12d81a6d71SPaul Gortmaker #include <linux/export.h>
13352f7f91STakashi Iwai #include <linux/sort.h>
1455196fffSTakashi Iwai #include <linux/delay.h>
15f873e536STakashi Iwai #include <linux/ctype.h>
16f873e536STakashi Iwai #include <linux/string.h>
1729476558STakashi Iwai #include <linux/bitops.h>
18b21bdd0dSTakashi Iwai #include <linux/module.h>
19b3802783STakashi Iwai #include <linux/leds.h>
201da177e4SLinus Torvalds #include <sound/core.h>
21352f7f91STakashi Iwai #include <sound/jack.h>
22d89c6c0cSTakashi Iwai #include <sound/tlv.h>
23be57bfffSPierre-Louis Bossart #include <sound/hda_codec.h>
241da177e4SLinus Torvalds #include "hda_local.h"
25352f7f91STakashi Iwai #include "hda_auto_parser.h"
26352f7f91STakashi Iwai #include "hda_jack.h"
277504b6cdSTakashi Iwai #include "hda_beep.h"
28352f7f91STakashi Iwai #include "hda_generic.h"
291da177e4SLinus Torvalds
301da177e4SLinus Torvalds
31dda42bd0STakashi Iwai /**
32dda42bd0STakashi Iwai * snd_hda_gen_spec_init - initialize hda_gen_spec struct
33dda42bd0STakashi Iwai * @spec: hda_gen_spec object to initialize
34dda42bd0STakashi Iwai *
35dda42bd0STakashi Iwai * Initialize the given hda_gen_spec object.
36dda42bd0STakashi Iwai */
snd_hda_gen_spec_init(struct hda_gen_spec * spec)37352f7f91STakashi Iwai int snd_hda_gen_spec_init(struct hda_gen_spec *spec)
381da177e4SLinus Torvalds {
39352f7f91STakashi Iwai snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
40352f7f91STakashi Iwai snd_array_init(&spec->paths, sizeof(struct nid_path), 8);
410186f4f4STakashi Iwai snd_array_init(&spec->loopback_list, sizeof(struct hda_amp_list), 8);
4238cf6f1aSTakashi Iwai mutex_init(&spec->pcm_mutex);
43352f7f91STakashi Iwai return 0;
44352f7f91STakashi Iwai }
452698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_spec_init);
461da177e4SLinus Torvalds
47dda42bd0STakashi Iwai /**
48dda42bd0STakashi Iwai * snd_hda_gen_add_kctl - Add a new kctl_new struct from the template
49dda42bd0STakashi Iwai * @spec: hda_gen_spec object
50dda42bd0STakashi Iwai * @name: name string to override the template, NULL if unchanged
51dda42bd0STakashi Iwai * @temp: template for the new kctl
52dda42bd0STakashi Iwai *
53dda42bd0STakashi Iwai * Add a new kctl (actually snd_kcontrol_new to be instantiated later)
54dda42bd0STakashi Iwai * element based on the given snd_kcontrol_new template @temp and the
55dda42bd0STakashi Iwai * name string @name to the list in @spec.
56dda42bd0STakashi Iwai * Returns the newly created object or NULL as error.
57dda42bd0STakashi Iwai */
5812c93df6STakashi Iwai struct snd_kcontrol_new *
snd_hda_gen_add_kctl(struct hda_gen_spec * spec,const char * name,const struct snd_kcontrol_new * temp)5912c93df6STakashi Iwai snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
60352f7f91STakashi Iwai const struct snd_kcontrol_new *temp)
61352f7f91STakashi Iwai {
62352f7f91STakashi Iwai struct snd_kcontrol_new *knew = snd_array_new(&spec->kctls);
63352f7f91STakashi Iwai if (!knew)
64352f7f91STakashi Iwai return NULL;
65352f7f91STakashi Iwai *knew = *temp;
66352f7f91STakashi Iwai if (name)
67352f7f91STakashi Iwai knew->name = kstrdup(name, GFP_KERNEL);
68352f7f91STakashi Iwai else if (knew->name)
69352f7f91STakashi Iwai knew->name = kstrdup(knew->name, GFP_KERNEL);
70352f7f91STakashi Iwai if (!knew->name)
71352f7f91STakashi Iwai return NULL;
72352f7f91STakashi Iwai return knew;
73352f7f91STakashi Iwai }
742698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_add_kctl);
75352f7f91STakashi Iwai
free_kctls(struct hda_gen_spec * spec)76352f7f91STakashi Iwai static void free_kctls(struct hda_gen_spec *spec)
77352f7f91STakashi Iwai {
78352f7f91STakashi Iwai if (spec->kctls.list) {
79352f7f91STakashi Iwai struct snd_kcontrol_new *kctl = spec->kctls.list;
80352f7f91STakashi Iwai int i;
81352f7f91STakashi Iwai for (i = 0; i < spec->kctls.used; i++)
82352f7f91STakashi Iwai kfree(kctl[i].name);
83352f7f91STakashi Iwai }
84352f7f91STakashi Iwai snd_array_free(&spec->kctls);
85352f7f91STakashi Iwai }
86352f7f91STakashi Iwai
snd_hda_gen_spec_free(struct hda_gen_spec * spec)87a8dca460STakashi Iwai static void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
88352f7f91STakashi Iwai {
891da177e4SLinus Torvalds if (!spec)
901da177e4SLinus Torvalds return;
91352f7f91STakashi Iwai free_kctls(spec);
92352f7f91STakashi Iwai snd_array_free(&spec->paths);
930186f4f4STakashi Iwai snd_array_free(&spec->loopback_list);
94549f8ffcSTakashi Iwai #ifdef CONFIG_SND_HDA_GENERIC_LEDS
95549f8ffcSTakashi Iwai if (spec->led_cdevs[LED_AUDIO_MUTE])
96549f8ffcSTakashi Iwai led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MUTE]);
97549f8ffcSTakashi Iwai if (spec->led_cdevs[LED_AUDIO_MICMUTE])
98549f8ffcSTakashi Iwai led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MICMUTE]);
99549f8ffcSTakashi Iwai #endif
1001da177e4SLinus Torvalds }
1011da177e4SLinus Torvalds
1021da177e4SLinus Torvalds /*
1031c70a583STakashi Iwai * store user hints
1041c70a583STakashi Iwai */
parse_user_hints(struct hda_codec * codec)1051c70a583STakashi Iwai static void parse_user_hints(struct hda_codec *codec)
1061c70a583STakashi Iwai {
1071c70a583STakashi Iwai struct hda_gen_spec *spec = codec->spec;
1081c70a583STakashi Iwai int val;
1091c70a583STakashi Iwai
1101c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "jack_detect");
1111c70a583STakashi Iwai if (val >= 0)
1121c70a583STakashi Iwai codec->no_jack_detect = !val;
1131c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "inv_jack_detect");
1141c70a583STakashi Iwai if (val >= 0)
1151c70a583STakashi Iwai codec->inv_jack_detect = !!val;
1161c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "trigger_sense");
1171c70a583STakashi Iwai if (val >= 0)
1181c70a583STakashi Iwai codec->no_trigger_sense = !val;
1191c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "inv_eapd");
1201c70a583STakashi Iwai if (val >= 0)
1211c70a583STakashi Iwai codec->inv_eapd = !!val;
1221c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "pcm_format_first");
1231c70a583STakashi Iwai if (val >= 0)
1241c70a583STakashi Iwai codec->pcm_format_first = !!val;
1251c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "sticky_stream");
1261c70a583STakashi Iwai if (val >= 0)
1271c70a583STakashi Iwai codec->no_sticky_stream = !val;
1281c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "spdif_status_reset");
1291c70a583STakashi Iwai if (val >= 0)
1301c70a583STakashi Iwai codec->spdif_status_reset = !!val;
1311c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "pin_amp_workaround");
1321c70a583STakashi Iwai if (val >= 0)
1331c70a583STakashi Iwai codec->pin_amp_workaround = !!val;
1341c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "single_adc_amp");
1351c70a583STakashi Iwai if (val >= 0)
1361c70a583STakashi Iwai codec->single_adc_amp = !!val;
137967b1307STakashi Iwai val = snd_hda_get_bool_hint(codec, "power_save_node");
138e6feb5d0STakashi Iwai if (val >= 0)
139967b1307STakashi Iwai codec->power_save_node = !!val;
1401c70a583STakashi Iwai
141f72706beSTakashi Iwai val = snd_hda_get_bool_hint(codec, "auto_mute");
142f72706beSTakashi Iwai if (val >= 0)
143f72706beSTakashi Iwai spec->suppress_auto_mute = !val;
1441c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "auto_mic");
1451c70a583STakashi Iwai if (val >= 0)
1461c70a583STakashi Iwai spec->suppress_auto_mic = !val;
1471c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "line_in_auto_switch");
1481c70a583STakashi Iwai if (val >= 0)
1491c70a583STakashi Iwai spec->line_in_auto_switch = !!val;
1507eebffd3STakashi Iwai val = snd_hda_get_bool_hint(codec, "auto_mute_via_amp");
1517eebffd3STakashi Iwai if (val >= 0)
1527eebffd3STakashi Iwai spec->auto_mute_via_amp = !!val;
1531c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "need_dac_fix");
1541c70a583STakashi Iwai if (val >= 0)
1551c70a583STakashi Iwai spec->need_dac_fix = !!val;
1561c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "primary_hp");
1571c70a583STakashi Iwai if (val >= 0)
1581c70a583STakashi Iwai spec->no_primary_hp = !val;
159da96fb5bSTakashi Iwai val = snd_hda_get_bool_hint(codec, "multi_io");
160da96fb5bSTakashi Iwai if (val >= 0)
161da96fb5bSTakashi Iwai spec->no_multi_io = !val;
1621c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "multi_cap_vol");
1631c70a583STakashi Iwai if (val >= 0)
1641c70a583STakashi Iwai spec->multi_cap_vol = !!val;
1651c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "inv_dmic_split");
1661c70a583STakashi Iwai if (val >= 0)
1671c70a583STakashi Iwai spec->inv_dmic_split = !!val;
1681c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "indep_hp");
1691c70a583STakashi Iwai if (val >= 0)
1701c70a583STakashi Iwai spec->indep_hp = !!val;
1711c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "add_stereo_mix_input");
1721c70a583STakashi Iwai if (val >= 0)
1731c70a583STakashi Iwai spec->add_stereo_mix_input = !!val;
174f811c3cfSTakashi Iwai /* the following two are just for compatibility */
1751c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "add_out_jack_modes");
1761c70a583STakashi Iwai if (val >= 0)
177f811c3cfSTakashi Iwai spec->add_jack_modes = !!val;
17829476558STakashi Iwai val = snd_hda_get_bool_hint(codec, "add_in_jack_modes");
17929476558STakashi Iwai if (val >= 0)
180f811c3cfSTakashi Iwai spec->add_jack_modes = !!val;
181f811c3cfSTakashi Iwai val = snd_hda_get_bool_hint(codec, "add_jack_modes");
182f811c3cfSTakashi Iwai if (val >= 0)
183f811c3cfSTakashi Iwai spec->add_jack_modes = !!val;
18455196fffSTakashi Iwai val = snd_hda_get_bool_hint(codec, "power_down_unused");
18555196fffSTakashi Iwai if (val >= 0)
18655196fffSTakashi Iwai spec->power_down_unused = !!val;
187967303daSTakashi Iwai val = snd_hda_get_bool_hint(codec, "add_hp_mic");
188967303daSTakashi Iwai if (val >= 0)
189967303daSTakashi Iwai spec->hp_mic = !!val;
190967303daSTakashi Iwai val = snd_hda_get_bool_hint(codec, "hp_mic_detect");
191967303daSTakashi Iwai if (val >= 0)
192967303daSTakashi Iwai spec->suppress_hp_mic_detect = !val;
1937480316cSTakashi Iwai val = snd_hda_get_bool_hint(codec, "vmaster");
1947480316cSTakashi Iwai if (val >= 0)
1957480316cSTakashi Iwai spec->suppress_vmaster = !val;
1961c70a583STakashi Iwai
1971c70a583STakashi Iwai if (!snd_hda_get_int_hint(codec, "mixer_nid", &val))
1981c70a583STakashi Iwai spec->mixer_nid = val;
1991c70a583STakashi Iwai }
2001c70a583STakashi Iwai
2011c70a583STakashi Iwai /*
2022c12c30dSTakashi Iwai * pin control value accesses
2032c12c30dSTakashi Iwai */
2042c12c30dSTakashi Iwai
2052c12c30dSTakashi Iwai #define update_pin_ctl(codec, pin, val) \
206401caff7STakashi Iwai snd_hda_codec_write_cache(codec, pin, 0, \
2072c12c30dSTakashi Iwai AC_VERB_SET_PIN_WIDGET_CONTROL, val)
2082c12c30dSTakashi Iwai
2092c12c30dSTakashi Iwai /* restore the pinctl based on the cached value */
restore_pin_ctl(struct hda_codec * codec,hda_nid_t pin)2102c12c30dSTakashi Iwai static inline void restore_pin_ctl(struct hda_codec *codec, hda_nid_t pin)
2112c12c30dSTakashi Iwai {
2122c12c30dSTakashi Iwai update_pin_ctl(codec, pin, snd_hda_codec_get_pin_target(codec, pin));
2132c12c30dSTakashi Iwai }
2142c12c30dSTakashi Iwai
2152c12c30dSTakashi Iwai /* set the pinctl target value and write it if requested */
set_pin_target(struct hda_codec * codec,hda_nid_t pin,unsigned int val,bool do_write)2162c12c30dSTakashi Iwai static void set_pin_target(struct hda_codec *codec, hda_nid_t pin,
2172c12c30dSTakashi Iwai unsigned int val, bool do_write)
2182c12c30dSTakashi Iwai {
2192c12c30dSTakashi Iwai if (!pin)
2202c12c30dSTakashi Iwai return;
2212c12c30dSTakashi Iwai val = snd_hda_correct_pin_ctl(codec, pin, val);
2222c12c30dSTakashi Iwai snd_hda_codec_set_pin_target(codec, pin, val);
2232c12c30dSTakashi Iwai if (do_write)
2242c12c30dSTakashi Iwai update_pin_ctl(codec, pin, val);
2252c12c30dSTakashi Iwai }
2262c12c30dSTakashi Iwai
2272c12c30dSTakashi Iwai /* set pinctl target values for all given pins */
set_pin_targets(struct hda_codec * codec,int num_pins,hda_nid_t * pins,unsigned int val)2282c12c30dSTakashi Iwai static void set_pin_targets(struct hda_codec *codec, int num_pins,
2292c12c30dSTakashi Iwai hda_nid_t *pins, unsigned int val)
2302c12c30dSTakashi Iwai {
2312c12c30dSTakashi Iwai int i;
2322c12c30dSTakashi Iwai for (i = 0; i < num_pins; i++)
2332c12c30dSTakashi Iwai set_pin_target(codec, pins[i], val, false);
2342c12c30dSTakashi Iwai }
2352c12c30dSTakashi Iwai
2362c12c30dSTakashi Iwai /*
237352f7f91STakashi Iwai * parsing paths
2381da177e4SLinus Torvalds */
2391da177e4SLinus Torvalds
2403ca529d3STakashi Iwai /* return the position of NID in the list, or -1 if not found */
find_idx_in_nid_list(hda_nid_t nid,const hda_nid_t * list,int nums)2413ca529d3STakashi Iwai static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
2423ca529d3STakashi Iwai {
2433ca529d3STakashi Iwai int i;
2443ca529d3STakashi Iwai for (i = 0; i < nums; i++)
2453ca529d3STakashi Iwai if (list[i] == nid)
2463ca529d3STakashi Iwai return i;
2473ca529d3STakashi Iwai return -1;
2483ca529d3STakashi Iwai }
2493ca529d3STakashi Iwai
2503ca529d3STakashi Iwai /* return true if the given NID is contained in the path */
is_nid_contained(struct nid_path * path,hda_nid_t nid)2513ca529d3STakashi Iwai static bool is_nid_contained(struct nid_path *path, hda_nid_t nid)
2523ca529d3STakashi Iwai {
2533ca529d3STakashi Iwai return find_idx_in_nid_list(nid, path->path, path->depth) >= 0;
2543ca529d3STakashi Iwai }
2553ca529d3STakashi Iwai
get_nid_path(struct hda_codec * codec,hda_nid_t from_nid,hda_nid_t to_nid,int anchor_nid)256f5172a7eSTakashi Iwai static struct nid_path *get_nid_path(struct hda_codec *codec,
257f5172a7eSTakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid,
2583ca529d3STakashi Iwai int anchor_nid)
2591da177e4SLinus Torvalds {
260352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
261a9c2dfc8STakashi Iwai struct nid_path *path;
262352f7f91STakashi Iwai int i;
2631da177e4SLinus Torvalds
264a9c2dfc8STakashi Iwai snd_array_for_each(&spec->paths, i, path) {
265352f7f91STakashi Iwai if (path->depth <= 0)
266352f7f91STakashi Iwai continue;
267352f7f91STakashi Iwai if ((!from_nid || path->path[0] == from_nid) &&
268f5172a7eSTakashi Iwai (!to_nid || path->path[path->depth - 1] == to_nid)) {
2693ca529d3STakashi Iwai if (!anchor_nid ||
2703ca529d3STakashi Iwai (anchor_nid > 0 && is_nid_contained(path, anchor_nid)) ||
2713ca529d3STakashi Iwai (anchor_nid < 0 && !is_nid_contained(path, anchor_nid)))
272352f7f91STakashi Iwai return path;
2731da177e4SLinus Torvalds }
274f5172a7eSTakashi Iwai }
2751da177e4SLinus Torvalds return NULL;
2761da177e4SLinus Torvalds }
277f5172a7eSTakashi Iwai
278dda42bd0STakashi Iwai /**
279dda42bd0STakashi Iwai * snd_hda_get_path_idx - get the index number corresponding to the path
280dda42bd0STakashi Iwai * instance
281dda42bd0STakashi Iwai * @codec: the HDA codec
282dda42bd0STakashi Iwai * @path: nid_path object
283dda42bd0STakashi Iwai *
284dda42bd0STakashi Iwai * The returned index starts from 1, i.e. the actual array index with offset 1,
285dda42bd0STakashi Iwai * and zero is handled as an invalid path
286196c1766STakashi Iwai */
snd_hda_get_path_idx(struct hda_codec * codec,struct nid_path * path)287196c1766STakashi Iwai int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path)
288196c1766STakashi Iwai {
289196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec;
290196c1766STakashi Iwai struct nid_path *array = spec->paths.list;
291196c1766STakashi Iwai ssize_t idx;
292196c1766STakashi Iwai
293196c1766STakashi Iwai if (!spec->paths.used)
294196c1766STakashi Iwai return 0;
295196c1766STakashi Iwai idx = path - array;
296196c1766STakashi Iwai if (idx < 0 || idx >= spec->paths.used)
297196c1766STakashi Iwai return 0;
298196c1766STakashi Iwai return idx + 1;
299196c1766STakashi Iwai }
3002698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_get_path_idx);
301196c1766STakashi Iwai
302dda42bd0STakashi Iwai /**
303dda42bd0STakashi Iwai * snd_hda_get_path_from_idx - get the path instance corresponding to the
304dda42bd0STakashi Iwai * given index number
305dda42bd0STakashi Iwai * @codec: the HDA codec
306dda42bd0STakashi Iwai * @idx: the path index
307dda42bd0STakashi Iwai */
snd_hda_get_path_from_idx(struct hda_codec * codec,int idx)308196c1766STakashi Iwai struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx)
309196c1766STakashi Iwai {
310196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec;
311196c1766STakashi Iwai
312196c1766STakashi Iwai if (idx <= 0 || idx > spec->paths.used)
313196c1766STakashi Iwai return NULL;
314196c1766STakashi Iwai return snd_array_elem(&spec->paths, idx - 1);
315196c1766STakashi Iwai }
3162698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_get_path_from_idx);
317196c1766STakashi Iwai
318352f7f91STakashi Iwai /* check whether the given DAC is already found in any existing paths */
is_dac_already_used(struct hda_codec * codec,hda_nid_t nid)319352f7f91STakashi Iwai static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
3201da177e4SLinus Torvalds {
321352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
322a9c2dfc8STakashi Iwai const struct nid_path *path;
323352f7f91STakashi Iwai int i;
324352f7f91STakashi Iwai
325a9c2dfc8STakashi Iwai snd_array_for_each(&spec->paths, i, path) {
326352f7f91STakashi Iwai if (path->path[0] == nid)
327352f7f91STakashi Iwai return true;
328352f7f91STakashi Iwai }
329352f7f91STakashi Iwai return false;
3301da177e4SLinus Torvalds }
3311da177e4SLinus Torvalds
332352f7f91STakashi Iwai /* check whether the given two widgets can be connected */
is_reachable_path(struct hda_codec * codec,hda_nid_t from_nid,hda_nid_t to_nid)333352f7f91STakashi Iwai static bool is_reachable_path(struct hda_codec *codec,
334352f7f91STakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid)
3351da177e4SLinus Torvalds {
336352f7f91STakashi Iwai if (!from_nid || !to_nid)
337352f7f91STakashi Iwai return false;
338352f7f91STakashi Iwai return snd_hda_get_conn_index(codec, to_nid, from_nid, true) >= 0;
3391da177e4SLinus Torvalds }
3401da177e4SLinus Torvalds
341352f7f91STakashi Iwai /* nid, dir and idx */
342352f7f91STakashi Iwai #define AMP_VAL_COMPARE_MASK (0xffff | (1U << 18) | (0x0f << 19))
343352f7f91STakashi Iwai
344352f7f91STakashi Iwai /* check whether the given ctl is already assigned in any path elements */
is_ctl_used(struct hda_codec * codec,unsigned int val,int type)345352f7f91STakashi Iwai static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type)
3461da177e4SLinus Torvalds {
347352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
348a9c2dfc8STakashi Iwai const struct nid_path *path;
349352f7f91STakashi Iwai int i;
350352f7f91STakashi Iwai
351352f7f91STakashi Iwai val &= AMP_VAL_COMPARE_MASK;
352a9c2dfc8STakashi Iwai snd_array_for_each(&spec->paths, i, path) {
353352f7f91STakashi Iwai if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val)
354352f7f91STakashi Iwai return true;
355352f7f91STakashi Iwai }
356352f7f91STakashi Iwai return false;
3571da177e4SLinus Torvalds }
3581da177e4SLinus Torvalds
359352f7f91STakashi Iwai /* check whether a control with the given (nid, dir, idx) was assigned */
is_ctl_associated(struct hda_codec * codec,hda_nid_t nid,int dir,int idx,int type)360352f7f91STakashi Iwai static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid,
3618999bf0aSTakashi Iwai int dir, int idx, int type)
362cb53c626STakashi Iwai {
363352f7f91STakashi Iwai unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
3648999bf0aSTakashi Iwai return is_ctl_used(codec, val, type);
365cb53c626STakashi Iwai }
366352f7f91STakashi Iwai
print_nid_path(struct hda_codec * codec,const char * pfx,struct nid_path * path)3674e76a883STakashi Iwai static void print_nid_path(struct hda_codec *codec,
3684e76a883STakashi Iwai const char *pfx, struct nid_path *path)
3690c8c0f56STakashi Iwai {
3700c8c0f56STakashi Iwai char buf[40];
371d82353e5SJoe Perches char *pos = buf;
3720c8c0f56STakashi Iwai int i;
3730c8c0f56STakashi Iwai
374d82353e5SJoe Perches *pos = 0;
375d82353e5SJoe Perches for (i = 0; i < path->depth; i++)
376d82353e5SJoe Perches pos += scnprintf(pos, sizeof(buf) - (pos - buf), "%s%02x",
377d82353e5SJoe Perches pos != buf ? ":" : "",
378d82353e5SJoe Perches path->path[i]);
3790c8c0f56STakashi Iwai
380d82353e5SJoe Perches codec_dbg(codec, "%s path: depth=%d '%s'\n", pfx, path->depth, buf);
3810c8c0f56STakashi Iwai }
3820c8c0f56STakashi Iwai
383352f7f91STakashi Iwai /* called recursively */
__parse_nid_path(struct hda_codec * codec,hda_nid_t from_nid,hda_nid_t to_nid,int anchor_nid,struct nid_path * path,int depth)384352f7f91STakashi Iwai static bool __parse_nid_path(struct hda_codec *codec,
385352f7f91STakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid,
3863ca529d3STakashi Iwai int anchor_nid, struct nid_path *path,
3873ca529d3STakashi Iwai int depth)
388352f7f91STakashi Iwai {
389ee8e765bSTakashi Iwai const hda_nid_t *conn;
390352f7f91STakashi Iwai int i, nums;
391352f7f91STakashi Iwai
3923ca529d3STakashi Iwai if (to_nid == anchor_nid)
3933ca529d3STakashi Iwai anchor_nid = 0; /* anchor passed */
3943ca529d3STakashi Iwai else if (to_nid == (hda_nid_t)(-anchor_nid))
3953ca529d3STakashi Iwai return false; /* hit the exclusive nid */
396352f7f91STakashi Iwai
397ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, to_nid, &conn);
398352f7f91STakashi Iwai for (i = 0; i < nums; i++) {
399352f7f91STakashi Iwai if (conn[i] != from_nid) {
400352f7f91STakashi Iwai /* special case: when from_nid is 0,
401352f7f91STakashi Iwai * try to find an empty DAC
402352f7f91STakashi Iwai */
403352f7f91STakashi Iwai if (from_nid ||
404352f7f91STakashi Iwai get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT ||
405352f7f91STakashi Iwai is_dac_already_used(codec, conn[i]))
406352f7f91STakashi Iwai continue;
407352f7f91STakashi Iwai }
4083ca529d3STakashi Iwai /* anchor is not requested or already passed? */
4093ca529d3STakashi Iwai if (anchor_nid <= 0)
410352f7f91STakashi Iwai goto found;
411352f7f91STakashi Iwai }
412352f7f91STakashi Iwai if (depth >= MAX_NID_PATH_DEPTH)
413352f7f91STakashi Iwai return false;
414352f7f91STakashi Iwai for (i = 0; i < nums; i++) {
415352f7f91STakashi Iwai unsigned int type;
416352f7f91STakashi Iwai type = get_wcaps_type(get_wcaps(codec, conn[i]));
417352f7f91STakashi Iwai if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN ||
418352f7f91STakashi Iwai type == AC_WID_PIN)
419352f7f91STakashi Iwai continue;
420352f7f91STakashi Iwai if (__parse_nid_path(codec, from_nid, conn[i],
4213ca529d3STakashi Iwai anchor_nid, path, depth + 1))
422352f7f91STakashi Iwai goto found;
423352f7f91STakashi Iwai }
424352f7f91STakashi Iwai return false;
425352f7f91STakashi Iwai
426352f7f91STakashi Iwai found:
427352f7f91STakashi Iwai path->path[path->depth] = conn[i];
428352f7f91STakashi Iwai path->idx[path->depth + 1] = i;
429352f7f91STakashi Iwai if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX)
430352f7f91STakashi Iwai path->multi[path->depth + 1] = 1;
431352f7f91STakashi Iwai path->depth++;
432352f7f91STakashi Iwai return true;
433352f7f91STakashi Iwai }
434352f7f91STakashi Iwai
435c4a58c30STakashi Iwai /*
436dda42bd0STakashi Iwai * snd_hda_parse_nid_path - parse the widget path from the given nid to
437dda42bd0STakashi Iwai * the target nid
438dda42bd0STakashi Iwai * @codec: the HDA codec
439dda42bd0STakashi Iwai * @from_nid: the NID where the path start from
440dda42bd0STakashi Iwai * @to_nid: the NID where the path ends at
441dda42bd0STakashi Iwai * @anchor_nid: the anchor indication
442dda42bd0STakashi Iwai * @path: the path object to store the result
443dda42bd0STakashi Iwai *
444dda42bd0STakashi Iwai * Returns true if a matching path is found.
445dda42bd0STakashi Iwai *
446dda42bd0STakashi Iwai * The parsing behavior depends on parameters:
447352f7f91STakashi Iwai * when @from_nid is 0, try to find an empty DAC;
4483ca529d3STakashi Iwai * when @anchor_nid is set to a positive value, only paths through the widget
4493ca529d3STakashi Iwai * with the given value are evaluated.
4503ca529d3STakashi Iwai * when @anchor_nid is set to a negative value, paths through the widget
4513ca529d3STakashi Iwai * with the negative of given value are excluded, only other paths are chosen.
4523ca529d3STakashi Iwai * when @anchor_nid is zero, no special handling about path selection.
453352f7f91STakashi Iwai */
snd_hda_parse_nid_path(struct hda_codec * codec,hda_nid_t from_nid,hda_nid_t to_nid,int anchor_nid,struct nid_path * path)454c4a58c30STakashi Iwai static bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
4553ca529d3STakashi Iwai hda_nid_t to_nid, int anchor_nid,
456352f7f91STakashi Iwai struct nid_path *path)
457352f7f91STakashi Iwai {
4583ca529d3STakashi Iwai if (__parse_nid_path(codec, from_nid, to_nid, anchor_nid, path, 1)) {
459352f7f91STakashi Iwai path->path[path->depth] = to_nid;
460352f7f91STakashi Iwai path->depth++;
461352f7f91STakashi Iwai return true;
462352f7f91STakashi Iwai }
463352f7f91STakashi Iwai return false;
464352f7f91STakashi Iwai }
465352f7f91STakashi Iwai
466dda42bd0STakashi Iwai /**
467dda42bd0STakashi Iwai * snd_hda_add_new_path - parse the path between the given NIDs and
468dda42bd0STakashi Iwai * add to the path list
469dda42bd0STakashi Iwai * @codec: the HDA codec
470dda42bd0STakashi Iwai * @from_nid: the NID where the path start from
471dda42bd0STakashi Iwai * @to_nid: the NID where the path ends at
472dda42bd0STakashi Iwai * @anchor_nid: the anchor indication, see snd_hda_parse_nid_path()
473dda42bd0STakashi Iwai *
474dda42bd0STakashi Iwai * If no valid path is found, returns NULL.
475352f7f91STakashi Iwai */
476352f7f91STakashi Iwai struct nid_path *
snd_hda_add_new_path(struct hda_codec * codec,hda_nid_t from_nid,hda_nid_t to_nid,int anchor_nid)477352f7f91STakashi Iwai snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
4783ca529d3STakashi Iwai hda_nid_t to_nid, int anchor_nid)
479352f7f91STakashi Iwai {
480352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
481352f7f91STakashi Iwai struct nid_path *path;
482352f7f91STakashi Iwai
483352f7f91STakashi Iwai if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid))
484352f7f91STakashi Iwai return NULL;
485352f7f91STakashi Iwai
486f5172a7eSTakashi Iwai /* check whether the path has been already added */
4873ca529d3STakashi Iwai path = get_nid_path(codec, from_nid, to_nid, anchor_nid);
488f5172a7eSTakashi Iwai if (path)
489f5172a7eSTakashi Iwai return path;
490f5172a7eSTakashi Iwai
491352f7f91STakashi Iwai path = snd_array_new(&spec->paths);
492352f7f91STakashi Iwai if (!path)
493352f7f91STakashi Iwai return NULL;
494352f7f91STakashi Iwai memset(path, 0, sizeof(*path));
4953ca529d3STakashi Iwai if (snd_hda_parse_nid_path(codec, from_nid, to_nid, anchor_nid, path))
496352f7f91STakashi Iwai return path;
497352f7f91STakashi Iwai /* push back */
498352f7f91STakashi Iwai spec->paths.used--;
499352f7f91STakashi Iwai return NULL;
500352f7f91STakashi Iwai }
5012698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_add_new_path);
502352f7f91STakashi Iwai
503980428ceSTakashi Iwai /* clear the given path as invalid so that it won't be picked up later */
invalidate_nid_path(struct hda_codec * codec,int idx)504980428ceSTakashi Iwai static void invalidate_nid_path(struct hda_codec *codec, int idx)
505980428ceSTakashi Iwai {
506980428ceSTakashi Iwai struct nid_path *path = snd_hda_get_path_from_idx(codec, idx);
507980428ceSTakashi Iwai if (!path)
508980428ceSTakashi Iwai return;
509980428ceSTakashi Iwai memset(path, 0, sizeof(*path));
510980428ceSTakashi Iwai }
511980428ceSTakashi Iwai
5123690739bSTakashi Iwai /* return a DAC if paired to the given pin by codec driver */
get_preferred_dac(struct hda_codec * codec,hda_nid_t pin)5133690739bSTakashi Iwai static hda_nid_t get_preferred_dac(struct hda_codec *codec, hda_nid_t pin)
5143690739bSTakashi Iwai {
5153690739bSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
5163690739bSTakashi Iwai const hda_nid_t *list = spec->preferred_dacs;
5173690739bSTakashi Iwai
5183690739bSTakashi Iwai if (!list)
5193690739bSTakashi Iwai return 0;
5203690739bSTakashi Iwai for (; *list; list += 2)
5213690739bSTakashi Iwai if (*list == pin)
5223690739bSTakashi Iwai return list[1];
5233690739bSTakashi Iwai return 0;
5243690739bSTakashi Iwai }
5253690739bSTakashi Iwai
526352f7f91STakashi Iwai /* look for an empty DAC slot */
look_for_dac(struct hda_codec * codec,hda_nid_t pin,bool is_digital)527352f7f91STakashi Iwai static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin,
528352f7f91STakashi Iwai bool is_digital)
529352f7f91STakashi Iwai {
530352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
531352f7f91STakashi Iwai bool cap_digital;
532352f7f91STakashi Iwai int i;
533352f7f91STakashi Iwai
534352f7f91STakashi Iwai for (i = 0; i < spec->num_all_dacs; i++) {
535352f7f91STakashi Iwai hda_nid_t nid = spec->all_dacs[i];
536352f7f91STakashi Iwai if (!nid || is_dac_already_used(codec, nid))
537352f7f91STakashi Iwai continue;
538352f7f91STakashi Iwai cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL);
539352f7f91STakashi Iwai if (is_digital != cap_digital)
540352f7f91STakashi Iwai continue;
541352f7f91STakashi Iwai if (is_reachable_path(codec, nid, pin))
542352f7f91STakashi Iwai return nid;
543352f7f91STakashi Iwai }
544352f7f91STakashi Iwai return 0;
545352f7f91STakashi Iwai }
546352f7f91STakashi Iwai
547352f7f91STakashi Iwai /* replace the channels in the composed amp value with the given number */
amp_val_replace_channels(unsigned int val,unsigned int chs)548352f7f91STakashi Iwai static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs)
549352f7f91STakashi Iwai {
550352f7f91STakashi Iwai val &= ~(0x3U << 16);
551352f7f91STakashi Iwai val |= chs << 16;
552352f7f91STakashi Iwai return val;
553352f7f91STakashi Iwai }
554352f7f91STakashi Iwai
same_amp_caps(struct hda_codec * codec,hda_nid_t nid1,hda_nid_t nid2,int dir)55599a5592dSDavid Henningsson static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1,
55699a5592dSDavid Henningsson hda_nid_t nid2, int dir)
55799a5592dSDavid Henningsson {
55899a5592dSDavid Henningsson if (!(get_wcaps(codec, nid1) & (1 << (dir + 1))))
55999a5592dSDavid Henningsson return !(get_wcaps(codec, nid2) & (1 << (dir + 1)));
56099a5592dSDavid Henningsson return (query_amp_caps(codec, nid1, dir) ==
56199a5592dSDavid Henningsson query_amp_caps(codec, nid2, dir));
56299a5592dSDavid Henningsson }
56399a5592dSDavid Henningsson
564352f7f91STakashi Iwai /* look for a widget suitable for assigning a mute switch in the path */
look_for_out_mute_nid(struct hda_codec * codec,struct nid_path * path)565352f7f91STakashi Iwai static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec,
566352f7f91STakashi Iwai struct nid_path *path)
567352f7f91STakashi Iwai {
568352f7f91STakashi Iwai int i;
569352f7f91STakashi Iwai
570352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) {
571352f7f91STakashi Iwai if (nid_has_mute(codec, path->path[i], HDA_OUTPUT))
572352f7f91STakashi Iwai return path->path[i];
573352f7f91STakashi Iwai if (i != path->depth - 1 && i != 0 &&
574352f7f91STakashi Iwai nid_has_mute(codec, path->path[i], HDA_INPUT))
575352f7f91STakashi Iwai return path->path[i];
576352f7f91STakashi Iwai }
577352f7f91STakashi Iwai return 0;
578352f7f91STakashi Iwai }
579352f7f91STakashi Iwai
580352f7f91STakashi Iwai /* look for a widget suitable for assigning a volume ctl in the path */
look_for_out_vol_nid(struct hda_codec * codec,struct nid_path * path)581352f7f91STakashi Iwai static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec,
582352f7f91STakashi Iwai struct nid_path *path)
583352f7f91STakashi Iwai {
584a1114a8cSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
585352f7f91STakashi Iwai int i;
586352f7f91STakashi Iwai
587352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) {
588a1114a8cSTakashi Iwai hda_nid_t nid = path->path[i];
589a1114a8cSTakashi Iwai if ((spec->out_vol_mask >> nid) & 1)
590a1114a8cSTakashi Iwai continue;
591a1114a8cSTakashi Iwai if (nid_has_volume(codec, nid, HDA_OUTPUT))
592a1114a8cSTakashi Iwai return nid;
593352f7f91STakashi Iwai }
594352f7f91STakashi Iwai return 0;
595352f7f91STakashi Iwai }
596352f7f91STakashi Iwai
597352f7f91STakashi Iwai /*
598352f7f91STakashi Iwai * path activation / deactivation
599352f7f91STakashi Iwai */
600352f7f91STakashi Iwai
601352f7f91STakashi Iwai /* can have the amp-in capability? */
has_amp_in(struct hda_codec * codec,struct nid_path * path,int idx)602352f7f91STakashi Iwai static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx)
603352f7f91STakashi Iwai {
604352f7f91STakashi Iwai hda_nid_t nid = path->path[idx];
605352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid);
606352f7f91STakashi Iwai unsigned int type = get_wcaps_type(caps);
607352f7f91STakashi Iwai
608352f7f91STakashi Iwai if (!(caps & AC_WCAP_IN_AMP))
609352f7f91STakashi Iwai return false;
610352f7f91STakashi Iwai if (type == AC_WID_PIN && idx > 0) /* only for input pins */
611352f7f91STakashi Iwai return false;
612352f7f91STakashi Iwai return true;
613352f7f91STakashi Iwai }
614352f7f91STakashi Iwai
615352f7f91STakashi Iwai /* can have the amp-out capability? */
has_amp_out(struct hda_codec * codec,struct nid_path * path,int idx)616352f7f91STakashi Iwai static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx)
617352f7f91STakashi Iwai {
618352f7f91STakashi Iwai hda_nid_t nid = path->path[idx];
619352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid);
620352f7f91STakashi Iwai unsigned int type = get_wcaps_type(caps);
621352f7f91STakashi Iwai
622352f7f91STakashi Iwai if (!(caps & AC_WCAP_OUT_AMP))
623352f7f91STakashi Iwai return false;
624352f7f91STakashi Iwai if (type == AC_WID_PIN && !idx) /* only for output pins */
625352f7f91STakashi Iwai return false;
626352f7f91STakashi Iwai return true;
627352f7f91STakashi Iwai }
628352f7f91STakashi Iwai
629352f7f91STakashi Iwai /* check whether the given (nid,dir,idx) is active */
is_active_nid(struct hda_codec * codec,hda_nid_t nid,unsigned int dir,unsigned int idx)630352f7f91STakashi Iwai static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid,
6317dddf2aeSTakashi Iwai unsigned int dir, unsigned int idx)
632352f7f91STakashi Iwai {
633352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
634e6feb5d0STakashi Iwai int type = get_wcaps_type(get_wcaps(codec, nid));
635a9c2dfc8STakashi Iwai const struct nid_path *path;
636352f7f91STakashi Iwai int i, n;
637352f7f91STakashi Iwai
6387639a06cSTakashi Iwai if (nid == codec->core.afg)
6395ccf835cSTakashi Iwai return true;
6405ccf835cSTakashi Iwai
641a9c2dfc8STakashi Iwai snd_array_for_each(&spec->paths, n, path) {
642352f7f91STakashi Iwai if (!path->active)
643352f7f91STakashi Iwai continue;
644967b1307STakashi Iwai if (codec->power_save_node) {
645e6feb5d0STakashi Iwai if (!path->stream_enabled)
646e6feb5d0STakashi Iwai continue;
647e6feb5d0STakashi Iwai /* ignore unplugged paths except for DAC/ADC */
6486b275b14STakashi Iwai if (!(path->pin_enabled || path->pin_fixed) &&
649e6feb5d0STakashi Iwai type != AC_WID_AUD_OUT && type != AC_WID_AUD_IN)
650e6feb5d0STakashi Iwai continue;
651e6feb5d0STakashi Iwai }
652352f7f91STakashi Iwai for (i = 0; i < path->depth; i++) {
653352f7f91STakashi Iwai if (path->path[i] == nid) {
6549d2b48f7STakashi Iwai if (dir == HDA_OUTPUT || idx == -1 ||
6559d2b48f7STakashi Iwai path->idx[i] == idx)
656352f7f91STakashi Iwai return true;
657352f7f91STakashi Iwai break;
658352f7f91STakashi Iwai }
659352f7f91STakashi Iwai }
660352f7f91STakashi Iwai }
661352f7f91STakashi Iwai return false;
662352f7f91STakashi Iwai }
663352f7f91STakashi Iwai
664b1b9fbd0STakashi Iwai /* check whether the NID is referred by any active paths */
665b1b9fbd0STakashi Iwai #define is_active_nid_for_any(codec, nid) \
6669d2b48f7STakashi Iwai is_active_nid(codec, nid, HDA_OUTPUT, -1)
667b1b9fbd0STakashi Iwai
668352f7f91STakashi Iwai /* get the default amp value for the target state */
get_amp_val_to_activate(struct hda_codec * codec,hda_nid_t nid,int dir,unsigned int caps,bool enable)669352f7f91STakashi Iwai static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid,
6708999bf0aSTakashi Iwai int dir, unsigned int caps, bool enable)
671352f7f91STakashi Iwai {
672352f7f91STakashi Iwai unsigned int val = 0;
673352f7f91STakashi Iwai
674352f7f91STakashi Iwai if (caps & AC_AMPCAP_NUM_STEPS) {
675352f7f91STakashi Iwai /* set to 0dB */
676352f7f91STakashi Iwai if (enable)
677352f7f91STakashi Iwai val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
678352f7f91STakashi Iwai }
679f69910ddSTakashi Iwai if (caps & (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) {
680352f7f91STakashi Iwai if (!enable)
681352f7f91STakashi Iwai val |= HDA_AMP_MUTE;
682352f7f91STakashi Iwai }
683352f7f91STakashi Iwai return val;
684352f7f91STakashi Iwai }
685352f7f91STakashi Iwai
686cc261738STakashi Iwai /* is this a stereo widget or a stereo-to-mono mix? */
is_stereo_amps(struct hda_codec * codec,hda_nid_t nid,int dir)687cc261738STakashi Iwai static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid, int dir)
688cc261738STakashi Iwai {
689cc261738STakashi Iwai unsigned int wcaps = get_wcaps(codec, nid);
690cc261738STakashi Iwai hda_nid_t conn;
691cc261738STakashi Iwai
692cc261738STakashi Iwai if (wcaps & AC_WCAP_STEREO)
693cc261738STakashi Iwai return true;
694cc261738STakashi Iwai if (dir != HDA_INPUT || get_wcaps_type(wcaps) != AC_WID_AUD_MIX)
695cc261738STakashi Iwai return false;
696cc261738STakashi Iwai if (snd_hda_get_num_conns(codec, nid) != 1)
697cc261738STakashi Iwai return false;
698cc261738STakashi Iwai if (snd_hda_get_connections(codec, nid, &conn, 1) < 0)
699cc261738STakashi Iwai return false;
700cc261738STakashi Iwai return !!(get_wcaps(codec, conn) & AC_WCAP_STEREO);
701cc261738STakashi Iwai }
702cc261738STakashi Iwai
703352f7f91STakashi Iwai /* initialize the amp value (only at the first time) */
init_amp(struct hda_codec * codec,hda_nid_t nid,int dir,int idx)704352f7f91STakashi Iwai static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
705352f7f91STakashi Iwai {
7068999bf0aSTakashi Iwai unsigned int caps = query_amp_caps(codec, nid, dir);
7078999bf0aSTakashi Iwai int val = get_amp_val_to_activate(codec, nid, dir, caps, false);
708ef403edbSTakashi Iwai
709cc261738STakashi Iwai if (is_stereo_amps(codec, nid, dir))
710352f7f91STakashi Iwai snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
711ef403edbSTakashi Iwai else
712ef403edbSTakashi Iwai snd_hda_codec_amp_init(codec, nid, 0, dir, idx, 0xff, val);
713ef403edbSTakashi Iwai }
714ef403edbSTakashi Iwai
715ef403edbSTakashi Iwai /* update the amp, doing in stereo or mono depending on NID */
update_amp(struct hda_codec * codec,hda_nid_t nid,int dir,int idx,unsigned int mask,unsigned int val)716ef403edbSTakashi Iwai static int update_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx,
717ef403edbSTakashi Iwai unsigned int mask, unsigned int val)
718ef403edbSTakashi Iwai {
719cc261738STakashi Iwai if (is_stereo_amps(codec, nid, dir))
720ef403edbSTakashi Iwai return snd_hda_codec_amp_stereo(codec, nid, dir, idx,
721ef403edbSTakashi Iwai mask, val);
722ef403edbSTakashi Iwai else
723ef403edbSTakashi Iwai return snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
724ef403edbSTakashi Iwai mask, val);
725352f7f91STakashi Iwai }
726352f7f91STakashi Iwai
7278999bf0aSTakashi Iwai /* calculate amp value mask we can modify;
7288999bf0aSTakashi Iwai * if the given amp is controlled by mixers, don't touch it
7298999bf0aSTakashi Iwai */
get_amp_mask_to_modify(struct hda_codec * codec,hda_nid_t nid,int dir,int idx,unsigned int caps)7308999bf0aSTakashi Iwai static unsigned int get_amp_mask_to_modify(struct hda_codec *codec,
7318999bf0aSTakashi Iwai hda_nid_t nid, int dir, int idx,
7328999bf0aSTakashi Iwai unsigned int caps)
733352f7f91STakashi Iwai {
7348999bf0aSTakashi Iwai unsigned int mask = 0xff;
7358999bf0aSTakashi Iwai
736f69910ddSTakashi Iwai if (caps & (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) {
7378999bf0aSTakashi Iwai if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_MUTE_CTL))
7388999bf0aSTakashi Iwai mask &= ~0x80;
7398999bf0aSTakashi Iwai }
7408999bf0aSTakashi Iwai if (caps & AC_AMPCAP_NUM_STEPS) {
7418999bf0aSTakashi Iwai if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) ||
7428999bf0aSTakashi Iwai is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL))
7438999bf0aSTakashi Iwai mask &= ~0x7f;
7448999bf0aSTakashi Iwai }
7458999bf0aSTakashi Iwai return mask;
7468999bf0aSTakashi Iwai }
7478999bf0aSTakashi Iwai
activate_amp(struct hda_codec * codec,hda_nid_t nid,int dir,int idx,int idx_to_check,bool enable)7488999bf0aSTakashi Iwai static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir,
7498999bf0aSTakashi Iwai int idx, int idx_to_check, bool enable)
7508999bf0aSTakashi Iwai {
7518999bf0aSTakashi Iwai unsigned int caps;
7528999bf0aSTakashi Iwai unsigned int mask, val;
7538999bf0aSTakashi Iwai
7548999bf0aSTakashi Iwai caps = query_amp_caps(codec, nid, dir);
7558999bf0aSTakashi Iwai val = get_amp_val_to_activate(codec, nid, dir, caps, enable);
7568999bf0aSTakashi Iwai mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps);
7578999bf0aSTakashi Iwai if (!mask)
7588999bf0aSTakashi Iwai return;
7598999bf0aSTakashi Iwai
7608999bf0aSTakashi Iwai val &= mask;
761ef403edbSTakashi Iwai update_amp(codec, nid, dir, idx, mask, val);
762352f7f91STakashi Iwai }
763352f7f91STakashi Iwai
check_and_activate_amp(struct hda_codec * codec,hda_nid_t nid,int dir,int idx,int idx_to_check,bool enable)764e7fdd527STakashi Iwai static void check_and_activate_amp(struct hda_codec *codec, hda_nid_t nid,
765e7fdd527STakashi Iwai int dir, int idx, int idx_to_check,
766e7fdd527STakashi Iwai bool enable)
767e7fdd527STakashi Iwai {
768e7fdd527STakashi Iwai /* check whether the given amp is still used by others */
769e7fdd527STakashi Iwai if (!enable && is_active_nid(codec, nid, dir, idx_to_check))
770e7fdd527STakashi Iwai return;
771e7fdd527STakashi Iwai activate_amp(codec, nid, dir, idx, idx_to_check, enable);
772e7fdd527STakashi Iwai }
773e7fdd527STakashi Iwai
activate_amp_out(struct hda_codec * codec,struct nid_path * path,int i,bool enable)774352f7f91STakashi Iwai static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
775352f7f91STakashi Iwai int i, bool enable)
776352f7f91STakashi Iwai {
777352f7f91STakashi Iwai hda_nid_t nid = path->path[i];
778352f7f91STakashi Iwai init_amp(codec, nid, HDA_OUTPUT, 0);
779e7fdd527STakashi Iwai check_and_activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable);
780352f7f91STakashi Iwai }
781352f7f91STakashi Iwai
activate_amp_in(struct hda_codec * codec,struct nid_path * path,int i,bool enable,bool add_aamix)782352f7f91STakashi Iwai static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
783352f7f91STakashi Iwai int i, bool enable, bool add_aamix)
784352f7f91STakashi Iwai {
785352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
786ee8e765bSTakashi Iwai const hda_nid_t *conn;
787352f7f91STakashi Iwai int n, nums, idx;
788352f7f91STakashi Iwai int type;
789352f7f91STakashi Iwai hda_nid_t nid = path->path[i];
790352f7f91STakashi Iwai
791ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, nid, &conn);
7920de7d835SDan Carpenter if (nums < 0)
7930de7d835SDan Carpenter return;
794352f7f91STakashi Iwai type = get_wcaps_type(get_wcaps(codec, nid));
795352f7f91STakashi Iwai if (type == AC_WID_PIN ||
796352f7f91STakashi Iwai (type == AC_WID_AUD_IN && codec->single_adc_amp)) {
797352f7f91STakashi Iwai nums = 1;
798352f7f91STakashi Iwai idx = 0;
799352f7f91STakashi Iwai } else
800352f7f91STakashi Iwai idx = path->idx[i];
801352f7f91STakashi Iwai
802352f7f91STakashi Iwai for (n = 0; n < nums; n++)
803352f7f91STakashi Iwai init_amp(codec, nid, HDA_INPUT, n);
804352f7f91STakashi Iwai
805352f7f91STakashi Iwai /* here is a little bit tricky in comparison with activate_amp_out();
806352f7f91STakashi Iwai * when aa-mixer is available, we need to enable the path as well
807352f7f91STakashi Iwai */
808352f7f91STakashi Iwai for (n = 0; n < nums; n++) {
809e7fdd527STakashi Iwai if (n != idx) {
810e7fdd527STakashi Iwai if (conn[n] != spec->mixer_merge_nid)
811352f7f91STakashi Iwai continue;
812e7fdd527STakashi Iwai /* when aamix is disabled, force to off */
813e7fdd527STakashi Iwai if (!add_aamix) {
814e7fdd527STakashi Iwai activate_amp(codec, nid, HDA_INPUT, n, n, false);
815e7fdd527STakashi Iwai continue;
816e7fdd527STakashi Iwai }
817e7fdd527STakashi Iwai }
818e7fdd527STakashi Iwai check_and_activate_amp(codec, nid, HDA_INPUT, n, idx, enable);
819352f7f91STakashi Iwai }
820352f7f91STakashi Iwai }
821352f7f91STakashi Iwai
822c7fabbc5SRandy Dunlap /* sync power of each widget in the given path */
path_power_update(struct hda_codec * codec,struct nid_path * path,bool allow_powerdown)823e6feb5d0STakashi Iwai static hda_nid_t path_power_update(struct hda_codec *codec,
824e6feb5d0STakashi Iwai struct nid_path *path,
825e6feb5d0STakashi Iwai bool allow_powerdown)
826e6feb5d0STakashi Iwai {
827e6feb5d0STakashi Iwai hda_nid_t nid, changed = 0;
82850fd4987STakashi Iwai int i, state, power;
829e6feb5d0STakashi Iwai
830e6feb5d0STakashi Iwai for (i = 0; i < path->depth; i++) {
831e6feb5d0STakashi Iwai nid = path->path[i];
8322206dc94STakashi Iwai if (!(get_wcaps(codec, nid) & AC_WCAP_POWER))
8332206dc94STakashi Iwai continue;
8347639a06cSTakashi Iwai if (nid == codec->core.afg)
8355ccf835cSTakashi Iwai continue;
836e6feb5d0STakashi Iwai if (!allow_powerdown || is_active_nid_for_any(codec, nid))
837e6feb5d0STakashi Iwai state = AC_PWRST_D0;
838e6feb5d0STakashi Iwai else
839e6feb5d0STakashi Iwai state = AC_PWRST_D3;
84050fd4987STakashi Iwai power = snd_hda_codec_read(codec, nid, 0,
84150fd4987STakashi Iwai AC_VERB_GET_POWER_STATE, 0);
84250fd4987STakashi Iwai if (power != (state | (state << 4))) {
843e6feb5d0STakashi Iwai snd_hda_codec_write(codec, nid, 0,
844e6feb5d0STakashi Iwai AC_VERB_SET_POWER_STATE, state);
845e6feb5d0STakashi Iwai changed = nid;
84648f4b3a2STakashi Iwai /* all known codecs seem to be capable to handl
84748f4b3a2STakashi Iwai * widgets state even in D3, so far.
84848f4b3a2STakashi Iwai * if any new codecs need to restore the widget
84948f4b3a2STakashi Iwai * states after D0 transition, call the function
85048f4b3a2STakashi Iwai * below.
85148f4b3a2STakashi Iwai */
85248f4b3a2STakashi Iwai #if 0 /* disabled */
853d545a57cSTakashi Iwai if (state == AC_PWRST_D0)
854d545a57cSTakashi Iwai snd_hdac_regmap_sync_node(&codec->core, nid);
85548f4b3a2STakashi Iwai #endif
856e6feb5d0STakashi Iwai }
857e6feb5d0STakashi Iwai }
858e6feb5d0STakashi Iwai return changed;
859e6feb5d0STakashi Iwai }
860e6feb5d0STakashi Iwai
861e6feb5d0STakashi Iwai /* do sync with the last power state change */
sync_power_state_change(struct hda_codec * codec,hda_nid_t nid)862e6feb5d0STakashi Iwai static void sync_power_state_change(struct hda_codec *codec, hda_nid_t nid)
863e6feb5d0STakashi Iwai {
864e6feb5d0STakashi Iwai if (nid) {
865e6feb5d0STakashi Iwai msleep(10);
866e6feb5d0STakashi Iwai snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
867e6feb5d0STakashi Iwai }
868e6feb5d0STakashi Iwai }
869e6feb5d0STakashi Iwai
870dda42bd0STakashi Iwai /**
871dda42bd0STakashi Iwai * snd_hda_activate_path - activate or deactivate the given path
872dda42bd0STakashi Iwai * @codec: the HDA codec
873dda42bd0STakashi Iwai * @path: the path to activate/deactivate
874dda42bd0STakashi Iwai * @enable: flag to activate or not
875dda42bd0STakashi Iwai * @add_aamix: enable the input from aamix NID
876dda42bd0STakashi Iwai *
877dda42bd0STakashi Iwai * If @add_aamix is set, enable the input from aa-mix NID as well (if any).
878352f7f91STakashi Iwai */
snd_hda_activate_path(struct hda_codec * codec,struct nid_path * path,bool enable,bool add_aamix)879352f7f91STakashi Iwai void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
880352f7f91STakashi Iwai bool enable, bool add_aamix)
881352f7f91STakashi Iwai {
88255196fffSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
883352f7f91STakashi Iwai int i;
884352f7f91STakashi Iwai
885c7cd0ef6STakashi Iwai path->active = enable;
886352f7f91STakashi Iwai
887e6feb5d0STakashi Iwai /* make sure the widget is powered up */
888967b1307STakashi Iwai if (enable && (spec->power_down_unused || codec->power_save_node))
889967b1307STakashi Iwai path_power_update(codec, path, codec->power_save_node);
890e6feb5d0STakashi Iwai
891352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) {
89255196fffSTakashi Iwai hda_nid_t nid = path->path[i];
893e6feb5d0STakashi Iwai
894352f7f91STakashi Iwai if (enable && path->multi[i])
895401caff7STakashi Iwai snd_hda_codec_write_cache(codec, nid, 0,
896352f7f91STakashi Iwai AC_VERB_SET_CONNECT_SEL,
897352f7f91STakashi Iwai path->idx[i]);
898352f7f91STakashi Iwai if (has_amp_in(codec, path, i))
899352f7f91STakashi Iwai activate_amp_in(codec, path, i, enable, add_aamix);
900352f7f91STakashi Iwai if (has_amp_out(codec, path, i))
901352f7f91STakashi Iwai activate_amp_out(codec, path, i, enable);
902352f7f91STakashi Iwai }
903352f7f91STakashi Iwai }
9042698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_activate_path);
905352f7f91STakashi Iwai
90655196fffSTakashi Iwai /* if the given path is inactive, put widgets into D3 (only if suitable) */
path_power_down_sync(struct hda_codec * codec,struct nid_path * path)90755196fffSTakashi Iwai static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path)
90855196fffSTakashi Iwai {
90955196fffSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
91055196fffSTakashi Iwai
911967b1307STakashi Iwai if (!(spec->power_down_unused || codec->power_save_node) || path->active)
91255196fffSTakashi Iwai return;
913e6feb5d0STakashi Iwai sync_power_state_change(codec, path_power_update(codec, path, true));
91455196fffSTakashi Iwai }
91555196fffSTakashi Iwai
916d5a9f1bbSTakashi Iwai /* turn on/off EAPD on the given pin */
set_pin_eapd(struct hda_codec * codec,hda_nid_t pin,bool enable)917d5a9f1bbSTakashi Iwai static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable)
918d5a9f1bbSTakashi Iwai {
919d5a9f1bbSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
920d5a9f1bbSTakashi Iwai if (spec->own_eapd_ctl ||
921d5a9f1bbSTakashi Iwai !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD))
922d5a9f1bbSTakashi Iwai return;
92305909d5cSTakashi Iwai if (spec->keep_eapd_on && !enable)
92405909d5cSTakashi Iwai return;
925468ac413STakashi Iwai if (codec->inv_eapd)
926468ac413STakashi Iwai enable = !enable;
927401caff7STakashi Iwai snd_hda_codec_write_cache(codec, pin, 0,
928d5a9f1bbSTakashi Iwai AC_VERB_SET_EAPD_BTLENABLE,
929d5a9f1bbSTakashi Iwai enable ? 0x02 : 0x00);
930d5a9f1bbSTakashi Iwai }
931d5a9f1bbSTakashi Iwai
9323e367f15STakashi Iwai /* re-initialize the path specified by the given path index */
resume_path_from_idx(struct hda_codec * codec,int path_idx)9333e367f15STakashi Iwai static void resume_path_from_idx(struct hda_codec *codec, int path_idx)
9343e367f15STakashi Iwai {
9353e367f15STakashi Iwai struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx);
9363e367f15STakashi Iwai if (path)
9373e367f15STakashi Iwai snd_hda_activate_path(codec, path, path->active, false);
9383e367f15STakashi Iwai }
9393e367f15STakashi Iwai
940352f7f91STakashi Iwai
941352f7f91STakashi Iwai /*
942352f7f91STakashi Iwai * Helper functions for creating mixer ctl elements
943352f7f91STakashi Iwai */
944352f7f91STakashi Iwai
9457eebffd3STakashi Iwai static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
9467eebffd3STakashi Iwai struct snd_ctl_elem_value *ucontrol);
947698f5ee3STakashi Iwai static int hda_gen_bind_mute_get(struct snd_kcontrol *kcontrol,
948698f5ee3STakashi Iwai struct snd_ctl_elem_value *ucontrol);
949bc2eee29STakashi Iwai static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol,
950bc2eee29STakashi Iwai struct snd_ctl_elem_value *ucontrol);
9517eebffd3STakashi Iwai
952352f7f91STakashi Iwai enum {
953352f7f91STakashi Iwai HDA_CTL_WIDGET_VOL,
954352f7f91STakashi Iwai HDA_CTL_WIDGET_MUTE,
955352f7f91STakashi Iwai HDA_CTL_BIND_MUTE,
956352f7f91STakashi Iwai };
957352f7f91STakashi Iwai static const struct snd_kcontrol_new control_templates[] = {
958352f7f91STakashi Iwai HDA_CODEC_VOLUME(NULL, 0, 0, 0),
9597eebffd3STakashi Iwai /* only the put callback is replaced for handling the special mute */
9607eebffd3STakashi Iwai {
9617eebffd3STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9627eebffd3STakashi Iwai .subdevice = HDA_SUBDEV_AMP_FLAG,
9637eebffd3STakashi Iwai .info = snd_hda_mixer_amp_switch_info,
9647eebffd3STakashi Iwai .get = snd_hda_mixer_amp_switch_get,
9657eebffd3STakashi Iwai .put = hda_gen_mixer_mute_put, /* replaced */
9667eebffd3STakashi Iwai .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0),
9677eebffd3STakashi Iwai },
968bc2eee29STakashi Iwai {
969bc2eee29STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
970bc2eee29STakashi Iwai .info = snd_hda_mixer_amp_switch_info,
971698f5ee3STakashi Iwai .get = hda_gen_bind_mute_get,
972bc2eee29STakashi Iwai .put = hda_gen_bind_mute_put, /* replaced */
973bc2eee29STakashi Iwai .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0),
974bc2eee29STakashi Iwai },
975352f7f91STakashi Iwai };
976352f7f91STakashi Iwai
977352f7f91STakashi Iwai /* add dynamic controls from template */
978a35bd1e3STakashi Iwai static struct snd_kcontrol_new *
add_control(struct hda_gen_spec * spec,int type,const char * name,int cidx,unsigned long val)979a35bd1e3STakashi Iwai add_control(struct hda_gen_spec *spec, int type, const char *name,
980352f7f91STakashi Iwai int cidx, unsigned long val)
981352f7f91STakashi Iwai {
982352f7f91STakashi Iwai struct snd_kcontrol_new *knew;
983352f7f91STakashi Iwai
98412c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]);
985352f7f91STakashi Iwai if (!knew)
986a35bd1e3STakashi Iwai return NULL;
987352f7f91STakashi Iwai knew->index = cidx;
988352f7f91STakashi Iwai if (get_amp_nid_(val))
989352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG;
990e65bf997SJaroslav Kysela if (knew->access == 0)
991e65bf997SJaroslav Kysela knew->access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
992352f7f91STakashi Iwai knew->private_value = val;
993a35bd1e3STakashi Iwai return knew;
994352f7f91STakashi Iwai }
995352f7f91STakashi Iwai
add_control_with_pfx(struct hda_gen_spec * spec,int type,const char * pfx,const char * dir,const char * sfx,int cidx,unsigned long val)996352f7f91STakashi Iwai static int add_control_with_pfx(struct hda_gen_spec *spec, int type,
997352f7f91STakashi Iwai const char *pfx, const char *dir,
998352f7f91STakashi Iwai const char *sfx, int cidx, unsigned long val)
999352f7f91STakashi Iwai {
1000975cc02aSTakashi Iwai char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
10015f6af005STakashi Iwai int len;
10025f6af005STakashi Iwai
10035f6af005STakashi Iwai len = snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
10045f6af005STakashi Iwai if (snd_BUG_ON(len >= sizeof(name)))
10055f6af005STakashi Iwai return -EINVAL;
1006a35bd1e3STakashi Iwai if (!add_control(spec, type, name, cidx, val))
1007a35bd1e3STakashi Iwai return -ENOMEM;
1008a35bd1e3STakashi Iwai return 0;
1009352f7f91STakashi Iwai }
1010352f7f91STakashi Iwai
1011352f7f91STakashi Iwai #define add_pb_vol_ctrl(spec, type, pfx, val) \
1012352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
1013352f7f91STakashi Iwai #define add_pb_sw_ctrl(spec, type, pfx, val) \
1014352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
1015352f7f91STakashi Iwai #define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \
1016352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
1017352f7f91STakashi Iwai #define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \
1018352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
1019352f7f91STakashi Iwai
add_vol_ctl(struct hda_codec * codec,const char * pfx,int cidx,unsigned int chs,struct nid_path * path)1020352f7f91STakashi Iwai static int add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx,
1021352f7f91STakashi Iwai unsigned int chs, struct nid_path *path)
1022352f7f91STakashi Iwai {
1023352f7f91STakashi Iwai unsigned int val;
1024352f7f91STakashi Iwai if (!path)
1025352f7f91STakashi Iwai return 0;
1026352f7f91STakashi Iwai val = path->ctls[NID_PATH_VOL_CTL];
1027352f7f91STakashi Iwai if (!val)
1028352f7f91STakashi Iwai return 0;
1029352f7f91STakashi Iwai val = amp_val_replace_channels(val, chs);
1030352f7f91STakashi Iwai return __add_pb_vol_ctrl(codec->spec, HDA_CTL_WIDGET_VOL, pfx, cidx, val);
1031352f7f91STakashi Iwai }
1032352f7f91STakashi Iwai
1033352f7f91STakashi Iwai /* return the channel bits suitable for the given path->ctls[] */
get_default_ch_nums(struct hda_codec * codec,struct nid_path * path,int type)1034352f7f91STakashi Iwai static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path,
1035352f7f91STakashi Iwai int type)
1036352f7f91STakashi Iwai {
1037352f7f91STakashi Iwai int chs = 1; /* mono (left only) */
1038352f7f91STakashi Iwai if (path) {
1039352f7f91STakashi Iwai hda_nid_t nid = get_amp_nid_(path->ctls[type]);
1040352f7f91STakashi Iwai if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO))
1041352f7f91STakashi Iwai chs = 3; /* stereo */
1042352f7f91STakashi Iwai }
1043352f7f91STakashi Iwai return chs;
1044352f7f91STakashi Iwai }
1045352f7f91STakashi Iwai
add_stereo_vol(struct hda_codec * codec,const char * pfx,int cidx,struct nid_path * path)1046352f7f91STakashi Iwai static int add_stereo_vol(struct hda_codec *codec, const char *pfx, int cidx,
1047352f7f91STakashi Iwai struct nid_path *path)
1048352f7f91STakashi Iwai {
1049352f7f91STakashi Iwai int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL);
1050352f7f91STakashi Iwai return add_vol_ctl(codec, pfx, cidx, chs, path);
1051352f7f91STakashi Iwai }
1052352f7f91STakashi Iwai
1053352f7f91STakashi Iwai /* create a mute-switch for the given mixer widget;
1054352f7f91STakashi Iwai * if it has multiple sources (e.g. DAC and loopback), create a bind-mute
1055352f7f91STakashi Iwai */
add_sw_ctl(struct hda_codec * codec,const char * pfx,int cidx,unsigned int chs,struct nid_path * path)1056352f7f91STakashi Iwai static int add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx,
1057352f7f91STakashi Iwai unsigned int chs, struct nid_path *path)
1058352f7f91STakashi Iwai {
1059352f7f91STakashi Iwai unsigned int val;
1060352f7f91STakashi Iwai int type = HDA_CTL_WIDGET_MUTE;
1061352f7f91STakashi Iwai
1062352f7f91STakashi Iwai if (!path)
1063352f7f91STakashi Iwai return 0;
1064352f7f91STakashi Iwai val = path->ctls[NID_PATH_MUTE_CTL];
1065352f7f91STakashi Iwai if (!val)
1066352f7f91STakashi Iwai return 0;
1067352f7f91STakashi Iwai val = amp_val_replace_channels(val, chs);
1068352f7f91STakashi Iwai if (get_amp_direction_(val) == HDA_INPUT) {
1069352f7f91STakashi Iwai hda_nid_t nid = get_amp_nid_(val);
1070352f7f91STakashi Iwai int nums = snd_hda_get_num_conns(codec, nid);
1071352f7f91STakashi Iwai if (nums > 1) {
1072352f7f91STakashi Iwai type = HDA_CTL_BIND_MUTE;
1073352f7f91STakashi Iwai val |= nums << 19;
1074352f7f91STakashi Iwai }
1075352f7f91STakashi Iwai }
1076352f7f91STakashi Iwai return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
1077352f7f91STakashi Iwai }
1078352f7f91STakashi Iwai
add_stereo_sw(struct hda_codec * codec,const char * pfx,int cidx,struct nid_path * path)1079352f7f91STakashi Iwai static int add_stereo_sw(struct hda_codec *codec, const char *pfx,
1080352f7f91STakashi Iwai int cidx, struct nid_path *path)
1081352f7f91STakashi Iwai {
1082352f7f91STakashi Iwai int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL);
1083352f7f91STakashi Iwai return add_sw_ctl(codec, pfx, cidx, chs, path);
1084352f7f91STakashi Iwai }
1085352f7f91STakashi Iwai
10867eebffd3STakashi Iwai /* playback mute control with the software mute bit check */
sync_auto_mute_bits(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1087bc2eee29STakashi Iwai static void sync_auto_mute_bits(struct snd_kcontrol *kcontrol,
10887eebffd3STakashi Iwai struct snd_ctl_elem_value *ucontrol)
10897eebffd3STakashi Iwai {
10907eebffd3STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10917eebffd3STakashi Iwai struct hda_gen_spec *spec = codec->spec;
10927eebffd3STakashi Iwai
10937eebffd3STakashi Iwai if (spec->auto_mute_via_amp) {
10947eebffd3STakashi Iwai hda_nid_t nid = get_amp_nid(kcontrol);
10957eebffd3STakashi Iwai bool enabled = !((spec->mute_bits >> nid) & 1);
10967eebffd3STakashi Iwai ucontrol->value.integer.value[0] &= enabled;
10977eebffd3STakashi Iwai ucontrol->value.integer.value[1] &= enabled;
10987eebffd3STakashi Iwai }
1099bc2eee29STakashi Iwai }
11007eebffd3STakashi Iwai
hda_gen_mixer_mute_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1101bc2eee29STakashi Iwai static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
1102bc2eee29STakashi Iwai struct snd_ctl_elem_value *ucontrol)
1103bc2eee29STakashi Iwai {
1104bc2eee29STakashi Iwai sync_auto_mute_bits(kcontrol, ucontrol);
11057eebffd3STakashi Iwai return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
11067eebffd3STakashi Iwai }
11077eebffd3STakashi Iwai
1108698f5ee3STakashi Iwai /*
1109698f5ee3STakashi Iwai * Bound mute controls
1110698f5ee3STakashi Iwai */
1111698f5ee3STakashi Iwai #define AMP_VAL_IDX_SHIFT 19
1112698f5ee3STakashi Iwai #define AMP_VAL_IDX_MASK (0x0f<<19)
1113698f5ee3STakashi Iwai
hda_gen_bind_mute_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1114698f5ee3STakashi Iwai static int hda_gen_bind_mute_get(struct snd_kcontrol *kcontrol,
1115698f5ee3STakashi Iwai struct snd_ctl_elem_value *ucontrol)
1116698f5ee3STakashi Iwai {
1117698f5ee3STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1118698f5ee3STakashi Iwai unsigned long pval;
1119698f5ee3STakashi Iwai int err;
1120698f5ee3STakashi Iwai
1121698f5ee3STakashi Iwai mutex_lock(&codec->control_mutex);
1122698f5ee3STakashi Iwai pval = kcontrol->private_value;
1123698f5ee3STakashi Iwai kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */
1124698f5ee3STakashi Iwai err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
1125698f5ee3STakashi Iwai kcontrol->private_value = pval;
1126698f5ee3STakashi Iwai mutex_unlock(&codec->control_mutex);
1127698f5ee3STakashi Iwai return err;
1128698f5ee3STakashi Iwai }
1129698f5ee3STakashi Iwai
hda_gen_bind_mute_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1130bc2eee29STakashi Iwai static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol,
1131bc2eee29STakashi Iwai struct snd_ctl_elem_value *ucontrol)
1132bc2eee29STakashi Iwai {
1133698f5ee3STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1134698f5ee3STakashi Iwai unsigned long pval;
1135698f5ee3STakashi Iwai int i, indices, err = 0, change = 0;
1136698f5ee3STakashi Iwai
1137bc2eee29STakashi Iwai sync_auto_mute_bits(kcontrol, ucontrol);
1138698f5ee3STakashi Iwai
1139698f5ee3STakashi Iwai mutex_lock(&codec->control_mutex);
1140698f5ee3STakashi Iwai pval = kcontrol->private_value;
1141698f5ee3STakashi Iwai indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT;
1142698f5ee3STakashi Iwai for (i = 0; i < indices; i++) {
1143698f5ee3STakashi Iwai kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) |
1144698f5ee3STakashi Iwai (i << AMP_VAL_IDX_SHIFT);
1145698f5ee3STakashi Iwai err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
1146698f5ee3STakashi Iwai if (err < 0)
1147698f5ee3STakashi Iwai break;
1148698f5ee3STakashi Iwai change |= err;
1149698f5ee3STakashi Iwai }
1150698f5ee3STakashi Iwai kcontrol->private_value = pval;
1151698f5ee3STakashi Iwai mutex_unlock(&codec->control_mutex);
1152698f5ee3STakashi Iwai return err < 0 ? err : change;
1153bc2eee29STakashi Iwai }
1154bc2eee29STakashi Iwai
1155247d85eeSTakashi Iwai /* any ctl assigned to the path with the given index? */
path_has_mixer(struct hda_codec * codec,int path_idx,int ctl_type)1156247d85eeSTakashi Iwai static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type)
1157247d85eeSTakashi Iwai {
1158247d85eeSTakashi Iwai struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx);
1159247d85eeSTakashi Iwai return path && path->ctls[ctl_type];
1160247d85eeSTakashi Iwai }
1161247d85eeSTakashi Iwai
11623b44ec8cSTakashi Iwai static const char * const channel_name[] = {
11633b44ec8cSTakashi Iwai "Front", "Surround", "CLFE", "Side", "Back",
1164352f7f91STakashi Iwai };
1165352f7f91STakashi Iwai
1166352f7f91STakashi Iwai /* give some appropriate ctl name prefix for the given line out channel */
get_line_out_pfx(struct hda_codec * codec,int ch,int * index,int ctl_type)1167247d85eeSTakashi Iwai static const char *get_line_out_pfx(struct hda_codec *codec, int ch,
1168247d85eeSTakashi Iwai int *index, int ctl_type)
1169352f7f91STakashi Iwai {
1170247d85eeSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
1171352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg;
1172352f7f91STakashi Iwai
1173352f7f91STakashi Iwai *index = 0;
1174352f7f91STakashi Iwai if (cfg->line_outs == 1 && !spec->multi_ios &&
11759f3dadb1STakashi Iwai !codec->force_pin_prefix &&
1176247d85eeSTakashi Iwai !cfg->hp_outs && !cfg->speaker_outs)
1177352f7f91STakashi Iwai return spec->vmaster_mute.hook ? "PCM" : "Master";
1178352f7f91STakashi Iwai
1179352f7f91STakashi Iwai /* if there is really a single DAC used in the whole output paths,
1180352f7f91STakashi Iwai * use it master (or "PCM" if a vmaster hook is present)
1181352f7f91STakashi Iwai */
1182352f7f91STakashi Iwai if (spec->multiout.num_dacs == 1 && !spec->mixer_nid &&
11839f3dadb1STakashi Iwai !codec->force_pin_prefix &&
1184352f7f91STakashi Iwai !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0])
1185352f7f91STakashi Iwai return spec->vmaster_mute.hook ? "PCM" : "Master";
1186352f7f91STakashi Iwai
1187247d85eeSTakashi Iwai /* multi-io channels */
1188247d85eeSTakashi Iwai if (ch >= cfg->line_outs)
11893b44ec8cSTakashi Iwai goto fixed_name;
1190247d85eeSTakashi Iwai
1191352f7f91STakashi Iwai switch (cfg->line_out_type) {
1192352f7f91STakashi Iwai case AUTO_PIN_SPEAKER_OUT:
1193247d85eeSTakashi Iwai /* if the primary channel vol/mute is shared with HP volume,
1194247d85eeSTakashi Iwai * don't name it as Speaker
1195247d85eeSTakashi Iwai */
1196247d85eeSTakashi Iwai if (!ch && cfg->hp_outs &&
1197247d85eeSTakashi Iwai !path_has_mixer(codec, spec->hp_paths[0], ctl_type))
1198247d85eeSTakashi Iwai break;
1199352f7f91STakashi Iwai if (cfg->line_outs == 1)
1200352f7f91STakashi Iwai return "Speaker";
1201352f7f91STakashi Iwai if (cfg->line_outs == 2)
1202352f7f91STakashi Iwai return ch ? "Bass Speaker" : "Speaker";
1203352f7f91STakashi Iwai break;
1204352f7f91STakashi Iwai case AUTO_PIN_HP_OUT:
1205247d85eeSTakashi Iwai /* if the primary channel vol/mute is shared with spk volume,
1206247d85eeSTakashi Iwai * don't name it as Headphone
1207247d85eeSTakashi Iwai */
1208247d85eeSTakashi Iwai if (!ch && cfg->speaker_outs &&
1209247d85eeSTakashi Iwai !path_has_mixer(codec, spec->speaker_paths[0], ctl_type))
1210247d85eeSTakashi Iwai break;
1211352f7f91STakashi Iwai /* for multi-io case, only the primary out */
1212352f7f91STakashi Iwai if (ch && spec->multi_ios)
1213352f7f91STakashi Iwai break;
1214352f7f91STakashi Iwai *index = ch;
1215352f7f91STakashi Iwai return "Headphone";
121603ad6a8cSDavid Henningsson case AUTO_PIN_LINE_OUT:
1217f48652bbSHui Wang /* This deals with the case where one HP or one Speaker or
1218f48652bbSHui Wang * one HP + one Speaker need to share the DAC with LO
1219f48652bbSHui Wang */
1220f48652bbSHui Wang if (!ch) {
1221f48652bbSHui Wang bool hp_lo_shared = false, spk_lo_shared = false;
1222f48652bbSHui Wang
1223f48652bbSHui Wang if (cfg->speaker_outs)
1224f48652bbSHui Wang spk_lo_shared = !path_has_mixer(codec,
1225f48652bbSHui Wang spec->speaker_paths[0], ctl_type);
1226f48652bbSHui Wang if (cfg->hp_outs)
1227f48652bbSHui Wang hp_lo_shared = !path_has_mixer(codec, spec->hp_paths[0], ctl_type);
122803ad6a8cSDavid Henningsson if (hp_lo_shared && spk_lo_shared)
122903ad6a8cSDavid Henningsson return spec->vmaster_mute.hook ? "PCM" : "Master";
123003ad6a8cSDavid Henningsson if (hp_lo_shared)
123103ad6a8cSDavid Henningsson return "Headphone+LO";
123203ad6a8cSDavid Henningsson if (spk_lo_shared)
123303ad6a8cSDavid Henningsson return "Speaker+LO";
123403ad6a8cSDavid Henningsson }
1235247d85eeSTakashi Iwai }
1236247d85eeSTakashi Iwai
1237247d85eeSTakashi Iwai /* for a single channel output, we don't have to name the channel */
1238352f7f91STakashi Iwai if (cfg->line_outs == 1 && !spec->multi_ios)
12393abb4f4dSDavid Henningsson return "Line Out";
1240247d85eeSTakashi Iwai
12413b44ec8cSTakashi Iwai fixed_name:
1242352f7f91STakashi Iwai if (ch >= ARRAY_SIZE(channel_name)) {
1243352f7f91STakashi Iwai snd_BUG();
1244352f7f91STakashi Iwai return "PCM";
1245352f7f91STakashi Iwai }
1246352f7f91STakashi Iwai
1247352f7f91STakashi Iwai return channel_name[ch];
1248352f7f91STakashi Iwai }
1249352f7f91STakashi Iwai
1250352f7f91STakashi Iwai /*
1251352f7f91STakashi Iwai * Parse output paths
1252352f7f91STakashi Iwai */
1253352f7f91STakashi Iwai
1254352f7f91STakashi Iwai /* badness definition */
1255352f7f91STakashi Iwai enum {
1256352f7f91STakashi Iwai /* No primary DAC is found for the main output */
1257352f7f91STakashi Iwai BAD_NO_PRIMARY_DAC = 0x10000,
1258352f7f91STakashi Iwai /* No DAC is found for the extra output */
1259352f7f91STakashi Iwai BAD_NO_DAC = 0x4000,
1260352f7f91STakashi Iwai /* No possible multi-ios */
12611d739066STakashi Iwai BAD_MULTI_IO = 0x120,
1262352f7f91STakashi Iwai /* No individual DAC for extra output */
1263352f7f91STakashi Iwai BAD_NO_EXTRA_DAC = 0x102,
1264352f7f91STakashi Iwai /* No individual DAC for extra surrounds */
1265352f7f91STakashi Iwai BAD_NO_EXTRA_SURR_DAC = 0x101,
1266352f7f91STakashi Iwai /* Primary DAC shared with main surrounds */
1267352f7f91STakashi Iwai BAD_SHARED_SURROUND = 0x100,
126855a63d4dSTakashi Iwai /* No independent HP possible */
1269bec8e680STakashi Iwai BAD_NO_INDEP_HP = 0x10,
1270352f7f91STakashi Iwai /* Primary DAC shared with main CLFE */
1271352f7f91STakashi Iwai BAD_SHARED_CLFE = 0x10,
1272352f7f91STakashi Iwai /* Primary DAC shared with extra surrounds */
1273352f7f91STakashi Iwai BAD_SHARED_EXTRA_SURROUND = 0x10,
1274352f7f91STakashi Iwai /* Volume widget is shared */
1275352f7f91STakashi Iwai BAD_SHARED_VOL = 0x10,
1276352f7f91STakashi Iwai };
1277352f7f91STakashi Iwai
12780e614dd0STakashi Iwai /* look for widgets in the given path which are appropriate for
1279352f7f91STakashi Iwai * volume and mute controls, and assign the values to ctls[].
1280352f7f91STakashi Iwai *
1281352f7f91STakashi Iwai * When no appropriate widget is found in the path, the badness value
1282352f7f91STakashi Iwai * is incremented depending on the situation. The function returns the
1283352f7f91STakashi Iwai * total badness for both volume and mute controls.
1284352f7f91STakashi Iwai */
assign_out_path_ctls(struct hda_codec * codec,struct nid_path * path)12850e614dd0STakashi Iwai static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path)
1286352f7f91STakashi Iwai {
1287d89c6c0cSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
1288352f7f91STakashi Iwai hda_nid_t nid;
1289352f7f91STakashi Iwai unsigned int val;
1290352f7f91STakashi Iwai int badness = 0;
1291352f7f91STakashi Iwai
1292352f7f91STakashi Iwai if (!path)
1293352f7f91STakashi Iwai return BAD_SHARED_VOL * 2;
12940e614dd0STakashi Iwai
12950e614dd0STakashi Iwai if (path->ctls[NID_PATH_VOL_CTL] ||
12960e614dd0STakashi Iwai path->ctls[NID_PATH_MUTE_CTL])
12970e614dd0STakashi Iwai return 0; /* already evaluated */
12980e614dd0STakashi Iwai
1299352f7f91STakashi Iwai nid = look_for_out_vol_nid(codec, path);
1300352f7f91STakashi Iwai if (nid) {
1301352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
1302d89c6c0cSTakashi Iwai if (spec->dac_min_mute)
1303d89c6c0cSTakashi Iwai val |= HDA_AMP_VAL_MIN_MUTE;
1304352f7f91STakashi Iwai if (is_ctl_used(codec, val, NID_PATH_VOL_CTL))
1305352f7f91STakashi Iwai badness += BAD_SHARED_VOL;
1306352f7f91STakashi Iwai else
1307352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = val;
1308352f7f91STakashi Iwai } else
1309352f7f91STakashi Iwai badness += BAD_SHARED_VOL;
1310352f7f91STakashi Iwai nid = look_for_out_mute_nid(codec, path);
1311352f7f91STakashi Iwai if (nid) {
1312352f7f91STakashi Iwai unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid));
1313352f7f91STakashi Iwai if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT ||
1314352f7f91STakashi Iwai nid_has_mute(codec, nid, HDA_OUTPUT))
1315352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
1316352f7f91STakashi Iwai else
1317352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT);
1318352f7f91STakashi Iwai if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL))
1319352f7f91STakashi Iwai badness += BAD_SHARED_VOL;
1320352f7f91STakashi Iwai else
1321352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = val;
1322352f7f91STakashi Iwai } else
1323352f7f91STakashi Iwai badness += BAD_SHARED_VOL;
1324352f7f91STakashi Iwai return badness;
1325352f7f91STakashi Iwai }
1326352f7f91STakashi Iwai
132798bd1115STakashi Iwai const struct badness_table hda_main_out_badness = {
1328352f7f91STakashi Iwai .no_primary_dac = BAD_NO_PRIMARY_DAC,
1329352f7f91STakashi Iwai .no_dac = BAD_NO_DAC,
1330352f7f91STakashi Iwai .shared_primary = BAD_NO_PRIMARY_DAC,
1331352f7f91STakashi Iwai .shared_surr = BAD_SHARED_SURROUND,
1332352f7f91STakashi Iwai .shared_clfe = BAD_SHARED_CLFE,
1333352f7f91STakashi Iwai .shared_surr_main = BAD_SHARED_SURROUND,
1334352f7f91STakashi Iwai };
13352698ea98STakashi Iwai EXPORT_SYMBOL_GPL(hda_main_out_badness);
1336352f7f91STakashi Iwai
133798bd1115STakashi Iwai const struct badness_table hda_extra_out_badness = {
1338352f7f91STakashi Iwai .no_primary_dac = BAD_NO_DAC,
1339352f7f91STakashi Iwai .no_dac = BAD_NO_DAC,
1340352f7f91STakashi Iwai .shared_primary = BAD_NO_EXTRA_DAC,
1341352f7f91STakashi Iwai .shared_surr = BAD_SHARED_EXTRA_SURROUND,
1342352f7f91STakashi Iwai .shared_clfe = BAD_SHARED_EXTRA_SURROUND,
1343352f7f91STakashi Iwai .shared_surr_main = BAD_NO_EXTRA_SURR_DAC,
1344352f7f91STakashi Iwai };
13452698ea98STakashi Iwai EXPORT_SYMBOL_GPL(hda_extra_out_badness);
1346352f7f91STakashi Iwai
13477385df61STakashi Iwai /* get the DAC of the primary output corresponding to the given array index */
get_primary_out(struct hda_codec * codec,int idx)13487385df61STakashi Iwai static hda_nid_t get_primary_out(struct hda_codec *codec, int idx)
13497385df61STakashi Iwai {
13507385df61STakashi Iwai struct hda_gen_spec *spec = codec->spec;
13517385df61STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg;
13527385df61STakashi Iwai
13537385df61STakashi Iwai if (cfg->line_outs > idx)
13547385df61STakashi Iwai return spec->private_dac_nids[idx];
13557385df61STakashi Iwai idx -= cfg->line_outs;
13567385df61STakashi Iwai if (spec->multi_ios > idx)
13577385df61STakashi Iwai return spec->multi_io[idx].dac;
13587385df61STakashi Iwai return 0;
13597385df61STakashi Iwai }
13607385df61STakashi Iwai
13617385df61STakashi Iwai /* return the DAC if it's reachable, otherwise zero */
try_dac(struct hda_codec * codec,hda_nid_t dac,hda_nid_t pin)13627385df61STakashi Iwai static inline hda_nid_t try_dac(struct hda_codec *codec,
13637385df61STakashi Iwai hda_nid_t dac, hda_nid_t pin)
13647385df61STakashi Iwai {
13657385df61STakashi Iwai return is_reachable_path(codec, dac, pin) ? dac : 0;
13667385df61STakashi Iwai }
13677385df61STakashi Iwai
1368352f7f91STakashi Iwai /* try to assign DACs to pins and return the resultant badness */
try_assign_dacs(struct hda_codec * codec,int num_outs,const hda_nid_t * pins,hda_nid_t * dacs,int * path_idx,const struct badness_table * bad)1369352f7f91STakashi Iwai static int try_assign_dacs(struct hda_codec *codec, int num_outs,
1370352f7f91STakashi Iwai const hda_nid_t *pins, hda_nid_t *dacs,
1371196c1766STakashi Iwai int *path_idx,
1372352f7f91STakashi Iwai const struct badness_table *bad)
1373352f7f91STakashi Iwai {
1374352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
1375352f7f91STakashi Iwai int i, j;
1376352f7f91STakashi Iwai int badness = 0;
1377352f7f91STakashi Iwai hda_nid_t dac;
1378352f7f91STakashi Iwai
1379352f7f91STakashi Iwai if (!num_outs)
1380352f7f91STakashi Iwai return 0;
1381352f7f91STakashi Iwai
1382352f7f91STakashi Iwai for (i = 0; i < num_outs; i++) {
13830c8c0f56STakashi Iwai struct nid_path *path;
1384352f7f91STakashi Iwai hda_nid_t pin = pins[i];
13851e0b5286STakashi Iwai
1386*f8f08157STakashi Iwai if (!spec->preferred_dacs) {
13870e614dd0STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx[i]);
13880e614dd0STakashi Iwai if (path) {
13890e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path);
13901e0b5286STakashi Iwai continue;
13911e0b5286STakashi Iwai }
1392242d990cSTakashi Iwai }
13931e0b5286STakashi Iwai
13943690739bSTakashi Iwai dacs[i] = get_preferred_dac(codec, pin);
13953690739bSTakashi Iwai if (dacs[i]) {
13963690739bSTakashi Iwai if (is_dac_already_used(codec, dacs[i]))
13973690739bSTakashi Iwai badness += bad->shared_primary;
1398*f8f08157STakashi Iwai } else if (spec->preferred_dacs) {
1399242d990cSTakashi Iwai badness += BAD_NO_PRIMARY_DAC;
14003690739bSTakashi Iwai }
14013690739bSTakashi Iwai
14023690739bSTakashi Iwai if (!dacs[i])
1403352f7f91STakashi Iwai dacs[i] = look_for_dac(codec, pin, false);
1404352f7f91STakashi Iwai if (!dacs[i] && !i) {
1405980428ceSTakashi Iwai /* try to steal the DAC of surrounds for the front */
1406352f7f91STakashi Iwai for (j = 1; j < num_outs; j++) {
1407352f7f91STakashi Iwai if (is_reachable_path(codec, dacs[j], pin)) {
1408352f7f91STakashi Iwai dacs[0] = dacs[j];
1409352f7f91STakashi Iwai dacs[j] = 0;
1410980428ceSTakashi Iwai invalidate_nid_path(codec, path_idx[j]);
1411196c1766STakashi Iwai path_idx[j] = 0;
1412352f7f91STakashi Iwai break;
1413352f7f91STakashi Iwai }
1414352f7f91STakashi Iwai }
1415352f7f91STakashi Iwai }
1416352f7f91STakashi Iwai dac = dacs[i];
1417352f7f91STakashi Iwai if (!dac) {
14187385df61STakashi Iwai if (num_outs > 2)
14197385df61STakashi Iwai dac = try_dac(codec, get_primary_out(codec, i), pin);
14207385df61STakashi Iwai if (!dac)
14217385df61STakashi Iwai dac = try_dac(codec, dacs[0], pin);
14227385df61STakashi Iwai if (!dac)
14237385df61STakashi Iwai dac = try_dac(codec, get_primary_out(codec, i), pin);
1424352f7f91STakashi Iwai if (dac) {
1425352f7f91STakashi Iwai if (!i)
1426352f7f91STakashi Iwai badness += bad->shared_primary;
1427352f7f91STakashi Iwai else if (i == 1)
1428352f7f91STakashi Iwai badness += bad->shared_surr;
1429352f7f91STakashi Iwai else
1430352f7f91STakashi Iwai badness += bad->shared_clfe;
1431352f7f91STakashi Iwai } else if (is_reachable_path(codec, spec->private_dac_nids[0], pin)) {
1432352f7f91STakashi Iwai dac = spec->private_dac_nids[0];
1433352f7f91STakashi Iwai badness += bad->shared_surr_main;
1434352f7f91STakashi Iwai } else if (!i)
1435352f7f91STakashi Iwai badness += bad->no_primary_dac;
1436352f7f91STakashi Iwai else
1437352f7f91STakashi Iwai badness += bad->no_dac;
1438352f7f91STakashi Iwai }
14391fa335b0STakashi Iwai if (!dac)
14401fa335b0STakashi Iwai continue;
14413ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, -spec->mixer_nid);
1442117688a9STakashi Iwai if (!path && !i && spec->mixer_nid) {
1443b3a8c745STakashi Iwai /* try with aamix */
14443ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, 0);
1445b3a8c745STakashi Iwai }
14461fa335b0STakashi Iwai if (!path) {
1447e73b4c9eSJiapeng Chong dacs[i] = 0;
14481fa335b0STakashi Iwai badness += bad->no_dac;
14491fa335b0STakashi Iwai } else {
14504e76a883STakashi Iwai /* print_nid_path(codec, "output", path); */
1451e1284af7STakashi Iwai path->active = true;
1452196c1766STakashi Iwai path_idx[i] = snd_hda_get_path_idx(codec, path);
14530e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path);
1454e1284af7STakashi Iwai }
1455352f7f91STakashi Iwai }
1456352f7f91STakashi Iwai
1457352f7f91STakashi Iwai return badness;
1458352f7f91STakashi Iwai }
1459352f7f91STakashi Iwai
1460352f7f91STakashi Iwai /* return NID if the given pin has only a single connection to a certain DAC */
get_dac_if_single(struct hda_codec * codec,hda_nid_t pin)1461352f7f91STakashi Iwai static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
1462352f7f91STakashi Iwai {
1463352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
1464352f7f91STakashi Iwai int i;
1465352f7f91STakashi Iwai hda_nid_t nid_found = 0;
1466352f7f91STakashi Iwai
1467352f7f91STakashi Iwai for (i = 0; i < spec->num_all_dacs; i++) {
1468352f7f91STakashi Iwai hda_nid_t nid = spec->all_dacs[i];
1469352f7f91STakashi Iwai if (!nid || is_dac_already_used(codec, nid))
1470352f7f91STakashi Iwai continue;
1471352f7f91STakashi Iwai if (is_reachable_path(codec, nid, pin)) {
1472352f7f91STakashi Iwai if (nid_found)
1473352f7f91STakashi Iwai return 0;
1474352f7f91STakashi Iwai nid_found = nid;
1475352f7f91STakashi Iwai }
1476352f7f91STakashi Iwai }
1477352f7f91STakashi Iwai return nid_found;
1478352f7f91STakashi Iwai }
1479352f7f91STakashi Iwai
1480352f7f91STakashi Iwai /* check whether the given pin can be a multi-io pin */
can_be_multiio_pin(struct hda_codec * codec,unsigned int location,hda_nid_t nid)1481352f7f91STakashi Iwai static bool can_be_multiio_pin(struct hda_codec *codec,
1482352f7f91STakashi Iwai unsigned int location, hda_nid_t nid)
1483352f7f91STakashi Iwai {
1484352f7f91STakashi Iwai unsigned int defcfg, caps;
1485352f7f91STakashi Iwai
1486352f7f91STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, nid);
1487352f7f91STakashi Iwai if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
1488352f7f91STakashi Iwai return false;
1489352f7f91STakashi Iwai if (location && get_defcfg_location(defcfg) != location)
1490352f7f91STakashi Iwai return false;
1491352f7f91STakashi Iwai caps = snd_hda_query_pin_caps(codec, nid);
1492352f7f91STakashi Iwai if (!(caps & AC_PINCAP_OUT))
1493352f7f91STakashi Iwai return false;
1494352f7f91STakashi Iwai return true;
1495352f7f91STakashi Iwai }
1496352f7f91STakashi Iwai
1497e22aab7dSTakashi Iwai /* count the number of input pins that are capable to be multi-io */
count_multiio_pins(struct hda_codec * codec,hda_nid_t reference_pin)1498e22aab7dSTakashi Iwai static int count_multiio_pins(struct hda_codec *codec, hda_nid_t reference_pin)
1499e22aab7dSTakashi Iwai {
1500e22aab7dSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
1501e22aab7dSTakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg;
1502e22aab7dSTakashi Iwai unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
1503e22aab7dSTakashi Iwai unsigned int location = get_defcfg_location(defcfg);
1504e22aab7dSTakashi Iwai int type, i;
1505e22aab7dSTakashi Iwai int num_pins = 0;
1506e22aab7dSTakashi Iwai
1507e22aab7dSTakashi Iwai for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
1508e22aab7dSTakashi Iwai for (i = 0; i < cfg->num_inputs; i++) {
1509e22aab7dSTakashi Iwai if (cfg->inputs[i].type != type)
1510e22aab7dSTakashi Iwai continue;
1511e22aab7dSTakashi Iwai if (can_be_multiio_pin(codec, location,
1512e22aab7dSTakashi Iwai cfg->inputs[i].pin))
1513e22aab7dSTakashi Iwai num_pins++;
1514e22aab7dSTakashi Iwai }
1515e22aab7dSTakashi Iwai }
1516e22aab7dSTakashi Iwai return num_pins;
1517e22aab7dSTakashi Iwai }
1518e22aab7dSTakashi Iwai
1519352f7f91STakashi Iwai /*
1520352f7f91STakashi Iwai * multi-io helper
1521352f7f91STakashi Iwai *
1522352f7f91STakashi Iwai * When hardwired is set, try to fill ony hardwired pins, and returns
1523352f7f91STakashi Iwai * zero if any pins are filled, non-zero if nothing found.
1524352f7f91STakashi Iwai * When hardwired is off, try to fill possible input pins, and returns
1525352f7f91STakashi Iwai * the badness value.
1526352f7f91STakashi Iwai */
fill_multi_ios(struct hda_codec * codec,hda_nid_t reference_pin,bool hardwired)1527352f7f91STakashi Iwai static int fill_multi_ios(struct hda_codec *codec,
1528352f7f91STakashi Iwai hda_nid_t reference_pin,
1529e22aab7dSTakashi Iwai bool hardwired)
1530352f7f91STakashi Iwai {
1531352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
1532352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg;
1533e22aab7dSTakashi Iwai int type, i, j, num_pins, old_pins;
1534352f7f91STakashi Iwai unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
1535352f7f91STakashi Iwai unsigned int location = get_defcfg_location(defcfg);
1536352f7f91STakashi Iwai int badness = 0;
15370e614dd0STakashi Iwai struct nid_path *path;
1538352f7f91STakashi Iwai
1539352f7f91STakashi Iwai old_pins = spec->multi_ios;
1540352f7f91STakashi Iwai if (old_pins >= 2)
1541352f7f91STakashi Iwai goto end_fill;
1542352f7f91STakashi Iwai
1543e22aab7dSTakashi Iwai num_pins = count_multiio_pins(codec, reference_pin);
1544352f7f91STakashi Iwai if (num_pins < 2)
1545352f7f91STakashi Iwai goto end_fill;
1546352f7f91STakashi Iwai
1547352f7f91STakashi Iwai for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
1548352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) {
1549352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin;
1550352f7f91STakashi Iwai hda_nid_t dac = 0;
1551352f7f91STakashi Iwai
1552352f7f91STakashi Iwai if (cfg->inputs[i].type != type)
1553352f7f91STakashi Iwai continue;
1554352f7f91STakashi Iwai if (!can_be_multiio_pin(codec, location, nid))
1555352f7f91STakashi Iwai continue;
1556352f7f91STakashi Iwai for (j = 0; j < spec->multi_ios; j++) {
1557352f7f91STakashi Iwai if (nid == spec->multi_io[j].pin)
1558352f7f91STakashi Iwai break;
1559352f7f91STakashi Iwai }
1560352f7f91STakashi Iwai if (j < spec->multi_ios)
1561352f7f91STakashi Iwai continue;
1562352f7f91STakashi Iwai
1563352f7f91STakashi Iwai if (hardwired)
1564352f7f91STakashi Iwai dac = get_dac_if_single(codec, nid);
1565352f7f91STakashi Iwai else if (!dac)
1566352f7f91STakashi Iwai dac = look_for_dac(codec, nid, false);
1567352f7f91STakashi Iwai if (!dac) {
1568352f7f91STakashi Iwai badness++;
1569352f7f91STakashi Iwai continue;
1570352f7f91STakashi Iwai }
15713ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, nid,
15723ca529d3STakashi Iwai -spec->mixer_nid);
15730c8c0f56STakashi Iwai if (!path) {
1574352f7f91STakashi Iwai badness++;
1575352f7f91STakashi Iwai continue;
1576352f7f91STakashi Iwai }
15774e76a883STakashi Iwai /* print_nid_path(codec, "multiio", path); */
1578352f7f91STakashi Iwai spec->multi_io[spec->multi_ios].pin = nid;
1579352f7f91STakashi Iwai spec->multi_io[spec->multi_ios].dac = dac;
1580196c1766STakashi Iwai spec->out_paths[cfg->line_outs + spec->multi_ios] =
1581196c1766STakashi Iwai snd_hda_get_path_idx(codec, path);
1582352f7f91STakashi Iwai spec->multi_ios++;
1583352f7f91STakashi Iwai if (spec->multi_ios >= 2)
1584352f7f91STakashi Iwai break;
1585352f7f91STakashi Iwai }
1586352f7f91STakashi Iwai }
1587352f7f91STakashi Iwai end_fill:
1588352f7f91STakashi Iwai if (badness)
1589352f7f91STakashi Iwai badness = BAD_MULTI_IO;
1590352f7f91STakashi Iwai if (old_pins == spec->multi_ios) {
1591352f7f91STakashi Iwai if (hardwired)
1592352f7f91STakashi Iwai return 1; /* nothing found */
1593352f7f91STakashi Iwai else
1594352f7f91STakashi Iwai return badness; /* no badness if nothing found */
1595352f7f91STakashi Iwai }
1596352f7f91STakashi Iwai if (!hardwired && spec->multi_ios < 2) {
1597352f7f91STakashi Iwai /* cancel newly assigned paths */
1598352f7f91STakashi Iwai spec->paths.used -= spec->multi_ios - old_pins;
1599352f7f91STakashi Iwai spec->multi_ios = old_pins;
1600352f7f91STakashi Iwai return badness;
1601352f7f91STakashi Iwai }
1602352f7f91STakashi Iwai
1603352f7f91STakashi Iwai /* assign volume and mute controls */
16040e614dd0STakashi Iwai for (i = old_pins; i < spec->multi_ios; i++) {
16050e614dd0STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[cfg->line_outs + i]);
16060e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path);
16070e614dd0STakashi Iwai }
1608352f7f91STakashi Iwai
1609352f7f91STakashi Iwai return badness;
1610352f7f91STakashi Iwai }
1611352f7f91STakashi Iwai
1612352f7f91STakashi Iwai /* map DACs for all pins in the list if they are single connections */
map_singles(struct hda_codec * codec,int outs,const hda_nid_t * pins,hda_nid_t * dacs,int * path_idx)1613352f7f91STakashi Iwai static bool map_singles(struct hda_codec *codec, int outs,
1614196c1766STakashi Iwai const hda_nid_t *pins, hda_nid_t *dacs, int *path_idx)
1615352f7f91STakashi Iwai {
1616b3a8c745STakashi Iwai struct hda_gen_spec *spec = codec->spec;
1617352f7f91STakashi Iwai int i;
1618352f7f91STakashi Iwai bool found = false;
1619352f7f91STakashi Iwai for (i = 0; i < outs; i++) {
16200c8c0f56STakashi Iwai struct nid_path *path;
1621352f7f91STakashi Iwai hda_nid_t dac;
1622352f7f91STakashi Iwai if (dacs[i])
1623352f7f91STakashi Iwai continue;
1624352f7f91STakashi Iwai dac = get_dac_if_single(codec, pins[i]);
1625352f7f91STakashi Iwai if (!dac)
1626352f7f91STakashi Iwai continue;
16273ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pins[i],
16283ca529d3STakashi Iwai -spec->mixer_nid);
1629117688a9STakashi Iwai if (!path && !i && spec->mixer_nid)
16303ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pins[i], 0);
16310c8c0f56STakashi Iwai if (path) {
1632352f7f91STakashi Iwai dacs[i] = dac;
1633352f7f91STakashi Iwai found = true;
16344e76a883STakashi Iwai /* print_nid_path(codec, "output", path); */
1635e1284af7STakashi Iwai path->active = true;
1636196c1766STakashi Iwai path_idx[i] = snd_hda_get_path_idx(codec, path);
1637352f7f91STakashi Iwai }
1638352f7f91STakashi Iwai }
1639352f7f91STakashi Iwai return found;
1640352f7f91STakashi Iwai }
1641352f7f91STakashi Iwai
has_aamix_out_paths(struct hda_gen_spec * spec)1642e7fdd527STakashi Iwai static inline bool has_aamix_out_paths(struct hda_gen_spec *spec)
1643e7fdd527STakashi Iwai {
1644e7fdd527STakashi Iwai return spec->aamix_out_paths[0] || spec->aamix_out_paths[1] ||
1645e7fdd527STakashi Iwai spec->aamix_out_paths[2];
1646e7fdd527STakashi Iwai }
1647e7fdd527STakashi Iwai
1648c30aa7b2STakashi Iwai /* create a new path including aamix if available, and return its index */
check_aamix_out_path(struct hda_codec * codec,int path_idx)1649c30aa7b2STakashi Iwai static int check_aamix_out_path(struct hda_codec *codec, int path_idx)
1650c30aa7b2STakashi Iwai {
16513ca529d3STakashi Iwai struct hda_gen_spec *spec = codec->spec;
1652c30aa7b2STakashi Iwai struct nid_path *path;
16535ead56f2STakashi Iwai hda_nid_t path_dac, dac, pin;
1654c30aa7b2STakashi Iwai
1655c30aa7b2STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx);
16563ca529d3STakashi Iwai if (!path || !path->depth ||
16573ca529d3STakashi Iwai is_nid_contained(path, spec->mixer_nid))
1658c30aa7b2STakashi Iwai return 0;
16595ead56f2STakashi Iwai path_dac = path->path[0];
16605ead56f2STakashi Iwai dac = spec->private_dac_nids[0];
1661f87498b6STakashi Iwai pin = path->path[path->depth - 1];
1662f87498b6STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, spec->mixer_nid);
1663f87498b6STakashi Iwai if (!path) {
16645ead56f2STakashi Iwai if (dac != path_dac)
16655ead56f2STakashi Iwai dac = path_dac;
1666f87498b6STakashi Iwai else if (spec->multiout.hp_out_nid[0])
1667f87498b6STakashi Iwai dac = spec->multiout.hp_out_nid[0];
1668f87498b6STakashi Iwai else if (spec->multiout.extra_out_nid[0])
1669f87498b6STakashi Iwai dac = spec->multiout.extra_out_nid[0];
16705ead56f2STakashi Iwai else
16715ead56f2STakashi Iwai dac = 0;
1672f87498b6STakashi Iwai if (dac)
1673f87498b6STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin,
16743ca529d3STakashi Iwai spec->mixer_nid);
1675f87498b6STakashi Iwai }
1676c30aa7b2STakashi Iwai if (!path)
1677c30aa7b2STakashi Iwai return 0;
16784e76a883STakashi Iwai /* print_nid_path(codec, "output-aamix", path); */
1679c30aa7b2STakashi Iwai path->active = false; /* unused as default */
16806b275b14STakashi Iwai path->pin_fixed = true; /* static route */
1681c30aa7b2STakashi Iwai return snd_hda_get_path_idx(codec, path);
1682c30aa7b2STakashi Iwai }
1683c30aa7b2STakashi Iwai
168455a63d4dSTakashi Iwai /* check whether the independent HP is available with the current config */
indep_hp_possible(struct hda_codec * codec)168555a63d4dSTakashi Iwai static bool indep_hp_possible(struct hda_codec *codec)
168655a63d4dSTakashi Iwai {
168755a63d4dSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
168855a63d4dSTakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg;
168955a63d4dSTakashi Iwai struct nid_path *path;
169055a63d4dSTakashi Iwai int i, idx;
169155a63d4dSTakashi Iwai
169255a63d4dSTakashi Iwai if (cfg->line_out_type == AUTO_PIN_HP_OUT)
169355a63d4dSTakashi Iwai idx = spec->out_paths[0];
169455a63d4dSTakashi Iwai else
169555a63d4dSTakashi Iwai idx = spec->hp_paths[0];
169655a63d4dSTakashi Iwai path = snd_hda_get_path_from_idx(codec, idx);
169755a63d4dSTakashi Iwai if (!path)
169855a63d4dSTakashi Iwai return false;
169955a63d4dSTakashi Iwai
170055a63d4dSTakashi Iwai /* assume no path conflicts unless aamix is involved */
170155a63d4dSTakashi Iwai if (!spec->mixer_nid || !is_nid_contained(path, spec->mixer_nid))
170255a63d4dSTakashi Iwai return true;
170355a63d4dSTakashi Iwai
170455a63d4dSTakashi Iwai /* check whether output paths contain aamix */
170555a63d4dSTakashi Iwai for (i = 0; i < cfg->line_outs; i++) {
170655a63d4dSTakashi Iwai if (spec->out_paths[i] == idx)
170755a63d4dSTakashi Iwai break;
170855a63d4dSTakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]);
170955a63d4dSTakashi Iwai if (path && is_nid_contained(path, spec->mixer_nid))
171055a63d4dSTakashi Iwai return false;
171155a63d4dSTakashi Iwai }
171255a63d4dSTakashi Iwai for (i = 0; i < cfg->speaker_outs; i++) {
171355a63d4dSTakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->speaker_paths[i]);
171455a63d4dSTakashi Iwai if (path && is_nid_contained(path, spec->mixer_nid))
171555a63d4dSTakashi Iwai return false;
171655a63d4dSTakashi Iwai }
171755a63d4dSTakashi Iwai
171855a63d4dSTakashi Iwai return true;
171955a63d4dSTakashi Iwai }
172055a63d4dSTakashi Iwai
1721a07a949bSTakashi Iwai /* fill the empty entries in the dac array for speaker/hp with the
1722a07a949bSTakashi Iwai * shared dac pointed by the paths
1723a07a949bSTakashi Iwai */
refill_shared_dacs(struct hda_codec * codec,int num_outs,hda_nid_t * dacs,int * path_idx)1724a07a949bSTakashi Iwai static void refill_shared_dacs(struct hda_codec *codec, int num_outs,
1725a07a949bSTakashi Iwai hda_nid_t *dacs, int *path_idx)
1726a07a949bSTakashi Iwai {
1727a07a949bSTakashi Iwai struct nid_path *path;
1728a07a949bSTakashi Iwai int i;
1729a07a949bSTakashi Iwai
1730a07a949bSTakashi Iwai for (i = 0; i < num_outs; i++) {
1731a07a949bSTakashi Iwai if (dacs[i])
1732a07a949bSTakashi Iwai continue;
1733a07a949bSTakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx[i]);
1734a07a949bSTakashi Iwai if (!path)
1735a07a949bSTakashi Iwai continue;
1736a07a949bSTakashi Iwai dacs[i] = path->path[0];
1737a07a949bSTakashi Iwai }
1738a07a949bSTakashi Iwai }
1739a07a949bSTakashi Iwai
1740352f7f91STakashi Iwai /* fill in the dac_nids table from the parsed pin configuration */
fill_and_eval_dacs(struct hda_codec * codec,bool fill_hardwired,bool fill_mio_first)1741352f7f91STakashi Iwai static int fill_and_eval_dacs(struct hda_codec *codec,
1742352f7f91STakashi Iwai bool fill_hardwired,
1743352f7f91STakashi Iwai bool fill_mio_first)
1744352f7f91STakashi Iwai {
1745352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
1746352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg;
1747352f7f91STakashi Iwai int i, err, badness;
1748352f7f91STakashi Iwai
1749352f7f91STakashi Iwai /* set num_dacs once to full for look_for_dac() */
1750352f7f91STakashi Iwai spec->multiout.num_dacs = cfg->line_outs;
1751352f7f91STakashi Iwai spec->multiout.dac_nids = spec->private_dac_nids;
1752352f7f91STakashi Iwai memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
1753352f7f91STakashi Iwai memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid));
1754352f7f91STakashi Iwai memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid));
1755352f7f91STakashi Iwai spec->multi_ios = 0;
1756352f7f91STakashi Iwai snd_array_free(&spec->paths);
1757cd5be3f9STakashi Iwai
1758cd5be3f9STakashi Iwai /* clear path indices */
1759cd5be3f9STakashi Iwai memset(spec->out_paths, 0, sizeof(spec->out_paths));
1760cd5be3f9STakashi Iwai memset(spec->hp_paths, 0, sizeof(spec->hp_paths));
1761cd5be3f9STakashi Iwai memset(spec->speaker_paths, 0, sizeof(spec->speaker_paths));
1762cd5be3f9STakashi Iwai memset(spec->aamix_out_paths, 0, sizeof(spec->aamix_out_paths));
1763cd5be3f9STakashi Iwai memset(spec->digout_paths, 0, sizeof(spec->digout_paths));
1764c697b716STakashi Iwai memset(spec->input_paths, 0, sizeof(spec->input_paths));
1765cd5be3f9STakashi Iwai memset(spec->loopback_paths, 0, sizeof(spec->loopback_paths));
1766cd5be3f9STakashi Iwai memset(&spec->digin_path, 0, sizeof(spec->digin_path));
1767cd5be3f9STakashi Iwai
1768352f7f91STakashi Iwai badness = 0;
1769352f7f91STakashi Iwai
1770352f7f91STakashi Iwai /* fill hard-wired DACs first */
1771352f7f91STakashi Iwai if (fill_hardwired) {
1772352f7f91STakashi Iwai bool mapped;
1773352f7f91STakashi Iwai do {
1774352f7f91STakashi Iwai mapped = map_singles(codec, cfg->line_outs,
1775352f7f91STakashi Iwai cfg->line_out_pins,
1776196c1766STakashi Iwai spec->private_dac_nids,
1777196c1766STakashi Iwai spec->out_paths);
1778352f7f91STakashi Iwai mapped |= map_singles(codec, cfg->hp_outs,
1779352f7f91STakashi Iwai cfg->hp_pins,
1780196c1766STakashi Iwai spec->multiout.hp_out_nid,
1781196c1766STakashi Iwai spec->hp_paths);
1782352f7f91STakashi Iwai mapped |= map_singles(codec, cfg->speaker_outs,
1783352f7f91STakashi Iwai cfg->speaker_pins,
1784196c1766STakashi Iwai spec->multiout.extra_out_nid,
1785196c1766STakashi Iwai spec->speaker_paths);
1786da96fb5bSTakashi Iwai if (!spec->no_multi_io &&
1787da96fb5bSTakashi Iwai fill_mio_first && cfg->line_outs == 1 &&
1788352f7f91STakashi Iwai cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1789e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], true);
1790352f7f91STakashi Iwai if (!err)
1791352f7f91STakashi Iwai mapped = true;
1792352f7f91STakashi Iwai }
1793352f7f91STakashi Iwai } while (mapped);
1794352f7f91STakashi Iwai }
1795352f7f91STakashi Iwai
1796352f7f91STakashi Iwai badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins,
1797196c1766STakashi Iwai spec->private_dac_nids, spec->out_paths,
179898bd1115STakashi Iwai spec->main_out_badness);
1799352f7f91STakashi Iwai
1800da96fb5bSTakashi Iwai if (!spec->no_multi_io && fill_mio_first &&
1801352f7f91STakashi Iwai cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1802352f7f91STakashi Iwai /* try to fill multi-io first */
1803e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
1804352f7f91STakashi Iwai if (err < 0)
1805352f7f91STakashi Iwai return err;
1806352f7f91STakashi Iwai /* we don't count badness at this stage yet */
1807352f7f91STakashi Iwai }
1808352f7f91STakashi Iwai
1809352f7f91STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
1810352f7f91STakashi Iwai err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins,
1811352f7f91STakashi Iwai spec->multiout.hp_out_nid,
1812196c1766STakashi Iwai spec->hp_paths,
181398bd1115STakashi Iwai spec->extra_out_badness);
1814352f7f91STakashi Iwai if (err < 0)
1815352f7f91STakashi Iwai return err;
1816352f7f91STakashi Iwai badness += err;
1817352f7f91STakashi Iwai }
1818352f7f91STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1819352f7f91STakashi Iwai err = try_assign_dacs(codec, cfg->speaker_outs,
1820352f7f91STakashi Iwai cfg->speaker_pins,
1821352f7f91STakashi Iwai spec->multiout.extra_out_nid,
1822196c1766STakashi Iwai spec->speaker_paths,
182398bd1115STakashi Iwai spec->extra_out_badness);
1824352f7f91STakashi Iwai if (err < 0)
1825352f7f91STakashi Iwai return err;
1826352f7f91STakashi Iwai badness += err;
1827352f7f91STakashi Iwai }
1828da96fb5bSTakashi Iwai if (!spec->no_multi_io &&
1829da96fb5bSTakashi Iwai cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
1830e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
1831352f7f91STakashi Iwai if (err < 0)
1832352f7f91STakashi Iwai return err;
1833352f7f91STakashi Iwai badness += err;
1834352f7f91STakashi Iwai }
1835e22aab7dSTakashi Iwai
1836c30aa7b2STakashi Iwai if (spec->mixer_nid) {
1837c30aa7b2STakashi Iwai spec->aamix_out_paths[0] =
1838c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->out_paths[0]);
1839c30aa7b2STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT)
1840c30aa7b2STakashi Iwai spec->aamix_out_paths[1] =
1841c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->hp_paths[0]);
1842c30aa7b2STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
1843c30aa7b2STakashi Iwai spec->aamix_out_paths[2] =
1844c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->speaker_paths[0]);
1845c30aa7b2STakashi Iwai }
1846c30aa7b2STakashi Iwai
1847da96fb5bSTakashi Iwai if (!spec->no_multi_io &&
1848da96fb5bSTakashi Iwai cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
1849e22aab7dSTakashi Iwai if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2)
1850e22aab7dSTakashi Iwai spec->multi_ios = 1; /* give badness */
1851352f7f91STakashi Iwai
1852a07a949bSTakashi Iwai /* re-count num_dacs and squash invalid entries */
1853a07a949bSTakashi Iwai spec->multiout.num_dacs = 0;
1854a07a949bSTakashi Iwai for (i = 0; i < cfg->line_outs; i++) {
1855a07a949bSTakashi Iwai if (spec->private_dac_nids[i])
1856a07a949bSTakashi Iwai spec->multiout.num_dacs++;
1857a07a949bSTakashi Iwai else {
1858a07a949bSTakashi Iwai memmove(spec->private_dac_nids + i,
1859a07a949bSTakashi Iwai spec->private_dac_nids + i + 1,
1860a07a949bSTakashi Iwai sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
1861a07a949bSTakashi Iwai spec->private_dac_nids[cfg->line_outs - 1] = 0;
1862a07a949bSTakashi Iwai }
1863a07a949bSTakashi Iwai }
1864a07a949bSTakashi Iwai
1865a07a949bSTakashi Iwai spec->ext_channel_count = spec->min_channel_count =
1866c0f3b216SDavid Henningsson spec->multiout.num_dacs * 2;
1867a07a949bSTakashi Iwai
1868352f7f91STakashi Iwai if (spec->multi_ios == 2) {
1869352f7f91STakashi Iwai for (i = 0; i < 2; i++)
1870352f7f91STakashi Iwai spec->private_dac_nids[spec->multiout.num_dacs++] =
1871352f7f91STakashi Iwai spec->multi_io[i].dac;
1872352f7f91STakashi Iwai } else if (spec->multi_ios) {
1873352f7f91STakashi Iwai spec->multi_ios = 0;
1874352f7f91STakashi Iwai badness += BAD_MULTI_IO;
1875352f7f91STakashi Iwai }
1876352f7f91STakashi Iwai
187755a63d4dSTakashi Iwai if (spec->indep_hp && !indep_hp_possible(codec))
187855a63d4dSTakashi Iwai badness += BAD_NO_INDEP_HP;
187955a63d4dSTakashi Iwai
1880a07a949bSTakashi Iwai /* re-fill the shared DAC for speaker / headphone */
1881a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT)
1882a07a949bSTakashi Iwai refill_shared_dacs(codec, cfg->hp_outs,
1883a07a949bSTakashi Iwai spec->multiout.hp_out_nid,
1884a07a949bSTakashi Iwai spec->hp_paths);
1885a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
1886a07a949bSTakashi Iwai refill_shared_dacs(codec, cfg->speaker_outs,
1887a07a949bSTakashi Iwai spec->multiout.extra_out_nid,
1888a07a949bSTakashi Iwai spec->speaker_paths);
1889a07a949bSTakashi Iwai
1890352f7f91STakashi Iwai return badness;
1891352f7f91STakashi Iwai }
1892352f7f91STakashi Iwai
1893352f7f91STakashi Iwai #define DEBUG_BADNESS
1894352f7f91STakashi Iwai
1895352f7f91STakashi Iwai #ifdef DEBUG_BADNESS
1896d82353e5SJoe Perches #define debug_badness(fmt, ...) \
1897d82353e5SJoe Perches codec_dbg(codec, fmt, ##__VA_ARGS__)
1898352f7f91STakashi Iwai #else
1899d82353e5SJoe Perches #define debug_badness(fmt, ...) \
1900d82353e5SJoe Perches do { if (0) codec_dbg(codec, fmt, ##__VA_ARGS__); } while (0)
1901352f7f91STakashi Iwai #endif
1902352f7f91STakashi Iwai
1903a769409cSTakashi Iwai #ifdef DEBUG_BADNESS
print_nid_path_idx(struct hda_codec * codec,const char * pfx,int idx)1904a769409cSTakashi Iwai static inline void print_nid_path_idx(struct hda_codec *codec,
1905a769409cSTakashi Iwai const char *pfx, int idx)
1906352f7f91STakashi Iwai {
1907a769409cSTakashi Iwai struct nid_path *path;
1908a769409cSTakashi Iwai
1909a769409cSTakashi Iwai path = snd_hda_get_path_from_idx(codec, idx);
1910a769409cSTakashi Iwai if (path)
19114e76a883STakashi Iwai print_nid_path(codec, pfx, path);
1912a769409cSTakashi Iwai }
1913a769409cSTakashi Iwai
debug_show_configs(struct hda_codec * codec,struct auto_pin_cfg * cfg)1914a769409cSTakashi Iwai static void debug_show_configs(struct hda_codec *codec,
1915a769409cSTakashi Iwai struct auto_pin_cfg *cfg)
1916a769409cSTakashi Iwai {
1917a769409cSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
1918a769409cSTakashi Iwai static const char * const lo_type[3] = { "LO", "SP", "HP" };
1919a769409cSTakashi Iwai int i;
1920a769409cSTakashi Iwai
1921a769409cSTakashi Iwai debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x (type %s)\n",
1922352f7f91STakashi Iwai cfg->line_out_pins[0], cfg->line_out_pins[1],
1923708122e8STakashi Iwai cfg->line_out_pins[2], cfg->line_out_pins[3],
1924352f7f91STakashi Iwai spec->multiout.dac_nids[0],
1925352f7f91STakashi Iwai spec->multiout.dac_nids[1],
1926352f7f91STakashi Iwai spec->multiout.dac_nids[2],
1927a769409cSTakashi Iwai spec->multiout.dac_nids[3],
1928a769409cSTakashi Iwai lo_type[cfg->line_out_type]);
1929a769409cSTakashi Iwai for (i = 0; i < cfg->line_outs; i++)
1930a769409cSTakashi Iwai print_nid_path_idx(codec, " out", spec->out_paths[i]);
1931352f7f91STakashi Iwai if (spec->multi_ios > 0)
1932352f7f91STakashi Iwai debug_badness("multi_ios(%d) = %x/%x : %x/%x\n",
1933352f7f91STakashi Iwai spec->multi_ios,
1934352f7f91STakashi Iwai spec->multi_io[0].pin, spec->multi_io[1].pin,
1935352f7f91STakashi Iwai spec->multi_io[0].dac, spec->multi_io[1].dac);
1936a769409cSTakashi Iwai for (i = 0; i < spec->multi_ios; i++)
1937a769409cSTakashi Iwai print_nid_path_idx(codec, " mio",
1938a769409cSTakashi Iwai spec->out_paths[cfg->line_outs + i]);
1939a769409cSTakashi Iwai if (cfg->hp_outs)
1940352f7f91STakashi Iwai debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
1941352f7f91STakashi Iwai cfg->hp_pins[0], cfg->hp_pins[1],
1942708122e8STakashi Iwai cfg->hp_pins[2], cfg->hp_pins[3],
1943352f7f91STakashi Iwai spec->multiout.hp_out_nid[0],
1944352f7f91STakashi Iwai spec->multiout.hp_out_nid[1],
1945352f7f91STakashi Iwai spec->multiout.hp_out_nid[2],
1946352f7f91STakashi Iwai spec->multiout.hp_out_nid[3]);
1947a769409cSTakashi Iwai for (i = 0; i < cfg->hp_outs; i++)
1948a769409cSTakashi Iwai print_nid_path_idx(codec, " hp ", spec->hp_paths[i]);
1949a769409cSTakashi Iwai if (cfg->speaker_outs)
1950352f7f91STakashi Iwai debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
1951352f7f91STakashi Iwai cfg->speaker_pins[0], cfg->speaker_pins[1],
1952352f7f91STakashi Iwai cfg->speaker_pins[2], cfg->speaker_pins[3],
1953352f7f91STakashi Iwai spec->multiout.extra_out_nid[0],
1954352f7f91STakashi Iwai spec->multiout.extra_out_nid[1],
1955352f7f91STakashi Iwai spec->multiout.extra_out_nid[2],
1956352f7f91STakashi Iwai spec->multiout.extra_out_nid[3]);
1957a769409cSTakashi Iwai for (i = 0; i < cfg->speaker_outs; i++)
1958a769409cSTakashi Iwai print_nid_path_idx(codec, " spk", spec->speaker_paths[i]);
1959a769409cSTakashi Iwai for (i = 0; i < 3; i++)
1960a769409cSTakashi Iwai print_nid_path_idx(codec, " mix", spec->aamix_out_paths[i]);
1961352f7f91STakashi Iwai }
1962a769409cSTakashi Iwai #else
1963a769409cSTakashi Iwai #define debug_show_configs(codec, cfg) /* NOP */
1964a769409cSTakashi Iwai #endif
1965352f7f91STakashi Iwai
1966352f7f91STakashi Iwai /* find all available DACs of the codec */
fill_all_dac_nids(struct hda_codec * codec)1967352f7f91STakashi Iwai static void fill_all_dac_nids(struct hda_codec *codec)
1968352f7f91STakashi Iwai {
1969352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
19707639a06cSTakashi Iwai hda_nid_t nid;
1971352f7f91STakashi Iwai
1972352f7f91STakashi Iwai spec->num_all_dacs = 0;
1973352f7f91STakashi Iwai memset(spec->all_dacs, 0, sizeof(spec->all_dacs));
19747639a06cSTakashi Iwai for_each_hda_codec_node(nid, codec) {
1975352f7f91STakashi Iwai if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT)
1976352f7f91STakashi Iwai continue;
1977352f7f91STakashi Iwai if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) {
19784e76a883STakashi Iwai codec_err(codec, "Too many DACs!\n");
1979352f7f91STakashi Iwai break;
1980352f7f91STakashi Iwai }
1981352f7f91STakashi Iwai spec->all_dacs[spec->num_all_dacs++] = nid;
1982352f7f91STakashi Iwai }
1983352f7f91STakashi Iwai }
1984352f7f91STakashi Iwai
parse_output_paths(struct hda_codec * codec)1985352f7f91STakashi Iwai static int parse_output_paths(struct hda_codec *codec)
1986352f7f91STakashi Iwai {
1987352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
1988352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg;
1989352f7f91STakashi Iwai struct auto_pin_cfg *best_cfg;
19909314a581STakashi Iwai unsigned int val;
1991352f7f91STakashi Iwai int best_badness = INT_MAX;
1992352f7f91STakashi Iwai int badness;
1993352f7f91STakashi Iwai bool fill_hardwired = true, fill_mio_first = true;
1994352f7f91STakashi Iwai bool best_wired = true, best_mio = true;
1995352f7f91STakashi Iwai bool hp_spk_swapped = false;
1996352f7f91STakashi Iwai
1997352f7f91STakashi Iwai best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL);
1998352f7f91STakashi Iwai if (!best_cfg)
1999352f7f91STakashi Iwai return -ENOMEM;
2000352f7f91STakashi Iwai *best_cfg = *cfg;
2001352f7f91STakashi Iwai
2002352f7f91STakashi Iwai for (;;) {
2003352f7f91STakashi Iwai badness = fill_and_eval_dacs(codec, fill_hardwired,
2004352f7f91STakashi Iwai fill_mio_first);
2005352f7f91STakashi Iwai if (badness < 0) {
2006352f7f91STakashi Iwai kfree(best_cfg);
2007352f7f91STakashi Iwai return badness;
2008352f7f91STakashi Iwai }
2009352f7f91STakashi Iwai debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n",
2010352f7f91STakashi Iwai cfg->line_out_type, fill_hardwired, fill_mio_first,
2011352f7f91STakashi Iwai badness);
2012a769409cSTakashi Iwai debug_show_configs(codec, cfg);
2013352f7f91STakashi Iwai if (badness < best_badness) {
2014352f7f91STakashi Iwai best_badness = badness;
2015352f7f91STakashi Iwai *best_cfg = *cfg;
2016352f7f91STakashi Iwai best_wired = fill_hardwired;
2017352f7f91STakashi Iwai best_mio = fill_mio_first;
2018352f7f91STakashi Iwai }
2019352f7f91STakashi Iwai if (!badness)
2020352f7f91STakashi Iwai break;
2021352f7f91STakashi Iwai fill_mio_first = !fill_mio_first;
2022352f7f91STakashi Iwai if (!fill_mio_first)
2023352f7f91STakashi Iwai continue;
2024352f7f91STakashi Iwai fill_hardwired = !fill_hardwired;
2025352f7f91STakashi Iwai if (!fill_hardwired)
2026352f7f91STakashi Iwai continue;
2027352f7f91STakashi Iwai if (hp_spk_swapped)
2028352f7f91STakashi Iwai break;
2029352f7f91STakashi Iwai hp_spk_swapped = true;
2030352f7f91STakashi Iwai if (cfg->speaker_outs > 0 &&
2031352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) {
2032352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs;
2033352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins,
2034352f7f91STakashi Iwai sizeof(cfg->hp_pins));
2035352f7f91STakashi Iwai cfg->line_outs = cfg->speaker_outs;
2036352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->speaker_pins,
2037352f7f91STakashi Iwai sizeof(cfg->speaker_pins));
2038352f7f91STakashi Iwai cfg->speaker_outs = 0;
2039352f7f91STakashi Iwai memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
2040352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
2041352f7f91STakashi Iwai fill_hardwired = true;
2042352f7f91STakashi Iwai continue;
2043352f7f91STakashi Iwai }
2044352f7f91STakashi Iwai if (cfg->hp_outs > 0 &&
2045352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
2046352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs;
2047352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins,
2048352f7f91STakashi Iwai sizeof(cfg->speaker_pins));
2049352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs;
2050352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins,
2051352f7f91STakashi Iwai sizeof(cfg->hp_pins));
2052352f7f91STakashi Iwai cfg->hp_outs = 0;
2053352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
2054352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT;
2055352f7f91STakashi Iwai fill_hardwired = true;
2056352f7f91STakashi Iwai continue;
2057352f7f91STakashi Iwai }
2058352f7f91STakashi Iwai break;
2059352f7f91STakashi Iwai }
2060352f7f91STakashi Iwai
2061352f7f91STakashi Iwai if (badness) {
20620c8c0f56STakashi Iwai debug_badness("==> restoring best_cfg\n");
2063352f7f91STakashi Iwai *cfg = *best_cfg;
2064352f7f91STakashi Iwai fill_and_eval_dacs(codec, best_wired, best_mio);
2065352f7f91STakashi Iwai }
2066352f7f91STakashi Iwai debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n",
2067352f7f91STakashi Iwai cfg->line_out_type, best_wired, best_mio);
2068a769409cSTakashi Iwai debug_show_configs(codec, cfg);
2069352f7f91STakashi Iwai
2070352f7f91STakashi Iwai if (cfg->line_out_pins[0]) {
2071352f7f91STakashi Iwai struct nid_path *path;
2072196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]);
2073352f7f91STakashi Iwai if (path)
2074352f7f91STakashi Iwai spec->vmaster_nid = look_for_out_vol_nid(codec, path);
2075d89c6c0cSTakashi Iwai if (spec->vmaster_nid) {
20767a71bbf3STakashi Iwai snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
20777a71bbf3STakashi Iwai HDA_OUTPUT, spec->vmaster_tlv);
2078d89c6c0cSTakashi Iwai if (spec->dac_min_mute)
207951cdc8b6STakashi Sakamoto spec->vmaster_tlv[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] |= TLV_DB_SCALE_MUTE;
2080d89c6c0cSTakashi Iwai }
2081352f7f91STakashi Iwai }
2082352f7f91STakashi Iwai
20839314a581STakashi Iwai /* set initial pinctl targets */
20849314a581STakashi Iwai if (spec->prefer_hp_amp || cfg->line_out_type == AUTO_PIN_HP_OUT)
20859314a581STakashi Iwai val = PIN_HP;
20869314a581STakashi Iwai else
20879314a581STakashi Iwai val = PIN_OUT;
20889314a581STakashi Iwai set_pin_targets(codec, cfg->line_outs, cfg->line_out_pins, val);
20899314a581STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT)
20909314a581STakashi Iwai set_pin_targets(codec, cfg->hp_outs, cfg->hp_pins, PIN_HP);
20919314a581STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
20929314a581STakashi Iwai val = spec->prefer_hp_amp ? PIN_HP : PIN_OUT;
20939314a581STakashi Iwai set_pin_targets(codec, cfg->speaker_outs,
20949314a581STakashi Iwai cfg->speaker_pins, val);
20959314a581STakashi Iwai }
20969314a581STakashi Iwai
209755a63d4dSTakashi Iwai /* clear indep_hp flag if not available */
209855a63d4dSTakashi Iwai if (spec->indep_hp && !indep_hp_possible(codec))
209955a63d4dSTakashi Iwai spec->indep_hp = 0;
210055a63d4dSTakashi Iwai
2101352f7f91STakashi Iwai kfree(best_cfg);
2102352f7f91STakashi Iwai return 0;
2103352f7f91STakashi Iwai }
2104352f7f91STakashi Iwai
2105352f7f91STakashi Iwai /* add playback controls from the parsed DAC table */
create_multi_out_ctls(struct hda_codec * codec,const struct auto_pin_cfg * cfg)2106352f7f91STakashi Iwai static int create_multi_out_ctls(struct hda_codec *codec,
2107352f7f91STakashi Iwai const struct auto_pin_cfg *cfg)
2108352f7f91STakashi Iwai {
2109352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
2110352f7f91STakashi Iwai int i, err, noutputs;
2111352f7f91STakashi Iwai
2112352f7f91STakashi Iwai noutputs = cfg->line_outs;
2113352f7f91STakashi Iwai if (spec->multi_ios > 0 && cfg->line_outs < 3)
2114352f7f91STakashi Iwai noutputs += spec->multi_ios;
2115352f7f91STakashi Iwai
2116352f7f91STakashi Iwai for (i = 0; i < noutputs; i++) {
2117352f7f91STakashi Iwai const char *name;
2118352f7f91STakashi Iwai int index;
2119352f7f91STakashi Iwai struct nid_path *path;
2120352f7f91STakashi Iwai
2121196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]);
2122352f7f91STakashi Iwai if (!path)
2123352f7f91STakashi Iwai continue;
2124247d85eeSTakashi Iwai
2125247d85eeSTakashi Iwai name = get_line_out_pfx(codec, i, &index, NID_PATH_VOL_CTL);
2126352f7f91STakashi Iwai if (!name || !strcmp(name, "CLFE")) {
2127352f7f91STakashi Iwai /* Center/LFE */
2128352f7f91STakashi Iwai err = add_vol_ctl(codec, "Center", 0, 1, path);
2129352f7f91STakashi Iwai if (err < 0)
2130352f7f91STakashi Iwai return err;
2131352f7f91STakashi Iwai err = add_vol_ctl(codec, "LFE", 0, 2, path);
2132352f7f91STakashi Iwai if (err < 0)
2133352f7f91STakashi Iwai return err;
2134247d85eeSTakashi Iwai } else {
2135247d85eeSTakashi Iwai err = add_stereo_vol(codec, name, index, path);
2136247d85eeSTakashi Iwai if (err < 0)
2137247d85eeSTakashi Iwai return err;
2138247d85eeSTakashi Iwai }
2139247d85eeSTakashi Iwai
2140247d85eeSTakashi Iwai name = get_line_out_pfx(codec, i, &index, NID_PATH_MUTE_CTL);
2141247d85eeSTakashi Iwai if (!name || !strcmp(name, "CLFE")) {
2142352f7f91STakashi Iwai err = add_sw_ctl(codec, "Center", 0, 1, path);
2143352f7f91STakashi Iwai if (err < 0)
2144352f7f91STakashi Iwai return err;
2145352f7f91STakashi Iwai err = add_sw_ctl(codec, "LFE", 0, 2, path);
2146352f7f91STakashi Iwai if (err < 0)
2147352f7f91STakashi Iwai return err;
2148352f7f91STakashi Iwai } else {
2149352f7f91STakashi Iwai err = add_stereo_sw(codec, name, index, path);
2150352f7f91STakashi Iwai if (err < 0)
2151352f7f91STakashi Iwai return err;
2152352f7f91STakashi Iwai }
2153352f7f91STakashi Iwai }
2154352f7f91STakashi Iwai return 0;
2155352f7f91STakashi Iwai }
2156352f7f91STakashi Iwai
create_extra_out(struct hda_codec * codec,int path_idx,const char * pfx,int cidx)2157c2c80383STakashi Iwai static int create_extra_out(struct hda_codec *codec, int path_idx,
2158196c1766STakashi Iwai const char *pfx, int cidx)
2159352f7f91STakashi Iwai {
2160352f7f91STakashi Iwai struct nid_path *path;
2161352f7f91STakashi Iwai int err;
2162352f7f91STakashi Iwai
2163196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx);
2164352f7f91STakashi Iwai if (!path)
2165352f7f91STakashi Iwai return 0;
2166352f7f91STakashi Iwai err = add_stereo_vol(codec, pfx, cidx, path);
2167352f7f91STakashi Iwai if (err < 0)
2168352f7f91STakashi Iwai return err;
2169352f7f91STakashi Iwai err = add_stereo_sw(codec, pfx, cidx, path);
2170352f7f91STakashi Iwai if (err < 0)
2171352f7f91STakashi Iwai return err;
2172352f7f91STakashi Iwai return 0;
2173352f7f91STakashi Iwai }
2174352f7f91STakashi Iwai
2175352f7f91STakashi Iwai /* add playback controls for speaker and HP outputs */
create_extra_outs(struct hda_codec * codec,int num_pins,const int * paths,const char * pfx)2176352f7f91STakashi Iwai static int create_extra_outs(struct hda_codec *codec, int num_pins,
2177196c1766STakashi Iwai const int *paths, const char *pfx)
2178352f7f91STakashi Iwai {
2179c2c80383STakashi Iwai int i;
2180352f7f91STakashi Iwai
2181352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) {
2182c2c80383STakashi Iwai const char *name;
2183975cc02aSTakashi Iwai char tmp[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
2184c2c80383STakashi Iwai int err, idx = 0;
2185c2c80383STakashi Iwai
2186c2c80383STakashi Iwai if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker"))
2187c2c80383STakashi Iwai name = "Bass Speaker";
2188c2c80383STakashi Iwai else if (num_pins >= 3) {
2189c2c80383STakashi Iwai snprintf(tmp, sizeof(tmp), "%s %s",
2190352f7f91STakashi Iwai pfx, channel_name[i]);
2191c2c80383STakashi Iwai name = tmp;
2192352f7f91STakashi Iwai } else {
2193c2c80383STakashi Iwai name = pfx;
2194c2c80383STakashi Iwai idx = i;
2195352f7f91STakashi Iwai }
2196c2c80383STakashi Iwai err = create_extra_out(codec, paths[i], name, idx);
2197352f7f91STakashi Iwai if (err < 0)
2198352f7f91STakashi Iwai return err;
2199352f7f91STakashi Iwai }
2200352f7f91STakashi Iwai return 0;
2201352f7f91STakashi Iwai }
2202352f7f91STakashi Iwai
create_hp_out_ctls(struct hda_codec * codec)2203352f7f91STakashi Iwai static int create_hp_out_ctls(struct hda_codec *codec)
2204352f7f91STakashi Iwai {
2205352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
2206352f7f91STakashi Iwai return create_extra_outs(codec, spec->autocfg.hp_outs,
2207196c1766STakashi Iwai spec->hp_paths,
2208352f7f91STakashi Iwai "Headphone");
2209352f7f91STakashi Iwai }
2210352f7f91STakashi Iwai
create_speaker_out_ctls(struct hda_codec * codec)2211352f7f91STakashi Iwai static int create_speaker_out_ctls(struct hda_codec *codec)
2212352f7f91STakashi Iwai {
2213352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
2214352f7f91STakashi Iwai return create_extra_outs(codec, spec->autocfg.speaker_outs,
2215196c1766STakashi Iwai spec->speaker_paths,
2216352f7f91STakashi Iwai "Speaker");
2217352f7f91STakashi Iwai }
2218352f7f91STakashi Iwai
2219352f7f91STakashi Iwai /*
222038cf6f1aSTakashi Iwai * independent HP controls
222138cf6f1aSTakashi Iwai */
222238cf6f1aSTakashi Iwai
22231a4f69d5STakashi Iwai static void call_hp_automute(struct hda_codec *codec,
22241a4f69d5STakashi Iwai struct hda_jack_callback *jack);
indep_hp_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)222538cf6f1aSTakashi Iwai static int indep_hp_info(struct snd_kcontrol *kcontrol,
222638cf6f1aSTakashi Iwai struct snd_ctl_elem_info *uinfo)
222738cf6f1aSTakashi Iwai {
222838cf6f1aSTakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo);
222938cf6f1aSTakashi Iwai }
223038cf6f1aSTakashi Iwai
indep_hp_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)223138cf6f1aSTakashi Iwai static int indep_hp_get(struct snd_kcontrol *kcontrol,
223238cf6f1aSTakashi Iwai struct snd_ctl_elem_value *ucontrol)
223338cf6f1aSTakashi Iwai {
223438cf6f1aSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
223538cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
223638cf6f1aSTakashi Iwai ucontrol->value.enumerated.item[0] = spec->indep_hp_enabled;
223738cf6f1aSTakashi Iwai return 0;
223838cf6f1aSTakashi Iwai }
223938cf6f1aSTakashi Iwai
2240a1e908edSTakashi Iwai static void update_aamix_paths(struct hda_codec *codec, bool do_mix,
2241a1e908edSTakashi Iwai int nomix_path_idx, int mix_path_idx,
2242a1e908edSTakashi Iwai int out_type);
2243a1e908edSTakashi Iwai
indep_hp_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)224438cf6f1aSTakashi Iwai static int indep_hp_put(struct snd_kcontrol *kcontrol,
224538cf6f1aSTakashi Iwai struct snd_ctl_elem_value *ucontrol)
224638cf6f1aSTakashi Iwai {
224738cf6f1aSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
224838cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
224938cf6f1aSTakashi Iwai unsigned int select = ucontrol->value.enumerated.item[0];
225038cf6f1aSTakashi Iwai int ret = 0;
225138cf6f1aSTakashi Iwai
225238cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex);
225338cf6f1aSTakashi Iwai if (spec->active_streams) {
225438cf6f1aSTakashi Iwai ret = -EBUSY;
225538cf6f1aSTakashi Iwai goto unlock;
225638cf6f1aSTakashi Iwai }
225738cf6f1aSTakashi Iwai
225838cf6f1aSTakashi Iwai if (spec->indep_hp_enabled != select) {
2259a1e908edSTakashi Iwai hda_nid_t *dacp;
2260a1e908edSTakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
2261a1e908edSTakashi Iwai dacp = &spec->private_dac_nids[0];
2262a1e908edSTakashi Iwai else
2263a1e908edSTakashi Iwai dacp = &spec->multiout.hp_out_nid[0];
2264a1e908edSTakashi Iwai
2265a1e908edSTakashi Iwai /* update HP aamix paths in case it conflicts with indep HP */
2266a1e908edSTakashi Iwai if (spec->have_aamix_ctl) {
2267a1e908edSTakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
2268a1e908edSTakashi Iwai update_aamix_paths(codec, spec->aamix_mode,
2269a1e908edSTakashi Iwai spec->out_paths[0],
2270a1e908edSTakashi Iwai spec->aamix_out_paths[0],
2271a1e908edSTakashi Iwai spec->autocfg.line_out_type);
2272a1e908edSTakashi Iwai else
2273a1e908edSTakashi Iwai update_aamix_paths(codec, spec->aamix_mode,
2274a1e908edSTakashi Iwai spec->hp_paths[0],
2275a1e908edSTakashi Iwai spec->aamix_out_paths[1],
2276a1e908edSTakashi Iwai AUTO_PIN_HP_OUT);
2277a1e908edSTakashi Iwai }
2278a1e908edSTakashi Iwai
227938cf6f1aSTakashi Iwai spec->indep_hp_enabled = select;
228038cf6f1aSTakashi Iwai if (spec->indep_hp_enabled)
2281a1e908edSTakashi Iwai *dacp = 0;
228238cf6f1aSTakashi Iwai else
2283a1e908edSTakashi Iwai *dacp = spec->alt_dac_nid;
228492603c59STakashi Iwai
2285963afde9STakashi Iwai call_hp_automute(codec, NULL);
228638cf6f1aSTakashi Iwai ret = 1;
228738cf6f1aSTakashi Iwai }
228838cf6f1aSTakashi Iwai unlock:
228938cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex);
229038cf6f1aSTakashi Iwai return ret;
229138cf6f1aSTakashi Iwai }
229238cf6f1aSTakashi Iwai
229338cf6f1aSTakashi Iwai static const struct snd_kcontrol_new indep_hp_ctl = {
229438cf6f1aSTakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
229538cf6f1aSTakashi Iwai .name = "Independent HP",
229638cf6f1aSTakashi Iwai .info = indep_hp_info,
229738cf6f1aSTakashi Iwai .get = indep_hp_get,
229838cf6f1aSTakashi Iwai .put = indep_hp_put,
229938cf6f1aSTakashi Iwai };
230038cf6f1aSTakashi Iwai
230138cf6f1aSTakashi Iwai
create_indep_hp_ctls(struct hda_codec * codec)230238cf6f1aSTakashi Iwai static int create_indep_hp_ctls(struct hda_codec *codec)
230338cf6f1aSTakashi Iwai {
230438cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
2305a1e908edSTakashi Iwai hda_nid_t dac;
230638cf6f1aSTakashi Iwai
230738cf6f1aSTakashi Iwai if (!spec->indep_hp)
230838cf6f1aSTakashi Iwai return 0;
2309a1e908edSTakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
2310a1e908edSTakashi Iwai dac = spec->multiout.dac_nids[0];
2311a1e908edSTakashi Iwai else
2312a1e908edSTakashi Iwai dac = spec->multiout.hp_out_nid[0];
2313a1e908edSTakashi Iwai if (!dac) {
231438cf6f1aSTakashi Iwai spec->indep_hp = 0;
231538cf6f1aSTakashi Iwai return 0;
231638cf6f1aSTakashi Iwai }
231738cf6f1aSTakashi Iwai
231838cf6f1aSTakashi Iwai spec->indep_hp_enabled = false;
2319a1e908edSTakashi Iwai spec->alt_dac_nid = dac;
232038cf6f1aSTakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl))
232138cf6f1aSTakashi Iwai return -ENOMEM;
232238cf6f1aSTakashi Iwai return 0;
232338cf6f1aSTakashi Iwai }
232438cf6f1aSTakashi Iwai
232538cf6f1aSTakashi Iwai /*
2326352f7f91STakashi Iwai * channel mode enum control
2327352f7f91STakashi Iwai */
2328352f7f91STakashi Iwai
ch_mode_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2329352f7f91STakashi Iwai static int ch_mode_info(struct snd_kcontrol *kcontrol,
2330352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo)
2331352f7f91STakashi Iwai {
2332352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2333352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
2334a07a949bSTakashi Iwai int chs;
2335352f7f91STakashi Iwai
2336352f7f91STakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2337352f7f91STakashi Iwai uinfo->count = 1;
2338352f7f91STakashi Iwai uinfo->value.enumerated.items = spec->multi_ios + 1;
2339352f7f91STakashi Iwai if (uinfo->value.enumerated.item > spec->multi_ios)
2340352f7f91STakashi Iwai uinfo->value.enumerated.item = spec->multi_ios;
2341a07a949bSTakashi Iwai chs = uinfo->value.enumerated.item * 2 + spec->min_channel_count;
2342a07a949bSTakashi Iwai sprintf(uinfo->value.enumerated.name, "%dch", chs);
2343352f7f91STakashi Iwai return 0;
2344352f7f91STakashi Iwai }
2345352f7f91STakashi Iwai
ch_mode_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2346352f7f91STakashi Iwai static int ch_mode_get(struct snd_kcontrol *kcontrol,
2347352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol)
2348352f7f91STakashi Iwai {
2349352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2350352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
2351a07a949bSTakashi Iwai ucontrol->value.enumerated.item[0] =
2352a07a949bSTakashi Iwai (spec->ext_channel_count - spec->min_channel_count) / 2;
2353352f7f91STakashi Iwai return 0;
2354352f7f91STakashi Iwai }
2355352f7f91STakashi Iwai
2356196c1766STakashi Iwai static inline struct nid_path *
get_multiio_path(struct hda_codec * codec,int idx)2357196c1766STakashi Iwai get_multiio_path(struct hda_codec *codec, int idx)
2358196c1766STakashi Iwai {
2359196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec;
2360196c1766STakashi Iwai return snd_hda_get_path_from_idx(codec,
2361196c1766STakashi Iwai spec->out_paths[spec->autocfg.line_outs + idx]);
2362196c1766STakashi Iwai }
2363196c1766STakashi Iwai
2364a5cc2509STakashi Iwai static void update_automute_all(struct hda_codec *codec);
2365a5cc2509STakashi Iwai
236665033cc8STakashi Iwai /* Default value to be passed as aamix argument for snd_hda_activate_path();
236765033cc8STakashi Iwai * used for output paths
236865033cc8STakashi Iwai */
aamix_default(struct hda_gen_spec * spec)236965033cc8STakashi Iwai static bool aamix_default(struct hda_gen_spec *spec)
237065033cc8STakashi Iwai {
237165033cc8STakashi Iwai return !spec->have_aamix_ctl || spec->aamix_mode;
237265033cc8STakashi Iwai }
237365033cc8STakashi Iwai
set_multi_io(struct hda_codec * codec,int idx,bool output)2374352f7f91STakashi Iwai static int set_multi_io(struct hda_codec *codec, int idx, bool output)
2375352f7f91STakashi Iwai {
2376352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
2377352f7f91STakashi Iwai hda_nid_t nid = spec->multi_io[idx].pin;
2378352f7f91STakashi Iwai struct nid_path *path;
2379352f7f91STakashi Iwai
2380196c1766STakashi Iwai path = get_multiio_path(codec, idx);
2381352f7f91STakashi Iwai if (!path)
2382352f7f91STakashi Iwai return -EINVAL;
2383352f7f91STakashi Iwai
2384352f7f91STakashi Iwai if (path->active == output)
2385352f7f91STakashi Iwai return 0;
2386352f7f91STakashi Iwai
2387352f7f91STakashi Iwai if (output) {
23882c12c30dSTakashi Iwai set_pin_target(codec, nid, PIN_OUT, true);
238965033cc8STakashi Iwai snd_hda_activate_path(codec, path, true, aamix_default(spec));
2390d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, true);
2391352f7f91STakashi Iwai } else {
2392d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, false);
239365033cc8STakashi Iwai snd_hda_activate_path(codec, path, false, aamix_default(spec));
23942c12c30dSTakashi Iwai set_pin_target(codec, nid, spec->multi_io[idx].ctl_in, true);
239555196fffSTakashi Iwai path_power_down_sync(codec, path);
2396352f7f91STakashi Iwai }
2397a365fed9STakashi Iwai
2398a365fed9STakashi Iwai /* update jack retasking in case it modifies any of them */
2399a5cc2509STakashi Iwai update_automute_all(codec);
2400a365fed9STakashi Iwai
2401352f7f91STakashi Iwai return 0;
2402352f7f91STakashi Iwai }
2403352f7f91STakashi Iwai
ch_mode_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2404352f7f91STakashi Iwai static int ch_mode_put(struct snd_kcontrol *kcontrol,
2405352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol)
2406352f7f91STakashi Iwai {
2407352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2408352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
2409352f7f91STakashi Iwai int i, ch;
2410352f7f91STakashi Iwai
2411352f7f91STakashi Iwai ch = ucontrol->value.enumerated.item[0];
2412352f7f91STakashi Iwai if (ch < 0 || ch > spec->multi_ios)
2413352f7f91STakashi Iwai return -EINVAL;
2414a07a949bSTakashi Iwai if (ch == (spec->ext_channel_count - spec->min_channel_count) / 2)
2415352f7f91STakashi Iwai return 0;
2416a07a949bSTakashi Iwai spec->ext_channel_count = ch * 2 + spec->min_channel_count;
2417352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++)
2418352f7f91STakashi Iwai set_multi_io(codec, i, i < ch);
2419352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count,
2420352f7f91STakashi Iwai spec->const_channel_count);
2421352f7f91STakashi Iwai if (spec->need_dac_fix)
2422352f7f91STakashi Iwai spec->multiout.num_dacs = spec->multiout.max_channels / 2;
2423352f7f91STakashi Iwai return 1;
2424352f7f91STakashi Iwai }
2425352f7f91STakashi Iwai
2426352f7f91STakashi Iwai static const struct snd_kcontrol_new channel_mode_enum = {
2427352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2428352f7f91STakashi Iwai .name = "Channel Mode",
2429352f7f91STakashi Iwai .info = ch_mode_info,
2430352f7f91STakashi Iwai .get = ch_mode_get,
2431352f7f91STakashi Iwai .put = ch_mode_put,
2432352f7f91STakashi Iwai };
2433352f7f91STakashi Iwai
create_multi_channel_mode(struct hda_codec * codec)2434352f7f91STakashi Iwai static int create_multi_channel_mode(struct hda_codec *codec)
2435352f7f91STakashi Iwai {
2436352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
2437352f7f91STakashi Iwai
2438352f7f91STakashi Iwai if (spec->multi_ios > 0) {
243912c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &channel_mode_enum))
2440352f7f91STakashi Iwai return -ENOMEM;
2441352f7f91STakashi Iwai }
2442352f7f91STakashi Iwai return 0;
2443352f7f91STakashi Iwai }
2444352f7f91STakashi Iwai
2445352f7f91STakashi Iwai /*
2446c30aa7b2STakashi Iwai * aamix loopback enable/disable switch
2447c30aa7b2STakashi Iwai */
2448c30aa7b2STakashi Iwai
2449c30aa7b2STakashi Iwai #define loopback_mixing_info indep_hp_info
2450c30aa7b2STakashi Iwai
loopback_mixing_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2451c30aa7b2STakashi Iwai static int loopback_mixing_get(struct snd_kcontrol *kcontrol,
2452c30aa7b2STakashi Iwai struct snd_ctl_elem_value *ucontrol)
2453c30aa7b2STakashi Iwai {
2454c30aa7b2STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2455c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec;
2456c30aa7b2STakashi Iwai ucontrol->value.enumerated.item[0] = spec->aamix_mode;
2457c30aa7b2STakashi Iwai return 0;
2458c30aa7b2STakashi Iwai }
2459c30aa7b2STakashi Iwai
update_aamix_paths(struct hda_codec * codec,bool do_mix,int nomix_path_idx,int mix_path_idx,int out_type)2460c30aa7b2STakashi Iwai static void update_aamix_paths(struct hda_codec *codec, bool do_mix,
2461a1e908edSTakashi Iwai int nomix_path_idx, int mix_path_idx,
2462a1e908edSTakashi Iwai int out_type)
2463c30aa7b2STakashi Iwai {
2464a1e908edSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
2465c30aa7b2STakashi Iwai struct nid_path *nomix_path, *mix_path;
2466c30aa7b2STakashi Iwai
2467c30aa7b2STakashi Iwai nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx);
2468c30aa7b2STakashi Iwai mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx);
2469c30aa7b2STakashi Iwai if (!nomix_path || !mix_path)
2470c30aa7b2STakashi Iwai return;
2471a1e908edSTakashi Iwai
2472a1e908edSTakashi Iwai /* if HP aamix path is driven from a different DAC and the
2473a1e908edSTakashi Iwai * independent HP mode is ON, can't turn on aamix path
2474a1e908edSTakashi Iwai */
2475a1e908edSTakashi Iwai if (out_type == AUTO_PIN_HP_OUT && spec->indep_hp_enabled &&
2476a1e908edSTakashi Iwai mix_path->path[0] != spec->alt_dac_nid)
2477a1e908edSTakashi Iwai do_mix = false;
2478a1e908edSTakashi Iwai
2479c30aa7b2STakashi Iwai if (do_mix) {
2480c30aa7b2STakashi Iwai snd_hda_activate_path(codec, nomix_path, false, true);
2481c30aa7b2STakashi Iwai snd_hda_activate_path(codec, mix_path, true, true);
248255196fffSTakashi Iwai path_power_down_sync(codec, nomix_path);
2483c30aa7b2STakashi Iwai } else {
248465033cc8STakashi Iwai snd_hda_activate_path(codec, mix_path, false, false);
248565033cc8STakashi Iwai snd_hda_activate_path(codec, nomix_path, true, false);
248655196fffSTakashi Iwai path_power_down_sync(codec, mix_path);
2487c30aa7b2STakashi Iwai }
2488c30aa7b2STakashi Iwai }
2489c30aa7b2STakashi Iwai
2490e7fdd527STakashi Iwai /* re-initialize the output paths; only called from loopback_mixing_put() */
update_output_paths(struct hda_codec * codec,int num_outs,const int * paths)2491e7fdd527STakashi Iwai static void update_output_paths(struct hda_codec *codec, int num_outs,
2492e7fdd527STakashi Iwai const int *paths)
2493e7fdd527STakashi Iwai {
2494e7fdd527STakashi Iwai struct hda_gen_spec *spec = codec->spec;
2495e7fdd527STakashi Iwai struct nid_path *path;
2496e7fdd527STakashi Iwai int i;
2497e7fdd527STakashi Iwai
2498e7fdd527STakashi Iwai for (i = 0; i < num_outs; i++) {
2499e7fdd527STakashi Iwai path = snd_hda_get_path_from_idx(codec, paths[i]);
2500e7fdd527STakashi Iwai if (path)
2501e7fdd527STakashi Iwai snd_hda_activate_path(codec, path, path->active,
2502e7fdd527STakashi Iwai spec->aamix_mode);
2503e7fdd527STakashi Iwai }
2504e7fdd527STakashi Iwai }
2505e7fdd527STakashi Iwai
loopback_mixing_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2506c30aa7b2STakashi Iwai static int loopback_mixing_put(struct snd_kcontrol *kcontrol,
2507c30aa7b2STakashi Iwai struct snd_ctl_elem_value *ucontrol)
2508c30aa7b2STakashi Iwai {
2509c30aa7b2STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2510c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec;
2511e7fdd527STakashi Iwai const struct auto_pin_cfg *cfg = &spec->autocfg;
2512c30aa7b2STakashi Iwai unsigned int val = ucontrol->value.enumerated.item[0];
2513c30aa7b2STakashi Iwai
2514c30aa7b2STakashi Iwai if (val == spec->aamix_mode)
2515c30aa7b2STakashi Iwai return 0;
2516c30aa7b2STakashi Iwai spec->aamix_mode = val;
2517e7fdd527STakashi Iwai if (has_aamix_out_paths(spec)) {
2518c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->out_paths[0],
2519a1e908edSTakashi Iwai spec->aamix_out_paths[0],
2520e7fdd527STakashi Iwai cfg->line_out_type);
2521c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->hp_paths[0],
2522a1e908edSTakashi Iwai spec->aamix_out_paths[1],
2523a1e908edSTakashi Iwai AUTO_PIN_HP_OUT);
2524c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->speaker_paths[0],
2525a1e908edSTakashi Iwai spec->aamix_out_paths[2],
2526a1e908edSTakashi Iwai AUTO_PIN_SPEAKER_OUT);
2527e7fdd527STakashi Iwai } else {
2528e7fdd527STakashi Iwai update_output_paths(codec, cfg->line_outs, spec->out_paths);
2529e7fdd527STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT)
2530e7fdd527STakashi Iwai update_output_paths(codec, cfg->hp_outs, spec->hp_paths);
2531e7fdd527STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
2532e7fdd527STakashi Iwai update_output_paths(codec, cfg->speaker_outs,
2533e7fdd527STakashi Iwai spec->speaker_paths);
2534e7fdd527STakashi Iwai }
2535c30aa7b2STakashi Iwai return 1;
2536c30aa7b2STakashi Iwai }
2537c30aa7b2STakashi Iwai
2538c30aa7b2STakashi Iwai static const struct snd_kcontrol_new loopback_mixing_enum = {
2539c30aa7b2STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2540c30aa7b2STakashi Iwai .name = "Loopback Mixing",
2541c30aa7b2STakashi Iwai .info = loopback_mixing_info,
2542c30aa7b2STakashi Iwai .get = loopback_mixing_get,
2543c30aa7b2STakashi Iwai .put = loopback_mixing_put,
2544c30aa7b2STakashi Iwai };
2545c30aa7b2STakashi Iwai
create_loopback_mixing_ctl(struct hda_codec * codec)2546c30aa7b2STakashi Iwai static int create_loopback_mixing_ctl(struct hda_codec *codec)
2547c30aa7b2STakashi Iwai {
2548c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec;
2549c30aa7b2STakashi Iwai
2550c30aa7b2STakashi Iwai if (!spec->mixer_nid)
2551c30aa7b2STakashi Iwai return 0;
2552c30aa7b2STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum))
2553c30aa7b2STakashi Iwai return -ENOMEM;
2554a1e908edSTakashi Iwai spec->have_aamix_ctl = 1;
2555c30aa7b2STakashi Iwai return 0;
2556c30aa7b2STakashi Iwai }
2557c30aa7b2STakashi Iwai
2558c30aa7b2STakashi Iwai /*
2559352f7f91STakashi Iwai * shared headphone/mic handling
2560352f7f91STakashi Iwai */
2561352f7f91STakashi Iwai
2562352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec);
2563352f7f91STakashi Iwai
2564352f7f91STakashi Iwai /* for shared I/O, change the pin-control accordingly */
update_hp_mic(struct hda_codec * codec,int adc_mux,bool force)2565967303daSTakashi Iwai static void update_hp_mic(struct hda_codec *codec, int adc_mux, bool force)
2566352f7f91STakashi Iwai {
2567352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
2568967303daSTakashi Iwai bool as_mic;
2569352f7f91STakashi Iwai unsigned int val;
2570967303daSTakashi Iwai hda_nid_t pin;
2571967303daSTakashi Iwai
2572967303daSTakashi Iwai pin = spec->hp_mic_pin;
2573967303daSTakashi Iwai as_mic = spec->cur_mux[adc_mux] == spec->hp_mic_mux_idx;
2574967303daSTakashi Iwai
2575967303daSTakashi Iwai if (!force) {
2576967303daSTakashi Iwai val = snd_hda_codec_get_pin_target(codec, pin);
2577967303daSTakashi Iwai if (as_mic) {
2578967303daSTakashi Iwai if (val & PIN_IN)
2579967303daSTakashi Iwai return;
2580967303daSTakashi Iwai } else {
2581967303daSTakashi Iwai if (val & PIN_OUT)
2582967303daSTakashi Iwai return;
2583967303daSTakashi Iwai }
2584967303daSTakashi Iwai }
2585352f7f91STakashi Iwai
2586352f7f91STakashi Iwai val = snd_hda_get_default_vref(codec, pin);
2587967303daSTakashi Iwai /* if the HP pin doesn't support VREF and the codec driver gives an
2588967303daSTakashi Iwai * alternative pin, set up the VREF on that pin instead
2589967303daSTakashi Iwai */
2590352f7f91STakashi Iwai if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) {
2591352f7f91STakashi Iwai const hda_nid_t vref_pin = spec->shared_mic_vref_pin;
2592352f7f91STakashi Iwai unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin);
2593352f7f91STakashi Iwai if (vref_val != AC_PINCTL_VREF_HIZ)
25947594aa33STakashi Iwai snd_hda_set_pin_ctl_cache(codec, vref_pin,
2595967303daSTakashi Iwai PIN_IN | (as_mic ? vref_val : 0));
2596352f7f91STakashi Iwai }
2597352f7f91STakashi Iwai
25988ba955ceSTakashi Iwai if (!spec->hp_mic_jack_modes) {
2599967303daSTakashi Iwai if (as_mic)
2600967303daSTakashi Iwai val |= PIN_IN;
2601967303daSTakashi Iwai else
2602967303daSTakashi Iwai val = PIN_HP;
26032c12c30dSTakashi Iwai set_pin_target(codec, pin, val, true);
2604963afde9STakashi Iwai call_hp_automute(codec, NULL);
26058ba955ceSTakashi Iwai }
2606352f7f91STakashi Iwai }
2607352f7f91STakashi Iwai
2608352f7f91STakashi Iwai /* create a shared input with the headphone out */
create_hp_mic(struct hda_codec * codec)2609967303daSTakashi Iwai static int create_hp_mic(struct hda_codec *codec)
2610352f7f91STakashi Iwai {
2611352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
2612352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg;
2613352f7f91STakashi Iwai unsigned int defcfg;
2614352f7f91STakashi Iwai hda_nid_t nid;
2615352f7f91STakashi Iwai
2616967303daSTakashi Iwai if (!spec->hp_mic) {
2617967303daSTakashi Iwai if (spec->suppress_hp_mic_detect)
2618352f7f91STakashi Iwai return 0;
2619967303daSTakashi Iwai /* automatic detection: only if no input or a single internal
2620967303daSTakashi Iwai * input pin is found, try to detect the shared hp/mic
2621967303daSTakashi Iwai */
2622967303daSTakashi Iwai if (cfg->num_inputs > 1)
2623967303daSTakashi Iwai return 0;
2624967303daSTakashi Iwai else if (cfg->num_inputs == 1) {
2625352f7f91STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin);
2626352f7f91STakashi Iwai if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT)
2627352f7f91STakashi Iwai return 0;
2628967303daSTakashi Iwai }
2629967303daSTakashi Iwai }
2630352f7f91STakashi Iwai
2631967303daSTakashi Iwai spec->hp_mic = 0; /* clear once */
2632967303daSTakashi Iwai if (cfg->num_inputs >= AUTO_CFG_MAX_INS)
2633967303daSTakashi Iwai return 0;
2634967303daSTakashi Iwai
2635967303daSTakashi Iwai nid = 0;
2636967303daSTakashi Iwai if (cfg->line_out_type == AUTO_PIN_HP_OUT && cfg->line_outs > 0)
2637967303daSTakashi Iwai nid = cfg->line_out_pins[0];
2638967303daSTakashi Iwai else if (cfg->hp_outs > 0)
2639967303daSTakashi Iwai nid = cfg->hp_pins[0];
2640967303daSTakashi Iwai if (!nid)
2641967303daSTakashi Iwai return 0;
2642352f7f91STakashi Iwai
2643352f7f91STakashi Iwai if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN))
2644352f7f91STakashi Iwai return 0; /* no input */
2645352f7f91STakashi Iwai
2646967303daSTakashi Iwai cfg->inputs[cfg->num_inputs].pin = nid;
2647967303daSTakashi Iwai cfg->inputs[cfg->num_inputs].type = AUTO_PIN_MIC;
2648cb420b11SDavid Henningsson cfg->inputs[cfg->num_inputs].is_headphone_mic = 1;
2649967303daSTakashi Iwai cfg->num_inputs++;
2650967303daSTakashi Iwai spec->hp_mic = 1;
2651967303daSTakashi Iwai spec->hp_mic_pin = nid;
2652967303daSTakashi Iwai /* we can't handle auto-mic together with HP-mic */
2653967303daSTakashi Iwai spec->suppress_auto_mic = 1;
26544e76a883STakashi Iwai codec_dbg(codec, "Enable shared I/O jack on NID 0x%x\n", nid);
2655352f7f91STakashi Iwai return 0;
2656352f7f91STakashi Iwai }
2657352f7f91STakashi Iwai
2658978e77e7STakashi Iwai /*
2659978e77e7STakashi Iwai * output jack mode
2660978e77e7STakashi Iwai */
26615f171baaSTakashi Iwai
26625f171baaSTakashi Iwai static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin);
26635f171baaSTakashi Iwai
26645f171baaSTakashi Iwai static const char * const out_jack_texts[] = {
26655f171baaSTakashi Iwai "Line Out", "Headphone Out",
26665f171baaSTakashi Iwai };
26675f171baaSTakashi Iwai
out_jack_mode_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2668978e77e7STakashi Iwai static int out_jack_mode_info(struct snd_kcontrol *kcontrol,
2669978e77e7STakashi Iwai struct snd_ctl_elem_info *uinfo)
2670978e77e7STakashi Iwai {
26715f171baaSTakashi Iwai return snd_hda_enum_helper_info(kcontrol, uinfo, 2, out_jack_texts);
2672978e77e7STakashi Iwai }
2673978e77e7STakashi Iwai
out_jack_mode_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2674978e77e7STakashi Iwai static int out_jack_mode_get(struct snd_kcontrol *kcontrol,
2675978e77e7STakashi Iwai struct snd_ctl_elem_value *ucontrol)
2676978e77e7STakashi Iwai {
2677978e77e7STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2678978e77e7STakashi Iwai hda_nid_t nid = kcontrol->private_value;
2679978e77e7STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) == PIN_HP)
2680978e77e7STakashi Iwai ucontrol->value.enumerated.item[0] = 1;
2681978e77e7STakashi Iwai else
2682978e77e7STakashi Iwai ucontrol->value.enumerated.item[0] = 0;
2683978e77e7STakashi Iwai return 0;
2684978e77e7STakashi Iwai }
2685978e77e7STakashi Iwai
out_jack_mode_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2686978e77e7STakashi Iwai static int out_jack_mode_put(struct snd_kcontrol *kcontrol,
2687978e77e7STakashi Iwai struct snd_ctl_elem_value *ucontrol)
2688978e77e7STakashi Iwai {
2689978e77e7STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2690978e77e7STakashi Iwai hda_nid_t nid = kcontrol->private_value;
2691978e77e7STakashi Iwai unsigned int val;
2692978e77e7STakashi Iwai
2693978e77e7STakashi Iwai val = ucontrol->value.enumerated.item[0] ? PIN_HP : PIN_OUT;
2694978e77e7STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) == val)
2695978e77e7STakashi Iwai return 0;
2696978e77e7STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, val);
2697978e77e7STakashi Iwai return 1;
2698978e77e7STakashi Iwai }
2699978e77e7STakashi Iwai
2700978e77e7STakashi Iwai static const struct snd_kcontrol_new out_jack_mode_enum = {
2701978e77e7STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2702978e77e7STakashi Iwai .info = out_jack_mode_info,
2703978e77e7STakashi Iwai .get = out_jack_mode_get,
2704978e77e7STakashi Iwai .put = out_jack_mode_put,
2705978e77e7STakashi Iwai };
2706978e77e7STakashi Iwai
find_kctl_name(struct hda_codec * codec,const char * name,int idx)2707978e77e7STakashi Iwai static bool find_kctl_name(struct hda_codec *codec, const char *name, int idx)
2708978e77e7STakashi Iwai {
2709978e77e7STakashi Iwai struct hda_gen_spec *spec = codec->spec;
2710a9c2dfc8STakashi Iwai const struct snd_kcontrol_new *kctl;
2711978e77e7STakashi Iwai int i;
2712978e77e7STakashi Iwai
2713a9c2dfc8STakashi Iwai snd_array_for_each(&spec->kctls, i, kctl) {
2714978e77e7STakashi Iwai if (!strcmp(kctl->name, name) && kctl->index == idx)
2715978e77e7STakashi Iwai return true;
2716978e77e7STakashi Iwai }
2717978e77e7STakashi Iwai return false;
2718978e77e7STakashi Iwai }
2719978e77e7STakashi Iwai
get_jack_mode_name(struct hda_codec * codec,hda_nid_t pin,char * name,size_t name_len)2720978e77e7STakashi Iwai static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin,
2721978e77e7STakashi Iwai char *name, size_t name_len)
2722978e77e7STakashi Iwai {
2723978e77e7STakashi Iwai struct hda_gen_spec *spec = codec->spec;
2724978e77e7STakashi Iwai int idx = 0;
2725978e77e7STakashi Iwai
2726978e77e7STakashi Iwai snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len, &idx);
2727978e77e7STakashi Iwai strlcat(name, " Jack Mode", name_len);
2728978e77e7STakashi Iwai
2729978e77e7STakashi Iwai for (; find_kctl_name(codec, name, idx); idx++)
2730978e77e7STakashi Iwai ;
2731978e77e7STakashi Iwai }
2732978e77e7STakashi Iwai
get_out_jack_num_items(struct hda_codec * codec,hda_nid_t pin)27335f171baaSTakashi Iwai static int get_out_jack_num_items(struct hda_codec *codec, hda_nid_t pin)
27345f171baaSTakashi Iwai {
27355f171baaSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
2736f811c3cfSTakashi Iwai if (spec->add_jack_modes) {
27375f171baaSTakashi Iwai unsigned int pincap = snd_hda_query_pin_caps(codec, pin);
27385f171baaSTakashi Iwai if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV))
27395f171baaSTakashi Iwai return 2;
27405f171baaSTakashi Iwai }
27415f171baaSTakashi Iwai return 1;
27425f171baaSTakashi Iwai }
27435f171baaSTakashi Iwai
create_out_jack_modes(struct hda_codec * codec,int num_pins,hda_nid_t * pins)2744978e77e7STakashi Iwai static int create_out_jack_modes(struct hda_codec *codec, int num_pins,
2745978e77e7STakashi Iwai hda_nid_t *pins)
2746978e77e7STakashi Iwai {
2747978e77e7STakashi Iwai struct hda_gen_spec *spec = codec->spec;
2748978e77e7STakashi Iwai int i;
2749978e77e7STakashi Iwai
2750978e77e7STakashi Iwai for (i = 0; i < num_pins; i++) {
2751978e77e7STakashi Iwai hda_nid_t pin = pins[i];
2752ced4cefcSTakashi Iwai if (pin == spec->hp_mic_pin)
27535f171baaSTakashi Iwai continue;
27545f171baaSTakashi Iwai if (get_out_jack_num_items(codec, pin) > 1) {
2755978e77e7STakashi Iwai struct snd_kcontrol_new *knew;
2756975cc02aSTakashi Iwai char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
2757978e77e7STakashi Iwai get_jack_mode_name(codec, pin, name, sizeof(name));
2758978e77e7STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name,
2759978e77e7STakashi Iwai &out_jack_mode_enum);
2760978e77e7STakashi Iwai if (!knew)
2761978e77e7STakashi Iwai return -ENOMEM;
2762978e77e7STakashi Iwai knew->private_value = pin;
2763978e77e7STakashi Iwai }
2764978e77e7STakashi Iwai }
2765978e77e7STakashi Iwai
2766978e77e7STakashi Iwai return 0;
2767978e77e7STakashi Iwai }
2768978e77e7STakashi Iwai
276929476558STakashi Iwai /*
277029476558STakashi Iwai * input jack mode
277129476558STakashi Iwai */
277229476558STakashi Iwai
277329476558STakashi Iwai /* from AC_PINCTL_VREF_HIZ to AC_PINCTL_VREF_100 */
277429476558STakashi Iwai #define NUM_VREFS 6
277529476558STakashi Iwai
277629476558STakashi Iwai static const char * const vref_texts[NUM_VREFS] = {
277729476558STakashi Iwai "Line In", "Mic 50pc Bias", "Mic 0V Bias",
277829476558STakashi Iwai "", "Mic 80pc Bias", "Mic 100pc Bias"
277929476558STakashi Iwai };
278029476558STakashi Iwai
get_vref_caps(struct hda_codec * codec,hda_nid_t pin)278129476558STakashi Iwai static unsigned int get_vref_caps(struct hda_codec *codec, hda_nid_t pin)
278229476558STakashi Iwai {
278329476558STakashi Iwai unsigned int pincap;
278429476558STakashi Iwai
278529476558STakashi Iwai pincap = snd_hda_query_pin_caps(codec, pin);
278629476558STakashi Iwai pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
278729476558STakashi Iwai /* filter out unusual vrefs */
278829476558STakashi Iwai pincap &= ~(AC_PINCAP_VREF_GRD | AC_PINCAP_VREF_100);
278929476558STakashi Iwai return pincap;
279029476558STakashi Iwai }
279129476558STakashi Iwai
279229476558STakashi Iwai /* convert from the enum item index to the vref ctl index (0=HIZ, 1=50%...) */
get_vref_idx(unsigned int vref_caps,unsigned int item_idx)279329476558STakashi Iwai static int get_vref_idx(unsigned int vref_caps, unsigned int item_idx)
279429476558STakashi Iwai {
279529476558STakashi Iwai unsigned int i, n = 0;
279629476558STakashi Iwai
279729476558STakashi Iwai for (i = 0; i < NUM_VREFS; i++) {
279829476558STakashi Iwai if (vref_caps & (1 << i)) {
279929476558STakashi Iwai if (n == item_idx)
280029476558STakashi Iwai return i;
280129476558STakashi Iwai n++;
280229476558STakashi Iwai }
280329476558STakashi Iwai }
280429476558STakashi Iwai return 0;
280529476558STakashi Iwai }
280629476558STakashi Iwai
280729476558STakashi Iwai /* convert back from the vref ctl index to the enum item index */
cvt_from_vref_idx(unsigned int vref_caps,unsigned int idx)280829476558STakashi Iwai static int cvt_from_vref_idx(unsigned int vref_caps, unsigned int idx)
280929476558STakashi Iwai {
281029476558STakashi Iwai unsigned int i, n = 0;
281129476558STakashi Iwai
281229476558STakashi Iwai for (i = 0; i < NUM_VREFS; i++) {
281329476558STakashi Iwai if (i == idx)
281429476558STakashi Iwai return n;
281529476558STakashi Iwai if (vref_caps & (1 << i))
281629476558STakashi Iwai n++;
281729476558STakashi Iwai }
281829476558STakashi Iwai return 0;
281929476558STakashi Iwai }
282029476558STakashi Iwai
in_jack_mode_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)282129476558STakashi Iwai static int in_jack_mode_info(struct snd_kcontrol *kcontrol,
282229476558STakashi Iwai struct snd_ctl_elem_info *uinfo)
282329476558STakashi Iwai {
282429476558STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
282529476558STakashi Iwai hda_nid_t nid = kcontrol->private_value;
282629476558STakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid);
282729476558STakashi Iwai
282829476558STakashi Iwai snd_hda_enum_helper_info(kcontrol, uinfo, hweight32(vref_caps),
282929476558STakashi Iwai vref_texts);
283029476558STakashi Iwai /* set the right text */
283129476558STakashi Iwai strcpy(uinfo->value.enumerated.name,
283229476558STakashi Iwai vref_texts[get_vref_idx(vref_caps, uinfo->value.enumerated.item)]);
283329476558STakashi Iwai return 0;
283429476558STakashi Iwai }
283529476558STakashi Iwai
in_jack_mode_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)283629476558STakashi Iwai static int in_jack_mode_get(struct snd_kcontrol *kcontrol,
283729476558STakashi Iwai struct snd_ctl_elem_value *ucontrol)
283829476558STakashi Iwai {
283929476558STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
284029476558STakashi Iwai hda_nid_t nid = kcontrol->private_value;
284129476558STakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid);
284229476558STakashi Iwai unsigned int idx;
284329476558STakashi Iwai
284429476558STakashi Iwai idx = snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_VREFEN;
284529476558STakashi Iwai ucontrol->value.enumerated.item[0] = cvt_from_vref_idx(vref_caps, idx);
284629476558STakashi Iwai return 0;
284729476558STakashi Iwai }
284829476558STakashi Iwai
in_jack_mode_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)284929476558STakashi Iwai static int in_jack_mode_put(struct snd_kcontrol *kcontrol,
285029476558STakashi Iwai struct snd_ctl_elem_value *ucontrol)
285129476558STakashi Iwai {
285229476558STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
285329476558STakashi Iwai hda_nid_t nid = kcontrol->private_value;
285429476558STakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid);
285529476558STakashi Iwai unsigned int val, idx;
285629476558STakashi Iwai
285729476558STakashi Iwai val = snd_hda_codec_get_pin_target(codec, nid);
285829476558STakashi Iwai idx = cvt_from_vref_idx(vref_caps, val & AC_PINCTL_VREFEN);
285929476558STakashi Iwai if (idx == ucontrol->value.enumerated.item[0])
286029476558STakashi Iwai return 0;
286129476558STakashi Iwai
286229476558STakashi Iwai val &= ~AC_PINCTL_VREFEN;
286329476558STakashi Iwai val |= get_vref_idx(vref_caps, ucontrol->value.enumerated.item[0]);
286429476558STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, val);
286529476558STakashi Iwai return 1;
286629476558STakashi Iwai }
286729476558STakashi Iwai
286829476558STakashi Iwai static const struct snd_kcontrol_new in_jack_mode_enum = {
286929476558STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
287029476558STakashi Iwai .info = in_jack_mode_info,
287129476558STakashi Iwai .get = in_jack_mode_get,
287229476558STakashi Iwai .put = in_jack_mode_put,
287329476558STakashi Iwai };
287429476558STakashi Iwai
get_in_jack_num_items(struct hda_codec * codec,hda_nid_t pin)28755f171baaSTakashi Iwai static int get_in_jack_num_items(struct hda_codec *codec, hda_nid_t pin)
28765f171baaSTakashi Iwai {
28775f171baaSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
28785f171baaSTakashi Iwai int nitems = 0;
2879f811c3cfSTakashi Iwai if (spec->add_jack_modes)
28805f171baaSTakashi Iwai nitems = hweight32(get_vref_caps(codec, pin));
28815f171baaSTakashi Iwai return nitems ? nitems : 1;
28825f171baaSTakashi Iwai }
28835f171baaSTakashi Iwai
create_in_jack_mode(struct hda_codec * codec,hda_nid_t pin)288429476558STakashi Iwai static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin)
288529476558STakashi Iwai {
288629476558STakashi Iwai struct hda_gen_spec *spec = codec->spec;
288729476558STakashi Iwai struct snd_kcontrol_new *knew;
2888975cc02aSTakashi Iwai char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
28895f171baaSTakashi Iwai unsigned int defcfg;
28905f171baaSTakashi Iwai
2891f811c3cfSTakashi Iwai if (pin == spec->hp_mic_pin)
2892f811c3cfSTakashi Iwai return 0; /* already done in create_out_jack_mode() */
289329476558STakashi Iwai
289429476558STakashi Iwai /* no jack mode for fixed pins */
289529476558STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, pin);
289629476558STakashi Iwai if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT)
289729476558STakashi Iwai return 0;
289829476558STakashi Iwai
289929476558STakashi Iwai /* no multiple vref caps? */
29005f171baaSTakashi Iwai if (get_in_jack_num_items(codec, pin) <= 1)
290129476558STakashi Iwai return 0;
290229476558STakashi Iwai
290329476558STakashi Iwai get_jack_mode_name(codec, pin, name, sizeof(name));
290429476558STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &in_jack_mode_enum);
290529476558STakashi Iwai if (!knew)
290629476558STakashi Iwai return -ENOMEM;
290729476558STakashi Iwai knew->private_value = pin;
290829476558STakashi Iwai return 0;
290929476558STakashi Iwai }
291029476558STakashi Iwai
29115f171baaSTakashi Iwai /*
29125f171baaSTakashi Iwai * HP/mic shared jack mode
29135f171baaSTakashi Iwai */
hp_mic_jack_mode_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)29145f171baaSTakashi Iwai static int hp_mic_jack_mode_info(struct snd_kcontrol *kcontrol,
29155f171baaSTakashi Iwai struct snd_ctl_elem_info *uinfo)
29165f171baaSTakashi Iwai {
29175f171baaSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
29185f171baaSTakashi Iwai hda_nid_t nid = kcontrol->private_value;
29195f171baaSTakashi Iwai int out_jacks = get_out_jack_num_items(codec, nid);
29205f171baaSTakashi Iwai int in_jacks = get_in_jack_num_items(codec, nid);
29215f171baaSTakashi Iwai const char *text = NULL;
29225f171baaSTakashi Iwai int idx;
29235f171baaSTakashi Iwai
29245f171baaSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
29255f171baaSTakashi Iwai uinfo->count = 1;
29265f171baaSTakashi Iwai uinfo->value.enumerated.items = out_jacks + in_jacks;
29275f171baaSTakashi Iwai if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
29285f171baaSTakashi Iwai uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
29295f171baaSTakashi Iwai idx = uinfo->value.enumerated.item;
29305f171baaSTakashi Iwai if (idx < out_jacks) {
29315f171baaSTakashi Iwai if (out_jacks > 1)
29325f171baaSTakashi Iwai text = out_jack_texts[idx];
29335f171baaSTakashi Iwai else
29345f171baaSTakashi Iwai text = "Headphone Out";
29355f171baaSTakashi Iwai } else {
29365f171baaSTakashi Iwai idx -= out_jacks;
29375f171baaSTakashi Iwai if (in_jacks > 1) {
29385f171baaSTakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid);
29395f171baaSTakashi Iwai text = vref_texts[get_vref_idx(vref_caps, idx)];
29405f171baaSTakashi Iwai } else
29415f171baaSTakashi Iwai text = "Mic In";
29425f171baaSTakashi Iwai }
29435f171baaSTakashi Iwai
29445f171baaSTakashi Iwai strcpy(uinfo->value.enumerated.name, text);
29455f171baaSTakashi Iwai return 0;
29465f171baaSTakashi Iwai }
29475f171baaSTakashi Iwai
get_cur_hp_mic_jack_mode(struct hda_codec * codec,hda_nid_t nid)29485f171baaSTakashi Iwai static int get_cur_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t nid)
29495f171baaSTakashi Iwai {
29505f171baaSTakashi Iwai int out_jacks = get_out_jack_num_items(codec, nid);
29515f171baaSTakashi Iwai int in_jacks = get_in_jack_num_items(codec, nid);
29525f171baaSTakashi Iwai unsigned int val = snd_hda_codec_get_pin_target(codec, nid);
29535f171baaSTakashi Iwai int idx = 0;
29545f171baaSTakashi Iwai
29555f171baaSTakashi Iwai if (val & PIN_OUT) {
29565f171baaSTakashi Iwai if (out_jacks > 1 && val == PIN_HP)
29575f171baaSTakashi Iwai idx = 1;
29585f171baaSTakashi Iwai } else if (val & PIN_IN) {
29595f171baaSTakashi Iwai idx = out_jacks;
29605f171baaSTakashi Iwai if (in_jacks > 1) {
29615f171baaSTakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid);
29625f171baaSTakashi Iwai val &= AC_PINCTL_VREFEN;
29635f171baaSTakashi Iwai idx += cvt_from_vref_idx(vref_caps, val);
29645f171baaSTakashi Iwai }
29655f171baaSTakashi Iwai }
29665f171baaSTakashi Iwai return idx;
29675f171baaSTakashi Iwai }
29685f171baaSTakashi Iwai
hp_mic_jack_mode_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)29695f171baaSTakashi Iwai static int hp_mic_jack_mode_get(struct snd_kcontrol *kcontrol,
29705f171baaSTakashi Iwai struct snd_ctl_elem_value *ucontrol)
29715f171baaSTakashi Iwai {
29725f171baaSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
29735f171baaSTakashi Iwai hda_nid_t nid = kcontrol->private_value;
29745f171baaSTakashi Iwai ucontrol->value.enumerated.item[0] =
29755f171baaSTakashi Iwai get_cur_hp_mic_jack_mode(codec, nid);
29765f171baaSTakashi Iwai return 0;
29775f171baaSTakashi Iwai }
29785f171baaSTakashi Iwai
hp_mic_jack_mode_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)29795f171baaSTakashi Iwai static int hp_mic_jack_mode_put(struct snd_kcontrol *kcontrol,
29805f171baaSTakashi Iwai struct snd_ctl_elem_value *ucontrol)
29815f171baaSTakashi Iwai {
29825f171baaSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
29835f171baaSTakashi Iwai hda_nid_t nid = kcontrol->private_value;
29845f171baaSTakashi Iwai int out_jacks = get_out_jack_num_items(codec, nid);
29855f171baaSTakashi Iwai int in_jacks = get_in_jack_num_items(codec, nid);
29865f171baaSTakashi Iwai unsigned int val, oldval, idx;
29875f171baaSTakashi Iwai
29885f171baaSTakashi Iwai oldval = get_cur_hp_mic_jack_mode(codec, nid);
29895f171baaSTakashi Iwai idx = ucontrol->value.enumerated.item[0];
29905f171baaSTakashi Iwai if (oldval == idx)
29915f171baaSTakashi Iwai return 0;
29925f171baaSTakashi Iwai
29935f171baaSTakashi Iwai if (idx < out_jacks) {
29945f171baaSTakashi Iwai if (out_jacks > 1)
29955f171baaSTakashi Iwai val = idx ? PIN_HP : PIN_OUT;
29965f171baaSTakashi Iwai else
29975f171baaSTakashi Iwai val = PIN_HP;
29985f171baaSTakashi Iwai } else {
29995f171baaSTakashi Iwai idx -= out_jacks;
30005f171baaSTakashi Iwai if (in_jacks > 1) {
30015f171baaSTakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid);
30025f171baaSTakashi Iwai val = snd_hda_codec_get_pin_target(codec, nid);
30033f550e32STakashi Iwai val &= ~(AC_PINCTL_VREFEN | PIN_HP);
30043f550e32STakashi Iwai val |= get_vref_idx(vref_caps, idx) | PIN_IN;
30055f171baaSTakashi Iwai } else
300616c0cefeSTakashi Iwai val = snd_hda_get_default_vref(codec, nid) | PIN_IN;
30075f171baaSTakashi Iwai }
30085f171baaSTakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, val);
3009963afde9STakashi Iwai call_hp_automute(codec, NULL);
30108ba955ceSTakashi Iwai
30115f171baaSTakashi Iwai return 1;
30125f171baaSTakashi Iwai }
30135f171baaSTakashi Iwai
30145f171baaSTakashi Iwai static const struct snd_kcontrol_new hp_mic_jack_mode_enum = {
30155f171baaSTakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
30165f171baaSTakashi Iwai .info = hp_mic_jack_mode_info,
30175f171baaSTakashi Iwai .get = hp_mic_jack_mode_get,
30185f171baaSTakashi Iwai .put = hp_mic_jack_mode_put,
30195f171baaSTakashi Iwai };
30205f171baaSTakashi Iwai
create_hp_mic_jack_mode(struct hda_codec * codec,hda_nid_t pin)30215f171baaSTakashi Iwai static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin)
30225f171baaSTakashi Iwai {
30235f171baaSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
30245f171baaSTakashi Iwai struct snd_kcontrol_new *knew;
30255f171baaSTakashi Iwai
30265f171baaSTakashi Iwai knew = snd_hda_gen_add_kctl(spec, "Headphone Mic Jack Mode",
30275f171baaSTakashi Iwai &hp_mic_jack_mode_enum);
30285f171baaSTakashi Iwai if (!knew)
30295f171baaSTakashi Iwai return -ENOMEM;
30305f171baaSTakashi Iwai knew->private_value = pin;
30318ba955ceSTakashi Iwai spec->hp_mic_jack_modes = 1;
30325f171baaSTakashi Iwai return 0;
30335f171baaSTakashi Iwai }
3034352f7f91STakashi Iwai
3035352f7f91STakashi Iwai /*
3036352f7f91STakashi Iwai * Parse input paths
3037352f7f91STakashi Iwai */
3038352f7f91STakashi Iwai
3039352f7f91STakashi Iwai /* add the powersave loopback-list entry */
add_loopback_list(struct hda_gen_spec * spec,hda_nid_t mix,int idx)30400186f4f4STakashi Iwai static int add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx)
3041352f7f91STakashi Iwai {
3042352f7f91STakashi Iwai struct hda_amp_list *list;
3043352f7f91STakashi Iwai
30440186f4f4STakashi Iwai list = snd_array_new(&spec->loopback_list);
30450186f4f4STakashi Iwai if (!list)
30460186f4f4STakashi Iwai return -ENOMEM;
3047352f7f91STakashi Iwai list->nid = mix;
3048352f7f91STakashi Iwai list->dir = HDA_INPUT;
3049352f7f91STakashi Iwai list->idx = idx;
30500186f4f4STakashi Iwai spec->loopback.amplist = spec->loopback_list.list;
30510186f4f4STakashi Iwai return 0;
3052cb53c626STakashi Iwai }
3053cb53c626STakashi Iwai
30542ded3e5bSTakashi Iwai /* return true if either a volume or a mute amp is found for the given
30552ded3e5bSTakashi Iwai * aamix path; the amp has to be either in the mixer node or its direct leaf
30562ded3e5bSTakashi Iwai */
look_for_mix_leaf_ctls(struct hda_codec * codec,hda_nid_t mix_nid,hda_nid_t pin,unsigned int * mix_val,unsigned int * mute_val)30572ded3e5bSTakashi Iwai static bool look_for_mix_leaf_ctls(struct hda_codec *codec, hda_nid_t mix_nid,
30582ded3e5bSTakashi Iwai hda_nid_t pin, unsigned int *mix_val,
30592ded3e5bSTakashi Iwai unsigned int *mute_val)
30602ded3e5bSTakashi Iwai {
30612ded3e5bSTakashi Iwai int idx, num_conns;
30622ded3e5bSTakashi Iwai const hda_nid_t *list;
30632ded3e5bSTakashi Iwai hda_nid_t nid;
30642ded3e5bSTakashi Iwai
30652ded3e5bSTakashi Iwai idx = snd_hda_get_conn_index(codec, mix_nid, pin, true);
30662ded3e5bSTakashi Iwai if (idx < 0)
30672ded3e5bSTakashi Iwai return false;
30682ded3e5bSTakashi Iwai
30692ded3e5bSTakashi Iwai *mix_val = *mute_val = 0;
30702ded3e5bSTakashi Iwai if (nid_has_volume(codec, mix_nid, HDA_INPUT))
30712ded3e5bSTakashi Iwai *mix_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
30722ded3e5bSTakashi Iwai if (nid_has_mute(codec, mix_nid, HDA_INPUT))
30732ded3e5bSTakashi Iwai *mute_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
30742ded3e5bSTakashi Iwai if (*mix_val && *mute_val)
30752ded3e5bSTakashi Iwai return true;
30762ded3e5bSTakashi Iwai
30772ded3e5bSTakashi Iwai /* check leaf node */
30782ded3e5bSTakashi Iwai num_conns = snd_hda_get_conn_list(codec, mix_nid, &list);
30792ded3e5bSTakashi Iwai if (num_conns < idx)
30802ded3e5bSTakashi Iwai return false;
30812ded3e5bSTakashi Iwai nid = list[idx];
308243a8e50aSTakashi Iwai if (!*mix_val && nid_has_volume(codec, nid, HDA_OUTPUT) &&
308343a8e50aSTakashi Iwai !is_ctl_associated(codec, nid, HDA_OUTPUT, 0, NID_PATH_VOL_CTL))
30842ded3e5bSTakashi Iwai *mix_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
308543a8e50aSTakashi Iwai if (!*mute_val && nid_has_mute(codec, nid, HDA_OUTPUT) &&
308643a8e50aSTakashi Iwai !is_ctl_associated(codec, nid, HDA_OUTPUT, 0, NID_PATH_MUTE_CTL))
30872ded3e5bSTakashi Iwai *mute_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
30882ded3e5bSTakashi Iwai
30892ded3e5bSTakashi Iwai return *mix_val || *mute_val;
30902ded3e5bSTakashi Iwai }
30912ded3e5bSTakashi Iwai
3092352f7f91STakashi Iwai /* create input playback/capture controls for the given pin */
new_analog_input(struct hda_codec * codec,int input_idx,hda_nid_t pin,const char * ctlname,int ctlidx,hda_nid_t mix_nid)3093196c1766STakashi Iwai static int new_analog_input(struct hda_codec *codec, int input_idx,
3094196c1766STakashi Iwai hda_nid_t pin, const char *ctlname, int ctlidx,
3095352f7f91STakashi Iwai hda_nid_t mix_nid)
30961da177e4SLinus Torvalds {
3097352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
3098352f7f91STakashi Iwai struct nid_path *path;
30992ded3e5bSTakashi Iwai unsigned int mix_val, mute_val;
3100352f7f91STakashi Iwai int err, idx;
31011da177e4SLinus Torvalds
31022ded3e5bSTakashi Iwai if (!look_for_mix_leaf_ctls(codec, mix_nid, pin, &mix_val, &mute_val))
31032ded3e5bSTakashi Iwai return 0;
3104352f7f91STakashi Iwai
31053ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, pin, mix_nid, 0);
3106352f7f91STakashi Iwai if (!path)
3107352f7f91STakashi Iwai return -EINVAL;
31084e76a883STakashi Iwai print_nid_path(codec, "loopback", path);
3109196c1766STakashi Iwai spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path);
3110352f7f91STakashi Iwai
3111352f7f91STakashi Iwai idx = path->idx[path->depth - 1];
31122ded3e5bSTakashi Iwai if (mix_val) {
31132ded3e5bSTakashi Iwai err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, mix_val);
3114d13bd412STakashi Iwai if (err < 0)
31151da177e4SLinus Torvalds return err;
31162ded3e5bSTakashi Iwai path->ctls[NID_PATH_VOL_CTL] = mix_val;
31171da177e4SLinus Torvalds }
31181da177e4SLinus Torvalds
31192ded3e5bSTakashi Iwai if (mute_val) {
31202ded3e5bSTakashi Iwai err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, mute_val);
3121d13bd412STakashi Iwai if (err < 0)
31221da177e4SLinus Torvalds return err;
31232ded3e5bSTakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = mute_val;
31241da177e4SLinus Torvalds }
31251da177e4SLinus Torvalds
3126352f7f91STakashi Iwai path->active = true;
3127e6feb5d0STakashi Iwai path->stream_enabled = true; /* no DAC/ADC involved */
31280186f4f4STakashi Iwai err = add_loopback_list(spec, mix_nid, idx);
31290186f4f4STakashi Iwai if (err < 0)
31300186f4f4STakashi Iwai return err;
3131e4a395e7STakashi Iwai
3132e4a395e7STakashi Iwai if (spec->mixer_nid != spec->mixer_merge_nid &&
3133e4a395e7STakashi Iwai !spec->loopback_merge_path) {
3134e4a395e7STakashi Iwai path = snd_hda_add_new_path(codec, spec->mixer_nid,
3135e4a395e7STakashi Iwai spec->mixer_merge_nid, 0);
3136e4a395e7STakashi Iwai if (path) {
31374e76a883STakashi Iwai print_nid_path(codec, "loopback-merge", path);
3138e4a395e7STakashi Iwai path->active = true;
31396b275b14STakashi Iwai path->pin_fixed = true; /* static route */
3140e6feb5d0STakashi Iwai path->stream_enabled = true; /* no DAC/ADC involved */
3141e4a395e7STakashi Iwai spec->loopback_merge_path =
3142e4a395e7STakashi Iwai snd_hda_get_path_idx(codec, path);
3143e4a395e7STakashi Iwai }
3144e4a395e7STakashi Iwai }
3145e4a395e7STakashi Iwai
3146352f7f91STakashi Iwai return 0;
31471da177e4SLinus Torvalds }
31481da177e4SLinus Torvalds
is_input_pin(struct hda_codec * codec,hda_nid_t nid)3149352f7f91STakashi Iwai static int is_input_pin(struct hda_codec *codec, hda_nid_t nid)
31501da177e4SLinus Torvalds {
3151352f7f91STakashi Iwai unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
3152352f7f91STakashi Iwai return (pincap & AC_PINCAP_IN) != 0;
3153352f7f91STakashi Iwai }
3154352f7f91STakashi Iwai
3155352f7f91STakashi Iwai /* Parse the codec tree and retrieve ADCs */
fill_adc_nids(struct hda_codec * codec)3156352f7f91STakashi Iwai static int fill_adc_nids(struct hda_codec *codec)
3157352f7f91STakashi Iwai {
3158352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
3159352f7f91STakashi Iwai hda_nid_t nid;
3160352f7f91STakashi Iwai hda_nid_t *adc_nids = spec->adc_nids;
3161352f7f91STakashi Iwai int max_nums = ARRAY_SIZE(spec->adc_nids);
31627639a06cSTakashi Iwai int nums = 0;
3163352f7f91STakashi Iwai
31647639a06cSTakashi Iwai for_each_hda_codec_node(nid, codec) {
3165352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid);
3166352f7f91STakashi Iwai int type = get_wcaps_type(caps);
3167352f7f91STakashi Iwai
3168352f7f91STakashi Iwai if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL))
3169352f7f91STakashi Iwai continue;
3170352f7f91STakashi Iwai adc_nids[nums] = nid;
3171352f7f91STakashi Iwai if (++nums >= max_nums)
3172352f7f91STakashi Iwai break;
3173352f7f91STakashi Iwai }
3174352f7f91STakashi Iwai spec->num_adc_nids = nums;
31750ffd534eSTakashi Iwai
31760ffd534eSTakashi Iwai /* copy the detected ADCs to all_adcs[] */
31770ffd534eSTakashi Iwai spec->num_all_adcs = nums;
31780ffd534eSTakashi Iwai memcpy(spec->all_adcs, spec->adc_nids, nums * sizeof(hda_nid_t));
31790ffd534eSTakashi Iwai
3180352f7f91STakashi Iwai return nums;
3181352f7f91STakashi Iwai }
3182352f7f91STakashi Iwai
3183352f7f91STakashi Iwai /* filter out invalid adc_nids that don't give all active input pins;
3184352f7f91STakashi Iwai * if needed, check whether dynamic ADC-switching is available
3185352f7f91STakashi Iwai */
check_dyn_adc_switch(struct hda_codec * codec)3186352f7f91STakashi Iwai static int check_dyn_adc_switch(struct hda_codec *codec)
3187352f7f91STakashi Iwai {
3188352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
3189352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux;
31903a65bcdcSTakashi Iwai unsigned int ok_bits;
3191352f7f91STakashi Iwai int i, n, nums;
3192352f7f91STakashi Iwai
3193352f7f91STakashi Iwai nums = 0;
31943a65bcdcSTakashi Iwai ok_bits = 0;
3195352f7f91STakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) {
3196352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) {
31973a65bcdcSTakashi Iwai if (!spec->input_paths[i][n])
3198352f7f91STakashi Iwai break;
3199352f7f91STakashi Iwai }
32003a65bcdcSTakashi Iwai if (i >= imux->num_items) {
32013a65bcdcSTakashi Iwai ok_bits |= (1 << n);
32023a65bcdcSTakashi Iwai nums++;
32033a65bcdcSTakashi Iwai }
3204352f7f91STakashi Iwai }
3205352f7f91STakashi Iwai
32063a65bcdcSTakashi Iwai if (!ok_bits) {
3207352f7f91STakashi Iwai /* check whether ADC-switch is possible */
3208352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) {
3209352f7f91STakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) {
32103a65bcdcSTakashi Iwai if (spec->input_paths[i][n]) {
3211352f7f91STakashi Iwai spec->dyn_adc_idx[i] = n;
3212352f7f91STakashi Iwai break;
3213352f7f91STakashi Iwai }
3214352f7f91STakashi Iwai }
3215352f7f91STakashi Iwai }
3216352f7f91STakashi Iwai
32174e76a883STakashi Iwai codec_dbg(codec, "enabling ADC switching\n");
3218352f7f91STakashi Iwai spec->dyn_adc_switch = 1;
3219352f7f91STakashi Iwai } else if (nums != spec->num_adc_nids) {
32203a65bcdcSTakashi Iwai /* shrink the invalid adcs and input paths */
32213a65bcdcSTakashi Iwai nums = 0;
32223a65bcdcSTakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) {
32233a65bcdcSTakashi Iwai if (!(ok_bits & (1 << n)))
32243a65bcdcSTakashi Iwai continue;
32253a65bcdcSTakashi Iwai if (n != nums) {
32263a65bcdcSTakashi Iwai spec->adc_nids[nums] = spec->adc_nids[n];
3227980428ceSTakashi Iwai for (i = 0; i < imux->num_items; i++) {
3228980428ceSTakashi Iwai invalidate_nid_path(codec,
3229980428ceSTakashi Iwai spec->input_paths[i][nums]);
32303a65bcdcSTakashi Iwai spec->input_paths[i][nums] =
32313a65bcdcSTakashi Iwai spec->input_paths[i][n];
3232a8f20fd2SHui Wang spec->input_paths[i][n] = 0;
32333a65bcdcSTakashi Iwai }
3234980428ceSTakashi Iwai }
32353a65bcdcSTakashi Iwai nums++;
32363a65bcdcSTakashi Iwai }
3237352f7f91STakashi Iwai spec->num_adc_nids = nums;
3238352f7f91STakashi Iwai }
3239352f7f91STakashi Iwai
3240967303daSTakashi Iwai if (imux->num_items == 1 ||
3241967303daSTakashi Iwai (imux->num_items == 2 && spec->hp_mic)) {
32424e76a883STakashi Iwai codec_dbg(codec, "reducing to a single ADC\n");
3243352f7f91STakashi Iwai spec->num_adc_nids = 1; /* reduce to a single ADC */
3244352f7f91STakashi Iwai }
3245352f7f91STakashi Iwai
3246352f7f91STakashi Iwai /* single index for individual volumes ctls */
3247352f7f91STakashi Iwai if (!spec->dyn_adc_switch && spec->multi_cap_vol)
3248352f7f91STakashi Iwai spec->num_adc_nids = 1;
3249352f7f91STakashi Iwai
32501da177e4SLinus Torvalds return 0;
32511da177e4SLinus Torvalds }
32521da177e4SLinus Torvalds
3253f3fc0b0bSTakashi Iwai /* parse capture source paths from the given pin and create imux items */
parse_capture_source(struct hda_codec * codec,hda_nid_t pin,int cfg_idx,int num_adcs,const char * label,int anchor)3254f3fc0b0bSTakashi Iwai static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin,
32559dba205bSTakashi Iwai int cfg_idx, int num_adcs,
32569dba205bSTakashi Iwai const char *label, int anchor)
3257f3fc0b0bSTakashi Iwai {
3258f3fc0b0bSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
3259f3fc0b0bSTakashi Iwai struct hda_input_mux *imux = &spec->input_mux;
3260f3fc0b0bSTakashi Iwai int imux_idx = imux->num_items;
3261f3fc0b0bSTakashi Iwai bool imux_added = false;
3262f3fc0b0bSTakashi Iwai int c;
3263f3fc0b0bSTakashi Iwai
3264f3fc0b0bSTakashi Iwai for (c = 0; c < num_adcs; c++) {
3265f3fc0b0bSTakashi Iwai struct nid_path *path;
3266f3fc0b0bSTakashi Iwai hda_nid_t adc = spec->adc_nids[c];
3267f3fc0b0bSTakashi Iwai
3268f3fc0b0bSTakashi Iwai if (!is_reachable_path(codec, pin, adc))
3269f3fc0b0bSTakashi Iwai continue;
3270f3fc0b0bSTakashi Iwai path = snd_hda_add_new_path(codec, pin, adc, anchor);
3271f3fc0b0bSTakashi Iwai if (!path)
3272f3fc0b0bSTakashi Iwai continue;
32734e76a883STakashi Iwai print_nid_path(codec, "input", path);
3274f3fc0b0bSTakashi Iwai spec->input_paths[imux_idx][c] =
3275f3fc0b0bSTakashi Iwai snd_hda_get_path_idx(codec, path);
3276f3fc0b0bSTakashi Iwai
3277f3fc0b0bSTakashi Iwai if (!imux_added) {
3278967303daSTakashi Iwai if (spec->hp_mic_pin == pin)
3279967303daSTakashi Iwai spec->hp_mic_mux_idx = imux->num_items;
3280f3fc0b0bSTakashi Iwai spec->imux_pins[imux->num_items] = pin;
32816194b99dSTakashi Iwai snd_hda_add_imux_item(codec, imux, label, cfg_idx, NULL);
3282f3fc0b0bSTakashi Iwai imux_added = true;
3283f1e762ddSTakashi Iwai if (spec->dyn_adc_switch)
3284f1e762ddSTakashi Iwai spec->dyn_adc_idx[imux_idx] = c;
3285f3fc0b0bSTakashi Iwai }
3286f3fc0b0bSTakashi Iwai }
3287f3fc0b0bSTakashi Iwai
3288f3fc0b0bSTakashi Iwai return 0;
3289f3fc0b0bSTakashi Iwai }
3290f3fc0b0bSTakashi Iwai
32911da177e4SLinus Torvalds /*
3292352f7f91STakashi Iwai * create playback/capture controls for input pins
32931da177e4SLinus Torvalds */
32949dba205bSTakashi Iwai
3295c970042cSTakashi Iwai /* fill the label for each input at first */
fill_input_pin_labels(struct hda_codec * codec)3296c970042cSTakashi Iwai static int fill_input_pin_labels(struct hda_codec *codec)
3297c970042cSTakashi Iwai {
3298c970042cSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
3299c970042cSTakashi Iwai const struct auto_pin_cfg *cfg = &spec->autocfg;
3300c970042cSTakashi Iwai int i;
3301c970042cSTakashi Iwai
3302c970042cSTakashi Iwai for (i = 0; i < cfg->num_inputs; i++) {
3303c970042cSTakashi Iwai hda_nid_t pin = cfg->inputs[i].pin;
3304c970042cSTakashi Iwai const char *label;
3305c970042cSTakashi Iwai int j, idx;
3306c970042cSTakashi Iwai
3307c970042cSTakashi Iwai if (!is_input_pin(codec, pin))
3308c970042cSTakashi Iwai continue;
3309c970042cSTakashi Iwai
3310c970042cSTakashi Iwai label = hda_get_autocfg_input_label(codec, cfg, i);
3311c970042cSTakashi Iwai idx = 0;
33128e8db7f1SDavid Henningsson for (j = i - 1; j >= 0; j--) {
3313c970042cSTakashi Iwai if (spec->input_labels[j] &&
3314c970042cSTakashi Iwai !strcmp(spec->input_labels[j], label)) {
3315c970042cSTakashi Iwai idx = spec->input_label_idxs[j] + 1;
3316c970042cSTakashi Iwai break;
3317c970042cSTakashi Iwai }
3318c970042cSTakashi Iwai }
3319c970042cSTakashi Iwai
3320c970042cSTakashi Iwai spec->input_labels[i] = label;
3321c970042cSTakashi Iwai spec->input_label_idxs[i] = idx;
3322c970042cSTakashi Iwai }
3323c970042cSTakashi Iwai
3324c970042cSTakashi Iwai return 0;
3325c970042cSTakashi Iwai }
3326c970042cSTakashi Iwai
33279dba205bSTakashi Iwai #define CFG_IDX_MIX 99 /* a dummy cfg->input idx for stereo mix */
33289dba205bSTakashi Iwai
create_input_ctls(struct hda_codec * codec)3329352f7f91STakashi Iwai static int create_input_ctls(struct hda_codec *codec)
3330a7da6ce5STakashi Iwai {
3331352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
3332352f7f91STakashi Iwai const struct auto_pin_cfg *cfg = &spec->autocfg;
3333352f7f91STakashi Iwai hda_nid_t mixer = spec->mixer_nid;
3334352f7f91STakashi Iwai int num_adcs;
3335c970042cSTakashi Iwai int i, err;
33362c12c30dSTakashi Iwai unsigned int val;
3337a7da6ce5STakashi Iwai
3338352f7f91STakashi Iwai num_adcs = fill_adc_nids(codec);
3339352f7f91STakashi Iwai if (num_adcs < 0)
3340352f7f91STakashi Iwai return 0;
3341352f7f91STakashi Iwai
3342c970042cSTakashi Iwai err = fill_input_pin_labels(codec);
3343c970042cSTakashi Iwai if (err < 0)
3344c970042cSTakashi Iwai return err;
3345c970042cSTakashi Iwai
3346352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) {
3347352f7f91STakashi Iwai hda_nid_t pin;
3348352f7f91STakashi Iwai
3349352f7f91STakashi Iwai pin = cfg->inputs[i].pin;
3350352f7f91STakashi Iwai if (!is_input_pin(codec, pin))
3351352f7f91STakashi Iwai continue;
3352352f7f91STakashi Iwai
33532c12c30dSTakashi Iwai val = PIN_IN;
33542c12c30dSTakashi Iwai if (cfg->inputs[i].type == AUTO_PIN_MIC)
33552c12c30dSTakashi Iwai val |= snd_hda_get_default_vref(codec, pin);
33563e1b0c4aSTakashi Iwai if (pin != spec->hp_mic_pin &&
33573e1b0c4aSTakashi Iwai !snd_hda_codec_get_pin_target(codec, pin))
33582c12c30dSTakashi Iwai set_pin_target(codec, pin, val, false);
33592c12c30dSTakashi Iwai
3360352f7f91STakashi Iwai if (mixer) {
3361352f7f91STakashi Iwai if (is_reachable_path(codec, pin, mixer)) {
3362196c1766STakashi Iwai err = new_analog_input(codec, i, pin,
3363c970042cSTakashi Iwai spec->input_labels[i],
3364c970042cSTakashi Iwai spec->input_label_idxs[i],
3365c970042cSTakashi Iwai mixer);
3366a7da6ce5STakashi Iwai if (err < 0)
3367a7da6ce5STakashi Iwai return err;
3368a7da6ce5STakashi Iwai }
3369352f7f91STakashi Iwai }
3370352f7f91STakashi Iwai
3371c970042cSTakashi Iwai err = parse_capture_source(codec, pin, i, num_adcs,
3372c970042cSTakashi Iwai spec->input_labels[i], -mixer);
3373f3fc0b0bSTakashi Iwai if (err < 0)
3374f3fc0b0bSTakashi Iwai return err;
337529476558STakashi Iwai
3376f811c3cfSTakashi Iwai if (spec->add_jack_modes) {
337729476558STakashi Iwai err = create_in_jack_mode(codec, pin);
337829476558STakashi Iwai if (err < 0)
337929476558STakashi Iwai return err;
338029476558STakashi Iwai }
3381352f7f91STakashi Iwai }
3382f3fc0b0bSTakashi Iwai
3383f1e762ddSTakashi Iwai /* add stereo mix when explicitly enabled via hint */
338474f14b36STakashi Iwai if (mixer && spec->add_stereo_mix_input == HDA_HINT_STEREO_MIX_ENABLE) {
33859dba205bSTakashi Iwai err = parse_capture_source(codec, mixer, CFG_IDX_MIX, num_adcs,
3386f3fc0b0bSTakashi Iwai "Stereo Mix", 0);
3387f3fc0b0bSTakashi Iwai if (err < 0)
3388f3fc0b0bSTakashi Iwai return err;
338982d04e10STakashi Iwai else
339082d04e10STakashi Iwai spec->suppress_auto_mic = 1;
3391352f7f91STakashi Iwai }
3392352f7f91STakashi Iwai
3393a7da6ce5STakashi Iwai return 0;
3394a7da6ce5STakashi Iwai }
3395a7da6ce5STakashi Iwai
33961da177e4SLinus Torvalds
3397352f7f91STakashi Iwai /*
3398352f7f91STakashi Iwai * input source mux
3399352f7f91STakashi Iwai */
3400352f7f91STakashi Iwai
3401c697b716STakashi Iwai /* get the input path specified by the given adc and imux indices */
get_input_path(struct hda_codec * codec,int adc_idx,int imux_idx)3402c697b716STakashi Iwai static struct nid_path *get_input_path(struct hda_codec *codec, int adc_idx, int imux_idx)
3403352f7f91STakashi Iwai {
3404352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
3405b56fa1edSDavid Henningsson if (imux_idx < 0 || imux_idx >= HDA_MAX_NUM_INPUTS) {
3406b56fa1edSDavid Henningsson snd_BUG();
3407b56fa1edSDavid Henningsson return NULL;
3408b56fa1edSDavid Henningsson }
3409352f7f91STakashi Iwai if (spec->dyn_adc_switch)
3410352f7f91STakashi Iwai adc_idx = spec->dyn_adc_idx[imux_idx];
3411d3d982f7SDavid Henningsson if (adc_idx < 0 || adc_idx >= AUTO_CFG_MAX_INS) {
3412b56fa1edSDavid Henningsson snd_BUG();
3413b56fa1edSDavid Henningsson return NULL;
3414b56fa1edSDavid Henningsson }
3415c697b716STakashi Iwai return snd_hda_get_path_from_idx(codec, spec->input_paths[imux_idx][adc_idx]);
341697ec558aSTakashi Iwai }
3417352f7f91STakashi Iwai
3418352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
3419352f7f91STakashi Iwai unsigned int idx);
3420352f7f91STakashi Iwai
mux_enum_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3421352f7f91STakashi Iwai static int mux_enum_info(struct snd_kcontrol *kcontrol,
3422352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo)
3423352f7f91STakashi Iwai {
3424352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3425352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
3426352f7f91STakashi Iwai return snd_hda_input_mux_info(&spec->input_mux, uinfo);
3427352f7f91STakashi Iwai }
3428352f7f91STakashi Iwai
mux_enum_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3429352f7f91STakashi Iwai static int mux_enum_get(struct snd_kcontrol *kcontrol,
3430352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol)
3431352f7f91STakashi Iwai {
3432352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3433352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
34342a8d5391STakashi Iwai /* the ctls are created at once with multiple counts */
34352a8d5391STakashi Iwai unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
3436352f7f91STakashi Iwai
3437352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
34381da177e4SLinus Torvalds return 0;
34391da177e4SLinus Torvalds }
34401da177e4SLinus Torvalds
mux_enum_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3441352f7f91STakashi Iwai static int mux_enum_put(struct snd_kcontrol *kcontrol,
3442352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol)
34431da177e4SLinus Torvalds {
3444352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
34452a8d5391STakashi Iwai unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
3446352f7f91STakashi Iwai return mux_select(codec, adc_idx,
3447352f7f91STakashi Iwai ucontrol->value.enumerated.item[0]);
3448352f7f91STakashi Iwai }
3449352f7f91STakashi Iwai
3450352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_src_temp = {
34511da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3452352f7f91STakashi Iwai .name = "Input Source",
3453352f7f91STakashi Iwai .info = mux_enum_info,
3454352f7f91STakashi Iwai .get = mux_enum_get,
3455352f7f91STakashi Iwai .put = mux_enum_put,
34561da177e4SLinus Torvalds };
3457071c73adSTakashi Iwai
345847d46abbSTakashi Iwai /*
345947d46abbSTakashi Iwai * capture volume and capture switch ctls
346047d46abbSTakashi Iwai */
346147d46abbSTakashi Iwai
3462352f7f91STakashi Iwai typedef int (*put_call_t)(struct snd_kcontrol *kcontrol,
3463352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol);
3464071c73adSTakashi Iwai
346547d46abbSTakashi Iwai /* call the given amp update function for all amps in the imux list at once */
cap_put_caller(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol,put_call_t func,int type)3466352f7f91STakashi Iwai static int cap_put_caller(struct snd_kcontrol *kcontrol,
3467352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol,
3468352f7f91STakashi Iwai put_call_t func, int type)
3469352f7f91STakashi Iwai {
3470352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3471352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
3472352f7f91STakashi Iwai const struct hda_input_mux *imux;
3473352f7f91STakashi Iwai struct nid_path *path;
3474a2befe93SJaroslav Kysela int i, adc_idx, ret, err = 0;
3475071c73adSTakashi Iwai
3476352f7f91STakashi Iwai imux = &spec->input_mux;
3477a053d1e3SDavid Henningsson adc_idx = kcontrol->id.index;
3478352f7f91STakashi Iwai mutex_lock(&codec->control_mutex);
3479352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) {
3480c697b716STakashi Iwai path = get_input_path(codec, adc_idx, i);
3481c697b716STakashi Iwai if (!path || !path->ctls[type])
3482352f7f91STakashi Iwai continue;
3483352f7f91STakashi Iwai kcontrol->private_value = path->ctls[type];
3484a2befe93SJaroslav Kysela ret = func(kcontrol, ucontrol);
3485a2befe93SJaroslav Kysela if (ret < 0) {
3486a2befe93SJaroslav Kysela err = ret;
3487a551d914STakashi Iwai break;
3488352f7f91STakashi Iwai }
3489a2befe93SJaroslav Kysela if (ret > 0)
3490a2befe93SJaroslav Kysela err = 1;
3491a2befe93SJaroslav Kysela }
3492352f7f91STakashi Iwai mutex_unlock(&codec->control_mutex);
3493352f7f91STakashi Iwai if (err >= 0 && spec->cap_sync_hook)
34947fe30711STakashi Iwai spec->cap_sync_hook(codec, kcontrol, ucontrol);
3495352f7f91STakashi Iwai return err;
3496352f7f91STakashi Iwai }
3497352f7f91STakashi Iwai
3498352f7f91STakashi Iwai /* capture volume ctl callbacks */
3499352f7f91STakashi Iwai #define cap_vol_info snd_hda_mixer_amp_volume_info
3500352f7f91STakashi Iwai #define cap_vol_get snd_hda_mixer_amp_volume_get
3501352f7f91STakashi Iwai #define cap_vol_tlv snd_hda_mixer_amp_tlv
3502352f7f91STakashi Iwai
cap_vol_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3503352f7f91STakashi Iwai static int cap_vol_put(struct snd_kcontrol *kcontrol,
3504352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol)
3505352f7f91STakashi Iwai {
3506352f7f91STakashi Iwai return cap_put_caller(kcontrol, ucontrol,
3507352f7f91STakashi Iwai snd_hda_mixer_amp_volume_put,
3508352f7f91STakashi Iwai NID_PATH_VOL_CTL);
3509352f7f91STakashi Iwai }
3510352f7f91STakashi Iwai
3511352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_vol_temp = {
3512352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3513352f7f91STakashi Iwai .name = "Capture Volume",
3514352f7f91STakashi Iwai .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
3515352f7f91STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ |
3516352f7f91STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK),
3517352f7f91STakashi Iwai .info = cap_vol_info,
3518352f7f91STakashi Iwai .get = cap_vol_get,
3519352f7f91STakashi Iwai .put = cap_vol_put,
3520352f7f91STakashi Iwai .tlv = { .c = cap_vol_tlv },
3521352f7f91STakashi Iwai };
3522352f7f91STakashi Iwai
3523352f7f91STakashi Iwai /* capture switch ctl callbacks */
3524352f7f91STakashi Iwai #define cap_sw_info snd_ctl_boolean_stereo_info
3525352f7f91STakashi Iwai #define cap_sw_get snd_hda_mixer_amp_switch_get
3526352f7f91STakashi Iwai
cap_sw_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3527352f7f91STakashi Iwai static int cap_sw_put(struct snd_kcontrol *kcontrol,
3528352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol)
3529352f7f91STakashi Iwai {
3530a90229e0STakashi Iwai return cap_put_caller(kcontrol, ucontrol,
3531352f7f91STakashi Iwai snd_hda_mixer_amp_switch_put,
3532352f7f91STakashi Iwai NID_PATH_MUTE_CTL);
3533352f7f91STakashi Iwai }
3534352f7f91STakashi Iwai
3535352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_sw_temp = {
3536352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3537352f7f91STakashi Iwai .name = "Capture Switch",
353808a4b904STakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
3539352f7f91STakashi Iwai .info = cap_sw_info,
3540352f7f91STakashi Iwai .get = cap_sw_get,
3541352f7f91STakashi Iwai .put = cap_sw_put,
3542352f7f91STakashi Iwai };
3543352f7f91STakashi Iwai
parse_capvol_in_path(struct hda_codec * codec,struct nid_path * path)3544352f7f91STakashi Iwai static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path)
3545352f7f91STakashi Iwai {
3546352f7f91STakashi Iwai hda_nid_t nid;
3547352f7f91STakashi Iwai int i, depth;
3548352f7f91STakashi Iwai
3549352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = path->ctls[NID_PATH_MUTE_CTL] = 0;
3550352f7f91STakashi Iwai for (depth = 0; depth < 3; depth++) {
3551352f7f91STakashi Iwai if (depth >= path->depth)
3552352f7f91STakashi Iwai return -EINVAL;
3553352f7f91STakashi Iwai i = path->depth - depth - 1;
3554352f7f91STakashi Iwai nid = path->path[i];
3555352f7f91STakashi Iwai if (!path->ctls[NID_PATH_VOL_CTL]) {
3556352f7f91STakashi Iwai if (nid_has_volume(codec, nid, HDA_OUTPUT))
3557352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] =
3558352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
3559352f7f91STakashi Iwai else if (nid_has_volume(codec, nid, HDA_INPUT)) {
3560352f7f91STakashi Iwai int idx = path->idx[i];
3561352f7f91STakashi Iwai if (!depth && codec->single_adc_amp)
3562352f7f91STakashi Iwai idx = 0;
3563352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] =
3564352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT);
3565352f7f91STakashi Iwai }
3566352f7f91STakashi Iwai }
3567352f7f91STakashi Iwai if (!path->ctls[NID_PATH_MUTE_CTL]) {
3568352f7f91STakashi Iwai if (nid_has_mute(codec, nid, HDA_OUTPUT))
3569352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] =
3570352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
3571352f7f91STakashi Iwai else if (nid_has_mute(codec, nid, HDA_INPUT)) {
3572352f7f91STakashi Iwai int idx = path->idx[i];
3573352f7f91STakashi Iwai if (!depth && codec->single_adc_amp)
3574352f7f91STakashi Iwai idx = 0;
3575352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] =
3576352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT);
3577352f7f91STakashi Iwai }
3578352f7f91STakashi Iwai }
3579352f7f91STakashi Iwai }
3580352f7f91STakashi Iwai return 0;
3581352f7f91STakashi Iwai }
3582352f7f91STakashi Iwai
is_inv_dmic_pin(struct hda_codec * codec,hda_nid_t nid)3583352f7f91STakashi Iwai static bool is_inv_dmic_pin(struct hda_codec *codec, hda_nid_t nid)
3584352f7f91STakashi Iwai {
3585352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
3586352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg;
3587352f7f91STakashi Iwai unsigned int val;
3588352f7f91STakashi Iwai int i;
3589352f7f91STakashi Iwai
3590352f7f91STakashi Iwai if (!spec->inv_dmic_split)
3591352f7f91STakashi Iwai return false;
3592352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) {
3593352f7f91STakashi Iwai if (cfg->inputs[i].pin != nid)
3594352f7f91STakashi Iwai continue;
3595352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC)
3596352f7f91STakashi Iwai return false;
3597352f7f91STakashi Iwai val = snd_hda_codec_get_pincfg(codec, nid);
3598352f7f91STakashi Iwai return snd_hda_get_input_pin_attr(val) == INPUT_PIN_ATTR_INT;
3599352f7f91STakashi Iwai }
3600352f7f91STakashi Iwai return false;
3601352f7f91STakashi Iwai }
3602352f7f91STakashi Iwai
3603a90229e0STakashi Iwai /* capture switch put callback for a single control with hook call */
cap_single_sw_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3604a35bd1e3STakashi Iwai static int cap_single_sw_put(struct snd_kcontrol *kcontrol,
3605a35bd1e3STakashi Iwai struct snd_ctl_elem_value *ucontrol)
3606a35bd1e3STakashi Iwai {
3607a35bd1e3STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3608a35bd1e3STakashi Iwai struct hda_gen_spec *spec = codec->spec;
3609a35bd1e3STakashi Iwai int ret;
3610a35bd1e3STakashi Iwai
3611a35bd1e3STakashi Iwai ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
3612a35bd1e3STakashi Iwai if (ret < 0)
3613a35bd1e3STakashi Iwai return ret;
3614a35bd1e3STakashi Iwai
3615a90229e0STakashi Iwai if (spec->cap_sync_hook)
36167fe30711STakashi Iwai spec->cap_sync_hook(codec, kcontrol, ucontrol);
3617a35bd1e3STakashi Iwai
3618a35bd1e3STakashi Iwai return ret;
3619a35bd1e3STakashi Iwai }
3620a35bd1e3STakashi Iwai
add_single_cap_ctl(struct hda_codec * codec,const char * label,int idx,bool is_switch,unsigned int ctl,bool inv_dmic)3621352f7f91STakashi Iwai static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
3622352f7f91STakashi Iwai int idx, bool is_switch, unsigned int ctl,
3623352f7f91STakashi Iwai bool inv_dmic)
3624352f7f91STakashi Iwai {
3625352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
3626975cc02aSTakashi Iwai char tmpname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
3627352f7f91STakashi Iwai int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL;
3628352f7f91STakashi Iwai const char *sfx = is_switch ? "Switch" : "Volume";
3629352f7f91STakashi Iwai unsigned int chs = inv_dmic ? 1 : 3;
3630a35bd1e3STakashi Iwai struct snd_kcontrol_new *knew;
3631352f7f91STakashi Iwai
3632352f7f91STakashi Iwai if (!ctl)
3633352f7f91STakashi Iwai return 0;
3634352f7f91STakashi Iwai
3635352f7f91STakashi Iwai if (label)
3636352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname),
3637352f7f91STakashi Iwai "%s Capture %s", label, sfx);
3638352f7f91STakashi Iwai else
3639352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname),
3640352f7f91STakashi Iwai "Capture %s", sfx);
3641a35bd1e3STakashi Iwai knew = add_control(spec, type, tmpname, idx,
3642352f7f91STakashi Iwai amp_val_replace_channels(ctl, chs));
3643a35bd1e3STakashi Iwai if (!knew)
3644a35bd1e3STakashi Iwai return -ENOMEM;
3645e65bf997SJaroslav Kysela if (is_switch) {
3646a35bd1e3STakashi Iwai knew->put = cap_single_sw_put;
3647e65bf997SJaroslav Kysela if (spec->mic_mute_led)
3648e65bf997SJaroslav Kysela knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
3649e65bf997SJaroslav Kysela }
3650a35bd1e3STakashi Iwai if (!inv_dmic)
3651a35bd1e3STakashi Iwai return 0;
3652352f7f91STakashi Iwai
3653352f7f91STakashi Iwai /* Make independent right kcontrol */
3654352f7f91STakashi Iwai if (label)
3655352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname),
3656352f7f91STakashi Iwai "Inverted %s Capture %s", label, sfx);
3657352f7f91STakashi Iwai else
3658352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname),
3659352f7f91STakashi Iwai "Inverted Capture %s", sfx);
3660a35bd1e3STakashi Iwai knew = add_control(spec, type, tmpname, idx,
3661352f7f91STakashi Iwai amp_val_replace_channels(ctl, 2));
3662a35bd1e3STakashi Iwai if (!knew)
3663a35bd1e3STakashi Iwai return -ENOMEM;
3664e65bf997SJaroslav Kysela if (is_switch) {
3665a35bd1e3STakashi Iwai knew->put = cap_single_sw_put;
3666e65bf997SJaroslav Kysela if (spec->mic_mute_led)
3667e65bf997SJaroslav Kysela knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
3668e65bf997SJaroslav Kysela }
3669a35bd1e3STakashi Iwai return 0;
3670352f7f91STakashi Iwai }
3671352f7f91STakashi Iwai
3672352f7f91STakashi Iwai /* create single (and simple) capture volume and switch controls */
create_single_cap_vol_ctl(struct hda_codec * codec,int idx,unsigned int vol_ctl,unsigned int sw_ctl,bool inv_dmic)3673352f7f91STakashi Iwai static int create_single_cap_vol_ctl(struct hda_codec *codec, int idx,
3674352f7f91STakashi Iwai unsigned int vol_ctl, unsigned int sw_ctl,
3675352f7f91STakashi Iwai bool inv_dmic)
3676352f7f91STakashi Iwai {
3677352f7f91STakashi Iwai int err;
3678352f7f91STakashi Iwai err = add_single_cap_ctl(codec, NULL, idx, false, vol_ctl, inv_dmic);
3679352f7f91STakashi Iwai if (err < 0)
3680352f7f91STakashi Iwai return err;
3681352f7f91STakashi Iwai err = add_single_cap_ctl(codec, NULL, idx, true, sw_ctl, inv_dmic);
3682071c73adSTakashi Iwai if (err < 0)
3683071c73adSTakashi Iwai return err;
3684071c73adSTakashi Iwai return 0;
36851da177e4SLinus Torvalds }
3686071c73adSTakashi Iwai
3687352f7f91STakashi Iwai /* create bound capture volume and switch controls */
create_bind_cap_vol_ctl(struct hda_codec * codec,int idx,unsigned int vol_ctl,unsigned int sw_ctl)3688352f7f91STakashi Iwai static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx,
3689352f7f91STakashi Iwai unsigned int vol_ctl, unsigned int sw_ctl)
3690352f7f91STakashi Iwai {
3691352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
3692352f7f91STakashi Iwai struct snd_kcontrol_new *knew;
3693352f7f91STakashi Iwai
3694352f7f91STakashi Iwai if (vol_ctl) {
369512c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, NULL, &cap_vol_temp);
3696352f7f91STakashi Iwai if (!knew)
3697352f7f91STakashi Iwai return -ENOMEM;
3698352f7f91STakashi Iwai knew->index = idx;
3699352f7f91STakashi Iwai knew->private_value = vol_ctl;
3700352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG;
3701352f7f91STakashi Iwai }
3702352f7f91STakashi Iwai if (sw_ctl) {
370312c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, NULL, &cap_sw_temp);
3704352f7f91STakashi Iwai if (!knew)
3705352f7f91STakashi Iwai return -ENOMEM;
3706352f7f91STakashi Iwai knew->index = idx;
3707352f7f91STakashi Iwai knew->private_value = sw_ctl;
3708352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG;
3709e65bf997SJaroslav Kysela if (spec->mic_mute_led)
3710e65bf997SJaroslav Kysela knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
3711352f7f91STakashi Iwai }
3712352f7f91STakashi Iwai return 0;
3713352f7f91STakashi Iwai }
3714352f7f91STakashi Iwai
3715352f7f91STakashi Iwai /* return the vol ctl when used first in the imux list */
get_first_cap_ctl(struct hda_codec * codec,int idx,int type)3716352f7f91STakashi Iwai static unsigned int get_first_cap_ctl(struct hda_codec *codec, int idx, int type)
3717352f7f91STakashi Iwai {
3718352f7f91STakashi Iwai struct nid_path *path;
3719352f7f91STakashi Iwai unsigned int ctl;
3720352f7f91STakashi Iwai int i;
3721352f7f91STakashi Iwai
3722c697b716STakashi Iwai path = get_input_path(codec, 0, idx);
3723352f7f91STakashi Iwai if (!path)
3724352f7f91STakashi Iwai return 0;
3725352f7f91STakashi Iwai ctl = path->ctls[type];
3726352f7f91STakashi Iwai if (!ctl)
3727352f7f91STakashi Iwai return 0;
3728352f7f91STakashi Iwai for (i = 0; i < idx - 1; i++) {
3729c697b716STakashi Iwai path = get_input_path(codec, 0, i);
3730352f7f91STakashi Iwai if (path && path->ctls[type] == ctl)
3731352f7f91STakashi Iwai return 0;
3732352f7f91STakashi Iwai }
3733352f7f91STakashi Iwai return ctl;
3734352f7f91STakashi Iwai }
3735352f7f91STakashi Iwai
3736352f7f91STakashi Iwai /* create individual capture volume and switch controls per input */
create_multi_cap_vol_ctl(struct hda_codec * codec)3737352f7f91STakashi Iwai static int create_multi_cap_vol_ctl(struct hda_codec *codec)
3738352f7f91STakashi Iwai {
3739352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
3740352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux;
3741c970042cSTakashi Iwai int i, err, type;
3742352f7f91STakashi Iwai
3743352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) {
3744352f7f91STakashi Iwai bool inv_dmic;
3745c970042cSTakashi Iwai int idx;
37469dba205bSTakashi Iwai
3747c970042cSTakashi Iwai idx = imux->items[i].index;
3748c970042cSTakashi Iwai if (idx >= spec->autocfg.num_inputs)
37499dba205bSTakashi Iwai continue;
3750352f7f91STakashi Iwai inv_dmic = is_inv_dmic_pin(codec, spec->imux_pins[i]);
3751352f7f91STakashi Iwai
3752352f7f91STakashi Iwai for (type = 0; type < 2; type++) {
3753c970042cSTakashi Iwai err = add_single_cap_ctl(codec,
3754c970042cSTakashi Iwai spec->input_labels[idx],
3755c970042cSTakashi Iwai spec->input_label_idxs[idx],
3756c970042cSTakashi Iwai type,
3757352f7f91STakashi Iwai get_first_cap_ctl(codec, i, type),
3758352f7f91STakashi Iwai inv_dmic);
3759d13bd412STakashi Iwai if (err < 0)
3760071c73adSTakashi Iwai return err;
3761352f7f91STakashi Iwai }
3762352f7f91STakashi Iwai }
3763071c73adSTakashi Iwai return 0;
3764352f7f91STakashi Iwai }
3765071c73adSTakashi Iwai
create_capture_mixers(struct hda_codec * codec)3766352f7f91STakashi Iwai static int create_capture_mixers(struct hda_codec *codec)
3767352f7f91STakashi Iwai {
3768352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
3769352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux;
3770352f7f91STakashi Iwai int i, n, nums, err;
3771352f7f91STakashi Iwai
3772352f7f91STakashi Iwai if (spec->dyn_adc_switch)
3773352f7f91STakashi Iwai nums = 1;
3774352f7f91STakashi Iwai else
3775352f7f91STakashi Iwai nums = spec->num_adc_nids;
3776352f7f91STakashi Iwai
3777352f7f91STakashi Iwai if (!spec->auto_mic && imux->num_items > 1) {
3778352f7f91STakashi Iwai struct snd_kcontrol_new *knew;
3779624d914dSTakashi Iwai const char *name;
3780624d914dSTakashi Iwai name = nums > 1 ? "Input Source" : "Capture Source";
3781624d914dSTakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &cap_src_temp);
3782352f7f91STakashi Iwai if (!knew)
3783352f7f91STakashi Iwai return -ENOMEM;
3784352f7f91STakashi Iwai knew->count = nums;
3785352f7f91STakashi Iwai }
3786352f7f91STakashi Iwai
3787352f7f91STakashi Iwai for (n = 0; n < nums; n++) {
3788352f7f91STakashi Iwai bool multi = false;
378999a5592dSDavid Henningsson bool multi_cap_vol = spec->multi_cap_vol;
3790352f7f91STakashi Iwai bool inv_dmic = false;
3791352f7f91STakashi Iwai int vol, sw;
3792352f7f91STakashi Iwai
3793352f7f91STakashi Iwai vol = sw = 0;
3794352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) {
3795352f7f91STakashi Iwai struct nid_path *path;
3796c697b716STakashi Iwai path = get_input_path(codec, n, i);
3797352f7f91STakashi Iwai if (!path)
3798352f7f91STakashi Iwai continue;
3799352f7f91STakashi Iwai parse_capvol_in_path(codec, path);
3800352f7f91STakashi Iwai if (!vol)
3801352f7f91STakashi Iwai vol = path->ctls[NID_PATH_VOL_CTL];
380299a5592dSDavid Henningsson else if (vol != path->ctls[NID_PATH_VOL_CTL]) {
3803352f7f91STakashi Iwai multi = true;
380499a5592dSDavid Henningsson if (!same_amp_caps(codec, vol,
380599a5592dSDavid Henningsson path->ctls[NID_PATH_VOL_CTL], HDA_INPUT))
380699a5592dSDavid Henningsson multi_cap_vol = true;
380799a5592dSDavid Henningsson }
3808352f7f91STakashi Iwai if (!sw)
3809352f7f91STakashi Iwai sw = path->ctls[NID_PATH_MUTE_CTL];
381099a5592dSDavid Henningsson else if (sw != path->ctls[NID_PATH_MUTE_CTL]) {
3811352f7f91STakashi Iwai multi = true;
381299a5592dSDavid Henningsson if (!same_amp_caps(codec, sw,
381399a5592dSDavid Henningsson path->ctls[NID_PATH_MUTE_CTL], HDA_INPUT))
381499a5592dSDavid Henningsson multi_cap_vol = true;
381599a5592dSDavid Henningsson }
3816352f7f91STakashi Iwai if (is_inv_dmic_pin(codec, spec->imux_pins[i]))
3817352f7f91STakashi Iwai inv_dmic = true;
3818352f7f91STakashi Iwai }
3819352f7f91STakashi Iwai
3820352f7f91STakashi Iwai if (!multi)
3821352f7f91STakashi Iwai err = create_single_cap_vol_ctl(codec, n, vol, sw,
3822352f7f91STakashi Iwai inv_dmic);
3823ccb04157SDavid Henningsson else if (!multi_cap_vol && !inv_dmic)
3824352f7f91STakashi Iwai err = create_bind_cap_vol_ctl(codec, n, vol, sw);
3825352f7f91STakashi Iwai else
3826352f7f91STakashi Iwai err = create_multi_cap_vol_ctl(codec);
3827d13bd412STakashi Iwai if (err < 0)
3828071c73adSTakashi Iwai return err;
3829071c73adSTakashi Iwai }
3830071c73adSTakashi Iwai
38311da177e4SLinus Torvalds return 0;
38321da177e4SLinus Torvalds }
38331da177e4SLinus Torvalds
3834352f7f91STakashi Iwai /*
3835352f7f91STakashi Iwai * add mic boosts if needed
3836352f7f91STakashi Iwai */
38376f7c83afSTakashi Iwai
38386f7c83afSTakashi Iwai /* check whether the given amp is feasible as a boost volume */
check_boost_vol(struct hda_codec * codec,hda_nid_t nid,int dir,int idx)38396f7c83afSTakashi Iwai static bool check_boost_vol(struct hda_codec *codec, hda_nid_t nid,
38406f7c83afSTakashi Iwai int dir, int idx)
38416f7c83afSTakashi Iwai {
38426f7c83afSTakashi Iwai unsigned int step;
38436f7c83afSTakashi Iwai
38446f7c83afSTakashi Iwai if (!nid_has_volume(codec, nid, dir) ||
38456f7c83afSTakashi Iwai is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) ||
38466f7c83afSTakashi Iwai is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL))
38476f7c83afSTakashi Iwai return false;
38486f7c83afSTakashi Iwai
38496f7c83afSTakashi Iwai step = (query_amp_caps(codec, nid, dir) & AC_AMPCAP_STEP_SIZE)
38506f7c83afSTakashi Iwai >> AC_AMPCAP_STEP_SIZE_SHIFT;
38516f7c83afSTakashi Iwai if (step < 0x20)
38526f7c83afSTakashi Iwai return false;
38536f7c83afSTakashi Iwai return true;
38546f7c83afSTakashi Iwai }
38556f7c83afSTakashi Iwai
38566f7c83afSTakashi Iwai /* look for a boost amp in a widget close to the pin */
look_for_boost_amp(struct hda_codec * codec,struct nid_path * path)38576f7c83afSTakashi Iwai static unsigned int look_for_boost_amp(struct hda_codec *codec,
38586f7c83afSTakashi Iwai struct nid_path *path)
38596f7c83afSTakashi Iwai {
38606f7c83afSTakashi Iwai unsigned int val = 0;
38616f7c83afSTakashi Iwai hda_nid_t nid;
38626f7c83afSTakashi Iwai int depth;
38636f7c83afSTakashi Iwai
38646f7c83afSTakashi Iwai for (depth = 0; depth < 3; depth++) {
38656f7c83afSTakashi Iwai if (depth >= path->depth - 1)
38666f7c83afSTakashi Iwai break;
38676f7c83afSTakashi Iwai nid = path->path[depth];
38686f7c83afSTakashi Iwai if (depth && check_boost_vol(codec, nid, HDA_OUTPUT, 0)) {
38696f7c83afSTakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
38706f7c83afSTakashi Iwai break;
38716f7c83afSTakashi Iwai } else if (check_boost_vol(codec, nid, HDA_INPUT,
38726f7c83afSTakashi Iwai path->idx[depth])) {
38736f7c83afSTakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, path->idx[depth],
38746f7c83afSTakashi Iwai HDA_INPUT);
38756f7c83afSTakashi Iwai break;
38766f7c83afSTakashi Iwai }
38776f7c83afSTakashi Iwai }
38786f7c83afSTakashi Iwai
38796f7c83afSTakashi Iwai return val;
38806f7c83afSTakashi Iwai }
38816f7c83afSTakashi Iwai
parse_mic_boost(struct hda_codec * codec)3882352f7f91STakashi Iwai static int parse_mic_boost(struct hda_codec *codec)
3883352f7f91STakashi Iwai {
3884352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
3885352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg;
38866f7c83afSTakashi Iwai struct hda_input_mux *imux = &spec->input_mux;
3887a35bd1e3STakashi Iwai int i;
3888352f7f91STakashi Iwai
38896f7c83afSTakashi Iwai if (!spec->num_adc_nids)
38906f7c83afSTakashi Iwai return 0;
38916f7c83afSTakashi Iwai
38926f7c83afSTakashi Iwai for (i = 0; i < imux->num_items; i++) {
3893352f7f91STakashi Iwai struct nid_path *path;
3894352f7f91STakashi Iwai unsigned int val;
38956f7c83afSTakashi Iwai int idx;
3896975cc02aSTakashi Iwai char boost_label[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
3897352f7f91STakashi Iwai
38986f7c83afSTakashi Iwai idx = imux->items[i].index;
38996f7c83afSTakashi Iwai if (idx >= imux->num_items)
390002aba550SDavid Henningsson continue;
390102aba550SDavid Henningsson
39026f7c83afSTakashi Iwai /* check only line-in and mic pins */
39031799cdd5STakashi Iwai if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN)
39046f7c83afSTakashi Iwai continue;
39056f7c83afSTakashi Iwai
39066f7c83afSTakashi Iwai path = get_input_path(codec, 0, i);
39076f7c83afSTakashi Iwai if (!path)
39086f7c83afSTakashi Iwai continue;
39096f7c83afSTakashi Iwai
39106f7c83afSTakashi Iwai val = look_for_boost_amp(codec, path);
39116f7c83afSTakashi Iwai if (!val)
39126f7c83afSTakashi Iwai continue;
39136f7c83afSTakashi Iwai
39146f7c83afSTakashi Iwai /* create a boost control */
3915352f7f91STakashi Iwai snprintf(boost_label, sizeof(boost_label),
39166f7c83afSTakashi Iwai "%s Boost Volume", spec->input_labels[idx]);
3917a35bd1e3STakashi Iwai if (!add_control(spec, HDA_CTL_WIDGET_VOL, boost_label,
3918a35bd1e3STakashi Iwai spec->input_label_idxs[idx], val))
3919a35bd1e3STakashi Iwai return -ENOMEM;
3920352f7f91STakashi Iwai
3921352f7f91STakashi Iwai path->ctls[NID_PATH_BOOST_CTL] = val;
3922352f7f91STakashi Iwai }
3923352f7f91STakashi Iwai return 0;
3924352f7f91STakashi Iwai }
3925352f7f91STakashi Iwai
39267cdf8c49STakashi Iwai #ifdef CONFIG_SND_HDA_GENERIC_LEDS
3927352f7f91STakashi Iwai /*
392815509b63STakashi Iwai * vmaster mute LED hook helpers
392915509b63STakashi Iwai */
393015509b63STakashi Iwai
create_mute_led_cdev(struct hda_codec * codec,int (* callback)(struct led_classdev *,enum led_brightness),bool micmute)393115509b63STakashi Iwai static int create_mute_led_cdev(struct hda_codec *codec,
393215509b63STakashi Iwai int (*callback)(struct led_classdev *,
393315509b63STakashi Iwai enum led_brightness),
393415509b63STakashi Iwai bool micmute)
393515509b63STakashi Iwai {
3936549f8ffcSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
393715509b63STakashi Iwai struct led_classdev *cdev;
3938549f8ffcSTakashi Iwai int idx = micmute ? LED_AUDIO_MICMUTE : LED_AUDIO_MUTE;
3939549f8ffcSTakashi Iwai int err;
394015509b63STakashi Iwai
394115509b63STakashi Iwai cdev = devm_kzalloc(&codec->core.dev, sizeof(*cdev), GFP_KERNEL);
394215509b63STakashi Iwai if (!cdev)
394315509b63STakashi Iwai return -ENOMEM;
394415509b63STakashi Iwai
394515509b63STakashi Iwai cdev->name = micmute ? "hda::micmute" : "hda::mute";
394615509b63STakashi Iwai cdev->max_brightness = 1;
394715509b63STakashi Iwai cdev->default_trigger = micmute ? "audio-micmute" : "audio-mute";
394815509b63STakashi Iwai cdev->brightness_set_blocking = callback;
3949549f8ffcSTakashi Iwai cdev->brightness = ledtrig_audio_get(idx);
3950c9e272f9STakashi Iwai cdev->flags = LED_CORE_SUSPENDRESUME;
395115509b63STakashi Iwai
3952549f8ffcSTakashi Iwai err = led_classdev_register(&codec->core.dev, cdev);
3953549f8ffcSTakashi Iwai if (err < 0)
3954549f8ffcSTakashi Iwai return err;
3955549f8ffcSTakashi Iwai spec->led_cdevs[idx] = cdev;
3956549f8ffcSTakashi Iwai return 0;
395715509b63STakashi Iwai }
395815509b63STakashi Iwai
395915509b63STakashi Iwai /**
39603531ba21SPierre-Louis Bossart * snd_hda_gen_add_mute_led_cdev - Create a LED classdev and enable as vmaster mute LED
396115509b63STakashi Iwai * @codec: the HDA codec
396215509b63STakashi Iwai * @callback: the callback for LED classdev brightness_set_blocking
396315509b63STakashi Iwai */
snd_hda_gen_add_mute_led_cdev(struct hda_codec * codec,int (* callback)(struct led_classdev *,enum led_brightness))396415509b63STakashi Iwai int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec,
396515509b63STakashi Iwai int (*callback)(struct led_classdev *,
396615509b63STakashi Iwai enum led_brightness))
396715509b63STakashi Iwai {
396815509b63STakashi Iwai struct hda_gen_spec *spec = codec->spec;
396915509b63STakashi Iwai int err;
397015509b63STakashi Iwai
397115509b63STakashi Iwai if (callback) {
397215509b63STakashi Iwai err = create_mute_led_cdev(codec, callback, false);
397315509b63STakashi Iwai if (err) {
397415509b63STakashi Iwai codec_warn(codec, "failed to create a mute LED cdev\n");
397515509b63STakashi Iwai return err;
397615509b63STakashi Iwai }
397715509b63STakashi Iwai }
397815509b63STakashi Iwai
397915509b63STakashi Iwai if (spec->vmaster_mute.hook)
398015509b63STakashi Iwai codec_err(codec, "vmaster hook already present before cdev!\n");
398115509b63STakashi Iwai
3982e65bf997SJaroslav Kysela spec->vmaster_mute_led = 1;
398315509b63STakashi Iwai return 0;
398415509b63STakashi Iwai }
398515509b63STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_add_mute_led_cdev);
398615509b63STakashi Iwai
3987b3802783STakashi Iwai /**
39883531ba21SPierre-Louis Bossart * snd_hda_gen_add_micmute_led_cdev - Create a LED classdev and enable as mic-mute LED
39897cdf8c49STakashi Iwai * @codec: the HDA codec
39907cdf8c49STakashi Iwai * @callback: the callback for LED classdev brightness_set_blocking
39917cdf8c49STakashi Iwai *
39927cdf8c49STakashi Iwai * Called from the codec drivers for offering the mic mute LED controls.
39937cdf8c49STakashi Iwai * This creates a LED classdev and sets up the cap_sync_hook that is called at
39947cdf8c49STakashi Iwai * each time when the capture mixer switch changes.
39957cdf8c49STakashi Iwai *
39967cdf8c49STakashi Iwai * When NULL is passed to @callback, no classdev is created but only the
39977cdf8c49STakashi Iwai * LED-trigger is set up.
39987cdf8c49STakashi Iwai *
39997cdf8c49STakashi Iwai * Returns 0 or a negative error.
40007cdf8c49STakashi Iwai */
snd_hda_gen_add_micmute_led_cdev(struct hda_codec * codec,int (* callback)(struct led_classdev *,enum led_brightness))40017cdf8c49STakashi Iwai int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec,
40027cdf8c49STakashi Iwai int (*callback)(struct led_classdev *,
40037cdf8c49STakashi Iwai enum led_brightness))
40047cdf8c49STakashi Iwai {
4005e65bf997SJaroslav Kysela struct hda_gen_spec *spec = codec->spec;
40067cdf8c49STakashi Iwai int err;
40077cdf8c49STakashi Iwai
40087cdf8c49STakashi Iwai if (callback) {
400915509b63STakashi Iwai err = create_mute_led_cdev(codec, callback, true);
40107cdf8c49STakashi Iwai if (err) {
40117cdf8c49STakashi Iwai codec_warn(codec, "failed to create a mic-mute LED cdev\n");
40127cdf8c49STakashi Iwai return err;
40137cdf8c49STakashi Iwai }
40147cdf8c49STakashi Iwai }
40157cdf8c49STakashi Iwai
4016e65bf997SJaroslav Kysela spec->mic_mute_led = 1;
4017e65bf997SJaroslav Kysela return 0;
40187cdf8c49STakashi Iwai }
40197cdf8c49STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led_cdev);
40207cdf8c49STakashi Iwai #endif /* CONFIG_SND_HDA_GENERIC_LEDS */
40217cdf8c49STakashi Iwai
4022f567b788STakashi Iwai /*
4023352f7f91STakashi Iwai * parse digital I/Os and set up NIDs in BIOS auto-parse mode
4024352f7f91STakashi Iwai */
parse_digital(struct hda_codec * codec)4025352f7f91STakashi Iwai static void parse_digital(struct hda_codec *codec)
4026352f7f91STakashi Iwai {
4027352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
40280c8c0f56STakashi Iwai struct nid_path *path;
4029352f7f91STakashi Iwai int i, nums;
40302c12c30dSTakashi Iwai hda_nid_t dig_nid, pin;
4031352f7f91STakashi Iwai
40329ab0cb30STakashi Iwai /* support multiple SPDIFs; the secondary is set up as a follower */
4033352f7f91STakashi Iwai nums = 0;
4034352f7f91STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) {
40352c12c30dSTakashi Iwai pin = spec->autocfg.dig_out_pins[i];
4036352f7f91STakashi Iwai dig_nid = look_for_dac(codec, pin, true);
4037352f7f91STakashi Iwai if (!dig_nid)
4038352f7f91STakashi Iwai continue;
40393ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dig_nid, pin, 0);
40400c8c0f56STakashi Iwai if (!path)
4041352f7f91STakashi Iwai continue;
40424e76a883STakashi Iwai print_nid_path(codec, "digout", path);
4043e1284af7STakashi Iwai path->active = true;
40446b275b14STakashi Iwai path->pin_fixed = true; /* no jack detection */
4045196c1766STakashi Iwai spec->digout_paths[i] = snd_hda_get_path_idx(codec, path);
40462c12c30dSTakashi Iwai set_pin_target(codec, pin, PIN_OUT, false);
4047352f7f91STakashi Iwai if (!nums) {
4048352f7f91STakashi Iwai spec->multiout.dig_out_nid = dig_nid;
4049352f7f91STakashi Iwai spec->dig_out_type = spec->autocfg.dig_out_type[0];
4050352f7f91STakashi Iwai } else {
40519ab0cb30STakashi Iwai spec->multiout.follower_dig_outs = spec->follower_dig_outs;
40529ab0cb30STakashi Iwai if (nums >= ARRAY_SIZE(spec->follower_dig_outs) - 1)
4053352f7f91STakashi Iwai break;
40549ab0cb30STakashi Iwai spec->follower_dig_outs[nums - 1] = dig_nid;
4055352f7f91STakashi Iwai }
4056352f7f91STakashi Iwai nums++;
4057352f7f91STakashi Iwai }
4058352f7f91STakashi Iwai
4059352f7f91STakashi Iwai if (spec->autocfg.dig_in_pin) {
40602c12c30dSTakashi Iwai pin = spec->autocfg.dig_in_pin;
40617639a06cSTakashi Iwai for_each_hda_codec_node(dig_nid, codec) {
4062352f7f91STakashi Iwai unsigned int wcaps = get_wcaps(codec, dig_nid);
4063352f7f91STakashi Iwai if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
4064352f7f91STakashi Iwai continue;
4065352f7f91STakashi Iwai if (!(wcaps & AC_WCAP_DIGITAL))
4066352f7f91STakashi Iwai continue;
40672c12c30dSTakashi Iwai path = snd_hda_add_new_path(codec, pin, dig_nid, 0);
4068352f7f91STakashi Iwai if (path) {
40694e76a883STakashi Iwai print_nid_path(codec, "digin", path);
4070352f7f91STakashi Iwai path->active = true;
40716b275b14STakashi Iwai path->pin_fixed = true; /* no jack */
4072352f7f91STakashi Iwai spec->dig_in_nid = dig_nid;
40732430d7b7STakashi Iwai spec->digin_path = snd_hda_get_path_idx(codec, path);
40742c12c30dSTakashi Iwai set_pin_target(codec, pin, PIN_IN, false);
4075352f7f91STakashi Iwai break;
4076352f7f91STakashi Iwai }
4077352f7f91STakashi Iwai }
4078352f7f91STakashi Iwai }
4079352f7f91STakashi Iwai }
4080352f7f91STakashi Iwai
40811da177e4SLinus Torvalds
40821da177e4SLinus Torvalds /*
4083352f7f91STakashi Iwai * input MUX handling
40841da177e4SLinus Torvalds */
40851da177e4SLinus Torvalds
4086352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur);
4087352f7f91STakashi Iwai
4088352f7f91STakashi Iwai /* select the given imux item; either unmute exclusively or select the route */
mux_select(struct hda_codec * codec,unsigned int adc_idx,unsigned int idx)4089352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
4090352f7f91STakashi Iwai unsigned int idx)
4091352f7f91STakashi Iwai {
4092352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
4093352f7f91STakashi Iwai const struct hda_input_mux *imux;
409455196fffSTakashi Iwai struct nid_path *old_path, *path;
4095352f7f91STakashi Iwai
4096352f7f91STakashi Iwai imux = &spec->input_mux;
4097352f7f91STakashi Iwai if (!imux->num_items)
40981da177e4SLinus Torvalds return 0;
40991da177e4SLinus Torvalds
4100352f7f91STakashi Iwai if (idx >= imux->num_items)
4101352f7f91STakashi Iwai idx = imux->num_items - 1;
4102352f7f91STakashi Iwai if (spec->cur_mux[adc_idx] == idx)
4103352f7f91STakashi Iwai return 0;
4104352f7f91STakashi Iwai
410555196fffSTakashi Iwai old_path = get_input_path(codec, adc_idx, spec->cur_mux[adc_idx]);
410655196fffSTakashi Iwai if (!old_path)
4107352f7f91STakashi Iwai return 0;
410855196fffSTakashi Iwai if (old_path->active)
410955196fffSTakashi Iwai snd_hda_activate_path(codec, old_path, false, false);
4110352f7f91STakashi Iwai
4111352f7f91STakashi Iwai spec->cur_mux[adc_idx] = idx;
4112352f7f91STakashi Iwai
4113967303daSTakashi Iwai if (spec->hp_mic)
4114967303daSTakashi Iwai update_hp_mic(codec, adc_idx, false);
4115352f7f91STakashi Iwai
4116352f7f91STakashi Iwai if (spec->dyn_adc_switch)
4117352f7f91STakashi Iwai dyn_adc_pcm_resetup(codec, idx);
4118352f7f91STakashi Iwai
4119c697b716STakashi Iwai path = get_input_path(codec, adc_idx, idx);
4120352f7f91STakashi Iwai if (!path)
4121352f7f91STakashi Iwai return 0;
4122352f7f91STakashi Iwai if (path->active)
4123352f7f91STakashi Iwai return 0;
4124352f7f91STakashi Iwai snd_hda_activate_path(codec, path, true, false);
4125352f7f91STakashi Iwai if (spec->cap_sync_hook)
41267fe30711STakashi Iwai spec->cap_sync_hook(codec, NULL, NULL);
412755196fffSTakashi Iwai path_power_down_sync(codec, old_path);
41281da177e4SLinus Torvalds return 1;
41291da177e4SLinus Torvalds }
41301da177e4SLinus Torvalds
4131e6feb5d0STakashi Iwai /* power up/down widgets in the all paths that match with the given NID
4132e6feb5d0STakashi Iwai * as terminals (either start- or endpoint)
4133e6feb5d0STakashi Iwai *
4134e6feb5d0STakashi Iwai * returns the last changed NID, or zero if unchanged.
4135e6feb5d0STakashi Iwai */
set_path_power(struct hda_codec * codec,hda_nid_t nid,int pin_state,int stream_state)4136e6feb5d0STakashi Iwai static hda_nid_t set_path_power(struct hda_codec *codec, hda_nid_t nid,
4137e6feb5d0STakashi Iwai int pin_state, int stream_state)
4138e6feb5d0STakashi Iwai {
4139e6feb5d0STakashi Iwai struct hda_gen_spec *spec = codec->spec;
4140e6feb5d0STakashi Iwai hda_nid_t last, changed = 0;
4141e6feb5d0STakashi Iwai struct nid_path *path;
4142e6feb5d0STakashi Iwai int n;
4143e6feb5d0STakashi Iwai
4144a9c2dfc8STakashi Iwai snd_array_for_each(&spec->paths, n, path) {
414581e43960SBob Copeland if (!path->depth)
414681e43960SBob Copeland continue;
4147e6feb5d0STakashi Iwai if (path->path[0] == nid ||
4148e6feb5d0STakashi Iwai path->path[path->depth - 1] == nid) {
4149e6feb5d0STakashi Iwai bool pin_old = path->pin_enabled;
4150e6feb5d0STakashi Iwai bool stream_old = path->stream_enabled;
4151e6feb5d0STakashi Iwai
4152e6feb5d0STakashi Iwai if (pin_state >= 0)
4153e6feb5d0STakashi Iwai path->pin_enabled = pin_state;
4154e6feb5d0STakashi Iwai if (stream_state >= 0)
4155e6feb5d0STakashi Iwai path->stream_enabled = stream_state;
41566b275b14STakashi Iwai if ((!path->pin_fixed && path->pin_enabled != pin_old)
41576b275b14STakashi Iwai || path->stream_enabled != stream_old) {
4158e6feb5d0STakashi Iwai last = path_power_update(codec, path, true);
4159e6feb5d0STakashi Iwai if (last)
4160e6feb5d0STakashi Iwai changed = last;
4161e6feb5d0STakashi Iwai }
4162e6feb5d0STakashi Iwai }
4163e6feb5d0STakashi Iwai }
4164e6feb5d0STakashi Iwai return changed;
4165e6feb5d0STakashi Iwai }
4166e6feb5d0STakashi Iwai
4167d5ac0100STakashi Iwai /* check the jack status for power control */
detect_pin_state(struct hda_codec * codec,hda_nid_t pin)4168d5ac0100STakashi Iwai static bool detect_pin_state(struct hda_codec *codec, hda_nid_t pin)
4169d5ac0100STakashi Iwai {
4170d5ac0100STakashi Iwai if (!is_jack_detectable(codec, pin))
4171d5ac0100STakashi Iwai return true;
4172d5ac0100STakashi Iwai return snd_hda_jack_detect_state(codec, pin) != HDA_JACK_NOT_PRESENT;
4173d5ac0100STakashi Iwai }
4174d5ac0100STakashi Iwai
4175e6feb5d0STakashi Iwai /* power up/down the paths of the given pin according to the jack state;
4176e6feb5d0STakashi Iwai * power = 0/1 : only power up/down if it matches with the jack state,
4177e6feb5d0STakashi Iwai * < 0 : force power up/down to follow the jack sate
4178e6feb5d0STakashi Iwai *
4179e6feb5d0STakashi Iwai * returns the last changed NID, or zero if unchanged.
4180e6feb5d0STakashi Iwai */
set_pin_power_jack(struct hda_codec * codec,hda_nid_t pin,int power)4181e6feb5d0STakashi Iwai static hda_nid_t set_pin_power_jack(struct hda_codec *codec, hda_nid_t pin,
4182e6feb5d0STakashi Iwai int power)
4183e6feb5d0STakashi Iwai {
4184e6feb5d0STakashi Iwai bool on;
4185e6feb5d0STakashi Iwai
4186967b1307STakashi Iwai if (!codec->power_save_node)
4187e6feb5d0STakashi Iwai return 0;
4188e6feb5d0STakashi Iwai
4189d5ac0100STakashi Iwai on = detect_pin_state(codec, pin);
4190d5ac0100STakashi Iwai
4191e6feb5d0STakashi Iwai if (power >= 0 && on != power)
4192e6feb5d0STakashi Iwai return 0;
4193e6feb5d0STakashi Iwai return set_path_power(codec, pin, on, -1);
4194e6feb5d0STakashi Iwai }
4195e6feb5d0STakashi Iwai
pin_power_callback(struct hda_codec * codec,struct hda_jack_callback * jack,bool on)4196e6feb5d0STakashi Iwai static void pin_power_callback(struct hda_codec *codec,
4197e6feb5d0STakashi Iwai struct hda_jack_callback *jack,
4198e6feb5d0STakashi Iwai bool on)
4199e6feb5d0STakashi Iwai {
42002ebab40eSTakashi Iwai if (jack && jack->nid)
4201e6feb5d0STakashi Iwai sync_power_state_change(codec,
42022ebab40eSTakashi Iwai set_pin_power_jack(codec, jack->nid, on));
4203e6feb5d0STakashi Iwai }
4204e6feb5d0STakashi Iwai
4205e6feb5d0STakashi Iwai /* callback only doing power up -- called at first */
pin_power_up_callback(struct hda_codec * codec,struct hda_jack_callback * jack)4206e6feb5d0STakashi Iwai static void pin_power_up_callback(struct hda_codec *codec,
4207e6feb5d0STakashi Iwai struct hda_jack_callback *jack)
4208e6feb5d0STakashi Iwai {
4209e6feb5d0STakashi Iwai pin_power_callback(codec, jack, true);
4210e6feb5d0STakashi Iwai }
4211e6feb5d0STakashi Iwai
4212e6feb5d0STakashi Iwai /* callback only doing power down -- called at last */
pin_power_down_callback(struct hda_codec * codec,struct hda_jack_callback * jack)4213e6feb5d0STakashi Iwai static void pin_power_down_callback(struct hda_codec *codec,
4214e6feb5d0STakashi Iwai struct hda_jack_callback *jack)
4215e6feb5d0STakashi Iwai {
4216e6feb5d0STakashi Iwai pin_power_callback(codec, jack, false);
4217e6feb5d0STakashi Iwai }
4218e6feb5d0STakashi Iwai
4219e6feb5d0STakashi Iwai /* set up the power up/down callbacks */
add_pin_power_ctls(struct hda_codec * codec,int num_pins,const hda_nid_t * pins,bool on)4220e6feb5d0STakashi Iwai static void add_pin_power_ctls(struct hda_codec *codec, int num_pins,
4221e6feb5d0STakashi Iwai const hda_nid_t *pins, bool on)
4222e6feb5d0STakashi Iwai {
4223e6feb5d0STakashi Iwai int i;
4224e6feb5d0STakashi Iwai hda_jack_callback_fn cb =
4225e6feb5d0STakashi Iwai on ? pin_power_up_callback : pin_power_down_callback;
4226e6feb5d0STakashi Iwai
4227e6feb5d0STakashi Iwai for (i = 0; i < num_pins && pins[i]; i++) {
4228e6feb5d0STakashi Iwai if (is_jack_detectable(codec, pins[i]))
4229e6feb5d0STakashi Iwai snd_hda_jack_detect_enable_callback(codec, pins[i], cb);
4230e6feb5d0STakashi Iwai else
4231e6feb5d0STakashi Iwai set_path_power(codec, pins[i], true, -1);
4232e6feb5d0STakashi Iwai }
4233e6feb5d0STakashi Iwai }
4234e6feb5d0STakashi Iwai
4235e6feb5d0STakashi Iwai /* enabled power callback to each available I/O pin with jack detections;
4236e6feb5d0STakashi Iwai * the digital I/O pins are excluded because of the unreliable detectsion
4237e6feb5d0STakashi Iwai */
add_all_pin_power_ctls(struct hda_codec * codec,bool on)4238e6feb5d0STakashi Iwai static void add_all_pin_power_ctls(struct hda_codec *codec, bool on)
4239e6feb5d0STakashi Iwai {
4240e6feb5d0STakashi Iwai struct hda_gen_spec *spec = codec->spec;
4241e6feb5d0STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg;
4242e6feb5d0STakashi Iwai int i;
4243e6feb5d0STakashi Iwai
4244967b1307STakashi Iwai if (!codec->power_save_node)
4245e6feb5d0STakashi Iwai return;
4246e6feb5d0STakashi Iwai add_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins, on);
4247e6feb5d0STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT)
4248e6feb5d0STakashi Iwai add_pin_power_ctls(codec, cfg->hp_outs, cfg->hp_pins, on);
4249e6feb5d0STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
4250e6feb5d0STakashi Iwai add_pin_power_ctls(codec, cfg->speaker_outs, cfg->speaker_pins, on);
4251e6feb5d0STakashi Iwai for (i = 0; i < cfg->num_inputs; i++)
4252e6feb5d0STakashi Iwai add_pin_power_ctls(codec, 1, &cfg->inputs[i].pin, on);
4253e6feb5d0STakashi Iwai }
4254e6feb5d0STakashi Iwai
4255e6feb5d0STakashi Iwai /* sync path power up/down with the jack states of given pins */
sync_pin_power_ctls(struct hda_codec * codec,int num_pins,const hda_nid_t * pins)4256e6feb5d0STakashi Iwai static void sync_pin_power_ctls(struct hda_codec *codec, int num_pins,
4257e6feb5d0STakashi Iwai const hda_nid_t *pins)
4258e6feb5d0STakashi Iwai {
4259e6feb5d0STakashi Iwai int i;
4260e6feb5d0STakashi Iwai
4261e6feb5d0STakashi Iwai for (i = 0; i < num_pins && pins[i]; i++)
4262e6feb5d0STakashi Iwai if (is_jack_detectable(codec, pins[i]))
4263e6feb5d0STakashi Iwai set_pin_power_jack(codec, pins[i], -1);
4264e6feb5d0STakashi Iwai }
4265e6feb5d0STakashi Iwai
4266e6feb5d0STakashi Iwai /* sync path power up/down with pins; called at init and resume */
sync_all_pin_power_ctls(struct hda_codec * codec)4267e6feb5d0STakashi Iwai static void sync_all_pin_power_ctls(struct hda_codec *codec)
4268e6feb5d0STakashi Iwai {
4269e6feb5d0STakashi Iwai struct hda_gen_spec *spec = codec->spec;
4270e6feb5d0STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg;
4271e6feb5d0STakashi Iwai int i;
4272e6feb5d0STakashi Iwai
4273967b1307STakashi Iwai if (!codec->power_save_node)
4274e6feb5d0STakashi Iwai return;
4275e6feb5d0STakashi Iwai sync_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins);
4276e6feb5d0STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT)
4277e6feb5d0STakashi Iwai sync_pin_power_ctls(codec, cfg->hp_outs, cfg->hp_pins);
4278e6feb5d0STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
4279e6feb5d0STakashi Iwai sync_pin_power_ctls(codec, cfg->speaker_outs, cfg->speaker_pins);
4280e6feb5d0STakashi Iwai for (i = 0; i < cfg->num_inputs; i++)
4281e6feb5d0STakashi Iwai sync_pin_power_ctls(codec, 1, &cfg->inputs[i].pin);
4282e6feb5d0STakashi Iwai }
42831da177e4SLinus Torvalds
42845ccf835cSTakashi Iwai /* add fake paths if not present yet */
add_fake_paths(struct hda_codec * codec,hda_nid_t nid,int num_pins,const hda_nid_t * pins)42855ccf835cSTakashi Iwai static int add_fake_paths(struct hda_codec *codec, hda_nid_t nid,
42865ccf835cSTakashi Iwai int num_pins, const hda_nid_t *pins)
42875ccf835cSTakashi Iwai {
42885ccf835cSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
42895ccf835cSTakashi Iwai struct nid_path *path;
42905ccf835cSTakashi Iwai int i;
42915ccf835cSTakashi Iwai
42925ccf835cSTakashi Iwai for (i = 0; i < num_pins; i++) {
42935ccf835cSTakashi Iwai if (!pins[i])
42945ccf835cSTakashi Iwai break;
42955ccf835cSTakashi Iwai if (get_nid_path(codec, nid, pins[i], 0))
42965ccf835cSTakashi Iwai continue;
42975ccf835cSTakashi Iwai path = snd_array_new(&spec->paths);
42985ccf835cSTakashi Iwai if (!path)
42995ccf835cSTakashi Iwai return -ENOMEM;
43005ccf835cSTakashi Iwai memset(path, 0, sizeof(*path));
43015ccf835cSTakashi Iwai path->depth = 2;
43025ccf835cSTakashi Iwai path->path[0] = nid;
43035ccf835cSTakashi Iwai path->path[1] = pins[i];
43045ccf835cSTakashi Iwai path->active = true;
43055ccf835cSTakashi Iwai }
43065ccf835cSTakashi Iwai return 0;
43075ccf835cSTakashi Iwai }
43085ccf835cSTakashi Iwai
43095ccf835cSTakashi Iwai /* create fake paths to all outputs from beep */
add_fake_beep_paths(struct hda_codec * codec)43105ccf835cSTakashi Iwai static int add_fake_beep_paths(struct hda_codec *codec)
43115ccf835cSTakashi Iwai {
43125ccf835cSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
43135ccf835cSTakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg;
43145ccf835cSTakashi Iwai hda_nid_t nid = spec->beep_nid;
43155ccf835cSTakashi Iwai int err;
43165ccf835cSTakashi Iwai
4317967b1307STakashi Iwai if (!codec->power_save_node || !nid)
43185ccf835cSTakashi Iwai return 0;
43195ccf835cSTakashi Iwai err = add_fake_paths(codec, nid, cfg->line_outs, cfg->line_out_pins);
43205ccf835cSTakashi Iwai if (err < 0)
43215ccf835cSTakashi Iwai return err;
43225ccf835cSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
43235ccf835cSTakashi Iwai err = add_fake_paths(codec, nid, cfg->hp_outs, cfg->hp_pins);
43245ccf835cSTakashi Iwai if (err < 0)
43255ccf835cSTakashi Iwai return err;
43265ccf835cSTakashi Iwai }
43275ccf835cSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
43285ccf835cSTakashi Iwai err = add_fake_paths(codec, nid, cfg->speaker_outs,
43295ccf835cSTakashi Iwai cfg->speaker_pins);
43305ccf835cSTakashi Iwai if (err < 0)
43315ccf835cSTakashi Iwai return err;
43325ccf835cSTakashi Iwai }
43335ccf835cSTakashi Iwai return 0;
43345ccf835cSTakashi Iwai }
43355ccf835cSTakashi Iwai
43365ccf835cSTakashi Iwai /* power up/down beep widget and its output paths */
beep_power_hook(struct hda_beep * beep,bool on)43375ccf835cSTakashi Iwai static void beep_power_hook(struct hda_beep *beep, bool on)
43385ccf835cSTakashi Iwai {
43395ccf835cSTakashi Iwai set_path_power(beep->codec, beep->nid, -1, on);
43405ccf835cSTakashi Iwai }
43415ccf835cSTakashi Iwai
43426b275b14STakashi Iwai /**
43436b275b14STakashi Iwai * snd_hda_gen_fix_pin_power - Fix the power of the given pin widget to D0
43446b275b14STakashi Iwai * @codec: the HDA codec
43456b275b14STakashi Iwai * @pin: NID of pin to fix
43466b275b14STakashi Iwai */
snd_hda_gen_fix_pin_power(struct hda_codec * codec,hda_nid_t pin)43476b275b14STakashi Iwai int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin)
43486b275b14STakashi Iwai {
43496b275b14STakashi Iwai struct hda_gen_spec *spec = codec->spec;
43506b275b14STakashi Iwai struct nid_path *path;
43516b275b14STakashi Iwai
43526b275b14STakashi Iwai path = snd_array_new(&spec->paths);
43536b275b14STakashi Iwai if (!path)
43546b275b14STakashi Iwai return -ENOMEM;
43556b275b14STakashi Iwai memset(path, 0, sizeof(*path));
43566b275b14STakashi Iwai path->depth = 1;
43576b275b14STakashi Iwai path->path[0] = pin;
43586b275b14STakashi Iwai path->active = true;
43596b275b14STakashi Iwai path->pin_fixed = true;
43606b275b14STakashi Iwai path->stream_enabled = true;
43616b275b14STakashi Iwai return 0;
43626b275b14STakashi Iwai }
43636b275b14STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_fix_pin_power);
43646b275b14STakashi Iwai
43651da177e4SLinus Torvalds /*
4366352f7f91STakashi Iwai * Jack detections for HP auto-mute and mic-switch
43671da177e4SLinus Torvalds */
4368352f7f91STakashi Iwai
4369352f7f91STakashi Iwai /* check each pin in the given array; returns true if any of them is plugged */
detect_jacks(struct hda_codec * codec,int num_pins,const hda_nid_t * pins)4370caf3c043SMichał Mirosław static bool detect_jacks(struct hda_codec *codec, int num_pins, const hda_nid_t *pins)
43711da177e4SLinus Torvalds {
437260ea8ca2STakashi Iwai int i;
437360ea8ca2STakashi Iwai bool present = false;
43741da177e4SLinus Torvalds
4375352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) {
4376352f7f91STakashi Iwai hda_nid_t nid = pins[i];
4377352f7f91STakashi Iwai if (!nid)
4378352f7f91STakashi Iwai break;
43790b4df931STakashi Iwai /* don't detect pins retasked as inputs */
43800b4df931STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN)
43810b4df931STakashi Iwai continue;
438260ea8ca2STakashi Iwai if (snd_hda_jack_detect_state(codec, nid) == HDA_JACK_PRESENT)
438360ea8ca2STakashi Iwai present = true;
43841da177e4SLinus Torvalds }
4385352f7f91STakashi Iwai return present;
43861da177e4SLinus Torvalds }
43871da177e4SLinus Torvalds
4388352f7f91STakashi Iwai /* standard HP/line-out auto-mute helper */
do_automute(struct hda_codec * codec,int num_pins,const hda_nid_t * pins,int * paths,bool mute)4389caf3c043SMichał Mirosław static void do_automute(struct hda_codec *codec, int num_pins, const hda_nid_t *pins,
4390e80c60f3STakashi Iwai int *paths, bool mute)
43911da177e4SLinus Torvalds {
4392352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
4393352f7f91STakashi Iwai int i;
43941da177e4SLinus Torvalds
4395352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) {
4396352f7f91STakashi Iwai hda_nid_t nid = pins[i];
4397967303daSTakashi Iwai unsigned int val, oldval;
4398352f7f91STakashi Iwai if (!nid)
4399352f7f91STakashi Iwai break;
44007eebffd3STakashi Iwai
4401e6feb5d0STakashi Iwai oldval = snd_hda_codec_get_pin_target(codec, nid);
4402e6feb5d0STakashi Iwai if (oldval & PIN_IN)
4403e6feb5d0STakashi Iwai continue; /* no mute for inputs */
4404e6feb5d0STakashi Iwai
44057eebffd3STakashi Iwai if (spec->auto_mute_via_amp) {
4406e80c60f3STakashi Iwai struct nid_path *path;
4407e80c60f3STakashi Iwai hda_nid_t mute_nid;
4408e80c60f3STakashi Iwai
4409e80c60f3STakashi Iwai path = snd_hda_get_path_from_idx(codec, paths[i]);
4410e80c60f3STakashi Iwai if (!path)
4411e80c60f3STakashi Iwai continue;
4412e80c60f3STakashi Iwai mute_nid = get_amp_nid_(path->ctls[NID_PATH_MUTE_CTL]);
4413e80c60f3STakashi Iwai if (!mute_nid)
4414e80c60f3STakashi Iwai continue;
44157eebffd3STakashi Iwai if (mute)
4416e80c60f3STakashi Iwai spec->mute_bits |= (1ULL << mute_nid);
44177eebffd3STakashi Iwai else
4418e80c60f3STakashi Iwai spec->mute_bits &= ~(1ULL << mute_nid);
44197eebffd3STakashi Iwai continue;
4420e6feb5d0STakashi Iwai } else {
4421352f7f91STakashi Iwai /* don't reset VREF value in case it's controlling
4422352f7f91STakashi Iwai * the amp (see alc861_fixup_asus_amp_vref_0f())
4423352f7f91STakashi Iwai */
44242c12c30dSTakashi Iwai if (spec->keep_vref_in_automute)
4425967303daSTakashi Iwai val = oldval & ~PIN_HP;
44262c12c30dSTakashi Iwai else
4427352f7f91STakashi Iwai val = 0;
44282c12c30dSTakashi Iwai if (!mute)
4429967303daSTakashi Iwai val |= oldval;
4430e6feb5d0STakashi Iwai /* here we call update_pin_ctl() so that the pinctl is
4431e6feb5d0STakashi Iwai * changed without changing the pinctl target value;
4432e6feb5d0STakashi Iwai * the original target value will be still referred at
4433e6feb5d0STakashi Iwai * the init / resume again
44342c12c30dSTakashi Iwai */
44352c12c30dSTakashi Iwai update_pin_ctl(codec, nid, val);
4436e6feb5d0STakashi Iwai }
4437e6feb5d0STakashi Iwai
4438d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, !mute);
4439967b1307STakashi Iwai if (codec->power_save_node) {
4440e6feb5d0STakashi Iwai bool on = !mute;
4441e6feb5d0STakashi Iwai if (on)
4442d5ac0100STakashi Iwai on = detect_pin_state(codec, nid);
4443e6feb5d0STakashi Iwai set_path_power(codec, nid, on, -1);
4444e6feb5d0STakashi Iwai }
4445352f7f91STakashi Iwai }
4446352f7f91STakashi Iwai }
44471da177e4SLinus Torvalds
4448dda42bd0STakashi Iwai /**
4449dda42bd0STakashi Iwai * snd_hda_gen_update_outputs - Toggle outputs muting
4450dda42bd0STakashi Iwai * @codec: the HDA codec
4451dda42bd0STakashi Iwai *
4452dda42bd0STakashi Iwai * Update the mute status of all outputs based on the current jack states.
4453dda42bd0STakashi Iwai */
snd_hda_gen_update_outputs(struct hda_codec * codec)44545d550e15STakashi Iwai void snd_hda_gen_update_outputs(struct hda_codec *codec)
4455352f7f91STakashi Iwai {
4456352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
4457e80c60f3STakashi Iwai int *paths;
4458352f7f91STakashi Iwai int on;
4459352f7f91STakashi Iwai
4460352f7f91STakashi Iwai /* Control HP pins/amps depending on master_mute state;
4461352f7f91STakashi Iwai * in general, HP pins/amps control should be enabled in all cases,
4462352f7f91STakashi Iwai * but currently set only for master_mute, just to be safe
4463352f7f91STakashi Iwai */
4464e80c60f3STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
4465e80c60f3STakashi Iwai paths = spec->out_paths;
4466e80c60f3STakashi Iwai else
4467e80c60f3STakashi Iwai paths = spec->hp_paths;
4468352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
4469e80c60f3STakashi Iwai spec->autocfg.hp_pins, paths, spec->master_mute);
4470352f7f91STakashi Iwai
4471352f7f91STakashi Iwai if (!spec->automute_speaker)
4472352f7f91STakashi Iwai on = 0;
4473352f7f91STakashi Iwai else
4474352f7f91STakashi Iwai on = spec->hp_jack_present | spec->line_jack_present;
4475352f7f91STakashi Iwai on |= spec->master_mute;
447647b9ddb8STakashi Iwai spec->speaker_muted = on;
4477e80c60f3STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
4478e80c60f3STakashi Iwai paths = spec->out_paths;
4479e80c60f3STakashi Iwai else
4480e80c60f3STakashi Iwai paths = spec->speaker_paths;
4481352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
4482e80c60f3STakashi Iwai spec->autocfg.speaker_pins, paths, on);
4483352f7f91STakashi Iwai
4484352f7f91STakashi Iwai /* toggle line-out mutes if needed, too */
4485352f7f91STakashi Iwai /* if LO is a copy of either HP or Speaker, don't need to handle it */
4486352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
4487352f7f91STakashi Iwai spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
4488352f7f91STakashi Iwai return;
4489352f7f91STakashi Iwai if (!spec->automute_lo)
4490352f7f91STakashi Iwai on = 0;
4491352f7f91STakashi Iwai else
4492352f7f91STakashi Iwai on = spec->hp_jack_present;
4493352f7f91STakashi Iwai on |= spec->master_mute;
449447b9ddb8STakashi Iwai spec->line_out_muted = on;
4495e80c60f3STakashi Iwai paths = spec->out_paths;
4496352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
4497e80c60f3STakashi Iwai spec->autocfg.line_out_pins, paths, on);
4498352f7f91STakashi Iwai }
44992698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_update_outputs);
4500352f7f91STakashi Iwai
call_update_outputs(struct hda_codec * codec)4501352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec)
4502352f7f91STakashi Iwai {
4503352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
4504352f7f91STakashi Iwai if (spec->automute_hook)
4505352f7f91STakashi Iwai spec->automute_hook(codec);
4506352f7f91STakashi Iwai else
45075d550e15STakashi Iwai snd_hda_gen_update_outputs(codec);
45087eebffd3STakashi Iwai
45099ab0cb30STakashi Iwai /* sync the whole vmaster followers to reflect the new auto-mute status */
45107eebffd3STakashi Iwai if (spec->auto_mute_via_amp && !codec->bus->shutdown)
45117eebffd3STakashi Iwai snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false);
4512352f7f91STakashi Iwai }
4513352f7f91STakashi Iwai
4514dda42bd0STakashi Iwai /**
4515dda42bd0STakashi Iwai * snd_hda_gen_hp_automute - standard HP-automute helper
4516dda42bd0STakashi Iwai * @codec: the HDA codec
4517dda42bd0STakashi Iwai * @jack: jack object, NULL for the whole
4518dda42bd0STakashi Iwai */
snd_hda_gen_hp_automute(struct hda_codec * codec,struct hda_jack_callback * jack)45191a4f69d5STakashi Iwai void snd_hda_gen_hp_automute(struct hda_codec *codec,
45201a4f69d5STakashi Iwai struct hda_jack_callback *jack)
4521352f7f91STakashi Iwai {
4522352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
452392603c59STakashi Iwai hda_nid_t *pins = spec->autocfg.hp_pins;
452492603c59STakashi Iwai int num_pins = ARRAY_SIZE(spec->autocfg.hp_pins);
4525352f7f91STakashi Iwai
452692603c59STakashi Iwai /* No detection for the first HP jack during indep-HP mode */
452792603c59STakashi Iwai if (spec->indep_hp_enabled) {
452892603c59STakashi Iwai pins++;
452992603c59STakashi Iwai num_pins--;
453092603c59STakashi Iwai }
453192603c59STakashi Iwai
453292603c59STakashi Iwai spec->hp_jack_present = detect_jacks(codec, num_pins, pins);
4533352f7f91STakashi Iwai if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo))
4534352f7f91STakashi Iwai return;
4535352f7f91STakashi Iwai call_update_outputs(codec);
4536352f7f91STakashi Iwai }
45372698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_hp_automute);
4538352f7f91STakashi Iwai
4539dda42bd0STakashi Iwai /**
4540dda42bd0STakashi Iwai * snd_hda_gen_line_automute - standard line-out-automute helper
4541dda42bd0STakashi Iwai * @codec: the HDA codec
4542dda42bd0STakashi Iwai * @jack: jack object, NULL for the whole
4543dda42bd0STakashi Iwai */
snd_hda_gen_line_automute(struct hda_codec * codec,struct hda_jack_callback * jack)45441a4f69d5STakashi Iwai void snd_hda_gen_line_automute(struct hda_codec *codec,
45451a4f69d5STakashi Iwai struct hda_jack_callback *jack)
4546352f7f91STakashi Iwai {
4547352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
4548352f7f91STakashi Iwai
4549352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
4550352f7f91STakashi Iwai return;
4551352f7f91STakashi Iwai /* check LO jack only when it's different from HP */
4552352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0])
4553352f7f91STakashi Iwai return;
4554352f7f91STakashi Iwai
4555352f7f91STakashi Iwai spec->line_jack_present =
4556352f7f91STakashi Iwai detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
4557352f7f91STakashi Iwai spec->autocfg.line_out_pins);
4558352f7f91STakashi Iwai if (!spec->automute_speaker || !spec->detect_lo)
4559352f7f91STakashi Iwai return;
4560352f7f91STakashi Iwai call_update_outputs(codec);
4561352f7f91STakashi Iwai }
45622698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_line_automute);
4563352f7f91STakashi Iwai
4564dda42bd0STakashi Iwai /**
4565dda42bd0STakashi Iwai * snd_hda_gen_mic_autoswitch - standard mic auto-switch helper
4566dda42bd0STakashi Iwai * @codec: the HDA codec
4567dda42bd0STakashi Iwai * @jack: jack object, NULL for the whole
4568dda42bd0STakashi Iwai */
snd_hda_gen_mic_autoswitch(struct hda_codec * codec,struct hda_jack_callback * jack)45691a4f69d5STakashi Iwai void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
45701a4f69d5STakashi Iwai struct hda_jack_callback *jack)
4571352f7f91STakashi Iwai {
4572352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
4573352f7f91STakashi Iwai int i;
4574352f7f91STakashi Iwai
4575352f7f91STakashi Iwai if (!spec->auto_mic)
4576352f7f91STakashi Iwai return;
4577352f7f91STakashi Iwai
4578352f7f91STakashi Iwai for (i = spec->am_num_entries - 1; i > 0; i--) {
45790b4df931STakashi Iwai hda_nid_t pin = spec->am_entry[i].pin;
45800b4df931STakashi Iwai /* don't detect pins retasked as outputs */
45810b4df931STakashi Iwai if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN)
45820b4df931STakashi Iwai continue;
458360ea8ca2STakashi Iwai if (snd_hda_jack_detect_state(codec, pin) == HDA_JACK_PRESENT) {
4584352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[i].idx);
4585352f7f91STakashi Iwai return;
4586352f7f91STakashi Iwai }
4587352f7f91STakashi Iwai }
4588352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[0].idx);
45891da177e4SLinus Torvalds }
45902698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_mic_autoswitch);
45911da177e4SLinus Torvalds
459277afe0e9STakashi Iwai /* call appropriate hooks */
call_hp_automute(struct hda_codec * codec,struct hda_jack_callback * jack)45931a4f69d5STakashi Iwai static void call_hp_automute(struct hda_codec *codec,
45941a4f69d5STakashi Iwai struct hda_jack_callback *jack)
459577afe0e9STakashi Iwai {
459677afe0e9STakashi Iwai struct hda_gen_spec *spec = codec->spec;
459777afe0e9STakashi Iwai if (spec->hp_automute_hook)
459877afe0e9STakashi Iwai spec->hp_automute_hook(codec, jack);
459977afe0e9STakashi Iwai else
460077afe0e9STakashi Iwai snd_hda_gen_hp_automute(codec, jack);
460177afe0e9STakashi Iwai }
460277afe0e9STakashi Iwai
call_line_automute(struct hda_codec * codec,struct hda_jack_callback * jack)460377afe0e9STakashi Iwai static void call_line_automute(struct hda_codec *codec,
46041a4f69d5STakashi Iwai struct hda_jack_callback *jack)
460577afe0e9STakashi Iwai {
460677afe0e9STakashi Iwai struct hda_gen_spec *spec = codec->spec;
460777afe0e9STakashi Iwai if (spec->line_automute_hook)
460877afe0e9STakashi Iwai spec->line_automute_hook(codec, jack);
460977afe0e9STakashi Iwai else
461077afe0e9STakashi Iwai snd_hda_gen_line_automute(codec, jack);
461177afe0e9STakashi Iwai }
461277afe0e9STakashi Iwai
call_mic_autoswitch(struct hda_codec * codec,struct hda_jack_callback * jack)461377afe0e9STakashi Iwai static void call_mic_autoswitch(struct hda_codec *codec,
46141a4f69d5STakashi Iwai struct hda_jack_callback *jack)
461577afe0e9STakashi Iwai {
461677afe0e9STakashi Iwai struct hda_gen_spec *spec = codec->spec;
461777afe0e9STakashi Iwai if (spec->mic_autoswitch_hook)
461877afe0e9STakashi Iwai spec->mic_autoswitch_hook(codec, jack);
461977afe0e9STakashi Iwai else
462077afe0e9STakashi Iwai snd_hda_gen_mic_autoswitch(codec, jack);
462177afe0e9STakashi Iwai }
462277afe0e9STakashi Iwai
4623963afde9STakashi Iwai /* update jack retasking */
update_automute_all(struct hda_codec * codec)4624963afde9STakashi Iwai static void update_automute_all(struct hda_codec *codec)
4625963afde9STakashi Iwai {
4626963afde9STakashi Iwai call_hp_automute(codec, NULL);
4627963afde9STakashi Iwai call_line_automute(codec, NULL);
4628963afde9STakashi Iwai call_mic_autoswitch(codec, NULL);
4629963afde9STakashi Iwai }
4630963afde9STakashi Iwai
46311da177e4SLinus Torvalds /*
4632352f7f91STakashi Iwai * Auto-Mute mode mixer enum support
46331da177e4SLinus Torvalds */
automute_mode_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)4634352f7f91STakashi Iwai static int automute_mode_info(struct snd_kcontrol *kcontrol,
4635352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo)
4636352f7f91STakashi Iwai {
4637352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4638352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
4639352f7f91STakashi Iwai static const char * const texts3[] = {
4640352f7f91STakashi Iwai "Disabled", "Speaker Only", "Line Out+Speaker"
46411da177e4SLinus Torvalds };
46421da177e4SLinus Torvalds
4643352f7f91STakashi Iwai if (spec->automute_speaker_possible && spec->automute_lo_possible)
4644352f7f91STakashi Iwai return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
4645352f7f91STakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo);
4646352f7f91STakashi Iwai }
4647352f7f91STakashi Iwai
automute_mode_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4648352f7f91STakashi Iwai static int automute_mode_get(struct snd_kcontrol *kcontrol,
4649352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol)
4650352f7f91STakashi Iwai {
4651352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4652352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
4653352f7f91STakashi Iwai unsigned int val = 0;
4654352f7f91STakashi Iwai if (spec->automute_speaker)
4655352f7f91STakashi Iwai val++;
4656352f7f91STakashi Iwai if (spec->automute_lo)
4657352f7f91STakashi Iwai val++;
4658352f7f91STakashi Iwai
4659352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = val;
4660352f7f91STakashi Iwai return 0;
4661352f7f91STakashi Iwai }
4662352f7f91STakashi Iwai
automute_mode_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4663352f7f91STakashi Iwai static int automute_mode_put(struct snd_kcontrol *kcontrol,
4664352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol)
4665352f7f91STakashi Iwai {
4666352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4667352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
4668352f7f91STakashi Iwai
4669352f7f91STakashi Iwai switch (ucontrol->value.enumerated.item[0]) {
4670352f7f91STakashi Iwai case 0:
4671352f7f91STakashi Iwai if (!spec->automute_speaker && !spec->automute_lo)
4672352f7f91STakashi Iwai return 0;
4673352f7f91STakashi Iwai spec->automute_speaker = 0;
4674352f7f91STakashi Iwai spec->automute_lo = 0;
4675352f7f91STakashi Iwai break;
4676352f7f91STakashi Iwai case 1:
4677352f7f91STakashi Iwai if (spec->automute_speaker_possible) {
4678352f7f91STakashi Iwai if (!spec->automute_lo && spec->automute_speaker)
4679352f7f91STakashi Iwai return 0;
4680352f7f91STakashi Iwai spec->automute_speaker = 1;
4681352f7f91STakashi Iwai spec->automute_lo = 0;
4682352f7f91STakashi Iwai } else if (spec->automute_lo_possible) {
4683352f7f91STakashi Iwai if (spec->automute_lo)
4684352f7f91STakashi Iwai return 0;
4685352f7f91STakashi Iwai spec->automute_lo = 1;
4686352f7f91STakashi Iwai } else
4687352f7f91STakashi Iwai return -EINVAL;
4688352f7f91STakashi Iwai break;
4689352f7f91STakashi Iwai case 2:
4690352f7f91STakashi Iwai if (!spec->automute_lo_possible || !spec->automute_speaker_possible)
4691352f7f91STakashi Iwai return -EINVAL;
4692352f7f91STakashi Iwai if (spec->automute_speaker && spec->automute_lo)
4693352f7f91STakashi Iwai return 0;
4694352f7f91STakashi Iwai spec->automute_speaker = 1;
4695352f7f91STakashi Iwai spec->automute_lo = 1;
4696352f7f91STakashi Iwai break;
4697352f7f91STakashi Iwai default:
4698352f7f91STakashi Iwai return -EINVAL;
4699352f7f91STakashi Iwai }
4700352f7f91STakashi Iwai call_update_outputs(codec);
4701352f7f91STakashi Iwai return 1;
4702352f7f91STakashi Iwai }
4703352f7f91STakashi Iwai
4704352f7f91STakashi Iwai static const struct snd_kcontrol_new automute_mode_enum = {
4705352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4706352f7f91STakashi Iwai .name = "Auto-Mute Mode",
4707352f7f91STakashi Iwai .info = automute_mode_info,
4708352f7f91STakashi Iwai .get = automute_mode_get,
4709352f7f91STakashi Iwai .put = automute_mode_put,
4710352f7f91STakashi Iwai };
4711352f7f91STakashi Iwai
add_automute_mode_enum(struct hda_codec * codec)4712352f7f91STakashi Iwai static int add_automute_mode_enum(struct hda_codec *codec)
4713352f7f91STakashi Iwai {
4714352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
4715352f7f91STakashi Iwai
471612c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &automute_mode_enum))
4717352f7f91STakashi Iwai return -ENOMEM;
4718352f7f91STakashi Iwai return 0;
4719352f7f91STakashi Iwai }
4720352f7f91STakashi Iwai
4721352f7f91STakashi Iwai /*
4722352f7f91STakashi Iwai * Check the availability of HP/line-out auto-mute;
4723352f7f91STakashi Iwai * Set up appropriately if really supported
4724352f7f91STakashi Iwai */
check_auto_mute_availability(struct hda_codec * codec)4725352f7f91STakashi Iwai static int check_auto_mute_availability(struct hda_codec *codec)
4726352f7f91STakashi Iwai {
4727352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
4728352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg;
4729352f7f91STakashi Iwai int present = 0;
4730352f7f91STakashi Iwai int i, err;
4731352f7f91STakashi Iwai
4732f72706beSTakashi Iwai if (spec->suppress_auto_mute)
4733f72706beSTakashi Iwai return 0;
4734f72706beSTakashi Iwai
4735352f7f91STakashi Iwai if (cfg->hp_pins[0])
4736352f7f91STakashi Iwai present++;
4737352f7f91STakashi Iwai if (cfg->line_out_pins[0])
4738352f7f91STakashi Iwai present++;
4739352f7f91STakashi Iwai if (cfg->speaker_pins[0])
4740352f7f91STakashi Iwai present++;
4741352f7f91STakashi Iwai if (present < 2) /* need two different output types */
4742352f7f91STakashi Iwai return 0;
4743352f7f91STakashi Iwai
4744352f7f91STakashi Iwai if (!cfg->speaker_pins[0] &&
4745352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
4746352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins,
4747352f7f91STakashi Iwai sizeof(cfg->speaker_pins));
4748352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs;
4749352f7f91STakashi Iwai }
4750352f7f91STakashi Iwai
4751352f7f91STakashi Iwai if (!cfg->hp_pins[0] &&
4752352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) {
4753352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins,
4754352f7f91STakashi Iwai sizeof(cfg->hp_pins));
4755352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs;
4756352f7f91STakashi Iwai }
4757352f7f91STakashi Iwai
4758352f7f91STakashi Iwai for (i = 0; i < cfg->hp_outs; i++) {
4759352f7f91STakashi Iwai hda_nid_t nid = cfg->hp_pins[i];
4760352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid))
4761352f7f91STakashi Iwai continue;
47624e76a883STakashi Iwai codec_dbg(codec, "Enable HP auto-muting on NID 0x%x\n", nid);
476362f949bfSTakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid,
476477afe0e9STakashi Iwai call_hp_automute);
4765352f7f91STakashi Iwai spec->detect_hp = 1;
4766352f7f91STakashi Iwai }
4767352f7f91STakashi Iwai
4768352f7f91STakashi Iwai if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) {
4769352f7f91STakashi Iwai if (cfg->speaker_outs)
4770352f7f91STakashi Iwai for (i = 0; i < cfg->line_outs; i++) {
4771352f7f91STakashi Iwai hda_nid_t nid = cfg->line_out_pins[i];
4772352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid))
4773352f7f91STakashi Iwai continue;
47744e76a883STakashi Iwai codec_dbg(codec, "Enable Line-Out auto-muting on NID 0x%x\n", nid);
4775352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid,
477677afe0e9STakashi Iwai call_line_automute);
4777352f7f91STakashi Iwai spec->detect_lo = 1;
4778352f7f91STakashi Iwai }
4779352f7f91STakashi Iwai spec->automute_lo_possible = spec->detect_hp;
4780352f7f91STakashi Iwai }
4781352f7f91STakashi Iwai
4782352f7f91STakashi Iwai spec->automute_speaker_possible = cfg->speaker_outs &&
4783352f7f91STakashi Iwai (spec->detect_hp || spec->detect_lo);
4784352f7f91STakashi Iwai
4785352f7f91STakashi Iwai spec->automute_lo = spec->automute_lo_possible;
4786352f7f91STakashi Iwai spec->automute_speaker = spec->automute_speaker_possible;
4787352f7f91STakashi Iwai
4788352f7f91STakashi Iwai if (spec->automute_speaker_possible || spec->automute_lo_possible) {
4789352f7f91STakashi Iwai /* create a control for automute mode */
4790352f7f91STakashi Iwai err = add_automute_mode_enum(codec);
4791352f7f91STakashi Iwai if (err < 0)
4792352f7f91STakashi Iwai return err;
4793352f7f91STakashi Iwai }
4794352f7f91STakashi Iwai return 0;
4795352f7f91STakashi Iwai }
4796352f7f91STakashi Iwai
4797352f7f91STakashi Iwai /* check whether all auto-mic pins are valid; setup indices if OK */
auto_mic_check_imux(struct hda_codec * codec)4798352f7f91STakashi Iwai static bool auto_mic_check_imux(struct hda_codec *codec)
4799352f7f91STakashi Iwai {
4800352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
4801352f7f91STakashi Iwai const struct hda_input_mux *imux;
4802352f7f91STakashi Iwai int i;
4803352f7f91STakashi Iwai
4804352f7f91STakashi Iwai imux = &spec->input_mux;
4805352f7f91STakashi Iwai for (i = 0; i < spec->am_num_entries; i++) {
4806352f7f91STakashi Iwai spec->am_entry[i].idx =
4807352f7f91STakashi Iwai find_idx_in_nid_list(spec->am_entry[i].pin,
4808352f7f91STakashi Iwai spec->imux_pins, imux->num_items);
4809352f7f91STakashi Iwai if (spec->am_entry[i].idx < 0)
4810352f7f91STakashi Iwai return false; /* no corresponding imux */
4811352f7f91STakashi Iwai }
4812352f7f91STakashi Iwai
4813352f7f91STakashi Iwai /* we don't need the jack detection for the first pin */
4814352f7f91STakashi Iwai for (i = 1; i < spec->am_num_entries; i++)
4815352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec,
4816352f7f91STakashi Iwai spec->am_entry[i].pin,
481777afe0e9STakashi Iwai call_mic_autoswitch);
4818352f7f91STakashi Iwai return true;
4819352f7f91STakashi Iwai }
4820352f7f91STakashi Iwai
compare_attr(const void * ap,const void * bp)4821352f7f91STakashi Iwai static int compare_attr(const void *ap, const void *bp)
4822352f7f91STakashi Iwai {
4823352f7f91STakashi Iwai const struct automic_entry *a = ap;
4824352f7f91STakashi Iwai const struct automic_entry *b = bp;
4825352f7f91STakashi Iwai return (int)(a->attr - b->attr);
4826352f7f91STakashi Iwai }
4827352f7f91STakashi Iwai
4828352f7f91STakashi Iwai /*
4829352f7f91STakashi Iwai * Check the availability of auto-mic switch;
4830352f7f91STakashi Iwai * Set up if really supported
4831352f7f91STakashi Iwai */
check_auto_mic_availability(struct hda_codec * codec)4832352f7f91STakashi Iwai static int check_auto_mic_availability(struct hda_codec *codec)
4833352f7f91STakashi Iwai {
4834352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
4835352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg;
4836352f7f91STakashi Iwai unsigned int types;
4837352f7f91STakashi Iwai int i, num_pins;
4838352f7f91STakashi Iwai
4839d12daf6fSTakashi Iwai if (spec->suppress_auto_mic)
4840d12daf6fSTakashi Iwai return 0;
4841d12daf6fSTakashi Iwai
4842352f7f91STakashi Iwai types = 0;
4843352f7f91STakashi Iwai num_pins = 0;
4844352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) {
4845352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin;
4846352f7f91STakashi Iwai unsigned int attr;
4847352f7f91STakashi Iwai attr = snd_hda_codec_get_pincfg(codec, nid);
4848352f7f91STakashi Iwai attr = snd_hda_get_input_pin_attr(attr);
4849352f7f91STakashi Iwai if (types & (1 << attr))
4850352f7f91STakashi Iwai return 0; /* already occupied */
4851352f7f91STakashi Iwai switch (attr) {
4852352f7f91STakashi Iwai case INPUT_PIN_ATTR_INT:
4853352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC)
4854352f7f91STakashi Iwai return 0; /* invalid type */
4855352f7f91STakashi Iwai break;
4856352f7f91STakashi Iwai case INPUT_PIN_ATTR_UNUSED:
4857352f7f91STakashi Iwai return 0; /* invalid entry */
4858352f7f91STakashi Iwai default:
4859352f7f91STakashi Iwai if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
4860352f7f91STakashi Iwai return 0; /* invalid type */
4861352f7f91STakashi Iwai if (!spec->line_in_auto_switch &&
4862352f7f91STakashi Iwai cfg->inputs[i].type != AUTO_PIN_MIC)
4863352f7f91STakashi Iwai return 0; /* only mic is allowed */
4864352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid))
4865352f7f91STakashi Iwai return 0; /* no unsol support */
4866352f7f91STakashi Iwai break;
4867352f7f91STakashi Iwai }
4868352f7f91STakashi Iwai if (num_pins >= MAX_AUTO_MIC_PINS)
4869352f7f91STakashi Iwai return 0;
4870352f7f91STakashi Iwai types |= (1 << attr);
4871352f7f91STakashi Iwai spec->am_entry[num_pins].pin = nid;
4872352f7f91STakashi Iwai spec->am_entry[num_pins].attr = attr;
4873352f7f91STakashi Iwai num_pins++;
4874352f7f91STakashi Iwai }
4875352f7f91STakashi Iwai
4876352f7f91STakashi Iwai if (num_pins < 2)
4877352f7f91STakashi Iwai return 0;
4878352f7f91STakashi Iwai
4879352f7f91STakashi Iwai spec->am_num_entries = num_pins;
4880352f7f91STakashi Iwai /* sort the am_entry in the order of attr so that the pin with a
4881352f7f91STakashi Iwai * higher attr will be selected when the jack is plugged.
4882352f7f91STakashi Iwai */
4883352f7f91STakashi Iwai sort(spec->am_entry, num_pins, sizeof(spec->am_entry[0]),
4884352f7f91STakashi Iwai compare_attr, NULL);
4885352f7f91STakashi Iwai
4886352f7f91STakashi Iwai if (!auto_mic_check_imux(codec))
4887352f7f91STakashi Iwai return 0;
4888352f7f91STakashi Iwai
4889352f7f91STakashi Iwai spec->auto_mic = 1;
4890352f7f91STakashi Iwai spec->num_adc_nids = 1;
4891352f7f91STakashi Iwai spec->cur_mux[0] = spec->am_entry[0].idx;
48924e76a883STakashi Iwai codec_dbg(codec, "Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
4893352f7f91STakashi Iwai spec->am_entry[0].pin,
4894352f7f91STakashi Iwai spec->am_entry[1].pin,
4895352f7f91STakashi Iwai spec->am_entry[2].pin);
4896352f7f91STakashi Iwai
4897352f7f91STakashi Iwai return 0;
4898352f7f91STakashi Iwai }
4899352f7f91STakashi Iwai
4900dda42bd0STakashi Iwai /**
4901dda42bd0STakashi Iwai * snd_hda_gen_path_power_filter - power_filter hook to make inactive widgets
4902dda42bd0STakashi Iwai * into power down
4903dda42bd0STakashi Iwai * @codec: the HDA codec
4904dda42bd0STakashi Iwai * @nid: NID to evalute
4905dda42bd0STakashi Iwai * @power_state: target power state
4906dda42bd0STakashi Iwai */
snd_hda_gen_path_power_filter(struct hda_codec * codec,hda_nid_t nid,unsigned int power_state)4907dfc6e469STakashi Iwai unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
490855196fffSTakashi Iwai hda_nid_t nid,
490955196fffSTakashi Iwai unsigned int power_state)
491055196fffSTakashi Iwai {
4911b6c09b3cSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
4912b6c09b3cSTakashi Iwai
4913b6c09b3cSTakashi Iwai if (!spec->power_down_unused && !codec->power_save_node)
4914b6c09b3cSTakashi Iwai return power_state;
49157639a06cSTakashi Iwai if (power_state != AC_PWRST_D0 || nid == codec->core.afg)
491655196fffSTakashi Iwai return power_state;
491755196fffSTakashi Iwai if (get_wcaps_type(get_wcaps(codec, nid)) >= AC_WID_POWER)
491855196fffSTakashi Iwai return power_state;
4919b1b9fbd0STakashi Iwai if (is_active_nid_for_any(codec, nid))
492055196fffSTakashi Iwai return power_state;
492155196fffSTakashi Iwai return AC_PWRST_D3;
492255196fffSTakashi Iwai }
4923dfc6e469STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_path_power_filter);
492455196fffSTakashi Iwai
4925ebb93c05STakashi Iwai /* mute all aamix inputs initially; parse up to the first leaves */
mute_all_mixer_nid(struct hda_codec * codec,hda_nid_t mix)4926ebb93c05STakashi Iwai static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix)
4927ebb93c05STakashi Iwai {
4928ebb93c05STakashi Iwai int i, nums;
4929ebb93c05STakashi Iwai const hda_nid_t *conn;
4930ebb93c05STakashi Iwai bool has_amp;
4931ebb93c05STakashi Iwai
4932ebb93c05STakashi Iwai nums = snd_hda_get_conn_list(codec, mix, &conn);
4933ebb93c05STakashi Iwai has_amp = nid_has_mute(codec, mix, HDA_INPUT);
4934ebb93c05STakashi Iwai for (i = 0; i < nums; i++) {
4935ebb93c05STakashi Iwai if (has_amp)
4936ef403edbSTakashi Iwai update_amp(codec, mix, HDA_INPUT, i,
4937ebb93c05STakashi Iwai 0xff, HDA_AMP_MUTE);
4938ebb93c05STakashi Iwai else if (nid_has_volume(codec, conn[i], HDA_OUTPUT))
4939ef403edbSTakashi Iwai update_amp(codec, conn[i], HDA_OUTPUT, 0,
4940ebb93c05STakashi Iwai 0xff, HDA_AMP_MUTE);
4941ebb93c05STakashi Iwai }
4942ebb93c05STakashi Iwai }
4943352f7f91STakashi Iwai
4944dda42bd0STakashi Iwai /**
4945e6feb5d0STakashi Iwai * snd_hda_gen_stream_pm - Stream power management callback
4946e6feb5d0STakashi Iwai * @codec: the HDA codec
4947e6feb5d0STakashi Iwai * @nid: audio widget
4948e6feb5d0STakashi Iwai * @on: power on/off flag
4949e6feb5d0STakashi Iwai *
4950967b1307STakashi Iwai * Set this in patch_ops.stream_pm. Only valid with power_save_node flag.
4951e6feb5d0STakashi Iwai */
snd_hda_gen_stream_pm(struct hda_codec * codec,hda_nid_t nid,bool on)4952e6feb5d0STakashi Iwai void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on)
4953e6feb5d0STakashi Iwai {
4954967b1307STakashi Iwai if (codec->power_save_node)
4955e6feb5d0STakashi Iwai set_path_power(codec, nid, -1, on);
4956e6feb5d0STakashi Iwai }
4957e6feb5d0STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_stream_pm);
4958e6feb5d0STakashi Iwai
49598f11fbe1STakashi Iwai /* forcibly mute the speaker output without caching; return true if updated */
force_mute_output_path(struct hda_codec * codec,hda_nid_t nid)49608f11fbe1STakashi Iwai static bool force_mute_output_path(struct hda_codec *codec, hda_nid_t nid)
49618f11fbe1STakashi Iwai {
49628f11fbe1STakashi Iwai if (!nid)
49638f11fbe1STakashi Iwai return false;
49648f11fbe1STakashi Iwai if (!nid_has_mute(codec, nid, HDA_OUTPUT))
49658f11fbe1STakashi Iwai return false; /* no mute, skip */
49668f11fbe1STakashi Iwai if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
49678f11fbe1STakashi Iwai snd_hda_codec_amp_read(codec, nid, 1, HDA_OUTPUT, 0) &
49688f11fbe1STakashi Iwai HDA_AMP_MUTE)
49698f11fbe1STakashi Iwai return false; /* both channels already muted, skip */
49708f11fbe1STakashi Iwai
49718f11fbe1STakashi Iwai /* direct amp update without caching */
49728f11fbe1STakashi Iwai snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
49738f11fbe1STakashi Iwai AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT |
49748f11fbe1STakashi Iwai AC_AMP_SET_RIGHT | HDA_AMP_MUTE);
49758f11fbe1STakashi Iwai return true;
49768f11fbe1STakashi Iwai }
49778f11fbe1STakashi Iwai
49788f11fbe1STakashi Iwai /**
49798f11fbe1STakashi Iwai * snd_hda_gen_shutup_speakers - Forcibly mute the speaker outputs
49808f11fbe1STakashi Iwai * @codec: the HDA codec
49818f11fbe1STakashi Iwai *
49828f11fbe1STakashi Iwai * Forcibly mute the speaker outputs, to be called at suspend or shutdown.
49838f11fbe1STakashi Iwai *
49848f11fbe1STakashi Iwai * The mute state done by this function isn't cached, hence the original state
49858f11fbe1STakashi Iwai * will be restored at resume.
49868f11fbe1STakashi Iwai *
49878f11fbe1STakashi Iwai * Return true if the mute state has been changed.
49888f11fbe1STakashi Iwai */
snd_hda_gen_shutup_speakers(struct hda_codec * codec)49898f11fbe1STakashi Iwai bool snd_hda_gen_shutup_speakers(struct hda_codec *codec)
49908f11fbe1STakashi Iwai {
49918f11fbe1STakashi Iwai struct hda_gen_spec *spec = codec->spec;
49928f11fbe1STakashi Iwai const int *paths;
49938f11fbe1STakashi Iwai const struct nid_path *path;
49948f11fbe1STakashi Iwai int i, p, num_paths;
49958f11fbe1STakashi Iwai bool updated = false;
49968f11fbe1STakashi Iwai
49978f11fbe1STakashi Iwai /* if already powered off, do nothing */
49988f11fbe1STakashi Iwai if (!snd_hdac_is_power_on(&codec->core))
49998f11fbe1STakashi Iwai return false;
50008f11fbe1STakashi Iwai
50018f11fbe1STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) {
50028f11fbe1STakashi Iwai paths = spec->out_paths;
50038f11fbe1STakashi Iwai num_paths = spec->autocfg.line_outs;
50048f11fbe1STakashi Iwai } else {
50058f11fbe1STakashi Iwai paths = spec->speaker_paths;
50068f11fbe1STakashi Iwai num_paths = spec->autocfg.speaker_outs;
50078f11fbe1STakashi Iwai }
50088f11fbe1STakashi Iwai
50098f11fbe1STakashi Iwai for (i = 0; i < num_paths; i++) {
50108f11fbe1STakashi Iwai path = snd_hda_get_path_from_idx(codec, paths[i]);
50118f11fbe1STakashi Iwai if (!path)
50128f11fbe1STakashi Iwai continue;
50138f11fbe1STakashi Iwai for (p = 0; p < path->depth; p++)
50148f11fbe1STakashi Iwai if (force_mute_output_path(codec, path->path[p]))
50158f11fbe1STakashi Iwai updated = true;
50168f11fbe1STakashi Iwai }
50178f11fbe1STakashi Iwai
50188f11fbe1STakashi Iwai return updated;
50198f11fbe1STakashi Iwai }
50208f11fbe1STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_shutup_speakers);
50218f11fbe1STakashi Iwai
5022e6feb5d0STakashi Iwai /**
5023dda42bd0STakashi Iwai * snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and
5024dda42bd0STakashi Iwai * set up the hda_gen_spec
5025dda42bd0STakashi Iwai * @codec: the HDA codec
5026dda42bd0STakashi Iwai * @cfg: Parsed pin configuration
50279eb413e5STakashi Iwai *
50289eb413e5STakashi Iwai * return 1 if successful, 0 if the proper config is not found,
5029352f7f91STakashi Iwai * or a negative error code
5030352f7f91STakashi Iwai */
snd_hda_gen_parse_auto_config(struct hda_codec * codec,struct auto_pin_cfg * cfg)5031352f7f91STakashi Iwai int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
50329eb413e5STakashi Iwai struct auto_pin_cfg *cfg)
5033352f7f91STakashi Iwai {
5034352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5035352f7f91STakashi Iwai int err;
5036352f7f91STakashi Iwai
50371c70a583STakashi Iwai parse_user_hints(codec);
50381c70a583STakashi Iwai
5039e65bf997SJaroslav Kysela if (spec->vmaster_mute_led || spec->mic_mute_led)
5040e65bf997SJaroslav Kysela snd_ctl_led_request();
5041e65bf997SJaroslav Kysela
5042e4a395e7STakashi Iwai if (spec->mixer_nid && !spec->mixer_merge_nid)
5043e4a395e7STakashi Iwai spec->mixer_merge_nid = spec->mixer_nid;
5044e4a395e7STakashi Iwai
50459eb413e5STakashi Iwai if (cfg != &spec->autocfg) {
50469eb413e5STakashi Iwai spec->autocfg = *cfg;
50479eb413e5STakashi Iwai cfg = &spec->autocfg;
50489eb413e5STakashi Iwai }
50499eb413e5STakashi Iwai
505098bd1115STakashi Iwai if (!spec->main_out_badness)
505198bd1115STakashi Iwai spec->main_out_badness = &hda_main_out_badness;
505298bd1115STakashi Iwai if (!spec->extra_out_badness)
505398bd1115STakashi Iwai spec->extra_out_badness = &hda_extra_out_badness;
505498bd1115STakashi Iwai
50556fc4cb97SDavid Henningsson fill_all_dac_nids(codec);
50566fc4cb97SDavid Henningsson
5057352f7f91STakashi Iwai if (!cfg->line_outs) {
5058352f7f91STakashi Iwai if (cfg->dig_outs || cfg->dig_in_pin) {
5059352f7f91STakashi Iwai spec->multiout.max_channels = 2;
5060352f7f91STakashi Iwai spec->no_analog = 1;
5061352f7f91STakashi Iwai goto dig_only;
5062352f7f91STakashi Iwai }
5063c9e4bdb7STakashi Iwai if (!cfg->num_inputs && !cfg->dig_in_pin)
5064352f7f91STakashi Iwai return 0; /* can't find valid BIOS pin config */
5065352f7f91STakashi Iwai }
5066352f7f91STakashi Iwai
5067352f7f91STakashi Iwai if (!spec->no_primary_hp &&
5068352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
5069352f7f91STakashi Iwai cfg->line_outs <= cfg->hp_outs) {
5070352f7f91STakashi Iwai /* use HP as primary out */
5071352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs;
5072352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins,
5073352f7f91STakashi Iwai sizeof(cfg->speaker_pins));
5074352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs;
5075352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins));
5076352f7f91STakashi Iwai cfg->hp_outs = 0;
5077352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
5078352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT;
5079352f7f91STakashi Iwai }
5080352f7f91STakashi Iwai
5081352f7f91STakashi Iwai err = parse_output_paths(codec);
5082352f7f91STakashi Iwai if (err < 0)
5083352f7f91STakashi Iwai return err;
5084352f7f91STakashi Iwai err = create_multi_channel_mode(codec);
5085352f7f91STakashi Iwai if (err < 0)
5086352f7f91STakashi Iwai return err;
5087352f7f91STakashi Iwai err = create_multi_out_ctls(codec, cfg);
5088352f7f91STakashi Iwai if (err < 0)
5089352f7f91STakashi Iwai return err;
5090352f7f91STakashi Iwai err = create_hp_out_ctls(codec);
5091352f7f91STakashi Iwai if (err < 0)
5092352f7f91STakashi Iwai return err;
5093352f7f91STakashi Iwai err = create_speaker_out_ctls(codec);
5094352f7f91STakashi Iwai if (err < 0)
5095352f7f91STakashi Iwai return err;
509638cf6f1aSTakashi Iwai err = create_indep_hp_ctls(codec);
509738cf6f1aSTakashi Iwai if (err < 0)
509838cf6f1aSTakashi Iwai return err;
5099c30aa7b2STakashi Iwai err = create_loopback_mixing_ctl(codec);
5100c30aa7b2STakashi Iwai if (err < 0)
5101c30aa7b2STakashi Iwai return err;
5102967303daSTakashi Iwai err = create_hp_mic(codec);
5103352f7f91STakashi Iwai if (err < 0)
5104352f7f91STakashi Iwai return err;
5105352f7f91STakashi Iwai err = create_input_ctls(codec);
5106352f7f91STakashi Iwai if (err < 0)
5107352f7f91STakashi Iwai return err;
5108352f7f91STakashi Iwai
5109e6feb5d0STakashi Iwai /* add power-down pin callbacks at first */
5110e6feb5d0STakashi Iwai add_all_pin_power_ctls(codec, false);
5111e6feb5d0STakashi Iwai
5112a07a949bSTakashi Iwai spec->const_channel_count = spec->ext_channel_count;
5113a07a949bSTakashi Iwai /* check the multiple speaker and headphone pins */
5114a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
5115a07a949bSTakashi Iwai spec->const_channel_count = max(spec->const_channel_count,
5116a07a949bSTakashi Iwai cfg->speaker_outs * 2);
5117a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT)
5118a07a949bSTakashi Iwai spec->const_channel_count = max(spec->const_channel_count,
5119a07a949bSTakashi Iwai cfg->hp_outs * 2);
5120352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count,
5121352f7f91STakashi Iwai spec->const_channel_count);
5122352f7f91STakashi Iwai
5123352f7f91STakashi Iwai err = check_auto_mute_availability(codec);
5124352f7f91STakashi Iwai if (err < 0)
5125352f7f91STakashi Iwai return err;
5126352f7f91STakashi Iwai
5127352f7f91STakashi Iwai err = check_dyn_adc_switch(codec);
5128352f7f91STakashi Iwai if (err < 0)
5129352f7f91STakashi Iwai return err;
5130352f7f91STakashi Iwai
5131352f7f91STakashi Iwai err = check_auto_mic_availability(codec);
5132352f7f91STakashi Iwai if (err < 0)
5133352f7f91STakashi Iwai return err;
5134352f7f91STakashi Iwai
5135f1e762ddSTakashi Iwai /* add stereo mix if available and not enabled yet */
5136f1e762ddSTakashi Iwai if (!spec->auto_mic && spec->mixer_nid &&
513774f14b36STakashi Iwai spec->add_stereo_mix_input == HDA_HINT_STEREO_MIX_AUTO &&
513874f14b36STakashi Iwai spec->input_mux.num_items > 1) {
5139f1e762ddSTakashi Iwai err = parse_capture_source(codec, spec->mixer_nid,
5140f1e762ddSTakashi Iwai CFG_IDX_MIX, spec->num_all_adcs,
5141f1e762ddSTakashi Iwai "Stereo Mix", 0);
5142f1e762ddSTakashi Iwai if (err < 0)
5143f1e762ddSTakashi Iwai return err;
5144f1e762ddSTakashi Iwai }
5145f1e762ddSTakashi Iwai
5146f1e762ddSTakashi Iwai
5147352f7f91STakashi Iwai err = create_capture_mixers(codec);
5148352f7f91STakashi Iwai if (err < 0)
5149352f7f91STakashi Iwai return err;
5150352f7f91STakashi Iwai
5151352f7f91STakashi Iwai err = parse_mic_boost(codec);
5152352f7f91STakashi Iwai if (err < 0)
5153352f7f91STakashi Iwai return err;
5154352f7f91STakashi Iwai
5155ced4cefcSTakashi Iwai /* create "Headphone Mic Jack Mode" if no input selection is
5156ced4cefcSTakashi Iwai * available (or user specifies add_jack_modes hint)
5157ced4cefcSTakashi Iwai */
5158ced4cefcSTakashi Iwai if (spec->hp_mic_pin &&
5159ced4cefcSTakashi Iwai (spec->auto_mic || spec->input_mux.num_items == 1 ||
5160ced4cefcSTakashi Iwai spec->add_jack_modes)) {
5161ced4cefcSTakashi Iwai err = create_hp_mic_jack_mode(codec, spec->hp_mic_pin);
5162ced4cefcSTakashi Iwai if (err < 0)
5163ced4cefcSTakashi Iwai return err;
5164ced4cefcSTakashi Iwai }
5165ced4cefcSTakashi Iwai
5166f811c3cfSTakashi Iwai if (spec->add_jack_modes) {
5167978e77e7STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
5168978e77e7STakashi Iwai err = create_out_jack_modes(codec, cfg->line_outs,
5169978e77e7STakashi Iwai cfg->line_out_pins);
5170978e77e7STakashi Iwai if (err < 0)
5171978e77e7STakashi Iwai return err;
5172978e77e7STakashi Iwai }
5173978e77e7STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
5174978e77e7STakashi Iwai err = create_out_jack_modes(codec, cfg->hp_outs,
5175978e77e7STakashi Iwai cfg->hp_pins);
5176978e77e7STakashi Iwai if (err < 0)
5177978e77e7STakashi Iwai return err;
5178978e77e7STakashi Iwai }
5179978e77e7STakashi Iwai }
5180978e77e7STakashi Iwai
5181e6feb5d0STakashi Iwai /* add power-up pin callbacks at last */
5182e6feb5d0STakashi Iwai add_all_pin_power_ctls(codec, true);
5183e6feb5d0STakashi Iwai
5184ebb93c05STakashi Iwai /* mute all aamix input initially */
5185ebb93c05STakashi Iwai if (spec->mixer_nid)
5186ebb93c05STakashi Iwai mute_all_mixer_nid(codec, spec->mixer_nid);
5187ebb93c05STakashi Iwai
5188352f7f91STakashi Iwai dig_only:
5189352f7f91STakashi Iwai parse_digital(codec);
5190352f7f91STakashi Iwai
519149fb1897STakashi Iwai if (spec->power_down_unused || codec->power_save_node) {
519224fef902STakashi Iwai if (!codec->power_filter)
519355196fffSTakashi Iwai codec->power_filter = snd_hda_gen_path_power_filter;
519449fb1897STakashi Iwai if (!codec->patch_ops.stream_pm)
519549fb1897STakashi Iwai codec->patch_ops.stream_pm = snd_hda_gen_stream_pm;
519649fb1897STakashi Iwai }
519755196fffSTakashi Iwai
51987504b6cdSTakashi Iwai if (!spec->no_analog && spec->beep_nid) {
51997504b6cdSTakashi Iwai err = snd_hda_attach_beep_device(codec, spec->beep_nid);
52007504b6cdSTakashi Iwai if (err < 0)
52017504b6cdSTakashi Iwai return err;
5202967b1307STakashi Iwai if (codec->beep && codec->power_save_node) {
52035ccf835cSTakashi Iwai err = add_fake_beep_paths(codec);
52045ccf835cSTakashi Iwai if (err < 0)
52055ccf835cSTakashi Iwai return err;
52065ccf835cSTakashi Iwai codec->beep->power_hook = beep_power_hook;
52075ccf835cSTakashi Iwai }
52087504b6cdSTakashi Iwai }
52097504b6cdSTakashi Iwai
5210352f7f91STakashi Iwai return 1;
5211352f7f91STakashi Iwai }
52122698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_parse_auto_config);
5213352f7f91STakashi Iwai
5214352f7f91STakashi Iwai
5215352f7f91STakashi Iwai /*
5216352f7f91STakashi Iwai * Build control elements
5217352f7f91STakashi Iwai */
5218352f7f91STakashi Iwai
52199ab0cb30STakashi Iwai /* follower controls for virtual master */
52209ab0cb30STakashi Iwai static const char * const follower_pfxs[] = {
5221352f7f91STakashi Iwai "Front", "Surround", "Center", "LFE", "Side",
5222352f7f91STakashi Iwai "Headphone", "Speaker", "Mono", "Line Out",
5223352f7f91STakashi Iwai "CLFE", "Bass Speaker", "PCM",
5224ee79c69aSTakashi Iwai "Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side",
5225ee79c69aSTakashi Iwai "Headphone Front", "Headphone Surround", "Headphone CLFE",
522603ad6a8cSDavid Henningsson "Headphone Side", "Headphone+LO", "Speaker+LO",
5227352f7f91STakashi Iwai NULL,
5228352f7f91STakashi Iwai };
5229352f7f91STakashi Iwai
5230dda42bd0STakashi Iwai /**
5231dda42bd0STakashi Iwai * snd_hda_gen_build_controls - Build controls from the parsed results
5232dda42bd0STakashi Iwai * @codec: the HDA codec
5233dda42bd0STakashi Iwai *
5234dda42bd0STakashi Iwai * Pass this to build_controls patch_ops.
5235dda42bd0STakashi Iwai */
snd_hda_gen_build_controls(struct hda_codec * codec)5236352f7f91STakashi Iwai int snd_hda_gen_build_controls(struct hda_codec *codec)
5237352f7f91STakashi Iwai {
5238352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5239352f7f91STakashi Iwai int err;
5240352f7f91STakashi Iwai
524136502d02STakashi Iwai if (spec->kctls.used) {
5242352f7f91STakashi Iwai err = snd_hda_add_new_ctls(codec, spec->kctls.list);
5243352f7f91STakashi Iwai if (err < 0)
5244352f7f91STakashi Iwai return err;
524536502d02STakashi Iwai }
5246352f7f91STakashi Iwai
5247352f7f91STakashi Iwai if (spec->multiout.dig_out_nid) {
5248352f7f91STakashi Iwai err = snd_hda_create_dig_out_ctls(codec,
5249352f7f91STakashi Iwai spec->multiout.dig_out_nid,
5250352f7f91STakashi Iwai spec->multiout.dig_out_nid,
5251bbbc7e85STakashi Iwai spec->pcm_rec[1]->pcm_type);
5252352f7f91STakashi Iwai if (err < 0)
5253352f7f91STakashi Iwai return err;
5254352f7f91STakashi Iwai if (!spec->no_analog) {
5255352f7f91STakashi Iwai err = snd_hda_create_spdif_share_sw(codec,
5256352f7f91STakashi Iwai &spec->multiout);
5257352f7f91STakashi Iwai if (err < 0)
5258352f7f91STakashi Iwai return err;
5259352f7f91STakashi Iwai spec->multiout.share_spdif = 1;
5260352f7f91STakashi Iwai }
5261352f7f91STakashi Iwai }
5262352f7f91STakashi Iwai if (spec->dig_in_nid) {
5263352f7f91STakashi Iwai err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
5264352f7f91STakashi Iwai if (err < 0)
5265352f7f91STakashi Iwai return err;
5266352f7f91STakashi Iwai }
5267352f7f91STakashi Iwai
5268352f7f91STakashi Iwai /* if we have no master control, let's create it */
52697480316cSTakashi Iwai if (!spec->no_analog && !spec->suppress_vmaster &&
5270352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
5271352f7f91STakashi Iwai err = snd_hda_add_vmaster(codec, "Master Playback Volume",
52729ab0cb30STakashi Iwai spec->vmaster_tlv, follower_pfxs,
5273e65bf997SJaroslav Kysela "Playback Volume", 0);
5274352f7f91STakashi Iwai if (err < 0)
5275352f7f91STakashi Iwai return err;
5276352f7f91STakashi Iwai }
52777480316cSTakashi Iwai if (!spec->no_analog && !spec->suppress_vmaster &&
5278352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
5279352f7f91STakashi Iwai err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
52809ab0cb30STakashi Iwai NULL, follower_pfxs,
5281e65bf997SJaroslav Kysela "Playback Switch", true,
5282e65bf997SJaroslav Kysela spec->vmaster_mute_led ?
5283e65bf997SJaroslav Kysela SNDRV_CTL_ELEM_ACCESS_SPK_LED : 0,
5284e65bf997SJaroslav Kysela &spec->vmaster_mute.sw_kctl);
5285352f7f91STakashi Iwai if (err < 0)
5286352f7f91STakashi Iwai return err;
5287b63eae0aSTakashi Iwai if (spec->vmaster_mute.hook) {
5288e65bf997SJaroslav Kysela snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute);
5289b63eae0aSTakashi Iwai snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
5290b63eae0aSTakashi Iwai }
5291352f7f91STakashi Iwai }
5292352f7f91STakashi Iwai
5293352f7f91STakashi Iwai free_kctls(spec); /* no longer needed */
5294352f7f91STakashi Iwai
5295352f7f91STakashi Iwai err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
5296352f7f91STakashi Iwai if (err < 0)
5297352f7f91STakashi Iwai return err;
5298352f7f91STakashi Iwai
5299352f7f91STakashi Iwai return 0;
5300352f7f91STakashi Iwai }
53012698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_build_controls);
5302352f7f91STakashi Iwai
5303352f7f91STakashi Iwai
5304352f7f91STakashi Iwai /*
5305352f7f91STakashi Iwai * PCM definitions
5306352f7f91STakashi Iwai */
5307352f7f91STakashi Iwai
call_pcm_playback_hook(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream,int action)5308e6b85f3cSTakashi Iwai static void call_pcm_playback_hook(struct hda_pcm_stream *hinfo,
5309e6b85f3cSTakashi Iwai struct hda_codec *codec,
5310e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream,
5311e6b85f3cSTakashi Iwai int action)
5312e6b85f3cSTakashi Iwai {
5313e6b85f3cSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
5314e6b85f3cSTakashi Iwai if (spec->pcm_playback_hook)
5315e6b85f3cSTakashi Iwai spec->pcm_playback_hook(hinfo, codec, substream, action);
5316e6b85f3cSTakashi Iwai }
5317e6b85f3cSTakashi Iwai
call_pcm_capture_hook(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream,int action)5318ac2e8736STakashi Iwai static void call_pcm_capture_hook(struct hda_pcm_stream *hinfo,
5319ac2e8736STakashi Iwai struct hda_codec *codec,
5320ac2e8736STakashi Iwai struct snd_pcm_substream *substream,
5321ac2e8736STakashi Iwai int action)
5322ac2e8736STakashi Iwai {
5323ac2e8736STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5324ac2e8736STakashi Iwai if (spec->pcm_capture_hook)
5325ac2e8736STakashi Iwai spec->pcm_capture_hook(hinfo, codec, substream, action);
5326ac2e8736STakashi Iwai }
5327ac2e8736STakashi Iwai
5328352f7f91STakashi Iwai /*
5329352f7f91STakashi Iwai * Analog playback callbacks
5330352f7f91STakashi Iwai */
playback_pcm_open(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5331352f7f91STakashi Iwai static int playback_pcm_open(struct hda_pcm_stream *hinfo,
5332352f7f91STakashi Iwai struct hda_codec *codec,
5333352f7f91STakashi Iwai struct snd_pcm_substream *substream)
5334352f7f91STakashi Iwai {
5335352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
533638cf6f1aSTakashi Iwai int err;
533738cf6f1aSTakashi Iwai
533838cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex);
533938cf6f1aSTakashi Iwai err = snd_hda_multi_out_analog_open(codec,
534038cf6f1aSTakashi Iwai &spec->multiout, substream,
5341352f7f91STakashi Iwai hinfo);
5342e6b85f3cSTakashi Iwai if (!err) {
534338cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_MULTI_OUT;
5344e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream,
5345e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_OPEN);
5346e6b85f3cSTakashi Iwai }
534738cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex);
534838cf6f1aSTakashi Iwai return err;
5349352f7f91STakashi Iwai }
5350352f7f91STakashi Iwai
playback_pcm_prepare(struct hda_pcm_stream * hinfo,struct hda_codec * codec,unsigned int stream_tag,unsigned int format,struct snd_pcm_substream * substream)5351352f7f91STakashi Iwai static int playback_pcm_prepare(struct hda_pcm_stream *hinfo,
535297ec558aSTakashi Iwai struct hda_codec *codec,
535397ec558aSTakashi Iwai unsigned int stream_tag,
535497ec558aSTakashi Iwai unsigned int format,
535597ec558aSTakashi Iwai struct snd_pcm_substream *substream)
535697ec558aSTakashi Iwai {
5357352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5358e6b85f3cSTakashi Iwai int err;
5359e6b85f3cSTakashi Iwai
5360e6b85f3cSTakashi Iwai err = snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
5361352f7f91STakashi Iwai stream_tag, format, substream);
5362e6b85f3cSTakashi Iwai if (!err)
5363e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream,
5364e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_PREPARE);
5365e6b85f3cSTakashi Iwai return err;
5366352f7f91STakashi Iwai }
536797ec558aSTakashi Iwai
playback_pcm_cleanup(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5368352f7f91STakashi Iwai static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
5369352f7f91STakashi Iwai struct hda_codec *codec,
5370352f7f91STakashi Iwai struct snd_pcm_substream *substream)
5371352f7f91STakashi Iwai {
5372352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5373e6b85f3cSTakashi Iwai int err;
5374e6b85f3cSTakashi Iwai
5375e6b85f3cSTakashi Iwai err = snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
5376e6b85f3cSTakashi Iwai if (!err)
5377e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream,
5378e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLEANUP);
5379e6b85f3cSTakashi Iwai return err;
5380352f7f91STakashi Iwai }
5381352f7f91STakashi Iwai
playback_pcm_close(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)538238cf6f1aSTakashi Iwai static int playback_pcm_close(struct hda_pcm_stream *hinfo,
538338cf6f1aSTakashi Iwai struct hda_codec *codec,
538438cf6f1aSTakashi Iwai struct snd_pcm_substream *substream)
538538cf6f1aSTakashi Iwai {
538638cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
538738cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex);
538838cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_MULTI_OUT);
5389e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream,
5390e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLOSE);
539138cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex);
539238cf6f1aSTakashi Iwai return 0;
539338cf6f1aSTakashi Iwai }
539438cf6f1aSTakashi Iwai
capture_pcm_open(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5395ac2e8736STakashi Iwai static int capture_pcm_open(struct hda_pcm_stream *hinfo,
5396ac2e8736STakashi Iwai struct hda_codec *codec,
5397ac2e8736STakashi Iwai struct snd_pcm_substream *substream)
5398ac2e8736STakashi Iwai {
5399ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_OPEN);
5400ac2e8736STakashi Iwai return 0;
5401ac2e8736STakashi Iwai }
5402ac2e8736STakashi Iwai
capture_pcm_prepare(struct hda_pcm_stream * hinfo,struct hda_codec * codec,unsigned int stream_tag,unsigned int format,struct snd_pcm_substream * substream)5403ac2e8736STakashi Iwai static int capture_pcm_prepare(struct hda_pcm_stream *hinfo,
5404ac2e8736STakashi Iwai struct hda_codec *codec,
5405ac2e8736STakashi Iwai unsigned int stream_tag,
5406ac2e8736STakashi Iwai unsigned int format,
5407ac2e8736STakashi Iwai struct snd_pcm_substream *substream)
5408ac2e8736STakashi Iwai {
5409ac2e8736STakashi Iwai snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
5410ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream,
5411ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_PREPARE);
5412ac2e8736STakashi Iwai return 0;
5413ac2e8736STakashi Iwai }
5414ac2e8736STakashi Iwai
capture_pcm_cleanup(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5415ac2e8736STakashi Iwai static int capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
5416ac2e8736STakashi Iwai struct hda_codec *codec,
5417ac2e8736STakashi Iwai struct snd_pcm_substream *substream)
5418ac2e8736STakashi Iwai {
5419ac2e8736STakashi Iwai snd_hda_codec_cleanup_stream(codec, hinfo->nid);
5420ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream,
5421ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_CLEANUP);
5422ac2e8736STakashi Iwai return 0;
5423ac2e8736STakashi Iwai }
5424ac2e8736STakashi Iwai
capture_pcm_close(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5425ac2e8736STakashi Iwai static int capture_pcm_close(struct hda_pcm_stream *hinfo,
5426ac2e8736STakashi Iwai struct hda_codec *codec,
5427ac2e8736STakashi Iwai struct snd_pcm_substream *substream)
5428ac2e8736STakashi Iwai {
5429ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLOSE);
5430ac2e8736STakashi Iwai return 0;
5431ac2e8736STakashi Iwai }
5432ac2e8736STakashi Iwai
alt_playback_pcm_open(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)543338cf6f1aSTakashi Iwai static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo,
543438cf6f1aSTakashi Iwai struct hda_codec *codec,
543538cf6f1aSTakashi Iwai struct snd_pcm_substream *substream)
543638cf6f1aSTakashi Iwai {
543738cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
543838cf6f1aSTakashi Iwai int err = 0;
543938cf6f1aSTakashi Iwai
544038cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex);
5441d1f15e06STakashi Iwai if (spec->indep_hp && !spec->indep_hp_enabled)
544238cf6f1aSTakashi Iwai err = -EBUSY;
544338cf6f1aSTakashi Iwai else
544438cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_INDEP_HP;
5445e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream,
5446e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_OPEN);
544738cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex);
544838cf6f1aSTakashi Iwai return err;
544938cf6f1aSTakashi Iwai }
545038cf6f1aSTakashi Iwai
alt_playback_pcm_close(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)545138cf6f1aSTakashi Iwai static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo,
545238cf6f1aSTakashi Iwai struct hda_codec *codec,
545338cf6f1aSTakashi Iwai struct snd_pcm_substream *substream)
545438cf6f1aSTakashi Iwai {
545538cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
545638cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex);
545738cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_INDEP_HP);
5458e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream,
5459e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLOSE);
546038cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex);
546138cf6f1aSTakashi Iwai return 0;
546238cf6f1aSTakashi Iwai }
546338cf6f1aSTakashi Iwai
alt_playback_pcm_prepare(struct hda_pcm_stream * hinfo,struct hda_codec * codec,unsigned int stream_tag,unsigned int format,struct snd_pcm_substream * substream)5464e6b85f3cSTakashi Iwai static int alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
5465e6b85f3cSTakashi Iwai struct hda_codec *codec,
5466e6b85f3cSTakashi Iwai unsigned int stream_tag,
5467e6b85f3cSTakashi Iwai unsigned int format,
5468e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream)
5469e6b85f3cSTakashi Iwai {
5470e6b85f3cSTakashi Iwai snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
5471e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream,
5472e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_PREPARE);
5473e6b85f3cSTakashi Iwai return 0;
5474e6b85f3cSTakashi Iwai }
5475e6b85f3cSTakashi Iwai
alt_playback_pcm_cleanup(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5476e6b85f3cSTakashi Iwai static int alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
5477e6b85f3cSTakashi Iwai struct hda_codec *codec,
5478e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream)
5479e6b85f3cSTakashi Iwai {
5480e6b85f3cSTakashi Iwai snd_hda_codec_cleanup_stream(codec, hinfo->nid);
5481e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream,
5482e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLEANUP);
5483e6b85f3cSTakashi Iwai return 0;
5484e6b85f3cSTakashi Iwai }
5485e6b85f3cSTakashi Iwai
5486352f7f91STakashi Iwai /*
5487352f7f91STakashi Iwai * Digital out
5488352f7f91STakashi Iwai */
dig_playback_pcm_open(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5489352f7f91STakashi Iwai static int dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
5490352f7f91STakashi Iwai struct hda_codec *codec,
5491352f7f91STakashi Iwai struct snd_pcm_substream *substream)
5492352f7f91STakashi Iwai {
5493352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5494352f7f91STakashi Iwai return snd_hda_multi_out_dig_open(codec, &spec->multiout);
5495352f7f91STakashi Iwai }
5496352f7f91STakashi Iwai
dig_playback_pcm_prepare(struct hda_pcm_stream * hinfo,struct hda_codec * codec,unsigned int stream_tag,unsigned int format,struct snd_pcm_substream * substream)5497352f7f91STakashi Iwai static int dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
5498352f7f91STakashi Iwai struct hda_codec *codec,
5499352f7f91STakashi Iwai unsigned int stream_tag,
5500352f7f91STakashi Iwai unsigned int format,
5501352f7f91STakashi Iwai struct snd_pcm_substream *substream)
5502352f7f91STakashi Iwai {
5503352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5504352f7f91STakashi Iwai return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
5505352f7f91STakashi Iwai stream_tag, format, substream);
5506352f7f91STakashi Iwai }
5507352f7f91STakashi Iwai
dig_playback_pcm_cleanup(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5508352f7f91STakashi Iwai static int dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
5509352f7f91STakashi Iwai struct hda_codec *codec,
5510352f7f91STakashi Iwai struct snd_pcm_substream *substream)
5511352f7f91STakashi Iwai {
5512352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5513352f7f91STakashi Iwai return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
5514352f7f91STakashi Iwai }
5515352f7f91STakashi Iwai
dig_playback_pcm_close(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5516352f7f91STakashi Iwai static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
5517352f7f91STakashi Iwai struct hda_codec *codec,
5518352f7f91STakashi Iwai struct snd_pcm_substream *substream)
5519352f7f91STakashi Iwai {
5520352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5521352f7f91STakashi Iwai return snd_hda_multi_out_dig_close(codec, &spec->multiout);
5522352f7f91STakashi Iwai }
5523352f7f91STakashi Iwai
5524352f7f91STakashi Iwai /*
5525352f7f91STakashi Iwai * Analog capture
5526352f7f91STakashi Iwai */
5527ac2e8736STakashi Iwai #define alt_capture_pcm_open capture_pcm_open
5528ac2e8736STakashi Iwai #define alt_capture_pcm_close capture_pcm_close
5529ac2e8736STakashi Iwai
alt_capture_pcm_prepare(struct hda_pcm_stream * hinfo,struct hda_codec * codec,unsigned int stream_tag,unsigned int format,struct snd_pcm_substream * substream)5530352f7f91STakashi Iwai static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
5531352f7f91STakashi Iwai struct hda_codec *codec,
5532352f7f91STakashi Iwai unsigned int stream_tag,
5533352f7f91STakashi Iwai unsigned int format,
5534352f7f91STakashi Iwai struct snd_pcm_substream *substream)
5535352f7f91STakashi Iwai {
5536352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5537352f7f91STakashi Iwai
5538352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
553997ec558aSTakashi Iwai stream_tag, 0, format);
5540ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream,
5541ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_PREPARE);
554297ec558aSTakashi Iwai return 0;
554397ec558aSTakashi Iwai }
554497ec558aSTakashi Iwai
alt_capture_pcm_cleanup(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5545352f7f91STakashi Iwai static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
554697ec558aSTakashi Iwai struct hda_codec *codec,
554797ec558aSTakashi Iwai struct snd_pcm_substream *substream)
554897ec558aSTakashi Iwai {
5549352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
555097ec558aSTakashi Iwai
5551352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec,
5552352f7f91STakashi Iwai spec->adc_nids[substream->number + 1]);
5553ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream,
5554ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_CLEANUP);
555597ec558aSTakashi Iwai return 0;
555697ec558aSTakashi Iwai }
555797ec558aSTakashi Iwai
5558352f7f91STakashi Iwai /*
5559352f7f91STakashi Iwai */
5560352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_playback = {
5561352f7f91STakashi Iwai .substreams = 1,
5562352f7f91STakashi Iwai .channels_min = 2,
5563352f7f91STakashi Iwai .channels_max = 8,
5564352f7f91STakashi Iwai /* NID is set in build_pcms */
5565352f7f91STakashi Iwai .ops = {
5566352f7f91STakashi Iwai .open = playback_pcm_open,
556738cf6f1aSTakashi Iwai .close = playback_pcm_close,
5568352f7f91STakashi Iwai .prepare = playback_pcm_prepare,
5569352f7f91STakashi Iwai .cleanup = playback_pcm_cleanup
5570352f7f91STakashi Iwai },
5571352f7f91STakashi Iwai };
5572352f7f91STakashi Iwai
5573352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_capture = {
5574352f7f91STakashi Iwai .substreams = 1,
5575352f7f91STakashi Iwai .channels_min = 2,
5576352f7f91STakashi Iwai .channels_max = 2,
5577352f7f91STakashi Iwai /* NID is set in build_pcms */
5578ac2e8736STakashi Iwai .ops = {
5579ac2e8736STakashi Iwai .open = capture_pcm_open,
5580ac2e8736STakashi Iwai .close = capture_pcm_close,
5581ac2e8736STakashi Iwai .prepare = capture_pcm_prepare,
5582ac2e8736STakashi Iwai .cleanup = capture_pcm_cleanup
5583ac2e8736STakashi Iwai },
5584352f7f91STakashi Iwai };
5585352f7f91STakashi Iwai
5586352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_playback = {
5587352f7f91STakashi Iwai .substreams = 1,
5588352f7f91STakashi Iwai .channels_min = 2,
5589352f7f91STakashi Iwai .channels_max = 2,
5590352f7f91STakashi Iwai /* NID is set in build_pcms */
559138cf6f1aSTakashi Iwai .ops = {
559238cf6f1aSTakashi Iwai .open = alt_playback_pcm_open,
5593e6b85f3cSTakashi Iwai .close = alt_playback_pcm_close,
5594e6b85f3cSTakashi Iwai .prepare = alt_playback_pcm_prepare,
5595e6b85f3cSTakashi Iwai .cleanup = alt_playback_pcm_cleanup
559638cf6f1aSTakashi Iwai },
5597352f7f91STakashi Iwai };
5598352f7f91STakashi Iwai
5599352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_capture = {
5600352f7f91STakashi Iwai .substreams = 2, /* can be overridden */
5601352f7f91STakashi Iwai .channels_min = 2,
5602352f7f91STakashi Iwai .channels_max = 2,
5603352f7f91STakashi Iwai /* NID is set in build_pcms */
5604352f7f91STakashi Iwai .ops = {
5605ac2e8736STakashi Iwai .open = alt_capture_pcm_open,
5606ac2e8736STakashi Iwai .close = alt_capture_pcm_close,
5607352f7f91STakashi Iwai .prepare = alt_capture_pcm_prepare,
5608352f7f91STakashi Iwai .cleanup = alt_capture_pcm_cleanup
5609352f7f91STakashi Iwai },
5610352f7f91STakashi Iwai };
5611352f7f91STakashi Iwai
5612352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_playback = {
5613352f7f91STakashi Iwai .substreams = 1,
5614352f7f91STakashi Iwai .channels_min = 2,
5615352f7f91STakashi Iwai .channels_max = 2,
5616352f7f91STakashi Iwai /* NID is set in build_pcms */
5617352f7f91STakashi Iwai .ops = {
5618352f7f91STakashi Iwai .open = dig_playback_pcm_open,
5619352f7f91STakashi Iwai .close = dig_playback_pcm_close,
5620352f7f91STakashi Iwai .prepare = dig_playback_pcm_prepare,
5621352f7f91STakashi Iwai .cleanup = dig_playback_pcm_cleanup
5622352f7f91STakashi Iwai },
5623352f7f91STakashi Iwai };
5624352f7f91STakashi Iwai
5625352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_capture = {
5626352f7f91STakashi Iwai .substreams = 1,
5627352f7f91STakashi Iwai .channels_min = 2,
5628352f7f91STakashi Iwai .channels_max = 2,
5629352f7f91STakashi Iwai /* NID is set in build_pcms */
5630352f7f91STakashi Iwai };
5631352f7f91STakashi Iwai
5632352f7f91STakashi Iwai /* Used by build_pcms to flag that a PCM has no playback stream */
5633352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_null_stream = {
5634352f7f91STakashi Iwai .substreams = 0,
5635352f7f91STakashi Iwai .channels_min = 0,
5636352f7f91STakashi Iwai .channels_max = 0,
5637352f7f91STakashi Iwai };
5638352f7f91STakashi Iwai
5639352f7f91STakashi Iwai /*
5640352f7f91STakashi Iwai * dynamic changing ADC PCM streams
5641352f7f91STakashi Iwai */
dyn_adc_pcm_resetup(struct hda_codec * codec,int cur)5642352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur)
56431da177e4SLinus Torvalds {
5644352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5645352f7f91STakashi Iwai hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]];
56461da177e4SLinus Torvalds
5647352f7f91STakashi Iwai if (spec->cur_adc && spec->cur_adc != new_adc) {
5648352f7f91STakashi Iwai /* stream is running, let's swap the current ADC */
5649352f7f91STakashi Iwai __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
5650352f7f91STakashi Iwai spec->cur_adc = new_adc;
5651352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, new_adc,
5652352f7f91STakashi Iwai spec->cur_adc_stream_tag, 0,
5653352f7f91STakashi Iwai spec->cur_adc_format);
5654352f7f91STakashi Iwai return true;
5655352f7f91STakashi Iwai }
5656352f7f91STakashi Iwai return false;
5657352f7f91STakashi Iwai }
5658352f7f91STakashi Iwai
5659352f7f91STakashi Iwai /* analog capture with dynamic dual-adc changes */
dyn_adc_capture_pcm_prepare(struct hda_pcm_stream * hinfo,struct hda_codec * codec,unsigned int stream_tag,unsigned int format,struct snd_pcm_substream * substream)5660352f7f91STakashi Iwai static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
5661352f7f91STakashi Iwai struct hda_codec *codec,
5662352f7f91STakashi Iwai unsigned int stream_tag,
5663352f7f91STakashi Iwai unsigned int format,
5664352f7f91STakashi Iwai struct snd_pcm_substream *substream)
5665352f7f91STakashi Iwai {
5666352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5667352f7f91STakashi Iwai spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]];
5668352f7f91STakashi Iwai spec->cur_adc_stream_tag = stream_tag;
5669352f7f91STakashi Iwai spec->cur_adc_format = format;
5670352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
56714f29efc0STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_PREPARE);
56721da177e4SLinus Torvalds return 0;
56731da177e4SLinus Torvalds }
56741da177e4SLinus Torvalds
dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)5675352f7f91STakashi Iwai static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
5676352f7f91STakashi Iwai struct hda_codec *codec,
5677352f7f91STakashi Iwai struct snd_pcm_substream *substream)
5678352f7f91STakashi Iwai {
5679352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5680352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
5681352f7f91STakashi Iwai spec->cur_adc = 0;
56824f29efc0STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLEANUP);
5683352f7f91STakashi Iwai return 0;
5684352f7f91STakashi Iwai }
5685352f7f91STakashi Iwai
5686352f7f91STakashi Iwai static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = {
5687352f7f91STakashi Iwai .substreams = 1,
5688352f7f91STakashi Iwai .channels_min = 2,
5689352f7f91STakashi Iwai .channels_max = 2,
5690352f7f91STakashi Iwai .nid = 0, /* fill later */
5691352f7f91STakashi Iwai .ops = {
5692352f7f91STakashi Iwai .prepare = dyn_adc_capture_pcm_prepare,
5693352f7f91STakashi Iwai .cleanup = dyn_adc_capture_pcm_cleanup
5694352f7f91STakashi Iwai },
5695352f7f91STakashi Iwai };
5696352f7f91STakashi Iwai
fill_pcm_stream_name(char * str,size_t len,const char * sfx,const char * chip_name)5697f873e536STakashi Iwai static void fill_pcm_stream_name(char *str, size_t len, const char *sfx,
5698f873e536STakashi Iwai const char *chip_name)
5699f873e536STakashi Iwai {
5700f873e536STakashi Iwai char *p;
5701f873e536STakashi Iwai
5702f873e536STakashi Iwai if (*str)
5703f873e536STakashi Iwai return;
570475b1a8f9SJoe Perches strscpy(str, chip_name, len);
5705f873e536STakashi Iwai
5706f873e536STakashi Iwai /* drop non-alnum chars after a space */
5707f873e536STakashi Iwai for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) {
5708f873e536STakashi Iwai if (!isalnum(p[1])) {
5709f873e536STakashi Iwai *p = 0;
5710f873e536STakashi Iwai break;
5711f873e536STakashi Iwai }
5712f873e536STakashi Iwai }
5713f873e536STakashi Iwai strlcat(str, sfx, len);
5714f873e536STakashi Iwai }
5715f873e536STakashi Iwai
5716fb83b635STakashi Iwai /* copy PCM stream info from @default_str, and override non-NULL entries
5717fb83b635STakashi Iwai * from @spec_str and @nid
5718fb83b635STakashi Iwai */
setup_pcm_stream(struct hda_pcm_stream * str,const struct hda_pcm_stream * default_str,const struct hda_pcm_stream * spec_str,hda_nid_t nid)5719fb83b635STakashi Iwai static void setup_pcm_stream(struct hda_pcm_stream *str,
5720fb83b635STakashi Iwai const struct hda_pcm_stream *default_str,
5721fb83b635STakashi Iwai const struct hda_pcm_stream *spec_str,
5722fb83b635STakashi Iwai hda_nid_t nid)
5723fb83b635STakashi Iwai {
5724fb83b635STakashi Iwai *str = *default_str;
5725fb83b635STakashi Iwai if (nid)
5726fb83b635STakashi Iwai str->nid = nid;
5727fb83b635STakashi Iwai if (spec_str) {
5728fb83b635STakashi Iwai if (spec_str->substreams)
5729fb83b635STakashi Iwai str->substreams = spec_str->substreams;
5730fb83b635STakashi Iwai if (spec_str->channels_min)
5731fb83b635STakashi Iwai str->channels_min = spec_str->channels_min;
5732fb83b635STakashi Iwai if (spec_str->channels_max)
5733fb83b635STakashi Iwai str->channels_max = spec_str->channels_max;
5734fb83b635STakashi Iwai if (spec_str->rates)
5735fb83b635STakashi Iwai str->rates = spec_str->rates;
5736fb83b635STakashi Iwai if (spec_str->formats)
5737fb83b635STakashi Iwai str->formats = spec_str->formats;
5738fb83b635STakashi Iwai if (spec_str->maxbps)
5739fb83b635STakashi Iwai str->maxbps = spec_str->maxbps;
5740fb83b635STakashi Iwai }
5741fb83b635STakashi Iwai }
5742fb83b635STakashi Iwai
5743dda42bd0STakashi Iwai /**
5744dda42bd0STakashi Iwai * snd_hda_gen_build_pcms - build PCM streams based on the parsed results
5745dda42bd0STakashi Iwai * @codec: the HDA codec
5746dda42bd0STakashi Iwai *
5747dda42bd0STakashi Iwai * Pass this to build_pcms patch_ops.
5748dda42bd0STakashi Iwai */
snd_hda_gen_build_pcms(struct hda_codec * codec)5749352f7f91STakashi Iwai int snd_hda_gen_build_pcms(struct hda_codec *codec)
5750352f7f91STakashi Iwai {
5751352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5752bbbc7e85STakashi Iwai struct hda_pcm *info;
5753352f7f91STakashi Iwai bool have_multi_adcs;
5754352f7f91STakashi Iwai
5755352f7f91STakashi Iwai if (spec->no_analog)
5756352f7f91STakashi Iwai goto skip_analog;
5757352f7f91STakashi Iwai
5758f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_analog,
5759f873e536STakashi Iwai sizeof(spec->stream_name_analog),
57607639a06cSTakashi Iwai " Analog", codec->core.chip_name);
5761bbbc7e85STakashi Iwai info = snd_hda_codec_pcm_new(codec, "%s", spec->stream_name_analog);
5762bbbc7e85STakashi Iwai if (!info)
5763bbbc7e85STakashi Iwai return -ENOMEM;
5764bbbc7e85STakashi Iwai spec->pcm_rec[0] = info;
5765352f7f91STakashi Iwai
5766352f7f91STakashi Iwai if (spec->multiout.num_dacs > 0) {
5767fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
5768fb83b635STakashi Iwai &pcm_analog_playback,
5769fb83b635STakashi Iwai spec->stream_analog_playback,
5770fb83b635STakashi Iwai spec->multiout.dac_nids[0]);
5771352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
5772352f7f91STakashi Iwai spec->multiout.max_channels;
5773352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
5774352f7f91STakashi Iwai spec->autocfg.line_outs == 2)
5775352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap =
5776352f7f91STakashi Iwai snd_pcm_2_1_chmaps;
5777352f7f91STakashi Iwai }
5778352f7f91STakashi Iwai if (spec->num_adc_nids) {
5779fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
5780fb83b635STakashi Iwai (spec->dyn_adc_switch ?
5781fb83b635STakashi Iwai &dyn_adc_pcm_analog_capture : &pcm_analog_capture),
5782fb83b635STakashi Iwai spec->stream_analog_capture,
5783fb83b635STakashi Iwai spec->adc_nids[0]);
5784352f7f91STakashi Iwai }
5785352f7f91STakashi Iwai
5786352f7f91STakashi Iwai skip_analog:
5787352f7f91STakashi Iwai /* SPDIF for stream index #1 */
5788352f7f91STakashi Iwai if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
5789f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_digital,
5790352f7f91STakashi Iwai sizeof(spec->stream_name_digital),
57917639a06cSTakashi Iwai " Digital", codec->core.chip_name);
5792bbbc7e85STakashi Iwai info = snd_hda_codec_pcm_new(codec, "%s",
5793bbbc7e85STakashi Iwai spec->stream_name_digital);
5794bbbc7e85STakashi Iwai if (!info)
5795bbbc7e85STakashi Iwai return -ENOMEM;
57969ab0cb30STakashi Iwai codec->follower_dig_outs = spec->multiout.follower_dig_outs;
5797bbbc7e85STakashi Iwai spec->pcm_rec[1] = info;
5798352f7f91STakashi Iwai if (spec->dig_out_type)
5799352f7f91STakashi Iwai info->pcm_type = spec->dig_out_type;
5800352f7f91STakashi Iwai else
5801352f7f91STakashi Iwai info->pcm_type = HDA_PCM_TYPE_SPDIF;
5802fb83b635STakashi Iwai if (spec->multiout.dig_out_nid)
5803fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
5804fb83b635STakashi Iwai &pcm_digital_playback,
5805fb83b635STakashi Iwai spec->stream_digital_playback,
5806fb83b635STakashi Iwai spec->multiout.dig_out_nid);
5807fb83b635STakashi Iwai if (spec->dig_in_nid)
5808fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
5809fb83b635STakashi Iwai &pcm_digital_capture,
5810fb83b635STakashi Iwai spec->stream_digital_capture,
5811fb83b635STakashi Iwai spec->dig_in_nid);
5812352f7f91STakashi Iwai }
5813352f7f91STakashi Iwai
5814352f7f91STakashi Iwai if (spec->no_analog)
5815352f7f91STakashi Iwai return 0;
5816352f7f91STakashi Iwai
5817352f7f91STakashi Iwai /* If the use of more than one ADC is requested for the current
5818352f7f91STakashi Iwai * model, configure a second analog capture-only PCM.
5819352f7f91STakashi Iwai */
5820352f7f91STakashi Iwai have_multi_adcs = (spec->num_adc_nids > 1) &&
5821352f7f91STakashi Iwai !spec->dyn_adc_switch && !spec->auto_mic;
5822352f7f91STakashi Iwai /* Additional Analaog capture for index #2 */
5823352f7f91STakashi Iwai if (spec->alt_dac_nid || have_multi_adcs) {
5824a607148fSTakashi Iwai fill_pcm_stream_name(spec->stream_name_alt_analog,
5825a607148fSTakashi Iwai sizeof(spec->stream_name_alt_analog),
58267639a06cSTakashi Iwai " Alt Analog", codec->core.chip_name);
5827bbbc7e85STakashi Iwai info = snd_hda_codec_pcm_new(codec, "%s",
5828bbbc7e85STakashi Iwai spec->stream_name_alt_analog);
5829bbbc7e85STakashi Iwai if (!info)
5830bbbc7e85STakashi Iwai return -ENOMEM;
5831bbbc7e85STakashi Iwai spec->pcm_rec[2] = info;
5832fb83b635STakashi Iwai if (spec->alt_dac_nid)
5833fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
5834fb83b635STakashi Iwai &pcm_analog_alt_playback,
5835fb83b635STakashi Iwai spec->stream_analog_alt_playback,
5836fb83b635STakashi Iwai spec->alt_dac_nid);
5837fb83b635STakashi Iwai else
5838fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
5839fb83b635STakashi Iwai &pcm_null_stream, NULL, 0);
5840352f7f91STakashi Iwai if (have_multi_adcs) {
5841fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
5842fb83b635STakashi Iwai &pcm_analog_alt_capture,
5843fb83b635STakashi Iwai spec->stream_analog_alt_capture,
5844fb83b635STakashi Iwai spec->adc_nids[1]);
5845352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
5846352f7f91STakashi Iwai spec->num_adc_nids - 1;
5847352f7f91STakashi Iwai } else {
5848fb83b635STakashi Iwai setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
5849fb83b635STakashi Iwai &pcm_null_stream, NULL, 0);
5850352f7f91STakashi Iwai }
58511da177e4SLinus Torvalds }
58521da177e4SLinus Torvalds
58531da177e4SLinus Torvalds return 0;
58541da177e4SLinus Torvalds }
58552698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_build_pcms);
5856352f7f91STakashi Iwai
5857352f7f91STakashi Iwai
5858352f7f91STakashi Iwai /*
5859352f7f91STakashi Iwai * Standard auto-parser initializations
5860352f7f91STakashi Iwai */
5861352f7f91STakashi Iwai
5862d4156930STakashi Iwai /* configure the given path as a proper output */
set_output_and_unmute(struct hda_codec * codec,int path_idx)58632c12c30dSTakashi Iwai static void set_output_and_unmute(struct hda_codec *codec, int path_idx)
5864352f7f91STakashi Iwai {
5865352f7f91STakashi Iwai struct nid_path *path;
5866d4156930STakashi Iwai hda_nid_t pin;
5867352f7f91STakashi Iwai
5868196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx);
5869d4156930STakashi Iwai if (!path || !path->depth)
5870352f7f91STakashi Iwai return;
5871d4156930STakashi Iwai pin = path->path[path->depth - 1];
58722c12c30dSTakashi Iwai restore_pin_ctl(codec, pin);
587365033cc8STakashi Iwai snd_hda_activate_path(codec, path, path->active,
587465033cc8STakashi Iwai aamix_default(codec->spec));
5875e1284af7STakashi Iwai set_pin_eapd(codec, pin, path->active);
5876352f7f91STakashi Iwai }
5877352f7f91STakashi Iwai
5878352f7f91STakashi Iwai /* initialize primary output paths */
init_multi_out(struct hda_codec * codec)5879352f7f91STakashi Iwai static void init_multi_out(struct hda_codec *codec)
5880352f7f91STakashi Iwai {
5881352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5882352f7f91STakashi Iwai int i;
5883352f7f91STakashi Iwai
5884d4156930STakashi Iwai for (i = 0; i < spec->autocfg.line_outs; i++)
58852c12c30dSTakashi Iwai set_output_and_unmute(codec, spec->out_paths[i]);
5886352f7f91STakashi Iwai }
5887352f7f91STakashi Iwai
5888db23fd19STakashi Iwai
__init_extra_out(struct hda_codec * codec,int num_outs,int * paths)58892c12c30dSTakashi Iwai static void __init_extra_out(struct hda_codec *codec, int num_outs, int *paths)
5890352f7f91STakashi Iwai {
5891352f7f91STakashi Iwai int i;
5892352f7f91STakashi Iwai
5893d4156930STakashi Iwai for (i = 0; i < num_outs; i++)
58942c12c30dSTakashi Iwai set_output_and_unmute(codec, paths[i]);
5895352f7f91STakashi Iwai }
5896db23fd19STakashi Iwai
5897db23fd19STakashi Iwai /* initialize hp and speaker paths */
init_extra_out(struct hda_codec * codec)5898db23fd19STakashi Iwai static void init_extra_out(struct hda_codec *codec)
5899db23fd19STakashi Iwai {
5900db23fd19STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5901db23fd19STakashi Iwai
5902db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT)
59032c12c30dSTakashi Iwai __init_extra_out(codec, spec->autocfg.hp_outs, spec->hp_paths);
5904db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT)
5905db23fd19STakashi Iwai __init_extra_out(codec, spec->autocfg.speaker_outs,
59062c12c30dSTakashi Iwai spec->speaker_paths);
5907352f7f91STakashi Iwai }
5908352f7f91STakashi Iwai
5909352f7f91STakashi Iwai /* initialize multi-io paths */
init_multi_io(struct hda_codec * codec)5910352f7f91STakashi Iwai static void init_multi_io(struct hda_codec *codec)
5911352f7f91STakashi Iwai {
5912352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5913352f7f91STakashi Iwai int i;
5914352f7f91STakashi Iwai
5915352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++) {
5916352f7f91STakashi Iwai hda_nid_t pin = spec->multi_io[i].pin;
5917352f7f91STakashi Iwai struct nid_path *path;
5918196c1766STakashi Iwai path = get_multiio_path(codec, i);
5919352f7f91STakashi Iwai if (!path)
5920352f7f91STakashi Iwai continue;
5921352f7f91STakashi Iwai if (!spec->multi_io[i].ctl_in)
5922352f7f91STakashi Iwai spec->multi_io[i].ctl_in =
59232c12c30dSTakashi Iwai snd_hda_codec_get_pin_target(codec, pin);
592465033cc8STakashi Iwai snd_hda_activate_path(codec, path, path->active,
592565033cc8STakashi Iwai aamix_default(spec));
5926352f7f91STakashi Iwai }
5927352f7f91STakashi Iwai }
5928352f7f91STakashi Iwai
init_aamix_paths(struct hda_codec * codec)59294f7f67fbSTakashi Iwai static void init_aamix_paths(struct hda_codec *codec)
59304f7f67fbSTakashi Iwai {
59314f7f67fbSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
59324f7f67fbSTakashi Iwai
59334f7f67fbSTakashi Iwai if (!spec->have_aamix_ctl)
59344f7f67fbSTakashi Iwai return;
5935e7fdd527STakashi Iwai if (!has_aamix_out_paths(spec))
5936e7fdd527STakashi Iwai return;
59374f7f67fbSTakashi Iwai update_aamix_paths(codec, spec->aamix_mode, spec->out_paths[0],
59384f7f67fbSTakashi Iwai spec->aamix_out_paths[0],
59394f7f67fbSTakashi Iwai spec->autocfg.line_out_type);
59404f7f67fbSTakashi Iwai update_aamix_paths(codec, spec->aamix_mode, spec->hp_paths[0],
59414f7f67fbSTakashi Iwai spec->aamix_out_paths[1],
59424f7f67fbSTakashi Iwai AUTO_PIN_HP_OUT);
59434f7f67fbSTakashi Iwai update_aamix_paths(codec, spec->aamix_mode, spec->speaker_paths[0],
59444f7f67fbSTakashi Iwai spec->aamix_out_paths[2],
59454f7f67fbSTakashi Iwai AUTO_PIN_SPEAKER_OUT);
59464f7f67fbSTakashi Iwai }
59474f7f67fbSTakashi Iwai
5948352f7f91STakashi Iwai /* set up input pins and loopback paths */
init_analog_input(struct hda_codec * codec)5949352f7f91STakashi Iwai static void init_analog_input(struct hda_codec *codec)
5950352f7f91STakashi Iwai {
5951352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5952352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg;
5953352f7f91STakashi Iwai int i;
5954352f7f91STakashi Iwai
5955352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) {
5956352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin;
5957352f7f91STakashi Iwai if (is_input_pin(codec, nid))
59582c12c30dSTakashi Iwai restore_pin_ctl(codec, nid);
5959352f7f91STakashi Iwai
5960352f7f91STakashi Iwai /* init loopback inputs */
5961352f7f91STakashi Iwai if (spec->mixer_nid) {
59623e367f15STakashi Iwai resume_path_from_idx(codec, spec->loopback_paths[i]);
59633e367f15STakashi Iwai resume_path_from_idx(codec, spec->loopback_merge_path);
5964352f7f91STakashi Iwai }
5965352f7f91STakashi Iwai }
5966352f7f91STakashi Iwai }
5967352f7f91STakashi Iwai
5968352f7f91STakashi Iwai /* initialize ADC paths */
init_input_src(struct hda_codec * codec)5969352f7f91STakashi Iwai static void init_input_src(struct hda_codec *codec)
5970352f7f91STakashi Iwai {
5971352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
5972352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux;
5973352f7f91STakashi Iwai struct nid_path *path;
5974352f7f91STakashi Iwai int i, c, nums;
5975352f7f91STakashi Iwai
5976352f7f91STakashi Iwai if (spec->dyn_adc_switch)
5977352f7f91STakashi Iwai nums = 1;
5978352f7f91STakashi Iwai else
5979352f7f91STakashi Iwai nums = spec->num_adc_nids;
5980352f7f91STakashi Iwai
5981352f7f91STakashi Iwai for (c = 0; c < nums; c++) {
5982352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) {
5983c697b716STakashi Iwai path = get_input_path(codec, c, i);
5984352f7f91STakashi Iwai if (path) {
5985352f7f91STakashi Iwai bool active = path->active;
5986352f7f91STakashi Iwai if (i == spec->cur_mux[c])
5987352f7f91STakashi Iwai active = true;
5988352f7f91STakashi Iwai snd_hda_activate_path(codec, path, active, false);
5989352f7f91STakashi Iwai }
5990352f7f91STakashi Iwai }
5991967303daSTakashi Iwai if (spec->hp_mic)
5992967303daSTakashi Iwai update_hp_mic(codec, c, true);
5993352f7f91STakashi Iwai }
5994352f7f91STakashi Iwai
5995352f7f91STakashi Iwai if (spec->cap_sync_hook)
59967fe30711STakashi Iwai spec->cap_sync_hook(codec, NULL, NULL);
5997352f7f91STakashi Iwai }
5998352f7f91STakashi Iwai
5999352f7f91STakashi Iwai /* set right pin controls for digital I/O */
init_digital(struct hda_codec * codec)6000352f7f91STakashi Iwai static void init_digital(struct hda_codec *codec)
6001352f7f91STakashi Iwai {
6002352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
6003352f7f91STakashi Iwai int i;
6004352f7f91STakashi Iwai hda_nid_t pin;
6005352f7f91STakashi Iwai
6006d4156930STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++)
60072c12c30dSTakashi Iwai set_output_and_unmute(codec, spec->digout_paths[i]);
6008352f7f91STakashi Iwai pin = spec->autocfg.dig_in_pin;
60092430d7b7STakashi Iwai if (pin) {
60102c12c30dSTakashi Iwai restore_pin_ctl(codec, pin);
60113e367f15STakashi Iwai resume_path_from_idx(codec, spec->digin_path);
60122430d7b7STakashi Iwai }
6013352f7f91STakashi Iwai }
6014352f7f91STakashi Iwai
6015973e4972STakashi Iwai /* clear unsol-event tags on unused pins; Conexant codecs seem to leave
6016973e4972STakashi Iwai * invalid unsol tags by some reason
6017973e4972STakashi Iwai */
clear_unsol_on_unused_pins(struct hda_codec * codec)6018973e4972STakashi Iwai static void clear_unsol_on_unused_pins(struct hda_codec *codec)
6019973e4972STakashi Iwai {
6020a9c2dfc8STakashi Iwai const struct hda_pincfg *pin;
6021973e4972STakashi Iwai int i;
6022973e4972STakashi Iwai
6023a9c2dfc8STakashi Iwai snd_array_for_each(&codec->init_pins, i, pin) {
6024973e4972STakashi Iwai hda_nid_t nid = pin->nid;
6025973e4972STakashi Iwai if (is_jack_detectable(codec, nid) &&
6026973e4972STakashi Iwai !snd_hda_jack_tbl_get(codec, nid))
6027401caff7STakashi Iwai snd_hda_codec_write_cache(codec, nid, 0,
6028973e4972STakashi Iwai AC_VERB_SET_UNSOLICITED_ENABLE, 0);
6029973e4972STakashi Iwai }
6030973e4972STakashi Iwai }
6031973e4972STakashi Iwai
6032dda42bd0STakashi Iwai /**
6033dda42bd0STakashi Iwai * snd_hda_gen_init - initialize the generic spec
6034dda42bd0STakashi Iwai * @codec: the HDA codec
6035dda42bd0STakashi Iwai *
6036dda42bd0STakashi Iwai * This can be put as patch_ops init function.
60375187ac16STakashi Iwai */
snd_hda_gen_init(struct hda_codec * codec)6038352f7f91STakashi Iwai int snd_hda_gen_init(struct hda_codec *codec)
6039352f7f91STakashi Iwai {
6040352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec;
6041352f7f91STakashi Iwai
6042352f7f91STakashi Iwai if (spec->init_hook)
6043352f7f91STakashi Iwai spec->init_hook(codec);
6044352f7f91STakashi Iwai
604589781d08STakashi Iwai if (!spec->skip_verbs)
6046352f7f91STakashi Iwai snd_hda_apply_verbs(codec);
6047352f7f91STakashi Iwai
6048352f7f91STakashi Iwai init_multi_out(codec);
6049352f7f91STakashi Iwai init_extra_out(codec);
6050352f7f91STakashi Iwai init_multi_io(codec);
60514f7f67fbSTakashi Iwai init_aamix_paths(codec);
6052352f7f91STakashi Iwai init_analog_input(codec);
6053352f7f91STakashi Iwai init_input_src(codec);
6054352f7f91STakashi Iwai init_digital(codec);
6055352f7f91STakashi Iwai
6056973e4972STakashi Iwai clear_unsol_on_unused_pins(codec);
6057973e4972STakashi Iwai
6058e6feb5d0STakashi Iwai sync_all_pin_power_ctls(codec);
6059e6feb5d0STakashi Iwai
6060352f7f91STakashi Iwai /* call init functions of standard auto-mute helpers */
6061a5cc2509STakashi Iwai update_automute_all(codec);
6062352f7f91STakashi Iwai
60631a462be5STakashi Iwai snd_hda_regmap_sync(codec);
60643bbcd274STakashi Iwai
6065352f7f91STakashi Iwai if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook)
6066352f7f91STakashi Iwai snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
6067352f7f91STakashi Iwai
6068352f7f91STakashi Iwai hda_call_check_power_status(codec, 0x01);
6069352f7f91STakashi Iwai return 0;
6070352f7f91STakashi Iwai }
60712698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_init);
6072fce52a3bSTakashi Iwai
6073dda42bd0STakashi Iwai /**
6074dda42bd0STakashi Iwai * snd_hda_gen_free - free the generic spec
6075dda42bd0STakashi Iwai * @codec: the HDA codec
6076dda42bd0STakashi Iwai *
6077dda42bd0STakashi Iwai * This can be put as patch_ops free function.
60785187ac16STakashi Iwai */
snd_hda_gen_free(struct hda_codec * codec)6079fce52a3bSTakashi Iwai void snd_hda_gen_free(struct hda_codec *codec)
6080fce52a3bSTakashi Iwai {
60818a02c0ccSTakashi Iwai snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE);
6082fce52a3bSTakashi Iwai snd_hda_gen_spec_free(codec->spec);
6083fce52a3bSTakashi Iwai kfree(codec->spec);
6084fce52a3bSTakashi Iwai codec->spec = NULL;
6085fce52a3bSTakashi Iwai }
60862698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_free);
6087fce52a3bSTakashi Iwai
6088fce52a3bSTakashi Iwai #ifdef CONFIG_PM
6089dda42bd0STakashi Iwai /**
6090dda42bd0STakashi Iwai * snd_hda_gen_check_power_status - check the loopback power save state
6091dda42bd0STakashi Iwai * @codec: the HDA codec
6092dda42bd0STakashi Iwai * @nid: NID to inspect
6093dda42bd0STakashi Iwai *
6094dda42bd0STakashi Iwai * This can be put as patch_ops check_power_status function.
60955187ac16STakashi Iwai */
snd_hda_gen_check_power_status(struct hda_codec * codec,hda_nid_t nid)6096fce52a3bSTakashi Iwai int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid)
6097fce52a3bSTakashi Iwai {
6098fce52a3bSTakashi Iwai struct hda_gen_spec *spec = codec->spec;
6099fce52a3bSTakashi Iwai return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
6100fce52a3bSTakashi Iwai }
61012698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_gen_check_power_status);
6102fce52a3bSTakashi Iwai #endif
6103352f7f91STakashi Iwai
6104352f7f91STakashi Iwai
6105352f7f91STakashi Iwai /*
6106352f7f91STakashi Iwai * the generic codec support
6107352f7f91STakashi Iwai */
61081da177e4SLinus Torvalds
6109352f7f91STakashi Iwai static const struct hda_codec_ops generic_patch_ops = {
6110352f7f91STakashi Iwai .build_controls = snd_hda_gen_build_controls,
6111352f7f91STakashi Iwai .build_pcms = snd_hda_gen_build_pcms,
6112352f7f91STakashi Iwai .init = snd_hda_gen_init,
6113fce52a3bSTakashi Iwai .free = snd_hda_gen_free,
6114352f7f91STakashi Iwai .unsol_event = snd_hda_jack_unsol_event,
611583012a7cSTakashi Iwai #ifdef CONFIG_PM
6116fce52a3bSTakashi Iwai .check_power_status = snd_hda_gen_check_power_status,
6117cb53c626STakashi Iwai #endif
61181da177e4SLinus Torvalds };
61191da177e4SLinus Torvalds
6120d8a766a1STakashi Iwai /*
6121dda42bd0STakashi Iwai * snd_hda_parse_generic_codec - Generic codec parser
6122dda42bd0STakashi Iwai * @codec: the HDA codec
6123dda42bd0STakashi Iwai */
snd_hda_parse_generic_codec(struct hda_codec * codec)6124d8a766a1STakashi Iwai static int snd_hda_parse_generic_codec(struct hda_codec *codec)
61251da177e4SLinus Torvalds {
6126352f7f91STakashi Iwai struct hda_gen_spec *spec;
61271da177e4SLinus Torvalds int err;
61281da177e4SLinus Torvalds
6129e560d8d8STakashi Iwai spec = kzalloc(sizeof(*spec), GFP_KERNEL);
6130352f7f91STakashi Iwai if (!spec)
61311da177e4SLinus Torvalds return -ENOMEM;
6132352f7f91STakashi Iwai snd_hda_gen_spec_init(spec);
61331da177e4SLinus Torvalds codec->spec = spec;
61341da177e4SLinus Torvalds
61359eb413e5STakashi Iwai err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0);
61369eb413e5STakashi Iwai if (err < 0)
6137cfef67f0SWenwen Wang goto error;
61389eb413e5STakashi Iwai
61399eb413e5STakashi Iwai err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg);
6140352f7f91STakashi Iwai if (err < 0)
61411da177e4SLinus Torvalds goto error;
61421da177e4SLinus Torvalds
61431da177e4SLinus Torvalds codec->patch_ops = generic_patch_ops;
61441da177e4SLinus Torvalds return 0;
61451da177e4SLinus Torvalds
61461da177e4SLinus Torvalds error:
6147fce52a3bSTakashi Iwai snd_hda_gen_free(codec);
61481da177e4SLinus Torvalds return err;
61491da177e4SLinus Torvalds }
6150d8a766a1STakashi Iwai
6151b9a94a9cSTakashi Iwai static const struct hda_device_id snd_hda_id_generic[] = {
6152b9a94a9cSTakashi Iwai HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC, "Generic", snd_hda_parse_generic_codec),
6153d8a766a1STakashi Iwai {} /* terminator */
6154d8a766a1STakashi Iwai };
6155b9a94a9cSTakashi Iwai MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_generic);
6156d8a766a1STakashi Iwai
6157d8a766a1STakashi Iwai static struct hda_codec_driver generic_driver = {
6158b9a94a9cSTakashi Iwai .id = snd_hda_id_generic,
6159d8a766a1STakashi Iwai };
6160d8a766a1STakashi Iwai
6161d8a766a1STakashi Iwai module_hda_codec_driver(generic_driver);
6162b21bdd0dSTakashi Iwai
6163b21bdd0dSTakashi Iwai MODULE_LICENSE("GPL");
6164b21bdd0dSTakashi Iwai MODULE_DESCRIPTION("Generic HD-audio codec parser");
6165