11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Universal Interface for Intel High Definition Audio Codec 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Generic widget tree parser 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * This driver is free software; you can redistribute it and/or modify 91da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 101da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 111da177e4SLinus Torvalds * (at your option) any later version. 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * This driver is distributed in the hope that it will be useful, 141da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 151da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 161da177e4SLinus Torvalds * GNU General Public License for more details. 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 191da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 201da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 211da177e4SLinus Torvalds */ 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds #include <linux/init.h> 241da177e4SLinus Torvalds #include <linux/slab.h> 25d81a6d71SPaul Gortmaker #include <linux/export.h> 26352f7f91STakashi Iwai #include <linux/sort.h> 2755196fffSTakashi Iwai #include <linux/delay.h> 28f873e536STakashi Iwai #include <linux/ctype.h> 29f873e536STakashi Iwai #include <linux/string.h> 3029476558STakashi Iwai #include <linux/bitops.h> 31b21bdd0dSTakashi Iwai #include <linux/module.h> 321da177e4SLinus Torvalds #include <sound/core.h> 33352f7f91STakashi Iwai #include <sound/jack.h> 341da177e4SLinus Torvalds #include "hda_codec.h" 351da177e4SLinus Torvalds #include "hda_local.h" 36352f7f91STakashi Iwai #include "hda_auto_parser.h" 37352f7f91STakashi Iwai #include "hda_jack.h" 387504b6cdSTakashi Iwai #include "hda_beep.h" 39352f7f91STakashi Iwai #include "hda_generic.h" 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds 42352f7f91STakashi Iwai /* initialize hda_gen_spec struct */ 43352f7f91STakashi Iwai int snd_hda_gen_spec_init(struct hda_gen_spec *spec) 441da177e4SLinus Torvalds { 45352f7f91STakashi Iwai snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); 46352f7f91STakashi Iwai snd_array_init(&spec->paths, sizeof(struct nid_path), 8); 470186f4f4STakashi Iwai snd_array_init(&spec->loopback_list, sizeof(struct hda_amp_list), 8); 4838cf6f1aSTakashi Iwai mutex_init(&spec->pcm_mutex); 49352f7f91STakashi Iwai return 0; 50352f7f91STakashi Iwai } 51352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_spec_init); 521da177e4SLinus Torvalds 5312c93df6STakashi Iwai struct snd_kcontrol_new * 5412c93df6STakashi Iwai snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name, 55352f7f91STakashi Iwai const struct snd_kcontrol_new *temp) 56352f7f91STakashi Iwai { 57352f7f91STakashi Iwai struct snd_kcontrol_new *knew = snd_array_new(&spec->kctls); 58352f7f91STakashi Iwai if (!knew) 59352f7f91STakashi Iwai return NULL; 60352f7f91STakashi Iwai *knew = *temp; 61352f7f91STakashi Iwai if (name) 62352f7f91STakashi Iwai knew->name = kstrdup(name, GFP_KERNEL); 63352f7f91STakashi Iwai else if (knew->name) 64352f7f91STakashi Iwai knew->name = kstrdup(knew->name, GFP_KERNEL); 65352f7f91STakashi Iwai if (!knew->name) 66352f7f91STakashi Iwai return NULL; 67352f7f91STakashi Iwai return knew; 68352f7f91STakashi Iwai } 6912c93df6STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_add_kctl); 70352f7f91STakashi Iwai 71352f7f91STakashi Iwai static void free_kctls(struct hda_gen_spec *spec) 72352f7f91STakashi Iwai { 73352f7f91STakashi Iwai if (spec->kctls.list) { 74352f7f91STakashi Iwai struct snd_kcontrol_new *kctl = spec->kctls.list; 75352f7f91STakashi Iwai int i; 76352f7f91STakashi Iwai for (i = 0; i < spec->kctls.used; i++) 77352f7f91STakashi Iwai kfree(kctl[i].name); 78352f7f91STakashi Iwai } 79352f7f91STakashi Iwai snd_array_free(&spec->kctls); 80352f7f91STakashi Iwai } 81352f7f91STakashi Iwai 82352f7f91STakashi Iwai void snd_hda_gen_spec_free(struct hda_gen_spec *spec) 83352f7f91STakashi Iwai { 841da177e4SLinus Torvalds if (!spec) 851da177e4SLinus Torvalds return; 86352f7f91STakashi Iwai free_kctls(spec); 87352f7f91STakashi Iwai snd_array_free(&spec->paths); 880186f4f4STakashi Iwai snd_array_free(&spec->loopback_list); 891da177e4SLinus Torvalds } 90352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_spec_free); 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds /* 931c70a583STakashi Iwai * store user hints 941c70a583STakashi Iwai */ 951c70a583STakashi Iwai static void parse_user_hints(struct hda_codec *codec) 961c70a583STakashi Iwai { 971c70a583STakashi Iwai struct hda_gen_spec *spec = codec->spec; 981c70a583STakashi Iwai int val; 991c70a583STakashi Iwai 1001c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "jack_detect"); 1011c70a583STakashi Iwai if (val >= 0) 1021c70a583STakashi Iwai codec->no_jack_detect = !val; 1031c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "inv_jack_detect"); 1041c70a583STakashi Iwai if (val >= 0) 1051c70a583STakashi Iwai codec->inv_jack_detect = !!val; 1061c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "trigger_sense"); 1071c70a583STakashi Iwai if (val >= 0) 1081c70a583STakashi Iwai codec->no_trigger_sense = !val; 1091c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "inv_eapd"); 1101c70a583STakashi Iwai if (val >= 0) 1111c70a583STakashi Iwai codec->inv_eapd = !!val; 1121c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "pcm_format_first"); 1131c70a583STakashi Iwai if (val >= 0) 1141c70a583STakashi Iwai codec->pcm_format_first = !!val; 1151c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "sticky_stream"); 1161c70a583STakashi Iwai if (val >= 0) 1171c70a583STakashi Iwai codec->no_sticky_stream = !val; 1181c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "spdif_status_reset"); 1191c70a583STakashi Iwai if (val >= 0) 1201c70a583STakashi Iwai codec->spdif_status_reset = !!val; 1211c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "pin_amp_workaround"); 1221c70a583STakashi Iwai if (val >= 0) 1231c70a583STakashi Iwai codec->pin_amp_workaround = !!val; 1241c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "single_adc_amp"); 1251c70a583STakashi Iwai if (val >= 0) 1261c70a583STakashi Iwai codec->single_adc_amp = !!val; 1271c70a583STakashi Iwai 128f72706beSTakashi Iwai val = snd_hda_get_bool_hint(codec, "auto_mute"); 129f72706beSTakashi Iwai if (val >= 0) 130f72706beSTakashi Iwai spec->suppress_auto_mute = !val; 1311c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "auto_mic"); 1321c70a583STakashi Iwai if (val >= 0) 1331c70a583STakashi Iwai spec->suppress_auto_mic = !val; 1341c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "line_in_auto_switch"); 1351c70a583STakashi Iwai if (val >= 0) 1361c70a583STakashi Iwai spec->line_in_auto_switch = !!val; 1377eebffd3STakashi Iwai val = snd_hda_get_bool_hint(codec, "auto_mute_via_amp"); 1387eebffd3STakashi Iwai if (val >= 0) 1397eebffd3STakashi Iwai spec->auto_mute_via_amp = !!val; 1401c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "need_dac_fix"); 1411c70a583STakashi Iwai if (val >= 0) 1421c70a583STakashi Iwai spec->need_dac_fix = !!val; 1431c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "primary_hp"); 1441c70a583STakashi Iwai if (val >= 0) 1451c70a583STakashi Iwai spec->no_primary_hp = !val; 146da96fb5bSTakashi Iwai val = snd_hda_get_bool_hint(codec, "multi_io"); 147da96fb5bSTakashi Iwai if (val >= 0) 148da96fb5bSTakashi Iwai spec->no_multi_io = !val; 1491c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "multi_cap_vol"); 1501c70a583STakashi Iwai if (val >= 0) 1511c70a583STakashi Iwai spec->multi_cap_vol = !!val; 1521c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "inv_dmic_split"); 1531c70a583STakashi Iwai if (val >= 0) 1541c70a583STakashi Iwai spec->inv_dmic_split = !!val; 1551c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "indep_hp"); 1561c70a583STakashi Iwai if (val >= 0) 1571c70a583STakashi Iwai spec->indep_hp = !!val; 1581c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "add_stereo_mix_input"); 1591c70a583STakashi Iwai if (val >= 0) 1601c70a583STakashi Iwai spec->add_stereo_mix_input = !!val; 161f811c3cfSTakashi Iwai /* the following two are just for compatibility */ 1621c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "add_out_jack_modes"); 1631c70a583STakashi Iwai if (val >= 0) 164f811c3cfSTakashi Iwai spec->add_jack_modes = !!val; 16529476558STakashi Iwai val = snd_hda_get_bool_hint(codec, "add_in_jack_modes"); 16629476558STakashi Iwai if (val >= 0) 167f811c3cfSTakashi Iwai spec->add_jack_modes = !!val; 168f811c3cfSTakashi Iwai val = snd_hda_get_bool_hint(codec, "add_jack_modes"); 169f811c3cfSTakashi Iwai if (val >= 0) 170f811c3cfSTakashi Iwai spec->add_jack_modes = !!val; 17155196fffSTakashi Iwai val = snd_hda_get_bool_hint(codec, "power_down_unused"); 17255196fffSTakashi Iwai if (val >= 0) 17355196fffSTakashi Iwai spec->power_down_unused = !!val; 174967303daSTakashi Iwai val = snd_hda_get_bool_hint(codec, "add_hp_mic"); 175967303daSTakashi Iwai if (val >= 0) 176967303daSTakashi Iwai spec->hp_mic = !!val; 177967303daSTakashi Iwai val = snd_hda_get_bool_hint(codec, "hp_mic_detect"); 178967303daSTakashi Iwai if (val >= 0) 179967303daSTakashi Iwai spec->suppress_hp_mic_detect = !val; 1801c70a583STakashi Iwai 1811c70a583STakashi Iwai if (!snd_hda_get_int_hint(codec, "mixer_nid", &val)) 1821c70a583STakashi Iwai spec->mixer_nid = val; 1831c70a583STakashi Iwai } 1841c70a583STakashi Iwai 1851c70a583STakashi Iwai /* 1862c12c30dSTakashi Iwai * pin control value accesses 1872c12c30dSTakashi Iwai */ 1882c12c30dSTakashi Iwai 1892c12c30dSTakashi Iwai #define update_pin_ctl(codec, pin, val) \ 1902c12c30dSTakashi Iwai snd_hda_codec_update_cache(codec, pin, 0, \ 1912c12c30dSTakashi Iwai AC_VERB_SET_PIN_WIDGET_CONTROL, val) 1922c12c30dSTakashi Iwai 1932c12c30dSTakashi Iwai /* restore the pinctl based on the cached value */ 1942c12c30dSTakashi Iwai static inline void restore_pin_ctl(struct hda_codec *codec, hda_nid_t pin) 1952c12c30dSTakashi Iwai { 1962c12c30dSTakashi Iwai update_pin_ctl(codec, pin, snd_hda_codec_get_pin_target(codec, pin)); 1972c12c30dSTakashi Iwai } 1982c12c30dSTakashi Iwai 1992c12c30dSTakashi Iwai /* set the pinctl target value and write it if requested */ 2002c12c30dSTakashi Iwai static void set_pin_target(struct hda_codec *codec, hda_nid_t pin, 2012c12c30dSTakashi Iwai unsigned int val, bool do_write) 2022c12c30dSTakashi Iwai { 2032c12c30dSTakashi Iwai if (!pin) 2042c12c30dSTakashi Iwai return; 2052c12c30dSTakashi Iwai val = snd_hda_correct_pin_ctl(codec, pin, val); 2062c12c30dSTakashi Iwai snd_hda_codec_set_pin_target(codec, pin, val); 2072c12c30dSTakashi Iwai if (do_write) 2082c12c30dSTakashi Iwai update_pin_ctl(codec, pin, val); 2092c12c30dSTakashi Iwai } 2102c12c30dSTakashi Iwai 2112c12c30dSTakashi Iwai /* set pinctl target values for all given pins */ 2122c12c30dSTakashi Iwai static void set_pin_targets(struct hda_codec *codec, int num_pins, 2132c12c30dSTakashi Iwai hda_nid_t *pins, unsigned int val) 2142c12c30dSTakashi Iwai { 2152c12c30dSTakashi Iwai int i; 2162c12c30dSTakashi Iwai for (i = 0; i < num_pins; i++) 2172c12c30dSTakashi Iwai set_pin_target(codec, pins[i], val, false); 2182c12c30dSTakashi Iwai } 2192c12c30dSTakashi Iwai 2202c12c30dSTakashi Iwai /* 221352f7f91STakashi Iwai * parsing paths 2221da177e4SLinus Torvalds */ 2231da177e4SLinus Torvalds 2243ca529d3STakashi Iwai /* return the position of NID in the list, or -1 if not found */ 2253ca529d3STakashi Iwai static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) 2263ca529d3STakashi Iwai { 2273ca529d3STakashi Iwai int i; 2283ca529d3STakashi Iwai for (i = 0; i < nums; i++) 2293ca529d3STakashi Iwai if (list[i] == nid) 2303ca529d3STakashi Iwai return i; 2313ca529d3STakashi Iwai return -1; 2323ca529d3STakashi Iwai } 2333ca529d3STakashi Iwai 2343ca529d3STakashi Iwai /* return true if the given NID is contained in the path */ 2353ca529d3STakashi Iwai static bool is_nid_contained(struct nid_path *path, hda_nid_t nid) 2363ca529d3STakashi Iwai { 2373ca529d3STakashi Iwai return find_idx_in_nid_list(nid, path->path, path->depth) >= 0; 2383ca529d3STakashi Iwai } 2393ca529d3STakashi Iwai 240f5172a7eSTakashi Iwai static struct nid_path *get_nid_path(struct hda_codec *codec, 241f5172a7eSTakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid, 2423ca529d3STakashi Iwai int anchor_nid) 2431da177e4SLinus Torvalds { 244352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 245352f7f91STakashi Iwai int i; 2461da177e4SLinus Torvalds 247352f7f91STakashi Iwai for (i = 0; i < spec->paths.used; i++) { 248352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, i); 249352f7f91STakashi Iwai if (path->depth <= 0) 250352f7f91STakashi Iwai continue; 251352f7f91STakashi Iwai if ((!from_nid || path->path[0] == from_nid) && 252f5172a7eSTakashi Iwai (!to_nid || path->path[path->depth - 1] == to_nid)) { 2533ca529d3STakashi Iwai if (!anchor_nid || 2543ca529d3STakashi Iwai (anchor_nid > 0 && is_nid_contained(path, anchor_nid)) || 2553ca529d3STakashi Iwai (anchor_nid < 0 && !is_nid_contained(path, anchor_nid))) 256352f7f91STakashi Iwai return path; 2571da177e4SLinus Torvalds } 258f5172a7eSTakashi Iwai } 2591da177e4SLinus Torvalds return NULL; 2601da177e4SLinus Torvalds } 261f5172a7eSTakashi Iwai 262f5172a7eSTakashi Iwai /* get the path between the given NIDs; 263f5172a7eSTakashi Iwai * passing 0 to either @pin or @dac behaves as a wildcard 264f5172a7eSTakashi Iwai */ 265f5172a7eSTakashi Iwai struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec, 266f5172a7eSTakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid) 267f5172a7eSTakashi Iwai { 2683ca529d3STakashi Iwai return get_nid_path(codec, from_nid, to_nid, 0); 269f5172a7eSTakashi Iwai } 270352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_nid_path); 2711da177e4SLinus Torvalds 272196c1766STakashi Iwai /* get the index number corresponding to the path instance; 273196c1766STakashi Iwai * the index starts from 1, for easier checking the invalid value 274196c1766STakashi Iwai */ 275196c1766STakashi Iwai int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path) 276196c1766STakashi Iwai { 277196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 278196c1766STakashi Iwai struct nid_path *array = spec->paths.list; 279196c1766STakashi Iwai ssize_t idx; 280196c1766STakashi Iwai 281196c1766STakashi Iwai if (!spec->paths.used) 282196c1766STakashi Iwai return 0; 283196c1766STakashi Iwai idx = path - array; 284196c1766STakashi Iwai if (idx < 0 || idx >= spec->paths.used) 285196c1766STakashi Iwai return 0; 286196c1766STakashi Iwai return idx + 1; 287196c1766STakashi Iwai } 2884bd01e93STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_path_idx); 289196c1766STakashi Iwai 290196c1766STakashi Iwai /* get the path instance corresponding to the given index number */ 291196c1766STakashi Iwai struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx) 292196c1766STakashi Iwai { 293196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 294196c1766STakashi Iwai 295196c1766STakashi Iwai if (idx <= 0 || idx > spec->paths.used) 296196c1766STakashi Iwai return NULL; 297196c1766STakashi Iwai return snd_array_elem(&spec->paths, idx - 1); 298196c1766STakashi Iwai } 2994bd01e93STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_path_from_idx); 300196c1766STakashi Iwai 301352f7f91STakashi Iwai /* check whether the given DAC is already found in any existing paths */ 302352f7f91STakashi Iwai static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid) 3031da177e4SLinus Torvalds { 304352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 305352f7f91STakashi Iwai int i; 306352f7f91STakashi Iwai 307352f7f91STakashi Iwai for (i = 0; i < spec->paths.used; i++) { 308352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, i); 309352f7f91STakashi Iwai if (path->path[0] == nid) 310352f7f91STakashi Iwai return true; 311352f7f91STakashi Iwai } 312352f7f91STakashi Iwai return false; 3131da177e4SLinus Torvalds } 3141da177e4SLinus Torvalds 315352f7f91STakashi Iwai /* check whether the given two widgets can be connected */ 316352f7f91STakashi Iwai static bool is_reachable_path(struct hda_codec *codec, 317352f7f91STakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid) 3181da177e4SLinus Torvalds { 319352f7f91STakashi Iwai if (!from_nid || !to_nid) 320352f7f91STakashi Iwai return false; 321352f7f91STakashi Iwai return snd_hda_get_conn_index(codec, to_nid, from_nid, true) >= 0; 3221da177e4SLinus Torvalds } 3231da177e4SLinus Torvalds 324352f7f91STakashi Iwai /* nid, dir and idx */ 325352f7f91STakashi Iwai #define AMP_VAL_COMPARE_MASK (0xffff | (1U << 18) | (0x0f << 19)) 326352f7f91STakashi Iwai 327352f7f91STakashi Iwai /* check whether the given ctl is already assigned in any path elements */ 328352f7f91STakashi Iwai static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type) 3291da177e4SLinus Torvalds { 330352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 331352f7f91STakashi Iwai int i; 332352f7f91STakashi Iwai 333352f7f91STakashi Iwai val &= AMP_VAL_COMPARE_MASK; 334352f7f91STakashi Iwai for (i = 0; i < spec->paths.used; i++) { 335352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, i); 336352f7f91STakashi Iwai if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val) 337352f7f91STakashi Iwai return true; 338352f7f91STakashi Iwai } 339352f7f91STakashi Iwai return false; 3401da177e4SLinus Torvalds } 3411da177e4SLinus Torvalds 342352f7f91STakashi Iwai /* check whether a control with the given (nid, dir, idx) was assigned */ 343352f7f91STakashi Iwai static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid, 3448999bf0aSTakashi Iwai int dir, int idx, int type) 345cb53c626STakashi Iwai { 346352f7f91STakashi Iwai unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir); 3478999bf0aSTakashi Iwai return is_ctl_used(codec, val, type); 348cb53c626STakashi Iwai } 349352f7f91STakashi Iwai 3500c8c0f56STakashi Iwai static void print_nid_path(const char *pfx, struct nid_path *path) 3510c8c0f56STakashi Iwai { 3520c8c0f56STakashi Iwai char buf[40]; 3530c8c0f56STakashi Iwai int i; 3540c8c0f56STakashi Iwai 3550c8c0f56STakashi Iwai 3560c8c0f56STakashi Iwai buf[0] = 0; 3570c8c0f56STakashi Iwai for (i = 0; i < path->depth; i++) { 3580c8c0f56STakashi Iwai char tmp[4]; 3590c8c0f56STakashi Iwai sprintf(tmp, ":%02x", path->path[i]); 3600c8c0f56STakashi Iwai strlcat(buf, tmp, sizeof(buf)); 3610c8c0f56STakashi Iwai } 3620c8c0f56STakashi Iwai snd_printdd("%s path: depth=%d %s\n", pfx, path->depth, buf); 3630c8c0f56STakashi Iwai } 3640c8c0f56STakashi Iwai 365352f7f91STakashi Iwai /* called recursively */ 366352f7f91STakashi Iwai static bool __parse_nid_path(struct hda_codec *codec, 367352f7f91STakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid, 3683ca529d3STakashi Iwai int anchor_nid, struct nid_path *path, 3693ca529d3STakashi Iwai int depth) 370352f7f91STakashi Iwai { 371ee8e765bSTakashi Iwai const hda_nid_t *conn; 372352f7f91STakashi Iwai int i, nums; 373352f7f91STakashi Iwai 3743ca529d3STakashi Iwai if (to_nid == anchor_nid) 3753ca529d3STakashi Iwai anchor_nid = 0; /* anchor passed */ 3763ca529d3STakashi Iwai else if (to_nid == (hda_nid_t)(-anchor_nid)) 3773ca529d3STakashi Iwai return false; /* hit the exclusive nid */ 378352f7f91STakashi Iwai 379ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, to_nid, &conn); 380352f7f91STakashi Iwai for (i = 0; i < nums; i++) { 381352f7f91STakashi Iwai if (conn[i] != from_nid) { 382352f7f91STakashi Iwai /* special case: when from_nid is 0, 383352f7f91STakashi Iwai * try to find an empty DAC 384352f7f91STakashi Iwai */ 385352f7f91STakashi Iwai if (from_nid || 386352f7f91STakashi Iwai get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT || 387352f7f91STakashi Iwai is_dac_already_used(codec, conn[i])) 388352f7f91STakashi Iwai continue; 389352f7f91STakashi Iwai } 3903ca529d3STakashi Iwai /* anchor is not requested or already passed? */ 3913ca529d3STakashi Iwai if (anchor_nid <= 0) 392352f7f91STakashi Iwai goto found; 393352f7f91STakashi Iwai } 394352f7f91STakashi Iwai if (depth >= MAX_NID_PATH_DEPTH) 395352f7f91STakashi Iwai return false; 396352f7f91STakashi Iwai for (i = 0; i < nums; i++) { 397352f7f91STakashi Iwai unsigned int type; 398352f7f91STakashi Iwai type = get_wcaps_type(get_wcaps(codec, conn[i])); 399352f7f91STakashi Iwai if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN || 400352f7f91STakashi Iwai type == AC_WID_PIN) 401352f7f91STakashi Iwai continue; 402352f7f91STakashi Iwai if (__parse_nid_path(codec, from_nid, conn[i], 4033ca529d3STakashi Iwai anchor_nid, path, depth + 1)) 404352f7f91STakashi Iwai goto found; 405352f7f91STakashi Iwai } 406352f7f91STakashi Iwai return false; 407352f7f91STakashi Iwai 408352f7f91STakashi Iwai found: 409352f7f91STakashi Iwai path->path[path->depth] = conn[i]; 410352f7f91STakashi Iwai path->idx[path->depth + 1] = i; 411352f7f91STakashi Iwai if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX) 412352f7f91STakashi Iwai path->multi[path->depth + 1] = 1; 413352f7f91STakashi Iwai path->depth++; 414352f7f91STakashi Iwai return true; 415352f7f91STakashi Iwai } 416352f7f91STakashi Iwai 417352f7f91STakashi Iwai /* parse the widget path from the given nid to the target nid; 418352f7f91STakashi Iwai * when @from_nid is 0, try to find an empty DAC; 4193ca529d3STakashi Iwai * when @anchor_nid is set to a positive value, only paths through the widget 4203ca529d3STakashi Iwai * with the given value are evaluated. 4213ca529d3STakashi Iwai * when @anchor_nid is set to a negative value, paths through the widget 4223ca529d3STakashi Iwai * with the negative of given value are excluded, only other paths are chosen. 4233ca529d3STakashi Iwai * when @anchor_nid is zero, no special handling about path selection. 424352f7f91STakashi Iwai */ 425352f7f91STakashi Iwai bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, 4263ca529d3STakashi Iwai hda_nid_t to_nid, int anchor_nid, 427352f7f91STakashi Iwai struct nid_path *path) 428352f7f91STakashi Iwai { 4293ca529d3STakashi Iwai if (__parse_nid_path(codec, from_nid, to_nid, anchor_nid, path, 1)) { 430352f7f91STakashi Iwai path->path[path->depth] = to_nid; 431352f7f91STakashi Iwai path->depth++; 432352f7f91STakashi Iwai return true; 433352f7f91STakashi Iwai } 434352f7f91STakashi Iwai return false; 435352f7f91STakashi Iwai } 436352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_parse_nid_path); 437352f7f91STakashi Iwai 438352f7f91STakashi Iwai /* 439352f7f91STakashi Iwai * parse the path between the given NIDs and add to the path list. 440352f7f91STakashi Iwai * if no valid path is found, return NULL 441352f7f91STakashi Iwai */ 442352f7f91STakashi Iwai struct nid_path * 443352f7f91STakashi Iwai snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid, 4443ca529d3STakashi Iwai hda_nid_t to_nid, int anchor_nid) 445352f7f91STakashi Iwai { 446352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 447352f7f91STakashi Iwai struct nid_path *path; 448352f7f91STakashi Iwai 449352f7f91STakashi Iwai if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid)) 450352f7f91STakashi Iwai return NULL; 451352f7f91STakashi Iwai 452f5172a7eSTakashi Iwai /* check whether the path has been already added */ 4533ca529d3STakashi Iwai path = get_nid_path(codec, from_nid, to_nid, anchor_nid); 454f5172a7eSTakashi Iwai if (path) 455f5172a7eSTakashi Iwai return path; 456f5172a7eSTakashi Iwai 457352f7f91STakashi Iwai path = snd_array_new(&spec->paths); 458352f7f91STakashi Iwai if (!path) 459352f7f91STakashi Iwai return NULL; 460352f7f91STakashi Iwai memset(path, 0, sizeof(*path)); 4613ca529d3STakashi Iwai if (snd_hda_parse_nid_path(codec, from_nid, to_nid, anchor_nid, path)) 462352f7f91STakashi Iwai return path; 463352f7f91STakashi Iwai /* push back */ 464352f7f91STakashi Iwai spec->paths.used--; 465352f7f91STakashi Iwai return NULL; 466352f7f91STakashi Iwai } 467352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_add_new_path); 468352f7f91STakashi Iwai 469980428ceSTakashi Iwai /* clear the given path as invalid so that it won't be picked up later */ 470980428ceSTakashi Iwai static void invalidate_nid_path(struct hda_codec *codec, int idx) 471980428ceSTakashi Iwai { 472980428ceSTakashi Iwai struct nid_path *path = snd_hda_get_path_from_idx(codec, idx); 473980428ceSTakashi Iwai if (!path) 474980428ceSTakashi Iwai return; 475980428ceSTakashi Iwai memset(path, 0, sizeof(*path)); 476980428ceSTakashi Iwai } 477980428ceSTakashi Iwai 478352f7f91STakashi Iwai /* look for an empty DAC slot */ 479352f7f91STakashi Iwai static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin, 480352f7f91STakashi Iwai bool is_digital) 481352f7f91STakashi Iwai { 482352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 483352f7f91STakashi Iwai bool cap_digital; 484352f7f91STakashi Iwai int i; 485352f7f91STakashi Iwai 486352f7f91STakashi Iwai for (i = 0; i < spec->num_all_dacs; i++) { 487352f7f91STakashi Iwai hda_nid_t nid = spec->all_dacs[i]; 488352f7f91STakashi Iwai if (!nid || is_dac_already_used(codec, nid)) 489352f7f91STakashi Iwai continue; 490352f7f91STakashi Iwai cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL); 491352f7f91STakashi Iwai if (is_digital != cap_digital) 492352f7f91STakashi Iwai continue; 493352f7f91STakashi Iwai if (is_reachable_path(codec, nid, pin)) 494352f7f91STakashi Iwai return nid; 495352f7f91STakashi Iwai } 496352f7f91STakashi Iwai return 0; 497352f7f91STakashi Iwai } 498352f7f91STakashi Iwai 499352f7f91STakashi Iwai /* replace the channels in the composed amp value with the given number */ 500352f7f91STakashi Iwai static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs) 501352f7f91STakashi Iwai { 502352f7f91STakashi Iwai val &= ~(0x3U << 16); 503352f7f91STakashi Iwai val |= chs << 16; 504352f7f91STakashi Iwai return val; 505352f7f91STakashi Iwai } 506352f7f91STakashi Iwai 507352f7f91STakashi Iwai /* check whether the widget has the given amp capability for the direction */ 508352f7f91STakashi Iwai static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, 509352f7f91STakashi Iwai int dir, unsigned int bits) 510352f7f91STakashi Iwai { 511352f7f91STakashi Iwai if (!nid) 512352f7f91STakashi Iwai return false; 513352f7f91STakashi Iwai if (get_wcaps(codec, nid) & (1 << (dir + 1))) 514352f7f91STakashi Iwai if (query_amp_caps(codec, nid, dir) & bits) 515352f7f91STakashi Iwai return true; 516352f7f91STakashi Iwai return false; 517352f7f91STakashi Iwai } 518352f7f91STakashi Iwai 51999a5592dSDavid Henningsson static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1, 52099a5592dSDavid Henningsson hda_nid_t nid2, int dir) 52199a5592dSDavid Henningsson { 52299a5592dSDavid Henningsson if (!(get_wcaps(codec, nid1) & (1 << (dir + 1)))) 52399a5592dSDavid Henningsson return !(get_wcaps(codec, nid2) & (1 << (dir + 1))); 52499a5592dSDavid Henningsson return (query_amp_caps(codec, nid1, dir) == 52599a5592dSDavid Henningsson query_amp_caps(codec, nid2, dir)); 52699a5592dSDavid Henningsson } 52799a5592dSDavid Henningsson 528352f7f91STakashi Iwai #define nid_has_mute(codec, nid, dir) \ 529f69910ddSTakashi Iwai check_amp_caps(codec, nid, dir, (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) 530352f7f91STakashi Iwai #define nid_has_volume(codec, nid, dir) \ 531352f7f91STakashi Iwai check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS) 532352f7f91STakashi Iwai 533352f7f91STakashi Iwai /* look for a widget suitable for assigning a mute switch in the path */ 534352f7f91STakashi Iwai static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec, 535352f7f91STakashi Iwai struct nid_path *path) 536352f7f91STakashi Iwai { 537352f7f91STakashi Iwai int i; 538352f7f91STakashi Iwai 539352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 540352f7f91STakashi Iwai if (nid_has_mute(codec, path->path[i], HDA_OUTPUT)) 541352f7f91STakashi Iwai return path->path[i]; 542352f7f91STakashi Iwai if (i != path->depth - 1 && i != 0 && 543352f7f91STakashi Iwai nid_has_mute(codec, path->path[i], HDA_INPUT)) 544352f7f91STakashi Iwai return path->path[i]; 545352f7f91STakashi Iwai } 546352f7f91STakashi Iwai return 0; 547352f7f91STakashi Iwai } 548352f7f91STakashi Iwai 549352f7f91STakashi Iwai /* look for a widget suitable for assigning a volume ctl in the path */ 550352f7f91STakashi Iwai static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec, 551352f7f91STakashi Iwai struct nid_path *path) 552352f7f91STakashi Iwai { 553a1114a8cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 554352f7f91STakashi Iwai int i; 555352f7f91STakashi Iwai 556352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 557a1114a8cSTakashi Iwai hda_nid_t nid = path->path[i]; 558a1114a8cSTakashi Iwai if ((spec->out_vol_mask >> nid) & 1) 559a1114a8cSTakashi Iwai continue; 560a1114a8cSTakashi Iwai if (nid_has_volume(codec, nid, HDA_OUTPUT)) 561a1114a8cSTakashi Iwai return nid; 562352f7f91STakashi Iwai } 563352f7f91STakashi Iwai return 0; 564352f7f91STakashi Iwai } 565352f7f91STakashi Iwai 566352f7f91STakashi Iwai /* 567352f7f91STakashi Iwai * path activation / deactivation 568352f7f91STakashi Iwai */ 569352f7f91STakashi Iwai 570352f7f91STakashi Iwai /* can have the amp-in capability? */ 571352f7f91STakashi Iwai static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx) 572352f7f91STakashi Iwai { 573352f7f91STakashi Iwai hda_nid_t nid = path->path[idx]; 574352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 575352f7f91STakashi Iwai unsigned int type = get_wcaps_type(caps); 576352f7f91STakashi Iwai 577352f7f91STakashi Iwai if (!(caps & AC_WCAP_IN_AMP)) 578352f7f91STakashi Iwai return false; 579352f7f91STakashi Iwai if (type == AC_WID_PIN && idx > 0) /* only for input pins */ 580352f7f91STakashi Iwai return false; 581352f7f91STakashi Iwai return true; 582352f7f91STakashi Iwai } 583352f7f91STakashi Iwai 584352f7f91STakashi Iwai /* can have the amp-out capability? */ 585352f7f91STakashi Iwai static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx) 586352f7f91STakashi Iwai { 587352f7f91STakashi Iwai hda_nid_t nid = path->path[idx]; 588352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 589352f7f91STakashi Iwai unsigned int type = get_wcaps_type(caps); 590352f7f91STakashi Iwai 591352f7f91STakashi Iwai if (!(caps & AC_WCAP_OUT_AMP)) 592352f7f91STakashi Iwai return false; 593352f7f91STakashi Iwai if (type == AC_WID_PIN && !idx) /* only for output pins */ 594352f7f91STakashi Iwai return false; 595352f7f91STakashi Iwai return true; 596352f7f91STakashi Iwai } 597352f7f91STakashi Iwai 598352f7f91STakashi Iwai /* check whether the given (nid,dir,idx) is active */ 599352f7f91STakashi Iwai static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid, 6007dddf2aeSTakashi Iwai unsigned int dir, unsigned int idx) 601352f7f91STakashi Iwai { 602352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 603352f7f91STakashi Iwai int i, n; 604352f7f91STakashi Iwai 605352f7f91STakashi Iwai for (n = 0; n < spec->paths.used; n++) { 606352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, n); 607352f7f91STakashi Iwai if (!path->active) 608352f7f91STakashi Iwai continue; 609352f7f91STakashi Iwai for (i = 0; i < path->depth; i++) { 610352f7f91STakashi Iwai if (path->path[i] == nid) { 611352f7f91STakashi Iwai if (dir == HDA_OUTPUT || path->idx[i] == idx) 612352f7f91STakashi Iwai return true; 613352f7f91STakashi Iwai break; 614352f7f91STakashi Iwai } 615352f7f91STakashi Iwai } 616352f7f91STakashi Iwai } 617352f7f91STakashi Iwai return false; 618352f7f91STakashi Iwai } 619352f7f91STakashi Iwai 620b1b9fbd0STakashi Iwai /* check whether the NID is referred by any active paths */ 621b1b9fbd0STakashi Iwai #define is_active_nid_for_any(codec, nid) \ 622b1b9fbd0STakashi Iwai is_active_nid(codec, nid, HDA_OUTPUT, 0) 623b1b9fbd0STakashi Iwai 624352f7f91STakashi Iwai /* get the default amp value for the target state */ 625352f7f91STakashi Iwai static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid, 6268999bf0aSTakashi Iwai int dir, unsigned int caps, bool enable) 627352f7f91STakashi Iwai { 628352f7f91STakashi Iwai unsigned int val = 0; 629352f7f91STakashi Iwai 630352f7f91STakashi Iwai if (caps & AC_AMPCAP_NUM_STEPS) { 631352f7f91STakashi Iwai /* set to 0dB */ 632352f7f91STakashi Iwai if (enable) 633352f7f91STakashi Iwai val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; 634352f7f91STakashi Iwai } 635f69910ddSTakashi Iwai if (caps & (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) { 636352f7f91STakashi Iwai if (!enable) 637352f7f91STakashi Iwai val |= HDA_AMP_MUTE; 638352f7f91STakashi Iwai } 639352f7f91STakashi Iwai return val; 640352f7f91STakashi Iwai } 641352f7f91STakashi Iwai 642352f7f91STakashi Iwai /* initialize the amp value (only at the first time) */ 643352f7f91STakashi Iwai static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx) 644352f7f91STakashi Iwai { 6458999bf0aSTakashi Iwai unsigned int caps = query_amp_caps(codec, nid, dir); 6468999bf0aSTakashi Iwai int val = get_amp_val_to_activate(codec, nid, dir, caps, false); 647352f7f91STakashi Iwai snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); 648352f7f91STakashi Iwai } 649352f7f91STakashi Iwai 6508999bf0aSTakashi Iwai /* calculate amp value mask we can modify; 6518999bf0aSTakashi Iwai * if the given amp is controlled by mixers, don't touch it 6528999bf0aSTakashi Iwai */ 6538999bf0aSTakashi Iwai static unsigned int get_amp_mask_to_modify(struct hda_codec *codec, 6548999bf0aSTakashi Iwai hda_nid_t nid, int dir, int idx, 6558999bf0aSTakashi Iwai unsigned int caps) 656352f7f91STakashi Iwai { 6578999bf0aSTakashi Iwai unsigned int mask = 0xff; 6588999bf0aSTakashi Iwai 659f69910ddSTakashi Iwai if (caps & (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) { 6608999bf0aSTakashi Iwai if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_MUTE_CTL)) 6618999bf0aSTakashi Iwai mask &= ~0x80; 6628999bf0aSTakashi Iwai } 6638999bf0aSTakashi Iwai if (caps & AC_AMPCAP_NUM_STEPS) { 6648999bf0aSTakashi Iwai if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) || 6658999bf0aSTakashi Iwai is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL)) 6668999bf0aSTakashi Iwai mask &= ~0x7f; 6678999bf0aSTakashi Iwai } 6688999bf0aSTakashi Iwai return mask; 6698999bf0aSTakashi Iwai } 6708999bf0aSTakashi Iwai 6718999bf0aSTakashi Iwai static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, 6728999bf0aSTakashi Iwai int idx, int idx_to_check, bool enable) 6738999bf0aSTakashi Iwai { 6748999bf0aSTakashi Iwai unsigned int caps; 6758999bf0aSTakashi Iwai unsigned int mask, val; 6768999bf0aSTakashi Iwai 6777dddf2aeSTakashi Iwai if (!enable && is_active_nid(codec, nid, dir, idx_to_check)) 678352f7f91STakashi Iwai return; 6798999bf0aSTakashi Iwai 6808999bf0aSTakashi Iwai caps = query_amp_caps(codec, nid, dir); 6818999bf0aSTakashi Iwai val = get_amp_val_to_activate(codec, nid, dir, caps, enable); 6828999bf0aSTakashi Iwai mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps); 6838999bf0aSTakashi Iwai if (!mask) 6848999bf0aSTakashi Iwai return; 6858999bf0aSTakashi Iwai 6868999bf0aSTakashi Iwai val &= mask; 6878999bf0aSTakashi Iwai snd_hda_codec_amp_stereo(codec, nid, dir, idx, mask, val); 688352f7f91STakashi Iwai } 689352f7f91STakashi Iwai 690352f7f91STakashi Iwai static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, 691352f7f91STakashi Iwai int i, bool enable) 692352f7f91STakashi Iwai { 693352f7f91STakashi Iwai hda_nid_t nid = path->path[i]; 694352f7f91STakashi Iwai init_amp(codec, nid, HDA_OUTPUT, 0); 6958999bf0aSTakashi Iwai activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable); 696352f7f91STakashi Iwai } 697352f7f91STakashi Iwai 698352f7f91STakashi Iwai static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, 699352f7f91STakashi Iwai int i, bool enable, bool add_aamix) 700352f7f91STakashi Iwai { 701352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 702ee8e765bSTakashi Iwai const hda_nid_t *conn; 703352f7f91STakashi Iwai int n, nums, idx; 704352f7f91STakashi Iwai int type; 705352f7f91STakashi Iwai hda_nid_t nid = path->path[i]; 706352f7f91STakashi Iwai 707ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, nid, &conn); 708352f7f91STakashi Iwai type = get_wcaps_type(get_wcaps(codec, nid)); 709352f7f91STakashi Iwai if (type == AC_WID_PIN || 710352f7f91STakashi Iwai (type == AC_WID_AUD_IN && codec->single_adc_amp)) { 711352f7f91STakashi Iwai nums = 1; 712352f7f91STakashi Iwai idx = 0; 713352f7f91STakashi Iwai } else 714352f7f91STakashi Iwai idx = path->idx[i]; 715352f7f91STakashi Iwai 716352f7f91STakashi Iwai for (n = 0; n < nums; n++) 717352f7f91STakashi Iwai init_amp(codec, nid, HDA_INPUT, n); 718352f7f91STakashi Iwai 719352f7f91STakashi Iwai /* here is a little bit tricky in comparison with activate_amp_out(); 720352f7f91STakashi Iwai * when aa-mixer is available, we need to enable the path as well 721352f7f91STakashi Iwai */ 722352f7f91STakashi Iwai for (n = 0; n < nums; n++) { 723e4a395e7STakashi Iwai if (n != idx && (!add_aamix || conn[n] != spec->mixer_merge_nid)) 724352f7f91STakashi Iwai continue; 7258999bf0aSTakashi Iwai activate_amp(codec, nid, HDA_INPUT, n, idx, enable); 726352f7f91STakashi Iwai } 727352f7f91STakashi Iwai } 728352f7f91STakashi Iwai 729352f7f91STakashi Iwai /* activate or deactivate the given path 730352f7f91STakashi Iwai * if @add_aamix is set, enable the input from aa-mix NID as well (if any) 731352f7f91STakashi Iwai */ 732352f7f91STakashi Iwai void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path, 733352f7f91STakashi Iwai bool enable, bool add_aamix) 734352f7f91STakashi Iwai { 73555196fffSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 736352f7f91STakashi Iwai int i; 737352f7f91STakashi Iwai 738352f7f91STakashi Iwai if (!enable) 739352f7f91STakashi Iwai path->active = false; 740352f7f91STakashi Iwai 741352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 74255196fffSTakashi Iwai hda_nid_t nid = path->path[i]; 74355196fffSTakashi Iwai if (enable && spec->power_down_unused) { 74455196fffSTakashi Iwai /* make sure the widget is powered up */ 74555196fffSTakashi Iwai if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0)) 74655196fffSTakashi Iwai snd_hda_codec_write(codec, nid, 0, 74755196fffSTakashi Iwai AC_VERB_SET_POWER_STATE, 74855196fffSTakashi Iwai AC_PWRST_D0); 74955196fffSTakashi Iwai } 750352f7f91STakashi Iwai if (enable && path->multi[i]) 75155196fffSTakashi Iwai snd_hda_codec_write_cache(codec, nid, 0, 752352f7f91STakashi Iwai AC_VERB_SET_CONNECT_SEL, 753352f7f91STakashi Iwai path->idx[i]); 754352f7f91STakashi Iwai if (has_amp_in(codec, path, i)) 755352f7f91STakashi Iwai activate_amp_in(codec, path, i, enable, add_aamix); 756352f7f91STakashi Iwai if (has_amp_out(codec, path, i)) 757352f7f91STakashi Iwai activate_amp_out(codec, path, i, enable); 758352f7f91STakashi Iwai } 759352f7f91STakashi Iwai 760352f7f91STakashi Iwai if (enable) 761352f7f91STakashi Iwai path->active = true; 762352f7f91STakashi Iwai } 763352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_activate_path); 764352f7f91STakashi Iwai 76555196fffSTakashi Iwai /* if the given path is inactive, put widgets into D3 (only if suitable) */ 76655196fffSTakashi Iwai static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path) 76755196fffSTakashi Iwai { 76855196fffSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 769868211dbSJiri Slaby bool changed = false; 77055196fffSTakashi Iwai int i; 77155196fffSTakashi Iwai 77255196fffSTakashi Iwai if (!spec->power_down_unused || path->active) 77355196fffSTakashi Iwai return; 77455196fffSTakashi Iwai 77555196fffSTakashi Iwai for (i = 0; i < path->depth; i++) { 77655196fffSTakashi Iwai hda_nid_t nid = path->path[i]; 777b1b9fbd0STakashi Iwai if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D3) && 778b1b9fbd0STakashi Iwai !is_active_nid_for_any(codec, nid)) { 77955196fffSTakashi Iwai snd_hda_codec_write(codec, nid, 0, 78055196fffSTakashi Iwai AC_VERB_SET_POWER_STATE, 78155196fffSTakashi Iwai AC_PWRST_D3); 78255196fffSTakashi Iwai changed = true; 78355196fffSTakashi Iwai } 78455196fffSTakashi Iwai } 78555196fffSTakashi Iwai 78655196fffSTakashi Iwai if (changed) { 78755196fffSTakashi Iwai msleep(10); 78855196fffSTakashi Iwai snd_hda_codec_read(codec, path->path[0], 0, 78955196fffSTakashi Iwai AC_VERB_GET_POWER_STATE, 0); 79055196fffSTakashi Iwai } 79155196fffSTakashi Iwai } 79255196fffSTakashi Iwai 793d5a9f1bbSTakashi Iwai /* turn on/off EAPD on the given pin */ 794d5a9f1bbSTakashi Iwai static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable) 795d5a9f1bbSTakashi Iwai { 796d5a9f1bbSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 797d5a9f1bbSTakashi Iwai if (spec->own_eapd_ctl || 798d5a9f1bbSTakashi Iwai !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD)) 799d5a9f1bbSTakashi Iwai return; 80005909d5cSTakashi Iwai if (spec->keep_eapd_on && !enable) 80105909d5cSTakashi Iwai return; 802468ac413STakashi Iwai if (codec->inv_eapd) 803468ac413STakashi Iwai enable = !enable; 804d5a9f1bbSTakashi Iwai snd_hda_codec_update_cache(codec, pin, 0, 805d5a9f1bbSTakashi Iwai AC_VERB_SET_EAPD_BTLENABLE, 806d5a9f1bbSTakashi Iwai enable ? 0x02 : 0x00); 807d5a9f1bbSTakashi Iwai } 808d5a9f1bbSTakashi Iwai 8093e367f15STakashi Iwai /* re-initialize the path specified by the given path index */ 8103e367f15STakashi Iwai static void resume_path_from_idx(struct hda_codec *codec, int path_idx) 8113e367f15STakashi Iwai { 8123e367f15STakashi Iwai struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx); 8133e367f15STakashi Iwai if (path) 8143e367f15STakashi Iwai snd_hda_activate_path(codec, path, path->active, false); 8153e367f15STakashi Iwai } 8163e367f15STakashi Iwai 817352f7f91STakashi Iwai 818352f7f91STakashi Iwai /* 819352f7f91STakashi Iwai * Helper functions for creating mixer ctl elements 820352f7f91STakashi Iwai */ 821352f7f91STakashi Iwai 8227eebffd3STakashi Iwai static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, 8237eebffd3STakashi Iwai struct snd_ctl_elem_value *ucontrol); 824bc2eee29STakashi Iwai static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol, 825bc2eee29STakashi Iwai struct snd_ctl_elem_value *ucontrol); 8267eebffd3STakashi Iwai 827352f7f91STakashi Iwai enum { 828352f7f91STakashi Iwai HDA_CTL_WIDGET_VOL, 829352f7f91STakashi Iwai HDA_CTL_WIDGET_MUTE, 830352f7f91STakashi Iwai HDA_CTL_BIND_MUTE, 831352f7f91STakashi Iwai }; 832352f7f91STakashi Iwai static const struct snd_kcontrol_new control_templates[] = { 833352f7f91STakashi Iwai HDA_CODEC_VOLUME(NULL, 0, 0, 0), 8347eebffd3STakashi Iwai /* only the put callback is replaced for handling the special mute */ 8357eebffd3STakashi Iwai { 8367eebffd3STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8377eebffd3STakashi Iwai .subdevice = HDA_SUBDEV_AMP_FLAG, 8387eebffd3STakashi Iwai .info = snd_hda_mixer_amp_switch_info, 8397eebffd3STakashi Iwai .get = snd_hda_mixer_amp_switch_get, 8407eebffd3STakashi Iwai .put = hda_gen_mixer_mute_put, /* replaced */ 8417eebffd3STakashi Iwai .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0), 8427eebffd3STakashi Iwai }, 843bc2eee29STakashi Iwai { 844bc2eee29STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 845bc2eee29STakashi Iwai .info = snd_hda_mixer_amp_switch_info, 846bc2eee29STakashi Iwai .get = snd_hda_mixer_bind_switch_get, 847bc2eee29STakashi Iwai .put = hda_gen_bind_mute_put, /* replaced */ 848bc2eee29STakashi Iwai .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0), 849bc2eee29STakashi Iwai }, 850352f7f91STakashi Iwai }; 851352f7f91STakashi Iwai 852352f7f91STakashi Iwai /* add dynamic controls from template */ 853a35bd1e3STakashi Iwai static struct snd_kcontrol_new * 854a35bd1e3STakashi Iwai add_control(struct hda_gen_spec *spec, int type, const char *name, 855352f7f91STakashi Iwai int cidx, unsigned long val) 856352f7f91STakashi Iwai { 857352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 858352f7f91STakashi Iwai 85912c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]); 860352f7f91STakashi Iwai if (!knew) 861a35bd1e3STakashi Iwai return NULL; 862352f7f91STakashi Iwai knew->index = cidx; 863352f7f91STakashi Iwai if (get_amp_nid_(val)) 864352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 865352f7f91STakashi Iwai knew->private_value = val; 866a35bd1e3STakashi Iwai return knew; 867352f7f91STakashi Iwai } 868352f7f91STakashi Iwai 869352f7f91STakashi Iwai static int add_control_with_pfx(struct hda_gen_spec *spec, int type, 870352f7f91STakashi Iwai const char *pfx, const char *dir, 871352f7f91STakashi Iwai const char *sfx, int cidx, unsigned long val) 872352f7f91STakashi Iwai { 873975cc02aSTakashi Iwai char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 874352f7f91STakashi Iwai snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); 875a35bd1e3STakashi Iwai if (!add_control(spec, type, name, cidx, val)) 876a35bd1e3STakashi Iwai return -ENOMEM; 877a35bd1e3STakashi Iwai return 0; 878352f7f91STakashi Iwai } 879352f7f91STakashi Iwai 880352f7f91STakashi Iwai #define add_pb_vol_ctrl(spec, type, pfx, val) \ 881352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val) 882352f7f91STakashi Iwai #define add_pb_sw_ctrl(spec, type, pfx, val) \ 883352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val) 884352f7f91STakashi Iwai #define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \ 885352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val) 886352f7f91STakashi Iwai #define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ 887352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) 888352f7f91STakashi Iwai 889352f7f91STakashi Iwai static int add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx, 890352f7f91STakashi Iwai unsigned int chs, struct nid_path *path) 891352f7f91STakashi Iwai { 892352f7f91STakashi Iwai unsigned int val; 893352f7f91STakashi Iwai if (!path) 894352f7f91STakashi Iwai return 0; 895352f7f91STakashi Iwai val = path->ctls[NID_PATH_VOL_CTL]; 896352f7f91STakashi Iwai if (!val) 897352f7f91STakashi Iwai return 0; 898352f7f91STakashi Iwai val = amp_val_replace_channels(val, chs); 899352f7f91STakashi Iwai return __add_pb_vol_ctrl(codec->spec, HDA_CTL_WIDGET_VOL, pfx, cidx, val); 900352f7f91STakashi Iwai } 901352f7f91STakashi Iwai 902352f7f91STakashi Iwai /* return the channel bits suitable for the given path->ctls[] */ 903352f7f91STakashi Iwai static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path, 904352f7f91STakashi Iwai int type) 905352f7f91STakashi Iwai { 906352f7f91STakashi Iwai int chs = 1; /* mono (left only) */ 907352f7f91STakashi Iwai if (path) { 908352f7f91STakashi Iwai hda_nid_t nid = get_amp_nid_(path->ctls[type]); 909352f7f91STakashi Iwai if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO)) 910352f7f91STakashi Iwai chs = 3; /* stereo */ 911352f7f91STakashi Iwai } 912352f7f91STakashi Iwai return chs; 913352f7f91STakashi Iwai } 914352f7f91STakashi Iwai 915352f7f91STakashi Iwai static int add_stereo_vol(struct hda_codec *codec, const char *pfx, int cidx, 916352f7f91STakashi Iwai struct nid_path *path) 917352f7f91STakashi Iwai { 918352f7f91STakashi Iwai int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL); 919352f7f91STakashi Iwai return add_vol_ctl(codec, pfx, cidx, chs, path); 920352f7f91STakashi Iwai } 921352f7f91STakashi Iwai 922352f7f91STakashi Iwai /* create a mute-switch for the given mixer widget; 923352f7f91STakashi Iwai * if it has multiple sources (e.g. DAC and loopback), create a bind-mute 924352f7f91STakashi Iwai */ 925352f7f91STakashi Iwai static int add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx, 926352f7f91STakashi Iwai unsigned int chs, struct nid_path *path) 927352f7f91STakashi Iwai { 928352f7f91STakashi Iwai unsigned int val; 929352f7f91STakashi Iwai int type = HDA_CTL_WIDGET_MUTE; 930352f7f91STakashi Iwai 931352f7f91STakashi Iwai if (!path) 932352f7f91STakashi Iwai return 0; 933352f7f91STakashi Iwai val = path->ctls[NID_PATH_MUTE_CTL]; 934352f7f91STakashi Iwai if (!val) 935352f7f91STakashi Iwai return 0; 936352f7f91STakashi Iwai val = amp_val_replace_channels(val, chs); 937352f7f91STakashi Iwai if (get_amp_direction_(val) == HDA_INPUT) { 938352f7f91STakashi Iwai hda_nid_t nid = get_amp_nid_(val); 939352f7f91STakashi Iwai int nums = snd_hda_get_num_conns(codec, nid); 940352f7f91STakashi Iwai if (nums > 1) { 941352f7f91STakashi Iwai type = HDA_CTL_BIND_MUTE; 942352f7f91STakashi Iwai val |= nums << 19; 943352f7f91STakashi Iwai } 944352f7f91STakashi Iwai } 945352f7f91STakashi Iwai return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val); 946352f7f91STakashi Iwai } 947352f7f91STakashi Iwai 948352f7f91STakashi Iwai static int add_stereo_sw(struct hda_codec *codec, const char *pfx, 949352f7f91STakashi Iwai int cidx, struct nid_path *path) 950352f7f91STakashi Iwai { 951352f7f91STakashi Iwai int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL); 952352f7f91STakashi Iwai return add_sw_ctl(codec, pfx, cidx, chs, path); 953352f7f91STakashi Iwai } 954352f7f91STakashi Iwai 9557eebffd3STakashi Iwai /* playback mute control with the software mute bit check */ 956bc2eee29STakashi Iwai static void sync_auto_mute_bits(struct snd_kcontrol *kcontrol, 9577eebffd3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 9587eebffd3STakashi Iwai { 9597eebffd3STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 9607eebffd3STakashi Iwai struct hda_gen_spec *spec = codec->spec; 9617eebffd3STakashi Iwai 9627eebffd3STakashi Iwai if (spec->auto_mute_via_amp) { 9637eebffd3STakashi Iwai hda_nid_t nid = get_amp_nid(kcontrol); 9647eebffd3STakashi Iwai bool enabled = !((spec->mute_bits >> nid) & 1); 9657eebffd3STakashi Iwai ucontrol->value.integer.value[0] &= enabled; 9667eebffd3STakashi Iwai ucontrol->value.integer.value[1] &= enabled; 9677eebffd3STakashi Iwai } 968bc2eee29STakashi Iwai } 9697eebffd3STakashi Iwai 970bc2eee29STakashi Iwai static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, 971bc2eee29STakashi Iwai struct snd_ctl_elem_value *ucontrol) 972bc2eee29STakashi Iwai { 973bc2eee29STakashi Iwai sync_auto_mute_bits(kcontrol, ucontrol); 9747eebffd3STakashi Iwai return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); 9757eebffd3STakashi Iwai } 9767eebffd3STakashi Iwai 977bc2eee29STakashi Iwai static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol, 978bc2eee29STakashi Iwai struct snd_ctl_elem_value *ucontrol) 979bc2eee29STakashi Iwai { 980bc2eee29STakashi Iwai sync_auto_mute_bits(kcontrol, ucontrol); 981bc2eee29STakashi Iwai return snd_hda_mixer_bind_switch_put(kcontrol, ucontrol); 982bc2eee29STakashi Iwai } 983bc2eee29STakashi Iwai 984247d85eeSTakashi Iwai /* any ctl assigned to the path with the given index? */ 985247d85eeSTakashi Iwai static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type) 986247d85eeSTakashi Iwai { 987247d85eeSTakashi Iwai struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx); 988247d85eeSTakashi Iwai return path && path->ctls[ctl_type]; 989247d85eeSTakashi Iwai } 990247d85eeSTakashi Iwai 991352f7f91STakashi Iwai static const char * const channel_name[4] = { 992352f7f91STakashi Iwai "Front", "Surround", "CLFE", "Side" 993352f7f91STakashi Iwai }; 994352f7f91STakashi Iwai 995352f7f91STakashi Iwai /* give some appropriate ctl name prefix for the given line out channel */ 996247d85eeSTakashi Iwai static const char *get_line_out_pfx(struct hda_codec *codec, int ch, 997247d85eeSTakashi Iwai int *index, int ctl_type) 998352f7f91STakashi Iwai { 999247d85eeSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 1000352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1001352f7f91STakashi Iwai 1002352f7f91STakashi Iwai *index = 0; 1003352f7f91STakashi Iwai if (cfg->line_outs == 1 && !spec->multi_ios && 1004247d85eeSTakashi Iwai !cfg->hp_outs && !cfg->speaker_outs) 1005352f7f91STakashi Iwai return spec->vmaster_mute.hook ? "PCM" : "Master"; 1006352f7f91STakashi Iwai 1007352f7f91STakashi Iwai /* if there is really a single DAC used in the whole output paths, 1008352f7f91STakashi Iwai * use it master (or "PCM" if a vmaster hook is present) 1009352f7f91STakashi Iwai */ 1010352f7f91STakashi Iwai if (spec->multiout.num_dacs == 1 && !spec->mixer_nid && 1011352f7f91STakashi Iwai !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0]) 1012352f7f91STakashi Iwai return spec->vmaster_mute.hook ? "PCM" : "Master"; 1013352f7f91STakashi Iwai 1014247d85eeSTakashi Iwai /* multi-io channels */ 1015247d85eeSTakashi Iwai if (ch >= cfg->line_outs) 1016247d85eeSTakashi Iwai return channel_name[ch]; 1017247d85eeSTakashi Iwai 1018352f7f91STakashi Iwai switch (cfg->line_out_type) { 1019352f7f91STakashi Iwai case AUTO_PIN_SPEAKER_OUT: 1020247d85eeSTakashi Iwai /* if the primary channel vol/mute is shared with HP volume, 1021247d85eeSTakashi Iwai * don't name it as Speaker 1022247d85eeSTakashi Iwai */ 1023247d85eeSTakashi Iwai if (!ch && cfg->hp_outs && 1024247d85eeSTakashi Iwai !path_has_mixer(codec, spec->hp_paths[0], ctl_type)) 1025247d85eeSTakashi Iwai break; 1026352f7f91STakashi Iwai if (cfg->line_outs == 1) 1027352f7f91STakashi Iwai return "Speaker"; 1028352f7f91STakashi Iwai if (cfg->line_outs == 2) 1029352f7f91STakashi Iwai return ch ? "Bass Speaker" : "Speaker"; 1030352f7f91STakashi Iwai break; 1031352f7f91STakashi Iwai case AUTO_PIN_HP_OUT: 1032247d85eeSTakashi Iwai /* if the primary channel vol/mute is shared with spk volume, 1033247d85eeSTakashi Iwai * don't name it as Headphone 1034247d85eeSTakashi Iwai */ 1035247d85eeSTakashi Iwai if (!ch && cfg->speaker_outs && 1036247d85eeSTakashi Iwai !path_has_mixer(codec, spec->speaker_paths[0], ctl_type)) 1037247d85eeSTakashi Iwai break; 1038352f7f91STakashi Iwai /* for multi-io case, only the primary out */ 1039352f7f91STakashi Iwai if (ch && spec->multi_ios) 1040352f7f91STakashi Iwai break; 1041352f7f91STakashi Iwai *index = ch; 1042352f7f91STakashi Iwai return "Headphone"; 1043247d85eeSTakashi Iwai } 1044247d85eeSTakashi Iwai 1045247d85eeSTakashi Iwai /* for a single channel output, we don't have to name the channel */ 1046352f7f91STakashi Iwai if (cfg->line_outs == 1 && !spec->multi_ios) 1047352f7f91STakashi Iwai return "PCM"; 1048247d85eeSTakashi Iwai 1049352f7f91STakashi Iwai if (ch >= ARRAY_SIZE(channel_name)) { 1050352f7f91STakashi Iwai snd_BUG(); 1051352f7f91STakashi Iwai return "PCM"; 1052352f7f91STakashi Iwai } 1053352f7f91STakashi Iwai 1054352f7f91STakashi Iwai return channel_name[ch]; 1055352f7f91STakashi Iwai } 1056352f7f91STakashi Iwai 1057352f7f91STakashi Iwai /* 1058352f7f91STakashi Iwai * Parse output paths 1059352f7f91STakashi Iwai */ 1060352f7f91STakashi Iwai 1061352f7f91STakashi Iwai /* badness definition */ 1062352f7f91STakashi Iwai enum { 1063352f7f91STakashi Iwai /* No primary DAC is found for the main output */ 1064352f7f91STakashi Iwai BAD_NO_PRIMARY_DAC = 0x10000, 1065352f7f91STakashi Iwai /* No DAC is found for the extra output */ 1066352f7f91STakashi Iwai BAD_NO_DAC = 0x4000, 1067352f7f91STakashi Iwai /* No possible multi-ios */ 10681d739066STakashi Iwai BAD_MULTI_IO = 0x120, 1069352f7f91STakashi Iwai /* No individual DAC for extra output */ 1070352f7f91STakashi Iwai BAD_NO_EXTRA_DAC = 0x102, 1071352f7f91STakashi Iwai /* No individual DAC for extra surrounds */ 1072352f7f91STakashi Iwai BAD_NO_EXTRA_SURR_DAC = 0x101, 1073352f7f91STakashi Iwai /* Primary DAC shared with main surrounds */ 1074352f7f91STakashi Iwai BAD_SHARED_SURROUND = 0x100, 107555a63d4dSTakashi Iwai /* No independent HP possible */ 1076bec8e680STakashi Iwai BAD_NO_INDEP_HP = 0x10, 1077352f7f91STakashi Iwai /* Primary DAC shared with main CLFE */ 1078352f7f91STakashi Iwai BAD_SHARED_CLFE = 0x10, 1079352f7f91STakashi Iwai /* Primary DAC shared with extra surrounds */ 1080352f7f91STakashi Iwai BAD_SHARED_EXTRA_SURROUND = 0x10, 1081352f7f91STakashi Iwai /* Volume widget is shared */ 1082352f7f91STakashi Iwai BAD_SHARED_VOL = 0x10, 1083352f7f91STakashi Iwai }; 1084352f7f91STakashi Iwai 10850e614dd0STakashi Iwai /* look for widgets in the given path which are appropriate for 1086352f7f91STakashi Iwai * volume and mute controls, and assign the values to ctls[]. 1087352f7f91STakashi Iwai * 1088352f7f91STakashi Iwai * When no appropriate widget is found in the path, the badness value 1089352f7f91STakashi Iwai * is incremented depending on the situation. The function returns the 1090352f7f91STakashi Iwai * total badness for both volume and mute controls. 1091352f7f91STakashi Iwai */ 10920e614dd0STakashi Iwai static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path) 1093352f7f91STakashi Iwai { 1094352f7f91STakashi Iwai hda_nid_t nid; 1095352f7f91STakashi Iwai unsigned int val; 1096352f7f91STakashi Iwai int badness = 0; 1097352f7f91STakashi Iwai 1098352f7f91STakashi Iwai if (!path) 1099352f7f91STakashi Iwai return BAD_SHARED_VOL * 2; 11000e614dd0STakashi Iwai 11010e614dd0STakashi Iwai if (path->ctls[NID_PATH_VOL_CTL] || 11020e614dd0STakashi Iwai path->ctls[NID_PATH_MUTE_CTL]) 11030e614dd0STakashi Iwai return 0; /* already evaluated */ 11040e614dd0STakashi Iwai 1105352f7f91STakashi Iwai nid = look_for_out_vol_nid(codec, path); 1106352f7f91STakashi Iwai if (nid) { 1107352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 1108352f7f91STakashi Iwai if (is_ctl_used(codec, val, NID_PATH_VOL_CTL)) 1109352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 1110352f7f91STakashi Iwai else 1111352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = val; 1112352f7f91STakashi Iwai } else 1113352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 1114352f7f91STakashi Iwai nid = look_for_out_mute_nid(codec, path); 1115352f7f91STakashi Iwai if (nid) { 1116352f7f91STakashi Iwai unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid)); 1117352f7f91STakashi Iwai if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT || 1118352f7f91STakashi Iwai nid_has_mute(codec, nid, HDA_OUTPUT)) 1119352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 1120352f7f91STakashi Iwai else 1121352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); 1122352f7f91STakashi Iwai if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL)) 1123352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 1124352f7f91STakashi Iwai else 1125352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = val; 1126352f7f91STakashi Iwai } else 1127352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 1128352f7f91STakashi Iwai return badness; 1129352f7f91STakashi Iwai } 1130352f7f91STakashi Iwai 113198bd1115STakashi Iwai const struct badness_table hda_main_out_badness = { 1132352f7f91STakashi Iwai .no_primary_dac = BAD_NO_PRIMARY_DAC, 1133352f7f91STakashi Iwai .no_dac = BAD_NO_DAC, 1134352f7f91STakashi Iwai .shared_primary = BAD_NO_PRIMARY_DAC, 1135352f7f91STakashi Iwai .shared_surr = BAD_SHARED_SURROUND, 1136352f7f91STakashi Iwai .shared_clfe = BAD_SHARED_CLFE, 1137352f7f91STakashi Iwai .shared_surr_main = BAD_SHARED_SURROUND, 1138352f7f91STakashi Iwai }; 113998bd1115STakashi Iwai EXPORT_SYMBOL_HDA(hda_main_out_badness); 1140352f7f91STakashi Iwai 114198bd1115STakashi Iwai const struct badness_table hda_extra_out_badness = { 1142352f7f91STakashi Iwai .no_primary_dac = BAD_NO_DAC, 1143352f7f91STakashi Iwai .no_dac = BAD_NO_DAC, 1144352f7f91STakashi Iwai .shared_primary = BAD_NO_EXTRA_DAC, 1145352f7f91STakashi Iwai .shared_surr = BAD_SHARED_EXTRA_SURROUND, 1146352f7f91STakashi Iwai .shared_clfe = BAD_SHARED_EXTRA_SURROUND, 1147352f7f91STakashi Iwai .shared_surr_main = BAD_NO_EXTRA_SURR_DAC, 1148352f7f91STakashi Iwai }; 114998bd1115STakashi Iwai EXPORT_SYMBOL_HDA(hda_extra_out_badness); 1150352f7f91STakashi Iwai 11517385df61STakashi Iwai /* get the DAC of the primary output corresponding to the given array index */ 11527385df61STakashi Iwai static hda_nid_t get_primary_out(struct hda_codec *codec, int idx) 11537385df61STakashi Iwai { 11547385df61STakashi Iwai struct hda_gen_spec *spec = codec->spec; 11557385df61STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 11567385df61STakashi Iwai 11577385df61STakashi Iwai if (cfg->line_outs > idx) 11587385df61STakashi Iwai return spec->private_dac_nids[idx]; 11597385df61STakashi Iwai idx -= cfg->line_outs; 11607385df61STakashi Iwai if (spec->multi_ios > idx) 11617385df61STakashi Iwai return spec->multi_io[idx].dac; 11627385df61STakashi Iwai return 0; 11637385df61STakashi Iwai } 11647385df61STakashi Iwai 11657385df61STakashi Iwai /* return the DAC if it's reachable, otherwise zero */ 11667385df61STakashi Iwai static inline hda_nid_t try_dac(struct hda_codec *codec, 11677385df61STakashi Iwai hda_nid_t dac, hda_nid_t pin) 11687385df61STakashi Iwai { 11697385df61STakashi Iwai return is_reachable_path(codec, dac, pin) ? dac : 0; 11707385df61STakashi Iwai } 11717385df61STakashi Iwai 1172352f7f91STakashi Iwai /* try to assign DACs to pins and return the resultant badness */ 1173352f7f91STakashi Iwai static int try_assign_dacs(struct hda_codec *codec, int num_outs, 1174352f7f91STakashi Iwai const hda_nid_t *pins, hda_nid_t *dacs, 1175196c1766STakashi Iwai int *path_idx, 1176352f7f91STakashi Iwai const struct badness_table *bad) 1177352f7f91STakashi Iwai { 1178352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1179352f7f91STakashi Iwai int i, j; 1180352f7f91STakashi Iwai int badness = 0; 1181352f7f91STakashi Iwai hda_nid_t dac; 1182352f7f91STakashi Iwai 1183352f7f91STakashi Iwai if (!num_outs) 1184352f7f91STakashi Iwai return 0; 1185352f7f91STakashi Iwai 1186352f7f91STakashi Iwai for (i = 0; i < num_outs; i++) { 11870c8c0f56STakashi Iwai struct nid_path *path; 1188352f7f91STakashi Iwai hda_nid_t pin = pins[i]; 11891e0b5286STakashi Iwai 11900e614dd0STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx[i]); 11910e614dd0STakashi Iwai if (path) { 11920e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path); 11931e0b5286STakashi Iwai continue; 11941e0b5286STakashi Iwai } 11951e0b5286STakashi Iwai 1196352f7f91STakashi Iwai dacs[i] = look_for_dac(codec, pin, false); 1197352f7f91STakashi Iwai if (!dacs[i] && !i) { 1198980428ceSTakashi Iwai /* try to steal the DAC of surrounds for the front */ 1199352f7f91STakashi Iwai for (j = 1; j < num_outs; j++) { 1200352f7f91STakashi Iwai if (is_reachable_path(codec, dacs[j], pin)) { 1201352f7f91STakashi Iwai dacs[0] = dacs[j]; 1202352f7f91STakashi Iwai dacs[j] = 0; 1203980428ceSTakashi Iwai invalidate_nid_path(codec, path_idx[j]); 1204196c1766STakashi Iwai path_idx[j] = 0; 1205352f7f91STakashi Iwai break; 1206352f7f91STakashi Iwai } 1207352f7f91STakashi Iwai } 1208352f7f91STakashi Iwai } 1209352f7f91STakashi Iwai dac = dacs[i]; 1210352f7f91STakashi Iwai if (!dac) { 12117385df61STakashi Iwai if (num_outs > 2) 12127385df61STakashi Iwai dac = try_dac(codec, get_primary_out(codec, i), pin); 12137385df61STakashi Iwai if (!dac) 12147385df61STakashi Iwai dac = try_dac(codec, dacs[0], pin); 12157385df61STakashi Iwai if (!dac) 12167385df61STakashi Iwai dac = try_dac(codec, get_primary_out(codec, i), pin); 1217352f7f91STakashi Iwai if (dac) { 1218352f7f91STakashi Iwai if (!i) 1219352f7f91STakashi Iwai badness += bad->shared_primary; 1220352f7f91STakashi Iwai else if (i == 1) 1221352f7f91STakashi Iwai badness += bad->shared_surr; 1222352f7f91STakashi Iwai else 1223352f7f91STakashi Iwai badness += bad->shared_clfe; 1224352f7f91STakashi Iwai } else if (is_reachable_path(codec, spec->private_dac_nids[0], pin)) { 1225352f7f91STakashi Iwai dac = spec->private_dac_nids[0]; 1226352f7f91STakashi Iwai badness += bad->shared_surr_main; 1227352f7f91STakashi Iwai } else if (!i) 1228352f7f91STakashi Iwai badness += bad->no_primary_dac; 1229352f7f91STakashi Iwai else 1230352f7f91STakashi Iwai badness += bad->no_dac; 1231352f7f91STakashi Iwai } 12321fa335b0STakashi Iwai if (!dac) 12331fa335b0STakashi Iwai continue; 12343ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, -spec->mixer_nid); 1235117688a9STakashi Iwai if (!path && !i && spec->mixer_nid) { 1236b3a8c745STakashi Iwai /* try with aamix */ 12373ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, 0); 1238b3a8c745STakashi Iwai } 12391fa335b0STakashi Iwai if (!path) { 1240352f7f91STakashi Iwai dac = dacs[i] = 0; 12411fa335b0STakashi Iwai badness += bad->no_dac; 12421fa335b0STakashi Iwai } else { 1243a769409cSTakashi Iwai /* print_nid_path("output", path); */ 1244e1284af7STakashi Iwai path->active = true; 1245196c1766STakashi Iwai path_idx[i] = snd_hda_get_path_idx(codec, path); 12460e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path); 1247e1284af7STakashi Iwai } 1248352f7f91STakashi Iwai } 1249352f7f91STakashi Iwai 1250352f7f91STakashi Iwai return badness; 1251352f7f91STakashi Iwai } 1252352f7f91STakashi Iwai 1253352f7f91STakashi Iwai /* return NID if the given pin has only a single connection to a certain DAC */ 1254352f7f91STakashi Iwai static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) 1255352f7f91STakashi Iwai { 1256352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1257352f7f91STakashi Iwai int i; 1258352f7f91STakashi Iwai hda_nid_t nid_found = 0; 1259352f7f91STakashi Iwai 1260352f7f91STakashi Iwai for (i = 0; i < spec->num_all_dacs; i++) { 1261352f7f91STakashi Iwai hda_nid_t nid = spec->all_dacs[i]; 1262352f7f91STakashi Iwai if (!nid || is_dac_already_used(codec, nid)) 1263352f7f91STakashi Iwai continue; 1264352f7f91STakashi Iwai if (is_reachable_path(codec, nid, pin)) { 1265352f7f91STakashi Iwai if (nid_found) 1266352f7f91STakashi Iwai return 0; 1267352f7f91STakashi Iwai nid_found = nid; 1268352f7f91STakashi Iwai } 1269352f7f91STakashi Iwai } 1270352f7f91STakashi Iwai return nid_found; 1271352f7f91STakashi Iwai } 1272352f7f91STakashi Iwai 1273352f7f91STakashi Iwai /* check whether the given pin can be a multi-io pin */ 1274352f7f91STakashi Iwai static bool can_be_multiio_pin(struct hda_codec *codec, 1275352f7f91STakashi Iwai unsigned int location, hda_nid_t nid) 1276352f7f91STakashi Iwai { 1277352f7f91STakashi Iwai unsigned int defcfg, caps; 1278352f7f91STakashi Iwai 1279352f7f91STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, nid); 1280352f7f91STakashi Iwai if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) 1281352f7f91STakashi Iwai return false; 1282352f7f91STakashi Iwai if (location && get_defcfg_location(defcfg) != location) 1283352f7f91STakashi Iwai return false; 1284352f7f91STakashi Iwai caps = snd_hda_query_pin_caps(codec, nid); 1285352f7f91STakashi Iwai if (!(caps & AC_PINCAP_OUT)) 1286352f7f91STakashi Iwai return false; 1287352f7f91STakashi Iwai return true; 1288352f7f91STakashi Iwai } 1289352f7f91STakashi Iwai 1290e22aab7dSTakashi Iwai /* count the number of input pins that are capable to be multi-io */ 1291e22aab7dSTakashi Iwai static int count_multiio_pins(struct hda_codec *codec, hda_nid_t reference_pin) 1292e22aab7dSTakashi Iwai { 1293e22aab7dSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 1294e22aab7dSTakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1295e22aab7dSTakashi Iwai unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); 1296e22aab7dSTakashi Iwai unsigned int location = get_defcfg_location(defcfg); 1297e22aab7dSTakashi Iwai int type, i; 1298e22aab7dSTakashi Iwai int num_pins = 0; 1299e22aab7dSTakashi Iwai 1300e22aab7dSTakashi Iwai for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { 1301e22aab7dSTakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 1302e22aab7dSTakashi Iwai if (cfg->inputs[i].type != type) 1303e22aab7dSTakashi Iwai continue; 1304e22aab7dSTakashi Iwai if (can_be_multiio_pin(codec, location, 1305e22aab7dSTakashi Iwai cfg->inputs[i].pin)) 1306e22aab7dSTakashi Iwai num_pins++; 1307e22aab7dSTakashi Iwai } 1308e22aab7dSTakashi Iwai } 1309e22aab7dSTakashi Iwai return num_pins; 1310e22aab7dSTakashi Iwai } 1311e22aab7dSTakashi Iwai 1312352f7f91STakashi Iwai /* 1313352f7f91STakashi Iwai * multi-io helper 1314352f7f91STakashi Iwai * 1315352f7f91STakashi Iwai * When hardwired is set, try to fill ony hardwired pins, and returns 1316352f7f91STakashi Iwai * zero if any pins are filled, non-zero if nothing found. 1317352f7f91STakashi Iwai * When hardwired is off, try to fill possible input pins, and returns 1318352f7f91STakashi Iwai * the badness value. 1319352f7f91STakashi Iwai */ 1320352f7f91STakashi Iwai static int fill_multi_ios(struct hda_codec *codec, 1321352f7f91STakashi Iwai hda_nid_t reference_pin, 1322e22aab7dSTakashi Iwai bool hardwired) 1323352f7f91STakashi Iwai { 1324352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1325352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1326e22aab7dSTakashi Iwai int type, i, j, num_pins, old_pins; 1327352f7f91STakashi Iwai unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); 1328352f7f91STakashi Iwai unsigned int location = get_defcfg_location(defcfg); 1329352f7f91STakashi Iwai int badness = 0; 13300e614dd0STakashi Iwai struct nid_path *path; 1331352f7f91STakashi Iwai 1332352f7f91STakashi Iwai old_pins = spec->multi_ios; 1333352f7f91STakashi Iwai if (old_pins >= 2) 1334352f7f91STakashi Iwai goto end_fill; 1335352f7f91STakashi Iwai 1336e22aab7dSTakashi Iwai num_pins = count_multiio_pins(codec, reference_pin); 1337352f7f91STakashi Iwai if (num_pins < 2) 1338352f7f91STakashi Iwai goto end_fill; 1339352f7f91STakashi Iwai 1340352f7f91STakashi Iwai for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { 1341352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 1342352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 1343352f7f91STakashi Iwai hda_nid_t dac = 0; 1344352f7f91STakashi Iwai 1345352f7f91STakashi Iwai if (cfg->inputs[i].type != type) 1346352f7f91STakashi Iwai continue; 1347352f7f91STakashi Iwai if (!can_be_multiio_pin(codec, location, nid)) 1348352f7f91STakashi Iwai continue; 1349352f7f91STakashi Iwai for (j = 0; j < spec->multi_ios; j++) { 1350352f7f91STakashi Iwai if (nid == spec->multi_io[j].pin) 1351352f7f91STakashi Iwai break; 1352352f7f91STakashi Iwai } 1353352f7f91STakashi Iwai if (j < spec->multi_ios) 1354352f7f91STakashi Iwai continue; 1355352f7f91STakashi Iwai 1356352f7f91STakashi Iwai if (hardwired) 1357352f7f91STakashi Iwai dac = get_dac_if_single(codec, nid); 1358352f7f91STakashi Iwai else if (!dac) 1359352f7f91STakashi Iwai dac = look_for_dac(codec, nid, false); 1360352f7f91STakashi Iwai if (!dac) { 1361352f7f91STakashi Iwai badness++; 1362352f7f91STakashi Iwai continue; 1363352f7f91STakashi Iwai } 13643ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, nid, 13653ca529d3STakashi Iwai -spec->mixer_nid); 13660c8c0f56STakashi Iwai if (!path) { 1367352f7f91STakashi Iwai badness++; 1368352f7f91STakashi Iwai continue; 1369352f7f91STakashi Iwai } 1370a769409cSTakashi Iwai /* print_nid_path("multiio", path); */ 1371352f7f91STakashi Iwai spec->multi_io[spec->multi_ios].pin = nid; 1372352f7f91STakashi Iwai spec->multi_io[spec->multi_ios].dac = dac; 1373196c1766STakashi Iwai spec->out_paths[cfg->line_outs + spec->multi_ios] = 1374196c1766STakashi Iwai snd_hda_get_path_idx(codec, path); 1375352f7f91STakashi Iwai spec->multi_ios++; 1376352f7f91STakashi Iwai if (spec->multi_ios >= 2) 1377352f7f91STakashi Iwai break; 1378352f7f91STakashi Iwai } 1379352f7f91STakashi Iwai } 1380352f7f91STakashi Iwai end_fill: 1381352f7f91STakashi Iwai if (badness) 1382352f7f91STakashi Iwai badness = BAD_MULTI_IO; 1383352f7f91STakashi Iwai if (old_pins == spec->multi_ios) { 1384352f7f91STakashi Iwai if (hardwired) 1385352f7f91STakashi Iwai return 1; /* nothing found */ 1386352f7f91STakashi Iwai else 1387352f7f91STakashi Iwai return badness; /* no badness if nothing found */ 1388352f7f91STakashi Iwai } 1389352f7f91STakashi Iwai if (!hardwired && spec->multi_ios < 2) { 1390352f7f91STakashi Iwai /* cancel newly assigned paths */ 1391352f7f91STakashi Iwai spec->paths.used -= spec->multi_ios - old_pins; 1392352f7f91STakashi Iwai spec->multi_ios = old_pins; 1393352f7f91STakashi Iwai return badness; 1394352f7f91STakashi Iwai } 1395352f7f91STakashi Iwai 1396352f7f91STakashi Iwai /* assign volume and mute controls */ 13970e614dd0STakashi Iwai for (i = old_pins; i < spec->multi_ios; i++) { 13980e614dd0STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[cfg->line_outs + i]); 13990e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path); 14000e614dd0STakashi Iwai } 1401352f7f91STakashi Iwai 1402352f7f91STakashi Iwai return badness; 1403352f7f91STakashi Iwai } 1404352f7f91STakashi Iwai 1405352f7f91STakashi Iwai /* map DACs for all pins in the list if they are single connections */ 1406352f7f91STakashi Iwai static bool map_singles(struct hda_codec *codec, int outs, 1407196c1766STakashi Iwai const hda_nid_t *pins, hda_nid_t *dacs, int *path_idx) 1408352f7f91STakashi Iwai { 1409b3a8c745STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1410352f7f91STakashi Iwai int i; 1411352f7f91STakashi Iwai bool found = false; 1412352f7f91STakashi Iwai for (i = 0; i < outs; i++) { 14130c8c0f56STakashi Iwai struct nid_path *path; 1414352f7f91STakashi Iwai hda_nid_t dac; 1415352f7f91STakashi Iwai if (dacs[i]) 1416352f7f91STakashi Iwai continue; 1417352f7f91STakashi Iwai dac = get_dac_if_single(codec, pins[i]); 1418352f7f91STakashi Iwai if (!dac) 1419352f7f91STakashi Iwai continue; 14203ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pins[i], 14213ca529d3STakashi Iwai -spec->mixer_nid); 1422117688a9STakashi Iwai if (!path && !i && spec->mixer_nid) 14233ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pins[i], 0); 14240c8c0f56STakashi Iwai if (path) { 1425352f7f91STakashi Iwai dacs[i] = dac; 1426352f7f91STakashi Iwai found = true; 1427a769409cSTakashi Iwai /* print_nid_path("output", path); */ 1428e1284af7STakashi Iwai path->active = true; 1429196c1766STakashi Iwai path_idx[i] = snd_hda_get_path_idx(codec, path); 1430352f7f91STakashi Iwai } 1431352f7f91STakashi Iwai } 1432352f7f91STakashi Iwai return found; 1433352f7f91STakashi Iwai } 1434352f7f91STakashi Iwai 1435c30aa7b2STakashi Iwai /* create a new path including aamix if available, and return its index */ 1436c30aa7b2STakashi Iwai static int check_aamix_out_path(struct hda_codec *codec, int path_idx) 1437c30aa7b2STakashi Iwai { 14383ca529d3STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1439c30aa7b2STakashi Iwai struct nid_path *path; 14405ead56f2STakashi Iwai hda_nid_t path_dac, dac, pin; 1441c30aa7b2STakashi Iwai 1442c30aa7b2STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 14433ca529d3STakashi Iwai if (!path || !path->depth || 14443ca529d3STakashi Iwai is_nid_contained(path, spec->mixer_nid)) 1445c30aa7b2STakashi Iwai return 0; 14465ead56f2STakashi Iwai path_dac = path->path[0]; 14475ead56f2STakashi Iwai dac = spec->private_dac_nids[0]; 1448f87498b6STakashi Iwai pin = path->path[path->depth - 1]; 1449f87498b6STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, spec->mixer_nid); 1450f87498b6STakashi Iwai if (!path) { 14515ead56f2STakashi Iwai if (dac != path_dac) 14525ead56f2STakashi Iwai dac = path_dac; 1453f87498b6STakashi Iwai else if (spec->multiout.hp_out_nid[0]) 1454f87498b6STakashi Iwai dac = spec->multiout.hp_out_nid[0]; 1455f87498b6STakashi Iwai else if (spec->multiout.extra_out_nid[0]) 1456f87498b6STakashi Iwai dac = spec->multiout.extra_out_nid[0]; 14575ead56f2STakashi Iwai else 14585ead56f2STakashi Iwai dac = 0; 1459f87498b6STakashi Iwai if (dac) 1460f87498b6STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, 14613ca529d3STakashi Iwai spec->mixer_nid); 1462f87498b6STakashi Iwai } 1463c30aa7b2STakashi Iwai if (!path) 1464c30aa7b2STakashi Iwai return 0; 1465a769409cSTakashi Iwai /* print_nid_path("output-aamix", path); */ 1466c30aa7b2STakashi Iwai path->active = false; /* unused as default */ 1467c30aa7b2STakashi Iwai return snd_hda_get_path_idx(codec, path); 1468c30aa7b2STakashi Iwai } 1469c30aa7b2STakashi Iwai 147055a63d4dSTakashi Iwai /* check whether the independent HP is available with the current config */ 147155a63d4dSTakashi Iwai static bool indep_hp_possible(struct hda_codec *codec) 147255a63d4dSTakashi Iwai { 147355a63d4dSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 147455a63d4dSTakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 147555a63d4dSTakashi Iwai struct nid_path *path; 147655a63d4dSTakashi Iwai int i, idx; 147755a63d4dSTakashi Iwai 147855a63d4dSTakashi Iwai if (cfg->line_out_type == AUTO_PIN_HP_OUT) 147955a63d4dSTakashi Iwai idx = spec->out_paths[0]; 148055a63d4dSTakashi Iwai else 148155a63d4dSTakashi Iwai idx = spec->hp_paths[0]; 148255a63d4dSTakashi Iwai path = snd_hda_get_path_from_idx(codec, idx); 148355a63d4dSTakashi Iwai if (!path) 148455a63d4dSTakashi Iwai return false; 148555a63d4dSTakashi Iwai 148655a63d4dSTakashi Iwai /* assume no path conflicts unless aamix is involved */ 148755a63d4dSTakashi Iwai if (!spec->mixer_nid || !is_nid_contained(path, spec->mixer_nid)) 148855a63d4dSTakashi Iwai return true; 148955a63d4dSTakashi Iwai 149055a63d4dSTakashi Iwai /* check whether output paths contain aamix */ 149155a63d4dSTakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 149255a63d4dSTakashi Iwai if (spec->out_paths[i] == idx) 149355a63d4dSTakashi Iwai break; 149455a63d4dSTakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]); 149555a63d4dSTakashi Iwai if (path && is_nid_contained(path, spec->mixer_nid)) 149655a63d4dSTakashi Iwai return false; 149755a63d4dSTakashi Iwai } 149855a63d4dSTakashi Iwai for (i = 0; i < cfg->speaker_outs; i++) { 149955a63d4dSTakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->speaker_paths[i]); 150055a63d4dSTakashi Iwai if (path && is_nid_contained(path, spec->mixer_nid)) 150155a63d4dSTakashi Iwai return false; 150255a63d4dSTakashi Iwai } 150355a63d4dSTakashi Iwai 150455a63d4dSTakashi Iwai return true; 150555a63d4dSTakashi Iwai } 150655a63d4dSTakashi Iwai 1507a07a949bSTakashi Iwai /* fill the empty entries in the dac array for speaker/hp with the 1508a07a949bSTakashi Iwai * shared dac pointed by the paths 1509a07a949bSTakashi Iwai */ 1510a07a949bSTakashi Iwai static void refill_shared_dacs(struct hda_codec *codec, int num_outs, 1511a07a949bSTakashi Iwai hda_nid_t *dacs, int *path_idx) 1512a07a949bSTakashi Iwai { 1513a07a949bSTakashi Iwai struct nid_path *path; 1514a07a949bSTakashi Iwai int i; 1515a07a949bSTakashi Iwai 1516a07a949bSTakashi Iwai for (i = 0; i < num_outs; i++) { 1517a07a949bSTakashi Iwai if (dacs[i]) 1518a07a949bSTakashi Iwai continue; 1519a07a949bSTakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx[i]); 1520a07a949bSTakashi Iwai if (!path) 1521a07a949bSTakashi Iwai continue; 1522a07a949bSTakashi Iwai dacs[i] = path->path[0]; 1523a07a949bSTakashi Iwai } 1524a07a949bSTakashi Iwai } 1525a07a949bSTakashi Iwai 1526352f7f91STakashi Iwai /* fill in the dac_nids table from the parsed pin configuration */ 1527352f7f91STakashi Iwai static int fill_and_eval_dacs(struct hda_codec *codec, 1528352f7f91STakashi Iwai bool fill_hardwired, 1529352f7f91STakashi Iwai bool fill_mio_first) 1530352f7f91STakashi Iwai { 1531352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1532352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1533352f7f91STakashi Iwai int i, err, badness; 1534352f7f91STakashi Iwai 1535352f7f91STakashi Iwai /* set num_dacs once to full for look_for_dac() */ 1536352f7f91STakashi Iwai spec->multiout.num_dacs = cfg->line_outs; 1537352f7f91STakashi Iwai spec->multiout.dac_nids = spec->private_dac_nids; 1538352f7f91STakashi Iwai memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); 1539352f7f91STakashi Iwai memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid)); 1540352f7f91STakashi Iwai memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid)); 1541352f7f91STakashi Iwai spec->multi_ios = 0; 1542352f7f91STakashi Iwai snd_array_free(&spec->paths); 1543cd5be3f9STakashi Iwai 1544cd5be3f9STakashi Iwai /* clear path indices */ 1545cd5be3f9STakashi Iwai memset(spec->out_paths, 0, sizeof(spec->out_paths)); 1546cd5be3f9STakashi Iwai memset(spec->hp_paths, 0, sizeof(spec->hp_paths)); 1547cd5be3f9STakashi Iwai memset(spec->speaker_paths, 0, sizeof(spec->speaker_paths)); 1548cd5be3f9STakashi Iwai memset(spec->aamix_out_paths, 0, sizeof(spec->aamix_out_paths)); 1549cd5be3f9STakashi Iwai memset(spec->digout_paths, 0, sizeof(spec->digout_paths)); 1550c697b716STakashi Iwai memset(spec->input_paths, 0, sizeof(spec->input_paths)); 1551cd5be3f9STakashi Iwai memset(spec->loopback_paths, 0, sizeof(spec->loopback_paths)); 1552cd5be3f9STakashi Iwai memset(&spec->digin_path, 0, sizeof(spec->digin_path)); 1553cd5be3f9STakashi Iwai 1554352f7f91STakashi Iwai badness = 0; 1555352f7f91STakashi Iwai 1556352f7f91STakashi Iwai /* fill hard-wired DACs first */ 1557352f7f91STakashi Iwai if (fill_hardwired) { 1558352f7f91STakashi Iwai bool mapped; 1559352f7f91STakashi Iwai do { 1560352f7f91STakashi Iwai mapped = map_singles(codec, cfg->line_outs, 1561352f7f91STakashi Iwai cfg->line_out_pins, 1562196c1766STakashi Iwai spec->private_dac_nids, 1563196c1766STakashi Iwai spec->out_paths); 1564352f7f91STakashi Iwai mapped |= map_singles(codec, cfg->hp_outs, 1565352f7f91STakashi Iwai cfg->hp_pins, 1566196c1766STakashi Iwai spec->multiout.hp_out_nid, 1567196c1766STakashi Iwai spec->hp_paths); 1568352f7f91STakashi Iwai mapped |= map_singles(codec, cfg->speaker_outs, 1569352f7f91STakashi Iwai cfg->speaker_pins, 1570196c1766STakashi Iwai spec->multiout.extra_out_nid, 1571196c1766STakashi Iwai spec->speaker_paths); 1572da96fb5bSTakashi Iwai if (!spec->no_multi_io && 1573da96fb5bSTakashi Iwai fill_mio_first && cfg->line_outs == 1 && 1574352f7f91STakashi Iwai cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1575e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], true); 1576352f7f91STakashi Iwai if (!err) 1577352f7f91STakashi Iwai mapped = true; 1578352f7f91STakashi Iwai } 1579352f7f91STakashi Iwai } while (mapped); 1580352f7f91STakashi Iwai } 1581352f7f91STakashi Iwai 1582352f7f91STakashi Iwai badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins, 1583196c1766STakashi Iwai spec->private_dac_nids, spec->out_paths, 158498bd1115STakashi Iwai spec->main_out_badness); 1585352f7f91STakashi Iwai 1586da96fb5bSTakashi Iwai if (!spec->no_multi_io && fill_mio_first && 1587352f7f91STakashi Iwai cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1588352f7f91STakashi Iwai /* try to fill multi-io first */ 1589e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], false); 1590352f7f91STakashi Iwai if (err < 0) 1591352f7f91STakashi Iwai return err; 1592352f7f91STakashi Iwai /* we don't count badness at this stage yet */ 1593352f7f91STakashi Iwai } 1594352f7f91STakashi Iwai 1595352f7f91STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) { 1596352f7f91STakashi Iwai err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins, 1597352f7f91STakashi Iwai spec->multiout.hp_out_nid, 1598196c1766STakashi Iwai spec->hp_paths, 159998bd1115STakashi Iwai spec->extra_out_badness); 1600352f7f91STakashi Iwai if (err < 0) 1601352f7f91STakashi Iwai return err; 1602352f7f91STakashi Iwai badness += err; 1603352f7f91STakashi Iwai } 1604352f7f91STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1605352f7f91STakashi Iwai err = try_assign_dacs(codec, cfg->speaker_outs, 1606352f7f91STakashi Iwai cfg->speaker_pins, 1607352f7f91STakashi Iwai spec->multiout.extra_out_nid, 1608196c1766STakashi Iwai spec->speaker_paths, 160998bd1115STakashi Iwai spec->extra_out_badness); 1610352f7f91STakashi Iwai if (err < 0) 1611352f7f91STakashi Iwai return err; 1612352f7f91STakashi Iwai badness += err; 1613352f7f91STakashi Iwai } 1614da96fb5bSTakashi Iwai if (!spec->no_multi_io && 1615da96fb5bSTakashi Iwai cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1616e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], false); 1617352f7f91STakashi Iwai if (err < 0) 1618352f7f91STakashi Iwai return err; 1619352f7f91STakashi Iwai badness += err; 1620352f7f91STakashi Iwai } 1621e22aab7dSTakashi Iwai 1622c30aa7b2STakashi Iwai if (spec->mixer_nid) { 1623c30aa7b2STakashi Iwai spec->aamix_out_paths[0] = 1624c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->out_paths[0]); 1625c30aa7b2STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 1626c30aa7b2STakashi Iwai spec->aamix_out_paths[1] = 1627c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->hp_paths[0]); 1628c30aa7b2STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 1629c30aa7b2STakashi Iwai spec->aamix_out_paths[2] = 1630c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->speaker_paths[0]); 1631c30aa7b2STakashi Iwai } 1632c30aa7b2STakashi Iwai 1633da96fb5bSTakashi Iwai if (!spec->no_multi_io && 1634da96fb5bSTakashi Iwai cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) 1635e22aab7dSTakashi Iwai if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2) 1636e22aab7dSTakashi Iwai spec->multi_ios = 1; /* give badness */ 1637352f7f91STakashi Iwai 1638a07a949bSTakashi Iwai /* re-count num_dacs and squash invalid entries */ 1639a07a949bSTakashi Iwai spec->multiout.num_dacs = 0; 1640a07a949bSTakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 1641a07a949bSTakashi Iwai if (spec->private_dac_nids[i]) 1642a07a949bSTakashi Iwai spec->multiout.num_dacs++; 1643a07a949bSTakashi Iwai else { 1644a07a949bSTakashi Iwai memmove(spec->private_dac_nids + i, 1645a07a949bSTakashi Iwai spec->private_dac_nids + i + 1, 1646a07a949bSTakashi Iwai sizeof(hda_nid_t) * (cfg->line_outs - i - 1)); 1647a07a949bSTakashi Iwai spec->private_dac_nids[cfg->line_outs - 1] = 0; 1648a07a949bSTakashi Iwai } 1649a07a949bSTakashi Iwai } 1650a07a949bSTakashi Iwai 1651a07a949bSTakashi Iwai spec->ext_channel_count = spec->min_channel_count = 1652c0f3b216SDavid Henningsson spec->multiout.num_dacs * 2; 1653a07a949bSTakashi Iwai 1654352f7f91STakashi Iwai if (spec->multi_ios == 2) { 1655352f7f91STakashi Iwai for (i = 0; i < 2; i++) 1656352f7f91STakashi Iwai spec->private_dac_nids[spec->multiout.num_dacs++] = 1657352f7f91STakashi Iwai spec->multi_io[i].dac; 1658352f7f91STakashi Iwai } else if (spec->multi_ios) { 1659352f7f91STakashi Iwai spec->multi_ios = 0; 1660352f7f91STakashi Iwai badness += BAD_MULTI_IO; 1661352f7f91STakashi Iwai } 1662352f7f91STakashi Iwai 166355a63d4dSTakashi Iwai if (spec->indep_hp && !indep_hp_possible(codec)) 166455a63d4dSTakashi Iwai badness += BAD_NO_INDEP_HP; 166555a63d4dSTakashi Iwai 1666a07a949bSTakashi Iwai /* re-fill the shared DAC for speaker / headphone */ 1667a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 1668a07a949bSTakashi Iwai refill_shared_dacs(codec, cfg->hp_outs, 1669a07a949bSTakashi Iwai spec->multiout.hp_out_nid, 1670a07a949bSTakashi Iwai spec->hp_paths); 1671a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 1672a07a949bSTakashi Iwai refill_shared_dacs(codec, cfg->speaker_outs, 1673a07a949bSTakashi Iwai spec->multiout.extra_out_nid, 1674a07a949bSTakashi Iwai spec->speaker_paths); 1675a07a949bSTakashi Iwai 1676352f7f91STakashi Iwai return badness; 1677352f7f91STakashi Iwai } 1678352f7f91STakashi Iwai 1679352f7f91STakashi Iwai #define DEBUG_BADNESS 1680352f7f91STakashi Iwai 1681352f7f91STakashi Iwai #ifdef DEBUG_BADNESS 1682352f7f91STakashi Iwai #define debug_badness snd_printdd 1683352f7f91STakashi Iwai #else 1684352f7f91STakashi Iwai #define debug_badness(...) 1685352f7f91STakashi Iwai #endif 1686352f7f91STakashi Iwai 1687a769409cSTakashi Iwai #ifdef DEBUG_BADNESS 1688a769409cSTakashi Iwai static inline void print_nid_path_idx(struct hda_codec *codec, 1689a769409cSTakashi Iwai const char *pfx, int idx) 1690352f7f91STakashi Iwai { 1691a769409cSTakashi Iwai struct nid_path *path; 1692a769409cSTakashi Iwai 1693a769409cSTakashi Iwai path = snd_hda_get_path_from_idx(codec, idx); 1694a769409cSTakashi Iwai if (path) 1695a769409cSTakashi Iwai print_nid_path(pfx, path); 1696a769409cSTakashi Iwai } 1697a769409cSTakashi Iwai 1698a769409cSTakashi Iwai static void debug_show_configs(struct hda_codec *codec, 1699a769409cSTakashi Iwai struct auto_pin_cfg *cfg) 1700a769409cSTakashi Iwai { 1701a769409cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 1702a769409cSTakashi Iwai static const char * const lo_type[3] = { "LO", "SP", "HP" }; 1703a769409cSTakashi Iwai int i; 1704a769409cSTakashi Iwai 1705a769409cSTakashi Iwai debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x (type %s)\n", 1706352f7f91STakashi Iwai cfg->line_out_pins[0], cfg->line_out_pins[1], 1707708122e8STakashi Iwai cfg->line_out_pins[2], cfg->line_out_pins[3], 1708352f7f91STakashi Iwai spec->multiout.dac_nids[0], 1709352f7f91STakashi Iwai spec->multiout.dac_nids[1], 1710352f7f91STakashi Iwai spec->multiout.dac_nids[2], 1711a769409cSTakashi Iwai spec->multiout.dac_nids[3], 1712a769409cSTakashi Iwai lo_type[cfg->line_out_type]); 1713a769409cSTakashi Iwai for (i = 0; i < cfg->line_outs; i++) 1714a769409cSTakashi Iwai print_nid_path_idx(codec, " out", spec->out_paths[i]); 1715352f7f91STakashi Iwai if (spec->multi_ios > 0) 1716352f7f91STakashi Iwai debug_badness("multi_ios(%d) = %x/%x : %x/%x\n", 1717352f7f91STakashi Iwai spec->multi_ios, 1718352f7f91STakashi Iwai spec->multi_io[0].pin, spec->multi_io[1].pin, 1719352f7f91STakashi Iwai spec->multi_io[0].dac, spec->multi_io[1].dac); 1720a769409cSTakashi Iwai for (i = 0; i < spec->multi_ios; i++) 1721a769409cSTakashi Iwai print_nid_path_idx(codec, " mio", 1722a769409cSTakashi Iwai spec->out_paths[cfg->line_outs + i]); 1723a769409cSTakashi Iwai if (cfg->hp_outs) 1724352f7f91STakashi Iwai debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1725352f7f91STakashi Iwai cfg->hp_pins[0], cfg->hp_pins[1], 1726708122e8STakashi Iwai cfg->hp_pins[2], cfg->hp_pins[3], 1727352f7f91STakashi Iwai spec->multiout.hp_out_nid[0], 1728352f7f91STakashi Iwai spec->multiout.hp_out_nid[1], 1729352f7f91STakashi Iwai spec->multiout.hp_out_nid[2], 1730352f7f91STakashi Iwai spec->multiout.hp_out_nid[3]); 1731a769409cSTakashi Iwai for (i = 0; i < cfg->hp_outs; i++) 1732a769409cSTakashi Iwai print_nid_path_idx(codec, " hp ", spec->hp_paths[i]); 1733a769409cSTakashi Iwai if (cfg->speaker_outs) 1734352f7f91STakashi Iwai debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1735352f7f91STakashi Iwai cfg->speaker_pins[0], cfg->speaker_pins[1], 1736352f7f91STakashi Iwai cfg->speaker_pins[2], cfg->speaker_pins[3], 1737352f7f91STakashi Iwai spec->multiout.extra_out_nid[0], 1738352f7f91STakashi Iwai spec->multiout.extra_out_nid[1], 1739352f7f91STakashi Iwai spec->multiout.extra_out_nid[2], 1740352f7f91STakashi Iwai spec->multiout.extra_out_nid[3]); 1741a769409cSTakashi Iwai for (i = 0; i < cfg->speaker_outs; i++) 1742a769409cSTakashi Iwai print_nid_path_idx(codec, " spk", spec->speaker_paths[i]); 1743a769409cSTakashi Iwai for (i = 0; i < 3; i++) 1744a769409cSTakashi Iwai print_nid_path_idx(codec, " mix", spec->aamix_out_paths[i]); 1745352f7f91STakashi Iwai } 1746a769409cSTakashi Iwai #else 1747a769409cSTakashi Iwai #define debug_show_configs(codec, cfg) /* NOP */ 1748a769409cSTakashi Iwai #endif 1749352f7f91STakashi Iwai 1750352f7f91STakashi Iwai /* find all available DACs of the codec */ 1751352f7f91STakashi Iwai static void fill_all_dac_nids(struct hda_codec *codec) 1752352f7f91STakashi Iwai { 1753352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1754352f7f91STakashi Iwai int i; 1755352f7f91STakashi Iwai hda_nid_t nid = codec->start_nid; 1756352f7f91STakashi Iwai 1757352f7f91STakashi Iwai spec->num_all_dacs = 0; 1758352f7f91STakashi Iwai memset(spec->all_dacs, 0, sizeof(spec->all_dacs)); 1759352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) { 1760352f7f91STakashi Iwai if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT) 1761352f7f91STakashi Iwai continue; 1762352f7f91STakashi Iwai if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) { 1763352f7f91STakashi Iwai snd_printk(KERN_ERR "hda: Too many DACs!\n"); 1764352f7f91STakashi Iwai break; 1765352f7f91STakashi Iwai } 1766352f7f91STakashi Iwai spec->all_dacs[spec->num_all_dacs++] = nid; 1767352f7f91STakashi Iwai } 1768352f7f91STakashi Iwai } 1769352f7f91STakashi Iwai 1770352f7f91STakashi Iwai static int parse_output_paths(struct hda_codec *codec) 1771352f7f91STakashi Iwai { 1772352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1773352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1774352f7f91STakashi Iwai struct auto_pin_cfg *best_cfg; 17759314a581STakashi Iwai unsigned int val; 1776352f7f91STakashi Iwai int best_badness = INT_MAX; 1777352f7f91STakashi Iwai int badness; 1778352f7f91STakashi Iwai bool fill_hardwired = true, fill_mio_first = true; 1779352f7f91STakashi Iwai bool best_wired = true, best_mio = true; 1780352f7f91STakashi Iwai bool hp_spk_swapped = false; 1781352f7f91STakashi Iwai 1782352f7f91STakashi Iwai best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL); 1783352f7f91STakashi Iwai if (!best_cfg) 1784352f7f91STakashi Iwai return -ENOMEM; 1785352f7f91STakashi Iwai *best_cfg = *cfg; 1786352f7f91STakashi Iwai 1787352f7f91STakashi Iwai for (;;) { 1788352f7f91STakashi Iwai badness = fill_and_eval_dacs(codec, fill_hardwired, 1789352f7f91STakashi Iwai fill_mio_first); 1790352f7f91STakashi Iwai if (badness < 0) { 1791352f7f91STakashi Iwai kfree(best_cfg); 1792352f7f91STakashi Iwai return badness; 1793352f7f91STakashi Iwai } 1794352f7f91STakashi Iwai debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n", 1795352f7f91STakashi Iwai cfg->line_out_type, fill_hardwired, fill_mio_first, 1796352f7f91STakashi Iwai badness); 1797a769409cSTakashi Iwai debug_show_configs(codec, cfg); 1798352f7f91STakashi Iwai if (badness < best_badness) { 1799352f7f91STakashi Iwai best_badness = badness; 1800352f7f91STakashi Iwai *best_cfg = *cfg; 1801352f7f91STakashi Iwai best_wired = fill_hardwired; 1802352f7f91STakashi Iwai best_mio = fill_mio_first; 1803352f7f91STakashi Iwai } 1804352f7f91STakashi Iwai if (!badness) 1805352f7f91STakashi Iwai break; 1806352f7f91STakashi Iwai fill_mio_first = !fill_mio_first; 1807352f7f91STakashi Iwai if (!fill_mio_first) 1808352f7f91STakashi Iwai continue; 1809352f7f91STakashi Iwai fill_hardwired = !fill_hardwired; 1810352f7f91STakashi Iwai if (!fill_hardwired) 1811352f7f91STakashi Iwai continue; 1812352f7f91STakashi Iwai if (hp_spk_swapped) 1813352f7f91STakashi Iwai break; 1814352f7f91STakashi Iwai hp_spk_swapped = true; 1815352f7f91STakashi Iwai if (cfg->speaker_outs > 0 && 1816352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) { 1817352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs; 1818352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins, 1819352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 1820352f7f91STakashi Iwai cfg->line_outs = cfg->speaker_outs; 1821352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->speaker_pins, 1822352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 1823352f7f91STakashi Iwai cfg->speaker_outs = 0; 1824352f7f91STakashi Iwai memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); 1825352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; 1826352f7f91STakashi Iwai fill_hardwired = true; 1827352f7f91STakashi Iwai continue; 1828352f7f91STakashi Iwai } 1829352f7f91STakashi Iwai if (cfg->hp_outs > 0 && 1830352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { 1831352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 1832352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 1833352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 1834352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs; 1835352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins, 1836352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 1837352f7f91STakashi Iwai cfg->hp_outs = 0; 1838352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 1839352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT; 1840352f7f91STakashi Iwai fill_hardwired = true; 1841352f7f91STakashi Iwai continue; 1842352f7f91STakashi Iwai } 1843352f7f91STakashi Iwai break; 1844352f7f91STakashi Iwai } 1845352f7f91STakashi Iwai 1846352f7f91STakashi Iwai if (badness) { 18470c8c0f56STakashi Iwai debug_badness("==> restoring best_cfg\n"); 1848352f7f91STakashi Iwai *cfg = *best_cfg; 1849352f7f91STakashi Iwai fill_and_eval_dacs(codec, best_wired, best_mio); 1850352f7f91STakashi Iwai } 1851352f7f91STakashi Iwai debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n", 1852352f7f91STakashi Iwai cfg->line_out_type, best_wired, best_mio); 1853a769409cSTakashi Iwai debug_show_configs(codec, cfg); 1854352f7f91STakashi Iwai 1855352f7f91STakashi Iwai if (cfg->line_out_pins[0]) { 1856352f7f91STakashi Iwai struct nid_path *path; 1857196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]); 1858352f7f91STakashi Iwai if (path) 1859352f7f91STakashi Iwai spec->vmaster_nid = look_for_out_vol_nid(codec, path); 18607a71bbf3STakashi Iwai if (spec->vmaster_nid) 18617a71bbf3STakashi Iwai snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, 18627a71bbf3STakashi Iwai HDA_OUTPUT, spec->vmaster_tlv); 1863352f7f91STakashi Iwai } 1864352f7f91STakashi Iwai 18659314a581STakashi Iwai /* set initial pinctl targets */ 18669314a581STakashi Iwai if (spec->prefer_hp_amp || cfg->line_out_type == AUTO_PIN_HP_OUT) 18679314a581STakashi Iwai val = PIN_HP; 18689314a581STakashi Iwai else 18699314a581STakashi Iwai val = PIN_OUT; 18709314a581STakashi Iwai set_pin_targets(codec, cfg->line_outs, cfg->line_out_pins, val); 18719314a581STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 18729314a581STakashi Iwai set_pin_targets(codec, cfg->hp_outs, cfg->hp_pins, PIN_HP); 18739314a581STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 18749314a581STakashi Iwai val = spec->prefer_hp_amp ? PIN_HP : PIN_OUT; 18759314a581STakashi Iwai set_pin_targets(codec, cfg->speaker_outs, 18769314a581STakashi Iwai cfg->speaker_pins, val); 18779314a581STakashi Iwai } 18789314a581STakashi Iwai 187955a63d4dSTakashi Iwai /* clear indep_hp flag if not available */ 188055a63d4dSTakashi Iwai if (spec->indep_hp && !indep_hp_possible(codec)) 188155a63d4dSTakashi Iwai spec->indep_hp = 0; 188255a63d4dSTakashi Iwai 1883352f7f91STakashi Iwai kfree(best_cfg); 1884352f7f91STakashi Iwai return 0; 1885352f7f91STakashi Iwai } 1886352f7f91STakashi Iwai 1887352f7f91STakashi Iwai /* add playback controls from the parsed DAC table */ 1888352f7f91STakashi Iwai static int create_multi_out_ctls(struct hda_codec *codec, 1889352f7f91STakashi Iwai const struct auto_pin_cfg *cfg) 1890352f7f91STakashi Iwai { 1891352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1892352f7f91STakashi Iwai int i, err, noutputs; 1893352f7f91STakashi Iwai 1894352f7f91STakashi Iwai noutputs = cfg->line_outs; 1895352f7f91STakashi Iwai if (spec->multi_ios > 0 && cfg->line_outs < 3) 1896352f7f91STakashi Iwai noutputs += spec->multi_ios; 1897352f7f91STakashi Iwai 1898352f7f91STakashi Iwai for (i = 0; i < noutputs; i++) { 1899352f7f91STakashi Iwai const char *name; 1900352f7f91STakashi Iwai int index; 1901352f7f91STakashi Iwai struct nid_path *path; 1902352f7f91STakashi Iwai 1903196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]); 1904352f7f91STakashi Iwai if (!path) 1905352f7f91STakashi Iwai continue; 1906247d85eeSTakashi Iwai 1907247d85eeSTakashi Iwai name = get_line_out_pfx(codec, i, &index, NID_PATH_VOL_CTL); 1908352f7f91STakashi Iwai if (!name || !strcmp(name, "CLFE")) { 1909352f7f91STakashi Iwai /* Center/LFE */ 1910352f7f91STakashi Iwai err = add_vol_ctl(codec, "Center", 0, 1, path); 1911352f7f91STakashi Iwai if (err < 0) 1912352f7f91STakashi Iwai return err; 1913352f7f91STakashi Iwai err = add_vol_ctl(codec, "LFE", 0, 2, path); 1914352f7f91STakashi Iwai if (err < 0) 1915352f7f91STakashi Iwai return err; 1916247d85eeSTakashi Iwai } else { 1917247d85eeSTakashi Iwai err = add_stereo_vol(codec, name, index, path); 1918247d85eeSTakashi Iwai if (err < 0) 1919247d85eeSTakashi Iwai return err; 1920247d85eeSTakashi Iwai } 1921247d85eeSTakashi Iwai 1922247d85eeSTakashi Iwai name = get_line_out_pfx(codec, i, &index, NID_PATH_MUTE_CTL); 1923247d85eeSTakashi Iwai if (!name || !strcmp(name, "CLFE")) { 1924352f7f91STakashi Iwai err = add_sw_ctl(codec, "Center", 0, 1, path); 1925352f7f91STakashi Iwai if (err < 0) 1926352f7f91STakashi Iwai return err; 1927352f7f91STakashi Iwai err = add_sw_ctl(codec, "LFE", 0, 2, path); 1928352f7f91STakashi Iwai if (err < 0) 1929352f7f91STakashi Iwai return err; 1930352f7f91STakashi Iwai } else { 1931352f7f91STakashi Iwai err = add_stereo_sw(codec, name, index, path); 1932352f7f91STakashi Iwai if (err < 0) 1933352f7f91STakashi Iwai return err; 1934352f7f91STakashi Iwai } 1935352f7f91STakashi Iwai } 1936352f7f91STakashi Iwai return 0; 1937352f7f91STakashi Iwai } 1938352f7f91STakashi Iwai 1939c2c80383STakashi Iwai static int create_extra_out(struct hda_codec *codec, int path_idx, 1940196c1766STakashi Iwai const char *pfx, int cidx) 1941352f7f91STakashi Iwai { 1942352f7f91STakashi Iwai struct nid_path *path; 1943352f7f91STakashi Iwai int err; 1944352f7f91STakashi Iwai 1945196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 1946352f7f91STakashi Iwai if (!path) 1947352f7f91STakashi Iwai return 0; 1948352f7f91STakashi Iwai err = add_stereo_vol(codec, pfx, cidx, path); 1949352f7f91STakashi Iwai if (err < 0) 1950352f7f91STakashi Iwai return err; 1951352f7f91STakashi Iwai err = add_stereo_sw(codec, pfx, cidx, path); 1952352f7f91STakashi Iwai if (err < 0) 1953352f7f91STakashi Iwai return err; 1954352f7f91STakashi Iwai return 0; 1955352f7f91STakashi Iwai } 1956352f7f91STakashi Iwai 1957352f7f91STakashi Iwai /* add playback controls for speaker and HP outputs */ 1958352f7f91STakashi Iwai static int create_extra_outs(struct hda_codec *codec, int num_pins, 1959196c1766STakashi Iwai const int *paths, const char *pfx) 1960352f7f91STakashi Iwai { 1961c2c80383STakashi Iwai int i; 1962352f7f91STakashi Iwai 1963352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 1964c2c80383STakashi Iwai const char *name; 1965975cc02aSTakashi Iwai char tmp[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 1966c2c80383STakashi Iwai int err, idx = 0; 1967c2c80383STakashi Iwai 1968c2c80383STakashi Iwai if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) 1969c2c80383STakashi Iwai name = "Bass Speaker"; 1970c2c80383STakashi Iwai else if (num_pins >= 3) { 1971c2c80383STakashi Iwai snprintf(tmp, sizeof(tmp), "%s %s", 1972352f7f91STakashi Iwai pfx, channel_name[i]); 1973c2c80383STakashi Iwai name = tmp; 1974352f7f91STakashi Iwai } else { 1975c2c80383STakashi Iwai name = pfx; 1976c2c80383STakashi Iwai idx = i; 1977352f7f91STakashi Iwai } 1978c2c80383STakashi Iwai err = create_extra_out(codec, paths[i], name, idx); 1979352f7f91STakashi Iwai if (err < 0) 1980352f7f91STakashi Iwai return err; 1981352f7f91STakashi Iwai } 1982352f7f91STakashi Iwai return 0; 1983352f7f91STakashi Iwai } 1984352f7f91STakashi Iwai 1985352f7f91STakashi Iwai static int create_hp_out_ctls(struct hda_codec *codec) 1986352f7f91STakashi Iwai { 1987352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1988352f7f91STakashi Iwai return create_extra_outs(codec, spec->autocfg.hp_outs, 1989196c1766STakashi Iwai spec->hp_paths, 1990352f7f91STakashi Iwai "Headphone"); 1991352f7f91STakashi Iwai } 1992352f7f91STakashi Iwai 1993352f7f91STakashi Iwai static int create_speaker_out_ctls(struct hda_codec *codec) 1994352f7f91STakashi Iwai { 1995352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1996352f7f91STakashi Iwai return create_extra_outs(codec, spec->autocfg.speaker_outs, 1997196c1766STakashi Iwai spec->speaker_paths, 1998352f7f91STakashi Iwai "Speaker"); 1999352f7f91STakashi Iwai } 2000352f7f91STakashi Iwai 2001352f7f91STakashi Iwai /* 200238cf6f1aSTakashi Iwai * independent HP controls 200338cf6f1aSTakashi Iwai */ 200438cf6f1aSTakashi Iwai 2005963afde9STakashi Iwai static void call_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack); 200638cf6f1aSTakashi Iwai static int indep_hp_info(struct snd_kcontrol *kcontrol, 200738cf6f1aSTakashi Iwai struct snd_ctl_elem_info *uinfo) 200838cf6f1aSTakashi Iwai { 200938cf6f1aSTakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo); 201038cf6f1aSTakashi Iwai } 201138cf6f1aSTakashi Iwai 201238cf6f1aSTakashi Iwai static int indep_hp_get(struct snd_kcontrol *kcontrol, 201338cf6f1aSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 201438cf6f1aSTakashi Iwai { 201538cf6f1aSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 201638cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 201738cf6f1aSTakashi Iwai ucontrol->value.enumerated.item[0] = spec->indep_hp_enabled; 201838cf6f1aSTakashi Iwai return 0; 201938cf6f1aSTakashi Iwai } 202038cf6f1aSTakashi Iwai 2021a1e908edSTakashi Iwai static void update_aamix_paths(struct hda_codec *codec, bool do_mix, 2022a1e908edSTakashi Iwai int nomix_path_idx, int mix_path_idx, 2023a1e908edSTakashi Iwai int out_type); 2024a1e908edSTakashi Iwai 202538cf6f1aSTakashi Iwai static int indep_hp_put(struct snd_kcontrol *kcontrol, 202638cf6f1aSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 202738cf6f1aSTakashi Iwai { 202838cf6f1aSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 202938cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 203038cf6f1aSTakashi Iwai unsigned int select = ucontrol->value.enumerated.item[0]; 203138cf6f1aSTakashi Iwai int ret = 0; 203238cf6f1aSTakashi Iwai 203338cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 203438cf6f1aSTakashi Iwai if (spec->active_streams) { 203538cf6f1aSTakashi Iwai ret = -EBUSY; 203638cf6f1aSTakashi Iwai goto unlock; 203738cf6f1aSTakashi Iwai } 203838cf6f1aSTakashi Iwai 203938cf6f1aSTakashi Iwai if (spec->indep_hp_enabled != select) { 2040a1e908edSTakashi Iwai hda_nid_t *dacp; 2041a1e908edSTakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) 2042a1e908edSTakashi Iwai dacp = &spec->private_dac_nids[0]; 2043a1e908edSTakashi Iwai else 2044a1e908edSTakashi Iwai dacp = &spec->multiout.hp_out_nid[0]; 2045a1e908edSTakashi Iwai 2046a1e908edSTakashi Iwai /* update HP aamix paths in case it conflicts with indep HP */ 2047a1e908edSTakashi Iwai if (spec->have_aamix_ctl) { 2048a1e908edSTakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) 2049a1e908edSTakashi Iwai update_aamix_paths(codec, spec->aamix_mode, 2050a1e908edSTakashi Iwai spec->out_paths[0], 2051a1e908edSTakashi Iwai spec->aamix_out_paths[0], 2052a1e908edSTakashi Iwai spec->autocfg.line_out_type); 2053a1e908edSTakashi Iwai else 2054a1e908edSTakashi Iwai update_aamix_paths(codec, spec->aamix_mode, 2055a1e908edSTakashi Iwai spec->hp_paths[0], 2056a1e908edSTakashi Iwai spec->aamix_out_paths[1], 2057a1e908edSTakashi Iwai AUTO_PIN_HP_OUT); 2058a1e908edSTakashi Iwai } 2059a1e908edSTakashi Iwai 206038cf6f1aSTakashi Iwai spec->indep_hp_enabled = select; 206138cf6f1aSTakashi Iwai if (spec->indep_hp_enabled) 2062a1e908edSTakashi Iwai *dacp = 0; 206338cf6f1aSTakashi Iwai else 2064a1e908edSTakashi Iwai *dacp = spec->alt_dac_nid; 206592603c59STakashi Iwai 2066963afde9STakashi Iwai call_hp_automute(codec, NULL); 206738cf6f1aSTakashi Iwai ret = 1; 206838cf6f1aSTakashi Iwai } 206938cf6f1aSTakashi Iwai unlock: 207038cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 207138cf6f1aSTakashi Iwai return ret; 207238cf6f1aSTakashi Iwai } 207338cf6f1aSTakashi Iwai 207438cf6f1aSTakashi Iwai static const struct snd_kcontrol_new indep_hp_ctl = { 207538cf6f1aSTakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 207638cf6f1aSTakashi Iwai .name = "Independent HP", 207738cf6f1aSTakashi Iwai .info = indep_hp_info, 207838cf6f1aSTakashi Iwai .get = indep_hp_get, 207938cf6f1aSTakashi Iwai .put = indep_hp_put, 208038cf6f1aSTakashi Iwai }; 208138cf6f1aSTakashi Iwai 208238cf6f1aSTakashi Iwai 208338cf6f1aSTakashi Iwai static int create_indep_hp_ctls(struct hda_codec *codec) 208438cf6f1aSTakashi Iwai { 208538cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 2086a1e908edSTakashi Iwai hda_nid_t dac; 208738cf6f1aSTakashi Iwai 208838cf6f1aSTakashi Iwai if (!spec->indep_hp) 208938cf6f1aSTakashi Iwai return 0; 2090a1e908edSTakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) 2091a1e908edSTakashi Iwai dac = spec->multiout.dac_nids[0]; 2092a1e908edSTakashi Iwai else 2093a1e908edSTakashi Iwai dac = spec->multiout.hp_out_nid[0]; 2094a1e908edSTakashi Iwai if (!dac) { 209538cf6f1aSTakashi Iwai spec->indep_hp = 0; 209638cf6f1aSTakashi Iwai return 0; 209738cf6f1aSTakashi Iwai } 209838cf6f1aSTakashi Iwai 209938cf6f1aSTakashi Iwai spec->indep_hp_enabled = false; 2100a1e908edSTakashi Iwai spec->alt_dac_nid = dac; 210138cf6f1aSTakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl)) 210238cf6f1aSTakashi Iwai return -ENOMEM; 210338cf6f1aSTakashi Iwai return 0; 210438cf6f1aSTakashi Iwai } 210538cf6f1aSTakashi Iwai 210638cf6f1aSTakashi Iwai /* 2107352f7f91STakashi Iwai * channel mode enum control 2108352f7f91STakashi Iwai */ 2109352f7f91STakashi Iwai 2110352f7f91STakashi Iwai static int ch_mode_info(struct snd_kcontrol *kcontrol, 2111352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 2112352f7f91STakashi Iwai { 2113352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2114352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2115a07a949bSTakashi Iwai int chs; 2116352f7f91STakashi Iwai 2117352f7f91STakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 2118352f7f91STakashi Iwai uinfo->count = 1; 2119352f7f91STakashi Iwai uinfo->value.enumerated.items = spec->multi_ios + 1; 2120352f7f91STakashi Iwai if (uinfo->value.enumerated.item > spec->multi_ios) 2121352f7f91STakashi Iwai uinfo->value.enumerated.item = spec->multi_ios; 2122a07a949bSTakashi Iwai chs = uinfo->value.enumerated.item * 2 + spec->min_channel_count; 2123a07a949bSTakashi Iwai sprintf(uinfo->value.enumerated.name, "%dch", chs); 2124352f7f91STakashi Iwai return 0; 2125352f7f91STakashi Iwai } 2126352f7f91STakashi Iwai 2127352f7f91STakashi Iwai static int ch_mode_get(struct snd_kcontrol *kcontrol, 2128352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2129352f7f91STakashi Iwai { 2130352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2131352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2132a07a949bSTakashi Iwai ucontrol->value.enumerated.item[0] = 2133a07a949bSTakashi Iwai (spec->ext_channel_count - spec->min_channel_count) / 2; 2134352f7f91STakashi Iwai return 0; 2135352f7f91STakashi Iwai } 2136352f7f91STakashi Iwai 2137196c1766STakashi Iwai static inline struct nid_path * 2138196c1766STakashi Iwai get_multiio_path(struct hda_codec *codec, int idx) 2139196c1766STakashi Iwai { 2140196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2141196c1766STakashi Iwai return snd_hda_get_path_from_idx(codec, 2142196c1766STakashi Iwai spec->out_paths[spec->autocfg.line_outs + idx]); 2143196c1766STakashi Iwai } 2144196c1766STakashi Iwai 2145a5cc2509STakashi Iwai static void update_automute_all(struct hda_codec *codec); 2146a5cc2509STakashi Iwai 214765033cc8STakashi Iwai /* Default value to be passed as aamix argument for snd_hda_activate_path(); 214865033cc8STakashi Iwai * used for output paths 214965033cc8STakashi Iwai */ 215065033cc8STakashi Iwai static bool aamix_default(struct hda_gen_spec *spec) 215165033cc8STakashi Iwai { 215265033cc8STakashi Iwai return !spec->have_aamix_ctl || spec->aamix_mode; 215365033cc8STakashi Iwai } 215465033cc8STakashi Iwai 2155352f7f91STakashi Iwai static int set_multi_io(struct hda_codec *codec, int idx, bool output) 2156352f7f91STakashi Iwai { 2157352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2158352f7f91STakashi Iwai hda_nid_t nid = spec->multi_io[idx].pin; 2159352f7f91STakashi Iwai struct nid_path *path; 2160352f7f91STakashi Iwai 2161196c1766STakashi Iwai path = get_multiio_path(codec, idx); 2162352f7f91STakashi Iwai if (!path) 2163352f7f91STakashi Iwai return -EINVAL; 2164352f7f91STakashi Iwai 2165352f7f91STakashi Iwai if (path->active == output) 2166352f7f91STakashi Iwai return 0; 2167352f7f91STakashi Iwai 2168352f7f91STakashi Iwai if (output) { 21692c12c30dSTakashi Iwai set_pin_target(codec, nid, PIN_OUT, true); 217065033cc8STakashi Iwai snd_hda_activate_path(codec, path, true, aamix_default(spec)); 2171d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, true); 2172352f7f91STakashi Iwai } else { 2173d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, false); 217465033cc8STakashi Iwai snd_hda_activate_path(codec, path, false, aamix_default(spec)); 21752c12c30dSTakashi Iwai set_pin_target(codec, nid, spec->multi_io[idx].ctl_in, true); 217655196fffSTakashi Iwai path_power_down_sync(codec, path); 2177352f7f91STakashi Iwai } 2178a365fed9STakashi Iwai 2179a365fed9STakashi Iwai /* update jack retasking in case it modifies any of them */ 2180a5cc2509STakashi Iwai update_automute_all(codec); 2181a365fed9STakashi Iwai 2182352f7f91STakashi Iwai return 0; 2183352f7f91STakashi Iwai } 2184352f7f91STakashi Iwai 2185352f7f91STakashi Iwai static int ch_mode_put(struct snd_kcontrol *kcontrol, 2186352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2187352f7f91STakashi Iwai { 2188352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2189352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2190352f7f91STakashi Iwai int i, ch; 2191352f7f91STakashi Iwai 2192352f7f91STakashi Iwai ch = ucontrol->value.enumerated.item[0]; 2193352f7f91STakashi Iwai if (ch < 0 || ch > spec->multi_ios) 2194352f7f91STakashi Iwai return -EINVAL; 2195a07a949bSTakashi Iwai if (ch == (spec->ext_channel_count - spec->min_channel_count) / 2) 2196352f7f91STakashi Iwai return 0; 2197a07a949bSTakashi Iwai spec->ext_channel_count = ch * 2 + spec->min_channel_count; 2198352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++) 2199352f7f91STakashi Iwai set_multi_io(codec, i, i < ch); 2200352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count, 2201352f7f91STakashi Iwai spec->const_channel_count); 2202352f7f91STakashi Iwai if (spec->need_dac_fix) 2203352f7f91STakashi Iwai spec->multiout.num_dacs = spec->multiout.max_channels / 2; 2204352f7f91STakashi Iwai return 1; 2205352f7f91STakashi Iwai } 2206352f7f91STakashi Iwai 2207352f7f91STakashi Iwai static const struct snd_kcontrol_new channel_mode_enum = { 2208352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2209352f7f91STakashi Iwai .name = "Channel Mode", 2210352f7f91STakashi Iwai .info = ch_mode_info, 2211352f7f91STakashi Iwai .get = ch_mode_get, 2212352f7f91STakashi Iwai .put = ch_mode_put, 2213352f7f91STakashi Iwai }; 2214352f7f91STakashi Iwai 2215352f7f91STakashi Iwai static int create_multi_channel_mode(struct hda_codec *codec) 2216352f7f91STakashi Iwai { 2217352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2218352f7f91STakashi Iwai 2219352f7f91STakashi Iwai if (spec->multi_ios > 0) { 222012c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &channel_mode_enum)) 2221352f7f91STakashi Iwai return -ENOMEM; 2222352f7f91STakashi Iwai } 2223352f7f91STakashi Iwai return 0; 2224352f7f91STakashi Iwai } 2225352f7f91STakashi Iwai 2226352f7f91STakashi Iwai /* 2227c30aa7b2STakashi Iwai * aamix loopback enable/disable switch 2228c30aa7b2STakashi Iwai */ 2229c30aa7b2STakashi Iwai 2230c30aa7b2STakashi Iwai #define loopback_mixing_info indep_hp_info 2231c30aa7b2STakashi Iwai 2232c30aa7b2STakashi Iwai static int loopback_mixing_get(struct snd_kcontrol *kcontrol, 2233c30aa7b2STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2234c30aa7b2STakashi Iwai { 2235c30aa7b2STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2236c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2237c30aa7b2STakashi Iwai ucontrol->value.enumerated.item[0] = spec->aamix_mode; 2238c30aa7b2STakashi Iwai return 0; 2239c30aa7b2STakashi Iwai } 2240c30aa7b2STakashi Iwai 2241c30aa7b2STakashi Iwai static void update_aamix_paths(struct hda_codec *codec, bool do_mix, 2242a1e908edSTakashi Iwai int nomix_path_idx, int mix_path_idx, 2243a1e908edSTakashi Iwai int out_type) 2244c30aa7b2STakashi Iwai { 2245a1e908edSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 2246c30aa7b2STakashi Iwai struct nid_path *nomix_path, *mix_path; 2247c30aa7b2STakashi Iwai 2248c30aa7b2STakashi Iwai nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx); 2249c30aa7b2STakashi Iwai mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx); 2250c30aa7b2STakashi Iwai if (!nomix_path || !mix_path) 2251c30aa7b2STakashi Iwai return; 2252a1e908edSTakashi Iwai 2253a1e908edSTakashi Iwai /* if HP aamix path is driven from a different DAC and the 2254a1e908edSTakashi Iwai * independent HP mode is ON, can't turn on aamix path 2255a1e908edSTakashi Iwai */ 2256a1e908edSTakashi Iwai if (out_type == AUTO_PIN_HP_OUT && spec->indep_hp_enabled && 2257a1e908edSTakashi Iwai mix_path->path[0] != spec->alt_dac_nid) 2258a1e908edSTakashi Iwai do_mix = false; 2259a1e908edSTakashi Iwai 2260c30aa7b2STakashi Iwai if (do_mix) { 2261c30aa7b2STakashi Iwai snd_hda_activate_path(codec, nomix_path, false, true); 2262c30aa7b2STakashi Iwai snd_hda_activate_path(codec, mix_path, true, true); 226355196fffSTakashi Iwai path_power_down_sync(codec, nomix_path); 2264c30aa7b2STakashi Iwai } else { 226565033cc8STakashi Iwai snd_hda_activate_path(codec, mix_path, false, false); 226665033cc8STakashi Iwai snd_hda_activate_path(codec, nomix_path, true, false); 226755196fffSTakashi Iwai path_power_down_sync(codec, mix_path); 2268c30aa7b2STakashi Iwai } 2269c30aa7b2STakashi Iwai } 2270c30aa7b2STakashi Iwai 2271c30aa7b2STakashi Iwai static int loopback_mixing_put(struct snd_kcontrol *kcontrol, 2272c30aa7b2STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2273c30aa7b2STakashi Iwai { 2274c30aa7b2STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2275c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2276c30aa7b2STakashi Iwai unsigned int val = ucontrol->value.enumerated.item[0]; 2277c30aa7b2STakashi Iwai 2278c30aa7b2STakashi Iwai if (val == spec->aamix_mode) 2279c30aa7b2STakashi Iwai return 0; 2280c30aa7b2STakashi Iwai spec->aamix_mode = val; 2281c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->out_paths[0], 2282a1e908edSTakashi Iwai spec->aamix_out_paths[0], 2283a1e908edSTakashi Iwai spec->autocfg.line_out_type); 2284c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->hp_paths[0], 2285a1e908edSTakashi Iwai spec->aamix_out_paths[1], 2286a1e908edSTakashi Iwai AUTO_PIN_HP_OUT); 2287c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->speaker_paths[0], 2288a1e908edSTakashi Iwai spec->aamix_out_paths[2], 2289a1e908edSTakashi Iwai AUTO_PIN_SPEAKER_OUT); 2290c30aa7b2STakashi Iwai return 1; 2291c30aa7b2STakashi Iwai } 2292c30aa7b2STakashi Iwai 2293c30aa7b2STakashi Iwai static const struct snd_kcontrol_new loopback_mixing_enum = { 2294c30aa7b2STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2295c30aa7b2STakashi Iwai .name = "Loopback Mixing", 2296c30aa7b2STakashi Iwai .info = loopback_mixing_info, 2297c30aa7b2STakashi Iwai .get = loopback_mixing_get, 2298c30aa7b2STakashi Iwai .put = loopback_mixing_put, 2299c30aa7b2STakashi Iwai }; 2300c30aa7b2STakashi Iwai 2301c30aa7b2STakashi Iwai static int create_loopback_mixing_ctl(struct hda_codec *codec) 2302c30aa7b2STakashi Iwai { 2303c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2304c30aa7b2STakashi Iwai 2305c30aa7b2STakashi Iwai if (!spec->mixer_nid) 2306c30aa7b2STakashi Iwai return 0; 2307c30aa7b2STakashi Iwai if (!(spec->aamix_out_paths[0] || spec->aamix_out_paths[1] || 2308c30aa7b2STakashi Iwai spec->aamix_out_paths[2])) 2309c30aa7b2STakashi Iwai return 0; 2310c30aa7b2STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum)) 2311c30aa7b2STakashi Iwai return -ENOMEM; 2312a1e908edSTakashi Iwai spec->have_aamix_ctl = 1; 2313c30aa7b2STakashi Iwai return 0; 2314c30aa7b2STakashi Iwai } 2315c30aa7b2STakashi Iwai 2316c30aa7b2STakashi Iwai /* 2317352f7f91STakashi Iwai * shared headphone/mic handling 2318352f7f91STakashi Iwai */ 2319352f7f91STakashi Iwai 2320352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec); 2321352f7f91STakashi Iwai 2322352f7f91STakashi Iwai /* for shared I/O, change the pin-control accordingly */ 2323967303daSTakashi Iwai static void update_hp_mic(struct hda_codec *codec, int adc_mux, bool force) 2324352f7f91STakashi Iwai { 2325352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2326967303daSTakashi Iwai bool as_mic; 2327352f7f91STakashi Iwai unsigned int val; 2328967303daSTakashi Iwai hda_nid_t pin; 2329967303daSTakashi Iwai 2330967303daSTakashi Iwai pin = spec->hp_mic_pin; 2331967303daSTakashi Iwai as_mic = spec->cur_mux[adc_mux] == spec->hp_mic_mux_idx; 2332967303daSTakashi Iwai 2333967303daSTakashi Iwai if (!force) { 2334967303daSTakashi Iwai val = snd_hda_codec_get_pin_target(codec, pin); 2335967303daSTakashi Iwai if (as_mic) { 2336967303daSTakashi Iwai if (val & PIN_IN) 2337967303daSTakashi Iwai return; 2338967303daSTakashi Iwai } else { 2339967303daSTakashi Iwai if (val & PIN_OUT) 2340967303daSTakashi Iwai return; 2341967303daSTakashi Iwai } 2342967303daSTakashi Iwai } 2343352f7f91STakashi Iwai 2344352f7f91STakashi Iwai val = snd_hda_get_default_vref(codec, pin); 2345967303daSTakashi Iwai /* if the HP pin doesn't support VREF and the codec driver gives an 2346967303daSTakashi Iwai * alternative pin, set up the VREF on that pin instead 2347967303daSTakashi Iwai */ 2348352f7f91STakashi Iwai if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) { 2349352f7f91STakashi Iwai const hda_nid_t vref_pin = spec->shared_mic_vref_pin; 2350352f7f91STakashi Iwai unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin); 2351352f7f91STakashi Iwai if (vref_val != AC_PINCTL_VREF_HIZ) 23527594aa33STakashi Iwai snd_hda_set_pin_ctl_cache(codec, vref_pin, 2353967303daSTakashi Iwai PIN_IN | (as_mic ? vref_val : 0)); 2354352f7f91STakashi Iwai } 2355352f7f91STakashi Iwai 23568ba955ceSTakashi Iwai if (!spec->hp_mic_jack_modes) { 2357967303daSTakashi Iwai if (as_mic) 2358967303daSTakashi Iwai val |= PIN_IN; 2359967303daSTakashi Iwai else 2360967303daSTakashi Iwai val = PIN_HP; 23612c12c30dSTakashi Iwai set_pin_target(codec, pin, val, true); 2362963afde9STakashi Iwai call_hp_automute(codec, NULL); 23638ba955ceSTakashi Iwai } 2364352f7f91STakashi Iwai } 2365352f7f91STakashi Iwai 2366352f7f91STakashi Iwai /* create a shared input with the headphone out */ 2367967303daSTakashi Iwai static int create_hp_mic(struct hda_codec *codec) 2368352f7f91STakashi Iwai { 2369352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2370352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 2371352f7f91STakashi Iwai unsigned int defcfg; 2372352f7f91STakashi Iwai hda_nid_t nid; 2373352f7f91STakashi Iwai 2374967303daSTakashi Iwai if (!spec->hp_mic) { 2375967303daSTakashi Iwai if (spec->suppress_hp_mic_detect) 2376352f7f91STakashi Iwai return 0; 2377967303daSTakashi Iwai /* automatic detection: only if no input or a single internal 2378967303daSTakashi Iwai * input pin is found, try to detect the shared hp/mic 2379967303daSTakashi Iwai */ 2380967303daSTakashi Iwai if (cfg->num_inputs > 1) 2381967303daSTakashi Iwai return 0; 2382967303daSTakashi Iwai else if (cfg->num_inputs == 1) { 2383352f7f91STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); 2384352f7f91STakashi Iwai if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) 2385352f7f91STakashi Iwai return 0; 2386967303daSTakashi Iwai } 2387967303daSTakashi Iwai } 2388352f7f91STakashi Iwai 2389967303daSTakashi Iwai spec->hp_mic = 0; /* clear once */ 2390967303daSTakashi Iwai if (cfg->num_inputs >= AUTO_CFG_MAX_INS) 2391967303daSTakashi Iwai return 0; 2392967303daSTakashi Iwai 2393967303daSTakashi Iwai nid = 0; 2394967303daSTakashi Iwai if (cfg->line_out_type == AUTO_PIN_HP_OUT && cfg->line_outs > 0) 2395967303daSTakashi Iwai nid = cfg->line_out_pins[0]; 2396967303daSTakashi Iwai else if (cfg->hp_outs > 0) 2397967303daSTakashi Iwai nid = cfg->hp_pins[0]; 2398967303daSTakashi Iwai if (!nid) 2399967303daSTakashi Iwai return 0; 2400352f7f91STakashi Iwai 2401352f7f91STakashi Iwai if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN)) 2402352f7f91STakashi Iwai return 0; /* no input */ 2403352f7f91STakashi Iwai 2404967303daSTakashi Iwai cfg->inputs[cfg->num_inputs].pin = nid; 2405967303daSTakashi Iwai cfg->inputs[cfg->num_inputs].type = AUTO_PIN_MIC; 2406cb420b11SDavid Henningsson cfg->inputs[cfg->num_inputs].is_headphone_mic = 1; 2407967303daSTakashi Iwai cfg->num_inputs++; 2408967303daSTakashi Iwai spec->hp_mic = 1; 2409967303daSTakashi Iwai spec->hp_mic_pin = nid; 2410967303daSTakashi Iwai /* we can't handle auto-mic together with HP-mic */ 2411967303daSTakashi Iwai spec->suppress_auto_mic = 1; 2412352f7f91STakashi Iwai snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid); 2413352f7f91STakashi Iwai return 0; 2414352f7f91STakashi Iwai } 2415352f7f91STakashi Iwai 2416978e77e7STakashi Iwai /* 2417978e77e7STakashi Iwai * output jack mode 2418978e77e7STakashi Iwai */ 24195f171baaSTakashi Iwai 24205f171baaSTakashi Iwai static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin); 24215f171baaSTakashi Iwai 24225f171baaSTakashi Iwai static const char * const out_jack_texts[] = { 24235f171baaSTakashi Iwai "Line Out", "Headphone Out", 24245f171baaSTakashi Iwai }; 24255f171baaSTakashi Iwai 2426978e77e7STakashi Iwai static int out_jack_mode_info(struct snd_kcontrol *kcontrol, 2427978e77e7STakashi Iwai struct snd_ctl_elem_info *uinfo) 2428978e77e7STakashi Iwai { 24295f171baaSTakashi Iwai return snd_hda_enum_helper_info(kcontrol, uinfo, 2, out_jack_texts); 2430978e77e7STakashi Iwai } 2431978e77e7STakashi Iwai 2432978e77e7STakashi Iwai static int out_jack_mode_get(struct snd_kcontrol *kcontrol, 2433978e77e7STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2434978e77e7STakashi Iwai { 2435978e77e7STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2436978e77e7STakashi Iwai hda_nid_t nid = kcontrol->private_value; 2437978e77e7STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) == PIN_HP) 2438978e77e7STakashi Iwai ucontrol->value.enumerated.item[0] = 1; 2439978e77e7STakashi Iwai else 2440978e77e7STakashi Iwai ucontrol->value.enumerated.item[0] = 0; 2441978e77e7STakashi Iwai return 0; 2442978e77e7STakashi Iwai } 2443978e77e7STakashi Iwai 2444978e77e7STakashi Iwai static int out_jack_mode_put(struct snd_kcontrol *kcontrol, 2445978e77e7STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2446978e77e7STakashi Iwai { 2447978e77e7STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2448978e77e7STakashi Iwai hda_nid_t nid = kcontrol->private_value; 2449978e77e7STakashi Iwai unsigned int val; 2450978e77e7STakashi Iwai 2451978e77e7STakashi Iwai val = ucontrol->value.enumerated.item[0] ? PIN_HP : PIN_OUT; 2452978e77e7STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) == val) 2453978e77e7STakashi Iwai return 0; 2454978e77e7STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, val); 2455978e77e7STakashi Iwai return 1; 2456978e77e7STakashi Iwai } 2457978e77e7STakashi Iwai 2458978e77e7STakashi Iwai static const struct snd_kcontrol_new out_jack_mode_enum = { 2459978e77e7STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2460978e77e7STakashi Iwai .info = out_jack_mode_info, 2461978e77e7STakashi Iwai .get = out_jack_mode_get, 2462978e77e7STakashi Iwai .put = out_jack_mode_put, 2463978e77e7STakashi Iwai }; 2464978e77e7STakashi Iwai 2465978e77e7STakashi Iwai static bool find_kctl_name(struct hda_codec *codec, const char *name, int idx) 2466978e77e7STakashi Iwai { 2467978e77e7STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2468978e77e7STakashi Iwai int i; 2469978e77e7STakashi Iwai 2470978e77e7STakashi Iwai for (i = 0; i < spec->kctls.used; i++) { 2471978e77e7STakashi Iwai struct snd_kcontrol_new *kctl = snd_array_elem(&spec->kctls, i); 2472978e77e7STakashi Iwai if (!strcmp(kctl->name, name) && kctl->index == idx) 2473978e77e7STakashi Iwai return true; 2474978e77e7STakashi Iwai } 2475978e77e7STakashi Iwai return false; 2476978e77e7STakashi Iwai } 2477978e77e7STakashi Iwai 2478978e77e7STakashi Iwai static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin, 2479978e77e7STakashi Iwai char *name, size_t name_len) 2480978e77e7STakashi Iwai { 2481978e77e7STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2482978e77e7STakashi Iwai int idx = 0; 2483978e77e7STakashi Iwai 2484978e77e7STakashi Iwai snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len, &idx); 2485978e77e7STakashi Iwai strlcat(name, " Jack Mode", name_len); 2486978e77e7STakashi Iwai 2487978e77e7STakashi Iwai for (; find_kctl_name(codec, name, idx); idx++) 2488978e77e7STakashi Iwai ; 2489978e77e7STakashi Iwai } 2490978e77e7STakashi Iwai 24915f171baaSTakashi Iwai static int get_out_jack_num_items(struct hda_codec *codec, hda_nid_t pin) 24925f171baaSTakashi Iwai { 24935f171baaSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 2494f811c3cfSTakashi Iwai if (spec->add_jack_modes) { 24955f171baaSTakashi Iwai unsigned int pincap = snd_hda_query_pin_caps(codec, pin); 24965f171baaSTakashi Iwai if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV)) 24975f171baaSTakashi Iwai return 2; 24985f171baaSTakashi Iwai } 24995f171baaSTakashi Iwai return 1; 25005f171baaSTakashi Iwai } 25015f171baaSTakashi Iwai 2502978e77e7STakashi Iwai static int create_out_jack_modes(struct hda_codec *codec, int num_pins, 2503978e77e7STakashi Iwai hda_nid_t *pins) 2504978e77e7STakashi Iwai { 2505978e77e7STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2506978e77e7STakashi Iwai int i; 2507978e77e7STakashi Iwai 2508978e77e7STakashi Iwai for (i = 0; i < num_pins; i++) { 2509978e77e7STakashi Iwai hda_nid_t pin = pins[i]; 2510ced4cefcSTakashi Iwai if (pin == spec->hp_mic_pin) 25115f171baaSTakashi Iwai continue; 25125f171baaSTakashi Iwai if (get_out_jack_num_items(codec, pin) > 1) { 2513978e77e7STakashi Iwai struct snd_kcontrol_new *knew; 2514975cc02aSTakashi Iwai char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 2515978e77e7STakashi Iwai get_jack_mode_name(codec, pin, name, sizeof(name)); 2516978e77e7STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, 2517978e77e7STakashi Iwai &out_jack_mode_enum); 2518978e77e7STakashi Iwai if (!knew) 2519978e77e7STakashi Iwai return -ENOMEM; 2520978e77e7STakashi Iwai knew->private_value = pin; 2521978e77e7STakashi Iwai } 2522978e77e7STakashi Iwai } 2523978e77e7STakashi Iwai 2524978e77e7STakashi Iwai return 0; 2525978e77e7STakashi Iwai } 2526978e77e7STakashi Iwai 252729476558STakashi Iwai /* 252829476558STakashi Iwai * input jack mode 252929476558STakashi Iwai */ 253029476558STakashi Iwai 253129476558STakashi Iwai /* from AC_PINCTL_VREF_HIZ to AC_PINCTL_VREF_100 */ 253229476558STakashi Iwai #define NUM_VREFS 6 253329476558STakashi Iwai 253429476558STakashi Iwai static const char * const vref_texts[NUM_VREFS] = { 253529476558STakashi Iwai "Line In", "Mic 50pc Bias", "Mic 0V Bias", 253629476558STakashi Iwai "", "Mic 80pc Bias", "Mic 100pc Bias" 253729476558STakashi Iwai }; 253829476558STakashi Iwai 253929476558STakashi Iwai static unsigned int get_vref_caps(struct hda_codec *codec, hda_nid_t pin) 254029476558STakashi Iwai { 254129476558STakashi Iwai unsigned int pincap; 254229476558STakashi Iwai 254329476558STakashi Iwai pincap = snd_hda_query_pin_caps(codec, pin); 254429476558STakashi Iwai pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; 254529476558STakashi Iwai /* filter out unusual vrefs */ 254629476558STakashi Iwai pincap &= ~(AC_PINCAP_VREF_GRD | AC_PINCAP_VREF_100); 254729476558STakashi Iwai return pincap; 254829476558STakashi Iwai } 254929476558STakashi Iwai 255029476558STakashi Iwai /* convert from the enum item index to the vref ctl index (0=HIZ, 1=50%...) */ 255129476558STakashi Iwai static int get_vref_idx(unsigned int vref_caps, unsigned int item_idx) 255229476558STakashi Iwai { 255329476558STakashi Iwai unsigned int i, n = 0; 255429476558STakashi Iwai 255529476558STakashi Iwai for (i = 0; i < NUM_VREFS; i++) { 255629476558STakashi Iwai if (vref_caps & (1 << i)) { 255729476558STakashi Iwai if (n == item_idx) 255829476558STakashi Iwai return i; 255929476558STakashi Iwai n++; 256029476558STakashi Iwai } 256129476558STakashi Iwai } 256229476558STakashi Iwai return 0; 256329476558STakashi Iwai } 256429476558STakashi Iwai 256529476558STakashi Iwai /* convert back from the vref ctl index to the enum item index */ 256629476558STakashi Iwai static int cvt_from_vref_idx(unsigned int vref_caps, unsigned int idx) 256729476558STakashi Iwai { 256829476558STakashi Iwai unsigned int i, n = 0; 256929476558STakashi Iwai 257029476558STakashi Iwai for (i = 0; i < NUM_VREFS; i++) { 257129476558STakashi Iwai if (i == idx) 257229476558STakashi Iwai return n; 257329476558STakashi Iwai if (vref_caps & (1 << i)) 257429476558STakashi Iwai n++; 257529476558STakashi Iwai } 257629476558STakashi Iwai return 0; 257729476558STakashi Iwai } 257829476558STakashi Iwai 257929476558STakashi Iwai static int in_jack_mode_info(struct snd_kcontrol *kcontrol, 258029476558STakashi Iwai struct snd_ctl_elem_info *uinfo) 258129476558STakashi Iwai { 258229476558STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 258329476558STakashi Iwai hda_nid_t nid = kcontrol->private_value; 258429476558STakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid); 258529476558STakashi Iwai 258629476558STakashi Iwai snd_hda_enum_helper_info(kcontrol, uinfo, hweight32(vref_caps), 258729476558STakashi Iwai vref_texts); 258829476558STakashi Iwai /* set the right text */ 258929476558STakashi Iwai strcpy(uinfo->value.enumerated.name, 259029476558STakashi Iwai vref_texts[get_vref_idx(vref_caps, uinfo->value.enumerated.item)]); 259129476558STakashi Iwai return 0; 259229476558STakashi Iwai } 259329476558STakashi Iwai 259429476558STakashi Iwai static int in_jack_mode_get(struct snd_kcontrol *kcontrol, 259529476558STakashi Iwai struct snd_ctl_elem_value *ucontrol) 259629476558STakashi Iwai { 259729476558STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 259829476558STakashi Iwai hda_nid_t nid = kcontrol->private_value; 259929476558STakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid); 260029476558STakashi Iwai unsigned int idx; 260129476558STakashi Iwai 260229476558STakashi Iwai idx = snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_VREFEN; 260329476558STakashi Iwai ucontrol->value.enumerated.item[0] = cvt_from_vref_idx(vref_caps, idx); 260429476558STakashi Iwai return 0; 260529476558STakashi Iwai } 260629476558STakashi Iwai 260729476558STakashi Iwai static int in_jack_mode_put(struct snd_kcontrol *kcontrol, 260829476558STakashi Iwai struct snd_ctl_elem_value *ucontrol) 260929476558STakashi Iwai { 261029476558STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 261129476558STakashi Iwai hda_nid_t nid = kcontrol->private_value; 261229476558STakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid); 261329476558STakashi Iwai unsigned int val, idx; 261429476558STakashi Iwai 261529476558STakashi Iwai val = snd_hda_codec_get_pin_target(codec, nid); 261629476558STakashi Iwai idx = cvt_from_vref_idx(vref_caps, val & AC_PINCTL_VREFEN); 261729476558STakashi Iwai if (idx == ucontrol->value.enumerated.item[0]) 261829476558STakashi Iwai return 0; 261929476558STakashi Iwai 262029476558STakashi Iwai val &= ~AC_PINCTL_VREFEN; 262129476558STakashi Iwai val |= get_vref_idx(vref_caps, ucontrol->value.enumerated.item[0]); 262229476558STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, val); 262329476558STakashi Iwai return 1; 262429476558STakashi Iwai } 262529476558STakashi Iwai 262629476558STakashi Iwai static const struct snd_kcontrol_new in_jack_mode_enum = { 262729476558STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 262829476558STakashi Iwai .info = in_jack_mode_info, 262929476558STakashi Iwai .get = in_jack_mode_get, 263029476558STakashi Iwai .put = in_jack_mode_put, 263129476558STakashi Iwai }; 263229476558STakashi Iwai 26335f171baaSTakashi Iwai static int get_in_jack_num_items(struct hda_codec *codec, hda_nid_t pin) 26345f171baaSTakashi Iwai { 26355f171baaSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 26365f171baaSTakashi Iwai int nitems = 0; 2637f811c3cfSTakashi Iwai if (spec->add_jack_modes) 26385f171baaSTakashi Iwai nitems = hweight32(get_vref_caps(codec, pin)); 26395f171baaSTakashi Iwai return nitems ? nitems : 1; 26405f171baaSTakashi Iwai } 26415f171baaSTakashi Iwai 264229476558STakashi Iwai static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin) 264329476558STakashi Iwai { 264429476558STakashi Iwai struct hda_gen_spec *spec = codec->spec; 264529476558STakashi Iwai struct snd_kcontrol_new *knew; 2646975cc02aSTakashi Iwai char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 26475f171baaSTakashi Iwai unsigned int defcfg; 26485f171baaSTakashi Iwai 2649f811c3cfSTakashi Iwai if (pin == spec->hp_mic_pin) 2650f811c3cfSTakashi Iwai return 0; /* already done in create_out_jack_mode() */ 265129476558STakashi Iwai 265229476558STakashi Iwai /* no jack mode for fixed pins */ 265329476558STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, pin); 265429476558STakashi Iwai if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT) 265529476558STakashi Iwai return 0; 265629476558STakashi Iwai 265729476558STakashi Iwai /* no multiple vref caps? */ 26585f171baaSTakashi Iwai if (get_in_jack_num_items(codec, pin) <= 1) 265929476558STakashi Iwai return 0; 266029476558STakashi Iwai 266129476558STakashi Iwai get_jack_mode_name(codec, pin, name, sizeof(name)); 266229476558STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &in_jack_mode_enum); 266329476558STakashi Iwai if (!knew) 266429476558STakashi Iwai return -ENOMEM; 266529476558STakashi Iwai knew->private_value = pin; 266629476558STakashi Iwai return 0; 266729476558STakashi Iwai } 266829476558STakashi Iwai 26695f171baaSTakashi Iwai /* 26705f171baaSTakashi Iwai * HP/mic shared jack mode 26715f171baaSTakashi Iwai */ 26725f171baaSTakashi Iwai static int hp_mic_jack_mode_info(struct snd_kcontrol *kcontrol, 26735f171baaSTakashi Iwai struct snd_ctl_elem_info *uinfo) 26745f171baaSTakashi Iwai { 26755f171baaSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 26765f171baaSTakashi Iwai hda_nid_t nid = kcontrol->private_value; 26775f171baaSTakashi Iwai int out_jacks = get_out_jack_num_items(codec, nid); 26785f171baaSTakashi Iwai int in_jacks = get_in_jack_num_items(codec, nid); 26795f171baaSTakashi Iwai const char *text = NULL; 26805f171baaSTakashi Iwai int idx; 26815f171baaSTakashi Iwai 26825f171baaSTakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 26835f171baaSTakashi Iwai uinfo->count = 1; 26845f171baaSTakashi Iwai uinfo->value.enumerated.items = out_jacks + in_jacks; 26855f171baaSTakashi Iwai if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 26865f171baaSTakashi Iwai uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; 26875f171baaSTakashi Iwai idx = uinfo->value.enumerated.item; 26885f171baaSTakashi Iwai if (idx < out_jacks) { 26895f171baaSTakashi Iwai if (out_jacks > 1) 26905f171baaSTakashi Iwai text = out_jack_texts[idx]; 26915f171baaSTakashi Iwai else 26925f171baaSTakashi Iwai text = "Headphone Out"; 26935f171baaSTakashi Iwai } else { 26945f171baaSTakashi Iwai idx -= out_jacks; 26955f171baaSTakashi Iwai if (in_jacks > 1) { 26965f171baaSTakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid); 26975f171baaSTakashi Iwai text = vref_texts[get_vref_idx(vref_caps, idx)]; 26985f171baaSTakashi Iwai } else 26995f171baaSTakashi Iwai text = "Mic In"; 27005f171baaSTakashi Iwai } 27015f171baaSTakashi Iwai 27025f171baaSTakashi Iwai strcpy(uinfo->value.enumerated.name, text); 27035f171baaSTakashi Iwai return 0; 27045f171baaSTakashi Iwai } 27055f171baaSTakashi Iwai 27065f171baaSTakashi Iwai static int get_cur_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t nid) 27075f171baaSTakashi Iwai { 27085f171baaSTakashi Iwai int out_jacks = get_out_jack_num_items(codec, nid); 27095f171baaSTakashi Iwai int in_jacks = get_in_jack_num_items(codec, nid); 27105f171baaSTakashi Iwai unsigned int val = snd_hda_codec_get_pin_target(codec, nid); 27115f171baaSTakashi Iwai int idx = 0; 27125f171baaSTakashi Iwai 27135f171baaSTakashi Iwai if (val & PIN_OUT) { 27145f171baaSTakashi Iwai if (out_jacks > 1 && val == PIN_HP) 27155f171baaSTakashi Iwai idx = 1; 27165f171baaSTakashi Iwai } else if (val & PIN_IN) { 27175f171baaSTakashi Iwai idx = out_jacks; 27185f171baaSTakashi Iwai if (in_jacks > 1) { 27195f171baaSTakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid); 27205f171baaSTakashi Iwai val &= AC_PINCTL_VREFEN; 27215f171baaSTakashi Iwai idx += cvt_from_vref_idx(vref_caps, val); 27225f171baaSTakashi Iwai } 27235f171baaSTakashi Iwai } 27245f171baaSTakashi Iwai return idx; 27255f171baaSTakashi Iwai } 27265f171baaSTakashi Iwai 27275f171baaSTakashi Iwai static int hp_mic_jack_mode_get(struct snd_kcontrol *kcontrol, 27285f171baaSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 27295f171baaSTakashi Iwai { 27305f171baaSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 27315f171baaSTakashi Iwai hda_nid_t nid = kcontrol->private_value; 27325f171baaSTakashi Iwai ucontrol->value.enumerated.item[0] = 27335f171baaSTakashi Iwai get_cur_hp_mic_jack_mode(codec, nid); 27345f171baaSTakashi Iwai return 0; 27355f171baaSTakashi Iwai } 27365f171baaSTakashi Iwai 27375f171baaSTakashi Iwai static int hp_mic_jack_mode_put(struct snd_kcontrol *kcontrol, 27385f171baaSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 27395f171baaSTakashi Iwai { 27405f171baaSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 27415f171baaSTakashi Iwai hda_nid_t nid = kcontrol->private_value; 27425f171baaSTakashi Iwai int out_jacks = get_out_jack_num_items(codec, nid); 27435f171baaSTakashi Iwai int in_jacks = get_in_jack_num_items(codec, nid); 27445f171baaSTakashi Iwai unsigned int val, oldval, idx; 27455f171baaSTakashi Iwai 27465f171baaSTakashi Iwai oldval = get_cur_hp_mic_jack_mode(codec, nid); 27475f171baaSTakashi Iwai idx = ucontrol->value.enumerated.item[0]; 27485f171baaSTakashi Iwai if (oldval == idx) 27495f171baaSTakashi Iwai return 0; 27505f171baaSTakashi Iwai 27515f171baaSTakashi Iwai if (idx < out_jacks) { 27525f171baaSTakashi Iwai if (out_jacks > 1) 27535f171baaSTakashi Iwai val = idx ? PIN_HP : PIN_OUT; 27545f171baaSTakashi Iwai else 27555f171baaSTakashi Iwai val = PIN_HP; 27565f171baaSTakashi Iwai } else { 27575f171baaSTakashi Iwai idx -= out_jacks; 27585f171baaSTakashi Iwai if (in_jacks > 1) { 27595f171baaSTakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid); 27605f171baaSTakashi Iwai val = snd_hda_codec_get_pin_target(codec, nid); 27613f550e32STakashi Iwai val &= ~(AC_PINCTL_VREFEN | PIN_HP); 27623f550e32STakashi Iwai val |= get_vref_idx(vref_caps, idx) | PIN_IN; 27635f171baaSTakashi Iwai } else 276416c0cefeSTakashi Iwai val = snd_hda_get_default_vref(codec, nid) | PIN_IN; 27655f171baaSTakashi Iwai } 27665f171baaSTakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, val); 2767963afde9STakashi Iwai call_hp_automute(codec, NULL); 27688ba955ceSTakashi Iwai 27695f171baaSTakashi Iwai return 1; 27705f171baaSTakashi Iwai } 27715f171baaSTakashi Iwai 27725f171baaSTakashi Iwai static const struct snd_kcontrol_new hp_mic_jack_mode_enum = { 27735f171baaSTakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 27745f171baaSTakashi Iwai .info = hp_mic_jack_mode_info, 27755f171baaSTakashi Iwai .get = hp_mic_jack_mode_get, 27765f171baaSTakashi Iwai .put = hp_mic_jack_mode_put, 27775f171baaSTakashi Iwai }; 27785f171baaSTakashi Iwai 27795f171baaSTakashi Iwai static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin) 27805f171baaSTakashi Iwai { 27815f171baaSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 27825f171baaSTakashi Iwai struct snd_kcontrol_new *knew; 27835f171baaSTakashi Iwai 27845f171baaSTakashi Iwai knew = snd_hda_gen_add_kctl(spec, "Headphone Mic Jack Mode", 27855f171baaSTakashi Iwai &hp_mic_jack_mode_enum); 27865f171baaSTakashi Iwai if (!knew) 27875f171baaSTakashi Iwai return -ENOMEM; 27885f171baaSTakashi Iwai knew->private_value = pin; 27898ba955ceSTakashi Iwai spec->hp_mic_jack_modes = 1; 27905f171baaSTakashi Iwai return 0; 27915f171baaSTakashi Iwai } 2792352f7f91STakashi Iwai 2793352f7f91STakashi Iwai /* 2794352f7f91STakashi Iwai * Parse input paths 2795352f7f91STakashi Iwai */ 2796352f7f91STakashi Iwai 2797352f7f91STakashi Iwai /* add the powersave loopback-list entry */ 27980186f4f4STakashi Iwai static int add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx) 2799352f7f91STakashi Iwai { 2800352f7f91STakashi Iwai struct hda_amp_list *list; 2801352f7f91STakashi Iwai 28020186f4f4STakashi Iwai list = snd_array_new(&spec->loopback_list); 28030186f4f4STakashi Iwai if (!list) 28040186f4f4STakashi Iwai return -ENOMEM; 2805352f7f91STakashi Iwai list->nid = mix; 2806352f7f91STakashi Iwai list->dir = HDA_INPUT; 2807352f7f91STakashi Iwai list->idx = idx; 28080186f4f4STakashi Iwai spec->loopback.amplist = spec->loopback_list.list; 28090186f4f4STakashi Iwai return 0; 2810cb53c626STakashi Iwai } 2811cb53c626STakashi Iwai 28122ded3e5bSTakashi Iwai /* return true if either a volume or a mute amp is found for the given 28132ded3e5bSTakashi Iwai * aamix path; the amp has to be either in the mixer node or its direct leaf 28142ded3e5bSTakashi Iwai */ 28152ded3e5bSTakashi Iwai static bool look_for_mix_leaf_ctls(struct hda_codec *codec, hda_nid_t mix_nid, 28162ded3e5bSTakashi Iwai hda_nid_t pin, unsigned int *mix_val, 28172ded3e5bSTakashi Iwai unsigned int *mute_val) 28182ded3e5bSTakashi Iwai { 28192ded3e5bSTakashi Iwai int idx, num_conns; 28202ded3e5bSTakashi Iwai const hda_nid_t *list; 28212ded3e5bSTakashi Iwai hda_nid_t nid; 28222ded3e5bSTakashi Iwai 28232ded3e5bSTakashi Iwai idx = snd_hda_get_conn_index(codec, mix_nid, pin, true); 28242ded3e5bSTakashi Iwai if (idx < 0) 28252ded3e5bSTakashi Iwai return false; 28262ded3e5bSTakashi Iwai 28272ded3e5bSTakashi Iwai *mix_val = *mute_val = 0; 28282ded3e5bSTakashi Iwai if (nid_has_volume(codec, mix_nid, HDA_INPUT)) 28292ded3e5bSTakashi Iwai *mix_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); 28302ded3e5bSTakashi Iwai if (nid_has_mute(codec, mix_nid, HDA_INPUT)) 28312ded3e5bSTakashi Iwai *mute_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); 28322ded3e5bSTakashi Iwai if (*mix_val && *mute_val) 28332ded3e5bSTakashi Iwai return true; 28342ded3e5bSTakashi Iwai 28352ded3e5bSTakashi Iwai /* check leaf node */ 28362ded3e5bSTakashi Iwai num_conns = snd_hda_get_conn_list(codec, mix_nid, &list); 28372ded3e5bSTakashi Iwai if (num_conns < idx) 28382ded3e5bSTakashi Iwai return false; 28392ded3e5bSTakashi Iwai nid = list[idx]; 28402ded3e5bSTakashi Iwai if (!*mix_val && nid_has_volume(codec, nid, HDA_OUTPUT)) 28412ded3e5bSTakashi Iwai *mix_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 28422ded3e5bSTakashi Iwai if (!*mute_val && nid_has_mute(codec, nid, HDA_OUTPUT)) 28432ded3e5bSTakashi Iwai *mute_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 28442ded3e5bSTakashi Iwai 28452ded3e5bSTakashi Iwai return *mix_val || *mute_val; 28462ded3e5bSTakashi Iwai } 28472ded3e5bSTakashi Iwai 2848352f7f91STakashi Iwai /* create input playback/capture controls for the given pin */ 2849196c1766STakashi Iwai static int new_analog_input(struct hda_codec *codec, int input_idx, 2850196c1766STakashi Iwai hda_nid_t pin, const char *ctlname, int ctlidx, 2851352f7f91STakashi Iwai hda_nid_t mix_nid) 28521da177e4SLinus Torvalds { 2853352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2854352f7f91STakashi Iwai struct nid_path *path; 28552ded3e5bSTakashi Iwai unsigned int mix_val, mute_val; 2856352f7f91STakashi Iwai int err, idx; 28571da177e4SLinus Torvalds 28582ded3e5bSTakashi Iwai if (!look_for_mix_leaf_ctls(codec, mix_nid, pin, &mix_val, &mute_val)) 28592ded3e5bSTakashi Iwai return 0; 2860352f7f91STakashi Iwai 28613ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, pin, mix_nid, 0); 2862352f7f91STakashi Iwai if (!path) 2863352f7f91STakashi Iwai return -EINVAL; 28640c8c0f56STakashi Iwai print_nid_path("loopback", path); 2865196c1766STakashi Iwai spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path); 2866352f7f91STakashi Iwai 2867352f7f91STakashi Iwai idx = path->idx[path->depth - 1]; 28682ded3e5bSTakashi Iwai if (mix_val) { 28692ded3e5bSTakashi Iwai err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, mix_val); 2870d13bd412STakashi Iwai if (err < 0) 28711da177e4SLinus Torvalds return err; 28722ded3e5bSTakashi Iwai path->ctls[NID_PATH_VOL_CTL] = mix_val; 28731da177e4SLinus Torvalds } 28741da177e4SLinus Torvalds 28752ded3e5bSTakashi Iwai if (mute_val) { 28762ded3e5bSTakashi Iwai err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, mute_val); 2877d13bd412STakashi Iwai if (err < 0) 28781da177e4SLinus Torvalds return err; 28792ded3e5bSTakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = mute_val; 28801da177e4SLinus Torvalds } 28811da177e4SLinus Torvalds 2882352f7f91STakashi Iwai path->active = true; 28830186f4f4STakashi Iwai err = add_loopback_list(spec, mix_nid, idx); 28840186f4f4STakashi Iwai if (err < 0) 28850186f4f4STakashi Iwai return err; 2886e4a395e7STakashi Iwai 2887e4a395e7STakashi Iwai if (spec->mixer_nid != spec->mixer_merge_nid && 2888e4a395e7STakashi Iwai !spec->loopback_merge_path) { 2889e4a395e7STakashi Iwai path = snd_hda_add_new_path(codec, spec->mixer_nid, 2890e4a395e7STakashi Iwai spec->mixer_merge_nid, 0); 2891e4a395e7STakashi Iwai if (path) { 2892e4a395e7STakashi Iwai print_nid_path("loopback-merge", path); 2893e4a395e7STakashi Iwai path->active = true; 2894e4a395e7STakashi Iwai spec->loopback_merge_path = 2895e4a395e7STakashi Iwai snd_hda_get_path_idx(codec, path); 2896e4a395e7STakashi Iwai } 2897e4a395e7STakashi Iwai } 2898e4a395e7STakashi Iwai 2899352f7f91STakashi Iwai return 0; 29001da177e4SLinus Torvalds } 29011da177e4SLinus Torvalds 2902352f7f91STakashi Iwai static int is_input_pin(struct hda_codec *codec, hda_nid_t nid) 29031da177e4SLinus Torvalds { 2904352f7f91STakashi Iwai unsigned int pincap = snd_hda_query_pin_caps(codec, nid); 2905352f7f91STakashi Iwai return (pincap & AC_PINCAP_IN) != 0; 2906352f7f91STakashi Iwai } 2907352f7f91STakashi Iwai 2908352f7f91STakashi Iwai /* Parse the codec tree and retrieve ADCs */ 2909352f7f91STakashi Iwai static int fill_adc_nids(struct hda_codec *codec) 2910352f7f91STakashi Iwai { 2911352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2912352f7f91STakashi Iwai hda_nid_t nid; 2913352f7f91STakashi Iwai hda_nid_t *adc_nids = spec->adc_nids; 2914352f7f91STakashi Iwai int max_nums = ARRAY_SIZE(spec->adc_nids); 2915352f7f91STakashi Iwai int i, nums = 0; 2916352f7f91STakashi Iwai 2917352f7f91STakashi Iwai nid = codec->start_nid; 2918352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) { 2919352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 2920352f7f91STakashi Iwai int type = get_wcaps_type(caps); 2921352f7f91STakashi Iwai 2922352f7f91STakashi Iwai if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL)) 2923352f7f91STakashi Iwai continue; 2924352f7f91STakashi Iwai adc_nids[nums] = nid; 2925352f7f91STakashi Iwai if (++nums >= max_nums) 2926352f7f91STakashi Iwai break; 2927352f7f91STakashi Iwai } 2928352f7f91STakashi Iwai spec->num_adc_nids = nums; 29290ffd534eSTakashi Iwai 29300ffd534eSTakashi Iwai /* copy the detected ADCs to all_adcs[] */ 29310ffd534eSTakashi Iwai spec->num_all_adcs = nums; 29320ffd534eSTakashi Iwai memcpy(spec->all_adcs, spec->adc_nids, nums * sizeof(hda_nid_t)); 29330ffd534eSTakashi Iwai 2934352f7f91STakashi Iwai return nums; 2935352f7f91STakashi Iwai } 2936352f7f91STakashi Iwai 2937352f7f91STakashi Iwai /* filter out invalid adc_nids that don't give all active input pins; 2938352f7f91STakashi Iwai * if needed, check whether dynamic ADC-switching is available 2939352f7f91STakashi Iwai */ 2940352f7f91STakashi Iwai static int check_dyn_adc_switch(struct hda_codec *codec) 2941352f7f91STakashi Iwai { 2942352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2943352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 29443a65bcdcSTakashi Iwai unsigned int ok_bits; 2945352f7f91STakashi Iwai int i, n, nums; 2946352f7f91STakashi Iwai 2947352f7f91STakashi Iwai nums = 0; 29483a65bcdcSTakashi Iwai ok_bits = 0; 2949352f7f91STakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 2950352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 29513a65bcdcSTakashi Iwai if (!spec->input_paths[i][n]) 2952352f7f91STakashi Iwai break; 2953352f7f91STakashi Iwai } 29543a65bcdcSTakashi Iwai if (i >= imux->num_items) { 29553a65bcdcSTakashi Iwai ok_bits |= (1 << n); 29563a65bcdcSTakashi Iwai nums++; 29573a65bcdcSTakashi Iwai } 2958352f7f91STakashi Iwai } 2959352f7f91STakashi Iwai 29603a65bcdcSTakashi Iwai if (!ok_bits) { 2961352f7f91STakashi Iwai /* check whether ADC-switch is possible */ 2962352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2963352f7f91STakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 29643a65bcdcSTakashi Iwai if (spec->input_paths[i][n]) { 2965352f7f91STakashi Iwai spec->dyn_adc_idx[i] = n; 2966352f7f91STakashi Iwai break; 2967352f7f91STakashi Iwai } 2968352f7f91STakashi Iwai } 2969352f7f91STakashi Iwai } 2970352f7f91STakashi Iwai 2971352f7f91STakashi Iwai snd_printdd("hda-codec: enabling ADC switching\n"); 2972352f7f91STakashi Iwai spec->dyn_adc_switch = 1; 2973352f7f91STakashi Iwai } else if (nums != spec->num_adc_nids) { 29743a65bcdcSTakashi Iwai /* shrink the invalid adcs and input paths */ 29753a65bcdcSTakashi Iwai nums = 0; 29763a65bcdcSTakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 29773a65bcdcSTakashi Iwai if (!(ok_bits & (1 << n))) 29783a65bcdcSTakashi Iwai continue; 29793a65bcdcSTakashi Iwai if (n != nums) { 29803a65bcdcSTakashi Iwai spec->adc_nids[nums] = spec->adc_nids[n]; 2981980428ceSTakashi Iwai for (i = 0; i < imux->num_items; i++) { 2982980428ceSTakashi Iwai invalidate_nid_path(codec, 2983980428ceSTakashi Iwai spec->input_paths[i][nums]); 29843a65bcdcSTakashi Iwai spec->input_paths[i][nums] = 29853a65bcdcSTakashi Iwai spec->input_paths[i][n]; 29863a65bcdcSTakashi Iwai } 2987980428ceSTakashi Iwai } 29883a65bcdcSTakashi Iwai nums++; 29893a65bcdcSTakashi Iwai } 2990352f7f91STakashi Iwai spec->num_adc_nids = nums; 2991352f7f91STakashi Iwai } 2992352f7f91STakashi Iwai 2993967303daSTakashi Iwai if (imux->num_items == 1 || 2994967303daSTakashi Iwai (imux->num_items == 2 && spec->hp_mic)) { 2995352f7f91STakashi Iwai snd_printdd("hda-codec: reducing to a single ADC\n"); 2996352f7f91STakashi Iwai spec->num_adc_nids = 1; /* reduce to a single ADC */ 2997352f7f91STakashi Iwai } 2998352f7f91STakashi Iwai 2999352f7f91STakashi Iwai /* single index for individual volumes ctls */ 3000352f7f91STakashi Iwai if (!spec->dyn_adc_switch && spec->multi_cap_vol) 3001352f7f91STakashi Iwai spec->num_adc_nids = 1; 3002352f7f91STakashi Iwai 30031da177e4SLinus Torvalds return 0; 30041da177e4SLinus Torvalds } 30051da177e4SLinus Torvalds 3006f3fc0b0bSTakashi Iwai /* parse capture source paths from the given pin and create imux items */ 3007f3fc0b0bSTakashi Iwai static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin, 30089dba205bSTakashi Iwai int cfg_idx, int num_adcs, 30099dba205bSTakashi Iwai const char *label, int anchor) 3010f3fc0b0bSTakashi Iwai { 3011f3fc0b0bSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 3012f3fc0b0bSTakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 3013f3fc0b0bSTakashi Iwai int imux_idx = imux->num_items; 3014f3fc0b0bSTakashi Iwai bool imux_added = false; 3015f3fc0b0bSTakashi Iwai int c; 3016f3fc0b0bSTakashi Iwai 3017f3fc0b0bSTakashi Iwai for (c = 0; c < num_adcs; c++) { 3018f3fc0b0bSTakashi Iwai struct nid_path *path; 3019f3fc0b0bSTakashi Iwai hda_nid_t adc = spec->adc_nids[c]; 3020f3fc0b0bSTakashi Iwai 3021f3fc0b0bSTakashi Iwai if (!is_reachable_path(codec, pin, adc)) 3022f3fc0b0bSTakashi Iwai continue; 3023f3fc0b0bSTakashi Iwai path = snd_hda_add_new_path(codec, pin, adc, anchor); 3024f3fc0b0bSTakashi Iwai if (!path) 3025f3fc0b0bSTakashi Iwai continue; 3026f3fc0b0bSTakashi Iwai print_nid_path("input", path); 3027f3fc0b0bSTakashi Iwai spec->input_paths[imux_idx][c] = 3028f3fc0b0bSTakashi Iwai snd_hda_get_path_idx(codec, path); 3029f3fc0b0bSTakashi Iwai 3030f3fc0b0bSTakashi Iwai if (!imux_added) { 3031967303daSTakashi Iwai if (spec->hp_mic_pin == pin) 3032967303daSTakashi Iwai spec->hp_mic_mux_idx = imux->num_items; 3033f3fc0b0bSTakashi Iwai spec->imux_pins[imux->num_items] = pin; 30349dba205bSTakashi Iwai snd_hda_add_imux_item(imux, label, cfg_idx, NULL); 3035f3fc0b0bSTakashi Iwai imux_added = true; 3036f1e762ddSTakashi Iwai if (spec->dyn_adc_switch) 3037f1e762ddSTakashi Iwai spec->dyn_adc_idx[imux_idx] = c; 3038f3fc0b0bSTakashi Iwai } 3039f3fc0b0bSTakashi Iwai } 3040f3fc0b0bSTakashi Iwai 3041f3fc0b0bSTakashi Iwai return 0; 3042f3fc0b0bSTakashi Iwai } 3043f3fc0b0bSTakashi Iwai 30441da177e4SLinus Torvalds /* 3045352f7f91STakashi Iwai * create playback/capture controls for input pins 30461da177e4SLinus Torvalds */ 30479dba205bSTakashi Iwai 3048c970042cSTakashi Iwai /* fill the label for each input at first */ 3049c970042cSTakashi Iwai static int fill_input_pin_labels(struct hda_codec *codec) 3050c970042cSTakashi Iwai { 3051c970042cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 3052c970042cSTakashi Iwai const struct auto_pin_cfg *cfg = &spec->autocfg; 3053c970042cSTakashi Iwai int i; 3054c970042cSTakashi Iwai 3055c970042cSTakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 3056c970042cSTakashi Iwai hda_nid_t pin = cfg->inputs[i].pin; 3057c970042cSTakashi Iwai const char *label; 3058c970042cSTakashi Iwai int j, idx; 3059c970042cSTakashi Iwai 3060c970042cSTakashi Iwai if (!is_input_pin(codec, pin)) 3061c970042cSTakashi Iwai continue; 3062c970042cSTakashi Iwai 3063c970042cSTakashi Iwai label = hda_get_autocfg_input_label(codec, cfg, i); 3064c970042cSTakashi Iwai idx = 0; 30658e8db7f1SDavid Henningsson for (j = i - 1; j >= 0; j--) { 3066c970042cSTakashi Iwai if (spec->input_labels[j] && 3067c970042cSTakashi Iwai !strcmp(spec->input_labels[j], label)) { 3068c970042cSTakashi Iwai idx = spec->input_label_idxs[j] + 1; 3069c970042cSTakashi Iwai break; 3070c970042cSTakashi Iwai } 3071c970042cSTakashi Iwai } 3072c970042cSTakashi Iwai 3073c970042cSTakashi Iwai spec->input_labels[i] = label; 3074c970042cSTakashi Iwai spec->input_label_idxs[i] = idx; 3075c970042cSTakashi Iwai } 3076c970042cSTakashi Iwai 3077c970042cSTakashi Iwai return 0; 3078c970042cSTakashi Iwai } 3079c970042cSTakashi Iwai 30809dba205bSTakashi Iwai #define CFG_IDX_MIX 99 /* a dummy cfg->input idx for stereo mix */ 30819dba205bSTakashi Iwai 3082352f7f91STakashi Iwai static int create_input_ctls(struct hda_codec *codec) 3083a7da6ce5STakashi Iwai { 3084352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3085352f7f91STakashi Iwai const struct auto_pin_cfg *cfg = &spec->autocfg; 3086352f7f91STakashi Iwai hda_nid_t mixer = spec->mixer_nid; 3087352f7f91STakashi Iwai int num_adcs; 3088c970042cSTakashi Iwai int i, err; 30892c12c30dSTakashi Iwai unsigned int val; 3090a7da6ce5STakashi Iwai 3091352f7f91STakashi Iwai num_adcs = fill_adc_nids(codec); 3092352f7f91STakashi Iwai if (num_adcs < 0) 3093352f7f91STakashi Iwai return 0; 3094352f7f91STakashi Iwai 3095c970042cSTakashi Iwai err = fill_input_pin_labels(codec); 3096c970042cSTakashi Iwai if (err < 0) 3097c970042cSTakashi Iwai return err; 3098c970042cSTakashi Iwai 3099352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 3100352f7f91STakashi Iwai hda_nid_t pin; 3101352f7f91STakashi Iwai 3102352f7f91STakashi Iwai pin = cfg->inputs[i].pin; 3103352f7f91STakashi Iwai if (!is_input_pin(codec, pin)) 3104352f7f91STakashi Iwai continue; 3105352f7f91STakashi Iwai 31062c12c30dSTakashi Iwai val = PIN_IN; 31072c12c30dSTakashi Iwai if (cfg->inputs[i].type == AUTO_PIN_MIC) 31082c12c30dSTakashi Iwai val |= snd_hda_get_default_vref(codec, pin); 310993c9d8aeSTakashi Iwai if (pin != spec->hp_mic_pin) 31102c12c30dSTakashi Iwai set_pin_target(codec, pin, val, false); 31112c12c30dSTakashi Iwai 3112352f7f91STakashi Iwai if (mixer) { 3113352f7f91STakashi Iwai if (is_reachable_path(codec, pin, mixer)) { 3114196c1766STakashi Iwai err = new_analog_input(codec, i, pin, 3115c970042cSTakashi Iwai spec->input_labels[i], 3116c970042cSTakashi Iwai spec->input_label_idxs[i], 3117c970042cSTakashi Iwai mixer); 3118a7da6ce5STakashi Iwai if (err < 0) 3119a7da6ce5STakashi Iwai return err; 3120a7da6ce5STakashi Iwai } 3121352f7f91STakashi Iwai } 3122352f7f91STakashi Iwai 3123c970042cSTakashi Iwai err = parse_capture_source(codec, pin, i, num_adcs, 3124c970042cSTakashi Iwai spec->input_labels[i], -mixer); 3125f3fc0b0bSTakashi Iwai if (err < 0) 3126f3fc0b0bSTakashi Iwai return err; 312729476558STakashi Iwai 3128f811c3cfSTakashi Iwai if (spec->add_jack_modes) { 312929476558STakashi Iwai err = create_in_jack_mode(codec, pin); 313029476558STakashi Iwai if (err < 0) 313129476558STakashi Iwai return err; 313229476558STakashi Iwai } 3133352f7f91STakashi Iwai } 3134f3fc0b0bSTakashi Iwai 3135f1e762ddSTakashi Iwai /* add stereo mix when explicitly enabled via hint */ 3136f1e762ddSTakashi Iwai if (mixer && spec->add_stereo_mix_input && 3137f1e762ddSTakashi Iwai snd_hda_get_bool_hint(codec, "add_stereo_mix_input") > 0) { 31389dba205bSTakashi Iwai err = parse_capture_source(codec, mixer, CFG_IDX_MIX, num_adcs, 3139f3fc0b0bSTakashi Iwai "Stereo Mix", 0); 3140f3fc0b0bSTakashi Iwai if (err < 0) 3141f3fc0b0bSTakashi Iwai return err; 3142352f7f91STakashi Iwai } 3143352f7f91STakashi Iwai 3144a7da6ce5STakashi Iwai return 0; 3145a7da6ce5STakashi Iwai } 3146a7da6ce5STakashi Iwai 31471da177e4SLinus Torvalds 3148352f7f91STakashi Iwai /* 3149352f7f91STakashi Iwai * input source mux 3150352f7f91STakashi Iwai */ 3151352f7f91STakashi Iwai 3152c697b716STakashi Iwai /* get the input path specified by the given adc and imux indices */ 3153c697b716STakashi Iwai static struct nid_path *get_input_path(struct hda_codec *codec, int adc_idx, int imux_idx) 3154352f7f91STakashi Iwai { 3155352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3156b56fa1edSDavid Henningsson if (imux_idx < 0 || imux_idx >= HDA_MAX_NUM_INPUTS) { 3157b56fa1edSDavid Henningsson snd_BUG(); 3158b56fa1edSDavid Henningsson return NULL; 3159b56fa1edSDavid Henningsson } 3160352f7f91STakashi Iwai if (spec->dyn_adc_switch) 3161352f7f91STakashi Iwai adc_idx = spec->dyn_adc_idx[imux_idx]; 3162d3d982f7SDavid Henningsson if (adc_idx < 0 || adc_idx >= AUTO_CFG_MAX_INS) { 3163b56fa1edSDavid Henningsson snd_BUG(); 3164b56fa1edSDavid Henningsson return NULL; 3165b56fa1edSDavid Henningsson } 3166c697b716STakashi Iwai return snd_hda_get_path_from_idx(codec, spec->input_paths[imux_idx][adc_idx]); 316797ec558aSTakashi Iwai } 3168352f7f91STakashi Iwai 3169352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx, 3170352f7f91STakashi Iwai unsigned int idx); 3171352f7f91STakashi Iwai 3172352f7f91STakashi Iwai static int mux_enum_info(struct snd_kcontrol *kcontrol, 3173352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 3174352f7f91STakashi Iwai { 3175352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3176352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3177352f7f91STakashi Iwai return snd_hda_input_mux_info(&spec->input_mux, uinfo); 3178352f7f91STakashi Iwai } 3179352f7f91STakashi Iwai 3180352f7f91STakashi Iwai static int mux_enum_get(struct snd_kcontrol *kcontrol, 3181352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3182352f7f91STakashi Iwai { 3183352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3184352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 31852a8d5391STakashi Iwai /* the ctls are created at once with multiple counts */ 31862a8d5391STakashi Iwai unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 3187352f7f91STakashi Iwai 3188352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; 31891da177e4SLinus Torvalds return 0; 31901da177e4SLinus Torvalds } 31911da177e4SLinus Torvalds 3192352f7f91STakashi Iwai static int mux_enum_put(struct snd_kcontrol *kcontrol, 3193352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 31941da177e4SLinus Torvalds { 3195352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 31962a8d5391STakashi Iwai unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 3197352f7f91STakashi Iwai return mux_select(codec, adc_idx, 3198352f7f91STakashi Iwai ucontrol->value.enumerated.item[0]); 3199352f7f91STakashi Iwai } 3200352f7f91STakashi Iwai 3201352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_src_temp = { 32021da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3203352f7f91STakashi Iwai .name = "Input Source", 3204352f7f91STakashi Iwai .info = mux_enum_info, 3205352f7f91STakashi Iwai .get = mux_enum_get, 3206352f7f91STakashi Iwai .put = mux_enum_put, 32071da177e4SLinus Torvalds }; 3208071c73adSTakashi Iwai 320947d46abbSTakashi Iwai /* 321047d46abbSTakashi Iwai * capture volume and capture switch ctls 321147d46abbSTakashi Iwai */ 321247d46abbSTakashi Iwai 3213352f7f91STakashi Iwai typedef int (*put_call_t)(struct snd_kcontrol *kcontrol, 3214352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol); 3215071c73adSTakashi Iwai 321647d46abbSTakashi Iwai /* call the given amp update function for all amps in the imux list at once */ 3217352f7f91STakashi Iwai static int cap_put_caller(struct snd_kcontrol *kcontrol, 3218352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol, 3219352f7f91STakashi Iwai put_call_t func, int type) 3220352f7f91STakashi Iwai { 3221352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3222352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3223352f7f91STakashi Iwai const struct hda_input_mux *imux; 3224352f7f91STakashi Iwai struct nid_path *path; 3225352f7f91STakashi Iwai int i, adc_idx, err = 0; 3226071c73adSTakashi Iwai 3227352f7f91STakashi Iwai imux = &spec->input_mux; 3228a053d1e3SDavid Henningsson adc_idx = kcontrol->id.index; 3229352f7f91STakashi Iwai mutex_lock(&codec->control_mutex); 323047d46abbSTakashi Iwai /* we use the cache-only update at first since multiple input paths 323147d46abbSTakashi Iwai * may shared the same amp; by updating only caches, the redundant 323247d46abbSTakashi Iwai * writes to hardware can be reduced. 323347d46abbSTakashi Iwai */ 3234352f7f91STakashi Iwai codec->cached_write = 1; 3235352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 3236c697b716STakashi Iwai path = get_input_path(codec, adc_idx, i); 3237c697b716STakashi Iwai if (!path || !path->ctls[type]) 3238352f7f91STakashi Iwai continue; 3239352f7f91STakashi Iwai kcontrol->private_value = path->ctls[type]; 3240352f7f91STakashi Iwai err = func(kcontrol, ucontrol); 3241352f7f91STakashi Iwai if (err < 0) 3242352f7f91STakashi Iwai goto error; 3243352f7f91STakashi Iwai } 3244352f7f91STakashi Iwai error: 3245352f7f91STakashi Iwai codec->cached_write = 0; 3246352f7f91STakashi Iwai mutex_unlock(&codec->control_mutex); 3247dc870f38STakashi Iwai snd_hda_codec_flush_cache(codec); /* flush the updates */ 3248352f7f91STakashi Iwai if (err >= 0 && spec->cap_sync_hook) 3249a90229e0STakashi Iwai spec->cap_sync_hook(codec, ucontrol); 3250352f7f91STakashi Iwai return err; 3251352f7f91STakashi Iwai } 3252352f7f91STakashi Iwai 3253352f7f91STakashi Iwai /* capture volume ctl callbacks */ 3254352f7f91STakashi Iwai #define cap_vol_info snd_hda_mixer_amp_volume_info 3255352f7f91STakashi Iwai #define cap_vol_get snd_hda_mixer_amp_volume_get 3256352f7f91STakashi Iwai #define cap_vol_tlv snd_hda_mixer_amp_tlv 3257352f7f91STakashi Iwai 3258352f7f91STakashi Iwai static int cap_vol_put(struct snd_kcontrol *kcontrol, 3259352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3260352f7f91STakashi Iwai { 3261352f7f91STakashi Iwai return cap_put_caller(kcontrol, ucontrol, 3262352f7f91STakashi Iwai snd_hda_mixer_amp_volume_put, 3263352f7f91STakashi Iwai NID_PATH_VOL_CTL); 3264352f7f91STakashi Iwai } 3265352f7f91STakashi Iwai 3266352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_vol_temp = { 3267352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3268352f7f91STakashi Iwai .name = "Capture Volume", 3269352f7f91STakashi Iwai .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 3270352f7f91STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ | 3271352f7f91STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), 3272352f7f91STakashi Iwai .info = cap_vol_info, 3273352f7f91STakashi Iwai .get = cap_vol_get, 3274352f7f91STakashi Iwai .put = cap_vol_put, 3275352f7f91STakashi Iwai .tlv = { .c = cap_vol_tlv }, 3276352f7f91STakashi Iwai }; 3277352f7f91STakashi Iwai 3278352f7f91STakashi Iwai /* capture switch ctl callbacks */ 3279352f7f91STakashi Iwai #define cap_sw_info snd_ctl_boolean_stereo_info 3280352f7f91STakashi Iwai #define cap_sw_get snd_hda_mixer_amp_switch_get 3281352f7f91STakashi Iwai 3282352f7f91STakashi Iwai static int cap_sw_put(struct snd_kcontrol *kcontrol, 3283352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3284352f7f91STakashi Iwai { 3285a90229e0STakashi Iwai return cap_put_caller(kcontrol, ucontrol, 3286352f7f91STakashi Iwai snd_hda_mixer_amp_switch_put, 3287352f7f91STakashi Iwai NID_PATH_MUTE_CTL); 3288352f7f91STakashi Iwai } 3289352f7f91STakashi Iwai 3290352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_sw_temp = { 3291352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3292352f7f91STakashi Iwai .name = "Capture Switch", 3293352f7f91STakashi Iwai .info = cap_sw_info, 3294352f7f91STakashi Iwai .get = cap_sw_get, 3295352f7f91STakashi Iwai .put = cap_sw_put, 3296352f7f91STakashi Iwai }; 3297352f7f91STakashi Iwai 3298352f7f91STakashi Iwai static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path) 3299352f7f91STakashi Iwai { 3300352f7f91STakashi Iwai hda_nid_t nid; 3301352f7f91STakashi Iwai int i, depth; 3302352f7f91STakashi Iwai 3303352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = path->ctls[NID_PATH_MUTE_CTL] = 0; 3304352f7f91STakashi Iwai for (depth = 0; depth < 3; depth++) { 3305352f7f91STakashi Iwai if (depth >= path->depth) 3306352f7f91STakashi Iwai return -EINVAL; 3307352f7f91STakashi Iwai i = path->depth - depth - 1; 3308352f7f91STakashi Iwai nid = path->path[i]; 3309352f7f91STakashi Iwai if (!path->ctls[NID_PATH_VOL_CTL]) { 3310352f7f91STakashi Iwai if (nid_has_volume(codec, nid, HDA_OUTPUT)) 3311352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = 3312352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 3313352f7f91STakashi Iwai else if (nid_has_volume(codec, nid, HDA_INPUT)) { 3314352f7f91STakashi Iwai int idx = path->idx[i]; 3315352f7f91STakashi Iwai if (!depth && codec->single_adc_amp) 3316352f7f91STakashi Iwai idx = 0; 3317352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = 3318352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); 3319352f7f91STakashi Iwai } 3320352f7f91STakashi Iwai } 3321352f7f91STakashi Iwai if (!path->ctls[NID_PATH_MUTE_CTL]) { 3322352f7f91STakashi Iwai if (nid_has_mute(codec, nid, HDA_OUTPUT)) 3323352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = 3324352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 3325352f7f91STakashi Iwai else if (nid_has_mute(codec, nid, HDA_INPUT)) { 3326352f7f91STakashi Iwai int idx = path->idx[i]; 3327352f7f91STakashi Iwai if (!depth && codec->single_adc_amp) 3328352f7f91STakashi Iwai idx = 0; 3329352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = 3330352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); 3331352f7f91STakashi Iwai } 3332352f7f91STakashi Iwai } 3333352f7f91STakashi Iwai } 3334352f7f91STakashi Iwai return 0; 3335352f7f91STakashi Iwai } 3336352f7f91STakashi Iwai 3337352f7f91STakashi Iwai static bool is_inv_dmic_pin(struct hda_codec *codec, hda_nid_t nid) 3338352f7f91STakashi Iwai { 3339352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3340352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 3341352f7f91STakashi Iwai unsigned int val; 3342352f7f91STakashi Iwai int i; 3343352f7f91STakashi Iwai 3344352f7f91STakashi Iwai if (!spec->inv_dmic_split) 3345352f7f91STakashi Iwai return false; 3346352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 3347352f7f91STakashi Iwai if (cfg->inputs[i].pin != nid) 3348352f7f91STakashi Iwai continue; 3349352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC) 3350352f7f91STakashi Iwai return false; 3351352f7f91STakashi Iwai val = snd_hda_codec_get_pincfg(codec, nid); 3352352f7f91STakashi Iwai return snd_hda_get_input_pin_attr(val) == INPUT_PIN_ATTR_INT; 3353352f7f91STakashi Iwai } 3354352f7f91STakashi Iwai return false; 3355352f7f91STakashi Iwai } 3356352f7f91STakashi Iwai 3357a90229e0STakashi Iwai /* capture switch put callback for a single control with hook call */ 3358a35bd1e3STakashi Iwai static int cap_single_sw_put(struct snd_kcontrol *kcontrol, 3359a35bd1e3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3360a35bd1e3STakashi Iwai { 3361a35bd1e3STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3362a35bd1e3STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3363a35bd1e3STakashi Iwai int ret; 3364a35bd1e3STakashi Iwai 3365a35bd1e3STakashi Iwai ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); 3366a35bd1e3STakashi Iwai if (ret < 0) 3367a35bd1e3STakashi Iwai return ret; 3368a35bd1e3STakashi Iwai 3369a90229e0STakashi Iwai if (spec->cap_sync_hook) 3370a90229e0STakashi Iwai spec->cap_sync_hook(codec, ucontrol); 3371a35bd1e3STakashi Iwai 3372a35bd1e3STakashi Iwai return ret; 3373a35bd1e3STakashi Iwai } 3374a35bd1e3STakashi Iwai 3375352f7f91STakashi Iwai static int add_single_cap_ctl(struct hda_codec *codec, const char *label, 3376352f7f91STakashi Iwai int idx, bool is_switch, unsigned int ctl, 3377352f7f91STakashi Iwai bool inv_dmic) 3378352f7f91STakashi Iwai { 3379352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3380975cc02aSTakashi Iwai char tmpname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 3381352f7f91STakashi Iwai int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL; 3382352f7f91STakashi Iwai const char *sfx = is_switch ? "Switch" : "Volume"; 3383352f7f91STakashi Iwai unsigned int chs = inv_dmic ? 1 : 3; 3384a35bd1e3STakashi Iwai struct snd_kcontrol_new *knew; 3385352f7f91STakashi Iwai 3386352f7f91STakashi Iwai if (!ctl) 3387352f7f91STakashi Iwai return 0; 3388352f7f91STakashi Iwai 3389352f7f91STakashi Iwai if (label) 3390352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 3391352f7f91STakashi Iwai "%s Capture %s", label, sfx); 3392352f7f91STakashi Iwai else 3393352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 3394352f7f91STakashi Iwai "Capture %s", sfx); 3395a35bd1e3STakashi Iwai knew = add_control(spec, type, tmpname, idx, 3396352f7f91STakashi Iwai amp_val_replace_channels(ctl, chs)); 3397a35bd1e3STakashi Iwai if (!knew) 3398a35bd1e3STakashi Iwai return -ENOMEM; 3399a90229e0STakashi Iwai if (is_switch) 3400a35bd1e3STakashi Iwai knew->put = cap_single_sw_put; 3401a35bd1e3STakashi Iwai if (!inv_dmic) 3402a35bd1e3STakashi Iwai return 0; 3403352f7f91STakashi Iwai 3404352f7f91STakashi Iwai /* Make independent right kcontrol */ 3405352f7f91STakashi Iwai if (label) 3406352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 3407352f7f91STakashi Iwai "Inverted %s Capture %s", label, sfx); 3408352f7f91STakashi Iwai else 3409352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 3410352f7f91STakashi Iwai "Inverted Capture %s", sfx); 3411a35bd1e3STakashi Iwai knew = add_control(spec, type, tmpname, idx, 3412352f7f91STakashi Iwai amp_val_replace_channels(ctl, 2)); 3413a35bd1e3STakashi Iwai if (!knew) 3414a35bd1e3STakashi Iwai return -ENOMEM; 3415a90229e0STakashi Iwai if (is_switch) 3416a35bd1e3STakashi Iwai knew->put = cap_single_sw_put; 3417a35bd1e3STakashi Iwai return 0; 3418352f7f91STakashi Iwai } 3419352f7f91STakashi Iwai 3420352f7f91STakashi Iwai /* create single (and simple) capture volume and switch controls */ 3421352f7f91STakashi Iwai static int create_single_cap_vol_ctl(struct hda_codec *codec, int idx, 3422352f7f91STakashi Iwai unsigned int vol_ctl, unsigned int sw_ctl, 3423352f7f91STakashi Iwai bool inv_dmic) 3424352f7f91STakashi Iwai { 3425352f7f91STakashi Iwai int err; 3426352f7f91STakashi Iwai err = add_single_cap_ctl(codec, NULL, idx, false, vol_ctl, inv_dmic); 3427352f7f91STakashi Iwai if (err < 0) 3428352f7f91STakashi Iwai return err; 3429352f7f91STakashi Iwai err = add_single_cap_ctl(codec, NULL, idx, true, sw_ctl, inv_dmic); 3430071c73adSTakashi Iwai if (err < 0) 3431071c73adSTakashi Iwai return err; 3432071c73adSTakashi Iwai return 0; 34331da177e4SLinus Torvalds } 3434071c73adSTakashi Iwai 3435352f7f91STakashi Iwai /* create bound capture volume and switch controls */ 3436352f7f91STakashi Iwai static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx, 3437352f7f91STakashi Iwai unsigned int vol_ctl, unsigned int sw_ctl) 3438352f7f91STakashi Iwai { 3439352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3440352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 3441352f7f91STakashi Iwai 3442352f7f91STakashi Iwai if (vol_ctl) { 344312c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, NULL, &cap_vol_temp); 3444352f7f91STakashi Iwai if (!knew) 3445352f7f91STakashi Iwai return -ENOMEM; 3446352f7f91STakashi Iwai knew->index = idx; 3447352f7f91STakashi Iwai knew->private_value = vol_ctl; 3448352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 3449352f7f91STakashi Iwai } 3450352f7f91STakashi Iwai if (sw_ctl) { 345112c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, NULL, &cap_sw_temp); 3452352f7f91STakashi Iwai if (!knew) 3453352f7f91STakashi Iwai return -ENOMEM; 3454352f7f91STakashi Iwai knew->index = idx; 3455352f7f91STakashi Iwai knew->private_value = sw_ctl; 3456352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 3457352f7f91STakashi Iwai } 3458352f7f91STakashi Iwai return 0; 3459352f7f91STakashi Iwai } 3460352f7f91STakashi Iwai 3461352f7f91STakashi Iwai /* return the vol ctl when used first in the imux list */ 3462352f7f91STakashi Iwai static unsigned int get_first_cap_ctl(struct hda_codec *codec, int idx, int type) 3463352f7f91STakashi Iwai { 3464352f7f91STakashi Iwai struct nid_path *path; 3465352f7f91STakashi Iwai unsigned int ctl; 3466352f7f91STakashi Iwai int i; 3467352f7f91STakashi Iwai 3468c697b716STakashi Iwai path = get_input_path(codec, 0, idx); 3469352f7f91STakashi Iwai if (!path) 3470352f7f91STakashi Iwai return 0; 3471352f7f91STakashi Iwai ctl = path->ctls[type]; 3472352f7f91STakashi Iwai if (!ctl) 3473352f7f91STakashi Iwai return 0; 3474352f7f91STakashi Iwai for (i = 0; i < idx - 1; i++) { 3475c697b716STakashi Iwai path = get_input_path(codec, 0, i); 3476352f7f91STakashi Iwai if (path && path->ctls[type] == ctl) 3477352f7f91STakashi Iwai return 0; 3478352f7f91STakashi Iwai } 3479352f7f91STakashi Iwai return ctl; 3480352f7f91STakashi Iwai } 3481352f7f91STakashi Iwai 3482352f7f91STakashi Iwai /* create individual capture volume and switch controls per input */ 3483352f7f91STakashi Iwai static int create_multi_cap_vol_ctl(struct hda_codec *codec) 3484352f7f91STakashi Iwai { 3485352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3486352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 3487c970042cSTakashi Iwai int i, err, type; 3488352f7f91STakashi Iwai 3489352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 3490352f7f91STakashi Iwai bool inv_dmic; 3491c970042cSTakashi Iwai int idx; 34929dba205bSTakashi Iwai 3493c970042cSTakashi Iwai idx = imux->items[i].index; 3494c970042cSTakashi Iwai if (idx >= spec->autocfg.num_inputs) 34959dba205bSTakashi Iwai continue; 3496352f7f91STakashi Iwai inv_dmic = is_inv_dmic_pin(codec, spec->imux_pins[i]); 3497352f7f91STakashi Iwai 3498352f7f91STakashi Iwai for (type = 0; type < 2; type++) { 3499c970042cSTakashi Iwai err = add_single_cap_ctl(codec, 3500c970042cSTakashi Iwai spec->input_labels[idx], 3501c970042cSTakashi Iwai spec->input_label_idxs[idx], 3502c970042cSTakashi Iwai type, 3503352f7f91STakashi Iwai get_first_cap_ctl(codec, i, type), 3504352f7f91STakashi Iwai inv_dmic); 3505d13bd412STakashi Iwai if (err < 0) 3506071c73adSTakashi Iwai return err; 3507352f7f91STakashi Iwai } 3508352f7f91STakashi Iwai } 3509071c73adSTakashi Iwai return 0; 3510352f7f91STakashi Iwai } 3511071c73adSTakashi Iwai 3512352f7f91STakashi Iwai static int create_capture_mixers(struct hda_codec *codec) 3513352f7f91STakashi Iwai { 3514352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3515352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 3516352f7f91STakashi Iwai int i, n, nums, err; 3517352f7f91STakashi Iwai 3518352f7f91STakashi Iwai if (spec->dyn_adc_switch) 3519352f7f91STakashi Iwai nums = 1; 3520352f7f91STakashi Iwai else 3521352f7f91STakashi Iwai nums = spec->num_adc_nids; 3522352f7f91STakashi Iwai 3523352f7f91STakashi Iwai if (!spec->auto_mic && imux->num_items > 1) { 3524352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 3525624d914dSTakashi Iwai const char *name; 3526624d914dSTakashi Iwai name = nums > 1 ? "Input Source" : "Capture Source"; 3527624d914dSTakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &cap_src_temp); 3528352f7f91STakashi Iwai if (!knew) 3529352f7f91STakashi Iwai return -ENOMEM; 3530352f7f91STakashi Iwai knew->count = nums; 3531352f7f91STakashi Iwai } 3532352f7f91STakashi Iwai 3533352f7f91STakashi Iwai for (n = 0; n < nums; n++) { 3534352f7f91STakashi Iwai bool multi = false; 353599a5592dSDavid Henningsson bool multi_cap_vol = spec->multi_cap_vol; 3536352f7f91STakashi Iwai bool inv_dmic = false; 3537352f7f91STakashi Iwai int vol, sw; 3538352f7f91STakashi Iwai 3539352f7f91STakashi Iwai vol = sw = 0; 3540352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 3541352f7f91STakashi Iwai struct nid_path *path; 3542c697b716STakashi Iwai path = get_input_path(codec, n, i); 3543352f7f91STakashi Iwai if (!path) 3544352f7f91STakashi Iwai continue; 3545352f7f91STakashi Iwai parse_capvol_in_path(codec, path); 3546352f7f91STakashi Iwai if (!vol) 3547352f7f91STakashi Iwai vol = path->ctls[NID_PATH_VOL_CTL]; 354899a5592dSDavid Henningsson else if (vol != path->ctls[NID_PATH_VOL_CTL]) { 3549352f7f91STakashi Iwai multi = true; 355099a5592dSDavid Henningsson if (!same_amp_caps(codec, vol, 355199a5592dSDavid Henningsson path->ctls[NID_PATH_VOL_CTL], HDA_INPUT)) 355299a5592dSDavid Henningsson multi_cap_vol = true; 355399a5592dSDavid Henningsson } 3554352f7f91STakashi Iwai if (!sw) 3555352f7f91STakashi Iwai sw = path->ctls[NID_PATH_MUTE_CTL]; 355699a5592dSDavid Henningsson else if (sw != path->ctls[NID_PATH_MUTE_CTL]) { 3557352f7f91STakashi Iwai multi = true; 355899a5592dSDavid Henningsson if (!same_amp_caps(codec, sw, 355999a5592dSDavid Henningsson path->ctls[NID_PATH_MUTE_CTL], HDA_INPUT)) 356099a5592dSDavid Henningsson multi_cap_vol = true; 356199a5592dSDavid Henningsson } 3562352f7f91STakashi Iwai if (is_inv_dmic_pin(codec, spec->imux_pins[i])) 3563352f7f91STakashi Iwai inv_dmic = true; 3564352f7f91STakashi Iwai } 3565352f7f91STakashi Iwai 3566352f7f91STakashi Iwai if (!multi) 3567352f7f91STakashi Iwai err = create_single_cap_vol_ctl(codec, n, vol, sw, 3568352f7f91STakashi Iwai inv_dmic); 3569ccb04157SDavid Henningsson else if (!multi_cap_vol && !inv_dmic) 3570352f7f91STakashi Iwai err = create_bind_cap_vol_ctl(codec, n, vol, sw); 3571352f7f91STakashi Iwai else 3572352f7f91STakashi Iwai err = create_multi_cap_vol_ctl(codec); 3573d13bd412STakashi Iwai if (err < 0) 3574071c73adSTakashi Iwai return err; 3575071c73adSTakashi Iwai } 3576071c73adSTakashi Iwai 35771da177e4SLinus Torvalds return 0; 35781da177e4SLinus Torvalds } 35791da177e4SLinus Torvalds 3580352f7f91STakashi Iwai /* 3581352f7f91STakashi Iwai * add mic boosts if needed 3582352f7f91STakashi Iwai */ 35836f7c83afSTakashi Iwai 35846f7c83afSTakashi Iwai /* check whether the given amp is feasible as a boost volume */ 35856f7c83afSTakashi Iwai static bool check_boost_vol(struct hda_codec *codec, hda_nid_t nid, 35866f7c83afSTakashi Iwai int dir, int idx) 35876f7c83afSTakashi Iwai { 35886f7c83afSTakashi Iwai unsigned int step; 35896f7c83afSTakashi Iwai 35906f7c83afSTakashi Iwai if (!nid_has_volume(codec, nid, dir) || 35916f7c83afSTakashi Iwai is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) || 35926f7c83afSTakashi Iwai is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL)) 35936f7c83afSTakashi Iwai return false; 35946f7c83afSTakashi Iwai 35956f7c83afSTakashi Iwai step = (query_amp_caps(codec, nid, dir) & AC_AMPCAP_STEP_SIZE) 35966f7c83afSTakashi Iwai >> AC_AMPCAP_STEP_SIZE_SHIFT; 35976f7c83afSTakashi Iwai if (step < 0x20) 35986f7c83afSTakashi Iwai return false; 35996f7c83afSTakashi Iwai return true; 36006f7c83afSTakashi Iwai } 36016f7c83afSTakashi Iwai 36026f7c83afSTakashi Iwai /* look for a boost amp in a widget close to the pin */ 36036f7c83afSTakashi Iwai static unsigned int look_for_boost_amp(struct hda_codec *codec, 36046f7c83afSTakashi Iwai struct nid_path *path) 36056f7c83afSTakashi Iwai { 36066f7c83afSTakashi Iwai unsigned int val = 0; 36076f7c83afSTakashi Iwai hda_nid_t nid; 36086f7c83afSTakashi Iwai int depth; 36096f7c83afSTakashi Iwai 36106f7c83afSTakashi Iwai for (depth = 0; depth < 3; depth++) { 36116f7c83afSTakashi Iwai if (depth >= path->depth - 1) 36126f7c83afSTakashi Iwai break; 36136f7c83afSTakashi Iwai nid = path->path[depth]; 36146f7c83afSTakashi Iwai if (depth && check_boost_vol(codec, nid, HDA_OUTPUT, 0)) { 36156f7c83afSTakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 36166f7c83afSTakashi Iwai break; 36176f7c83afSTakashi Iwai } else if (check_boost_vol(codec, nid, HDA_INPUT, 36186f7c83afSTakashi Iwai path->idx[depth])) { 36196f7c83afSTakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, path->idx[depth], 36206f7c83afSTakashi Iwai HDA_INPUT); 36216f7c83afSTakashi Iwai break; 36226f7c83afSTakashi Iwai } 36236f7c83afSTakashi Iwai } 36246f7c83afSTakashi Iwai 36256f7c83afSTakashi Iwai return val; 36266f7c83afSTakashi Iwai } 36276f7c83afSTakashi Iwai 3628352f7f91STakashi Iwai static int parse_mic_boost(struct hda_codec *codec) 3629352f7f91STakashi Iwai { 3630352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3631352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 36326f7c83afSTakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 3633a35bd1e3STakashi Iwai int i; 3634352f7f91STakashi Iwai 36356f7c83afSTakashi Iwai if (!spec->num_adc_nids) 36366f7c83afSTakashi Iwai return 0; 36376f7c83afSTakashi Iwai 36386f7c83afSTakashi Iwai for (i = 0; i < imux->num_items; i++) { 3639352f7f91STakashi Iwai struct nid_path *path; 3640352f7f91STakashi Iwai unsigned int val; 36416f7c83afSTakashi Iwai int idx; 3642975cc02aSTakashi Iwai char boost_label[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 3643352f7f91STakashi Iwai 36446f7c83afSTakashi Iwai idx = imux->items[i].index; 36456f7c83afSTakashi Iwai if (idx >= imux->num_items) 364602aba550SDavid Henningsson continue; 364702aba550SDavid Henningsson 36486f7c83afSTakashi Iwai /* check only line-in and mic pins */ 36491799cdd5STakashi Iwai if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN) 36506f7c83afSTakashi Iwai continue; 36516f7c83afSTakashi Iwai 36526f7c83afSTakashi Iwai path = get_input_path(codec, 0, i); 36536f7c83afSTakashi Iwai if (!path) 36546f7c83afSTakashi Iwai continue; 36556f7c83afSTakashi Iwai 36566f7c83afSTakashi Iwai val = look_for_boost_amp(codec, path); 36576f7c83afSTakashi Iwai if (!val) 36586f7c83afSTakashi Iwai continue; 36596f7c83afSTakashi Iwai 36606f7c83afSTakashi Iwai /* create a boost control */ 3661352f7f91STakashi Iwai snprintf(boost_label, sizeof(boost_label), 36626f7c83afSTakashi Iwai "%s Boost Volume", spec->input_labels[idx]); 3663a35bd1e3STakashi Iwai if (!add_control(spec, HDA_CTL_WIDGET_VOL, boost_label, 3664a35bd1e3STakashi Iwai spec->input_label_idxs[idx], val)) 3665a35bd1e3STakashi Iwai return -ENOMEM; 3666352f7f91STakashi Iwai 3667352f7f91STakashi Iwai path->ctls[NID_PATH_BOOST_CTL] = val; 3668352f7f91STakashi Iwai } 3669352f7f91STakashi Iwai return 0; 3670352f7f91STakashi Iwai } 3671352f7f91STakashi Iwai 3672352f7f91STakashi Iwai /* 3673352f7f91STakashi Iwai * parse digital I/Os and set up NIDs in BIOS auto-parse mode 3674352f7f91STakashi Iwai */ 3675352f7f91STakashi Iwai static void parse_digital(struct hda_codec *codec) 3676352f7f91STakashi Iwai { 3677352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 36780c8c0f56STakashi Iwai struct nid_path *path; 3679352f7f91STakashi Iwai int i, nums; 36802c12c30dSTakashi Iwai hda_nid_t dig_nid, pin; 3681352f7f91STakashi Iwai 3682352f7f91STakashi Iwai /* support multiple SPDIFs; the secondary is set up as a slave */ 3683352f7f91STakashi Iwai nums = 0; 3684352f7f91STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) { 36852c12c30dSTakashi Iwai pin = spec->autocfg.dig_out_pins[i]; 3686352f7f91STakashi Iwai dig_nid = look_for_dac(codec, pin, true); 3687352f7f91STakashi Iwai if (!dig_nid) 3688352f7f91STakashi Iwai continue; 36893ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dig_nid, pin, 0); 36900c8c0f56STakashi Iwai if (!path) 3691352f7f91STakashi Iwai continue; 36920c8c0f56STakashi Iwai print_nid_path("digout", path); 3693e1284af7STakashi Iwai path->active = true; 3694196c1766STakashi Iwai spec->digout_paths[i] = snd_hda_get_path_idx(codec, path); 36952c12c30dSTakashi Iwai set_pin_target(codec, pin, PIN_OUT, false); 3696352f7f91STakashi Iwai if (!nums) { 3697352f7f91STakashi Iwai spec->multiout.dig_out_nid = dig_nid; 3698352f7f91STakashi Iwai spec->dig_out_type = spec->autocfg.dig_out_type[0]; 3699352f7f91STakashi Iwai } else { 3700352f7f91STakashi Iwai spec->multiout.slave_dig_outs = spec->slave_dig_outs; 3701352f7f91STakashi Iwai if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) 3702352f7f91STakashi Iwai break; 3703352f7f91STakashi Iwai spec->slave_dig_outs[nums - 1] = dig_nid; 3704352f7f91STakashi Iwai } 3705352f7f91STakashi Iwai nums++; 3706352f7f91STakashi Iwai } 3707352f7f91STakashi Iwai 3708352f7f91STakashi Iwai if (spec->autocfg.dig_in_pin) { 37092c12c30dSTakashi Iwai pin = spec->autocfg.dig_in_pin; 3710352f7f91STakashi Iwai dig_nid = codec->start_nid; 3711352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, dig_nid++) { 3712352f7f91STakashi Iwai unsigned int wcaps = get_wcaps(codec, dig_nid); 3713352f7f91STakashi Iwai if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) 3714352f7f91STakashi Iwai continue; 3715352f7f91STakashi Iwai if (!(wcaps & AC_WCAP_DIGITAL)) 3716352f7f91STakashi Iwai continue; 37172c12c30dSTakashi Iwai path = snd_hda_add_new_path(codec, pin, dig_nid, 0); 3718352f7f91STakashi Iwai if (path) { 37190c8c0f56STakashi Iwai print_nid_path("digin", path); 3720352f7f91STakashi Iwai path->active = true; 3721352f7f91STakashi Iwai spec->dig_in_nid = dig_nid; 37222430d7b7STakashi Iwai spec->digin_path = snd_hda_get_path_idx(codec, path); 37232c12c30dSTakashi Iwai set_pin_target(codec, pin, PIN_IN, false); 3724352f7f91STakashi Iwai break; 3725352f7f91STakashi Iwai } 3726352f7f91STakashi Iwai } 3727352f7f91STakashi Iwai } 3728352f7f91STakashi Iwai } 3729352f7f91STakashi Iwai 37301da177e4SLinus Torvalds 37311da177e4SLinus Torvalds /* 3732352f7f91STakashi Iwai * input MUX handling 37331da177e4SLinus Torvalds */ 37341da177e4SLinus Torvalds 3735352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur); 3736352f7f91STakashi Iwai 3737352f7f91STakashi Iwai /* select the given imux item; either unmute exclusively or select the route */ 3738352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx, 3739352f7f91STakashi Iwai unsigned int idx) 3740352f7f91STakashi Iwai { 3741352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3742352f7f91STakashi Iwai const struct hda_input_mux *imux; 374355196fffSTakashi Iwai struct nid_path *old_path, *path; 3744352f7f91STakashi Iwai 3745352f7f91STakashi Iwai imux = &spec->input_mux; 3746352f7f91STakashi Iwai if (!imux->num_items) 37471da177e4SLinus Torvalds return 0; 37481da177e4SLinus Torvalds 3749352f7f91STakashi Iwai if (idx >= imux->num_items) 3750352f7f91STakashi Iwai idx = imux->num_items - 1; 3751352f7f91STakashi Iwai if (spec->cur_mux[adc_idx] == idx) 3752352f7f91STakashi Iwai return 0; 3753352f7f91STakashi Iwai 375455196fffSTakashi Iwai old_path = get_input_path(codec, adc_idx, spec->cur_mux[adc_idx]); 375555196fffSTakashi Iwai if (!old_path) 3756352f7f91STakashi Iwai return 0; 375755196fffSTakashi Iwai if (old_path->active) 375855196fffSTakashi Iwai snd_hda_activate_path(codec, old_path, false, false); 3759352f7f91STakashi Iwai 3760352f7f91STakashi Iwai spec->cur_mux[adc_idx] = idx; 3761352f7f91STakashi Iwai 3762967303daSTakashi Iwai if (spec->hp_mic) 3763967303daSTakashi Iwai update_hp_mic(codec, adc_idx, false); 3764352f7f91STakashi Iwai 3765352f7f91STakashi Iwai if (spec->dyn_adc_switch) 3766352f7f91STakashi Iwai dyn_adc_pcm_resetup(codec, idx); 3767352f7f91STakashi Iwai 3768c697b716STakashi Iwai path = get_input_path(codec, adc_idx, idx); 3769352f7f91STakashi Iwai if (!path) 3770352f7f91STakashi Iwai return 0; 3771352f7f91STakashi Iwai if (path->active) 3772352f7f91STakashi Iwai return 0; 3773352f7f91STakashi Iwai snd_hda_activate_path(codec, path, true, false); 3774352f7f91STakashi Iwai if (spec->cap_sync_hook) 3775a90229e0STakashi Iwai spec->cap_sync_hook(codec, NULL); 377655196fffSTakashi Iwai path_power_down_sync(codec, old_path); 37771da177e4SLinus Torvalds return 1; 37781da177e4SLinus Torvalds } 37791da177e4SLinus Torvalds 37801da177e4SLinus Torvalds 37811da177e4SLinus Torvalds /* 3782352f7f91STakashi Iwai * Jack detections for HP auto-mute and mic-switch 37831da177e4SLinus Torvalds */ 3784352f7f91STakashi Iwai 3785352f7f91STakashi Iwai /* check each pin in the given array; returns true if any of them is plugged */ 3786352f7f91STakashi Iwai static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) 37871da177e4SLinus Torvalds { 378860ea8ca2STakashi Iwai int i; 378960ea8ca2STakashi Iwai bool present = false; 37901da177e4SLinus Torvalds 3791352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 3792352f7f91STakashi Iwai hda_nid_t nid = pins[i]; 3793352f7f91STakashi Iwai if (!nid) 3794352f7f91STakashi Iwai break; 37950b4df931STakashi Iwai /* don't detect pins retasked as inputs */ 37960b4df931STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN) 37970b4df931STakashi Iwai continue; 379860ea8ca2STakashi Iwai if (snd_hda_jack_detect_state(codec, nid) == HDA_JACK_PRESENT) 379960ea8ca2STakashi Iwai present = true; 38001da177e4SLinus Torvalds } 3801352f7f91STakashi Iwai return present; 38021da177e4SLinus Torvalds } 38031da177e4SLinus Torvalds 3804352f7f91STakashi Iwai /* standard HP/line-out auto-mute helper */ 3805352f7f91STakashi Iwai static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, 3806e80c60f3STakashi Iwai int *paths, bool mute) 38071da177e4SLinus Torvalds { 3808352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3809352f7f91STakashi Iwai int i; 38101da177e4SLinus Torvalds 3811352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 3812352f7f91STakashi Iwai hda_nid_t nid = pins[i]; 3813967303daSTakashi Iwai unsigned int val, oldval; 3814352f7f91STakashi Iwai if (!nid) 3815352f7f91STakashi Iwai break; 38167eebffd3STakashi Iwai 38177eebffd3STakashi Iwai if (spec->auto_mute_via_amp) { 3818e80c60f3STakashi Iwai struct nid_path *path; 3819e80c60f3STakashi Iwai hda_nid_t mute_nid; 3820e80c60f3STakashi Iwai 3821e80c60f3STakashi Iwai path = snd_hda_get_path_from_idx(codec, paths[i]); 3822e80c60f3STakashi Iwai if (!path) 3823e80c60f3STakashi Iwai continue; 3824e80c60f3STakashi Iwai mute_nid = get_amp_nid_(path->ctls[NID_PATH_MUTE_CTL]); 3825e80c60f3STakashi Iwai if (!mute_nid) 3826e80c60f3STakashi Iwai continue; 38277eebffd3STakashi Iwai if (mute) 3828e80c60f3STakashi Iwai spec->mute_bits |= (1ULL << mute_nid); 38297eebffd3STakashi Iwai else 3830e80c60f3STakashi Iwai spec->mute_bits &= ~(1ULL << mute_nid); 38317eebffd3STakashi Iwai set_pin_eapd(codec, nid, !mute); 38327eebffd3STakashi Iwai continue; 38337eebffd3STakashi Iwai } 38347eebffd3STakashi Iwai 3835967303daSTakashi Iwai oldval = snd_hda_codec_get_pin_target(codec, nid); 3836967303daSTakashi Iwai if (oldval & PIN_IN) 3837967303daSTakashi Iwai continue; /* no mute for inputs */ 3838352f7f91STakashi Iwai /* don't reset VREF value in case it's controlling 3839352f7f91STakashi Iwai * the amp (see alc861_fixup_asus_amp_vref_0f()) 3840352f7f91STakashi Iwai */ 38412c12c30dSTakashi Iwai if (spec->keep_vref_in_automute) 3842967303daSTakashi Iwai val = oldval & ~PIN_HP; 38432c12c30dSTakashi Iwai else 3844352f7f91STakashi Iwai val = 0; 38452c12c30dSTakashi Iwai if (!mute) 3846967303daSTakashi Iwai val |= oldval; 38472c12c30dSTakashi Iwai /* here we call update_pin_ctl() so that the pinctl is changed 38482c12c30dSTakashi Iwai * without changing the pinctl target value; 38492c12c30dSTakashi Iwai * the original target value will be still referred at the 38502c12c30dSTakashi Iwai * init / resume again 38512c12c30dSTakashi Iwai */ 38522c12c30dSTakashi Iwai update_pin_ctl(codec, nid, val); 3853d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, !mute); 3854352f7f91STakashi Iwai } 3855352f7f91STakashi Iwai } 38561da177e4SLinus Torvalds 3857352f7f91STakashi Iwai /* Toggle outputs muting */ 38585d550e15STakashi Iwai void snd_hda_gen_update_outputs(struct hda_codec *codec) 3859352f7f91STakashi Iwai { 3860352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3861e80c60f3STakashi Iwai int *paths; 3862352f7f91STakashi Iwai int on; 3863352f7f91STakashi Iwai 3864352f7f91STakashi Iwai /* Control HP pins/amps depending on master_mute state; 3865352f7f91STakashi Iwai * in general, HP pins/amps control should be enabled in all cases, 3866352f7f91STakashi Iwai * but currently set only for master_mute, just to be safe 3867352f7f91STakashi Iwai */ 3868e80c60f3STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) 3869e80c60f3STakashi Iwai paths = spec->out_paths; 3870e80c60f3STakashi Iwai else 3871e80c60f3STakashi Iwai paths = spec->hp_paths; 3872352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), 3873e80c60f3STakashi Iwai spec->autocfg.hp_pins, paths, spec->master_mute); 3874352f7f91STakashi Iwai 3875352f7f91STakashi Iwai if (!spec->automute_speaker) 3876352f7f91STakashi Iwai on = 0; 3877352f7f91STakashi Iwai else 3878352f7f91STakashi Iwai on = spec->hp_jack_present | spec->line_jack_present; 3879352f7f91STakashi Iwai on |= spec->master_mute; 388047b9ddb8STakashi Iwai spec->speaker_muted = on; 3881e80c60f3STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) 3882e80c60f3STakashi Iwai paths = spec->out_paths; 3883e80c60f3STakashi Iwai else 3884e80c60f3STakashi Iwai paths = spec->speaker_paths; 3885352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), 3886e80c60f3STakashi Iwai spec->autocfg.speaker_pins, paths, on); 3887352f7f91STakashi Iwai 3888352f7f91STakashi Iwai /* toggle line-out mutes if needed, too */ 3889352f7f91STakashi Iwai /* if LO is a copy of either HP or Speaker, don't need to handle it */ 3890352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] || 3891352f7f91STakashi Iwai spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0]) 3892352f7f91STakashi Iwai return; 3893352f7f91STakashi Iwai if (!spec->automute_lo) 3894352f7f91STakashi Iwai on = 0; 3895352f7f91STakashi Iwai else 3896352f7f91STakashi Iwai on = spec->hp_jack_present; 3897352f7f91STakashi Iwai on |= spec->master_mute; 389847b9ddb8STakashi Iwai spec->line_out_muted = on; 3899e80c60f3STakashi Iwai paths = spec->out_paths; 3900352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), 3901e80c60f3STakashi Iwai spec->autocfg.line_out_pins, paths, on); 3902352f7f91STakashi Iwai } 39035d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs); 3904352f7f91STakashi Iwai 3905352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec) 3906352f7f91STakashi Iwai { 3907352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3908352f7f91STakashi Iwai if (spec->automute_hook) 3909352f7f91STakashi Iwai spec->automute_hook(codec); 3910352f7f91STakashi Iwai else 39115d550e15STakashi Iwai snd_hda_gen_update_outputs(codec); 39127eebffd3STakashi Iwai 39137eebffd3STakashi Iwai /* sync the whole vmaster slaves to reflect the new auto-mute status */ 39147eebffd3STakashi Iwai if (spec->auto_mute_via_amp && !codec->bus->shutdown) 39157eebffd3STakashi Iwai snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false); 3916352f7f91STakashi Iwai } 3917352f7f91STakashi Iwai 3918352f7f91STakashi Iwai /* standard HP-automute helper */ 39195d550e15STakashi Iwai void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) 3920352f7f91STakashi Iwai { 3921352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 392292603c59STakashi Iwai hda_nid_t *pins = spec->autocfg.hp_pins; 392392603c59STakashi Iwai int num_pins = ARRAY_SIZE(spec->autocfg.hp_pins); 3924352f7f91STakashi Iwai 392592603c59STakashi Iwai /* No detection for the first HP jack during indep-HP mode */ 392692603c59STakashi Iwai if (spec->indep_hp_enabled) { 392792603c59STakashi Iwai pins++; 392892603c59STakashi Iwai num_pins--; 392992603c59STakashi Iwai } 393092603c59STakashi Iwai 393192603c59STakashi Iwai spec->hp_jack_present = detect_jacks(codec, num_pins, pins); 3932352f7f91STakashi Iwai if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo)) 3933352f7f91STakashi Iwai return; 3934352f7f91STakashi Iwai call_update_outputs(codec); 3935352f7f91STakashi Iwai } 39365d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_hp_automute); 3937352f7f91STakashi Iwai 3938352f7f91STakashi Iwai /* standard line-out-automute helper */ 39395d550e15STakashi Iwai void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) 3940352f7f91STakashi Iwai { 3941352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3942352f7f91STakashi Iwai 3943352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) 3944352f7f91STakashi Iwai return; 3945352f7f91STakashi Iwai /* check LO jack only when it's different from HP */ 3946352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0]) 3947352f7f91STakashi Iwai return; 3948352f7f91STakashi Iwai 3949352f7f91STakashi Iwai spec->line_jack_present = 3950352f7f91STakashi Iwai detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), 3951352f7f91STakashi Iwai spec->autocfg.line_out_pins); 3952352f7f91STakashi Iwai if (!spec->automute_speaker || !spec->detect_lo) 3953352f7f91STakashi Iwai return; 3954352f7f91STakashi Iwai call_update_outputs(codec); 3955352f7f91STakashi Iwai } 39565d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_line_automute); 3957352f7f91STakashi Iwai 3958352f7f91STakashi Iwai /* standard mic auto-switch helper */ 39595d550e15STakashi Iwai void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *jack) 3960352f7f91STakashi Iwai { 3961352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3962352f7f91STakashi Iwai int i; 3963352f7f91STakashi Iwai 3964352f7f91STakashi Iwai if (!spec->auto_mic) 3965352f7f91STakashi Iwai return; 3966352f7f91STakashi Iwai 3967352f7f91STakashi Iwai for (i = spec->am_num_entries - 1; i > 0; i--) { 39680b4df931STakashi Iwai hda_nid_t pin = spec->am_entry[i].pin; 39690b4df931STakashi Iwai /* don't detect pins retasked as outputs */ 39700b4df931STakashi Iwai if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN) 39710b4df931STakashi Iwai continue; 397260ea8ca2STakashi Iwai if (snd_hda_jack_detect_state(codec, pin) == HDA_JACK_PRESENT) { 3973352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[i].idx); 3974352f7f91STakashi Iwai return; 3975352f7f91STakashi Iwai } 3976352f7f91STakashi Iwai } 3977352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[0].idx); 39781da177e4SLinus Torvalds } 39795d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_mic_autoswitch); 39801da177e4SLinus Torvalds 398177afe0e9STakashi Iwai /* call appropriate hooks */ 398277afe0e9STakashi Iwai static void call_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) 398377afe0e9STakashi Iwai { 398477afe0e9STakashi Iwai struct hda_gen_spec *spec = codec->spec; 398577afe0e9STakashi Iwai if (spec->hp_automute_hook) 398677afe0e9STakashi Iwai spec->hp_automute_hook(codec, jack); 398777afe0e9STakashi Iwai else 398877afe0e9STakashi Iwai snd_hda_gen_hp_automute(codec, jack); 398977afe0e9STakashi Iwai } 399077afe0e9STakashi Iwai 399177afe0e9STakashi Iwai static void call_line_automute(struct hda_codec *codec, 399277afe0e9STakashi Iwai struct hda_jack_tbl *jack) 399377afe0e9STakashi Iwai { 399477afe0e9STakashi Iwai struct hda_gen_spec *spec = codec->spec; 399577afe0e9STakashi Iwai if (spec->line_automute_hook) 399677afe0e9STakashi Iwai spec->line_automute_hook(codec, jack); 399777afe0e9STakashi Iwai else 399877afe0e9STakashi Iwai snd_hda_gen_line_automute(codec, jack); 399977afe0e9STakashi Iwai } 400077afe0e9STakashi Iwai 400177afe0e9STakashi Iwai static void call_mic_autoswitch(struct hda_codec *codec, 400277afe0e9STakashi Iwai struct hda_jack_tbl *jack) 400377afe0e9STakashi Iwai { 400477afe0e9STakashi Iwai struct hda_gen_spec *spec = codec->spec; 400577afe0e9STakashi Iwai if (spec->mic_autoswitch_hook) 400677afe0e9STakashi Iwai spec->mic_autoswitch_hook(codec, jack); 400777afe0e9STakashi Iwai else 400877afe0e9STakashi Iwai snd_hda_gen_mic_autoswitch(codec, jack); 400977afe0e9STakashi Iwai } 401077afe0e9STakashi Iwai 4011963afde9STakashi Iwai /* update jack retasking */ 4012963afde9STakashi Iwai static void update_automute_all(struct hda_codec *codec) 4013963afde9STakashi Iwai { 4014963afde9STakashi Iwai call_hp_automute(codec, NULL); 4015963afde9STakashi Iwai call_line_automute(codec, NULL); 4016963afde9STakashi Iwai call_mic_autoswitch(codec, NULL); 4017963afde9STakashi Iwai } 4018963afde9STakashi Iwai 40191da177e4SLinus Torvalds /* 4020352f7f91STakashi Iwai * Auto-Mute mode mixer enum support 40211da177e4SLinus Torvalds */ 4022352f7f91STakashi Iwai static int automute_mode_info(struct snd_kcontrol *kcontrol, 4023352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 4024352f7f91STakashi Iwai { 4025352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 4026352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4027352f7f91STakashi Iwai static const char * const texts3[] = { 4028352f7f91STakashi Iwai "Disabled", "Speaker Only", "Line Out+Speaker" 40291da177e4SLinus Torvalds }; 40301da177e4SLinus Torvalds 4031352f7f91STakashi Iwai if (spec->automute_speaker_possible && spec->automute_lo_possible) 4032352f7f91STakashi Iwai return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3); 4033352f7f91STakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo); 4034352f7f91STakashi Iwai } 4035352f7f91STakashi Iwai 4036352f7f91STakashi Iwai static int automute_mode_get(struct snd_kcontrol *kcontrol, 4037352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 4038352f7f91STakashi Iwai { 4039352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 4040352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4041352f7f91STakashi Iwai unsigned int val = 0; 4042352f7f91STakashi Iwai if (spec->automute_speaker) 4043352f7f91STakashi Iwai val++; 4044352f7f91STakashi Iwai if (spec->automute_lo) 4045352f7f91STakashi Iwai val++; 4046352f7f91STakashi Iwai 4047352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = val; 4048352f7f91STakashi Iwai return 0; 4049352f7f91STakashi Iwai } 4050352f7f91STakashi Iwai 4051352f7f91STakashi Iwai static int automute_mode_put(struct snd_kcontrol *kcontrol, 4052352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 4053352f7f91STakashi Iwai { 4054352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 4055352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4056352f7f91STakashi Iwai 4057352f7f91STakashi Iwai switch (ucontrol->value.enumerated.item[0]) { 4058352f7f91STakashi Iwai case 0: 4059352f7f91STakashi Iwai if (!spec->automute_speaker && !spec->automute_lo) 4060352f7f91STakashi Iwai return 0; 4061352f7f91STakashi Iwai spec->automute_speaker = 0; 4062352f7f91STakashi Iwai spec->automute_lo = 0; 4063352f7f91STakashi Iwai break; 4064352f7f91STakashi Iwai case 1: 4065352f7f91STakashi Iwai if (spec->automute_speaker_possible) { 4066352f7f91STakashi Iwai if (!spec->automute_lo && spec->automute_speaker) 4067352f7f91STakashi Iwai return 0; 4068352f7f91STakashi Iwai spec->automute_speaker = 1; 4069352f7f91STakashi Iwai spec->automute_lo = 0; 4070352f7f91STakashi Iwai } else if (spec->automute_lo_possible) { 4071352f7f91STakashi Iwai if (spec->automute_lo) 4072352f7f91STakashi Iwai return 0; 4073352f7f91STakashi Iwai spec->automute_lo = 1; 4074352f7f91STakashi Iwai } else 4075352f7f91STakashi Iwai return -EINVAL; 4076352f7f91STakashi Iwai break; 4077352f7f91STakashi Iwai case 2: 4078352f7f91STakashi Iwai if (!spec->automute_lo_possible || !spec->automute_speaker_possible) 4079352f7f91STakashi Iwai return -EINVAL; 4080352f7f91STakashi Iwai if (spec->automute_speaker && spec->automute_lo) 4081352f7f91STakashi Iwai return 0; 4082352f7f91STakashi Iwai spec->automute_speaker = 1; 4083352f7f91STakashi Iwai spec->automute_lo = 1; 4084352f7f91STakashi Iwai break; 4085352f7f91STakashi Iwai default: 4086352f7f91STakashi Iwai return -EINVAL; 4087352f7f91STakashi Iwai } 4088352f7f91STakashi Iwai call_update_outputs(codec); 4089352f7f91STakashi Iwai return 1; 4090352f7f91STakashi Iwai } 4091352f7f91STakashi Iwai 4092352f7f91STakashi Iwai static const struct snd_kcontrol_new automute_mode_enum = { 4093352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4094352f7f91STakashi Iwai .name = "Auto-Mute Mode", 4095352f7f91STakashi Iwai .info = automute_mode_info, 4096352f7f91STakashi Iwai .get = automute_mode_get, 4097352f7f91STakashi Iwai .put = automute_mode_put, 4098352f7f91STakashi Iwai }; 4099352f7f91STakashi Iwai 4100352f7f91STakashi Iwai static int add_automute_mode_enum(struct hda_codec *codec) 4101352f7f91STakashi Iwai { 4102352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4103352f7f91STakashi Iwai 410412c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &automute_mode_enum)) 4105352f7f91STakashi Iwai return -ENOMEM; 4106352f7f91STakashi Iwai return 0; 4107352f7f91STakashi Iwai } 4108352f7f91STakashi Iwai 4109352f7f91STakashi Iwai /* 4110352f7f91STakashi Iwai * Check the availability of HP/line-out auto-mute; 4111352f7f91STakashi Iwai * Set up appropriately if really supported 4112352f7f91STakashi Iwai */ 4113352f7f91STakashi Iwai static int check_auto_mute_availability(struct hda_codec *codec) 4114352f7f91STakashi Iwai { 4115352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4116352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 4117352f7f91STakashi Iwai int present = 0; 4118352f7f91STakashi Iwai int i, err; 4119352f7f91STakashi Iwai 4120f72706beSTakashi Iwai if (spec->suppress_auto_mute) 4121f72706beSTakashi Iwai return 0; 4122f72706beSTakashi Iwai 4123352f7f91STakashi Iwai if (cfg->hp_pins[0]) 4124352f7f91STakashi Iwai present++; 4125352f7f91STakashi Iwai if (cfg->line_out_pins[0]) 4126352f7f91STakashi Iwai present++; 4127352f7f91STakashi Iwai if (cfg->speaker_pins[0]) 4128352f7f91STakashi Iwai present++; 4129352f7f91STakashi Iwai if (present < 2) /* need two different output types */ 4130352f7f91STakashi Iwai return 0; 4131352f7f91STakashi Iwai 4132352f7f91STakashi Iwai if (!cfg->speaker_pins[0] && 4133352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { 4134352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 4135352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 4136352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 4137352f7f91STakashi Iwai } 4138352f7f91STakashi Iwai 4139352f7f91STakashi Iwai if (!cfg->hp_pins[0] && 4140352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) { 4141352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins, 4142352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 4143352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs; 4144352f7f91STakashi Iwai } 4145352f7f91STakashi Iwai 4146352f7f91STakashi Iwai for (i = 0; i < cfg->hp_outs; i++) { 4147352f7f91STakashi Iwai hda_nid_t nid = cfg->hp_pins[i]; 4148352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 4149352f7f91STakashi Iwai continue; 4150352f7f91STakashi Iwai snd_printdd("hda-codec: Enable HP auto-muting on NID 0x%x\n", 4151352f7f91STakashi Iwai nid); 4152352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid, HDA_GEN_HP_EVENT, 415377afe0e9STakashi Iwai call_hp_automute); 4154352f7f91STakashi Iwai spec->detect_hp = 1; 4155352f7f91STakashi Iwai } 4156352f7f91STakashi Iwai 4157352f7f91STakashi Iwai if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) { 4158352f7f91STakashi Iwai if (cfg->speaker_outs) 4159352f7f91STakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 4160352f7f91STakashi Iwai hda_nid_t nid = cfg->line_out_pins[i]; 4161352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 4162352f7f91STakashi Iwai continue; 4163352f7f91STakashi Iwai snd_printdd("hda-codec: Enable Line-Out auto-muting on NID 0x%x\n", nid); 4164352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid, 4165352f7f91STakashi Iwai HDA_GEN_FRONT_EVENT, 416677afe0e9STakashi Iwai call_line_automute); 4167352f7f91STakashi Iwai spec->detect_lo = 1; 4168352f7f91STakashi Iwai } 4169352f7f91STakashi Iwai spec->automute_lo_possible = spec->detect_hp; 4170352f7f91STakashi Iwai } 4171352f7f91STakashi Iwai 4172352f7f91STakashi Iwai spec->automute_speaker_possible = cfg->speaker_outs && 4173352f7f91STakashi Iwai (spec->detect_hp || spec->detect_lo); 4174352f7f91STakashi Iwai 4175352f7f91STakashi Iwai spec->automute_lo = spec->automute_lo_possible; 4176352f7f91STakashi Iwai spec->automute_speaker = spec->automute_speaker_possible; 4177352f7f91STakashi Iwai 4178352f7f91STakashi Iwai if (spec->automute_speaker_possible || spec->automute_lo_possible) { 4179352f7f91STakashi Iwai /* create a control for automute mode */ 4180352f7f91STakashi Iwai err = add_automute_mode_enum(codec); 4181352f7f91STakashi Iwai if (err < 0) 4182352f7f91STakashi Iwai return err; 4183352f7f91STakashi Iwai } 4184352f7f91STakashi Iwai return 0; 4185352f7f91STakashi Iwai } 4186352f7f91STakashi Iwai 4187352f7f91STakashi Iwai /* check whether all auto-mic pins are valid; setup indices if OK */ 4188352f7f91STakashi Iwai static bool auto_mic_check_imux(struct hda_codec *codec) 4189352f7f91STakashi Iwai { 4190352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4191352f7f91STakashi Iwai const struct hda_input_mux *imux; 4192352f7f91STakashi Iwai int i; 4193352f7f91STakashi Iwai 4194352f7f91STakashi Iwai imux = &spec->input_mux; 4195352f7f91STakashi Iwai for (i = 0; i < spec->am_num_entries; i++) { 4196352f7f91STakashi Iwai spec->am_entry[i].idx = 4197352f7f91STakashi Iwai find_idx_in_nid_list(spec->am_entry[i].pin, 4198352f7f91STakashi Iwai spec->imux_pins, imux->num_items); 4199352f7f91STakashi Iwai if (spec->am_entry[i].idx < 0) 4200352f7f91STakashi Iwai return false; /* no corresponding imux */ 4201352f7f91STakashi Iwai } 4202352f7f91STakashi Iwai 4203352f7f91STakashi Iwai /* we don't need the jack detection for the first pin */ 4204352f7f91STakashi Iwai for (i = 1; i < spec->am_num_entries; i++) 4205352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, 4206352f7f91STakashi Iwai spec->am_entry[i].pin, 4207352f7f91STakashi Iwai HDA_GEN_MIC_EVENT, 420877afe0e9STakashi Iwai call_mic_autoswitch); 4209352f7f91STakashi Iwai return true; 4210352f7f91STakashi Iwai } 4211352f7f91STakashi Iwai 4212352f7f91STakashi Iwai static int compare_attr(const void *ap, const void *bp) 4213352f7f91STakashi Iwai { 4214352f7f91STakashi Iwai const struct automic_entry *a = ap; 4215352f7f91STakashi Iwai const struct automic_entry *b = bp; 4216352f7f91STakashi Iwai return (int)(a->attr - b->attr); 4217352f7f91STakashi Iwai } 4218352f7f91STakashi Iwai 4219352f7f91STakashi Iwai /* 4220352f7f91STakashi Iwai * Check the availability of auto-mic switch; 4221352f7f91STakashi Iwai * Set up if really supported 4222352f7f91STakashi Iwai */ 4223352f7f91STakashi Iwai static int check_auto_mic_availability(struct hda_codec *codec) 4224352f7f91STakashi Iwai { 4225352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4226352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 4227352f7f91STakashi Iwai unsigned int types; 4228352f7f91STakashi Iwai int i, num_pins; 4229352f7f91STakashi Iwai 4230d12daf6fSTakashi Iwai if (spec->suppress_auto_mic) 4231d12daf6fSTakashi Iwai return 0; 4232d12daf6fSTakashi Iwai 4233352f7f91STakashi Iwai types = 0; 4234352f7f91STakashi Iwai num_pins = 0; 4235352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 4236352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 4237352f7f91STakashi Iwai unsigned int attr; 4238352f7f91STakashi Iwai attr = snd_hda_codec_get_pincfg(codec, nid); 4239352f7f91STakashi Iwai attr = snd_hda_get_input_pin_attr(attr); 4240352f7f91STakashi Iwai if (types & (1 << attr)) 4241352f7f91STakashi Iwai return 0; /* already occupied */ 4242352f7f91STakashi Iwai switch (attr) { 4243352f7f91STakashi Iwai case INPUT_PIN_ATTR_INT: 4244352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC) 4245352f7f91STakashi Iwai return 0; /* invalid type */ 4246352f7f91STakashi Iwai break; 4247352f7f91STakashi Iwai case INPUT_PIN_ATTR_UNUSED: 4248352f7f91STakashi Iwai return 0; /* invalid entry */ 4249352f7f91STakashi Iwai default: 4250352f7f91STakashi Iwai if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) 4251352f7f91STakashi Iwai return 0; /* invalid type */ 4252352f7f91STakashi Iwai if (!spec->line_in_auto_switch && 4253352f7f91STakashi Iwai cfg->inputs[i].type != AUTO_PIN_MIC) 4254352f7f91STakashi Iwai return 0; /* only mic is allowed */ 4255352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 4256352f7f91STakashi Iwai return 0; /* no unsol support */ 4257352f7f91STakashi Iwai break; 4258352f7f91STakashi Iwai } 4259352f7f91STakashi Iwai if (num_pins >= MAX_AUTO_MIC_PINS) 4260352f7f91STakashi Iwai return 0; 4261352f7f91STakashi Iwai types |= (1 << attr); 4262352f7f91STakashi Iwai spec->am_entry[num_pins].pin = nid; 4263352f7f91STakashi Iwai spec->am_entry[num_pins].attr = attr; 4264352f7f91STakashi Iwai num_pins++; 4265352f7f91STakashi Iwai } 4266352f7f91STakashi Iwai 4267352f7f91STakashi Iwai if (num_pins < 2) 4268352f7f91STakashi Iwai return 0; 4269352f7f91STakashi Iwai 4270352f7f91STakashi Iwai spec->am_num_entries = num_pins; 4271352f7f91STakashi Iwai /* sort the am_entry in the order of attr so that the pin with a 4272352f7f91STakashi Iwai * higher attr will be selected when the jack is plugged. 4273352f7f91STakashi Iwai */ 4274352f7f91STakashi Iwai sort(spec->am_entry, num_pins, sizeof(spec->am_entry[0]), 4275352f7f91STakashi Iwai compare_attr, NULL); 4276352f7f91STakashi Iwai 4277352f7f91STakashi Iwai if (!auto_mic_check_imux(codec)) 4278352f7f91STakashi Iwai return 0; 4279352f7f91STakashi Iwai 4280352f7f91STakashi Iwai spec->auto_mic = 1; 4281352f7f91STakashi Iwai spec->num_adc_nids = 1; 4282352f7f91STakashi Iwai spec->cur_mux[0] = spec->am_entry[0].idx; 4283352f7f91STakashi Iwai snd_printdd("hda-codec: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", 4284352f7f91STakashi Iwai spec->am_entry[0].pin, 4285352f7f91STakashi Iwai spec->am_entry[1].pin, 4286352f7f91STakashi Iwai spec->am_entry[2].pin); 4287352f7f91STakashi Iwai 4288352f7f91STakashi Iwai return 0; 4289352f7f91STakashi Iwai } 4290352f7f91STakashi Iwai 429155196fffSTakashi Iwai /* power_filter hook; make inactive widgets into power down */ 429255196fffSTakashi Iwai static unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec, 429355196fffSTakashi Iwai hda_nid_t nid, 429455196fffSTakashi Iwai unsigned int power_state) 429555196fffSTakashi Iwai { 429655196fffSTakashi Iwai if (power_state != AC_PWRST_D0) 429755196fffSTakashi Iwai return power_state; 429855196fffSTakashi Iwai if (get_wcaps_type(get_wcaps(codec, nid)) >= AC_WID_POWER) 429955196fffSTakashi Iwai return power_state; 4300b1b9fbd0STakashi Iwai if (is_active_nid_for_any(codec, nid)) 430155196fffSTakashi Iwai return power_state; 430255196fffSTakashi Iwai return AC_PWRST_D3; 430355196fffSTakashi Iwai } 430455196fffSTakashi Iwai 4305352f7f91STakashi Iwai 43069eb413e5STakashi Iwai /* 43079eb413e5STakashi Iwai * Parse the given BIOS configuration and set up the hda_gen_spec 43089eb413e5STakashi Iwai * 43099eb413e5STakashi Iwai * return 1 if successful, 0 if the proper config is not found, 4310352f7f91STakashi Iwai * or a negative error code 4311352f7f91STakashi Iwai */ 4312352f7f91STakashi Iwai int snd_hda_gen_parse_auto_config(struct hda_codec *codec, 43139eb413e5STakashi Iwai struct auto_pin_cfg *cfg) 4314352f7f91STakashi Iwai { 4315352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4316352f7f91STakashi Iwai int err; 4317352f7f91STakashi Iwai 43181c70a583STakashi Iwai parse_user_hints(codec); 43191c70a583STakashi Iwai 4320e4a395e7STakashi Iwai if (spec->mixer_nid && !spec->mixer_merge_nid) 4321e4a395e7STakashi Iwai spec->mixer_merge_nid = spec->mixer_nid; 4322e4a395e7STakashi Iwai 43239eb413e5STakashi Iwai if (cfg != &spec->autocfg) { 43249eb413e5STakashi Iwai spec->autocfg = *cfg; 43259eb413e5STakashi Iwai cfg = &spec->autocfg; 43269eb413e5STakashi Iwai } 43279eb413e5STakashi Iwai 432898bd1115STakashi Iwai if (!spec->main_out_badness) 432998bd1115STakashi Iwai spec->main_out_badness = &hda_main_out_badness; 433098bd1115STakashi Iwai if (!spec->extra_out_badness) 433198bd1115STakashi Iwai spec->extra_out_badness = &hda_extra_out_badness; 433298bd1115STakashi Iwai 43336fc4cb97SDavid Henningsson fill_all_dac_nids(codec); 43346fc4cb97SDavid Henningsson 4335352f7f91STakashi Iwai if (!cfg->line_outs) { 4336352f7f91STakashi Iwai if (cfg->dig_outs || cfg->dig_in_pin) { 4337352f7f91STakashi Iwai spec->multiout.max_channels = 2; 4338352f7f91STakashi Iwai spec->no_analog = 1; 4339352f7f91STakashi Iwai goto dig_only; 4340352f7f91STakashi Iwai } 4341c9e4bdb7STakashi Iwai if (!cfg->num_inputs && !cfg->dig_in_pin) 4342352f7f91STakashi Iwai return 0; /* can't find valid BIOS pin config */ 4343352f7f91STakashi Iwai } 4344352f7f91STakashi Iwai 4345352f7f91STakashi Iwai if (!spec->no_primary_hp && 4346352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && 4347352f7f91STakashi Iwai cfg->line_outs <= cfg->hp_outs) { 4348352f7f91STakashi Iwai /* use HP as primary out */ 4349352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 4350352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 4351352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 4352352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs; 4353352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); 4354352f7f91STakashi Iwai cfg->hp_outs = 0; 4355352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 4356352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT; 4357352f7f91STakashi Iwai } 4358352f7f91STakashi Iwai 4359352f7f91STakashi Iwai err = parse_output_paths(codec); 4360352f7f91STakashi Iwai if (err < 0) 4361352f7f91STakashi Iwai return err; 4362352f7f91STakashi Iwai err = create_multi_channel_mode(codec); 4363352f7f91STakashi Iwai if (err < 0) 4364352f7f91STakashi Iwai return err; 4365352f7f91STakashi Iwai err = create_multi_out_ctls(codec, cfg); 4366352f7f91STakashi Iwai if (err < 0) 4367352f7f91STakashi Iwai return err; 4368352f7f91STakashi Iwai err = create_hp_out_ctls(codec); 4369352f7f91STakashi Iwai if (err < 0) 4370352f7f91STakashi Iwai return err; 4371352f7f91STakashi Iwai err = create_speaker_out_ctls(codec); 4372352f7f91STakashi Iwai if (err < 0) 4373352f7f91STakashi Iwai return err; 437438cf6f1aSTakashi Iwai err = create_indep_hp_ctls(codec); 437538cf6f1aSTakashi Iwai if (err < 0) 437638cf6f1aSTakashi Iwai return err; 4377c30aa7b2STakashi Iwai err = create_loopback_mixing_ctl(codec); 4378c30aa7b2STakashi Iwai if (err < 0) 4379c30aa7b2STakashi Iwai return err; 4380967303daSTakashi Iwai err = create_hp_mic(codec); 4381352f7f91STakashi Iwai if (err < 0) 4382352f7f91STakashi Iwai return err; 4383352f7f91STakashi Iwai err = create_input_ctls(codec); 4384352f7f91STakashi Iwai if (err < 0) 4385352f7f91STakashi Iwai return err; 4386352f7f91STakashi Iwai 4387a07a949bSTakashi Iwai spec->const_channel_count = spec->ext_channel_count; 4388a07a949bSTakashi Iwai /* check the multiple speaker and headphone pins */ 4389a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 4390a07a949bSTakashi Iwai spec->const_channel_count = max(spec->const_channel_count, 4391a07a949bSTakashi Iwai cfg->speaker_outs * 2); 4392a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 4393a07a949bSTakashi Iwai spec->const_channel_count = max(spec->const_channel_count, 4394a07a949bSTakashi Iwai cfg->hp_outs * 2); 4395352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count, 4396352f7f91STakashi Iwai spec->const_channel_count); 4397352f7f91STakashi Iwai 4398352f7f91STakashi Iwai err = check_auto_mute_availability(codec); 4399352f7f91STakashi Iwai if (err < 0) 4400352f7f91STakashi Iwai return err; 4401352f7f91STakashi Iwai 4402352f7f91STakashi Iwai err = check_dyn_adc_switch(codec); 4403352f7f91STakashi Iwai if (err < 0) 4404352f7f91STakashi Iwai return err; 4405352f7f91STakashi Iwai 4406352f7f91STakashi Iwai err = check_auto_mic_availability(codec); 4407352f7f91STakashi Iwai if (err < 0) 4408352f7f91STakashi Iwai return err; 4409352f7f91STakashi Iwai 4410f1e762ddSTakashi Iwai /* add stereo mix if available and not enabled yet */ 4411f1e762ddSTakashi Iwai if (!spec->auto_mic && spec->mixer_nid && 4412f1e762ddSTakashi Iwai spec->add_stereo_mix_input && 4413f1e762ddSTakashi Iwai spec->input_mux.num_items > 1 && 4414f1e762ddSTakashi Iwai snd_hda_get_bool_hint(codec, "add_stereo_mix_input") < 0) { 4415f1e762ddSTakashi Iwai err = parse_capture_source(codec, spec->mixer_nid, 4416f1e762ddSTakashi Iwai CFG_IDX_MIX, spec->num_all_adcs, 4417f1e762ddSTakashi Iwai "Stereo Mix", 0); 4418f1e762ddSTakashi Iwai if (err < 0) 4419f1e762ddSTakashi Iwai return err; 4420f1e762ddSTakashi Iwai } 4421f1e762ddSTakashi Iwai 4422f1e762ddSTakashi Iwai 4423352f7f91STakashi Iwai err = create_capture_mixers(codec); 4424352f7f91STakashi Iwai if (err < 0) 4425352f7f91STakashi Iwai return err; 4426352f7f91STakashi Iwai 4427352f7f91STakashi Iwai err = parse_mic_boost(codec); 4428352f7f91STakashi Iwai if (err < 0) 4429352f7f91STakashi Iwai return err; 4430352f7f91STakashi Iwai 4431ced4cefcSTakashi Iwai /* create "Headphone Mic Jack Mode" if no input selection is 4432ced4cefcSTakashi Iwai * available (or user specifies add_jack_modes hint) 4433ced4cefcSTakashi Iwai */ 4434ced4cefcSTakashi Iwai if (spec->hp_mic_pin && 4435ced4cefcSTakashi Iwai (spec->auto_mic || spec->input_mux.num_items == 1 || 4436ced4cefcSTakashi Iwai spec->add_jack_modes)) { 4437ced4cefcSTakashi Iwai err = create_hp_mic_jack_mode(codec, spec->hp_mic_pin); 4438ced4cefcSTakashi Iwai if (err < 0) 4439ced4cefcSTakashi Iwai return err; 4440ced4cefcSTakashi Iwai } 4441ced4cefcSTakashi Iwai 4442f811c3cfSTakashi Iwai if (spec->add_jack_modes) { 4443978e77e7STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 4444978e77e7STakashi Iwai err = create_out_jack_modes(codec, cfg->line_outs, 4445978e77e7STakashi Iwai cfg->line_out_pins); 4446978e77e7STakashi Iwai if (err < 0) 4447978e77e7STakashi Iwai return err; 4448978e77e7STakashi Iwai } 4449978e77e7STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) { 4450978e77e7STakashi Iwai err = create_out_jack_modes(codec, cfg->hp_outs, 4451978e77e7STakashi Iwai cfg->hp_pins); 4452978e77e7STakashi Iwai if (err < 0) 4453978e77e7STakashi Iwai return err; 4454978e77e7STakashi Iwai } 4455978e77e7STakashi Iwai } 4456978e77e7STakashi Iwai 4457352f7f91STakashi Iwai dig_only: 4458352f7f91STakashi Iwai parse_digital(codec); 4459352f7f91STakashi Iwai 446055196fffSTakashi Iwai if (spec->power_down_unused) 446155196fffSTakashi Iwai codec->power_filter = snd_hda_gen_path_power_filter; 446255196fffSTakashi Iwai 44637504b6cdSTakashi Iwai if (!spec->no_analog && spec->beep_nid) { 44647504b6cdSTakashi Iwai err = snd_hda_attach_beep_device(codec, spec->beep_nid); 44657504b6cdSTakashi Iwai if (err < 0) 44667504b6cdSTakashi Iwai return err; 44677504b6cdSTakashi Iwai } 44687504b6cdSTakashi Iwai 4469352f7f91STakashi Iwai return 1; 4470352f7f91STakashi Iwai } 4471352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_parse_auto_config); 4472352f7f91STakashi Iwai 4473352f7f91STakashi Iwai 4474352f7f91STakashi Iwai /* 4475352f7f91STakashi Iwai * Build control elements 4476352f7f91STakashi Iwai */ 4477352f7f91STakashi Iwai 4478352f7f91STakashi Iwai /* slave controls for virtual master */ 4479352f7f91STakashi Iwai static const char * const slave_pfxs[] = { 4480352f7f91STakashi Iwai "Front", "Surround", "Center", "LFE", "Side", 4481352f7f91STakashi Iwai "Headphone", "Speaker", "Mono", "Line Out", 4482352f7f91STakashi Iwai "CLFE", "Bass Speaker", "PCM", 4483ee79c69aSTakashi Iwai "Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side", 4484ee79c69aSTakashi Iwai "Headphone Front", "Headphone Surround", "Headphone CLFE", 4485ee79c69aSTakashi Iwai "Headphone Side", 4486352f7f91STakashi Iwai NULL, 4487352f7f91STakashi Iwai }; 4488352f7f91STakashi Iwai 4489352f7f91STakashi Iwai int snd_hda_gen_build_controls(struct hda_codec *codec) 4490352f7f91STakashi Iwai { 4491352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4492352f7f91STakashi Iwai int err; 4493352f7f91STakashi Iwai 449436502d02STakashi Iwai if (spec->kctls.used) { 4495352f7f91STakashi Iwai err = snd_hda_add_new_ctls(codec, spec->kctls.list); 4496352f7f91STakashi Iwai if (err < 0) 4497352f7f91STakashi Iwai return err; 449836502d02STakashi Iwai } 4499352f7f91STakashi Iwai 4500352f7f91STakashi Iwai if (spec->multiout.dig_out_nid) { 4501352f7f91STakashi Iwai err = snd_hda_create_dig_out_ctls(codec, 4502352f7f91STakashi Iwai spec->multiout.dig_out_nid, 4503352f7f91STakashi Iwai spec->multiout.dig_out_nid, 4504352f7f91STakashi Iwai spec->pcm_rec[1].pcm_type); 4505352f7f91STakashi Iwai if (err < 0) 4506352f7f91STakashi Iwai return err; 4507352f7f91STakashi Iwai if (!spec->no_analog) { 4508352f7f91STakashi Iwai err = snd_hda_create_spdif_share_sw(codec, 4509352f7f91STakashi Iwai &spec->multiout); 4510352f7f91STakashi Iwai if (err < 0) 4511352f7f91STakashi Iwai return err; 4512352f7f91STakashi Iwai spec->multiout.share_spdif = 1; 4513352f7f91STakashi Iwai } 4514352f7f91STakashi Iwai } 4515352f7f91STakashi Iwai if (spec->dig_in_nid) { 4516352f7f91STakashi Iwai err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 4517352f7f91STakashi Iwai if (err < 0) 4518352f7f91STakashi Iwai return err; 4519352f7f91STakashi Iwai } 4520352f7f91STakashi Iwai 4521352f7f91STakashi Iwai /* if we have no master control, let's create it */ 4522352f7f91STakashi Iwai if (!spec->no_analog && 4523352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { 4524352f7f91STakashi Iwai err = snd_hda_add_vmaster(codec, "Master Playback Volume", 45257a71bbf3STakashi Iwai spec->vmaster_tlv, slave_pfxs, 4526352f7f91STakashi Iwai "Playback Volume"); 4527352f7f91STakashi Iwai if (err < 0) 4528352f7f91STakashi Iwai return err; 4529352f7f91STakashi Iwai } 4530352f7f91STakashi Iwai if (!spec->no_analog && 4531352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { 4532352f7f91STakashi Iwai err = __snd_hda_add_vmaster(codec, "Master Playback Switch", 4533352f7f91STakashi Iwai NULL, slave_pfxs, 4534352f7f91STakashi Iwai "Playback Switch", 4535352f7f91STakashi Iwai true, &spec->vmaster_mute.sw_kctl); 4536352f7f91STakashi Iwai if (err < 0) 4537352f7f91STakashi Iwai return err; 4538b63eae0aSTakashi Iwai if (spec->vmaster_mute.hook) { 4539fd25a97aSTakashi Iwai snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, 4540fd25a97aSTakashi Iwai spec->vmaster_mute_enum); 4541b63eae0aSTakashi Iwai snd_hda_sync_vmaster_hook(&spec->vmaster_mute); 4542b63eae0aSTakashi Iwai } 4543352f7f91STakashi Iwai } 4544352f7f91STakashi Iwai 4545352f7f91STakashi Iwai free_kctls(spec); /* no longer needed */ 4546352f7f91STakashi Iwai 4547352f7f91STakashi Iwai err = snd_hda_jack_add_kctls(codec, &spec->autocfg); 4548352f7f91STakashi Iwai if (err < 0) 4549352f7f91STakashi Iwai return err; 4550352f7f91STakashi Iwai 4551352f7f91STakashi Iwai return 0; 4552352f7f91STakashi Iwai } 4553352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_controls); 4554352f7f91STakashi Iwai 4555352f7f91STakashi Iwai 4556352f7f91STakashi Iwai /* 4557352f7f91STakashi Iwai * PCM definitions 4558352f7f91STakashi Iwai */ 4559352f7f91STakashi Iwai 4560e6b85f3cSTakashi Iwai static void call_pcm_playback_hook(struct hda_pcm_stream *hinfo, 4561e6b85f3cSTakashi Iwai struct hda_codec *codec, 4562e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream, 4563e6b85f3cSTakashi Iwai int action) 4564e6b85f3cSTakashi Iwai { 4565e6b85f3cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 4566e6b85f3cSTakashi Iwai if (spec->pcm_playback_hook) 4567e6b85f3cSTakashi Iwai spec->pcm_playback_hook(hinfo, codec, substream, action); 4568e6b85f3cSTakashi Iwai } 4569e6b85f3cSTakashi Iwai 4570ac2e8736STakashi Iwai static void call_pcm_capture_hook(struct hda_pcm_stream *hinfo, 4571ac2e8736STakashi Iwai struct hda_codec *codec, 4572ac2e8736STakashi Iwai struct snd_pcm_substream *substream, 4573ac2e8736STakashi Iwai int action) 4574ac2e8736STakashi Iwai { 4575ac2e8736STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4576ac2e8736STakashi Iwai if (spec->pcm_capture_hook) 4577ac2e8736STakashi Iwai spec->pcm_capture_hook(hinfo, codec, substream, action); 4578ac2e8736STakashi Iwai } 4579ac2e8736STakashi Iwai 4580352f7f91STakashi Iwai /* 4581352f7f91STakashi Iwai * Analog playback callbacks 4582352f7f91STakashi Iwai */ 4583352f7f91STakashi Iwai static int playback_pcm_open(struct hda_pcm_stream *hinfo, 4584352f7f91STakashi Iwai struct hda_codec *codec, 4585352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4586352f7f91STakashi Iwai { 4587352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 458838cf6f1aSTakashi Iwai int err; 458938cf6f1aSTakashi Iwai 459038cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 459138cf6f1aSTakashi Iwai err = snd_hda_multi_out_analog_open(codec, 459238cf6f1aSTakashi Iwai &spec->multiout, substream, 4593352f7f91STakashi Iwai hinfo); 4594e6b85f3cSTakashi Iwai if (!err) { 459538cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_MULTI_OUT; 4596e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 4597e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_OPEN); 4598e6b85f3cSTakashi Iwai } 459938cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 460038cf6f1aSTakashi Iwai return err; 4601352f7f91STakashi Iwai } 4602352f7f91STakashi Iwai 4603352f7f91STakashi Iwai static int playback_pcm_prepare(struct hda_pcm_stream *hinfo, 460497ec558aSTakashi Iwai struct hda_codec *codec, 460597ec558aSTakashi Iwai unsigned int stream_tag, 460697ec558aSTakashi Iwai unsigned int format, 460797ec558aSTakashi Iwai struct snd_pcm_substream *substream) 460897ec558aSTakashi Iwai { 4609352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4610e6b85f3cSTakashi Iwai int err; 4611e6b85f3cSTakashi Iwai 4612e6b85f3cSTakashi Iwai err = snd_hda_multi_out_analog_prepare(codec, &spec->multiout, 4613352f7f91STakashi Iwai stream_tag, format, substream); 4614e6b85f3cSTakashi Iwai if (!err) 4615e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 4616e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 4617e6b85f3cSTakashi Iwai return err; 4618352f7f91STakashi Iwai } 461997ec558aSTakashi Iwai 4620352f7f91STakashi Iwai static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 4621352f7f91STakashi Iwai struct hda_codec *codec, 4622352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4623352f7f91STakashi Iwai { 4624352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4625e6b85f3cSTakashi Iwai int err; 4626e6b85f3cSTakashi Iwai 4627e6b85f3cSTakashi Iwai err = snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); 4628e6b85f3cSTakashi Iwai if (!err) 4629e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 4630e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 4631e6b85f3cSTakashi Iwai return err; 4632352f7f91STakashi Iwai } 4633352f7f91STakashi Iwai 463438cf6f1aSTakashi Iwai static int playback_pcm_close(struct hda_pcm_stream *hinfo, 463538cf6f1aSTakashi Iwai struct hda_codec *codec, 463638cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 463738cf6f1aSTakashi Iwai { 463838cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 463938cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 464038cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_MULTI_OUT); 4641e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 4642e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLOSE); 464338cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 464438cf6f1aSTakashi Iwai return 0; 464538cf6f1aSTakashi Iwai } 464638cf6f1aSTakashi Iwai 4647ac2e8736STakashi Iwai static int capture_pcm_open(struct hda_pcm_stream *hinfo, 4648ac2e8736STakashi Iwai struct hda_codec *codec, 4649ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 4650ac2e8736STakashi Iwai { 4651ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_OPEN); 4652ac2e8736STakashi Iwai return 0; 4653ac2e8736STakashi Iwai } 4654ac2e8736STakashi Iwai 4655ac2e8736STakashi Iwai static int capture_pcm_prepare(struct hda_pcm_stream *hinfo, 4656ac2e8736STakashi Iwai struct hda_codec *codec, 4657ac2e8736STakashi Iwai unsigned int stream_tag, 4658ac2e8736STakashi Iwai unsigned int format, 4659ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 4660ac2e8736STakashi Iwai { 4661ac2e8736STakashi Iwai snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); 4662ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 4663ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 4664ac2e8736STakashi Iwai return 0; 4665ac2e8736STakashi Iwai } 4666ac2e8736STakashi Iwai 4667ac2e8736STakashi Iwai static int capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 4668ac2e8736STakashi Iwai struct hda_codec *codec, 4669ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 4670ac2e8736STakashi Iwai { 4671ac2e8736STakashi Iwai snd_hda_codec_cleanup_stream(codec, hinfo->nid); 4672ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 4673ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 4674ac2e8736STakashi Iwai return 0; 4675ac2e8736STakashi Iwai } 4676ac2e8736STakashi Iwai 4677ac2e8736STakashi Iwai static int capture_pcm_close(struct hda_pcm_stream *hinfo, 4678ac2e8736STakashi Iwai struct hda_codec *codec, 4679ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 4680ac2e8736STakashi Iwai { 4681ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLOSE); 4682ac2e8736STakashi Iwai return 0; 4683ac2e8736STakashi Iwai } 4684ac2e8736STakashi Iwai 468538cf6f1aSTakashi Iwai static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo, 468638cf6f1aSTakashi Iwai struct hda_codec *codec, 468738cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 468838cf6f1aSTakashi Iwai { 468938cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 469038cf6f1aSTakashi Iwai int err = 0; 469138cf6f1aSTakashi Iwai 469238cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 469338cf6f1aSTakashi Iwai if (!spec->indep_hp_enabled) 469438cf6f1aSTakashi Iwai err = -EBUSY; 469538cf6f1aSTakashi Iwai else 469638cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_INDEP_HP; 4697e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 4698e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_OPEN); 469938cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 470038cf6f1aSTakashi Iwai return err; 470138cf6f1aSTakashi Iwai } 470238cf6f1aSTakashi Iwai 470338cf6f1aSTakashi Iwai static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo, 470438cf6f1aSTakashi Iwai struct hda_codec *codec, 470538cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 470638cf6f1aSTakashi Iwai { 470738cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 470838cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 470938cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_INDEP_HP); 4710e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 4711e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLOSE); 471238cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 471338cf6f1aSTakashi Iwai return 0; 471438cf6f1aSTakashi Iwai } 471538cf6f1aSTakashi Iwai 4716e6b85f3cSTakashi Iwai static int alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 4717e6b85f3cSTakashi Iwai struct hda_codec *codec, 4718e6b85f3cSTakashi Iwai unsigned int stream_tag, 4719e6b85f3cSTakashi Iwai unsigned int format, 4720e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream) 4721e6b85f3cSTakashi Iwai { 4722e6b85f3cSTakashi Iwai snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); 4723e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 4724e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 4725e6b85f3cSTakashi Iwai return 0; 4726e6b85f3cSTakashi Iwai } 4727e6b85f3cSTakashi Iwai 4728e6b85f3cSTakashi Iwai static int alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 4729e6b85f3cSTakashi Iwai struct hda_codec *codec, 4730e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream) 4731e6b85f3cSTakashi Iwai { 4732e6b85f3cSTakashi Iwai snd_hda_codec_cleanup_stream(codec, hinfo->nid); 4733e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 4734e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 4735e6b85f3cSTakashi Iwai return 0; 4736e6b85f3cSTakashi Iwai } 4737e6b85f3cSTakashi Iwai 4738352f7f91STakashi Iwai /* 4739352f7f91STakashi Iwai * Digital out 4740352f7f91STakashi Iwai */ 4741352f7f91STakashi Iwai static int dig_playback_pcm_open(struct hda_pcm_stream *hinfo, 4742352f7f91STakashi Iwai struct hda_codec *codec, 4743352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4744352f7f91STakashi Iwai { 4745352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4746352f7f91STakashi Iwai return snd_hda_multi_out_dig_open(codec, &spec->multiout); 4747352f7f91STakashi Iwai } 4748352f7f91STakashi Iwai 4749352f7f91STakashi Iwai static int dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 4750352f7f91STakashi Iwai struct hda_codec *codec, 4751352f7f91STakashi Iwai unsigned int stream_tag, 4752352f7f91STakashi Iwai unsigned int format, 4753352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4754352f7f91STakashi Iwai { 4755352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4756352f7f91STakashi Iwai return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, 4757352f7f91STakashi Iwai stream_tag, format, substream); 4758352f7f91STakashi Iwai } 4759352f7f91STakashi Iwai 4760352f7f91STakashi Iwai static int dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 4761352f7f91STakashi Iwai struct hda_codec *codec, 4762352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4763352f7f91STakashi Iwai { 4764352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4765352f7f91STakashi Iwai return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); 4766352f7f91STakashi Iwai } 4767352f7f91STakashi Iwai 4768352f7f91STakashi Iwai static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo, 4769352f7f91STakashi Iwai struct hda_codec *codec, 4770352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4771352f7f91STakashi Iwai { 4772352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4773352f7f91STakashi Iwai return snd_hda_multi_out_dig_close(codec, &spec->multiout); 4774352f7f91STakashi Iwai } 4775352f7f91STakashi Iwai 4776352f7f91STakashi Iwai /* 4777352f7f91STakashi Iwai * Analog capture 4778352f7f91STakashi Iwai */ 4779ac2e8736STakashi Iwai #define alt_capture_pcm_open capture_pcm_open 4780ac2e8736STakashi Iwai #define alt_capture_pcm_close capture_pcm_close 4781ac2e8736STakashi Iwai 4782352f7f91STakashi Iwai static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 4783352f7f91STakashi Iwai struct hda_codec *codec, 4784352f7f91STakashi Iwai unsigned int stream_tag, 4785352f7f91STakashi Iwai unsigned int format, 4786352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4787352f7f91STakashi Iwai { 4788352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4789352f7f91STakashi Iwai 4790352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], 479197ec558aSTakashi Iwai stream_tag, 0, format); 4792ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 4793ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 479497ec558aSTakashi Iwai return 0; 479597ec558aSTakashi Iwai } 479697ec558aSTakashi Iwai 4797352f7f91STakashi Iwai static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 479897ec558aSTakashi Iwai struct hda_codec *codec, 479997ec558aSTakashi Iwai struct snd_pcm_substream *substream) 480097ec558aSTakashi Iwai { 4801352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 480297ec558aSTakashi Iwai 4803352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, 4804352f7f91STakashi Iwai spec->adc_nids[substream->number + 1]); 4805ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 4806ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 480797ec558aSTakashi Iwai return 0; 480897ec558aSTakashi Iwai } 480997ec558aSTakashi Iwai 4810352f7f91STakashi Iwai /* 4811352f7f91STakashi Iwai */ 4812352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_playback = { 4813352f7f91STakashi Iwai .substreams = 1, 4814352f7f91STakashi Iwai .channels_min = 2, 4815352f7f91STakashi Iwai .channels_max = 8, 4816352f7f91STakashi Iwai /* NID is set in build_pcms */ 4817352f7f91STakashi Iwai .ops = { 4818352f7f91STakashi Iwai .open = playback_pcm_open, 481938cf6f1aSTakashi Iwai .close = playback_pcm_close, 4820352f7f91STakashi Iwai .prepare = playback_pcm_prepare, 4821352f7f91STakashi Iwai .cleanup = playback_pcm_cleanup 4822352f7f91STakashi Iwai }, 4823352f7f91STakashi Iwai }; 4824352f7f91STakashi Iwai 4825352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_capture = { 4826352f7f91STakashi Iwai .substreams = 1, 4827352f7f91STakashi Iwai .channels_min = 2, 4828352f7f91STakashi Iwai .channels_max = 2, 4829352f7f91STakashi Iwai /* NID is set in build_pcms */ 4830ac2e8736STakashi Iwai .ops = { 4831ac2e8736STakashi Iwai .open = capture_pcm_open, 4832ac2e8736STakashi Iwai .close = capture_pcm_close, 4833ac2e8736STakashi Iwai .prepare = capture_pcm_prepare, 4834ac2e8736STakashi Iwai .cleanup = capture_pcm_cleanup 4835ac2e8736STakashi Iwai }, 4836352f7f91STakashi Iwai }; 4837352f7f91STakashi Iwai 4838352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_playback = { 4839352f7f91STakashi Iwai .substreams = 1, 4840352f7f91STakashi Iwai .channels_min = 2, 4841352f7f91STakashi Iwai .channels_max = 2, 4842352f7f91STakashi Iwai /* NID is set in build_pcms */ 484338cf6f1aSTakashi Iwai .ops = { 484438cf6f1aSTakashi Iwai .open = alt_playback_pcm_open, 4845e6b85f3cSTakashi Iwai .close = alt_playback_pcm_close, 4846e6b85f3cSTakashi Iwai .prepare = alt_playback_pcm_prepare, 4847e6b85f3cSTakashi Iwai .cleanup = alt_playback_pcm_cleanup 484838cf6f1aSTakashi Iwai }, 4849352f7f91STakashi Iwai }; 4850352f7f91STakashi Iwai 4851352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_capture = { 4852352f7f91STakashi Iwai .substreams = 2, /* can be overridden */ 4853352f7f91STakashi Iwai .channels_min = 2, 4854352f7f91STakashi Iwai .channels_max = 2, 4855352f7f91STakashi Iwai /* NID is set in build_pcms */ 4856352f7f91STakashi Iwai .ops = { 4857ac2e8736STakashi Iwai .open = alt_capture_pcm_open, 4858ac2e8736STakashi Iwai .close = alt_capture_pcm_close, 4859352f7f91STakashi Iwai .prepare = alt_capture_pcm_prepare, 4860352f7f91STakashi Iwai .cleanup = alt_capture_pcm_cleanup 4861352f7f91STakashi Iwai }, 4862352f7f91STakashi Iwai }; 4863352f7f91STakashi Iwai 4864352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_playback = { 4865352f7f91STakashi Iwai .substreams = 1, 4866352f7f91STakashi Iwai .channels_min = 2, 4867352f7f91STakashi Iwai .channels_max = 2, 4868352f7f91STakashi Iwai /* NID is set in build_pcms */ 4869352f7f91STakashi Iwai .ops = { 4870352f7f91STakashi Iwai .open = dig_playback_pcm_open, 4871352f7f91STakashi Iwai .close = dig_playback_pcm_close, 4872352f7f91STakashi Iwai .prepare = dig_playback_pcm_prepare, 4873352f7f91STakashi Iwai .cleanup = dig_playback_pcm_cleanup 4874352f7f91STakashi Iwai }, 4875352f7f91STakashi Iwai }; 4876352f7f91STakashi Iwai 4877352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_capture = { 4878352f7f91STakashi Iwai .substreams = 1, 4879352f7f91STakashi Iwai .channels_min = 2, 4880352f7f91STakashi Iwai .channels_max = 2, 4881352f7f91STakashi Iwai /* NID is set in build_pcms */ 4882352f7f91STakashi Iwai }; 4883352f7f91STakashi Iwai 4884352f7f91STakashi Iwai /* Used by build_pcms to flag that a PCM has no playback stream */ 4885352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_null_stream = { 4886352f7f91STakashi Iwai .substreams = 0, 4887352f7f91STakashi Iwai .channels_min = 0, 4888352f7f91STakashi Iwai .channels_max = 0, 4889352f7f91STakashi Iwai }; 4890352f7f91STakashi Iwai 4891352f7f91STakashi Iwai /* 4892352f7f91STakashi Iwai * dynamic changing ADC PCM streams 4893352f7f91STakashi Iwai */ 4894352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) 48951da177e4SLinus Torvalds { 4896352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4897352f7f91STakashi Iwai hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]]; 48981da177e4SLinus Torvalds 4899352f7f91STakashi Iwai if (spec->cur_adc && spec->cur_adc != new_adc) { 4900352f7f91STakashi Iwai /* stream is running, let's swap the current ADC */ 4901352f7f91STakashi Iwai __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); 4902352f7f91STakashi Iwai spec->cur_adc = new_adc; 4903352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, new_adc, 4904352f7f91STakashi Iwai spec->cur_adc_stream_tag, 0, 4905352f7f91STakashi Iwai spec->cur_adc_format); 4906352f7f91STakashi Iwai return true; 4907352f7f91STakashi Iwai } 4908352f7f91STakashi Iwai return false; 4909352f7f91STakashi Iwai } 4910352f7f91STakashi Iwai 4911352f7f91STakashi Iwai /* analog capture with dynamic dual-adc changes */ 4912352f7f91STakashi Iwai static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 4913352f7f91STakashi Iwai struct hda_codec *codec, 4914352f7f91STakashi Iwai unsigned int stream_tag, 4915352f7f91STakashi Iwai unsigned int format, 4916352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4917352f7f91STakashi Iwai { 4918352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4919352f7f91STakashi Iwai spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]]; 4920352f7f91STakashi Iwai spec->cur_adc_stream_tag = stream_tag; 4921352f7f91STakashi Iwai spec->cur_adc_format = format; 4922352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); 49231da177e4SLinus Torvalds return 0; 49241da177e4SLinus Torvalds } 49251da177e4SLinus Torvalds 4926352f7f91STakashi Iwai static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 4927352f7f91STakashi Iwai struct hda_codec *codec, 4928352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4929352f7f91STakashi Iwai { 4930352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4931352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, spec->cur_adc); 4932352f7f91STakashi Iwai spec->cur_adc = 0; 4933352f7f91STakashi Iwai return 0; 4934352f7f91STakashi Iwai } 4935352f7f91STakashi Iwai 4936352f7f91STakashi Iwai static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = { 4937352f7f91STakashi Iwai .substreams = 1, 4938352f7f91STakashi Iwai .channels_min = 2, 4939352f7f91STakashi Iwai .channels_max = 2, 4940352f7f91STakashi Iwai .nid = 0, /* fill later */ 4941352f7f91STakashi Iwai .ops = { 4942352f7f91STakashi Iwai .prepare = dyn_adc_capture_pcm_prepare, 4943352f7f91STakashi Iwai .cleanup = dyn_adc_capture_pcm_cleanup 4944352f7f91STakashi Iwai }, 4945352f7f91STakashi Iwai }; 4946352f7f91STakashi Iwai 4947f873e536STakashi Iwai static void fill_pcm_stream_name(char *str, size_t len, const char *sfx, 4948f873e536STakashi Iwai const char *chip_name) 4949f873e536STakashi Iwai { 4950f873e536STakashi Iwai char *p; 4951f873e536STakashi Iwai 4952f873e536STakashi Iwai if (*str) 4953f873e536STakashi Iwai return; 4954f873e536STakashi Iwai strlcpy(str, chip_name, len); 4955f873e536STakashi Iwai 4956f873e536STakashi Iwai /* drop non-alnum chars after a space */ 4957f873e536STakashi Iwai for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) { 4958f873e536STakashi Iwai if (!isalnum(p[1])) { 4959f873e536STakashi Iwai *p = 0; 4960f873e536STakashi Iwai break; 4961f873e536STakashi Iwai } 4962f873e536STakashi Iwai } 4963f873e536STakashi Iwai strlcat(str, sfx, len); 4964f873e536STakashi Iwai } 4965f873e536STakashi Iwai 4966352f7f91STakashi Iwai /* build PCM streams based on the parsed results */ 4967352f7f91STakashi Iwai int snd_hda_gen_build_pcms(struct hda_codec *codec) 4968352f7f91STakashi Iwai { 4969352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4970352f7f91STakashi Iwai struct hda_pcm *info = spec->pcm_rec; 4971352f7f91STakashi Iwai const struct hda_pcm_stream *p; 4972352f7f91STakashi Iwai bool have_multi_adcs; 4973352f7f91STakashi Iwai 49741da177e4SLinus Torvalds codec->num_pcms = 1; 49751da177e4SLinus Torvalds codec->pcm_info = info; 49761da177e4SLinus Torvalds 4977352f7f91STakashi Iwai if (spec->no_analog) 4978352f7f91STakashi Iwai goto skip_analog; 4979352f7f91STakashi Iwai 4980f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_analog, 4981f873e536STakashi Iwai sizeof(spec->stream_name_analog), 4982f873e536STakashi Iwai " Analog", codec->chip_name); 4983352f7f91STakashi Iwai info->name = spec->stream_name_analog; 4984352f7f91STakashi Iwai 4985352f7f91STakashi Iwai if (spec->multiout.num_dacs > 0) { 4986352f7f91STakashi Iwai p = spec->stream_analog_playback; 4987352f7f91STakashi Iwai if (!p) 4988352f7f91STakashi Iwai p = &pcm_analog_playback; 4989352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 4990352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; 4991352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 4992352f7f91STakashi Iwai spec->multiout.max_channels; 4993352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT && 4994352f7f91STakashi Iwai spec->autocfg.line_outs == 2) 4995352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap = 4996352f7f91STakashi Iwai snd_pcm_2_1_chmaps; 4997352f7f91STakashi Iwai } 4998352f7f91STakashi Iwai if (spec->num_adc_nids) { 4999352f7f91STakashi Iwai p = spec->stream_analog_capture; 5000352f7f91STakashi Iwai if (!p) { 5001352f7f91STakashi Iwai if (spec->dyn_adc_switch) 5002352f7f91STakashi Iwai p = &dyn_adc_pcm_analog_capture; 5003352f7f91STakashi Iwai else 5004352f7f91STakashi Iwai p = &pcm_analog_capture; 5005352f7f91STakashi Iwai } 5006352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 5007352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; 5008352f7f91STakashi Iwai } 5009352f7f91STakashi Iwai 5010352f7f91STakashi Iwai skip_analog: 5011352f7f91STakashi Iwai /* SPDIF for stream index #1 */ 5012352f7f91STakashi Iwai if (spec->multiout.dig_out_nid || spec->dig_in_nid) { 5013f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_digital, 5014352f7f91STakashi Iwai sizeof(spec->stream_name_digital), 5015f873e536STakashi Iwai " Digital", codec->chip_name); 5016352f7f91STakashi Iwai codec->num_pcms = 2; 5017352f7f91STakashi Iwai codec->slave_dig_outs = spec->multiout.slave_dig_outs; 5018352f7f91STakashi Iwai info = spec->pcm_rec + 1; 5019352f7f91STakashi Iwai info->name = spec->stream_name_digital; 5020352f7f91STakashi Iwai if (spec->dig_out_type) 5021352f7f91STakashi Iwai info->pcm_type = spec->dig_out_type; 5022352f7f91STakashi Iwai else 5023352f7f91STakashi Iwai info->pcm_type = HDA_PCM_TYPE_SPDIF; 5024352f7f91STakashi Iwai if (spec->multiout.dig_out_nid) { 5025352f7f91STakashi Iwai p = spec->stream_digital_playback; 5026352f7f91STakashi Iwai if (!p) 5027352f7f91STakashi Iwai p = &pcm_digital_playback; 5028352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 5029352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; 5030352f7f91STakashi Iwai } 5031352f7f91STakashi Iwai if (spec->dig_in_nid) { 5032352f7f91STakashi Iwai p = spec->stream_digital_capture; 5033352f7f91STakashi Iwai if (!p) 5034352f7f91STakashi Iwai p = &pcm_digital_capture; 5035352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 5036352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; 5037352f7f91STakashi Iwai } 5038352f7f91STakashi Iwai } 5039352f7f91STakashi Iwai 5040352f7f91STakashi Iwai if (spec->no_analog) 5041352f7f91STakashi Iwai return 0; 5042352f7f91STakashi Iwai 5043352f7f91STakashi Iwai /* If the use of more than one ADC is requested for the current 5044352f7f91STakashi Iwai * model, configure a second analog capture-only PCM. 5045352f7f91STakashi Iwai */ 5046352f7f91STakashi Iwai have_multi_adcs = (spec->num_adc_nids > 1) && 5047352f7f91STakashi Iwai !spec->dyn_adc_switch && !spec->auto_mic; 5048352f7f91STakashi Iwai /* Additional Analaog capture for index #2 */ 5049352f7f91STakashi Iwai if (spec->alt_dac_nid || have_multi_adcs) { 5050a607148fSTakashi Iwai fill_pcm_stream_name(spec->stream_name_alt_analog, 5051a607148fSTakashi Iwai sizeof(spec->stream_name_alt_analog), 5052a607148fSTakashi Iwai " Alt Analog", codec->chip_name); 5053352f7f91STakashi Iwai codec->num_pcms = 3; 5054352f7f91STakashi Iwai info = spec->pcm_rec + 2; 5055a607148fSTakashi Iwai info->name = spec->stream_name_alt_analog; 5056352f7f91STakashi Iwai if (spec->alt_dac_nid) { 5057352f7f91STakashi Iwai p = spec->stream_analog_alt_playback; 5058352f7f91STakashi Iwai if (!p) 5059352f7f91STakashi Iwai p = &pcm_analog_alt_playback; 5060352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 5061352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 5062352f7f91STakashi Iwai spec->alt_dac_nid; 5063352f7f91STakashi Iwai } else { 5064352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = 5065352f7f91STakashi Iwai pcm_null_stream; 5066352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; 5067352f7f91STakashi Iwai } 5068352f7f91STakashi Iwai if (have_multi_adcs) { 5069352f7f91STakashi Iwai p = spec->stream_analog_alt_capture; 5070352f7f91STakashi Iwai if (!p) 5071352f7f91STakashi Iwai p = &pcm_analog_alt_capture; 5072352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 5073352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 5074352f7f91STakashi Iwai spec->adc_nids[1]; 5075352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 5076352f7f91STakashi Iwai spec->num_adc_nids - 1; 5077352f7f91STakashi Iwai } else { 5078352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = 5079352f7f91STakashi Iwai pcm_null_stream; 5080352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0; 5081352f7f91STakashi Iwai } 50821da177e4SLinus Torvalds } 50831da177e4SLinus Torvalds 50841da177e4SLinus Torvalds return 0; 50851da177e4SLinus Torvalds } 5086352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_pcms); 5087352f7f91STakashi Iwai 5088352f7f91STakashi Iwai 5089352f7f91STakashi Iwai /* 5090352f7f91STakashi Iwai * Standard auto-parser initializations 5091352f7f91STakashi Iwai */ 5092352f7f91STakashi Iwai 5093d4156930STakashi Iwai /* configure the given path as a proper output */ 50942c12c30dSTakashi Iwai static void set_output_and_unmute(struct hda_codec *codec, int path_idx) 5095352f7f91STakashi Iwai { 5096352f7f91STakashi Iwai struct nid_path *path; 5097d4156930STakashi Iwai hda_nid_t pin; 5098352f7f91STakashi Iwai 5099196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 5100d4156930STakashi Iwai if (!path || !path->depth) 5101352f7f91STakashi Iwai return; 5102d4156930STakashi Iwai pin = path->path[path->depth - 1]; 51032c12c30dSTakashi Iwai restore_pin_ctl(codec, pin); 510465033cc8STakashi Iwai snd_hda_activate_path(codec, path, path->active, 510565033cc8STakashi Iwai aamix_default(codec->spec)); 5106e1284af7STakashi Iwai set_pin_eapd(codec, pin, path->active); 5107352f7f91STakashi Iwai } 5108352f7f91STakashi Iwai 5109352f7f91STakashi Iwai /* initialize primary output paths */ 5110352f7f91STakashi Iwai static void init_multi_out(struct hda_codec *codec) 5111352f7f91STakashi Iwai { 5112352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5113352f7f91STakashi Iwai int i; 5114352f7f91STakashi Iwai 5115d4156930STakashi Iwai for (i = 0; i < spec->autocfg.line_outs; i++) 51162c12c30dSTakashi Iwai set_output_and_unmute(codec, spec->out_paths[i]); 5117352f7f91STakashi Iwai } 5118352f7f91STakashi Iwai 5119db23fd19STakashi Iwai 51202c12c30dSTakashi Iwai static void __init_extra_out(struct hda_codec *codec, int num_outs, int *paths) 5121352f7f91STakashi Iwai { 5122352f7f91STakashi Iwai int i; 5123352f7f91STakashi Iwai 5124d4156930STakashi Iwai for (i = 0; i < num_outs; i++) 51252c12c30dSTakashi Iwai set_output_and_unmute(codec, paths[i]); 5126352f7f91STakashi Iwai } 5127db23fd19STakashi Iwai 5128db23fd19STakashi Iwai /* initialize hp and speaker paths */ 5129db23fd19STakashi Iwai static void init_extra_out(struct hda_codec *codec) 5130db23fd19STakashi Iwai { 5131db23fd19STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5132db23fd19STakashi Iwai 5133db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) 51342c12c30dSTakashi Iwai __init_extra_out(codec, spec->autocfg.hp_outs, spec->hp_paths); 5135db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) 5136db23fd19STakashi Iwai __init_extra_out(codec, spec->autocfg.speaker_outs, 51372c12c30dSTakashi Iwai spec->speaker_paths); 5138352f7f91STakashi Iwai } 5139352f7f91STakashi Iwai 5140352f7f91STakashi Iwai /* initialize multi-io paths */ 5141352f7f91STakashi Iwai static void init_multi_io(struct hda_codec *codec) 5142352f7f91STakashi Iwai { 5143352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5144352f7f91STakashi Iwai int i; 5145352f7f91STakashi Iwai 5146352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++) { 5147352f7f91STakashi Iwai hda_nid_t pin = spec->multi_io[i].pin; 5148352f7f91STakashi Iwai struct nid_path *path; 5149196c1766STakashi Iwai path = get_multiio_path(codec, i); 5150352f7f91STakashi Iwai if (!path) 5151352f7f91STakashi Iwai continue; 5152352f7f91STakashi Iwai if (!spec->multi_io[i].ctl_in) 5153352f7f91STakashi Iwai spec->multi_io[i].ctl_in = 51542c12c30dSTakashi Iwai snd_hda_codec_get_pin_target(codec, pin); 515565033cc8STakashi Iwai snd_hda_activate_path(codec, path, path->active, 515665033cc8STakashi Iwai aamix_default(spec)); 5157352f7f91STakashi Iwai } 5158352f7f91STakashi Iwai } 5159352f7f91STakashi Iwai 51604f7f67fbSTakashi Iwai static void init_aamix_paths(struct hda_codec *codec) 51614f7f67fbSTakashi Iwai { 51624f7f67fbSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 51634f7f67fbSTakashi Iwai 51644f7f67fbSTakashi Iwai if (!spec->have_aamix_ctl) 51654f7f67fbSTakashi Iwai return; 51664f7f67fbSTakashi Iwai update_aamix_paths(codec, spec->aamix_mode, spec->out_paths[0], 51674f7f67fbSTakashi Iwai spec->aamix_out_paths[0], 51684f7f67fbSTakashi Iwai spec->autocfg.line_out_type); 51694f7f67fbSTakashi Iwai update_aamix_paths(codec, spec->aamix_mode, spec->hp_paths[0], 51704f7f67fbSTakashi Iwai spec->aamix_out_paths[1], 51714f7f67fbSTakashi Iwai AUTO_PIN_HP_OUT); 51724f7f67fbSTakashi Iwai update_aamix_paths(codec, spec->aamix_mode, spec->speaker_paths[0], 51734f7f67fbSTakashi Iwai spec->aamix_out_paths[2], 51744f7f67fbSTakashi Iwai AUTO_PIN_SPEAKER_OUT); 51754f7f67fbSTakashi Iwai } 51764f7f67fbSTakashi Iwai 5177352f7f91STakashi Iwai /* set up input pins and loopback paths */ 5178352f7f91STakashi Iwai static void init_analog_input(struct hda_codec *codec) 5179352f7f91STakashi Iwai { 5180352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5181352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 5182352f7f91STakashi Iwai int i; 5183352f7f91STakashi Iwai 5184352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 5185352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 5186352f7f91STakashi Iwai if (is_input_pin(codec, nid)) 51872c12c30dSTakashi Iwai restore_pin_ctl(codec, nid); 5188352f7f91STakashi Iwai 5189352f7f91STakashi Iwai /* init loopback inputs */ 5190352f7f91STakashi Iwai if (spec->mixer_nid) { 51913e367f15STakashi Iwai resume_path_from_idx(codec, spec->loopback_paths[i]); 51923e367f15STakashi Iwai resume_path_from_idx(codec, spec->loopback_merge_path); 5193352f7f91STakashi Iwai } 5194352f7f91STakashi Iwai } 5195352f7f91STakashi Iwai } 5196352f7f91STakashi Iwai 5197352f7f91STakashi Iwai /* initialize ADC paths */ 5198352f7f91STakashi Iwai static void init_input_src(struct hda_codec *codec) 5199352f7f91STakashi Iwai { 5200352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5201352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 5202352f7f91STakashi Iwai struct nid_path *path; 5203352f7f91STakashi Iwai int i, c, nums; 5204352f7f91STakashi Iwai 5205352f7f91STakashi Iwai if (spec->dyn_adc_switch) 5206352f7f91STakashi Iwai nums = 1; 5207352f7f91STakashi Iwai else 5208352f7f91STakashi Iwai nums = spec->num_adc_nids; 5209352f7f91STakashi Iwai 5210352f7f91STakashi Iwai for (c = 0; c < nums; c++) { 5211352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 5212c697b716STakashi Iwai path = get_input_path(codec, c, i); 5213352f7f91STakashi Iwai if (path) { 5214352f7f91STakashi Iwai bool active = path->active; 5215352f7f91STakashi Iwai if (i == spec->cur_mux[c]) 5216352f7f91STakashi Iwai active = true; 5217352f7f91STakashi Iwai snd_hda_activate_path(codec, path, active, false); 5218352f7f91STakashi Iwai } 5219352f7f91STakashi Iwai } 5220967303daSTakashi Iwai if (spec->hp_mic) 5221967303daSTakashi Iwai update_hp_mic(codec, c, true); 5222352f7f91STakashi Iwai } 5223352f7f91STakashi Iwai 5224352f7f91STakashi Iwai if (spec->cap_sync_hook) 5225a90229e0STakashi Iwai spec->cap_sync_hook(codec, NULL); 5226352f7f91STakashi Iwai } 5227352f7f91STakashi Iwai 5228352f7f91STakashi Iwai /* set right pin controls for digital I/O */ 5229352f7f91STakashi Iwai static void init_digital(struct hda_codec *codec) 5230352f7f91STakashi Iwai { 5231352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5232352f7f91STakashi Iwai int i; 5233352f7f91STakashi Iwai hda_nid_t pin; 5234352f7f91STakashi Iwai 5235d4156930STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) 52362c12c30dSTakashi Iwai set_output_and_unmute(codec, spec->digout_paths[i]); 5237352f7f91STakashi Iwai pin = spec->autocfg.dig_in_pin; 52382430d7b7STakashi Iwai if (pin) { 52392c12c30dSTakashi Iwai restore_pin_ctl(codec, pin); 52403e367f15STakashi Iwai resume_path_from_idx(codec, spec->digin_path); 52412430d7b7STakashi Iwai } 5242352f7f91STakashi Iwai } 5243352f7f91STakashi Iwai 5244973e4972STakashi Iwai /* clear unsol-event tags on unused pins; Conexant codecs seem to leave 5245973e4972STakashi Iwai * invalid unsol tags by some reason 5246973e4972STakashi Iwai */ 5247973e4972STakashi Iwai static void clear_unsol_on_unused_pins(struct hda_codec *codec) 5248973e4972STakashi Iwai { 5249973e4972STakashi Iwai int i; 5250973e4972STakashi Iwai 5251973e4972STakashi Iwai for (i = 0; i < codec->init_pins.used; i++) { 5252973e4972STakashi Iwai struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); 5253973e4972STakashi Iwai hda_nid_t nid = pin->nid; 5254973e4972STakashi Iwai if (is_jack_detectable(codec, nid) && 5255973e4972STakashi Iwai !snd_hda_jack_tbl_get(codec, nid)) 5256973e4972STakashi Iwai snd_hda_codec_update_cache(codec, nid, 0, 5257973e4972STakashi Iwai AC_VERB_SET_UNSOLICITED_ENABLE, 0); 5258973e4972STakashi Iwai } 5259973e4972STakashi Iwai } 5260973e4972STakashi Iwai 52615187ac16STakashi Iwai /* 52625187ac16STakashi Iwai * initialize the generic spec; 52635187ac16STakashi Iwai * this can be put as patch_ops.init function 52645187ac16STakashi Iwai */ 5265352f7f91STakashi Iwai int snd_hda_gen_init(struct hda_codec *codec) 5266352f7f91STakashi Iwai { 5267352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 5268352f7f91STakashi Iwai 5269352f7f91STakashi Iwai if (spec->init_hook) 5270352f7f91STakashi Iwai spec->init_hook(codec); 5271352f7f91STakashi Iwai 5272352f7f91STakashi Iwai snd_hda_apply_verbs(codec); 5273352f7f91STakashi Iwai 52743bbcd274STakashi Iwai codec->cached_write = 1; 52753bbcd274STakashi Iwai 5276352f7f91STakashi Iwai init_multi_out(codec); 5277352f7f91STakashi Iwai init_extra_out(codec); 5278352f7f91STakashi Iwai init_multi_io(codec); 52794f7f67fbSTakashi Iwai init_aamix_paths(codec); 5280352f7f91STakashi Iwai init_analog_input(codec); 5281352f7f91STakashi Iwai init_input_src(codec); 5282352f7f91STakashi Iwai init_digital(codec); 5283352f7f91STakashi Iwai 5284973e4972STakashi Iwai clear_unsol_on_unused_pins(codec); 5285973e4972STakashi Iwai 5286352f7f91STakashi Iwai /* call init functions of standard auto-mute helpers */ 5287a5cc2509STakashi Iwai update_automute_all(codec); 5288352f7f91STakashi Iwai 5289dc870f38STakashi Iwai snd_hda_codec_flush_cache(codec); 52903bbcd274STakashi Iwai 5291352f7f91STakashi Iwai if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook) 5292352f7f91STakashi Iwai snd_hda_sync_vmaster_hook(&spec->vmaster_mute); 5293352f7f91STakashi Iwai 5294352f7f91STakashi Iwai hda_call_check_power_status(codec, 0x01); 5295352f7f91STakashi Iwai return 0; 5296352f7f91STakashi Iwai } 5297fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_init); 5298fce52a3bSTakashi Iwai 52995187ac16STakashi Iwai /* 53005187ac16STakashi Iwai * free the generic spec; 53015187ac16STakashi Iwai * this can be put as patch_ops.free function 53025187ac16STakashi Iwai */ 5303fce52a3bSTakashi Iwai void snd_hda_gen_free(struct hda_codec *codec) 5304fce52a3bSTakashi Iwai { 53057504b6cdSTakashi Iwai snd_hda_detach_beep_device(codec); 5306fce52a3bSTakashi Iwai snd_hda_gen_spec_free(codec->spec); 5307fce52a3bSTakashi Iwai kfree(codec->spec); 5308fce52a3bSTakashi Iwai codec->spec = NULL; 5309fce52a3bSTakashi Iwai } 5310fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_free); 5311fce52a3bSTakashi Iwai 5312fce52a3bSTakashi Iwai #ifdef CONFIG_PM 53135187ac16STakashi Iwai /* 53145187ac16STakashi Iwai * check the loopback power save state; 53155187ac16STakashi Iwai * this can be put as patch_ops.check_power_status function 53165187ac16STakashi Iwai */ 5317fce52a3bSTakashi Iwai int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid) 5318fce52a3bSTakashi Iwai { 5319fce52a3bSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 5320fce52a3bSTakashi Iwai return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); 5321fce52a3bSTakashi Iwai } 5322fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_check_power_status); 5323fce52a3bSTakashi Iwai #endif 5324352f7f91STakashi Iwai 5325352f7f91STakashi Iwai 5326352f7f91STakashi Iwai /* 5327352f7f91STakashi Iwai * the generic codec support 5328352f7f91STakashi Iwai */ 53291da177e4SLinus Torvalds 5330352f7f91STakashi Iwai static const struct hda_codec_ops generic_patch_ops = { 5331352f7f91STakashi Iwai .build_controls = snd_hda_gen_build_controls, 5332352f7f91STakashi Iwai .build_pcms = snd_hda_gen_build_pcms, 5333352f7f91STakashi Iwai .init = snd_hda_gen_init, 5334fce52a3bSTakashi Iwai .free = snd_hda_gen_free, 5335352f7f91STakashi Iwai .unsol_event = snd_hda_jack_unsol_event, 533683012a7cSTakashi Iwai #ifdef CONFIG_PM 5337fce52a3bSTakashi Iwai .check_power_status = snd_hda_gen_check_power_status, 5338cb53c626STakashi Iwai #endif 53391da177e4SLinus Torvalds }; 53401da177e4SLinus Torvalds 53411da177e4SLinus Torvalds int snd_hda_parse_generic_codec(struct hda_codec *codec) 53421da177e4SLinus Torvalds { 5343352f7f91STakashi Iwai struct hda_gen_spec *spec; 53441da177e4SLinus Torvalds int err; 53451da177e4SLinus Torvalds 5346e560d8d8STakashi Iwai spec = kzalloc(sizeof(*spec), GFP_KERNEL); 5347352f7f91STakashi Iwai if (!spec) 53481da177e4SLinus Torvalds return -ENOMEM; 5349352f7f91STakashi Iwai snd_hda_gen_spec_init(spec); 53501da177e4SLinus Torvalds codec->spec = spec; 53511da177e4SLinus Torvalds 53529eb413e5STakashi Iwai err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0); 53539eb413e5STakashi Iwai if (err < 0) 53549eb413e5STakashi Iwai return err; 53559eb413e5STakashi Iwai 53569eb413e5STakashi Iwai err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg); 5357352f7f91STakashi Iwai if (err < 0) 53581da177e4SLinus Torvalds goto error; 53591da177e4SLinus Torvalds 53601da177e4SLinus Torvalds codec->patch_ops = generic_patch_ops; 53611da177e4SLinus Torvalds return 0; 53621da177e4SLinus Torvalds 53631da177e4SLinus Torvalds error: 5364fce52a3bSTakashi Iwai snd_hda_gen_free(codec); 53651da177e4SLinus Torvalds return err; 53661da177e4SLinus Torvalds } 5367fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_parse_generic_codec); 5368b21bdd0dSTakashi Iwai 5369b21bdd0dSTakashi Iwai MODULE_LICENSE("GPL"); 5370b21bdd0dSTakashi Iwai MODULE_DESCRIPTION("Generic HD-audio codec parser"); 5371