11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Universal Interface for Intel High Definition Audio Codec 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Generic widget tree parser 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * This driver is free software; you can redistribute it and/or modify 91da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 101da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 111da177e4SLinus Torvalds * (at your option) any later version. 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * This driver is distributed in the hope that it will be useful, 141da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 151da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 161da177e4SLinus Torvalds * GNU General Public License for more details. 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 191da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 201da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 211da177e4SLinus Torvalds */ 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds #include <linux/init.h> 241da177e4SLinus Torvalds #include <linux/slab.h> 25d81a6d71SPaul Gortmaker #include <linux/export.h> 26352f7f91STakashi Iwai #include <linux/sort.h> 27f873e536STakashi Iwai #include <linux/ctype.h> 28f873e536STakashi Iwai #include <linux/string.h> 2929476558STakashi Iwai #include <linux/bitops.h> 301da177e4SLinus Torvalds #include <sound/core.h> 31352f7f91STakashi Iwai #include <sound/jack.h> 321da177e4SLinus Torvalds #include "hda_codec.h" 331da177e4SLinus Torvalds #include "hda_local.h" 34352f7f91STakashi Iwai #include "hda_auto_parser.h" 35352f7f91STakashi Iwai #include "hda_jack.h" 36352f7f91STakashi Iwai #include "hda_generic.h" 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds 39352f7f91STakashi Iwai /* initialize hda_gen_spec struct */ 40352f7f91STakashi Iwai int snd_hda_gen_spec_init(struct hda_gen_spec *spec) 411da177e4SLinus Torvalds { 42352f7f91STakashi Iwai snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); 43352f7f91STakashi Iwai snd_array_init(&spec->paths, sizeof(struct nid_path), 8); 4438cf6f1aSTakashi Iwai mutex_init(&spec->pcm_mutex); 45352f7f91STakashi Iwai return 0; 46352f7f91STakashi Iwai } 47352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_spec_init); 481da177e4SLinus Torvalds 4912c93df6STakashi Iwai struct snd_kcontrol_new * 5012c93df6STakashi Iwai snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name, 51352f7f91STakashi Iwai const struct snd_kcontrol_new *temp) 52352f7f91STakashi Iwai { 53352f7f91STakashi Iwai struct snd_kcontrol_new *knew = snd_array_new(&spec->kctls); 54352f7f91STakashi Iwai if (!knew) 55352f7f91STakashi Iwai return NULL; 56352f7f91STakashi Iwai *knew = *temp; 57352f7f91STakashi Iwai if (name) 58352f7f91STakashi Iwai knew->name = kstrdup(name, GFP_KERNEL); 59352f7f91STakashi Iwai else if (knew->name) 60352f7f91STakashi Iwai knew->name = kstrdup(knew->name, GFP_KERNEL); 61352f7f91STakashi Iwai if (!knew->name) 62352f7f91STakashi Iwai return NULL; 63352f7f91STakashi Iwai return knew; 64352f7f91STakashi Iwai } 6512c93df6STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_add_kctl); 66352f7f91STakashi Iwai 67352f7f91STakashi Iwai static void free_kctls(struct hda_gen_spec *spec) 68352f7f91STakashi Iwai { 69352f7f91STakashi Iwai if (spec->kctls.list) { 70352f7f91STakashi Iwai struct snd_kcontrol_new *kctl = spec->kctls.list; 71352f7f91STakashi Iwai int i; 72352f7f91STakashi Iwai for (i = 0; i < spec->kctls.used; i++) 73352f7f91STakashi Iwai kfree(kctl[i].name); 74352f7f91STakashi Iwai } 75352f7f91STakashi Iwai snd_array_free(&spec->kctls); 76352f7f91STakashi Iwai } 77352f7f91STakashi Iwai 78352f7f91STakashi Iwai void snd_hda_gen_spec_free(struct hda_gen_spec *spec) 79352f7f91STakashi Iwai { 801da177e4SLinus Torvalds if (!spec) 811da177e4SLinus Torvalds return; 82352f7f91STakashi Iwai free_kctls(spec); 83352f7f91STakashi Iwai snd_array_free(&spec->paths); 841da177e4SLinus Torvalds } 85352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_spec_free); 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds /* 881c70a583STakashi Iwai * store user hints 891c70a583STakashi Iwai */ 901c70a583STakashi Iwai static void parse_user_hints(struct hda_codec *codec) 911c70a583STakashi Iwai { 921c70a583STakashi Iwai struct hda_gen_spec *spec = codec->spec; 931c70a583STakashi Iwai int val; 941c70a583STakashi Iwai 951c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "jack_detect"); 961c70a583STakashi Iwai if (val >= 0) 971c70a583STakashi Iwai codec->no_jack_detect = !val; 981c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "inv_jack_detect"); 991c70a583STakashi Iwai if (val >= 0) 1001c70a583STakashi Iwai codec->inv_jack_detect = !!val; 1011c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "trigger_sense"); 1021c70a583STakashi Iwai if (val >= 0) 1031c70a583STakashi Iwai codec->no_trigger_sense = !val; 1041c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "inv_eapd"); 1051c70a583STakashi Iwai if (val >= 0) 1061c70a583STakashi Iwai codec->inv_eapd = !!val; 1071c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "pcm_format_first"); 1081c70a583STakashi Iwai if (val >= 0) 1091c70a583STakashi Iwai codec->pcm_format_first = !!val; 1101c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "sticky_stream"); 1111c70a583STakashi Iwai if (val >= 0) 1121c70a583STakashi Iwai codec->no_sticky_stream = !val; 1131c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "spdif_status_reset"); 1141c70a583STakashi Iwai if (val >= 0) 1151c70a583STakashi Iwai codec->spdif_status_reset = !!val; 1161c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "pin_amp_workaround"); 1171c70a583STakashi Iwai if (val >= 0) 1181c70a583STakashi Iwai codec->pin_amp_workaround = !!val; 1191c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "single_adc_amp"); 1201c70a583STakashi Iwai if (val >= 0) 1211c70a583STakashi Iwai codec->single_adc_amp = !!val; 1221c70a583STakashi Iwai 123f72706beSTakashi Iwai val = snd_hda_get_bool_hint(codec, "auto_mute"); 124f72706beSTakashi Iwai if (val >= 0) 125f72706beSTakashi Iwai spec->suppress_auto_mute = !val; 1261c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "auto_mic"); 1271c70a583STakashi Iwai if (val >= 0) 1281c70a583STakashi Iwai spec->suppress_auto_mic = !val; 1291c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "line_in_auto_switch"); 1301c70a583STakashi Iwai if (val >= 0) 1311c70a583STakashi Iwai spec->line_in_auto_switch = !!val; 1321c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "need_dac_fix"); 1331c70a583STakashi Iwai if (val >= 0) 1341c70a583STakashi Iwai spec->need_dac_fix = !!val; 1351c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "primary_hp"); 1361c70a583STakashi Iwai if (val >= 0) 1371c70a583STakashi Iwai spec->no_primary_hp = !val; 1381c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "multi_cap_vol"); 1391c70a583STakashi Iwai if (val >= 0) 1401c70a583STakashi Iwai spec->multi_cap_vol = !!val; 1411c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "inv_dmic_split"); 1421c70a583STakashi Iwai if (val >= 0) 1431c70a583STakashi Iwai spec->inv_dmic_split = !!val; 1441c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "indep_hp"); 1451c70a583STakashi Iwai if (val >= 0) 1461c70a583STakashi Iwai spec->indep_hp = !!val; 1471c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "add_stereo_mix_input"); 1481c70a583STakashi Iwai if (val >= 0) 1491c70a583STakashi Iwai spec->add_stereo_mix_input = !!val; 1501c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "add_out_jack_modes"); 1511c70a583STakashi Iwai if (val >= 0) 1521c70a583STakashi Iwai spec->add_out_jack_modes = !!val; 15329476558STakashi Iwai val = snd_hda_get_bool_hint(codec, "add_in_jack_modes"); 15429476558STakashi Iwai if (val >= 0) 15529476558STakashi Iwai spec->add_in_jack_modes = !!val; 1561c70a583STakashi Iwai 1571c70a583STakashi Iwai if (!snd_hda_get_int_hint(codec, "mixer_nid", &val)) 1581c70a583STakashi Iwai spec->mixer_nid = val; 1591c70a583STakashi Iwai } 1601c70a583STakashi Iwai 1611c70a583STakashi Iwai /* 1622c12c30dSTakashi Iwai * pin control value accesses 1632c12c30dSTakashi Iwai */ 1642c12c30dSTakashi Iwai 1652c12c30dSTakashi Iwai #define update_pin_ctl(codec, pin, val) \ 1662c12c30dSTakashi Iwai snd_hda_codec_update_cache(codec, pin, 0, \ 1672c12c30dSTakashi Iwai AC_VERB_SET_PIN_WIDGET_CONTROL, val) 1682c12c30dSTakashi Iwai 1692c12c30dSTakashi Iwai /* restore the pinctl based on the cached value */ 1702c12c30dSTakashi Iwai static inline void restore_pin_ctl(struct hda_codec *codec, hda_nid_t pin) 1712c12c30dSTakashi Iwai { 1722c12c30dSTakashi Iwai update_pin_ctl(codec, pin, snd_hda_codec_get_pin_target(codec, pin)); 1732c12c30dSTakashi Iwai } 1742c12c30dSTakashi Iwai 1752c12c30dSTakashi Iwai /* set the pinctl target value and write it if requested */ 1762c12c30dSTakashi Iwai static void set_pin_target(struct hda_codec *codec, hda_nid_t pin, 1772c12c30dSTakashi Iwai unsigned int val, bool do_write) 1782c12c30dSTakashi Iwai { 1792c12c30dSTakashi Iwai if (!pin) 1802c12c30dSTakashi Iwai return; 1812c12c30dSTakashi Iwai val = snd_hda_correct_pin_ctl(codec, pin, val); 1822c12c30dSTakashi Iwai snd_hda_codec_set_pin_target(codec, pin, val); 1832c12c30dSTakashi Iwai if (do_write) 1842c12c30dSTakashi Iwai update_pin_ctl(codec, pin, val); 1852c12c30dSTakashi Iwai } 1862c12c30dSTakashi Iwai 1872c12c30dSTakashi Iwai /* set pinctl target values for all given pins */ 1882c12c30dSTakashi Iwai static void set_pin_targets(struct hda_codec *codec, int num_pins, 1892c12c30dSTakashi Iwai hda_nid_t *pins, unsigned int val) 1902c12c30dSTakashi Iwai { 1912c12c30dSTakashi Iwai int i; 1922c12c30dSTakashi Iwai for (i = 0; i < num_pins; i++) 1932c12c30dSTakashi Iwai set_pin_target(codec, pins[i], val, false); 1942c12c30dSTakashi Iwai } 1952c12c30dSTakashi Iwai 1962c12c30dSTakashi Iwai /* 197352f7f91STakashi Iwai * parsing paths 1981da177e4SLinus Torvalds */ 1991da177e4SLinus Torvalds 2003ca529d3STakashi Iwai /* return the position of NID in the list, or -1 if not found */ 2013ca529d3STakashi Iwai static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) 2023ca529d3STakashi Iwai { 2033ca529d3STakashi Iwai int i; 2043ca529d3STakashi Iwai for (i = 0; i < nums; i++) 2053ca529d3STakashi Iwai if (list[i] == nid) 2063ca529d3STakashi Iwai return i; 2073ca529d3STakashi Iwai return -1; 2083ca529d3STakashi Iwai } 2093ca529d3STakashi Iwai 2103ca529d3STakashi Iwai /* return true if the given NID is contained in the path */ 2113ca529d3STakashi Iwai static bool is_nid_contained(struct nid_path *path, hda_nid_t nid) 2123ca529d3STakashi Iwai { 2133ca529d3STakashi Iwai return find_idx_in_nid_list(nid, path->path, path->depth) >= 0; 2143ca529d3STakashi Iwai } 2153ca529d3STakashi Iwai 216f5172a7eSTakashi Iwai static struct nid_path *get_nid_path(struct hda_codec *codec, 217f5172a7eSTakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid, 2183ca529d3STakashi Iwai int anchor_nid) 2191da177e4SLinus Torvalds { 220352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 221352f7f91STakashi Iwai int i; 2221da177e4SLinus Torvalds 223352f7f91STakashi Iwai for (i = 0; i < spec->paths.used; i++) { 224352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, i); 225352f7f91STakashi Iwai if (path->depth <= 0) 226352f7f91STakashi Iwai continue; 227352f7f91STakashi Iwai if ((!from_nid || path->path[0] == from_nid) && 228f5172a7eSTakashi Iwai (!to_nid || path->path[path->depth - 1] == to_nid)) { 2293ca529d3STakashi Iwai if (!anchor_nid || 2303ca529d3STakashi Iwai (anchor_nid > 0 && is_nid_contained(path, anchor_nid)) || 2313ca529d3STakashi Iwai (anchor_nid < 0 && !is_nid_contained(path, anchor_nid))) 232352f7f91STakashi Iwai return path; 2331da177e4SLinus Torvalds } 234f5172a7eSTakashi Iwai } 2351da177e4SLinus Torvalds return NULL; 2361da177e4SLinus Torvalds } 237f5172a7eSTakashi Iwai 238f5172a7eSTakashi Iwai /* get the path between the given NIDs; 239f5172a7eSTakashi Iwai * passing 0 to either @pin or @dac behaves as a wildcard 240f5172a7eSTakashi Iwai */ 241f5172a7eSTakashi Iwai struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec, 242f5172a7eSTakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid) 243f5172a7eSTakashi Iwai { 2443ca529d3STakashi Iwai return get_nid_path(codec, from_nid, to_nid, 0); 245f5172a7eSTakashi Iwai } 246352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_nid_path); 2471da177e4SLinus Torvalds 248196c1766STakashi Iwai /* get the index number corresponding to the path instance; 249196c1766STakashi Iwai * the index starts from 1, for easier checking the invalid value 250196c1766STakashi Iwai */ 251196c1766STakashi Iwai int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path) 252196c1766STakashi Iwai { 253196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 254196c1766STakashi Iwai struct nid_path *array = spec->paths.list; 255196c1766STakashi Iwai ssize_t idx; 256196c1766STakashi Iwai 257196c1766STakashi Iwai if (!spec->paths.used) 258196c1766STakashi Iwai return 0; 259196c1766STakashi Iwai idx = path - array; 260196c1766STakashi Iwai if (idx < 0 || idx >= spec->paths.used) 261196c1766STakashi Iwai return 0; 262196c1766STakashi Iwai return idx + 1; 263196c1766STakashi Iwai } 264196c1766STakashi Iwai 265196c1766STakashi Iwai /* get the path instance corresponding to the given index number */ 266196c1766STakashi Iwai struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx) 267196c1766STakashi Iwai { 268196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 269196c1766STakashi Iwai 270196c1766STakashi Iwai if (idx <= 0 || idx > spec->paths.used) 271196c1766STakashi Iwai return NULL; 272196c1766STakashi Iwai return snd_array_elem(&spec->paths, idx - 1); 273196c1766STakashi Iwai } 274196c1766STakashi Iwai 275352f7f91STakashi Iwai /* check whether the given DAC is already found in any existing paths */ 276352f7f91STakashi Iwai static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid) 2771da177e4SLinus Torvalds { 278352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 279352f7f91STakashi Iwai int i; 280352f7f91STakashi Iwai 281352f7f91STakashi Iwai for (i = 0; i < spec->paths.used; i++) { 282352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, i); 283352f7f91STakashi Iwai if (path->path[0] == nid) 284352f7f91STakashi Iwai return true; 285352f7f91STakashi Iwai } 286352f7f91STakashi Iwai return false; 2871da177e4SLinus Torvalds } 2881da177e4SLinus Torvalds 289352f7f91STakashi Iwai /* check whether the given two widgets can be connected */ 290352f7f91STakashi Iwai static bool is_reachable_path(struct hda_codec *codec, 291352f7f91STakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid) 2921da177e4SLinus Torvalds { 293352f7f91STakashi Iwai if (!from_nid || !to_nid) 294352f7f91STakashi Iwai return false; 295352f7f91STakashi Iwai return snd_hda_get_conn_index(codec, to_nid, from_nid, true) >= 0; 2961da177e4SLinus Torvalds } 2971da177e4SLinus Torvalds 298352f7f91STakashi Iwai /* nid, dir and idx */ 299352f7f91STakashi Iwai #define AMP_VAL_COMPARE_MASK (0xffff | (1U << 18) | (0x0f << 19)) 300352f7f91STakashi Iwai 301352f7f91STakashi Iwai /* check whether the given ctl is already assigned in any path elements */ 302352f7f91STakashi Iwai static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type) 3031da177e4SLinus Torvalds { 304352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 305352f7f91STakashi Iwai int i; 306352f7f91STakashi Iwai 307352f7f91STakashi Iwai val &= AMP_VAL_COMPARE_MASK; 308352f7f91STakashi Iwai for (i = 0; i < spec->paths.used; i++) { 309352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, i); 310352f7f91STakashi Iwai if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val) 311352f7f91STakashi Iwai return true; 312352f7f91STakashi Iwai } 313352f7f91STakashi Iwai return false; 3141da177e4SLinus Torvalds } 3151da177e4SLinus Torvalds 316352f7f91STakashi Iwai /* check whether a control with the given (nid, dir, idx) was assigned */ 317352f7f91STakashi Iwai static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid, 3188999bf0aSTakashi Iwai int dir, int idx, int type) 319cb53c626STakashi Iwai { 320352f7f91STakashi Iwai unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir); 3218999bf0aSTakashi Iwai return is_ctl_used(codec, val, type); 322cb53c626STakashi Iwai } 323352f7f91STakashi Iwai 3240c8c0f56STakashi Iwai static void print_nid_path(const char *pfx, struct nid_path *path) 3250c8c0f56STakashi Iwai { 3260c8c0f56STakashi Iwai char buf[40]; 3270c8c0f56STakashi Iwai int i; 3280c8c0f56STakashi Iwai 3290c8c0f56STakashi Iwai 3300c8c0f56STakashi Iwai buf[0] = 0; 3310c8c0f56STakashi Iwai for (i = 0; i < path->depth; i++) { 3320c8c0f56STakashi Iwai char tmp[4]; 3330c8c0f56STakashi Iwai sprintf(tmp, ":%02x", path->path[i]); 3340c8c0f56STakashi Iwai strlcat(buf, tmp, sizeof(buf)); 3350c8c0f56STakashi Iwai } 3360c8c0f56STakashi Iwai snd_printdd("%s path: depth=%d %s\n", pfx, path->depth, buf); 3370c8c0f56STakashi Iwai } 3380c8c0f56STakashi Iwai 339352f7f91STakashi Iwai /* called recursively */ 340352f7f91STakashi Iwai static bool __parse_nid_path(struct hda_codec *codec, 341352f7f91STakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid, 3423ca529d3STakashi Iwai int anchor_nid, struct nid_path *path, 3433ca529d3STakashi Iwai int depth) 344352f7f91STakashi Iwai { 345ee8e765bSTakashi Iwai const hda_nid_t *conn; 346352f7f91STakashi Iwai int i, nums; 347352f7f91STakashi Iwai 3483ca529d3STakashi Iwai if (to_nid == anchor_nid) 3493ca529d3STakashi Iwai anchor_nid = 0; /* anchor passed */ 3503ca529d3STakashi Iwai else if (to_nid == (hda_nid_t)(-anchor_nid)) 3513ca529d3STakashi Iwai return false; /* hit the exclusive nid */ 352352f7f91STakashi Iwai 353ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, to_nid, &conn); 354352f7f91STakashi Iwai for (i = 0; i < nums; i++) { 355352f7f91STakashi Iwai if (conn[i] != from_nid) { 356352f7f91STakashi Iwai /* special case: when from_nid is 0, 357352f7f91STakashi Iwai * try to find an empty DAC 358352f7f91STakashi Iwai */ 359352f7f91STakashi Iwai if (from_nid || 360352f7f91STakashi Iwai get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT || 361352f7f91STakashi Iwai is_dac_already_used(codec, conn[i])) 362352f7f91STakashi Iwai continue; 363352f7f91STakashi Iwai } 3643ca529d3STakashi Iwai /* anchor is not requested or already passed? */ 3653ca529d3STakashi Iwai if (anchor_nid <= 0) 366352f7f91STakashi Iwai goto found; 367352f7f91STakashi Iwai } 368352f7f91STakashi Iwai if (depth >= MAX_NID_PATH_DEPTH) 369352f7f91STakashi Iwai return false; 370352f7f91STakashi Iwai for (i = 0; i < nums; i++) { 371352f7f91STakashi Iwai unsigned int type; 372352f7f91STakashi Iwai type = get_wcaps_type(get_wcaps(codec, conn[i])); 373352f7f91STakashi Iwai if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN || 374352f7f91STakashi Iwai type == AC_WID_PIN) 375352f7f91STakashi Iwai continue; 376352f7f91STakashi Iwai if (__parse_nid_path(codec, from_nid, conn[i], 3773ca529d3STakashi Iwai anchor_nid, path, depth + 1)) 378352f7f91STakashi Iwai goto found; 379352f7f91STakashi Iwai } 380352f7f91STakashi Iwai return false; 381352f7f91STakashi Iwai 382352f7f91STakashi Iwai found: 383352f7f91STakashi Iwai path->path[path->depth] = conn[i]; 384352f7f91STakashi Iwai path->idx[path->depth + 1] = i; 385352f7f91STakashi Iwai if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX) 386352f7f91STakashi Iwai path->multi[path->depth + 1] = 1; 387352f7f91STakashi Iwai path->depth++; 388352f7f91STakashi Iwai return true; 389352f7f91STakashi Iwai } 390352f7f91STakashi Iwai 391352f7f91STakashi Iwai /* parse the widget path from the given nid to the target nid; 392352f7f91STakashi Iwai * when @from_nid is 0, try to find an empty DAC; 3933ca529d3STakashi Iwai * when @anchor_nid is set to a positive value, only paths through the widget 3943ca529d3STakashi Iwai * with the given value are evaluated. 3953ca529d3STakashi Iwai * when @anchor_nid is set to a negative value, paths through the widget 3963ca529d3STakashi Iwai * with the negative of given value are excluded, only other paths are chosen. 3973ca529d3STakashi Iwai * when @anchor_nid is zero, no special handling about path selection. 398352f7f91STakashi Iwai */ 399352f7f91STakashi Iwai bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, 4003ca529d3STakashi Iwai hda_nid_t to_nid, int anchor_nid, 401352f7f91STakashi Iwai struct nid_path *path) 402352f7f91STakashi Iwai { 4033ca529d3STakashi Iwai if (__parse_nid_path(codec, from_nid, to_nid, anchor_nid, path, 1)) { 404352f7f91STakashi Iwai path->path[path->depth] = to_nid; 405352f7f91STakashi Iwai path->depth++; 406352f7f91STakashi Iwai return true; 407352f7f91STakashi Iwai } 408352f7f91STakashi Iwai return false; 409352f7f91STakashi Iwai } 410352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_parse_nid_path); 411352f7f91STakashi Iwai 412352f7f91STakashi Iwai /* 413352f7f91STakashi Iwai * parse the path between the given NIDs and add to the path list. 414352f7f91STakashi Iwai * if no valid path is found, return NULL 415352f7f91STakashi Iwai */ 416352f7f91STakashi Iwai struct nid_path * 417352f7f91STakashi Iwai snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid, 4183ca529d3STakashi Iwai hda_nid_t to_nid, int anchor_nid) 419352f7f91STakashi Iwai { 420352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 421352f7f91STakashi Iwai struct nid_path *path; 422352f7f91STakashi Iwai 423352f7f91STakashi Iwai if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid)) 424352f7f91STakashi Iwai return NULL; 425352f7f91STakashi Iwai 426f5172a7eSTakashi Iwai /* check whether the path has been already added */ 4273ca529d3STakashi Iwai path = get_nid_path(codec, from_nid, to_nid, anchor_nid); 428f5172a7eSTakashi Iwai if (path) 429f5172a7eSTakashi Iwai return path; 430f5172a7eSTakashi Iwai 431352f7f91STakashi Iwai path = snd_array_new(&spec->paths); 432352f7f91STakashi Iwai if (!path) 433352f7f91STakashi Iwai return NULL; 434352f7f91STakashi Iwai memset(path, 0, sizeof(*path)); 4353ca529d3STakashi Iwai if (snd_hda_parse_nid_path(codec, from_nid, to_nid, anchor_nid, path)) 436352f7f91STakashi Iwai return path; 437352f7f91STakashi Iwai /* push back */ 438352f7f91STakashi Iwai spec->paths.used--; 439352f7f91STakashi Iwai return NULL; 440352f7f91STakashi Iwai } 441352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_add_new_path); 442352f7f91STakashi Iwai 443980428ceSTakashi Iwai /* clear the given path as invalid so that it won't be picked up later */ 444980428ceSTakashi Iwai static void invalidate_nid_path(struct hda_codec *codec, int idx) 445980428ceSTakashi Iwai { 446980428ceSTakashi Iwai struct nid_path *path = snd_hda_get_path_from_idx(codec, idx); 447980428ceSTakashi Iwai if (!path) 448980428ceSTakashi Iwai return; 449980428ceSTakashi Iwai memset(path, 0, sizeof(*path)); 450980428ceSTakashi Iwai } 451980428ceSTakashi Iwai 452352f7f91STakashi Iwai /* look for an empty DAC slot */ 453352f7f91STakashi Iwai static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin, 454352f7f91STakashi Iwai bool is_digital) 455352f7f91STakashi Iwai { 456352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 457352f7f91STakashi Iwai bool cap_digital; 458352f7f91STakashi Iwai int i; 459352f7f91STakashi Iwai 460352f7f91STakashi Iwai for (i = 0; i < spec->num_all_dacs; i++) { 461352f7f91STakashi Iwai hda_nid_t nid = spec->all_dacs[i]; 462352f7f91STakashi Iwai if (!nid || is_dac_already_used(codec, nid)) 463352f7f91STakashi Iwai continue; 464352f7f91STakashi Iwai cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL); 465352f7f91STakashi Iwai if (is_digital != cap_digital) 466352f7f91STakashi Iwai continue; 467352f7f91STakashi Iwai if (is_reachable_path(codec, nid, pin)) 468352f7f91STakashi Iwai return nid; 469352f7f91STakashi Iwai } 470352f7f91STakashi Iwai return 0; 471352f7f91STakashi Iwai } 472352f7f91STakashi Iwai 473352f7f91STakashi Iwai /* replace the channels in the composed amp value with the given number */ 474352f7f91STakashi Iwai static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs) 475352f7f91STakashi Iwai { 476352f7f91STakashi Iwai val &= ~(0x3U << 16); 477352f7f91STakashi Iwai val |= chs << 16; 478352f7f91STakashi Iwai return val; 479352f7f91STakashi Iwai } 480352f7f91STakashi Iwai 481352f7f91STakashi Iwai /* check whether the widget has the given amp capability for the direction */ 482352f7f91STakashi Iwai static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, 483352f7f91STakashi Iwai int dir, unsigned int bits) 484352f7f91STakashi Iwai { 485352f7f91STakashi Iwai if (!nid) 486352f7f91STakashi Iwai return false; 487352f7f91STakashi Iwai if (get_wcaps(codec, nid) & (1 << (dir + 1))) 488352f7f91STakashi Iwai if (query_amp_caps(codec, nid, dir) & bits) 489352f7f91STakashi Iwai return true; 490352f7f91STakashi Iwai return false; 491352f7f91STakashi Iwai } 492352f7f91STakashi Iwai 49399a5592dSDavid Henningsson static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1, 49499a5592dSDavid Henningsson hda_nid_t nid2, int dir) 49599a5592dSDavid Henningsson { 49699a5592dSDavid Henningsson if (!(get_wcaps(codec, nid1) & (1 << (dir + 1)))) 49799a5592dSDavid Henningsson return !(get_wcaps(codec, nid2) & (1 << (dir + 1))); 49899a5592dSDavid Henningsson return (query_amp_caps(codec, nid1, dir) == 49999a5592dSDavid Henningsson query_amp_caps(codec, nid2, dir)); 50099a5592dSDavid Henningsson } 50199a5592dSDavid Henningsson 502352f7f91STakashi Iwai #define nid_has_mute(codec, nid, dir) \ 503352f7f91STakashi Iwai check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE) 504352f7f91STakashi Iwai #define nid_has_volume(codec, nid, dir) \ 505352f7f91STakashi Iwai check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS) 506352f7f91STakashi Iwai 507352f7f91STakashi Iwai /* look for a widget suitable for assigning a mute switch in the path */ 508352f7f91STakashi Iwai static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec, 509352f7f91STakashi Iwai struct nid_path *path) 510352f7f91STakashi Iwai { 511352f7f91STakashi Iwai int i; 512352f7f91STakashi Iwai 513352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 514352f7f91STakashi Iwai if (nid_has_mute(codec, path->path[i], HDA_OUTPUT)) 515352f7f91STakashi Iwai return path->path[i]; 516352f7f91STakashi Iwai if (i != path->depth - 1 && i != 0 && 517352f7f91STakashi Iwai nid_has_mute(codec, path->path[i], HDA_INPUT)) 518352f7f91STakashi Iwai return path->path[i]; 519352f7f91STakashi Iwai } 520352f7f91STakashi Iwai return 0; 521352f7f91STakashi Iwai } 522352f7f91STakashi Iwai 523352f7f91STakashi Iwai /* look for a widget suitable for assigning a volume ctl in the path */ 524352f7f91STakashi Iwai static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec, 525352f7f91STakashi Iwai struct nid_path *path) 526352f7f91STakashi Iwai { 527352f7f91STakashi Iwai int i; 528352f7f91STakashi Iwai 529352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 530352f7f91STakashi Iwai if (nid_has_volume(codec, path->path[i], HDA_OUTPUT)) 531352f7f91STakashi Iwai return path->path[i]; 532352f7f91STakashi Iwai } 533352f7f91STakashi Iwai return 0; 534352f7f91STakashi Iwai } 535352f7f91STakashi Iwai 536352f7f91STakashi Iwai /* 537352f7f91STakashi Iwai * path activation / deactivation 538352f7f91STakashi Iwai */ 539352f7f91STakashi Iwai 540352f7f91STakashi Iwai /* can have the amp-in capability? */ 541352f7f91STakashi Iwai static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx) 542352f7f91STakashi Iwai { 543352f7f91STakashi Iwai hda_nid_t nid = path->path[idx]; 544352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 545352f7f91STakashi Iwai unsigned int type = get_wcaps_type(caps); 546352f7f91STakashi Iwai 547352f7f91STakashi Iwai if (!(caps & AC_WCAP_IN_AMP)) 548352f7f91STakashi Iwai return false; 549352f7f91STakashi Iwai if (type == AC_WID_PIN && idx > 0) /* only for input pins */ 550352f7f91STakashi Iwai return false; 551352f7f91STakashi Iwai return true; 552352f7f91STakashi Iwai } 553352f7f91STakashi Iwai 554352f7f91STakashi Iwai /* can have the amp-out capability? */ 555352f7f91STakashi Iwai static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx) 556352f7f91STakashi Iwai { 557352f7f91STakashi Iwai hda_nid_t nid = path->path[idx]; 558352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 559352f7f91STakashi Iwai unsigned int type = get_wcaps_type(caps); 560352f7f91STakashi Iwai 561352f7f91STakashi Iwai if (!(caps & AC_WCAP_OUT_AMP)) 562352f7f91STakashi Iwai return false; 563352f7f91STakashi Iwai if (type == AC_WID_PIN && !idx) /* only for output pins */ 564352f7f91STakashi Iwai return false; 565352f7f91STakashi Iwai return true; 566352f7f91STakashi Iwai } 567352f7f91STakashi Iwai 568352f7f91STakashi Iwai /* check whether the given (nid,dir,idx) is active */ 569352f7f91STakashi Iwai static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid, 570352f7f91STakashi Iwai unsigned int idx, unsigned int dir) 571352f7f91STakashi Iwai { 572352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 573352f7f91STakashi Iwai int i, n; 574352f7f91STakashi Iwai 575352f7f91STakashi Iwai for (n = 0; n < spec->paths.used; n++) { 576352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, n); 577352f7f91STakashi Iwai if (!path->active) 578352f7f91STakashi Iwai continue; 579352f7f91STakashi Iwai for (i = 0; i < path->depth; i++) { 580352f7f91STakashi Iwai if (path->path[i] == nid) { 581352f7f91STakashi Iwai if (dir == HDA_OUTPUT || path->idx[i] == idx) 582352f7f91STakashi Iwai return true; 583352f7f91STakashi Iwai break; 584352f7f91STakashi Iwai } 585352f7f91STakashi Iwai } 586352f7f91STakashi Iwai } 587352f7f91STakashi Iwai return false; 588352f7f91STakashi Iwai } 589352f7f91STakashi Iwai 590352f7f91STakashi Iwai /* get the default amp value for the target state */ 591352f7f91STakashi Iwai static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid, 5928999bf0aSTakashi Iwai int dir, unsigned int caps, bool enable) 593352f7f91STakashi Iwai { 594352f7f91STakashi Iwai unsigned int val = 0; 595352f7f91STakashi Iwai 596352f7f91STakashi Iwai if (caps & AC_AMPCAP_NUM_STEPS) { 597352f7f91STakashi Iwai /* set to 0dB */ 598352f7f91STakashi Iwai if (enable) 599352f7f91STakashi Iwai val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; 600352f7f91STakashi Iwai } 601352f7f91STakashi Iwai if (caps & AC_AMPCAP_MUTE) { 602352f7f91STakashi Iwai if (!enable) 603352f7f91STakashi Iwai val |= HDA_AMP_MUTE; 604352f7f91STakashi Iwai } 605352f7f91STakashi Iwai return val; 606352f7f91STakashi Iwai } 607352f7f91STakashi Iwai 608352f7f91STakashi Iwai /* initialize the amp value (only at the first time) */ 609352f7f91STakashi Iwai static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx) 610352f7f91STakashi Iwai { 6118999bf0aSTakashi Iwai unsigned int caps = query_amp_caps(codec, nid, dir); 6128999bf0aSTakashi Iwai int val = get_amp_val_to_activate(codec, nid, dir, caps, false); 613352f7f91STakashi Iwai snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); 614352f7f91STakashi Iwai } 615352f7f91STakashi Iwai 6168999bf0aSTakashi Iwai /* calculate amp value mask we can modify; 6178999bf0aSTakashi Iwai * if the given amp is controlled by mixers, don't touch it 6188999bf0aSTakashi Iwai */ 6198999bf0aSTakashi Iwai static unsigned int get_amp_mask_to_modify(struct hda_codec *codec, 6208999bf0aSTakashi Iwai hda_nid_t nid, int dir, int idx, 6218999bf0aSTakashi Iwai unsigned int caps) 622352f7f91STakashi Iwai { 6238999bf0aSTakashi Iwai unsigned int mask = 0xff; 6248999bf0aSTakashi Iwai 6258999bf0aSTakashi Iwai if (caps & AC_AMPCAP_MUTE) { 6268999bf0aSTakashi Iwai if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_MUTE_CTL)) 6278999bf0aSTakashi Iwai mask &= ~0x80; 6288999bf0aSTakashi Iwai } 6298999bf0aSTakashi Iwai if (caps & AC_AMPCAP_NUM_STEPS) { 6308999bf0aSTakashi Iwai if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) || 6318999bf0aSTakashi Iwai is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL)) 6328999bf0aSTakashi Iwai mask &= ~0x7f; 6338999bf0aSTakashi Iwai } 6348999bf0aSTakashi Iwai return mask; 6358999bf0aSTakashi Iwai } 6368999bf0aSTakashi Iwai 6378999bf0aSTakashi Iwai static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, 6388999bf0aSTakashi Iwai int idx, int idx_to_check, bool enable) 6398999bf0aSTakashi Iwai { 6408999bf0aSTakashi Iwai unsigned int caps; 6418999bf0aSTakashi Iwai unsigned int mask, val; 6428999bf0aSTakashi Iwai 6438999bf0aSTakashi Iwai if (!enable && is_active_nid(codec, nid, dir, idx)) 644352f7f91STakashi Iwai return; 6458999bf0aSTakashi Iwai 6468999bf0aSTakashi Iwai caps = query_amp_caps(codec, nid, dir); 6478999bf0aSTakashi Iwai val = get_amp_val_to_activate(codec, nid, dir, caps, enable); 6488999bf0aSTakashi Iwai mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps); 6498999bf0aSTakashi Iwai if (!mask) 6508999bf0aSTakashi Iwai return; 6518999bf0aSTakashi Iwai 6528999bf0aSTakashi Iwai val &= mask; 6538999bf0aSTakashi Iwai snd_hda_codec_amp_stereo(codec, nid, dir, idx, mask, val); 654352f7f91STakashi Iwai } 655352f7f91STakashi Iwai 656352f7f91STakashi Iwai static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, 657352f7f91STakashi Iwai int i, bool enable) 658352f7f91STakashi Iwai { 659352f7f91STakashi Iwai hda_nid_t nid = path->path[i]; 660352f7f91STakashi Iwai init_amp(codec, nid, HDA_OUTPUT, 0); 6618999bf0aSTakashi Iwai activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable); 662352f7f91STakashi Iwai } 663352f7f91STakashi Iwai 664352f7f91STakashi Iwai static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, 665352f7f91STakashi Iwai int i, bool enable, bool add_aamix) 666352f7f91STakashi Iwai { 667352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 668ee8e765bSTakashi Iwai const hda_nid_t *conn; 669352f7f91STakashi Iwai int n, nums, idx; 670352f7f91STakashi Iwai int type; 671352f7f91STakashi Iwai hda_nid_t nid = path->path[i]; 672352f7f91STakashi Iwai 673ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, nid, &conn); 674352f7f91STakashi Iwai type = get_wcaps_type(get_wcaps(codec, nid)); 675352f7f91STakashi Iwai if (type == AC_WID_PIN || 676352f7f91STakashi Iwai (type == AC_WID_AUD_IN && codec->single_adc_amp)) { 677352f7f91STakashi Iwai nums = 1; 678352f7f91STakashi Iwai idx = 0; 679352f7f91STakashi Iwai } else 680352f7f91STakashi Iwai idx = path->idx[i]; 681352f7f91STakashi Iwai 682352f7f91STakashi Iwai for (n = 0; n < nums; n++) 683352f7f91STakashi Iwai init_amp(codec, nid, HDA_INPUT, n); 684352f7f91STakashi Iwai 685352f7f91STakashi Iwai /* here is a little bit tricky in comparison with activate_amp_out(); 686352f7f91STakashi Iwai * when aa-mixer is available, we need to enable the path as well 687352f7f91STakashi Iwai */ 688352f7f91STakashi Iwai for (n = 0; n < nums; n++) { 689352f7f91STakashi Iwai if (n != idx && (!add_aamix || conn[n] != spec->mixer_nid)) 690352f7f91STakashi Iwai continue; 6918999bf0aSTakashi Iwai activate_amp(codec, nid, HDA_INPUT, n, idx, enable); 692352f7f91STakashi Iwai } 693352f7f91STakashi Iwai } 694352f7f91STakashi Iwai 695352f7f91STakashi Iwai /* activate or deactivate the given path 696352f7f91STakashi Iwai * if @add_aamix is set, enable the input from aa-mix NID as well (if any) 697352f7f91STakashi Iwai */ 698352f7f91STakashi Iwai void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path, 699352f7f91STakashi Iwai bool enable, bool add_aamix) 700352f7f91STakashi Iwai { 701352f7f91STakashi Iwai int i; 702352f7f91STakashi Iwai 703352f7f91STakashi Iwai if (!enable) 704352f7f91STakashi Iwai path->active = false; 705352f7f91STakashi Iwai 706352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 707352f7f91STakashi Iwai if (enable && path->multi[i]) 708352f7f91STakashi Iwai snd_hda_codec_write_cache(codec, path->path[i], 0, 709352f7f91STakashi Iwai AC_VERB_SET_CONNECT_SEL, 710352f7f91STakashi Iwai path->idx[i]); 711352f7f91STakashi Iwai if (has_amp_in(codec, path, i)) 712352f7f91STakashi Iwai activate_amp_in(codec, path, i, enable, add_aamix); 713352f7f91STakashi Iwai if (has_amp_out(codec, path, i)) 714352f7f91STakashi Iwai activate_amp_out(codec, path, i, enable); 715352f7f91STakashi Iwai } 716352f7f91STakashi Iwai 717352f7f91STakashi Iwai if (enable) 718352f7f91STakashi Iwai path->active = true; 719352f7f91STakashi Iwai } 720352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_activate_path); 721352f7f91STakashi Iwai 722d5a9f1bbSTakashi Iwai /* turn on/off EAPD on the given pin */ 723d5a9f1bbSTakashi Iwai static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable) 724d5a9f1bbSTakashi Iwai { 725d5a9f1bbSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 726d5a9f1bbSTakashi Iwai if (spec->own_eapd_ctl || 727d5a9f1bbSTakashi Iwai !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD)) 728d5a9f1bbSTakashi Iwai return; 729ecac3ed1STakashi Iwai if (codec->inv_eapd) 730ecac3ed1STakashi Iwai enable = !enable; 731d5a9f1bbSTakashi Iwai snd_hda_codec_update_cache(codec, pin, 0, 732d5a9f1bbSTakashi Iwai AC_VERB_SET_EAPD_BTLENABLE, 733d5a9f1bbSTakashi Iwai enable ? 0x02 : 0x00); 734d5a9f1bbSTakashi Iwai } 735d5a9f1bbSTakashi Iwai 736352f7f91STakashi Iwai 737352f7f91STakashi Iwai /* 738352f7f91STakashi Iwai * Helper functions for creating mixer ctl elements 739352f7f91STakashi Iwai */ 740352f7f91STakashi Iwai 741352f7f91STakashi Iwai enum { 742352f7f91STakashi Iwai HDA_CTL_WIDGET_VOL, 743352f7f91STakashi Iwai HDA_CTL_WIDGET_MUTE, 744352f7f91STakashi Iwai HDA_CTL_BIND_MUTE, 745352f7f91STakashi Iwai }; 746352f7f91STakashi Iwai static const struct snd_kcontrol_new control_templates[] = { 747352f7f91STakashi Iwai HDA_CODEC_VOLUME(NULL, 0, 0, 0), 748352f7f91STakashi Iwai HDA_CODEC_MUTE(NULL, 0, 0, 0), 749352f7f91STakashi Iwai HDA_BIND_MUTE(NULL, 0, 0, 0), 750352f7f91STakashi Iwai }; 751352f7f91STakashi Iwai 752352f7f91STakashi Iwai /* add dynamic controls from template */ 753352f7f91STakashi Iwai static int add_control(struct hda_gen_spec *spec, int type, const char *name, 754352f7f91STakashi Iwai int cidx, unsigned long val) 755352f7f91STakashi Iwai { 756352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 757352f7f91STakashi Iwai 75812c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]); 759352f7f91STakashi Iwai if (!knew) 760352f7f91STakashi Iwai return -ENOMEM; 761352f7f91STakashi Iwai knew->index = cidx; 762352f7f91STakashi Iwai if (get_amp_nid_(val)) 763352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 764352f7f91STakashi Iwai knew->private_value = val; 765352f7f91STakashi Iwai return 0; 766352f7f91STakashi Iwai } 767352f7f91STakashi Iwai 768352f7f91STakashi Iwai static int add_control_with_pfx(struct hda_gen_spec *spec, int type, 769352f7f91STakashi Iwai const char *pfx, const char *dir, 770352f7f91STakashi Iwai const char *sfx, int cidx, unsigned long val) 771352f7f91STakashi Iwai { 772352f7f91STakashi Iwai char name[32]; 773352f7f91STakashi Iwai snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); 774352f7f91STakashi Iwai return add_control(spec, type, name, cidx, val); 775352f7f91STakashi Iwai } 776352f7f91STakashi Iwai 777352f7f91STakashi Iwai #define add_pb_vol_ctrl(spec, type, pfx, val) \ 778352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val) 779352f7f91STakashi Iwai #define add_pb_sw_ctrl(spec, type, pfx, val) \ 780352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val) 781352f7f91STakashi Iwai #define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \ 782352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val) 783352f7f91STakashi Iwai #define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ 784352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) 785352f7f91STakashi Iwai 786352f7f91STakashi Iwai static int add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx, 787352f7f91STakashi Iwai unsigned int chs, struct nid_path *path) 788352f7f91STakashi Iwai { 789352f7f91STakashi Iwai unsigned int val; 790352f7f91STakashi Iwai if (!path) 791352f7f91STakashi Iwai return 0; 792352f7f91STakashi Iwai val = path->ctls[NID_PATH_VOL_CTL]; 793352f7f91STakashi Iwai if (!val) 794352f7f91STakashi Iwai return 0; 795352f7f91STakashi Iwai val = amp_val_replace_channels(val, chs); 796352f7f91STakashi Iwai return __add_pb_vol_ctrl(codec->spec, HDA_CTL_WIDGET_VOL, pfx, cidx, val); 797352f7f91STakashi Iwai } 798352f7f91STakashi Iwai 799352f7f91STakashi Iwai /* return the channel bits suitable for the given path->ctls[] */ 800352f7f91STakashi Iwai static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path, 801352f7f91STakashi Iwai int type) 802352f7f91STakashi Iwai { 803352f7f91STakashi Iwai int chs = 1; /* mono (left only) */ 804352f7f91STakashi Iwai if (path) { 805352f7f91STakashi Iwai hda_nid_t nid = get_amp_nid_(path->ctls[type]); 806352f7f91STakashi Iwai if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO)) 807352f7f91STakashi Iwai chs = 3; /* stereo */ 808352f7f91STakashi Iwai } 809352f7f91STakashi Iwai return chs; 810352f7f91STakashi Iwai } 811352f7f91STakashi Iwai 812352f7f91STakashi Iwai static int add_stereo_vol(struct hda_codec *codec, const char *pfx, int cidx, 813352f7f91STakashi Iwai struct nid_path *path) 814352f7f91STakashi Iwai { 815352f7f91STakashi Iwai int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL); 816352f7f91STakashi Iwai return add_vol_ctl(codec, pfx, cidx, chs, path); 817352f7f91STakashi Iwai } 818352f7f91STakashi Iwai 819352f7f91STakashi Iwai /* create a mute-switch for the given mixer widget; 820352f7f91STakashi Iwai * if it has multiple sources (e.g. DAC and loopback), create a bind-mute 821352f7f91STakashi Iwai */ 822352f7f91STakashi Iwai static int add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx, 823352f7f91STakashi Iwai unsigned int chs, struct nid_path *path) 824352f7f91STakashi Iwai { 825352f7f91STakashi Iwai unsigned int val; 826352f7f91STakashi Iwai int type = HDA_CTL_WIDGET_MUTE; 827352f7f91STakashi Iwai 828352f7f91STakashi Iwai if (!path) 829352f7f91STakashi Iwai return 0; 830352f7f91STakashi Iwai val = path->ctls[NID_PATH_MUTE_CTL]; 831352f7f91STakashi Iwai if (!val) 832352f7f91STakashi Iwai return 0; 833352f7f91STakashi Iwai val = amp_val_replace_channels(val, chs); 834352f7f91STakashi Iwai if (get_amp_direction_(val) == HDA_INPUT) { 835352f7f91STakashi Iwai hda_nid_t nid = get_amp_nid_(val); 836352f7f91STakashi Iwai int nums = snd_hda_get_num_conns(codec, nid); 837352f7f91STakashi Iwai if (nums > 1) { 838352f7f91STakashi Iwai type = HDA_CTL_BIND_MUTE; 839352f7f91STakashi Iwai val |= nums << 19; 840352f7f91STakashi Iwai } 841352f7f91STakashi Iwai } 842352f7f91STakashi Iwai return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val); 843352f7f91STakashi Iwai } 844352f7f91STakashi Iwai 845352f7f91STakashi Iwai static int add_stereo_sw(struct hda_codec *codec, const char *pfx, 846352f7f91STakashi Iwai int cidx, struct nid_path *path) 847352f7f91STakashi Iwai { 848352f7f91STakashi Iwai int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL); 849352f7f91STakashi Iwai return add_sw_ctl(codec, pfx, cidx, chs, path); 850352f7f91STakashi Iwai } 851352f7f91STakashi Iwai 852247d85eeSTakashi Iwai /* any ctl assigned to the path with the given index? */ 853247d85eeSTakashi Iwai static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type) 854247d85eeSTakashi Iwai { 855247d85eeSTakashi Iwai struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx); 856247d85eeSTakashi Iwai return path && path->ctls[ctl_type]; 857247d85eeSTakashi Iwai } 858247d85eeSTakashi Iwai 859352f7f91STakashi Iwai static const char * const channel_name[4] = { 860352f7f91STakashi Iwai "Front", "Surround", "CLFE", "Side" 861352f7f91STakashi Iwai }; 862352f7f91STakashi Iwai 863352f7f91STakashi Iwai /* give some appropriate ctl name prefix for the given line out channel */ 864247d85eeSTakashi Iwai static const char *get_line_out_pfx(struct hda_codec *codec, int ch, 865247d85eeSTakashi Iwai int *index, int ctl_type) 866352f7f91STakashi Iwai { 867247d85eeSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 868352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 869352f7f91STakashi Iwai 870352f7f91STakashi Iwai *index = 0; 871352f7f91STakashi Iwai if (cfg->line_outs == 1 && !spec->multi_ios && 872247d85eeSTakashi Iwai !cfg->hp_outs && !cfg->speaker_outs) 873352f7f91STakashi Iwai return spec->vmaster_mute.hook ? "PCM" : "Master"; 874352f7f91STakashi Iwai 875352f7f91STakashi Iwai /* if there is really a single DAC used in the whole output paths, 876352f7f91STakashi Iwai * use it master (or "PCM" if a vmaster hook is present) 877352f7f91STakashi Iwai */ 878352f7f91STakashi Iwai if (spec->multiout.num_dacs == 1 && !spec->mixer_nid && 879352f7f91STakashi Iwai !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0]) 880352f7f91STakashi Iwai return spec->vmaster_mute.hook ? "PCM" : "Master"; 881352f7f91STakashi Iwai 882247d85eeSTakashi Iwai /* multi-io channels */ 883247d85eeSTakashi Iwai if (ch >= cfg->line_outs) 884247d85eeSTakashi Iwai return channel_name[ch]; 885247d85eeSTakashi Iwai 886352f7f91STakashi Iwai switch (cfg->line_out_type) { 887352f7f91STakashi Iwai case AUTO_PIN_SPEAKER_OUT: 888247d85eeSTakashi Iwai /* if the primary channel vol/mute is shared with HP volume, 889247d85eeSTakashi Iwai * don't name it as Speaker 890247d85eeSTakashi Iwai */ 891247d85eeSTakashi Iwai if (!ch && cfg->hp_outs && 892247d85eeSTakashi Iwai !path_has_mixer(codec, spec->hp_paths[0], ctl_type)) 893247d85eeSTakashi Iwai break; 894352f7f91STakashi Iwai if (cfg->line_outs == 1) 895352f7f91STakashi Iwai return "Speaker"; 896352f7f91STakashi Iwai if (cfg->line_outs == 2) 897352f7f91STakashi Iwai return ch ? "Bass Speaker" : "Speaker"; 898352f7f91STakashi Iwai break; 899352f7f91STakashi Iwai case AUTO_PIN_HP_OUT: 900247d85eeSTakashi Iwai /* if the primary channel vol/mute is shared with spk volume, 901247d85eeSTakashi Iwai * don't name it as Headphone 902247d85eeSTakashi Iwai */ 903247d85eeSTakashi Iwai if (!ch && cfg->speaker_outs && 904247d85eeSTakashi Iwai !path_has_mixer(codec, spec->speaker_paths[0], ctl_type)) 905247d85eeSTakashi Iwai break; 906352f7f91STakashi Iwai /* for multi-io case, only the primary out */ 907352f7f91STakashi Iwai if (ch && spec->multi_ios) 908352f7f91STakashi Iwai break; 909352f7f91STakashi Iwai *index = ch; 910352f7f91STakashi Iwai return "Headphone"; 911247d85eeSTakashi Iwai } 912247d85eeSTakashi Iwai 913247d85eeSTakashi Iwai /* for a single channel output, we don't have to name the channel */ 914352f7f91STakashi Iwai if (cfg->line_outs == 1 && !spec->multi_ios) 915352f7f91STakashi Iwai return "PCM"; 916247d85eeSTakashi Iwai 917352f7f91STakashi Iwai if (ch >= ARRAY_SIZE(channel_name)) { 918352f7f91STakashi Iwai snd_BUG(); 919352f7f91STakashi Iwai return "PCM"; 920352f7f91STakashi Iwai } 921352f7f91STakashi Iwai 922352f7f91STakashi Iwai return channel_name[ch]; 923352f7f91STakashi Iwai } 924352f7f91STakashi Iwai 925352f7f91STakashi Iwai /* 926352f7f91STakashi Iwai * Parse output paths 927352f7f91STakashi Iwai */ 928352f7f91STakashi Iwai 929352f7f91STakashi Iwai /* badness definition */ 930352f7f91STakashi Iwai enum { 931352f7f91STakashi Iwai /* No primary DAC is found for the main output */ 932352f7f91STakashi Iwai BAD_NO_PRIMARY_DAC = 0x10000, 933352f7f91STakashi Iwai /* No DAC is found for the extra output */ 934352f7f91STakashi Iwai BAD_NO_DAC = 0x4000, 935352f7f91STakashi Iwai /* No possible multi-ios */ 936352f7f91STakashi Iwai BAD_MULTI_IO = 0x103, 937352f7f91STakashi Iwai /* No individual DAC for extra output */ 938352f7f91STakashi Iwai BAD_NO_EXTRA_DAC = 0x102, 939352f7f91STakashi Iwai /* No individual DAC for extra surrounds */ 940352f7f91STakashi Iwai BAD_NO_EXTRA_SURR_DAC = 0x101, 941352f7f91STakashi Iwai /* Primary DAC shared with main surrounds */ 942352f7f91STakashi Iwai BAD_SHARED_SURROUND = 0x100, 943352f7f91STakashi Iwai /* Primary DAC shared with main CLFE */ 944352f7f91STakashi Iwai BAD_SHARED_CLFE = 0x10, 945352f7f91STakashi Iwai /* Primary DAC shared with extra surrounds */ 946352f7f91STakashi Iwai BAD_SHARED_EXTRA_SURROUND = 0x10, 947352f7f91STakashi Iwai /* Volume widget is shared */ 948352f7f91STakashi Iwai BAD_SHARED_VOL = 0x10, 949352f7f91STakashi Iwai }; 950352f7f91STakashi Iwai 9510e614dd0STakashi Iwai /* look for widgets in the given path which are appropriate for 952352f7f91STakashi Iwai * volume and mute controls, and assign the values to ctls[]. 953352f7f91STakashi Iwai * 954352f7f91STakashi Iwai * When no appropriate widget is found in the path, the badness value 955352f7f91STakashi Iwai * is incremented depending on the situation. The function returns the 956352f7f91STakashi Iwai * total badness for both volume and mute controls. 957352f7f91STakashi Iwai */ 9580e614dd0STakashi Iwai static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path) 959352f7f91STakashi Iwai { 960352f7f91STakashi Iwai hda_nid_t nid; 961352f7f91STakashi Iwai unsigned int val; 962352f7f91STakashi Iwai int badness = 0; 963352f7f91STakashi Iwai 964352f7f91STakashi Iwai if (!path) 965352f7f91STakashi Iwai return BAD_SHARED_VOL * 2; 9660e614dd0STakashi Iwai 9670e614dd0STakashi Iwai if (path->ctls[NID_PATH_VOL_CTL] || 9680e614dd0STakashi Iwai path->ctls[NID_PATH_MUTE_CTL]) 9690e614dd0STakashi Iwai return 0; /* already evaluated */ 9700e614dd0STakashi Iwai 971352f7f91STakashi Iwai nid = look_for_out_vol_nid(codec, path); 972352f7f91STakashi Iwai if (nid) { 973352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 974352f7f91STakashi Iwai if (is_ctl_used(codec, val, NID_PATH_VOL_CTL)) 975352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 976352f7f91STakashi Iwai else 977352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = val; 978352f7f91STakashi Iwai } else 979352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 980352f7f91STakashi Iwai nid = look_for_out_mute_nid(codec, path); 981352f7f91STakashi Iwai if (nid) { 982352f7f91STakashi Iwai unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid)); 983352f7f91STakashi Iwai if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT || 984352f7f91STakashi Iwai nid_has_mute(codec, nid, HDA_OUTPUT)) 985352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 986352f7f91STakashi Iwai else 987352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); 988352f7f91STakashi Iwai if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL)) 989352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 990352f7f91STakashi Iwai else 991352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = val; 992352f7f91STakashi Iwai } else 993352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 994352f7f91STakashi Iwai return badness; 995352f7f91STakashi Iwai } 996352f7f91STakashi Iwai 997352f7f91STakashi Iwai struct badness_table { 998352f7f91STakashi Iwai int no_primary_dac; /* no primary DAC */ 999352f7f91STakashi Iwai int no_dac; /* no secondary DACs */ 1000352f7f91STakashi Iwai int shared_primary; /* primary DAC is shared with main output */ 1001352f7f91STakashi Iwai int shared_surr; /* secondary DAC shared with main or primary */ 1002352f7f91STakashi Iwai int shared_clfe; /* third DAC shared with main or primary */ 1003352f7f91STakashi Iwai int shared_surr_main; /* secondary DAC sahred with main/DAC0 */ 1004352f7f91STakashi Iwai }; 1005352f7f91STakashi Iwai 1006352f7f91STakashi Iwai static struct badness_table main_out_badness = { 1007352f7f91STakashi Iwai .no_primary_dac = BAD_NO_PRIMARY_DAC, 1008352f7f91STakashi Iwai .no_dac = BAD_NO_DAC, 1009352f7f91STakashi Iwai .shared_primary = BAD_NO_PRIMARY_DAC, 1010352f7f91STakashi Iwai .shared_surr = BAD_SHARED_SURROUND, 1011352f7f91STakashi Iwai .shared_clfe = BAD_SHARED_CLFE, 1012352f7f91STakashi Iwai .shared_surr_main = BAD_SHARED_SURROUND, 1013352f7f91STakashi Iwai }; 1014352f7f91STakashi Iwai 1015352f7f91STakashi Iwai static struct badness_table extra_out_badness = { 1016352f7f91STakashi Iwai .no_primary_dac = BAD_NO_DAC, 1017352f7f91STakashi Iwai .no_dac = BAD_NO_DAC, 1018352f7f91STakashi Iwai .shared_primary = BAD_NO_EXTRA_DAC, 1019352f7f91STakashi Iwai .shared_surr = BAD_SHARED_EXTRA_SURROUND, 1020352f7f91STakashi Iwai .shared_clfe = BAD_SHARED_EXTRA_SURROUND, 1021352f7f91STakashi Iwai .shared_surr_main = BAD_NO_EXTRA_SURR_DAC, 1022352f7f91STakashi Iwai }; 1023352f7f91STakashi Iwai 10247385df61STakashi Iwai /* get the DAC of the primary output corresponding to the given array index */ 10257385df61STakashi Iwai static hda_nid_t get_primary_out(struct hda_codec *codec, int idx) 10267385df61STakashi Iwai { 10277385df61STakashi Iwai struct hda_gen_spec *spec = codec->spec; 10287385df61STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 10297385df61STakashi Iwai 10307385df61STakashi Iwai if (cfg->line_outs > idx) 10317385df61STakashi Iwai return spec->private_dac_nids[idx]; 10327385df61STakashi Iwai idx -= cfg->line_outs; 10337385df61STakashi Iwai if (spec->multi_ios > idx) 10347385df61STakashi Iwai return spec->multi_io[idx].dac; 10357385df61STakashi Iwai return 0; 10367385df61STakashi Iwai } 10377385df61STakashi Iwai 10387385df61STakashi Iwai /* return the DAC if it's reachable, otherwise zero */ 10397385df61STakashi Iwai static inline hda_nid_t try_dac(struct hda_codec *codec, 10407385df61STakashi Iwai hda_nid_t dac, hda_nid_t pin) 10417385df61STakashi Iwai { 10427385df61STakashi Iwai return is_reachable_path(codec, dac, pin) ? dac : 0; 10437385df61STakashi Iwai } 10447385df61STakashi Iwai 1045352f7f91STakashi Iwai /* try to assign DACs to pins and return the resultant badness */ 1046352f7f91STakashi Iwai static int try_assign_dacs(struct hda_codec *codec, int num_outs, 1047352f7f91STakashi Iwai const hda_nid_t *pins, hda_nid_t *dacs, 1048196c1766STakashi Iwai int *path_idx, 1049352f7f91STakashi Iwai const struct badness_table *bad) 1050352f7f91STakashi Iwai { 1051352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1052352f7f91STakashi Iwai int i, j; 1053352f7f91STakashi Iwai int badness = 0; 1054352f7f91STakashi Iwai hda_nid_t dac; 1055352f7f91STakashi Iwai 1056352f7f91STakashi Iwai if (!num_outs) 1057352f7f91STakashi Iwai return 0; 1058352f7f91STakashi Iwai 1059352f7f91STakashi Iwai for (i = 0; i < num_outs; i++) { 10600c8c0f56STakashi Iwai struct nid_path *path; 1061352f7f91STakashi Iwai hda_nid_t pin = pins[i]; 10621e0b5286STakashi Iwai 10630e614dd0STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx[i]); 10640e614dd0STakashi Iwai if (path) { 10650e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path); 10661e0b5286STakashi Iwai continue; 10671e0b5286STakashi Iwai } 10681e0b5286STakashi Iwai 1069352f7f91STakashi Iwai dacs[i] = look_for_dac(codec, pin, false); 1070352f7f91STakashi Iwai if (!dacs[i] && !i) { 1071980428ceSTakashi Iwai /* try to steal the DAC of surrounds for the front */ 1072352f7f91STakashi Iwai for (j = 1; j < num_outs; j++) { 1073352f7f91STakashi Iwai if (is_reachable_path(codec, dacs[j], pin)) { 1074352f7f91STakashi Iwai dacs[0] = dacs[j]; 1075352f7f91STakashi Iwai dacs[j] = 0; 1076980428ceSTakashi Iwai invalidate_nid_path(codec, path_idx[j]); 1077196c1766STakashi Iwai path_idx[j] = 0; 1078352f7f91STakashi Iwai break; 1079352f7f91STakashi Iwai } 1080352f7f91STakashi Iwai } 1081352f7f91STakashi Iwai } 1082352f7f91STakashi Iwai dac = dacs[i]; 1083352f7f91STakashi Iwai if (!dac) { 10847385df61STakashi Iwai if (num_outs > 2) 10857385df61STakashi Iwai dac = try_dac(codec, get_primary_out(codec, i), pin); 10867385df61STakashi Iwai if (!dac) 10877385df61STakashi Iwai dac = try_dac(codec, dacs[0], pin); 10887385df61STakashi Iwai if (!dac) 10897385df61STakashi Iwai dac = try_dac(codec, get_primary_out(codec, i), pin); 1090352f7f91STakashi Iwai if (dac) { 1091352f7f91STakashi Iwai if (!i) 1092352f7f91STakashi Iwai badness += bad->shared_primary; 1093352f7f91STakashi Iwai else if (i == 1) 1094352f7f91STakashi Iwai badness += bad->shared_surr; 1095352f7f91STakashi Iwai else 1096352f7f91STakashi Iwai badness += bad->shared_clfe; 1097352f7f91STakashi Iwai } else if (is_reachable_path(codec, spec->private_dac_nids[0], pin)) { 1098352f7f91STakashi Iwai dac = spec->private_dac_nids[0]; 1099352f7f91STakashi Iwai badness += bad->shared_surr_main; 1100352f7f91STakashi Iwai } else if (!i) 1101352f7f91STakashi Iwai badness += bad->no_primary_dac; 1102352f7f91STakashi Iwai else 1103352f7f91STakashi Iwai badness += bad->no_dac; 1104352f7f91STakashi Iwai } 11053ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, -spec->mixer_nid); 1106117688a9STakashi Iwai if (!path && !i && spec->mixer_nid) { 1107b3a8c745STakashi Iwai /* try with aamix */ 11083ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, 0); 1109b3a8c745STakashi Iwai } 11100c8c0f56STakashi Iwai if (!path) 1111352f7f91STakashi Iwai dac = dacs[i] = 0; 1112e1284af7STakashi Iwai else { 11130c8c0f56STakashi Iwai print_nid_path("output", path); 1114e1284af7STakashi Iwai path->active = true; 1115196c1766STakashi Iwai path_idx[i] = snd_hda_get_path_idx(codec, path); 11160e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path); 1117e1284af7STakashi Iwai } 1118352f7f91STakashi Iwai } 1119352f7f91STakashi Iwai 1120352f7f91STakashi Iwai return badness; 1121352f7f91STakashi Iwai } 1122352f7f91STakashi Iwai 1123352f7f91STakashi Iwai /* return NID if the given pin has only a single connection to a certain DAC */ 1124352f7f91STakashi Iwai static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) 1125352f7f91STakashi Iwai { 1126352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1127352f7f91STakashi Iwai int i; 1128352f7f91STakashi Iwai hda_nid_t nid_found = 0; 1129352f7f91STakashi Iwai 1130352f7f91STakashi Iwai for (i = 0; i < spec->num_all_dacs; i++) { 1131352f7f91STakashi Iwai hda_nid_t nid = spec->all_dacs[i]; 1132352f7f91STakashi Iwai if (!nid || is_dac_already_used(codec, nid)) 1133352f7f91STakashi Iwai continue; 1134352f7f91STakashi Iwai if (is_reachable_path(codec, nid, pin)) { 1135352f7f91STakashi Iwai if (nid_found) 1136352f7f91STakashi Iwai return 0; 1137352f7f91STakashi Iwai nid_found = nid; 1138352f7f91STakashi Iwai } 1139352f7f91STakashi Iwai } 1140352f7f91STakashi Iwai return nid_found; 1141352f7f91STakashi Iwai } 1142352f7f91STakashi Iwai 1143352f7f91STakashi Iwai /* check whether the given pin can be a multi-io pin */ 1144352f7f91STakashi Iwai static bool can_be_multiio_pin(struct hda_codec *codec, 1145352f7f91STakashi Iwai unsigned int location, hda_nid_t nid) 1146352f7f91STakashi Iwai { 1147352f7f91STakashi Iwai unsigned int defcfg, caps; 1148352f7f91STakashi Iwai 1149352f7f91STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, nid); 1150352f7f91STakashi Iwai if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) 1151352f7f91STakashi Iwai return false; 1152352f7f91STakashi Iwai if (location && get_defcfg_location(defcfg) != location) 1153352f7f91STakashi Iwai return false; 1154352f7f91STakashi Iwai caps = snd_hda_query_pin_caps(codec, nid); 1155352f7f91STakashi Iwai if (!(caps & AC_PINCAP_OUT)) 1156352f7f91STakashi Iwai return false; 1157352f7f91STakashi Iwai return true; 1158352f7f91STakashi Iwai } 1159352f7f91STakashi Iwai 1160e22aab7dSTakashi Iwai /* count the number of input pins that are capable to be multi-io */ 1161e22aab7dSTakashi Iwai static int count_multiio_pins(struct hda_codec *codec, hda_nid_t reference_pin) 1162e22aab7dSTakashi Iwai { 1163e22aab7dSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 1164e22aab7dSTakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1165e22aab7dSTakashi Iwai unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); 1166e22aab7dSTakashi Iwai unsigned int location = get_defcfg_location(defcfg); 1167e22aab7dSTakashi Iwai int type, i; 1168e22aab7dSTakashi Iwai int num_pins = 0; 1169e22aab7dSTakashi Iwai 1170e22aab7dSTakashi Iwai for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { 1171e22aab7dSTakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 1172e22aab7dSTakashi Iwai if (cfg->inputs[i].type != type) 1173e22aab7dSTakashi Iwai continue; 1174e22aab7dSTakashi Iwai if (can_be_multiio_pin(codec, location, 1175e22aab7dSTakashi Iwai cfg->inputs[i].pin)) 1176e22aab7dSTakashi Iwai num_pins++; 1177e22aab7dSTakashi Iwai } 1178e22aab7dSTakashi Iwai } 1179e22aab7dSTakashi Iwai return num_pins; 1180e22aab7dSTakashi Iwai } 1181e22aab7dSTakashi Iwai 1182352f7f91STakashi Iwai /* 1183352f7f91STakashi Iwai * multi-io helper 1184352f7f91STakashi Iwai * 1185352f7f91STakashi Iwai * When hardwired is set, try to fill ony hardwired pins, and returns 1186352f7f91STakashi Iwai * zero if any pins are filled, non-zero if nothing found. 1187352f7f91STakashi Iwai * When hardwired is off, try to fill possible input pins, and returns 1188352f7f91STakashi Iwai * the badness value. 1189352f7f91STakashi Iwai */ 1190352f7f91STakashi Iwai static int fill_multi_ios(struct hda_codec *codec, 1191352f7f91STakashi Iwai hda_nid_t reference_pin, 1192e22aab7dSTakashi Iwai bool hardwired) 1193352f7f91STakashi Iwai { 1194352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1195352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1196e22aab7dSTakashi Iwai int type, i, j, num_pins, old_pins; 1197352f7f91STakashi Iwai unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); 1198352f7f91STakashi Iwai unsigned int location = get_defcfg_location(defcfg); 1199352f7f91STakashi Iwai int badness = 0; 12000e614dd0STakashi Iwai struct nid_path *path; 1201352f7f91STakashi Iwai 1202352f7f91STakashi Iwai old_pins = spec->multi_ios; 1203352f7f91STakashi Iwai if (old_pins >= 2) 1204352f7f91STakashi Iwai goto end_fill; 1205352f7f91STakashi Iwai 1206e22aab7dSTakashi Iwai num_pins = count_multiio_pins(codec, reference_pin); 1207352f7f91STakashi Iwai if (num_pins < 2) 1208352f7f91STakashi Iwai goto end_fill; 1209352f7f91STakashi Iwai 1210352f7f91STakashi Iwai for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { 1211352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 1212352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 1213352f7f91STakashi Iwai hda_nid_t dac = 0; 1214352f7f91STakashi Iwai 1215352f7f91STakashi Iwai if (cfg->inputs[i].type != type) 1216352f7f91STakashi Iwai continue; 1217352f7f91STakashi Iwai if (!can_be_multiio_pin(codec, location, nid)) 1218352f7f91STakashi Iwai continue; 1219352f7f91STakashi Iwai for (j = 0; j < spec->multi_ios; j++) { 1220352f7f91STakashi Iwai if (nid == spec->multi_io[j].pin) 1221352f7f91STakashi Iwai break; 1222352f7f91STakashi Iwai } 1223352f7f91STakashi Iwai if (j < spec->multi_ios) 1224352f7f91STakashi Iwai continue; 1225352f7f91STakashi Iwai 1226352f7f91STakashi Iwai if (hardwired) 1227352f7f91STakashi Iwai dac = get_dac_if_single(codec, nid); 1228352f7f91STakashi Iwai else if (!dac) 1229352f7f91STakashi Iwai dac = look_for_dac(codec, nid, false); 1230352f7f91STakashi Iwai if (!dac) { 1231352f7f91STakashi Iwai badness++; 1232352f7f91STakashi Iwai continue; 1233352f7f91STakashi Iwai } 12343ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, nid, 12353ca529d3STakashi Iwai -spec->mixer_nid); 12360c8c0f56STakashi Iwai if (!path) { 1237352f7f91STakashi Iwai badness++; 1238352f7f91STakashi Iwai continue; 1239352f7f91STakashi Iwai } 12400c8c0f56STakashi Iwai print_nid_path("multiio", path); 1241352f7f91STakashi Iwai spec->multi_io[spec->multi_ios].pin = nid; 1242352f7f91STakashi Iwai spec->multi_io[spec->multi_ios].dac = dac; 1243196c1766STakashi Iwai spec->out_paths[cfg->line_outs + spec->multi_ios] = 1244196c1766STakashi Iwai snd_hda_get_path_idx(codec, path); 1245352f7f91STakashi Iwai spec->multi_ios++; 1246352f7f91STakashi Iwai if (spec->multi_ios >= 2) 1247352f7f91STakashi Iwai break; 1248352f7f91STakashi Iwai } 1249352f7f91STakashi Iwai } 1250352f7f91STakashi Iwai end_fill: 1251352f7f91STakashi Iwai if (badness) 1252352f7f91STakashi Iwai badness = BAD_MULTI_IO; 1253352f7f91STakashi Iwai if (old_pins == spec->multi_ios) { 1254352f7f91STakashi Iwai if (hardwired) 1255352f7f91STakashi Iwai return 1; /* nothing found */ 1256352f7f91STakashi Iwai else 1257352f7f91STakashi Iwai return badness; /* no badness if nothing found */ 1258352f7f91STakashi Iwai } 1259352f7f91STakashi Iwai if (!hardwired && spec->multi_ios < 2) { 1260352f7f91STakashi Iwai /* cancel newly assigned paths */ 1261352f7f91STakashi Iwai spec->paths.used -= spec->multi_ios - old_pins; 1262352f7f91STakashi Iwai spec->multi_ios = old_pins; 1263352f7f91STakashi Iwai return badness; 1264352f7f91STakashi Iwai } 1265352f7f91STakashi Iwai 1266352f7f91STakashi Iwai /* assign volume and mute controls */ 12670e614dd0STakashi Iwai for (i = old_pins; i < spec->multi_ios; i++) { 12680e614dd0STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[cfg->line_outs + i]); 12690e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path); 12700e614dd0STakashi Iwai } 1271352f7f91STakashi Iwai 1272352f7f91STakashi Iwai return badness; 1273352f7f91STakashi Iwai } 1274352f7f91STakashi Iwai 1275352f7f91STakashi Iwai /* map DACs for all pins in the list if they are single connections */ 1276352f7f91STakashi Iwai static bool map_singles(struct hda_codec *codec, int outs, 1277196c1766STakashi Iwai const hda_nid_t *pins, hda_nid_t *dacs, int *path_idx) 1278352f7f91STakashi Iwai { 1279b3a8c745STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1280352f7f91STakashi Iwai int i; 1281352f7f91STakashi Iwai bool found = false; 1282352f7f91STakashi Iwai for (i = 0; i < outs; i++) { 12830c8c0f56STakashi Iwai struct nid_path *path; 1284352f7f91STakashi Iwai hda_nid_t dac; 1285352f7f91STakashi Iwai if (dacs[i]) 1286352f7f91STakashi Iwai continue; 1287352f7f91STakashi Iwai dac = get_dac_if_single(codec, pins[i]); 1288352f7f91STakashi Iwai if (!dac) 1289352f7f91STakashi Iwai continue; 12903ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pins[i], 12913ca529d3STakashi Iwai -spec->mixer_nid); 1292117688a9STakashi Iwai if (!path && !i && spec->mixer_nid) 12933ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pins[i], 0); 12940c8c0f56STakashi Iwai if (path) { 1295352f7f91STakashi Iwai dacs[i] = dac; 1296352f7f91STakashi Iwai found = true; 12970c8c0f56STakashi Iwai print_nid_path("output", path); 1298e1284af7STakashi Iwai path->active = true; 1299196c1766STakashi Iwai path_idx[i] = snd_hda_get_path_idx(codec, path); 1300352f7f91STakashi Iwai } 1301352f7f91STakashi Iwai } 1302352f7f91STakashi Iwai return found; 1303352f7f91STakashi Iwai } 1304352f7f91STakashi Iwai 1305c30aa7b2STakashi Iwai /* create a new path including aamix if available, and return its index */ 1306c30aa7b2STakashi Iwai static int check_aamix_out_path(struct hda_codec *codec, int path_idx) 1307c30aa7b2STakashi Iwai { 13083ca529d3STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1309c30aa7b2STakashi Iwai struct nid_path *path; 1310c30aa7b2STakashi Iwai 1311c30aa7b2STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 13123ca529d3STakashi Iwai if (!path || !path->depth || 13133ca529d3STakashi Iwai is_nid_contained(path, spec->mixer_nid)) 1314c30aa7b2STakashi Iwai return 0; 1315c30aa7b2STakashi Iwai path = snd_hda_add_new_path(codec, path->path[0], 1316c30aa7b2STakashi Iwai path->path[path->depth - 1], 13173ca529d3STakashi Iwai spec->mixer_nid); 1318c30aa7b2STakashi Iwai if (!path) 1319c30aa7b2STakashi Iwai return 0; 1320c30aa7b2STakashi Iwai print_nid_path("output-aamix", path); 1321c30aa7b2STakashi Iwai path->active = false; /* unused as default */ 1322c30aa7b2STakashi Iwai return snd_hda_get_path_idx(codec, path); 1323c30aa7b2STakashi Iwai } 1324c30aa7b2STakashi Iwai 1325a07a949bSTakashi Iwai /* fill the empty entries in the dac array for speaker/hp with the 1326a07a949bSTakashi Iwai * shared dac pointed by the paths 1327a07a949bSTakashi Iwai */ 1328a07a949bSTakashi Iwai static void refill_shared_dacs(struct hda_codec *codec, int num_outs, 1329a07a949bSTakashi Iwai hda_nid_t *dacs, int *path_idx) 1330a07a949bSTakashi Iwai { 1331a07a949bSTakashi Iwai struct nid_path *path; 1332a07a949bSTakashi Iwai int i; 1333a07a949bSTakashi Iwai 1334a07a949bSTakashi Iwai for (i = 0; i < num_outs; i++) { 1335a07a949bSTakashi Iwai if (dacs[i]) 1336a07a949bSTakashi Iwai continue; 1337a07a949bSTakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx[i]); 1338a07a949bSTakashi Iwai if (!path) 1339a07a949bSTakashi Iwai continue; 1340a07a949bSTakashi Iwai dacs[i] = path->path[0]; 1341a07a949bSTakashi Iwai } 1342a07a949bSTakashi Iwai } 1343a07a949bSTakashi Iwai 1344352f7f91STakashi Iwai /* fill in the dac_nids table from the parsed pin configuration */ 1345352f7f91STakashi Iwai static int fill_and_eval_dacs(struct hda_codec *codec, 1346352f7f91STakashi Iwai bool fill_hardwired, 1347352f7f91STakashi Iwai bool fill_mio_first) 1348352f7f91STakashi Iwai { 1349352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1350352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1351352f7f91STakashi Iwai int i, err, badness; 1352ea46c3c8STakashi Iwai unsigned int val; 1353352f7f91STakashi Iwai 1354352f7f91STakashi Iwai /* set num_dacs once to full for look_for_dac() */ 1355352f7f91STakashi Iwai spec->multiout.num_dacs = cfg->line_outs; 1356352f7f91STakashi Iwai spec->multiout.dac_nids = spec->private_dac_nids; 1357352f7f91STakashi Iwai memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); 1358352f7f91STakashi Iwai memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid)); 1359352f7f91STakashi Iwai memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid)); 1360352f7f91STakashi Iwai spec->multi_ios = 0; 1361352f7f91STakashi Iwai snd_array_free(&spec->paths); 1362cd5be3f9STakashi Iwai 1363cd5be3f9STakashi Iwai /* clear path indices */ 1364cd5be3f9STakashi Iwai memset(spec->out_paths, 0, sizeof(spec->out_paths)); 1365cd5be3f9STakashi Iwai memset(spec->hp_paths, 0, sizeof(spec->hp_paths)); 1366cd5be3f9STakashi Iwai memset(spec->speaker_paths, 0, sizeof(spec->speaker_paths)); 1367cd5be3f9STakashi Iwai memset(spec->aamix_out_paths, 0, sizeof(spec->aamix_out_paths)); 1368cd5be3f9STakashi Iwai memset(spec->digout_paths, 0, sizeof(spec->digout_paths)); 1369c697b716STakashi Iwai memset(spec->input_paths, 0, sizeof(spec->input_paths)); 1370cd5be3f9STakashi Iwai memset(spec->loopback_paths, 0, sizeof(spec->loopback_paths)); 1371cd5be3f9STakashi Iwai memset(&spec->digin_path, 0, sizeof(spec->digin_path)); 1372cd5be3f9STakashi Iwai 1373352f7f91STakashi Iwai badness = 0; 1374352f7f91STakashi Iwai 1375352f7f91STakashi Iwai /* fill hard-wired DACs first */ 1376352f7f91STakashi Iwai if (fill_hardwired) { 1377352f7f91STakashi Iwai bool mapped; 1378352f7f91STakashi Iwai do { 1379352f7f91STakashi Iwai mapped = map_singles(codec, cfg->line_outs, 1380352f7f91STakashi Iwai cfg->line_out_pins, 1381196c1766STakashi Iwai spec->private_dac_nids, 1382196c1766STakashi Iwai spec->out_paths); 1383352f7f91STakashi Iwai mapped |= map_singles(codec, cfg->hp_outs, 1384352f7f91STakashi Iwai cfg->hp_pins, 1385196c1766STakashi Iwai spec->multiout.hp_out_nid, 1386196c1766STakashi Iwai spec->hp_paths); 1387352f7f91STakashi Iwai mapped |= map_singles(codec, cfg->speaker_outs, 1388352f7f91STakashi Iwai cfg->speaker_pins, 1389196c1766STakashi Iwai spec->multiout.extra_out_nid, 1390196c1766STakashi Iwai spec->speaker_paths); 1391352f7f91STakashi Iwai if (fill_mio_first && cfg->line_outs == 1 && 1392352f7f91STakashi Iwai cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1393e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], true); 1394352f7f91STakashi Iwai if (!err) 1395352f7f91STakashi Iwai mapped = true; 1396352f7f91STakashi Iwai } 1397352f7f91STakashi Iwai } while (mapped); 1398352f7f91STakashi Iwai } 1399352f7f91STakashi Iwai 1400352f7f91STakashi Iwai badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins, 1401196c1766STakashi Iwai spec->private_dac_nids, spec->out_paths, 1402352f7f91STakashi Iwai &main_out_badness); 1403352f7f91STakashi Iwai 1404352f7f91STakashi Iwai if (fill_mio_first && 1405352f7f91STakashi Iwai cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1406352f7f91STakashi Iwai /* try to fill multi-io first */ 1407e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], false); 1408352f7f91STakashi Iwai if (err < 0) 1409352f7f91STakashi Iwai return err; 1410352f7f91STakashi Iwai /* we don't count badness at this stage yet */ 1411352f7f91STakashi Iwai } 1412352f7f91STakashi Iwai 1413352f7f91STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) { 1414352f7f91STakashi Iwai err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins, 1415352f7f91STakashi Iwai spec->multiout.hp_out_nid, 1416196c1766STakashi Iwai spec->hp_paths, 1417352f7f91STakashi Iwai &extra_out_badness); 1418352f7f91STakashi Iwai if (err < 0) 1419352f7f91STakashi Iwai return err; 1420352f7f91STakashi Iwai badness += err; 1421352f7f91STakashi Iwai } 1422352f7f91STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1423352f7f91STakashi Iwai err = try_assign_dacs(codec, cfg->speaker_outs, 1424352f7f91STakashi Iwai cfg->speaker_pins, 1425352f7f91STakashi Iwai spec->multiout.extra_out_nid, 1426196c1766STakashi Iwai spec->speaker_paths, 1427352f7f91STakashi Iwai &extra_out_badness); 1428352f7f91STakashi Iwai if (err < 0) 1429352f7f91STakashi Iwai return err; 1430352f7f91STakashi Iwai badness += err; 1431352f7f91STakashi Iwai } 1432352f7f91STakashi Iwai if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1433e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], false); 1434352f7f91STakashi Iwai if (err < 0) 1435352f7f91STakashi Iwai return err; 1436352f7f91STakashi Iwai badness += err; 1437352f7f91STakashi Iwai } 1438e22aab7dSTakashi Iwai 1439c30aa7b2STakashi Iwai if (spec->mixer_nid) { 1440c30aa7b2STakashi Iwai spec->aamix_out_paths[0] = 1441c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->out_paths[0]); 1442c30aa7b2STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 1443c30aa7b2STakashi Iwai spec->aamix_out_paths[1] = 1444c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->hp_paths[0]); 1445c30aa7b2STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 1446c30aa7b2STakashi Iwai spec->aamix_out_paths[2] = 1447c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->speaker_paths[0]); 1448c30aa7b2STakashi Iwai } 1449c30aa7b2STakashi Iwai 1450e22aab7dSTakashi Iwai if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) 1451e22aab7dSTakashi Iwai if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2) 1452e22aab7dSTakashi Iwai spec->multi_ios = 1; /* give badness */ 1453352f7f91STakashi Iwai 1454a07a949bSTakashi Iwai /* re-count num_dacs and squash invalid entries */ 1455a07a949bSTakashi Iwai spec->multiout.num_dacs = 0; 1456a07a949bSTakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 1457a07a949bSTakashi Iwai if (spec->private_dac_nids[i]) 1458a07a949bSTakashi Iwai spec->multiout.num_dacs++; 1459a07a949bSTakashi Iwai else { 1460a07a949bSTakashi Iwai memmove(spec->private_dac_nids + i, 1461a07a949bSTakashi Iwai spec->private_dac_nids + i + 1, 1462a07a949bSTakashi Iwai sizeof(hda_nid_t) * (cfg->line_outs - i - 1)); 1463a07a949bSTakashi Iwai spec->private_dac_nids[cfg->line_outs - 1] = 0; 1464a07a949bSTakashi Iwai } 1465a07a949bSTakashi Iwai } 1466a07a949bSTakashi Iwai 1467a07a949bSTakashi Iwai spec->ext_channel_count = spec->min_channel_count = 1468c0f3b216SDavid Henningsson spec->multiout.num_dacs * 2; 1469a07a949bSTakashi Iwai 1470352f7f91STakashi Iwai if (spec->multi_ios == 2) { 1471352f7f91STakashi Iwai for (i = 0; i < 2; i++) 1472352f7f91STakashi Iwai spec->private_dac_nids[spec->multiout.num_dacs++] = 1473352f7f91STakashi Iwai spec->multi_io[i].dac; 1474352f7f91STakashi Iwai } else if (spec->multi_ios) { 1475352f7f91STakashi Iwai spec->multi_ios = 0; 1476352f7f91STakashi Iwai badness += BAD_MULTI_IO; 1477352f7f91STakashi Iwai } 1478352f7f91STakashi Iwai 1479a07a949bSTakashi Iwai /* re-fill the shared DAC for speaker / headphone */ 1480a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 1481a07a949bSTakashi Iwai refill_shared_dacs(codec, cfg->hp_outs, 1482a07a949bSTakashi Iwai spec->multiout.hp_out_nid, 1483a07a949bSTakashi Iwai spec->hp_paths); 1484a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 1485a07a949bSTakashi Iwai refill_shared_dacs(codec, cfg->speaker_outs, 1486a07a949bSTakashi Iwai spec->multiout.extra_out_nid, 1487a07a949bSTakashi Iwai spec->speaker_paths); 1488a07a949bSTakashi Iwai 14892c12c30dSTakashi Iwai /* set initial pinctl targets */ 1490ea46c3c8STakashi Iwai if (spec->prefer_hp_amp || cfg->line_out_type == AUTO_PIN_HP_OUT) 1491ea46c3c8STakashi Iwai val = PIN_HP; 1492ea46c3c8STakashi Iwai else 1493ea46c3c8STakashi Iwai val = PIN_OUT; 1494ea46c3c8STakashi Iwai set_pin_targets(codec, cfg->line_outs, cfg->line_out_pins, val); 14952c12c30dSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 14962c12c30dSTakashi Iwai set_pin_targets(codec, cfg->hp_outs, cfg->hp_pins, PIN_HP); 1497ea46c3c8STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1498ea46c3c8STakashi Iwai val = spec->prefer_hp_amp ? PIN_HP : PIN_OUT; 14992c12c30dSTakashi Iwai set_pin_targets(codec, cfg->speaker_outs, 1500ea46c3c8STakashi Iwai cfg->speaker_pins, val); 1501ea46c3c8STakashi Iwai } 15022c12c30dSTakashi Iwai 1503352f7f91STakashi Iwai return badness; 1504352f7f91STakashi Iwai } 1505352f7f91STakashi Iwai 1506352f7f91STakashi Iwai #define DEBUG_BADNESS 1507352f7f91STakashi Iwai 1508352f7f91STakashi Iwai #ifdef DEBUG_BADNESS 1509352f7f91STakashi Iwai #define debug_badness snd_printdd 1510352f7f91STakashi Iwai #else 1511352f7f91STakashi Iwai #define debug_badness(...) 1512352f7f91STakashi Iwai #endif 1513352f7f91STakashi Iwai 1514352f7f91STakashi Iwai static void debug_show_configs(struct hda_gen_spec *spec, struct auto_pin_cfg *cfg) 1515352f7f91STakashi Iwai { 1516352f7f91STakashi Iwai debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1517352f7f91STakashi Iwai cfg->line_out_pins[0], cfg->line_out_pins[1], 1518708122e8STakashi Iwai cfg->line_out_pins[2], cfg->line_out_pins[3], 1519352f7f91STakashi Iwai spec->multiout.dac_nids[0], 1520352f7f91STakashi Iwai spec->multiout.dac_nids[1], 1521352f7f91STakashi Iwai spec->multiout.dac_nids[2], 1522352f7f91STakashi Iwai spec->multiout.dac_nids[3]); 1523352f7f91STakashi Iwai if (spec->multi_ios > 0) 1524352f7f91STakashi Iwai debug_badness("multi_ios(%d) = %x/%x : %x/%x\n", 1525352f7f91STakashi Iwai spec->multi_ios, 1526352f7f91STakashi Iwai spec->multi_io[0].pin, spec->multi_io[1].pin, 1527352f7f91STakashi Iwai spec->multi_io[0].dac, spec->multi_io[1].dac); 1528352f7f91STakashi Iwai debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1529352f7f91STakashi Iwai cfg->hp_pins[0], cfg->hp_pins[1], 1530708122e8STakashi Iwai cfg->hp_pins[2], cfg->hp_pins[3], 1531352f7f91STakashi Iwai spec->multiout.hp_out_nid[0], 1532352f7f91STakashi Iwai spec->multiout.hp_out_nid[1], 1533352f7f91STakashi Iwai spec->multiout.hp_out_nid[2], 1534352f7f91STakashi Iwai spec->multiout.hp_out_nid[3]); 1535352f7f91STakashi Iwai debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1536352f7f91STakashi Iwai cfg->speaker_pins[0], cfg->speaker_pins[1], 1537352f7f91STakashi Iwai cfg->speaker_pins[2], cfg->speaker_pins[3], 1538352f7f91STakashi Iwai spec->multiout.extra_out_nid[0], 1539352f7f91STakashi Iwai spec->multiout.extra_out_nid[1], 1540352f7f91STakashi Iwai spec->multiout.extra_out_nid[2], 1541352f7f91STakashi Iwai spec->multiout.extra_out_nid[3]); 1542352f7f91STakashi Iwai } 1543352f7f91STakashi Iwai 1544352f7f91STakashi Iwai /* find all available DACs of the codec */ 1545352f7f91STakashi Iwai static void fill_all_dac_nids(struct hda_codec *codec) 1546352f7f91STakashi Iwai { 1547352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1548352f7f91STakashi Iwai int i; 1549352f7f91STakashi Iwai hda_nid_t nid = codec->start_nid; 1550352f7f91STakashi Iwai 1551352f7f91STakashi Iwai spec->num_all_dacs = 0; 1552352f7f91STakashi Iwai memset(spec->all_dacs, 0, sizeof(spec->all_dacs)); 1553352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) { 1554352f7f91STakashi Iwai if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT) 1555352f7f91STakashi Iwai continue; 1556352f7f91STakashi Iwai if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) { 1557352f7f91STakashi Iwai snd_printk(KERN_ERR "hda: Too many DACs!\n"); 1558352f7f91STakashi Iwai break; 1559352f7f91STakashi Iwai } 1560352f7f91STakashi Iwai spec->all_dacs[spec->num_all_dacs++] = nid; 1561352f7f91STakashi Iwai } 1562352f7f91STakashi Iwai } 1563352f7f91STakashi Iwai 1564352f7f91STakashi Iwai static int parse_output_paths(struct hda_codec *codec) 1565352f7f91STakashi Iwai { 1566352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1567352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1568352f7f91STakashi Iwai struct auto_pin_cfg *best_cfg; 1569352f7f91STakashi Iwai int best_badness = INT_MAX; 1570352f7f91STakashi Iwai int badness; 1571352f7f91STakashi Iwai bool fill_hardwired = true, fill_mio_first = true; 1572352f7f91STakashi Iwai bool best_wired = true, best_mio = true; 1573352f7f91STakashi Iwai bool hp_spk_swapped = false; 1574352f7f91STakashi Iwai 1575352f7f91STakashi Iwai best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL); 1576352f7f91STakashi Iwai if (!best_cfg) 1577352f7f91STakashi Iwai return -ENOMEM; 1578352f7f91STakashi Iwai *best_cfg = *cfg; 1579352f7f91STakashi Iwai 1580352f7f91STakashi Iwai for (;;) { 1581352f7f91STakashi Iwai badness = fill_and_eval_dacs(codec, fill_hardwired, 1582352f7f91STakashi Iwai fill_mio_first); 1583352f7f91STakashi Iwai if (badness < 0) { 1584352f7f91STakashi Iwai kfree(best_cfg); 1585352f7f91STakashi Iwai return badness; 1586352f7f91STakashi Iwai } 1587352f7f91STakashi Iwai debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n", 1588352f7f91STakashi Iwai cfg->line_out_type, fill_hardwired, fill_mio_first, 1589352f7f91STakashi Iwai badness); 1590352f7f91STakashi Iwai debug_show_configs(spec, cfg); 1591352f7f91STakashi Iwai if (badness < best_badness) { 1592352f7f91STakashi Iwai best_badness = badness; 1593352f7f91STakashi Iwai *best_cfg = *cfg; 1594352f7f91STakashi Iwai best_wired = fill_hardwired; 1595352f7f91STakashi Iwai best_mio = fill_mio_first; 1596352f7f91STakashi Iwai } 1597352f7f91STakashi Iwai if (!badness) 1598352f7f91STakashi Iwai break; 1599352f7f91STakashi Iwai fill_mio_first = !fill_mio_first; 1600352f7f91STakashi Iwai if (!fill_mio_first) 1601352f7f91STakashi Iwai continue; 1602352f7f91STakashi Iwai fill_hardwired = !fill_hardwired; 1603352f7f91STakashi Iwai if (!fill_hardwired) 1604352f7f91STakashi Iwai continue; 1605352f7f91STakashi Iwai if (hp_spk_swapped) 1606352f7f91STakashi Iwai break; 1607352f7f91STakashi Iwai hp_spk_swapped = true; 1608352f7f91STakashi Iwai if (cfg->speaker_outs > 0 && 1609352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) { 1610352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs; 1611352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins, 1612352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 1613352f7f91STakashi Iwai cfg->line_outs = cfg->speaker_outs; 1614352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->speaker_pins, 1615352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 1616352f7f91STakashi Iwai cfg->speaker_outs = 0; 1617352f7f91STakashi Iwai memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); 1618352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; 1619352f7f91STakashi Iwai fill_hardwired = true; 1620352f7f91STakashi Iwai continue; 1621352f7f91STakashi Iwai } 1622352f7f91STakashi Iwai if (cfg->hp_outs > 0 && 1623352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { 1624352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 1625352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 1626352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 1627352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs; 1628352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins, 1629352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 1630352f7f91STakashi Iwai cfg->hp_outs = 0; 1631352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 1632352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT; 1633352f7f91STakashi Iwai fill_hardwired = true; 1634352f7f91STakashi Iwai continue; 1635352f7f91STakashi Iwai } 1636352f7f91STakashi Iwai break; 1637352f7f91STakashi Iwai } 1638352f7f91STakashi Iwai 1639352f7f91STakashi Iwai if (badness) { 16400c8c0f56STakashi Iwai debug_badness("==> restoring best_cfg\n"); 1641352f7f91STakashi Iwai *cfg = *best_cfg; 1642352f7f91STakashi Iwai fill_and_eval_dacs(codec, best_wired, best_mio); 1643352f7f91STakashi Iwai } 1644352f7f91STakashi Iwai debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n", 1645352f7f91STakashi Iwai cfg->line_out_type, best_wired, best_mio); 1646352f7f91STakashi Iwai debug_show_configs(spec, cfg); 1647352f7f91STakashi Iwai 1648352f7f91STakashi Iwai if (cfg->line_out_pins[0]) { 1649352f7f91STakashi Iwai struct nid_path *path; 1650196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]); 1651352f7f91STakashi Iwai if (path) 1652352f7f91STakashi Iwai spec->vmaster_nid = look_for_out_vol_nid(codec, path); 16537a71bbf3STakashi Iwai if (spec->vmaster_nid) 16547a71bbf3STakashi Iwai snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, 16557a71bbf3STakashi Iwai HDA_OUTPUT, spec->vmaster_tlv); 1656352f7f91STakashi Iwai } 1657352f7f91STakashi Iwai 1658352f7f91STakashi Iwai kfree(best_cfg); 1659352f7f91STakashi Iwai return 0; 1660352f7f91STakashi Iwai } 1661352f7f91STakashi Iwai 1662352f7f91STakashi Iwai /* add playback controls from the parsed DAC table */ 1663352f7f91STakashi Iwai static int create_multi_out_ctls(struct hda_codec *codec, 1664352f7f91STakashi Iwai const struct auto_pin_cfg *cfg) 1665352f7f91STakashi Iwai { 1666352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1667352f7f91STakashi Iwai int i, err, noutputs; 1668352f7f91STakashi Iwai 1669352f7f91STakashi Iwai noutputs = cfg->line_outs; 1670352f7f91STakashi Iwai if (spec->multi_ios > 0 && cfg->line_outs < 3) 1671352f7f91STakashi Iwai noutputs += spec->multi_ios; 1672352f7f91STakashi Iwai 1673352f7f91STakashi Iwai for (i = 0; i < noutputs; i++) { 1674352f7f91STakashi Iwai const char *name; 1675352f7f91STakashi Iwai int index; 1676352f7f91STakashi Iwai struct nid_path *path; 1677352f7f91STakashi Iwai 1678196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]); 1679352f7f91STakashi Iwai if (!path) 1680352f7f91STakashi Iwai continue; 1681247d85eeSTakashi Iwai 1682247d85eeSTakashi Iwai name = get_line_out_pfx(codec, i, &index, NID_PATH_VOL_CTL); 1683352f7f91STakashi Iwai if (!name || !strcmp(name, "CLFE")) { 1684352f7f91STakashi Iwai /* Center/LFE */ 1685352f7f91STakashi Iwai err = add_vol_ctl(codec, "Center", 0, 1, path); 1686352f7f91STakashi Iwai if (err < 0) 1687352f7f91STakashi Iwai return err; 1688352f7f91STakashi Iwai err = add_vol_ctl(codec, "LFE", 0, 2, path); 1689352f7f91STakashi Iwai if (err < 0) 1690352f7f91STakashi Iwai return err; 1691247d85eeSTakashi Iwai } else { 1692247d85eeSTakashi Iwai err = add_stereo_vol(codec, name, index, path); 1693247d85eeSTakashi Iwai if (err < 0) 1694247d85eeSTakashi Iwai return err; 1695247d85eeSTakashi Iwai } 1696247d85eeSTakashi Iwai 1697247d85eeSTakashi Iwai name = get_line_out_pfx(codec, i, &index, NID_PATH_MUTE_CTL); 1698247d85eeSTakashi Iwai if (!name || !strcmp(name, "CLFE")) { 1699352f7f91STakashi Iwai err = add_sw_ctl(codec, "Center", 0, 1, path); 1700352f7f91STakashi Iwai if (err < 0) 1701352f7f91STakashi Iwai return err; 1702352f7f91STakashi Iwai err = add_sw_ctl(codec, "LFE", 0, 2, path); 1703352f7f91STakashi Iwai if (err < 0) 1704352f7f91STakashi Iwai return err; 1705352f7f91STakashi Iwai } else { 1706352f7f91STakashi Iwai err = add_stereo_sw(codec, name, index, path); 1707352f7f91STakashi Iwai if (err < 0) 1708352f7f91STakashi Iwai return err; 1709352f7f91STakashi Iwai } 1710352f7f91STakashi Iwai } 1711352f7f91STakashi Iwai return 0; 1712352f7f91STakashi Iwai } 1713352f7f91STakashi Iwai 1714c2c80383STakashi Iwai static int create_extra_out(struct hda_codec *codec, int path_idx, 1715196c1766STakashi Iwai const char *pfx, int cidx) 1716352f7f91STakashi Iwai { 1717352f7f91STakashi Iwai struct nid_path *path; 1718352f7f91STakashi Iwai int err; 1719352f7f91STakashi Iwai 1720196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 1721352f7f91STakashi Iwai if (!path) 1722352f7f91STakashi Iwai return 0; 1723352f7f91STakashi Iwai err = add_stereo_vol(codec, pfx, cidx, path); 1724352f7f91STakashi Iwai if (err < 0) 1725352f7f91STakashi Iwai return err; 1726352f7f91STakashi Iwai err = add_stereo_sw(codec, pfx, cidx, path); 1727352f7f91STakashi Iwai if (err < 0) 1728352f7f91STakashi Iwai return err; 1729352f7f91STakashi Iwai return 0; 1730352f7f91STakashi Iwai } 1731352f7f91STakashi Iwai 1732352f7f91STakashi Iwai /* add playback controls for speaker and HP outputs */ 1733352f7f91STakashi Iwai static int create_extra_outs(struct hda_codec *codec, int num_pins, 1734196c1766STakashi Iwai const int *paths, const char *pfx) 1735352f7f91STakashi Iwai { 1736c2c80383STakashi Iwai int i; 1737352f7f91STakashi Iwai 1738352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 1739c2c80383STakashi Iwai const char *name; 1740c2c80383STakashi Iwai char tmp[44]; 1741c2c80383STakashi Iwai int err, idx = 0; 1742c2c80383STakashi Iwai 1743c2c80383STakashi Iwai if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) 1744c2c80383STakashi Iwai name = "Bass Speaker"; 1745c2c80383STakashi Iwai else if (num_pins >= 3) { 1746c2c80383STakashi Iwai snprintf(tmp, sizeof(tmp), "%s %s", 1747352f7f91STakashi Iwai pfx, channel_name[i]); 1748c2c80383STakashi Iwai name = tmp; 1749352f7f91STakashi Iwai } else { 1750c2c80383STakashi Iwai name = pfx; 1751c2c80383STakashi Iwai idx = i; 1752352f7f91STakashi Iwai } 1753c2c80383STakashi Iwai err = create_extra_out(codec, paths[i], name, idx); 1754352f7f91STakashi Iwai if (err < 0) 1755352f7f91STakashi Iwai return err; 1756352f7f91STakashi Iwai } 1757352f7f91STakashi Iwai return 0; 1758352f7f91STakashi Iwai } 1759352f7f91STakashi Iwai 1760352f7f91STakashi Iwai static int create_hp_out_ctls(struct hda_codec *codec) 1761352f7f91STakashi Iwai { 1762352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1763352f7f91STakashi Iwai return create_extra_outs(codec, spec->autocfg.hp_outs, 1764196c1766STakashi Iwai spec->hp_paths, 1765352f7f91STakashi Iwai "Headphone"); 1766352f7f91STakashi Iwai } 1767352f7f91STakashi Iwai 1768352f7f91STakashi Iwai static int create_speaker_out_ctls(struct hda_codec *codec) 1769352f7f91STakashi Iwai { 1770352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1771352f7f91STakashi Iwai return create_extra_outs(codec, spec->autocfg.speaker_outs, 1772196c1766STakashi Iwai spec->speaker_paths, 1773352f7f91STakashi Iwai "Speaker"); 1774352f7f91STakashi Iwai } 1775352f7f91STakashi Iwai 1776352f7f91STakashi Iwai /* 177738cf6f1aSTakashi Iwai * independent HP controls 177838cf6f1aSTakashi Iwai */ 177938cf6f1aSTakashi Iwai 178038cf6f1aSTakashi Iwai static int indep_hp_info(struct snd_kcontrol *kcontrol, 178138cf6f1aSTakashi Iwai struct snd_ctl_elem_info *uinfo) 178238cf6f1aSTakashi Iwai { 178338cf6f1aSTakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo); 178438cf6f1aSTakashi Iwai } 178538cf6f1aSTakashi Iwai 178638cf6f1aSTakashi Iwai static int indep_hp_get(struct snd_kcontrol *kcontrol, 178738cf6f1aSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 178838cf6f1aSTakashi Iwai { 178938cf6f1aSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 179038cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 179138cf6f1aSTakashi Iwai ucontrol->value.enumerated.item[0] = spec->indep_hp_enabled; 179238cf6f1aSTakashi Iwai return 0; 179338cf6f1aSTakashi Iwai } 179438cf6f1aSTakashi Iwai 179538cf6f1aSTakashi Iwai static int indep_hp_put(struct snd_kcontrol *kcontrol, 179638cf6f1aSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 179738cf6f1aSTakashi Iwai { 179838cf6f1aSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 179938cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 180038cf6f1aSTakashi Iwai unsigned int select = ucontrol->value.enumerated.item[0]; 180138cf6f1aSTakashi Iwai int ret = 0; 180238cf6f1aSTakashi Iwai 180338cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 180438cf6f1aSTakashi Iwai if (spec->active_streams) { 180538cf6f1aSTakashi Iwai ret = -EBUSY; 180638cf6f1aSTakashi Iwai goto unlock; 180738cf6f1aSTakashi Iwai } 180838cf6f1aSTakashi Iwai 180938cf6f1aSTakashi Iwai if (spec->indep_hp_enabled != select) { 181038cf6f1aSTakashi Iwai spec->indep_hp_enabled = select; 181138cf6f1aSTakashi Iwai if (spec->indep_hp_enabled) 181238cf6f1aSTakashi Iwai spec->multiout.hp_out_nid[0] = 0; 181338cf6f1aSTakashi Iwai else 181438cf6f1aSTakashi Iwai spec->multiout.hp_out_nid[0] = spec->alt_dac_nid; 181538cf6f1aSTakashi Iwai ret = 1; 181638cf6f1aSTakashi Iwai } 181738cf6f1aSTakashi Iwai unlock: 181838cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 181938cf6f1aSTakashi Iwai return ret; 182038cf6f1aSTakashi Iwai } 182138cf6f1aSTakashi Iwai 182238cf6f1aSTakashi Iwai static const struct snd_kcontrol_new indep_hp_ctl = { 182338cf6f1aSTakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 182438cf6f1aSTakashi Iwai .name = "Independent HP", 182538cf6f1aSTakashi Iwai .info = indep_hp_info, 182638cf6f1aSTakashi Iwai .get = indep_hp_get, 182738cf6f1aSTakashi Iwai .put = indep_hp_put, 182838cf6f1aSTakashi Iwai }; 182938cf6f1aSTakashi Iwai 183038cf6f1aSTakashi Iwai 183138cf6f1aSTakashi Iwai static int create_indep_hp_ctls(struct hda_codec *codec) 183238cf6f1aSTakashi Iwai { 183338cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 183438cf6f1aSTakashi Iwai 183538cf6f1aSTakashi Iwai if (!spec->indep_hp) 183638cf6f1aSTakashi Iwai return 0; 183738cf6f1aSTakashi Iwai if (!spec->multiout.hp_out_nid[0]) { 183838cf6f1aSTakashi Iwai spec->indep_hp = 0; 183938cf6f1aSTakashi Iwai return 0; 184038cf6f1aSTakashi Iwai } 184138cf6f1aSTakashi Iwai 184238cf6f1aSTakashi Iwai spec->indep_hp_enabled = false; 184338cf6f1aSTakashi Iwai spec->alt_dac_nid = spec->multiout.hp_out_nid[0]; 184438cf6f1aSTakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl)) 184538cf6f1aSTakashi Iwai return -ENOMEM; 184638cf6f1aSTakashi Iwai return 0; 184738cf6f1aSTakashi Iwai } 184838cf6f1aSTakashi Iwai 184938cf6f1aSTakashi Iwai /* 1850352f7f91STakashi Iwai * channel mode enum control 1851352f7f91STakashi Iwai */ 1852352f7f91STakashi Iwai 1853352f7f91STakashi Iwai static int ch_mode_info(struct snd_kcontrol *kcontrol, 1854352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 1855352f7f91STakashi Iwai { 1856352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1857352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1858a07a949bSTakashi Iwai int chs; 1859352f7f91STakashi Iwai 1860352f7f91STakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 1861352f7f91STakashi Iwai uinfo->count = 1; 1862352f7f91STakashi Iwai uinfo->value.enumerated.items = spec->multi_ios + 1; 1863352f7f91STakashi Iwai if (uinfo->value.enumerated.item > spec->multi_ios) 1864352f7f91STakashi Iwai uinfo->value.enumerated.item = spec->multi_ios; 1865a07a949bSTakashi Iwai chs = uinfo->value.enumerated.item * 2 + spec->min_channel_count; 1866a07a949bSTakashi Iwai sprintf(uinfo->value.enumerated.name, "%dch", chs); 1867352f7f91STakashi Iwai return 0; 1868352f7f91STakashi Iwai } 1869352f7f91STakashi Iwai 1870352f7f91STakashi Iwai static int ch_mode_get(struct snd_kcontrol *kcontrol, 1871352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1872352f7f91STakashi Iwai { 1873352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1874352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1875a07a949bSTakashi Iwai ucontrol->value.enumerated.item[0] = 1876a07a949bSTakashi Iwai (spec->ext_channel_count - spec->min_channel_count) / 2; 1877352f7f91STakashi Iwai return 0; 1878352f7f91STakashi Iwai } 1879352f7f91STakashi Iwai 1880196c1766STakashi Iwai static inline struct nid_path * 1881196c1766STakashi Iwai get_multiio_path(struct hda_codec *codec, int idx) 1882196c1766STakashi Iwai { 1883196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1884196c1766STakashi Iwai return snd_hda_get_path_from_idx(codec, 1885196c1766STakashi Iwai spec->out_paths[spec->autocfg.line_outs + idx]); 1886196c1766STakashi Iwai } 1887196c1766STakashi Iwai 1888a5cc2509STakashi Iwai static void update_automute_all(struct hda_codec *codec); 1889a5cc2509STakashi Iwai 1890352f7f91STakashi Iwai static int set_multi_io(struct hda_codec *codec, int idx, bool output) 1891352f7f91STakashi Iwai { 1892352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1893352f7f91STakashi Iwai hda_nid_t nid = spec->multi_io[idx].pin; 1894352f7f91STakashi Iwai struct nid_path *path; 1895352f7f91STakashi Iwai 1896196c1766STakashi Iwai path = get_multiio_path(codec, idx); 1897352f7f91STakashi Iwai if (!path) 1898352f7f91STakashi Iwai return -EINVAL; 1899352f7f91STakashi Iwai 1900352f7f91STakashi Iwai if (path->active == output) 1901352f7f91STakashi Iwai return 0; 1902352f7f91STakashi Iwai 1903352f7f91STakashi Iwai if (output) { 19042c12c30dSTakashi Iwai set_pin_target(codec, nid, PIN_OUT, true); 1905352f7f91STakashi Iwai snd_hda_activate_path(codec, path, true, true); 1906d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, true); 1907352f7f91STakashi Iwai } else { 1908d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, false); 1909352f7f91STakashi Iwai snd_hda_activate_path(codec, path, false, true); 19102c12c30dSTakashi Iwai set_pin_target(codec, nid, spec->multi_io[idx].ctl_in, true); 1911352f7f91STakashi Iwai } 1912a365fed9STakashi Iwai 1913a365fed9STakashi Iwai /* update jack retasking in case it modifies any of them */ 1914a5cc2509STakashi Iwai update_automute_all(codec); 1915a365fed9STakashi Iwai 1916352f7f91STakashi Iwai return 0; 1917352f7f91STakashi Iwai } 1918352f7f91STakashi Iwai 1919352f7f91STakashi Iwai static int ch_mode_put(struct snd_kcontrol *kcontrol, 1920352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1921352f7f91STakashi Iwai { 1922352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1923352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1924352f7f91STakashi Iwai int i, ch; 1925352f7f91STakashi Iwai 1926352f7f91STakashi Iwai ch = ucontrol->value.enumerated.item[0]; 1927352f7f91STakashi Iwai if (ch < 0 || ch > spec->multi_ios) 1928352f7f91STakashi Iwai return -EINVAL; 1929a07a949bSTakashi Iwai if (ch == (spec->ext_channel_count - spec->min_channel_count) / 2) 1930352f7f91STakashi Iwai return 0; 1931a07a949bSTakashi Iwai spec->ext_channel_count = ch * 2 + spec->min_channel_count; 1932352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++) 1933352f7f91STakashi Iwai set_multi_io(codec, i, i < ch); 1934352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count, 1935352f7f91STakashi Iwai spec->const_channel_count); 1936352f7f91STakashi Iwai if (spec->need_dac_fix) 1937352f7f91STakashi Iwai spec->multiout.num_dacs = spec->multiout.max_channels / 2; 1938352f7f91STakashi Iwai return 1; 1939352f7f91STakashi Iwai } 1940352f7f91STakashi Iwai 1941352f7f91STakashi Iwai static const struct snd_kcontrol_new channel_mode_enum = { 1942352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1943352f7f91STakashi Iwai .name = "Channel Mode", 1944352f7f91STakashi Iwai .info = ch_mode_info, 1945352f7f91STakashi Iwai .get = ch_mode_get, 1946352f7f91STakashi Iwai .put = ch_mode_put, 1947352f7f91STakashi Iwai }; 1948352f7f91STakashi Iwai 1949352f7f91STakashi Iwai static int create_multi_channel_mode(struct hda_codec *codec) 1950352f7f91STakashi Iwai { 1951352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1952352f7f91STakashi Iwai 1953352f7f91STakashi Iwai if (spec->multi_ios > 0) { 195412c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &channel_mode_enum)) 1955352f7f91STakashi Iwai return -ENOMEM; 1956352f7f91STakashi Iwai } 1957352f7f91STakashi Iwai return 0; 1958352f7f91STakashi Iwai } 1959352f7f91STakashi Iwai 1960352f7f91STakashi Iwai /* 1961c30aa7b2STakashi Iwai * aamix loopback enable/disable switch 1962c30aa7b2STakashi Iwai */ 1963c30aa7b2STakashi Iwai 1964c30aa7b2STakashi Iwai #define loopback_mixing_info indep_hp_info 1965c30aa7b2STakashi Iwai 1966c30aa7b2STakashi Iwai static int loopback_mixing_get(struct snd_kcontrol *kcontrol, 1967c30aa7b2STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1968c30aa7b2STakashi Iwai { 1969c30aa7b2STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1970c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1971c30aa7b2STakashi Iwai ucontrol->value.enumerated.item[0] = spec->aamix_mode; 1972c30aa7b2STakashi Iwai return 0; 1973c30aa7b2STakashi Iwai } 1974c30aa7b2STakashi Iwai 1975c30aa7b2STakashi Iwai static void update_aamix_paths(struct hda_codec *codec, bool do_mix, 1976c30aa7b2STakashi Iwai int nomix_path_idx, int mix_path_idx) 1977c30aa7b2STakashi Iwai { 1978c30aa7b2STakashi Iwai struct nid_path *nomix_path, *mix_path; 1979c30aa7b2STakashi Iwai 1980c30aa7b2STakashi Iwai nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx); 1981c30aa7b2STakashi Iwai mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx); 1982c30aa7b2STakashi Iwai if (!nomix_path || !mix_path) 1983c30aa7b2STakashi Iwai return; 1984c30aa7b2STakashi Iwai if (do_mix) { 1985c30aa7b2STakashi Iwai snd_hda_activate_path(codec, nomix_path, false, true); 1986c30aa7b2STakashi Iwai snd_hda_activate_path(codec, mix_path, true, true); 1987c30aa7b2STakashi Iwai } else { 1988c30aa7b2STakashi Iwai snd_hda_activate_path(codec, mix_path, false, true); 1989c30aa7b2STakashi Iwai snd_hda_activate_path(codec, nomix_path, true, true); 1990c30aa7b2STakashi Iwai } 1991c30aa7b2STakashi Iwai } 1992c30aa7b2STakashi Iwai 1993c30aa7b2STakashi Iwai static int loopback_mixing_put(struct snd_kcontrol *kcontrol, 1994c30aa7b2STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1995c30aa7b2STakashi Iwai { 1996c30aa7b2STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1997c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1998c30aa7b2STakashi Iwai unsigned int val = ucontrol->value.enumerated.item[0]; 1999c30aa7b2STakashi Iwai 2000c30aa7b2STakashi Iwai if (val == spec->aamix_mode) 2001c30aa7b2STakashi Iwai return 0; 2002c30aa7b2STakashi Iwai spec->aamix_mode = val; 2003c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->out_paths[0], 2004c30aa7b2STakashi Iwai spec->aamix_out_paths[0]); 2005c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->hp_paths[0], 2006c30aa7b2STakashi Iwai spec->aamix_out_paths[1]); 2007c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->speaker_paths[0], 2008c30aa7b2STakashi Iwai spec->aamix_out_paths[2]); 2009c30aa7b2STakashi Iwai return 1; 2010c30aa7b2STakashi Iwai } 2011c30aa7b2STakashi Iwai 2012c30aa7b2STakashi Iwai static const struct snd_kcontrol_new loopback_mixing_enum = { 2013c30aa7b2STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2014c30aa7b2STakashi Iwai .name = "Loopback Mixing", 2015c30aa7b2STakashi Iwai .info = loopback_mixing_info, 2016c30aa7b2STakashi Iwai .get = loopback_mixing_get, 2017c30aa7b2STakashi Iwai .put = loopback_mixing_put, 2018c30aa7b2STakashi Iwai }; 2019c30aa7b2STakashi Iwai 2020c30aa7b2STakashi Iwai static int create_loopback_mixing_ctl(struct hda_codec *codec) 2021c30aa7b2STakashi Iwai { 2022c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2023c30aa7b2STakashi Iwai 2024c30aa7b2STakashi Iwai if (!spec->mixer_nid) 2025c30aa7b2STakashi Iwai return 0; 2026c30aa7b2STakashi Iwai if (!(spec->aamix_out_paths[0] || spec->aamix_out_paths[1] || 2027c30aa7b2STakashi Iwai spec->aamix_out_paths[2])) 2028c30aa7b2STakashi Iwai return 0; 2029c30aa7b2STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum)) 2030c30aa7b2STakashi Iwai return -ENOMEM; 2031c30aa7b2STakashi Iwai return 0; 2032c30aa7b2STakashi Iwai } 2033c30aa7b2STakashi Iwai 2034c30aa7b2STakashi Iwai /* 2035352f7f91STakashi Iwai * shared headphone/mic handling 2036352f7f91STakashi Iwai */ 2037352f7f91STakashi Iwai 2038352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec); 2039352f7f91STakashi Iwai 2040352f7f91STakashi Iwai /* for shared I/O, change the pin-control accordingly */ 2041352f7f91STakashi Iwai static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic) 2042352f7f91STakashi Iwai { 2043352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2044352f7f91STakashi Iwai unsigned int val; 2045352f7f91STakashi Iwai hda_nid_t pin = spec->autocfg.inputs[1].pin; 2046352f7f91STakashi Iwai /* NOTE: this assumes that there are only two inputs, the 2047352f7f91STakashi Iwai * first is the real internal mic and the second is HP/mic jack. 2048352f7f91STakashi Iwai */ 2049352f7f91STakashi Iwai 2050352f7f91STakashi Iwai val = snd_hda_get_default_vref(codec, pin); 2051352f7f91STakashi Iwai 2052352f7f91STakashi Iwai /* This pin does not have vref caps - let's enable vref on pin 0x18 2053352f7f91STakashi Iwai instead, as suggested by Realtek */ 2054352f7f91STakashi Iwai if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) { 2055352f7f91STakashi Iwai const hda_nid_t vref_pin = spec->shared_mic_vref_pin; 2056352f7f91STakashi Iwai unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin); 2057352f7f91STakashi Iwai if (vref_val != AC_PINCTL_VREF_HIZ) 20587594aa33STakashi Iwai snd_hda_set_pin_ctl_cache(codec, vref_pin, 20597594aa33STakashi Iwai PIN_IN | (set_as_mic ? vref_val : 0)); 2060352f7f91STakashi Iwai } 2061352f7f91STakashi Iwai 2062352f7f91STakashi Iwai val = set_as_mic ? val | PIN_IN : PIN_HP; 20632c12c30dSTakashi Iwai set_pin_target(codec, pin, val, true); 2064352f7f91STakashi Iwai 2065352f7f91STakashi Iwai spec->automute_speaker = !set_as_mic; 2066352f7f91STakashi Iwai call_update_outputs(codec); 2067352f7f91STakashi Iwai } 2068352f7f91STakashi Iwai 2069352f7f91STakashi Iwai /* create a shared input with the headphone out */ 2070352f7f91STakashi Iwai static int create_shared_input(struct hda_codec *codec) 2071352f7f91STakashi Iwai { 2072352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2073352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 2074352f7f91STakashi Iwai unsigned int defcfg; 2075352f7f91STakashi Iwai hda_nid_t nid; 2076352f7f91STakashi Iwai 2077352f7f91STakashi Iwai /* only one internal input pin? */ 2078352f7f91STakashi Iwai if (cfg->num_inputs != 1) 2079352f7f91STakashi Iwai return 0; 2080352f7f91STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); 2081352f7f91STakashi Iwai if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) 2082352f7f91STakashi Iwai return 0; 2083352f7f91STakashi Iwai 2084352f7f91STakashi Iwai if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) 2085352f7f91STakashi Iwai nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */ 2086352f7f91STakashi Iwai else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT) 2087352f7f91STakashi Iwai nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */ 2088352f7f91STakashi Iwai else 2089352f7f91STakashi Iwai return 0; /* both not available */ 2090352f7f91STakashi Iwai 2091352f7f91STakashi Iwai if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN)) 2092352f7f91STakashi Iwai return 0; /* no input */ 2093352f7f91STakashi Iwai 2094352f7f91STakashi Iwai cfg->inputs[1].pin = nid; 2095352f7f91STakashi Iwai cfg->inputs[1].type = AUTO_PIN_MIC; 2096352f7f91STakashi Iwai cfg->num_inputs = 2; 2097352f7f91STakashi Iwai spec->shared_mic_hp = 1; 2098352f7f91STakashi Iwai snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid); 2099352f7f91STakashi Iwai return 0; 2100352f7f91STakashi Iwai } 2101352f7f91STakashi Iwai 2102978e77e7STakashi Iwai /* 2103978e77e7STakashi Iwai * output jack mode 2104978e77e7STakashi Iwai */ 2105978e77e7STakashi Iwai static int out_jack_mode_info(struct snd_kcontrol *kcontrol, 2106978e77e7STakashi Iwai struct snd_ctl_elem_info *uinfo) 2107978e77e7STakashi Iwai { 2108978e77e7STakashi Iwai static const char * const texts[] = { 2109978e77e7STakashi Iwai "Line Out", "Headphone Out", 2110978e77e7STakashi Iwai }; 2111978e77e7STakashi Iwai return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts); 2112978e77e7STakashi Iwai } 2113978e77e7STakashi Iwai 2114978e77e7STakashi Iwai static int out_jack_mode_get(struct snd_kcontrol *kcontrol, 2115978e77e7STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2116978e77e7STakashi Iwai { 2117978e77e7STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2118978e77e7STakashi Iwai hda_nid_t nid = kcontrol->private_value; 2119978e77e7STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) == PIN_HP) 2120978e77e7STakashi Iwai ucontrol->value.enumerated.item[0] = 1; 2121978e77e7STakashi Iwai else 2122978e77e7STakashi Iwai ucontrol->value.enumerated.item[0] = 0; 2123978e77e7STakashi Iwai return 0; 2124978e77e7STakashi Iwai } 2125978e77e7STakashi Iwai 2126978e77e7STakashi Iwai static int out_jack_mode_put(struct snd_kcontrol *kcontrol, 2127978e77e7STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2128978e77e7STakashi Iwai { 2129978e77e7STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2130978e77e7STakashi Iwai hda_nid_t nid = kcontrol->private_value; 2131978e77e7STakashi Iwai unsigned int val; 2132978e77e7STakashi Iwai 2133978e77e7STakashi Iwai val = ucontrol->value.enumerated.item[0] ? PIN_HP : PIN_OUT; 2134978e77e7STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) == val) 2135978e77e7STakashi Iwai return 0; 2136978e77e7STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, val); 2137978e77e7STakashi Iwai return 1; 2138978e77e7STakashi Iwai } 2139978e77e7STakashi Iwai 2140978e77e7STakashi Iwai static const struct snd_kcontrol_new out_jack_mode_enum = { 2141978e77e7STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2142978e77e7STakashi Iwai .info = out_jack_mode_info, 2143978e77e7STakashi Iwai .get = out_jack_mode_get, 2144978e77e7STakashi Iwai .put = out_jack_mode_put, 2145978e77e7STakashi Iwai }; 2146978e77e7STakashi Iwai 2147978e77e7STakashi Iwai static bool find_kctl_name(struct hda_codec *codec, const char *name, int idx) 2148978e77e7STakashi Iwai { 2149978e77e7STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2150978e77e7STakashi Iwai int i; 2151978e77e7STakashi Iwai 2152978e77e7STakashi Iwai for (i = 0; i < spec->kctls.used; i++) { 2153978e77e7STakashi Iwai struct snd_kcontrol_new *kctl = snd_array_elem(&spec->kctls, i); 2154978e77e7STakashi Iwai if (!strcmp(kctl->name, name) && kctl->index == idx) 2155978e77e7STakashi Iwai return true; 2156978e77e7STakashi Iwai } 2157978e77e7STakashi Iwai return false; 2158978e77e7STakashi Iwai } 2159978e77e7STakashi Iwai 2160978e77e7STakashi Iwai static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin, 2161978e77e7STakashi Iwai char *name, size_t name_len) 2162978e77e7STakashi Iwai { 2163978e77e7STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2164978e77e7STakashi Iwai int idx = 0; 2165978e77e7STakashi Iwai 2166978e77e7STakashi Iwai snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len, &idx); 2167978e77e7STakashi Iwai strlcat(name, " Jack Mode", name_len); 2168978e77e7STakashi Iwai 2169978e77e7STakashi Iwai for (; find_kctl_name(codec, name, idx); idx++) 2170978e77e7STakashi Iwai ; 2171978e77e7STakashi Iwai } 2172978e77e7STakashi Iwai 2173978e77e7STakashi Iwai static int create_out_jack_modes(struct hda_codec *codec, int num_pins, 2174978e77e7STakashi Iwai hda_nid_t *pins) 2175978e77e7STakashi Iwai { 2176978e77e7STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2177978e77e7STakashi Iwai int i; 2178978e77e7STakashi Iwai 2179978e77e7STakashi Iwai for (i = 0; i < num_pins; i++) { 2180978e77e7STakashi Iwai hda_nid_t pin = pins[i]; 2181978e77e7STakashi Iwai unsigned int pincap = snd_hda_query_pin_caps(codec, pin); 2182978e77e7STakashi Iwai if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV)) { 2183978e77e7STakashi Iwai struct snd_kcontrol_new *knew; 2184978e77e7STakashi Iwai char name[44]; 2185978e77e7STakashi Iwai get_jack_mode_name(codec, pin, name, sizeof(name)); 2186978e77e7STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, 2187978e77e7STakashi Iwai &out_jack_mode_enum); 2188978e77e7STakashi Iwai if (!knew) 2189978e77e7STakashi Iwai return -ENOMEM; 2190978e77e7STakashi Iwai knew->private_value = pin; 2191978e77e7STakashi Iwai } 2192978e77e7STakashi Iwai } 2193978e77e7STakashi Iwai 2194978e77e7STakashi Iwai return 0; 2195978e77e7STakashi Iwai } 2196978e77e7STakashi Iwai 219729476558STakashi Iwai /* 219829476558STakashi Iwai * input jack mode 219929476558STakashi Iwai */ 220029476558STakashi Iwai 220129476558STakashi Iwai /* from AC_PINCTL_VREF_HIZ to AC_PINCTL_VREF_100 */ 220229476558STakashi Iwai #define NUM_VREFS 6 220329476558STakashi Iwai 220429476558STakashi Iwai static const char * const vref_texts[NUM_VREFS] = { 220529476558STakashi Iwai "Line In", "Mic 50pc Bias", "Mic 0V Bias", 220629476558STakashi Iwai "", "Mic 80pc Bias", "Mic 100pc Bias" 220729476558STakashi Iwai }; 220829476558STakashi Iwai 220929476558STakashi Iwai static unsigned int get_vref_caps(struct hda_codec *codec, hda_nid_t pin) 221029476558STakashi Iwai { 221129476558STakashi Iwai unsigned int pincap; 221229476558STakashi Iwai 221329476558STakashi Iwai pincap = snd_hda_query_pin_caps(codec, pin); 221429476558STakashi Iwai pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; 221529476558STakashi Iwai /* filter out unusual vrefs */ 221629476558STakashi Iwai pincap &= ~(AC_PINCAP_VREF_GRD | AC_PINCAP_VREF_100); 221729476558STakashi Iwai return pincap; 221829476558STakashi Iwai } 221929476558STakashi Iwai 222029476558STakashi Iwai /* convert from the enum item index to the vref ctl index (0=HIZ, 1=50%...) */ 222129476558STakashi Iwai static int get_vref_idx(unsigned int vref_caps, unsigned int item_idx) 222229476558STakashi Iwai { 222329476558STakashi Iwai unsigned int i, n = 0; 222429476558STakashi Iwai 222529476558STakashi Iwai for (i = 0; i < NUM_VREFS; i++) { 222629476558STakashi Iwai if (vref_caps & (1 << i)) { 222729476558STakashi Iwai if (n == item_idx) 222829476558STakashi Iwai return i; 222929476558STakashi Iwai n++; 223029476558STakashi Iwai } 223129476558STakashi Iwai } 223229476558STakashi Iwai return 0; 223329476558STakashi Iwai } 223429476558STakashi Iwai 223529476558STakashi Iwai /* convert back from the vref ctl index to the enum item index */ 223629476558STakashi Iwai static int cvt_from_vref_idx(unsigned int vref_caps, unsigned int idx) 223729476558STakashi Iwai { 223829476558STakashi Iwai unsigned int i, n = 0; 223929476558STakashi Iwai 224029476558STakashi Iwai for (i = 0; i < NUM_VREFS; i++) { 224129476558STakashi Iwai if (i == idx) 224229476558STakashi Iwai return n; 224329476558STakashi Iwai if (vref_caps & (1 << i)) 224429476558STakashi Iwai n++; 224529476558STakashi Iwai } 224629476558STakashi Iwai return 0; 224729476558STakashi Iwai } 224829476558STakashi Iwai 224929476558STakashi Iwai static int in_jack_mode_info(struct snd_kcontrol *kcontrol, 225029476558STakashi Iwai struct snd_ctl_elem_info *uinfo) 225129476558STakashi Iwai { 225229476558STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 225329476558STakashi Iwai hda_nid_t nid = kcontrol->private_value; 225429476558STakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid); 225529476558STakashi Iwai 225629476558STakashi Iwai snd_hda_enum_helper_info(kcontrol, uinfo, hweight32(vref_caps), 225729476558STakashi Iwai vref_texts); 225829476558STakashi Iwai /* set the right text */ 225929476558STakashi Iwai strcpy(uinfo->value.enumerated.name, 226029476558STakashi Iwai vref_texts[get_vref_idx(vref_caps, uinfo->value.enumerated.item)]); 226129476558STakashi Iwai return 0; 226229476558STakashi Iwai } 226329476558STakashi Iwai 226429476558STakashi Iwai static int in_jack_mode_get(struct snd_kcontrol *kcontrol, 226529476558STakashi Iwai struct snd_ctl_elem_value *ucontrol) 226629476558STakashi Iwai { 226729476558STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 226829476558STakashi Iwai hda_nid_t nid = kcontrol->private_value; 226929476558STakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid); 227029476558STakashi Iwai unsigned int idx; 227129476558STakashi Iwai 227229476558STakashi Iwai idx = snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_VREFEN; 227329476558STakashi Iwai ucontrol->value.enumerated.item[0] = cvt_from_vref_idx(vref_caps, idx); 227429476558STakashi Iwai return 0; 227529476558STakashi Iwai } 227629476558STakashi Iwai 227729476558STakashi Iwai static int in_jack_mode_put(struct snd_kcontrol *kcontrol, 227829476558STakashi Iwai struct snd_ctl_elem_value *ucontrol) 227929476558STakashi Iwai { 228029476558STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 228129476558STakashi Iwai hda_nid_t nid = kcontrol->private_value; 228229476558STakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid); 228329476558STakashi Iwai unsigned int val, idx; 228429476558STakashi Iwai 228529476558STakashi Iwai val = snd_hda_codec_get_pin_target(codec, nid); 228629476558STakashi Iwai idx = cvt_from_vref_idx(vref_caps, val & AC_PINCTL_VREFEN); 228729476558STakashi Iwai if (idx == ucontrol->value.enumerated.item[0]) 228829476558STakashi Iwai return 0; 228929476558STakashi Iwai 229029476558STakashi Iwai val &= ~AC_PINCTL_VREFEN; 229129476558STakashi Iwai val |= get_vref_idx(vref_caps, ucontrol->value.enumerated.item[0]); 229229476558STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, val); 229329476558STakashi Iwai return 1; 229429476558STakashi Iwai } 229529476558STakashi Iwai 229629476558STakashi Iwai static const struct snd_kcontrol_new in_jack_mode_enum = { 229729476558STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 229829476558STakashi Iwai .info = in_jack_mode_info, 229929476558STakashi Iwai .get = in_jack_mode_get, 230029476558STakashi Iwai .put = in_jack_mode_put, 230129476558STakashi Iwai }; 230229476558STakashi Iwai 230329476558STakashi Iwai static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin) 230429476558STakashi Iwai { 230529476558STakashi Iwai struct hda_gen_spec *spec = codec->spec; 230629476558STakashi Iwai unsigned int defcfg; 230729476558STakashi Iwai struct snd_kcontrol_new *knew; 230829476558STakashi Iwai char name[44]; 230929476558STakashi Iwai 231029476558STakashi Iwai /* no jack mode for fixed pins */ 231129476558STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, pin); 231229476558STakashi Iwai if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT) 231329476558STakashi Iwai return 0; 231429476558STakashi Iwai 231529476558STakashi Iwai /* no multiple vref caps? */ 231629476558STakashi Iwai if (hweight32(get_vref_caps(codec, pin)) <= 1) 231729476558STakashi Iwai return 0; 231829476558STakashi Iwai 231929476558STakashi Iwai get_jack_mode_name(codec, pin, name, sizeof(name)); 232029476558STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &in_jack_mode_enum); 232129476558STakashi Iwai if (!knew) 232229476558STakashi Iwai return -ENOMEM; 232329476558STakashi Iwai knew->private_value = pin; 232429476558STakashi Iwai return 0; 232529476558STakashi Iwai } 232629476558STakashi Iwai 2327352f7f91STakashi Iwai 2328352f7f91STakashi Iwai /* 2329352f7f91STakashi Iwai * Parse input paths 2330352f7f91STakashi Iwai */ 2331352f7f91STakashi Iwai 2332352f7f91STakashi Iwai #ifdef CONFIG_PM 2333352f7f91STakashi Iwai /* add the powersave loopback-list entry */ 2334352f7f91STakashi Iwai static void add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx) 2335352f7f91STakashi Iwai { 2336352f7f91STakashi Iwai struct hda_amp_list *list; 2337352f7f91STakashi Iwai 2338352f7f91STakashi Iwai if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1) 2339352f7f91STakashi Iwai return; 2340352f7f91STakashi Iwai list = spec->loopback_list + spec->num_loopbacks; 2341352f7f91STakashi Iwai list->nid = mix; 2342352f7f91STakashi Iwai list->dir = HDA_INPUT; 2343352f7f91STakashi Iwai list->idx = idx; 2344352f7f91STakashi Iwai spec->num_loopbacks++; 2345cb53c626STakashi Iwai spec->loopback.amplist = spec->loopback_list; 2346cb53c626STakashi Iwai } 2347cb53c626STakashi Iwai #else 2348352f7f91STakashi Iwai #define add_loopback_list(spec, mix, idx) /* NOP */ 2349cb53c626STakashi Iwai #endif 2350cb53c626STakashi Iwai 2351352f7f91STakashi Iwai /* create input playback/capture controls for the given pin */ 2352196c1766STakashi Iwai static int new_analog_input(struct hda_codec *codec, int input_idx, 2353196c1766STakashi Iwai hda_nid_t pin, const char *ctlname, int ctlidx, 2354352f7f91STakashi Iwai hda_nid_t mix_nid) 23551da177e4SLinus Torvalds { 2356352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2357352f7f91STakashi Iwai struct nid_path *path; 2358352f7f91STakashi Iwai unsigned int val; 2359352f7f91STakashi Iwai int err, idx; 23601da177e4SLinus Torvalds 2361352f7f91STakashi Iwai if (!nid_has_volume(codec, mix_nid, HDA_INPUT) && 2362352f7f91STakashi Iwai !nid_has_mute(codec, mix_nid, HDA_INPUT)) 2363352f7f91STakashi Iwai return 0; /* no need for analog loopback */ 2364352f7f91STakashi Iwai 23653ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, pin, mix_nid, 0); 2366352f7f91STakashi Iwai if (!path) 2367352f7f91STakashi Iwai return -EINVAL; 23680c8c0f56STakashi Iwai print_nid_path("loopback", path); 2369196c1766STakashi Iwai spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path); 2370352f7f91STakashi Iwai 2371352f7f91STakashi Iwai idx = path->idx[path->depth - 1]; 2372352f7f91STakashi Iwai if (nid_has_volume(codec, mix_nid, HDA_INPUT)) { 2373352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); 2374352f7f91STakashi Iwai err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, val); 2375d13bd412STakashi Iwai if (err < 0) 23761da177e4SLinus Torvalds return err; 2377352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = val; 23781da177e4SLinus Torvalds } 23791da177e4SLinus Torvalds 2380352f7f91STakashi Iwai if (nid_has_mute(codec, mix_nid, HDA_INPUT)) { 2381352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); 2382352f7f91STakashi Iwai err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, val); 2383d13bd412STakashi Iwai if (err < 0) 23841da177e4SLinus Torvalds return err; 2385352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = val; 23861da177e4SLinus Torvalds } 23871da177e4SLinus Torvalds 2388352f7f91STakashi Iwai path->active = true; 2389352f7f91STakashi Iwai add_loopback_list(spec, mix_nid, idx); 2390352f7f91STakashi Iwai return 0; 23911da177e4SLinus Torvalds } 23921da177e4SLinus Torvalds 2393352f7f91STakashi Iwai static int is_input_pin(struct hda_codec *codec, hda_nid_t nid) 23941da177e4SLinus Torvalds { 2395352f7f91STakashi Iwai unsigned int pincap = snd_hda_query_pin_caps(codec, nid); 2396352f7f91STakashi Iwai return (pincap & AC_PINCAP_IN) != 0; 2397352f7f91STakashi Iwai } 2398352f7f91STakashi Iwai 2399352f7f91STakashi Iwai /* Parse the codec tree and retrieve ADCs */ 2400352f7f91STakashi Iwai static int fill_adc_nids(struct hda_codec *codec) 2401352f7f91STakashi Iwai { 2402352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2403352f7f91STakashi Iwai hda_nid_t nid; 2404352f7f91STakashi Iwai hda_nid_t *adc_nids = spec->adc_nids; 2405352f7f91STakashi Iwai int max_nums = ARRAY_SIZE(spec->adc_nids); 2406352f7f91STakashi Iwai int i, nums = 0; 2407352f7f91STakashi Iwai 2408352f7f91STakashi Iwai nid = codec->start_nid; 2409352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) { 2410352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 2411352f7f91STakashi Iwai int type = get_wcaps_type(caps); 2412352f7f91STakashi Iwai 2413352f7f91STakashi Iwai if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL)) 2414352f7f91STakashi Iwai continue; 2415352f7f91STakashi Iwai adc_nids[nums] = nid; 2416352f7f91STakashi Iwai if (++nums >= max_nums) 2417352f7f91STakashi Iwai break; 2418352f7f91STakashi Iwai } 2419352f7f91STakashi Iwai spec->num_adc_nids = nums; 24200ffd534eSTakashi Iwai 24210ffd534eSTakashi Iwai /* copy the detected ADCs to all_adcs[] */ 24220ffd534eSTakashi Iwai spec->num_all_adcs = nums; 24230ffd534eSTakashi Iwai memcpy(spec->all_adcs, spec->adc_nids, nums * sizeof(hda_nid_t)); 24240ffd534eSTakashi Iwai 2425352f7f91STakashi Iwai return nums; 2426352f7f91STakashi Iwai } 2427352f7f91STakashi Iwai 2428352f7f91STakashi Iwai /* filter out invalid adc_nids that don't give all active input pins; 2429352f7f91STakashi Iwai * if needed, check whether dynamic ADC-switching is available 2430352f7f91STakashi Iwai */ 2431352f7f91STakashi Iwai static int check_dyn_adc_switch(struct hda_codec *codec) 2432352f7f91STakashi Iwai { 2433352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2434352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 24353a65bcdcSTakashi Iwai unsigned int ok_bits; 2436352f7f91STakashi Iwai int i, n, nums; 2437352f7f91STakashi Iwai 2438352f7f91STakashi Iwai again: 2439352f7f91STakashi Iwai nums = 0; 24403a65bcdcSTakashi Iwai ok_bits = 0; 2441352f7f91STakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 2442352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 24433a65bcdcSTakashi Iwai if (!spec->input_paths[i][n]) 2444352f7f91STakashi Iwai break; 2445352f7f91STakashi Iwai } 24463a65bcdcSTakashi Iwai if (i >= imux->num_items) { 24473a65bcdcSTakashi Iwai ok_bits |= (1 << n); 24483a65bcdcSTakashi Iwai nums++; 24493a65bcdcSTakashi Iwai } 2450352f7f91STakashi Iwai } 2451352f7f91STakashi Iwai 24523a65bcdcSTakashi Iwai if (!ok_bits) { 2453352f7f91STakashi Iwai if (spec->shared_mic_hp) { 2454352f7f91STakashi Iwai spec->shared_mic_hp = 0; 2455352f7f91STakashi Iwai imux->num_items = 1; 2456352f7f91STakashi Iwai goto again; 2457352f7f91STakashi Iwai } 2458352f7f91STakashi Iwai 2459352f7f91STakashi Iwai /* check whether ADC-switch is possible */ 2460352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2461352f7f91STakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 24623a65bcdcSTakashi Iwai if (spec->input_paths[i][n]) { 2463352f7f91STakashi Iwai spec->dyn_adc_idx[i] = n; 2464352f7f91STakashi Iwai break; 2465352f7f91STakashi Iwai } 2466352f7f91STakashi Iwai } 2467352f7f91STakashi Iwai } 2468352f7f91STakashi Iwai 2469352f7f91STakashi Iwai snd_printdd("hda-codec: enabling ADC switching\n"); 2470352f7f91STakashi Iwai spec->dyn_adc_switch = 1; 2471352f7f91STakashi Iwai } else if (nums != spec->num_adc_nids) { 24723a65bcdcSTakashi Iwai /* shrink the invalid adcs and input paths */ 24733a65bcdcSTakashi Iwai nums = 0; 24743a65bcdcSTakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 24753a65bcdcSTakashi Iwai if (!(ok_bits & (1 << n))) 24763a65bcdcSTakashi Iwai continue; 24773a65bcdcSTakashi Iwai if (n != nums) { 24783a65bcdcSTakashi Iwai spec->adc_nids[nums] = spec->adc_nids[n]; 2479980428ceSTakashi Iwai for (i = 0; i < imux->num_items; i++) { 2480980428ceSTakashi Iwai invalidate_nid_path(codec, 2481980428ceSTakashi Iwai spec->input_paths[i][nums]); 24823a65bcdcSTakashi Iwai spec->input_paths[i][nums] = 24833a65bcdcSTakashi Iwai spec->input_paths[i][n]; 24843a65bcdcSTakashi Iwai } 2485980428ceSTakashi Iwai } 24863a65bcdcSTakashi Iwai nums++; 24873a65bcdcSTakashi Iwai } 2488352f7f91STakashi Iwai spec->num_adc_nids = nums; 2489352f7f91STakashi Iwai } 2490352f7f91STakashi Iwai 2491352f7f91STakashi Iwai if (imux->num_items == 1 || spec->shared_mic_hp) { 2492352f7f91STakashi Iwai snd_printdd("hda-codec: reducing to a single ADC\n"); 2493352f7f91STakashi Iwai spec->num_adc_nids = 1; /* reduce to a single ADC */ 2494352f7f91STakashi Iwai } 2495352f7f91STakashi Iwai 2496352f7f91STakashi Iwai /* single index for individual volumes ctls */ 2497352f7f91STakashi Iwai if (!spec->dyn_adc_switch && spec->multi_cap_vol) 2498352f7f91STakashi Iwai spec->num_adc_nids = 1; 2499352f7f91STakashi Iwai 25001da177e4SLinus Torvalds return 0; 25011da177e4SLinus Torvalds } 25021da177e4SLinus Torvalds 2503f3fc0b0bSTakashi Iwai /* parse capture source paths from the given pin and create imux items */ 2504f3fc0b0bSTakashi Iwai static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin, 25059dba205bSTakashi Iwai int cfg_idx, int num_adcs, 25069dba205bSTakashi Iwai const char *label, int anchor) 2507f3fc0b0bSTakashi Iwai { 2508f3fc0b0bSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 2509f3fc0b0bSTakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 2510f3fc0b0bSTakashi Iwai int imux_idx = imux->num_items; 2511f3fc0b0bSTakashi Iwai bool imux_added = false; 2512f3fc0b0bSTakashi Iwai int c; 2513f3fc0b0bSTakashi Iwai 2514f3fc0b0bSTakashi Iwai for (c = 0; c < num_adcs; c++) { 2515f3fc0b0bSTakashi Iwai struct nid_path *path; 2516f3fc0b0bSTakashi Iwai hda_nid_t adc = spec->adc_nids[c]; 2517f3fc0b0bSTakashi Iwai 2518f3fc0b0bSTakashi Iwai if (!is_reachable_path(codec, pin, adc)) 2519f3fc0b0bSTakashi Iwai continue; 2520f3fc0b0bSTakashi Iwai path = snd_hda_add_new_path(codec, pin, adc, anchor); 2521f3fc0b0bSTakashi Iwai if (!path) 2522f3fc0b0bSTakashi Iwai continue; 2523f3fc0b0bSTakashi Iwai print_nid_path("input", path); 2524f3fc0b0bSTakashi Iwai spec->input_paths[imux_idx][c] = 2525f3fc0b0bSTakashi Iwai snd_hda_get_path_idx(codec, path); 2526f3fc0b0bSTakashi Iwai 2527f3fc0b0bSTakashi Iwai if (!imux_added) { 2528f3fc0b0bSTakashi Iwai spec->imux_pins[imux->num_items] = pin; 25299dba205bSTakashi Iwai snd_hda_add_imux_item(imux, label, cfg_idx, NULL); 2530f3fc0b0bSTakashi Iwai imux_added = true; 2531f3fc0b0bSTakashi Iwai } 2532f3fc0b0bSTakashi Iwai } 2533f3fc0b0bSTakashi Iwai 2534f3fc0b0bSTakashi Iwai return 0; 2535f3fc0b0bSTakashi Iwai } 2536f3fc0b0bSTakashi Iwai 25371da177e4SLinus Torvalds /* 2538352f7f91STakashi Iwai * create playback/capture controls for input pins 25391da177e4SLinus Torvalds */ 25409dba205bSTakashi Iwai 2541c970042cSTakashi Iwai /* fill the label for each input at first */ 2542c970042cSTakashi Iwai static int fill_input_pin_labels(struct hda_codec *codec) 2543c970042cSTakashi Iwai { 2544c970042cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 2545c970042cSTakashi Iwai const struct auto_pin_cfg *cfg = &spec->autocfg; 2546c970042cSTakashi Iwai int i; 2547c970042cSTakashi Iwai 2548c970042cSTakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 2549c970042cSTakashi Iwai hda_nid_t pin = cfg->inputs[i].pin; 2550c970042cSTakashi Iwai const char *label; 2551c970042cSTakashi Iwai int j, idx; 2552c970042cSTakashi Iwai 2553c970042cSTakashi Iwai if (!is_input_pin(codec, pin)) 2554c970042cSTakashi Iwai continue; 2555c970042cSTakashi Iwai 2556c970042cSTakashi Iwai label = hda_get_autocfg_input_label(codec, cfg, i); 2557c970042cSTakashi Iwai idx = 0; 2558c970042cSTakashi Iwai for (j = i; j >= 0; j--) { 2559c970042cSTakashi Iwai if (spec->input_labels[j] && 2560c970042cSTakashi Iwai !strcmp(spec->input_labels[j], label)) { 2561c970042cSTakashi Iwai idx = spec->input_label_idxs[j] + 1; 2562c970042cSTakashi Iwai break; 2563c970042cSTakashi Iwai } 2564c970042cSTakashi Iwai } 2565c970042cSTakashi Iwai 2566c970042cSTakashi Iwai spec->input_labels[i] = label; 2567c970042cSTakashi Iwai spec->input_label_idxs[i] = idx; 2568c970042cSTakashi Iwai } 2569c970042cSTakashi Iwai 2570c970042cSTakashi Iwai return 0; 2571c970042cSTakashi Iwai } 2572c970042cSTakashi Iwai 25739dba205bSTakashi Iwai #define CFG_IDX_MIX 99 /* a dummy cfg->input idx for stereo mix */ 25749dba205bSTakashi Iwai 2575352f7f91STakashi Iwai static int create_input_ctls(struct hda_codec *codec) 2576a7da6ce5STakashi Iwai { 2577352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2578352f7f91STakashi Iwai const struct auto_pin_cfg *cfg = &spec->autocfg; 2579352f7f91STakashi Iwai hda_nid_t mixer = spec->mixer_nid; 2580352f7f91STakashi Iwai int num_adcs; 2581c970042cSTakashi Iwai int i, err; 25822c12c30dSTakashi Iwai unsigned int val; 2583a7da6ce5STakashi Iwai 2584352f7f91STakashi Iwai num_adcs = fill_adc_nids(codec); 2585352f7f91STakashi Iwai if (num_adcs < 0) 2586352f7f91STakashi Iwai return 0; 2587352f7f91STakashi Iwai 2588c970042cSTakashi Iwai err = fill_input_pin_labels(codec); 2589c970042cSTakashi Iwai if (err < 0) 2590c970042cSTakashi Iwai return err; 2591c970042cSTakashi Iwai 2592352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 2593352f7f91STakashi Iwai hda_nid_t pin; 2594352f7f91STakashi Iwai 2595352f7f91STakashi Iwai pin = cfg->inputs[i].pin; 2596352f7f91STakashi Iwai if (!is_input_pin(codec, pin)) 2597352f7f91STakashi Iwai continue; 2598352f7f91STakashi Iwai 25992c12c30dSTakashi Iwai val = PIN_IN; 26002c12c30dSTakashi Iwai if (cfg->inputs[i].type == AUTO_PIN_MIC) 26012c12c30dSTakashi Iwai val |= snd_hda_get_default_vref(codec, pin); 26022c12c30dSTakashi Iwai set_pin_target(codec, pin, val, false); 26032c12c30dSTakashi Iwai 2604352f7f91STakashi Iwai if (mixer) { 2605352f7f91STakashi Iwai if (is_reachable_path(codec, pin, mixer)) { 2606196c1766STakashi Iwai err = new_analog_input(codec, i, pin, 2607c970042cSTakashi Iwai spec->input_labels[i], 2608c970042cSTakashi Iwai spec->input_label_idxs[i], 2609c970042cSTakashi Iwai mixer); 2610a7da6ce5STakashi Iwai if (err < 0) 2611a7da6ce5STakashi Iwai return err; 2612a7da6ce5STakashi Iwai } 2613352f7f91STakashi Iwai } 2614352f7f91STakashi Iwai 2615c970042cSTakashi Iwai err = parse_capture_source(codec, pin, i, num_adcs, 2616c970042cSTakashi Iwai spec->input_labels[i], -mixer); 2617f3fc0b0bSTakashi Iwai if (err < 0) 2618f3fc0b0bSTakashi Iwai return err; 261929476558STakashi Iwai 262029476558STakashi Iwai if (spec->add_in_jack_modes) { 262129476558STakashi Iwai err = create_in_jack_mode(codec, pin); 262229476558STakashi Iwai if (err < 0) 262329476558STakashi Iwai return err; 262429476558STakashi Iwai } 2625352f7f91STakashi Iwai } 2626f3fc0b0bSTakashi Iwai 2627f3fc0b0bSTakashi Iwai if (mixer && spec->add_stereo_mix_input) { 26289dba205bSTakashi Iwai err = parse_capture_source(codec, mixer, CFG_IDX_MIX, num_adcs, 2629f3fc0b0bSTakashi Iwai "Stereo Mix", 0); 2630f3fc0b0bSTakashi Iwai if (err < 0) 2631f3fc0b0bSTakashi Iwai return err; 2632352f7f91STakashi Iwai } 2633352f7f91STakashi Iwai 2634a7da6ce5STakashi Iwai return 0; 2635a7da6ce5STakashi Iwai } 2636a7da6ce5STakashi Iwai 26371da177e4SLinus Torvalds 2638352f7f91STakashi Iwai /* 2639352f7f91STakashi Iwai * input source mux 2640352f7f91STakashi Iwai */ 2641352f7f91STakashi Iwai 2642c697b716STakashi Iwai /* get the input path specified by the given adc and imux indices */ 2643c697b716STakashi Iwai static struct nid_path *get_input_path(struct hda_codec *codec, int adc_idx, int imux_idx) 2644352f7f91STakashi Iwai { 2645352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2646b56fa1edSDavid Henningsson if (imux_idx < 0 || imux_idx >= HDA_MAX_NUM_INPUTS) { 2647b56fa1edSDavid Henningsson snd_BUG(); 2648b56fa1edSDavid Henningsson return NULL; 2649b56fa1edSDavid Henningsson } 2650352f7f91STakashi Iwai if (spec->dyn_adc_switch) 2651352f7f91STakashi Iwai adc_idx = spec->dyn_adc_idx[imux_idx]; 2652b56fa1edSDavid Henningsson if (adc_idx < 0 || adc_idx >= AUTO_CFG_MAX_OUTS) { 2653b56fa1edSDavid Henningsson snd_BUG(); 2654b56fa1edSDavid Henningsson return NULL; 2655b56fa1edSDavid Henningsson } 2656c697b716STakashi Iwai return snd_hda_get_path_from_idx(codec, spec->input_paths[imux_idx][adc_idx]); 265797ec558aSTakashi Iwai } 2658352f7f91STakashi Iwai 2659352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx, 2660352f7f91STakashi Iwai unsigned int idx); 2661352f7f91STakashi Iwai 2662352f7f91STakashi Iwai static int mux_enum_info(struct snd_kcontrol *kcontrol, 2663352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 2664352f7f91STakashi Iwai { 2665352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2666352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2667352f7f91STakashi Iwai return snd_hda_input_mux_info(&spec->input_mux, uinfo); 2668352f7f91STakashi Iwai } 2669352f7f91STakashi Iwai 2670352f7f91STakashi Iwai static int mux_enum_get(struct snd_kcontrol *kcontrol, 2671352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2672352f7f91STakashi Iwai { 2673352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2674352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2675a053d1e3SDavid Henningsson unsigned int adc_idx = kcontrol->id.index; 2676352f7f91STakashi Iwai 2677352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; 26781da177e4SLinus Torvalds return 0; 26791da177e4SLinus Torvalds } 26801da177e4SLinus Torvalds 2681352f7f91STakashi Iwai static int mux_enum_put(struct snd_kcontrol *kcontrol, 2682352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 26831da177e4SLinus Torvalds { 2684352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2685a053d1e3SDavid Henningsson unsigned int adc_idx = kcontrol->id.index; 2686352f7f91STakashi Iwai return mux_select(codec, adc_idx, 2687352f7f91STakashi Iwai ucontrol->value.enumerated.item[0]); 2688352f7f91STakashi Iwai } 2689352f7f91STakashi Iwai 2690352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_src_temp = { 26911da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2692352f7f91STakashi Iwai .name = "Input Source", 2693352f7f91STakashi Iwai .info = mux_enum_info, 2694352f7f91STakashi Iwai .get = mux_enum_get, 2695352f7f91STakashi Iwai .put = mux_enum_put, 26961da177e4SLinus Torvalds }; 2697071c73adSTakashi Iwai 269847d46abbSTakashi Iwai /* 269947d46abbSTakashi Iwai * capture volume and capture switch ctls 270047d46abbSTakashi Iwai */ 270147d46abbSTakashi Iwai 2702352f7f91STakashi Iwai typedef int (*put_call_t)(struct snd_kcontrol *kcontrol, 2703352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol); 2704071c73adSTakashi Iwai 270547d46abbSTakashi Iwai /* call the given amp update function for all amps in the imux list at once */ 2706352f7f91STakashi Iwai static int cap_put_caller(struct snd_kcontrol *kcontrol, 2707352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol, 2708352f7f91STakashi Iwai put_call_t func, int type) 2709352f7f91STakashi Iwai { 2710352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2711352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2712352f7f91STakashi Iwai const struct hda_input_mux *imux; 2713352f7f91STakashi Iwai struct nid_path *path; 2714352f7f91STakashi Iwai int i, adc_idx, err = 0; 2715071c73adSTakashi Iwai 2716352f7f91STakashi Iwai imux = &spec->input_mux; 2717a053d1e3SDavid Henningsson adc_idx = kcontrol->id.index; 2718352f7f91STakashi Iwai mutex_lock(&codec->control_mutex); 271947d46abbSTakashi Iwai /* we use the cache-only update at first since multiple input paths 272047d46abbSTakashi Iwai * may shared the same amp; by updating only caches, the redundant 272147d46abbSTakashi Iwai * writes to hardware can be reduced. 272247d46abbSTakashi Iwai */ 2723352f7f91STakashi Iwai codec->cached_write = 1; 2724352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2725c697b716STakashi Iwai path = get_input_path(codec, adc_idx, i); 2726c697b716STakashi Iwai if (!path || !path->ctls[type]) 2727352f7f91STakashi Iwai continue; 2728352f7f91STakashi Iwai kcontrol->private_value = path->ctls[type]; 2729352f7f91STakashi Iwai err = func(kcontrol, ucontrol); 2730352f7f91STakashi Iwai if (err < 0) 2731352f7f91STakashi Iwai goto error; 2732352f7f91STakashi Iwai } 2733352f7f91STakashi Iwai error: 2734352f7f91STakashi Iwai codec->cached_write = 0; 2735352f7f91STakashi Iwai mutex_unlock(&codec->control_mutex); 273647d46abbSTakashi Iwai snd_hda_codec_flush_amp_cache(codec); /* flush the updates */ 2737352f7f91STakashi Iwai if (err >= 0 && spec->cap_sync_hook) 2738352f7f91STakashi Iwai spec->cap_sync_hook(codec); 2739352f7f91STakashi Iwai return err; 2740352f7f91STakashi Iwai } 2741352f7f91STakashi Iwai 2742352f7f91STakashi Iwai /* capture volume ctl callbacks */ 2743352f7f91STakashi Iwai #define cap_vol_info snd_hda_mixer_amp_volume_info 2744352f7f91STakashi Iwai #define cap_vol_get snd_hda_mixer_amp_volume_get 2745352f7f91STakashi Iwai #define cap_vol_tlv snd_hda_mixer_amp_tlv 2746352f7f91STakashi Iwai 2747352f7f91STakashi Iwai static int cap_vol_put(struct snd_kcontrol *kcontrol, 2748352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2749352f7f91STakashi Iwai { 2750352f7f91STakashi Iwai return cap_put_caller(kcontrol, ucontrol, 2751352f7f91STakashi Iwai snd_hda_mixer_amp_volume_put, 2752352f7f91STakashi Iwai NID_PATH_VOL_CTL); 2753352f7f91STakashi Iwai } 2754352f7f91STakashi Iwai 2755352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_vol_temp = { 2756352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2757352f7f91STakashi Iwai .name = "Capture Volume", 2758352f7f91STakashi Iwai .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 2759352f7f91STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ | 2760352f7f91STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), 2761352f7f91STakashi Iwai .info = cap_vol_info, 2762352f7f91STakashi Iwai .get = cap_vol_get, 2763352f7f91STakashi Iwai .put = cap_vol_put, 2764352f7f91STakashi Iwai .tlv = { .c = cap_vol_tlv }, 2765352f7f91STakashi Iwai }; 2766352f7f91STakashi Iwai 2767352f7f91STakashi Iwai /* capture switch ctl callbacks */ 2768352f7f91STakashi Iwai #define cap_sw_info snd_ctl_boolean_stereo_info 2769352f7f91STakashi Iwai #define cap_sw_get snd_hda_mixer_amp_switch_get 2770352f7f91STakashi Iwai 2771352f7f91STakashi Iwai static int cap_sw_put(struct snd_kcontrol *kcontrol, 2772352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2773352f7f91STakashi Iwai { 2774ae177c3fSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2775ae177c3fSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 2776ae177c3fSTakashi Iwai int ret; 2777ae177c3fSTakashi Iwai 2778ae177c3fSTakashi Iwai ret = cap_put_caller(kcontrol, ucontrol, 2779352f7f91STakashi Iwai snd_hda_mixer_amp_switch_put, 2780352f7f91STakashi Iwai NID_PATH_MUTE_CTL); 2781ae177c3fSTakashi Iwai if (ret < 0) 2782ae177c3fSTakashi Iwai return ret; 2783ae177c3fSTakashi Iwai 2784ae177c3fSTakashi Iwai if (spec->capture_switch_hook) { 2785ae177c3fSTakashi Iwai bool enable = (ucontrol->value.integer.value[0] || 2786ae177c3fSTakashi Iwai ucontrol->value.integer.value[1]); 2787ae177c3fSTakashi Iwai spec->capture_switch_hook(codec, enable); 2788ae177c3fSTakashi Iwai } 2789ae177c3fSTakashi Iwai 2790ae177c3fSTakashi Iwai return ret; 2791352f7f91STakashi Iwai } 2792352f7f91STakashi Iwai 2793352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_sw_temp = { 2794352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2795352f7f91STakashi Iwai .name = "Capture Switch", 2796352f7f91STakashi Iwai .info = cap_sw_info, 2797352f7f91STakashi Iwai .get = cap_sw_get, 2798352f7f91STakashi Iwai .put = cap_sw_put, 2799352f7f91STakashi Iwai }; 2800352f7f91STakashi Iwai 2801352f7f91STakashi Iwai static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path) 2802352f7f91STakashi Iwai { 2803352f7f91STakashi Iwai hda_nid_t nid; 2804352f7f91STakashi Iwai int i, depth; 2805352f7f91STakashi Iwai 2806352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = path->ctls[NID_PATH_MUTE_CTL] = 0; 2807352f7f91STakashi Iwai for (depth = 0; depth < 3; depth++) { 2808352f7f91STakashi Iwai if (depth >= path->depth) 2809352f7f91STakashi Iwai return -EINVAL; 2810352f7f91STakashi Iwai i = path->depth - depth - 1; 2811352f7f91STakashi Iwai nid = path->path[i]; 2812352f7f91STakashi Iwai if (!path->ctls[NID_PATH_VOL_CTL]) { 2813352f7f91STakashi Iwai if (nid_has_volume(codec, nid, HDA_OUTPUT)) 2814352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = 2815352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 2816352f7f91STakashi Iwai else if (nid_has_volume(codec, nid, HDA_INPUT)) { 2817352f7f91STakashi Iwai int idx = path->idx[i]; 2818352f7f91STakashi Iwai if (!depth && codec->single_adc_amp) 2819352f7f91STakashi Iwai idx = 0; 2820352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = 2821352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); 2822352f7f91STakashi Iwai } 2823352f7f91STakashi Iwai } 2824352f7f91STakashi Iwai if (!path->ctls[NID_PATH_MUTE_CTL]) { 2825352f7f91STakashi Iwai if (nid_has_mute(codec, nid, HDA_OUTPUT)) 2826352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = 2827352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 2828352f7f91STakashi Iwai else if (nid_has_mute(codec, nid, HDA_INPUT)) { 2829352f7f91STakashi Iwai int idx = path->idx[i]; 2830352f7f91STakashi Iwai if (!depth && codec->single_adc_amp) 2831352f7f91STakashi Iwai idx = 0; 2832352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = 2833352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); 2834352f7f91STakashi Iwai } 2835352f7f91STakashi Iwai } 2836352f7f91STakashi Iwai } 2837352f7f91STakashi Iwai return 0; 2838352f7f91STakashi Iwai } 2839352f7f91STakashi Iwai 2840352f7f91STakashi Iwai static bool is_inv_dmic_pin(struct hda_codec *codec, hda_nid_t nid) 2841352f7f91STakashi Iwai { 2842352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2843352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 2844352f7f91STakashi Iwai unsigned int val; 2845352f7f91STakashi Iwai int i; 2846352f7f91STakashi Iwai 2847352f7f91STakashi Iwai if (!spec->inv_dmic_split) 2848352f7f91STakashi Iwai return false; 2849352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 2850352f7f91STakashi Iwai if (cfg->inputs[i].pin != nid) 2851352f7f91STakashi Iwai continue; 2852352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC) 2853352f7f91STakashi Iwai return false; 2854352f7f91STakashi Iwai val = snd_hda_codec_get_pincfg(codec, nid); 2855352f7f91STakashi Iwai return snd_hda_get_input_pin_attr(val) == INPUT_PIN_ATTR_INT; 2856352f7f91STakashi Iwai } 2857352f7f91STakashi Iwai return false; 2858352f7f91STakashi Iwai } 2859352f7f91STakashi Iwai 2860352f7f91STakashi Iwai static int add_single_cap_ctl(struct hda_codec *codec, const char *label, 2861352f7f91STakashi Iwai int idx, bool is_switch, unsigned int ctl, 2862352f7f91STakashi Iwai bool inv_dmic) 2863352f7f91STakashi Iwai { 2864352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2865352f7f91STakashi Iwai char tmpname[44]; 2866352f7f91STakashi Iwai int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL; 2867352f7f91STakashi Iwai const char *sfx = is_switch ? "Switch" : "Volume"; 2868352f7f91STakashi Iwai unsigned int chs = inv_dmic ? 1 : 3; 2869352f7f91STakashi Iwai int err; 2870352f7f91STakashi Iwai 2871352f7f91STakashi Iwai if (!ctl) 2872352f7f91STakashi Iwai return 0; 2873352f7f91STakashi Iwai 2874352f7f91STakashi Iwai if (label) 2875352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2876352f7f91STakashi Iwai "%s Capture %s", label, sfx); 2877352f7f91STakashi Iwai else 2878352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2879352f7f91STakashi Iwai "Capture %s", sfx); 2880352f7f91STakashi Iwai err = add_control(spec, type, tmpname, idx, 2881352f7f91STakashi Iwai amp_val_replace_channels(ctl, chs)); 2882352f7f91STakashi Iwai if (err < 0 || !inv_dmic) 2883352f7f91STakashi Iwai return err; 2884352f7f91STakashi Iwai 2885352f7f91STakashi Iwai /* Make independent right kcontrol */ 2886352f7f91STakashi Iwai if (label) 2887352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2888352f7f91STakashi Iwai "Inverted %s Capture %s", label, sfx); 2889352f7f91STakashi Iwai else 2890352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2891352f7f91STakashi Iwai "Inverted Capture %s", sfx); 2892352f7f91STakashi Iwai return add_control(spec, type, tmpname, idx, 2893352f7f91STakashi Iwai amp_val_replace_channels(ctl, 2)); 2894352f7f91STakashi Iwai } 2895352f7f91STakashi Iwai 2896352f7f91STakashi Iwai /* create single (and simple) capture volume and switch controls */ 2897352f7f91STakashi Iwai static int create_single_cap_vol_ctl(struct hda_codec *codec, int idx, 2898352f7f91STakashi Iwai unsigned int vol_ctl, unsigned int sw_ctl, 2899352f7f91STakashi Iwai bool inv_dmic) 2900352f7f91STakashi Iwai { 2901352f7f91STakashi Iwai int err; 2902352f7f91STakashi Iwai err = add_single_cap_ctl(codec, NULL, idx, false, vol_ctl, inv_dmic); 2903352f7f91STakashi Iwai if (err < 0) 2904352f7f91STakashi Iwai return err; 2905352f7f91STakashi Iwai err = add_single_cap_ctl(codec, NULL, idx, true, sw_ctl, inv_dmic); 2906071c73adSTakashi Iwai if (err < 0) 2907071c73adSTakashi Iwai return err; 2908071c73adSTakashi Iwai return 0; 29091da177e4SLinus Torvalds } 2910071c73adSTakashi Iwai 2911352f7f91STakashi Iwai /* create bound capture volume and switch controls */ 2912352f7f91STakashi Iwai static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx, 2913352f7f91STakashi Iwai unsigned int vol_ctl, unsigned int sw_ctl) 2914352f7f91STakashi Iwai { 2915352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2916352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 2917352f7f91STakashi Iwai 2918352f7f91STakashi Iwai if (vol_ctl) { 291912c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, NULL, &cap_vol_temp); 2920352f7f91STakashi Iwai if (!knew) 2921352f7f91STakashi Iwai return -ENOMEM; 2922352f7f91STakashi Iwai knew->index = idx; 2923352f7f91STakashi Iwai knew->private_value = vol_ctl; 2924352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 2925352f7f91STakashi Iwai } 2926352f7f91STakashi Iwai if (sw_ctl) { 292712c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, NULL, &cap_sw_temp); 2928352f7f91STakashi Iwai if (!knew) 2929352f7f91STakashi Iwai return -ENOMEM; 2930352f7f91STakashi Iwai knew->index = idx; 2931352f7f91STakashi Iwai knew->private_value = sw_ctl; 2932352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 2933352f7f91STakashi Iwai } 2934352f7f91STakashi Iwai return 0; 2935352f7f91STakashi Iwai } 2936352f7f91STakashi Iwai 2937352f7f91STakashi Iwai /* return the vol ctl when used first in the imux list */ 2938352f7f91STakashi Iwai static unsigned int get_first_cap_ctl(struct hda_codec *codec, int idx, int type) 2939352f7f91STakashi Iwai { 2940352f7f91STakashi Iwai struct nid_path *path; 2941352f7f91STakashi Iwai unsigned int ctl; 2942352f7f91STakashi Iwai int i; 2943352f7f91STakashi Iwai 2944c697b716STakashi Iwai path = get_input_path(codec, 0, idx); 2945352f7f91STakashi Iwai if (!path) 2946352f7f91STakashi Iwai return 0; 2947352f7f91STakashi Iwai ctl = path->ctls[type]; 2948352f7f91STakashi Iwai if (!ctl) 2949352f7f91STakashi Iwai return 0; 2950352f7f91STakashi Iwai for (i = 0; i < idx - 1; i++) { 2951c697b716STakashi Iwai path = get_input_path(codec, 0, i); 2952352f7f91STakashi Iwai if (path && path->ctls[type] == ctl) 2953352f7f91STakashi Iwai return 0; 2954352f7f91STakashi Iwai } 2955352f7f91STakashi Iwai return ctl; 2956352f7f91STakashi Iwai } 2957352f7f91STakashi Iwai 2958352f7f91STakashi Iwai /* create individual capture volume and switch controls per input */ 2959352f7f91STakashi Iwai static int create_multi_cap_vol_ctl(struct hda_codec *codec) 2960352f7f91STakashi Iwai { 2961352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2962352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 2963c970042cSTakashi Iwai int i, err, type; 2964352f7f91STakashi Iwai 2965352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2966352f7f91STakashi Iwai bool inv_dmic; 2967c970042cSTakashi Iwai int idx; 29689dba205bSTakashi Iwai 2969c970042cSTakashi Iwai idx = imux->items[i].index; 2970c970042cSTakashi Iwai if (idx >= spec->autocfg.num_inputs) 29719dba205bSTakashi Iwai continue; 2972352f7f91STakashi Iwai inv_dmic = is_inv_dmic_pin(codec, spec->imux_pins[i]); 2973352f7f91STakashi Iwai 2974352f7f91STakashi Iwai for (type = 0; type < 2; type++) { 2975c970042cSTakashi Iwai err = add_single_cap_ctl(codec, 2976c970042cSTakashi Iwai spec->input_labels[idx], 2977c970042cSTakashi Iwai spec->input_label_idxs[idx], 2978c970042cSTakashi Iwai type, 2979352f7f91STakashi Iwai get_first_cap_ctl(codec, i, type), 2980352f7f91STakashi Iwai inv_dmic); 2981d13bd412STakashi Iwai if (err < 0) 2982071c73adSTakashi Iwai return err; 2983352f7f91STakashi Iwai } 2984352f7f91STakashi Iwai } 2985071c73adSTakashi Iwai return 0; 2986352f7f91STakashi Iwai } 2987071c73adSTakashi Iwai 2988352f7f91STakashi Iwai static int create_capture_mixers(struct hda_codec *codec) 2989352f7f91STakashi Iwai { 2990352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2991352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 2992352f7f91STakashi Iwai int i, n, nums, err; 2993352f7f91STakashi Iwai 2994352f7f91STakashi Iwai if (spec->dyn_adc_switch) 2995352f7f91STakashi Iwai nums = 1; 2996352f7f91STakashi Iwai else 2997352f7f91STakashi Iwai nums = spec->num_adc_nids; 2998352f7f91STakashi Iwai 2999352f7f91STakashi Iwai if (!spec->auto_mic && imux->num_items > 1) { 3000352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 3001624d914dSTakashi Iwai const char *name; 3002624d914dSTakashi Iwai name = nums > 1 ? "Input Source" : "Capture Source"; 3003624d914dSTakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &cap_src_temp); 3004352f7f91STakashi Iwai if (!knew) 3005352f7f91STakashi Iwai return -ENOMEM; 3006352f7f91STakashi Iwai knew->count = nums; 3007352f7f91STakashi Iwai } 3008352f7f91STakashi Iwai 3009352f7f91STakashi Iwai for (n = 0; n < nums; n++) { 3010352f7f91STakashi Iwai bool multi = false; 301199a5592dSDavid Henningsson bool multi_cap_vol = spec->multi_cap_vol; 3012352f7f91STakashi Iwai bool inv_dmic = false; 3013352f7f91STakashi Iwai int vol, sw; 3014352f7f91STakashi Iwai 3015352f7f91STakashi Iwai vol = sw = 0; 3016352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 3017352f7f91STakashi Iwai struct nid_path *path; 3018c697b716STakashi Iwai path = get_input_path(codec, n, i); 3019352f7f91STakashi Iwai if (!path) 3020352f7f91STakashi Iwai continue; 3021352f7f91STakashi Iwai parse_capvol_in_path(codec, path); 3022352f7f91STakashi Iwai if (!vol) 3023352f7f91STakashi Iwai vol = path->ctls[NID_PATH_VOL_CTL]; 302499a5592dSDavid Henningsson else if (vol != path->ctls[NID_PATH_VOL_CTL]) { 3025352f7f91STakashi Iwai multi = true; 302699a5592dSDavid Henningsson if (!same_amp_caps(codec, vol, 302799a5592dSDavid Henningsson path->ctls[NID_PATH_VOL_CTL], HDA_INPUT)) 302899a5592dSDavid Henningsson multi_cap_vol = true; 302999a5592dSDavid Henningsson } 3030352f7f91STakashi Iwai if (!sw) 3031352f7f91STakashi Iwai sw = path->ctls[NID_PATH_MUTE_CTL]; 303299a5592dSDavid Henningsson else if (sw != path->ctls[NID_PATH_MUTE_CTL]) { 3033352f7f91STakashi Iwai multi = true; 303499a5592dSDavid Henningsson if (!same_amp_caps(codec, sw, 303599a5592dSDavid Henningsson path->ctls[NID_PATH_MUTE_CTL], HDA_INPUT)) 303699a5592dSDavid Henningsson multi_cap_vol = true; 303799a5592dSDavid Henningsson } 3038352f7f91STakashi Iwai if (is_inv_dmic_pin(codec, spec->imux_pins[i])) 3039352f7f91STakashi Iwai inv_dmic = true; 3040352f7f91STakashi Iwai } 3041352f7f91STakashi Iwai 3042352f7f91STakashi Iwai if (!multi) 3043352f7f91STakashi Iwai err = create_single_cap_vol_ctl(codec, n, vol, sw, 3044352f7f91STakashi Iwai inv_dmic); 304599a5592dSDavid Henningsson else if (!multi_cap_vol) 3046352f7f91STakashi Iwai err = create_bind_cap_vol_ctl(codec, n, vol, sw); 3047352f7f91STakashi Iwai else 3048352f7f91STakashi Iwai err = create_multi_cap_vol_ctl(codec); 3049d13bd412STakashi Iwai if (err < 0) 3050071c73adSTakashi Iwai return err; 3051071c73adSTakashi Iwai } 3052071c73adSTakashi Iwai 30531da177e4SLinus Torvalds return 0; 30541da177e4SLinus Torvalds } 30551da177e4SLinus Torvalds 3056352f7f91STakashi Iwai /* 3057352f7f91STakashi Iwai * add mic boosts if needed 3058352f7f91STakashi Iwai */ 3059352f7f91STakashi Iwai static int parse_mic_boost(struct hda_codec *codec) 3060352f7f91STakashi Iwai { 3061352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3062352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 3063352f7f91STakashi Iwai int i, err; 3064352f7f91STakashi Iwai hda_nid_t nid; 3065352f7f91STakashi Iwai 3066352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 3067352f7f91STakashi Iwai if (cfg->inputs[i].type > AUTO_PIN_MIC) 3068352f7f91STakashi Iwai break; 3069352f7f91STakashi Iwai nid = cfg->inputs[i].pin; 3070352f7f91STakashi Iwai if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { 30715abd4888STakashi Iwai char boost_label[44]; 3072352f7f91STakashi Iwai struct nid_path *path; 3073352f7f91STakashi Iwai unsigned int val; 3074352f7f91STakashi Iwai 307502aba550SDavid Henningsson if (!nid_has_volume(codec, nid, HDA_INPUT)) 307602aba550SDavid Henningsson continue; 307702aba550SDavid Henningsson 3078352f7f91STakashi Iwai snprintf(boost_label, sizeof(boost_label), 3079c970042cSTakashi Iwai "%s Boost Volume", 3080c970042cSTakashi Iwai spec->input_labels[i]); 3081352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); 3082352f7f91STakashi Iwai err = add_control(spec, HDA_CTL_WIDGET_VOL, 3083c970042cSTakashi Iwai boost_label, 3084c970042cSTakashi Iwai spec->input_label_idxs[i], val); 3085352f7f91STakashi Iwai if (err < 0) 3086352f7f91STakashi Iwai return err; 3087352f7f91STakashi Iwai 3088352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, nid, 0); 3089352f7f91STakashi Iwai if (path) 3090352f7f91STakashi Iwai path->ctls[NID_PATH_BOOST_CTL] = val; 3091352f7f91STakashi Iwai } 3092352f7f91STakashi Iwai } 3093352f7f91STakashi Iwai return 0; 3094352f7f91STakashi Iwai } 3095352f7f91STakashi Iwai 3096352f7f91STakashi Iwai /* 3097352f7f91STakashi Iwai * parse digital I/Os and set up NIDs in BIOS auto-parse mode 3098352f7f91STakashi Iwai */ 3099352f7f91STakashi Iwai static void parse_digital(struct hda_codec *codec) 3100352f7f91STakashi Iwai { 3101352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 31020c8c0f56STakashi Iwai struct nid_path *path; 3103352f7f91STakashi Iwai int i, nums; 31042c12c30dSTakashi Iwai hda_nid_t dig_nid, pin; 3105352f7f91STakashi Iwai 3106352f7f91STakashi Iwai /* support multiple SPDIFs; the secondary is set up as a slave */ 3107352f7f91STakashi Iwai nums = 0; 3108352f7f91STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) { 31092c12c30dSTakashi Iwai pin = spec->autocfg.dig_out_pins[i]; 3110352f7f91STakashi Iwai dig_nid = look_for_dac(codec, pin, true); 3111352f7f91STakashi Iwai if (!dig_nid) 3112352f7f91STakashi Iwai continue; 31133ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dig_nid, pin, 0); 31140c8c0f56STakashi Iwai if (!path) 3115352f7f91STakashi Iwai continue; 31160c8c0f56STakashi Iwai print_nid_path("digout", path); 3117e1284af7STakashi Iwai path->active = true; 3118196c1766STakashi Iwai spec->digout_paths[i] = snd_hda_get_path_idx(codec, path); 31192c12c30dSTakashi Iwai set_pin_target(codec, pin, PIN_OUT, false); 3120352f7f91STakashi Iwai if (!nums) { 3121352f7f91STakashi Iwai spec->multiout.dig_out_nid = dig_nid; 3122352f7f91STakashi Iwai spec->dig_out_type = spec->autocfg.dig_out_type[0]; 3123352f7f91STakashi Iwai } else { 3124352f7f91STakashi Iwai spec->multiout.slave_dig_outs = spec->slave_dig_outs; 3125352f7f91STakashi Iwai if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) 3126352f7f91STakashi Iwai break; 3127352f7f91STakashi Iwai spec->slave_dig_outs[nums - 1] = dig_nid; 3128352f7f91STakashi Iwai } 3129352f7f91STakashi Iwai nums++; 3130352f7f91STakashi Iwai } 3131352f7f91STakashi Iwai 3132352f7f91STakashi Iwai if (spec->autocfg.dig_in_pin) { 31332c12c30dSTakashi Iwai pin = spec->autocfg.dig_in_pin; 3134352f7f91STakashi Iwai dig_nid = codec->start_nid; 3135352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, dig_nid++) { 3136352f7f91STakashi Iwai unsigned int wcaps = get_wcaps(codec, dig_nid); 3137352f7f91STakashi Iwai if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) 3138352f7f91STakashi Iwai continue; 3139352f7f91STakashi Iwai if (!(wcaps & AC_WCAP_DIGITAL)) 3140352f7f91STakashi Iwai continue; 31412c12c30dSTakashi Iwai path = snd_hda_add_new_path(codec, pin, dig_nid, 0); 3142352f7f91STakashi Iwai if (path) { 31430c8c0f56STakashi Iwai print_nid_path("digin", path); 3144352f7f91STakashi Iwai path->active = true; 3145352f7f91STakashi Iwai spec->dig_in_nid = dig_nid; 31462430d7b7STakashi Iwai spec->digin_path = snd_hda_get_path_idx(codec, path); 31472c12c30dSTakashi Iwai set_pin_target(codec, pin, PIN_IN, false); 3148352f7f91STakashi Iwai break; 3149352f7f91STakashi Iwai } 3150352f7f91STakashi Iwai } 3151352f7f91STakashi Iwai } 3152352f7f91STakashi Iwai } 3153352f7f91STakashi Iwai 31541da177e4SLinus Torvalds 31551da177e4SLinus Torvalds /* 3156352f7f91STakashi Iwai * input MUX handling 31571da177e4SLinus Torvalds */ 31581da177e4SLinus Torvalds 3159352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur); 3160352f7f91STakashi Iwai 3161352f7f91STakashi Iwai /* select the given imux item; either unmute exclusively or select the route */ 3162352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx, 3163352f7f91STakashi Iwai unsigned int idx) 3164352f7f91STakashi Iwai { 3165352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3166352f7f91STakashi Iwai const struct hda_input_mux *imux; 3167352f7f91STakashi Iwai struct nid_path *path; 3168352f7f91STakashi Iwai 3169352f7f91STakashi Iwai imux = &spec->input_mux; 3170352f7f91STakashi Iwai if (!imux->num_items) 31711da177e4SLinus Torvalds return 0; 31721da177e4SLinus Torvalds 3173352f7f91STakashi Iwai if (idx >= imux->num_items) 3174352f7f91STakashi Iwai idx = imux->num_items - 1; 3175352f7f91STakashi Iwai if (spec->cur_mux[adc_idx] == idx) 3176352f7f91STakashi Iwai return 0; 3177352f7f91STakashi Iwai 3178c697b716STakashi Iwai path = get_input_path(codec, adc_idx, spec->cur_mux[adc_idx]); 3179352f7f91STakashi Iwai if (!path) 3180352f7f91STakashi Iwai return 0; 3181352f7f91STakashi Iwai if (path->active) 3182352f7f91STakashi Iwai snd_hda_activate_path(codec, path, false, false); 3183352f7f91STakashi Iwai 3184352f7f91STakashi Iwai spec->cur_mux[adc_idx] = idx; 3185352f7f91STakashi Iwai 3186352f7f91STakashi Iwai if (spec->shared_mic_hp) 3187352f7f91STakashi Iwai update_shared_mic_hp(codec, spec->cur_mux[adc_idx]); 3188352f7f91STakashi Iwai 3189352f7f91STakashi Iwai if (spec->dyn_adc_switch) 3190352f7f91STakashi Iwai dyn_adc_pcm_resetup(codec, idx); 3191352f7f91STakashi Iwai 3192c697b716STakashi Iwai path = get_input_path(codec, adc_idx, idx); 3193352f7f91STakashi Iwai if (!path) 3194352f7f91STakashi Iwai return 0; 3195352f7f91STakashi Iwai if (path->active) 3196352f7f91STakashi Iwai return 0; 3197352f7f91STakashi Iwai snd_hda_activate_path(codec, path, true, false); 3198352f7f91STakashi Iwai if (spec->cap_sync_hook) 3199352f7f91STakashi Iwai spec->cap_sync_hook(codec); 32001da177e4SLinus Torvalds return 1; 32011da177e4SLinus Torvalds } 32021da177e4SLinus Torvalds 32031da177e4SLinus Torvalds 32041da177e4SLinus Torvalds /* 3205352f7f91STakashi Iwai * Jack detections for HP auto-mute and mic-switch 32061da177e4SLinus Torvalds */ 3207352f7f91STakashi Iwai 3208352f7f91STakashi Iwai /* check each pin in the given array; returns true if any of them is plugged */ 3209352f7f91STakashi Iwai static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) 32101da177e4SLinus Torvalds { 3211352f7f91STakashi Iwai int i, present = 0; 32121da177e4SLinus Torvalds 3213352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 3214352f7f91STakashi Iwai hda_nid_t nid = pins[i]; 3215352f7f91STakashi Iwai if (!nid) 3216352f7f91STakashi Iwai break; 32170b4df931STakashi Iwai /* don't detect pins retasked as inputs */ 32180b4df931STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN) 32190b4df931STakashi Iwai continue; 3220352f7f91STakashi Iwai present |= snd_hda_jack_detect(codec, nid); 32211da177e4SLinus Torvalds } 3222352f7f91STakashi Iwai return present; 32231da177e4SLinus Torvalds } 32241da177e4SLinus Torvalds 3225352f7f91STakashi Iwai /* standard HP/line-out auto-mute helper */ 3226352f7f91STakashi Iwai static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, 32272c12c30dSTakashi Iwai bool mute) 32281da177e4SLinus Torvalds { 3229352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3230352f7f91STakashi Iwai int i; 32311da177e4SLinus Torvalds 3232352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 3233352f7f91STakashi Iwai hda_nid_t nid = pins[i]; 3234352f7f91STakashi Iwai unsigned int val; 3235352f7f91STakashi Iwai if (!nid) 3236352f7f91STakashi Iwai break; 3237352f7f91STakashi Iwai /* don't reset VREF value in case it's controlling 3238352f7f91STakashi Iwai * the amp (see alc861_fixup_asus_amp_vref_0f()) 3239352f7f91STakashi Iwai */ 32402c12c30dSTakashi Iwai if (spec->keep_vref_in_automute) 32412c12c30dSTakashi Iwai val = snd_hda_codec_get_pin_target(codec, nid) & ~PIN_HP; 32422c12c30dSTakashi Iwai else 3243352f7f91STakashi Iwai val = 0; 32442c12c30dSTakashi Iwai if (!mute) 32452c12c30dSTakashi Iwai val |= snd_hda_codec_get_pin_target(codec, nid); 32462c12c30dSTakashi Iwai /* here we call update_pin_ctl() so that the pinctl is changed 32472c12c30dSTakashi Iwai * without changing the pinctl target value; 32482c12c30dSTakashi Iwai * the original target value will be still referred at the 32492c12c30dSTakashi Iwai * init / resume again 32502c12c30dSTakashi Iwai */ 32512c12c30dSTakashi Iwai update_pin_ctl(codec, nid, val); 3252d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, !mute); 3253352f7f91STakashi Iwai } 3254352f7f91STakashi Iwai } 32551da177e4SLinus Torvalds 3256352f7f91STakashi Iwai /* Toggle outputs muting */ 32575d550e15STakashi Iwai void snd_hda_gen_update_outputs(struct hda_codec *codec) 3258352f7f91STakashi Iwai { 3259352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3260352f7f91STakashi Iwai int on; 3261352f7f91STakashi Iwai 3262352f7f91STakashi Iwai /* Control HP pins/amps depending on master_mute state; 3263352f7f91STakashi Iwai * in general, HP pins/amps control should be enabled in all cases, 3264352f7f91STakashi Iwai * but currently set only for master_mute, just to be safe 3265352f7f91STakashi Iwai */ 3266352f7f91STakashi Iwai if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */ 3267352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), 32682c12c30dSTakashi Iwai spec->autocfg.hp_pins, spec->master_mute); 3269352f7f91STakashi Iwai 3270352f7f91STakashi Iwai if (!spec->automute_speaker) 3271352f7f91STakashi Iwai on = 0; 3272352f7f91STakashi Iwai else 3273352f7f91STakashi Iwai on = spec->hp_jack_present | spec->line_jack_present; 3274352f7f91STakashi Iwai on |= spec->master_mute; 327547b9ddb8STakashi Iwai spec->speaker_muted = on; 3276352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), 32772c12c30dSTakashi Iwai spec->autocfg.speaker_pins, on); 3278352f7f91STakashi Iwai 3279352f7f91STakashi Iwai /* toggle line-out mutes if needed, too */ 3280352f7f91STakashi Iwai /* if LO is a copy of either HP or Speaker, don't need to handle it */ 3281352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] || 3282352f7f91STakashi Iwai spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0]) 3283352f7f91STakashi Iwai return; 3284352f7f91STakashi Iwai if (!spec->automute_lo) 3285352f7f91STakashi Iwai on = 0; 3286352f7f91STakashi Iwai else 3287352f7f91STakashi Iwai on = spec->hp_jack_present; 3288352f7f91STakashi Iwai on |= spec->master_mute; 328947b9ddb8STakashi Iwai spec->line_out_muted = on; 3290352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), 32912c12c30dSTakashi Iwai spec->autocfg.line_out_pins, on); 3292352f7f91STakashi Iwai } 32935d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs); 3294352f7f91STakashi Iwai 3295352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec) 3296352f7f91STakashi Iwai { 3297352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3298352f7f91STakashi Iwai if (spec->automute_hook) 3299352f7f91STakashi Iwai spec->automute_hook(codec); 3300352f7f91STakashi Iwai else 33015d550e15STakashi Iwai snd_hda_gen_update_outputs(codec); 3302352f7f91STakashi Iwai } 3303352f7f91STakashi Iwai 3304352f7f91STakashi Iwai /* standard HP-automute helper */ 33055d550e15STakashi Iwai void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) 3306352f7f91STakashi Iwai { 3307352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3308352f7f91STakashi Iwai 3309352f7f91STakashi Iwai spec->hp_jack_present = 3310352f7f91STakashi Iwai detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins), 3311352f7f91STakashi Iwai spec->autocfg.hp_pins); 3312352f7f91STakashi Iwai if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo)) 3313352f7f91STakashi Iwai return; 3314352f7f91STakashi Iwai call_update_outputs(codec); 3315352f7f91STakashi Iwai } 33165d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_hp_automute); 3317352f7f91STakashi Iwai 3318352f7f91STakashi Iwai /* standard line-out-automute helper */ 33195d550e15STakashi Iwai void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) 3320352f7f91STakashi Iwai { 3321352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3322352f7f91STakashi Iwai 3323352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) 3324352f7f91STakashi Iwai return; 3325352f7f91STakashi Iwai /* check LO jack only when it's different from HP */ 3326352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0]) 3327352f7f91STakashi Iwai return; 3328352f7f91STakashi Iwai 3329352f7f91STakashi Iwai spec->line_jack_present = 3330352f7f91STakashi Iwai detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), 3331352f7f91STakashi Iwai spec->autocfg.line_out_pins); 3332352f7f91STakashi Iwai if (!spec->automute_speaker || !spec->detect_lo) 3333352f7f91STakashi Iwai return; 3334352f7f91STakashi Iwai call_update_outputs(codec); 3335352f7f91STakashi Iwai } 33365d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_line_automute); 3337352f7f91STakashi Iwai 3338352f7f91STakashi Iwai /* standard mic auto-switch helper */ 33395d550e15STakashi Iwai void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *jack) 3340352f7f91STakashi Iwai { 3341352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3342352f7f91STakashi Iwai int i; 3343352f7f91STakashi Iwai 3344352f7f91STakashi Iwai if (!spec->auto_mic) 3345352f7f91STakashi Iwai return; 3346352f7f91STakashi Iwai 3347352f7f91STakashi Iwai for (i = spec->am_num_entries - 1; i > 0; i--) { 33480b4df931STakashi Iwai hda_nid_t pin = spec->am_entry[i].pin; 33490b4df931STakashi Iwai /* don't detect pins retasked as outputs */ 33500b4df931STakashi Iwai if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN) 33510b4df931STakashi Iwai continue; 33520b4df931STakashi Iwai if (snd_hda_jack_detect(codec, pin)) { 3353352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[i].idx); 3354352f7f91STakashi Iwai return; 3355352f7f91STakashi Iwai } 3356352f7f91STakashi Iwai } 3357352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[0].idx); 33581da177e4SLinus Torvalds } 33595d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_mic_autoswitch); 33601da177e4SLinus Torvalds 3361a5cc2509STakashi Iwai /* update jack retasking */ 3362a5cc2509STakashi Iwai static void update_automute_all(struct hda_codec *codec) 3363a5cc2509STakashi Iwai { 3364a5cc2509STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3365a5cc2509STakashi Iwai 3366a5cc2509STakashi Iwai if (spec->hp_automute_hook) 3367a5cc2509STakashi Iwai spec->hp_automute_hook(codec, NULL); 3368a5cc2509STakashi Iwai else 3369a5cc2509STakashi Iwai snd_hda_gen_hp_automute(codec, NULL); 3370a5cc2509STakashi Iwai if (spec->line_automute_hook) 3371a5cc2509STakashi Iwai spec->line_automute_hook(codec, NULL); 3372a5cc2509STakashi Iwai else 3373a5cc2509STakashi Iwai snd_hda_gen_line_automute(codec, NULL); 3374a5cc2509STakashi Iwai if (spec->mic_autoswitch_hook) 3375a5cc2509STakashi Iwai spec->mic_autoswitch_hook(codec, NULL); 3376a5cc2509STakashi Iwai else 3377a5cc2509STakashi Iwai snd_hda_gen_mic_autoswitch(codec, NULL); 3378a5cc2509STakashi Iwai } 3379a5cc2509STakashi Iwai 33801da177e4SLinus Torvalds /* 3381352f7f91STakashi Iwai * Auto-Mute mode mixer enum support 33821da177e4SLinus Torvalds */ 3383352f7f91STakashi Iwai static int automute_mode_info(struct snd_kcontrol *kcontrol, 3384352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 3385352f7f91STakashi Iwai { 3386352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3387352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3388352f7f91STakashi Iwai static const char * const texts3[] = { 3389352f7f91STakashi Iwai "Disabled", "Speaker Only", "Line Out+Speaker" 33901da177e4SLinus Torvalds }; 33911da177e4SLinus Torvalds 3392352f7f91STakashi Iwai if (spec->automute_speaker_possible && spec->automute_lo_possible) 3393352f7f91STakashi Iwai return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3); 3394352f7f91STakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo); 3395352f7f91STakashi Iwai } 3396352f7f91STakashi Iwai 3397352f7f91STakashi Iwai static int automute_mode_get(struct snd_kcontrol *kcontrol, 3398352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3399352f7f91STakashi Iwai { 3400352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3401352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3402352f7f91STakashi Iwai unsigned int val = 0; 3403352f7f91STakashi Iwai if (spec->automute_speaker) 3404352f7f91STakashi Iwai val++; 3405352f7f91STakashi Iwai if (spec->automute_lo) 3406352f7f91STakashi Iwai val++; 3407352f7f91STakashi Iwai 3408352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = val; 3409352f7f91STakashi Iwai return 0; 3410352f7f91STakashi Iwai } 3411352f7f91STakashi Iwai 3412352f7f91STakashi Iwai static int automute_mode_put(struct snd_kcontrol *kcontrol, 3413352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3414352f7f91STakashi Iwai { 3415352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3416352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3417352f7f91STakashi Iwai 3418352f7f91STakashi Iwai switch (ucontrol->value.enumerated.item[0]) { 3419352f7f91STakashi Iwai case 0: 3420352f7f91STakashi Iwai if (!spec->automute_speaker && !spec->automute_lo) 3421352f7f91STakashi Iwai return 0; 3422352f7f91STakashi Iwai spec->automute_speaker = 0; 3423352f7f91STakashi Iwai spec->automute_lo = 0; 3424352f7f91STakashi Iwai break; 3425352f7f91STakashi Iwai case 1: 3426352f7f91STakashi Iwai if (spec->automute_speaker_possible) { 3427352f7f91STakashi Iwai if (!spec->automute_lo && spec->automute_speaker) 3428352f7f91STakashi Iwai return 0; 3429352f7f91STakashi Iwai spec->automute_speaker = 1; 3430352f7f91STakashi Iwai spec->automute_lo = 0; 3431352f7f91STakashi Iwai } else if (spec->automute_lo_possible) { 3432352f7f91STakashi Iwai if (spec->automute_lo) 3433352f7f91STakashi Iwai return 0; 3434352f7f91STakashi Iwai spec->automute_lo = 1; 3435352f7f91STakashi Iwai } else 3436352f7f91STakashi Iwai return -EINVAL; 3437352f7f91STakashi Iwai break; 3438352f7f91STakashi Iwai case 2: 3439352f7f91STakashi Iwai if (!spec->automute_lo_possible || !spec->automute_speaker_possible) 3440352f7f91STakashi Iwai return -EINVAL; 3441352f7f91STakashi Iwai if (spec->automute_speaker && spec->automute_lo) 3442352f7f91STakashi Iwai return 0; 3443352f7f91STakashi Iwai spec->automute_speaker = 1; 3444352f7f91STakashi Iwai spec->automute_lo = 1; 3445352f7f91STakashi Iwai break; 3446352f7f91STakashi Iwai default: 3447352f7f91STakashi Iwai return -EINVAL; 3448352f7f91STakashi Iwai } 3449352f7f91STakashi Iwai call_update_outputs(codec); 3450352f7f91STakashi Iwai return 1; 3451352f7f91STakashi Iwai } 3452352f7f91STakashi Iwai 3453352f7f91STakashi Iwai static const struct snd_kcontrol_new automute_mode_enum = { 3454352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3455352f7f91STakashi Iwai .name = "Auto-Mute Mode", 3456352f7f91STakashi Iwai .info = automute_mode_info, 3457352f7f91STakashi Iwai .get = automute_mode_get, 3458352f7f91STakashi Iwai .put = automute_mode_put, 3459352f7f91STakashi Iwai }; 3460352f7f91STakashi Iwai 3461352f7f91STakashi Iwai static int add_automute_mode_enum(struct hda_codec *codec) 3462352f7f91STakashi Iwai { 3463352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3464352f7f91STakashi Iwai 346512c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &automute_mode_enum)) 3466352f7f91STakashi Iwai return -ENOMEM; 3467352f7f91STakashi Iwai return 0; 3468352f7f91STakashi Iwai } 3469352f7f91STakashi Iwai 3470352f7f91STakashi Iwai /* 3471352f7f91STakashi Iwai * Check the availability of HP/line-out auto-mute; 3472352f7f91STakashi Iwai * Set up appropriately if really supported 3473352f7f91STakashi Iwai */ 3474352f7f91STakashi Iwai static int check_auto_mute_availability(struct hda_codec *codec) 3475352f7f91STakashi Iwai { 3476352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3477352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 3478352f7f91STakashi Iwai int present = 0; 3479352f7f91STakashi Iwai int i, err; 3480352f7f91STakashi Iwai 3481f72706beSTakashi Iwai if (spec->suppress_auto_mute) 3482f72706beSTakashi Iwai return 0; 3483f72706beSTakashi Iwai 3484352f7f91STakashi Iwai if (cfg->hp_pins[0]) 3485352f7f91STakashi Iwai present++; 3486352f7f91STakashi Iwai if (cfg->line_out_pins[0]) 3487352f7f91STakashi Iwai present++; 3488352f7f91STakashi Iwai if (cfg->speaker_pins[0]) 3489352f7f91STakashi Iwai present++; 3490352f7f91STakashi Iwai if (present < 2) /* need two different output types */ 3491352f7f91STakashi Iwai return 0; 3492352f7f91STakashi Iwai 3493352f7f91STakashi Iwai if (!cfg->speaker_pins[0] && 3494352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { 3495352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 3496352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 3497352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 3498352f7f91STakashi Iwai } 3499352f7f91STakashi Iwai 3500352f7f91STakashi Iwai if (!cfg->hp_pins[0] && 3501352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) { 3502352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins, 3503352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 3504352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs; 3505352f7f91STakashi Iwai } 3506352f7f91STakashi Iwai 3507352f7f91STakashi Iwai for (i = 0; i < cfg->hp_outs; i++) { 3508352f7f91STakashi Iwai hda_nid_t nid = cfg->hp_pins[i]; 3509352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 3510352f7f91STakashi Iwai continue; 3511352f7f91STakashi Iwai snd_printdd("hda-codec: Enable HP auto-muting on NID 0x%x\n", 3512352f7f91STakashi Iwai nid); 3513352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid, HDA_GEN_HP_EVENT, 35142e03e952STakashi Iwai spec->hp_automute_hook ? 35152e03e952STakashi Iwai spec->hp_automute_hook : 35165d550e15STakashi Iwai snd_hda_gen_hp_automute); 3517352f7f91STakashi Iwai spec->detect_hp = 1; 3518352f7f91STakashi Iwai } 3519352f7f91STakashi Iwai 3520352f7f91STakashi Iwai if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) { 3521352f7f91STakashi Iwai if (cfg->speaker_outs) 3522352f7f91STakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 3523352f7f91STakashi Iwai hda_nid_t nid = cfg->line_out_pins[i]; 3524352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 3525352f7f91STakashi Iwai continue; 3526352f7f91STakashi Iwai snd_printdd("hda-codec: Enable Line-Out auto-muting on NID 0x%x\n", nid); 3527352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid, 3528352f7f91STakashi Iwai HDA_GEN_FRONT_EVENT, 35292e03e952STakashi Iwai spec->line_automute_hook ? 35302e03e952STakashi Iwai spec->line_automute_hook : 35315d550e15STakashi Iwai snd_hda_gen_line_automute); 3532352f7f91STakashi Iwai spec->detect_lo = 1; 3533352f7f91STakashi Iwai } 3534352f7f91STakashi Iwai spec->automute_lo_possible = spec->detect_hp; 3535352f7f91STakashi Iwai } 3536352f7f91STakashi Iwai 3537352f7f91STakashi Iwai spec->automute_speaker_possible = cfg->speaker_outs && 3538352f7f91STakashi Iwai (spec->detect_hp || spec->detect_lo); 3539352f7f91STakashi Iwai 3540352f7f91STakashi Iwai spec->automute_lo = spec->automute_lo_possible; 3541352f7f91STakashi Iwai spec->automute_speaker = spec->automute_speaker_possible; 3542352f7f91STakashi Iwai 3543352f7f91STakashi Iwai if (spec->automute_speaker_possible || spec->automute_lo_possible) { 3544352f7f91STakashi Iwai /* create a control for automute mode */ 3545352f7f91STakashi Iwai err = add_automute_mode_enum(codec); 3546352f7f91STakashi Iwai if (err < 0) 3547352f7f91STakashi Iwai return err; 3548352f7f91STakashi Iwai } 3549352f7f91STakashi Iwai return 0; 3550352f7f91STakashi Iwai } 3551352f7f91STakashi Iwai 3552352f7f91STakashi Iwai /* check whether all auto-mic pins are valid; setup indices if OK */ 3553352f7f91STakashi Iwai static bool auto_mic_check_imux(struct hda_codec *codec) 3554352f7f91STakashi Iwai { 3555352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3556352f7f91STakashi Iwai const struct hda_input_mux *imux; 3557352f7f91STakashi Iwai int i; 3558352f7f91STakashi Iwai 3559352f7f91STakashi Iwai imux = &spec->input_mux; 3560352f7f91STakashi Iwai for (i = 0; i < spec->am_num_entries; i++) { 3561352f7f91STakashi Iwai spec->am_entry[i].idx = 3562352f7f91STakashi Iwai find_idx_in_nid_list(spec->am_entry[i].pin, 3563352f7f91STakashi Iwai spec->imux_pins, imux->num_items); 3564352f7f91STakashi Iwai if (spec->am_entry[i].idx < 0) 3565352f7f91STakashi Iwai return false; /* no corresponding imux */ 3566352f7f91STakashi Iwai } 3567352f7f91STakashi Iwai 3568352f7f91STakashi Iwai /* we don't need the jack detection for the first pin */ 3569352f7f91STakashi Iwai for (i = 1; i < spec->am_num_entries; i++) 3570352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, 3571352f7f91STakashi Iwai spec->am_entry[i].pin, 3572352f7f91STakashi Iwai HDA_GEN_MIC_EVENT, 35732e03e952STakashi Iwai spec->mic_autoswitch_hook ? 35742e03e952STakashi Iwai spec->mic_autoswitch_hook : 35755d550e15STakashi Iwai snd_hda_gen_mic_autoswitch); 3576352f7f91STakashi Iwai return true; 3577352f7f91STakashi Iwai } 3578352f7f91STakashi Iwai 3579352f7f91STakashi Iwai static int compare_attr(const void *ap, const void *bp) 3580352f7f91STakashi Iwai { 3581352f7f91STakashi Iwai const struct automic_entry *a = ap; 3582352f7f91STakashi Iwai const struct automic_entry *b = bp; 3583352f7f91STakashi Iwai return (int)(a->attr - b->attr); 3584352f7f91STakashi Iwai } 3585352f7f91STakashi Iwai 3586352f7f91STakashi Iwai /* 3587352f7f91STakashi Iwai * Check the availability of auto-mic switch; 3588352f7f91STakashi Iwai * Set up if really supported 3589352f7f91STakashi Iwai */ 3590352f7f91STakashi Iwai static int check_auto_mic_availability(struct hda_codec *codec) 3591352f7f91STakashi Iwai { 3592352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3593352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 3594352f7f91STakashi Iwai unsigned int types; 3595352f7f91STakashi Iwai int i, num_pins; 3596352f7f91STakashi Iwai 3597d12daf6fSTakashi Iwai if (spec->suppress_auto_mic) 3598d12daf6fSTakashi Iwai return 0; 3599d12daf6fSTakashi Iwai 3600352f7f91STakashi Iwai types = 0; 3601352f7f91STakashi Iwai num_pins = 0; 3602352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 3603352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 3604352f7f91STakashi Iwai unsigned int attr; 3605352f7f91STakashi Iwai attr = snd_hda_codec_get_pincfg(codec, nid); 3606352f7f91STakashi Iwai attr = snd_hda_get_input_pin_attr(attr); 3607352f7f91STakashi Iwai if (types & (1 << attr)) 3608352f7f91STakashi Iwai return 0; /* already occupied */ 3609352f7f91STakashi Iwai switch (attr) { 3610352f7f91STakashi Iwai case INPUT_PIN_ATTR_INT: 3611352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC) 3612352f7f91STakashi Iwai return 0; /* invalid type */ 3613352f7f91STakashi Iwai break; 3614352f7f91STakashi Iwai case INPUT_PIN_ATTR_UNUSED: 3615352f7f91STakashi Iwai return 0; /* invalid entry */ 3616352f7f91STakashi Iwai default: 3617352f7f91STakashi Iwai if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) 3618352f7f91STakashi Iwai return 0; /* invalid type */ 3619352f7f91STakashi Iwai if (!spec->line_in_auto_switch && 3620352f7f91STakashi Iwai cfg->inputs[i].type != AUTO_PIN_MIC) 3621352f7f91STakashi Iwai return 0; /* only mic is allowed */ 3622352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 3623352f7f91STakashi Iwai return 0; /* no unsol support */ 3624352f7f91STakashi Iwai break; 3625352f7f91STakashi Iwai } 3626352f7f91STakashi Iwai if (num_pins >= MAX_AUTO_MIC_PINS) 3627352f7f91STakashi Iwai return 0; 3628352f7f91STakashi Iwai types |= (1 << attr); 3629352f7f91STakashi Iwai spec->am_entry[num_pins].pin = nid; 3630352f7f91STakashi Iwai spec->am_entry[num_pins].attr = attr; 3631352f7f91STakashi Iwai num_pins++; 3632352f7f91STakashi Iwai } 3633352f7f91STakashi Iwai 3634352f7f91STakashi Iwai if (num_pins < 2) 3635352f7f91STakashi Iwai return 0; 3636352f7f91STakashi Iwai 3637352f7f91STakashi Iwai spec->am_num_entries = num_pins; 3638352f7f91STakashi Iwai /* sort the am_entry in the order of attr so that the pin with a 3639352f7f91STakashi Iwai * higher attr will be selected when the jack is plugged. 3640352f7f91STakashi Iwai */ 3641352f7f91STakashi Iwai sort(spec->am_entry, num_pins, sizeof(spec->am_entry[0]), 3642352f7f91STakashi Iwai compare_attr, NULL); 3643352f7f91STakashi Iwai 3644352f7f91STakashi Iwai if (!auto_mic_check_imux(codec)) 3645352f7f91STakashi Iwai return 0; 3646352f7f91STakashi Iwai 3647352f7f91STakashi Iwai spec->auto_mic = 1; 3648352f7f91STakashi Iwai spec->num_adc_nids = 1; 3649352f7f91STakashi Iwai spec->cur_mux[0] = spec->am_entry[0].idx; 3650352f7f91STakashi Iwai snd_printdd("hda-codec: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", 3651352f7f91STakashi Iwai spec->am_entry[0].pin, 3652352f7f91STakashi Iwai spec->am_entry[1].pin, 3653352f7f91STakashi Iwai spec->am_entry[2].pin); 3654352f7f91STakashi Iwai 3655352f7f91STakashi Iwai return 0; 3656352f7f91STakashi Iwai } 3657352f7f91STakashi Iwai 3658352f7f91STakashi Iwai 36599eb413e5STakashi Iwai /* 36609eb413e5STakashi Iwai * Parse the given BIOS configuration and set up the hda_gen_spec 36619eb413e5STakashi Iwai * 36629eb413e5STakashi Iwai * return 1 if successful, 0 if the proper config is not found, 3663352f7f91STakashi Iwai * or a negative error code 3664352f7f91STakashi Iwai */ 3665352f7f91STakashi Iwai int snd_hda_gen_parse_auto_config(struct hda_codec *codec, 36669eb413e5STakashi Iwai struct auto_pin_cfg *cfg) 3667352f7f91STakashi Iwai { 3668352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3669352f7f91STakashi Iwai int err; 3670352f7f91STakashi Iwai 36711c70a583STakashi Iwai parse_user_hints(codec); 36721c70a583STakashi Iwai 36739eb413e5STakashi Iwai if (cfg != &spec->autocfg) { 36749eb413e5STakashi Iwai spec->autocfg = *cfg; 36759eb413e5STakashi Iwai cfg = &spec->autocfg; 36769eb413e5STakashi Iwai } 36779eb413e5STakashi Iwai 36786fc4cb97SDavid Henningsson fill_all_dac_nids(codec); 36796fc4cb97SDavid Henningsson 3680352f7f91STakashi Iwai if (!cfg->line_outs) { 3681352f7f91STakashi Iwai if (cfg->dig_outs || cfg->dig_in_pin) { 3682352f7f91STakashi Iwai spec->multiout.max_channels = 2; 3683352f7f91STakashi Iwai spec->no_analog = 1; 3684352f7f91STakashi Iwai goto dig_only; 3685352f7f91STakashi Iwai } 3686352f7f91STakashi Iwai return 0; /* can't find valid BIOS pin config */ 3687352f7f91STakashi Iwai } 3688352f7f91STakashi Iwai 3689352f7f91STakashi Iwai if (!spec->no_primary_hp && 3690352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && 3691352f7f91STakashi Iwai cfg->line_outs <= cfg->hp_outs) { 3692352f7f91STakashi Iwai /* use HP as primary out */ 3693352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 3694352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 3695352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 3696352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs; 3697352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); 3698352f7f91STakashi Iwai cfg->hp_outs = 0; 3699352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 3700352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT; 3701352f7f91STakashi Iwai } 3702352f7f91STakashi Iwai 3703352f7f91STakashi Iwai err = parse_output_paths(codec); 3704352f7f91STakashi Iwai if (err < 0) 3705352f7f91STakashi Iwai return err; 3706352f7f91STakashi Iwai err = create_multi_channel_mode(codec); 3707352f7f91STakashi Iwai if (err < 0) 3708352f7f91STakashi Iwai return err; 3709352f7f91STakashi Iwai err = create_multi_out_ctls(codec, cfg); 3710352f7f91STakashi Iwai if (err < 0) 3711352f7f91STakashi Iwai return err; 3712352f7f91STakashi Iwai err = create_hp_out_ctls(codec); 3713352f7f91STakashi Iwai if (err < 0) 3714352f7f91STakashi Iwai return err; 3715352f7f91STakashi Iwai err = create_speaker_out_ctls(codec); 3716352f7f91STakashi Iwai if (err < 0) 3717352f7f91STakashi Iwai return err; 371838cf6f1aSTakashi Iwai err = create_indep_hp_ctls(codec); 371938cf6f1aSTakashi Iwai if (err < 0) 372038cf6f1aSTakashi Iwai return err; 3721c30aa7b2STakashi Iwai err = create_loopback_mixing_ctl(codec); 3722c30aa7b2STakashi Iwai if (err < 0) 3723c30aa7b2STakashi Iwai return err; 3724352f7f91STakashi Iwai err = create_shared_input(codec); 3725352f7f91STakashi Iwai if (err < 0) 3726352f7f91STakashi Iwai return err; 3727352f7f91STakashi Iwai err = create_input_ctls(codec); 3728352f7f91STakashi Iwai if (err < 0) 3729352f7f91STakashi Iwai return err; 3730352f7f91STakashi Iwai 3731a07a949bSTakashi Iwai spec->const_channel_count = spec->ext_channel_count; 3732a07a949bSTakashi Iwai /* check the multiple speaker and headphone pins */ 3733a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 3734a07a949bSTakashi Iwai spec->const_channel_count = max(spec->const_channel_count, 3735a07a949bSTakashi Iwai cfg->speaker_outs * 2); 3736a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 3737a07a949bSTakashi Iwai spec->const_channel_count = max(spec->const_channel_count, 3738a07a949bSTakashi Iwai cfg->hp_outs * 2); 3739352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count, 3740352f7f91STakashi Iwai spec->const_channel_count); 3741352f7f91STakashi Iwai 3742352f7f91STakashi Iwai err = check_auto_mute_availability(codec); 3743352f7f91STakashi Iwai if (err < 0) 3744352f7f91STakashi Iwai return err; 3745352f7f91STakashi Iwai 3746352f7f91STakashi Iwai err = check_dyn_adc_switch(codec); 3747352f7f91STakashi Iwai if (err < 0) 3748352f7f91STakashi Iwai return err; 3749352f7f91STakashi Iwai 3750352f7f91STakashi Iwai if (!spec->shared_mic_hp) { 3751352f7f91STakashi Iwai err = check_auto_mic_availability(codec); 3752352f7f91STakashi Iwai if (err < 0) 3753352f7f91STakashi Iwai return err; 3754352f7f91STakashi Iwai } 3755352f7f91STakashi Iwai 3756352f7f91STakashi Iwai err = create_capture_mixers(codec); 3757352f7f91STakashi Iwai if (err < 0) 3758352f7f91STakashi Iwai return err; 3759352f7f91STakashi Iwai 3760352f7f91STakashi Iwai err = parse_mic_boost(codec); 3761352f7f91STakashi Iwai if (err < 0) 3762352f7f91STakashi Iwai return err; 3763352f7f91STakashi Iwai 3764978e77e7STakashi Iwai if (spec->add_out_jack_modes) { 3765978e77e7STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 3766978e77e7STakashi Iwai err = create_out_jack_modes(codec, cfg->line_outs, 3767978e77e7STakashi Iwai cfg->line_out_pins); 3768978e77e7STakashi Iwai if (err < 0) 3769978e77e7STakashi Iwai return err; 3770978e77e7STakashi Iwai } 3771978e77e7STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) { 3772978e77e7STakashi Iwai err = create_out_jack_modes(codec, cfg->hp_outs, 3773978e77e7STakashi Iwai cfg->hp_pins); 3774978e77e7STakashi Iwai if (err < 0) 3775978e77e7STakashi Iwai return err; 3776978e77e7STakashi Iwai } 3777978e77e7STakashi Iwai } 3778978e77e7STakashi Iwai 3779352f7f91STakashi Iwai dig_only: 3780352f7f91STakashi Iwai parse_digital(codec); 3781352f7f91STakashi Iwai 3782352f7f91STakashi Iwai return 1; 3783352f7f91STakashi Iwai } 3784352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_parse_auto_config); 3785352f7f91STakashi Iwai 3786352f7f91STakashi Iwai 3787352f7f91STakashi Iwai /* 3788352f7f91STakashi Iwai * Build control elements 3789352f7f91STakashi Iwai */ 3790352f7f91STakashi Iwai 3791352f7f91STakashi Iwai /* slave controls for virtual master */ 3792352f7f91STakashi Iwai static const char * const slave_pfxs[] = { 3793352f7f91STakashi Iwai "Front", "Surround", "Center", "LFE", "Side", 3794352f7f91STakashi Iwai "Headphone", "Speaker", "Mono", "Line Out", 3795352f7f91STakashi Iwai "CLFE", "Bass Speaker", "PCM", 3796ee79c69aSTakashi Iwai "Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side", 3797ee79c69aSTakashi Iwai "Headphone Front", "Headphone Surround", "Headphone CLFE", 3798ee79c69aSTakashi Iwai "Headphone Side", 3799352f7f91STakashi Iwai NULL, 3800352f7f91STakashi Iwai }; 3801352f7f91STakashi Iwai 3802352f7f91STakashi Iwai int snd_hda_gen_build_controls(struct hda_codec *codec) 3803352f7f91STakashi Iwai { 3804352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3805352f7f91STakashi Iwai int err; 3806352f7f91STakashi Iwai 380736502d02STakashi Iwai if (spec->kctls.used) { 3808352f7f91STakashi Iwai err = snd_hda_add_new_ctls(codec, spec->kctls.list); 3809352f7f91STakashi Iwai if (err < 0) 3810352f7f91STakashi Iwai return err; 381136502d02STakashi Iwai } 3812352f7f91STakashi Iwai 3813352f7f91STakashi Iwai if (spec->multiout.dig_out_nid) { 3814352f7f91STakashi Iwai err = snd_hda_create_dig_out_ctls(codec, 3815352f7f91STakashi Iwai spec->multiout.dig_out_nid, 3816352f7f91STakashi Iwai spec->multiout.dig_out_nid, 3817352f7f91STakashi Iwai spec->pcm_rec[1].pcm_type); 3818352f7f91STakashi Iwai if (err < 0) 3819352f7f91STakashi Iwai return err; 3820352f7f91STakashi Iwai if (!spec->no_analog) { 3821352f7f91STakashi Iwai err = snd_hda_create_spdif_share_sw(codec, 3822352f7f91STakashi Iwai &spec->multiout); 3823352f7f91STakashi Iwai if (err < 0) 3824352f7f91STakashi Iwai return err; 3825352f7f91STakashi Iwai spec->multiout.share_spdif = 1; 3826352f7f91STakashi Iwai } 3827352f7f91STakashi Iwai } 3828352f7f91STakashi Iwai if (spec->dig_in_nid) { 3829352f7f91STakashi Iwai err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 3830352f7f91STakashi Iwai if (err < 0) 3831352f7f91STakashi Iwai return err; 3832352f7f91STakashi Iwai } 3833352f7f91STakashi Iwai 3834352f7f91STakashi Iwai /* if we have no master control, let's create it */ 3835352f7f91STakashi Iwai if (!spec->no_analog && 3836352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { 3837352f7f91STakashi Iwai err = snd_hda_add_vmaster(codec, "Master Playback Volume", 38387a71bbf3STakashi Iwai spec->vmaster_tlv, slave_pfxs, 3839352f7f91STakashi Iwai "Playback Volume"); 3840352f7f91STakashi Iwai if (err < 0) 3841352f7f91STakashi Iwai return err; 3842352f7f91STakashi Iwai } 3843352f7f91STakashi Iwai if (!spec->no_analog && 3844352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { 3845352f7f91STakashi Iwai err = __snd_hda_add_vmaster(codec, "Master Playback Switch", 3846352f7f91STakashi Iwai NULL, slave_pfxs, 3847352f7f91STakashi Iwai "Playback Switch", 3848352f7f91STakashi Iwai true, &spec->vmaster_mute.sw_kctl); 3849352f7f91STakashi Iwai if (err < 0) 3850352f7f91STakashi Iwai return err; 3851352f7f91STakashi Iwai if (spec->vmaster_mute.hook) 3852fd25a97aSTakashi Iwai snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, 3853fd25a97aSTakashi Iwai spec->vmaster_mute_enum); 3854352f7f91STakashi Iwai } 3855352f7f91STakashi Iwai 3856352f7f91STakashi Iwai free_kctls(spec); /* no longer needed */ 3857352f7f91STakashi Iwai 3858352f7f91STakashi Iwai if (spec->shared_mic_hp) { 3859352f7f91STakashi Iwai int err; 3860352f7f91STakashi Iwai int nid = spec->autocfg.inputs[1].pin; 3861352f7f91STakashi Iwai err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0); 3862352f7f91STakashi Iwai if (err < 0) 3863352f7f91STakashi Iwai return err; 3864352f7f91STakashi Iwai err = snd_hda_jack_detect_enable(codec, nid, 0); 3865352f7f91STakashi Iwai if (err < 0) 3866352f7f91STakashi Iwai return err; 3867352f7f91STakashi Iwai } 3868352f7f91STakashi Iwai 3869352f7f91STakashi Iwai err = snd_hda_jack_add_kctls(codec, &spec->autocfg); 3870352f7f91STakashi Iwai if (err < 0) 3871352f7f91STakashi Iwai return err; 3872352f7f91STakashi Iwai 3873352f7f91STakashi Iwai return 0; 3874352f7f91STakashi Iwai } 3875352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_controls); 3876352f7f91STakashi Iwai 3877352f7f91STakashi Iwai 3878352f7f91STakashi Iwai /* 3879352f7f91STakashi Iwai * PCM definitions 3880352f7f91STakashi Iwai */ 3881352f7f91STakashi Iwai 3882e6b85f3cSTakashi Iwai static void call_pcm_playback_hook(struct hda_pcm_stream *hinfo, 3883e6b85f3cSTakashi Iwai struct hda_codec *codec, 3884e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream, 3885e6b85f3cSTakashi Iwai int action) 3886e6b85f3cSTakashi Iwai { 3887e6b85f3cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 3888e6b85f3cSTakashi Iwai if (spec->pcm_playback_hook) 3889e6b85f3cSTakashi Iwai spec->pcm_playback_hook(hinfo, codec, substream, action); 3890e6b85f3cSTakashi Iwai } 3891e6b85f3cSTakashi Iwai 3892ac2e8736STakashi Iwai static void call_pcm_capture_hook(struct hda_pcm_stream *hinfo, 3893ac2e8736STakashi Iwai struct hda_codec *codec, 3894ac2e8736STakashi Iwai struct snd_pcm_substream *substream, 3895ac2e8736STakashi Iwai int action) 3896ac2e8736STakashi Iwai { 3897ac2e8736STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3898ac2e8736STakashi Iwai if (spec->pcm_capture_hook) 3899ac2e8736STakashi Iwai spec->pcm_capture_hook(hinfo, codec, substream, action); 3900ac2e8736STakashi Iwai } 3901ac2e8736STakashi Iwai 3902352f7f91STakashi Iwai /* 3903352f7f91STakashi Iwai * Analog playback callbacks 3904352f7f91STakashi Iwai */ 3905352f7f91STakashi Iwai static int playback_pcm_open(struct hda_pcm_stream *hinfo, 3906352f7f91STakashi Iwai struct hda_codec *codec, 3907352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3908352f7f91STakashi Iwai { 3909352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 391038cf6f1aSTakashi Iwai int err; 391138cf6f1aSTakashi Iwai 391238cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 391338cf6f1aSTakashi Iwai err = snd_hda_multi_out_analog_open(codec, 391438cf6f1aSTakashi Iwai &spec->multiout, substream, 3915352f7f91STakashi Iwai hinfo); 3916e6b85f3cSTakashi Iwai if (!err) { 391738cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_MULTI_OUT; 3918e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3919e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_OPEN); 3920e6b85f3cSTakashi Iwai } 392138cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 392238cf6f1aSTakashi Iwai return err; 3923352f7f91STakashi Iwai } 3924352f7f91STakashi Iwai 3925352f7f91STakashi Iwai static int playback_pcm_prepare(struct hda_pcm_stream *hinfo, 392697ec558aSTakashi Iwai struct hda_codec *codec, 392797ec558aSTakashi Iwai unsigned int stream_tag, 392897ec558aSTakashi Iwai unsigned int format, 392997ec558aSTakashi Iwai struct snd_pcm_substream *substream) 393097ec558aSTakashi Iwai { 3931352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3932e6b85f3cSTakashi Iwai int err; 3933e6b85f3cSTakashi Iwai 3934e6b85f3cSTakashi Iwai err = snd_hda_multi_out_analog_prepare(codec, &spec->multiout, 3935352f7f91STakashi Iwai stream_tag, format, substream); 3936e6b85f3cSTakashi Iwai if (!err) 3937e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3938e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 3939e6b85f3cSTakashi Iwai return err; 3940352f7f91STakashi Iwai } 394197ec558aSTakashi Iwai 3942352f7f91STakashi Iwai static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 3943352f7f91STakashi Iwai struct hda_codec *codec, 3944352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3945352f7f91STakashi Iwai { 3946352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3947e6b85f3cSTakashi Iwai int err; 3948e6b85f3cSTakashi Iwai 3949e6b85f3cSTakashi Iwai err = snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); 3950e6b85f3cSTakashi Iwai if (!err) 3951e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3952e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 3953e6b85f3cSTakashi Iwai return err; 3954352f7f91STakashi Iwai } 3955352f7f91STakashi Iwai 395638cf6f1aSTakashi Iwai static int playback_pcm_close(struct hda_pcm_stream *hinfo, 395738cf6f1aSTakashi Iwai struct hda_codec *codec, 395838cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 395938cf6f1aSTakashi Iwai { 396038cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 396138cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 396238cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_MULTI_OUT); 3963e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3964e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLOSE); 396538cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 396638cf6f1aSTakashi Iwai return 0; 396738cf6f1aSTakashi Iwai } 396838cf6f1aSTakashi Iwai 3969ac2e8736STakashi Iwai static int capture_pcm_open(struct hda_pcm_stream *hinfo, 3970ac2e8736STakashi Iwai struct hda_codec *codec, 3971ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 3972ac2e8736STakashi Iwai { 3973ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_OPEN); 3974ac2e8736STakashi Iwai return 0; 3975ac2e8736STakashi Iwai } 3976ac2e8736STakashi Iwai 3977ac2e8736STakashi Iwai static int capture_pcm_prepare(struct hda_pcm_stream *hinfo, 3978ac2e8736STakashi Iwai struct hda_codec *codec, 3979ac2e8736STakashi Iwai unsigned int stream_tag, 3980ac2e8736STakashi Iwai unsigned int format, 3981ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 3982ac2e8736STakashi Iwai { 3983ac2e8736STakashi Iwai snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); 3984ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 3985ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 3986ac2e8736STakashi Iwai return 0; 3987ac2e8736STakashi Iwai } 3988ac2e8736STakashi Iwai 3989ac2e8736STakashi Iwai static int capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 3990ac2e8736STakashi Iwai struct hda_codec *codec, 3991ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 3992ac2e8736STakashi Iwai { 3993ac2e8736STakashi Iwai snd_hda_codec_cleanup_stream(codec, hinfo->nid); 3994ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 3995ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 3996ac2e8736STakashi Iwai return 0; 3997ac2e8736STakashi Iwai } 3998ac2e8736STakashi Iwai 3999ac2e8736STakashi Iwai static int capture_pcm_close(struct hda_pcm_stream *hinfo, 4000ac2e8736STakashi Iwai struct hda_codec *codec, 4001ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 4002ac2e8736STakashi Iwai { 4003ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLOSE); 4004ac2e8736STakashi Iwai return 0; 4005ac2e8736STakashi Iwai } 4006ac2e8736STakashi Iwai 400738cf6f1aSTakashi Iwai static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo, 400838cf6f1aSTakashi Iwai struct hda_codec *codec, 400938cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 401038cf6f1aSTakashi Iwai { 401138cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 401238cf6f1aSTakashi Iwai int err = 0; 401338cf6f1aSTakashi Iwai 401438cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 401538cf6f1aSTakashi Iwai if (!spec->indep_hp_enabled) 401638cf6f1aSTakashi Iwai err = -EBUSY; 401738cf6f1aSTakashi Iwai else 401838cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_INDEP_HP; 4019e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 4020e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_OPEN); 402138cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 402238cf6f1aSTakashi Iwai return err; 402338cf6f1aSTakashi Iwai } 402438cf6f1aSTakashi Iwai 402538cf6f1aSTakashi Iwai static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo, 402638cf6f1aSTakashi Iwai struct hda_codec *codec, 402738cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 402838cf6f1aSTakashi Iwai { 402938cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 403038cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 403138cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_INDEP_HP); 4032e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 4033e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLOSE); 403438cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 403538cf6f1aSTakashi Iwai return 0; 403638cf6f1aSTakashi Iwai } 403738cf6f1aSTakashi Iwai 4038e6b85f3cSTakashi Iwai static int alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 4039e6b85f3cSTakashi Iwai struct hda_codec *codec, 4040e6b85f3cSTakashi Iwai unsigned int stream_tag, 4041e6b85f3cSTakashi Iwai unsigned int format, 4042e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream) 4043e6b85f3cSTakashi Iwai { 4044e6b85f3cSTakashi Iwai snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); 4045e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 4046e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 4047e6b85f3cSTakashi Iwai return 0; 4048e6b85f3cSTakashi Iwai } 4049e6b85f3cSTakashi Iwai 4050e6b85f3cSTakashi Iwai static int alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 4051e6b85f3cSTakashi Iwai struct hda_codec *codec, 4052e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream) 4053e6b85f3cSTakashi Iwai { 4054e6b85f3cSTakashi Iwai snd_hda_codec_cleanup_stream(codec, hinfo->nid); 4055e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 4056e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 4057e6b85f3cSTakashi Iwai return 0; 4058e6b85f3cSTakashi Iwai } 4059e6b85f3cSTakashi Iwai 4060352f7f91STakashi Iwai /* 4061352f7f91STakashi Iwai * Digital out 4062352f7f91STakashi Iwai */ 4063352f7f91STakashi Iwai static int dig_playback_pcm_open(struct hda_pcm_stream *hinfo, 4064352f7f91STakashi Iwai struct hda_codec *codec, 4065352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4066352f7f91STakashi Iwai { 4067352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4068352f7f91STakashi Iwai return snd_hda_multi_out_dig_open(codec, &spec->multiout); 4069352f7f91STakashi Iwai } 4070352f7f91STakashi Iwai 4071352f7f91STakashi Iwai static int dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 4072352f7f91STakashi Iwai struct hda_codec *codec, 4073352f7f91STakashi Iwai unsigned int stream_tag, 4074352f7f91STakashi Iwai unsigned int format, 4075352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4076352f7f91STakashi Iwai { 4077352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4078352f7f91STakashi Iwai return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, 4079352f7f91STakashi Iwai stream_tag, format, substream); 4080352f7f91STakashi Iwai } 4081352f7f91STakashi Iwai 4082352f7f91STakashi Iwai static int dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 4083352f7f91STakashi Iwai struct hda_codec *codec, 4084352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4085352f7f91STakashi Iwai { 4086352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4087352f7f91STakashi Iwai return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); 4088352f7f91STakashi Iwai } 4089352f7f91STakashi Iwai 4090352f7f91STakashi Iwai static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo, 4091352f7f91STakashi Iwai struct hda_codec *codec, 4092352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4093352f7f91STakashi Iwai { 4094352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4095352f7f91STakashi Iwai return snd_hda_multi_out_dig_close(codec, &spec->multiout); 4096352f7f91STakashi Iwai } 4097352f7f91STakashi Iwai 4098352f7f91STakashi Iwai /* 4099352f7f91STakashi Iwai * Analog capture 4100352f7f91STakashi Iwai */ 4101ac2e8736STakashi Iwai #define alt_capture_pcm_open capture_pcm_open 4102ac2e8736STakashi Iwai #define alt_capture_pcm_close capture_pcm_close 4103ac2e8736STakashi Iwai 4104352f7f91STakashi Iwai static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 4105352f7f91STakashi Iwai struct hda_codec *codec, 4106352f7f91STakashi Iwai unsigned int stream_tag, 4107352f7f91STakashi Iwai unsigned int format, 4108352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4109352f7f91STakashi Iwai { 4110352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4111352f7f91STakashi Iwai 4112352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], 411397ec558aSTakashi Iwai stream_tag, 0, format); 4114ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 4115ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 411697ec558aSTakashi Iwai return 0; 411797ec558aSTakashi Iwai } 411897ec558aSTakashi Iwai 4119352f7f91STakashi Iwai static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 412097ec558aSTakashi Iwai struct hda_codec *codec, 412197ec558aSTakashi Iwai struct snd_pcm_substream *substream) 412297ec558aSTakashi Iwai { 4123352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 412497ec558aSTakashi Iwai 4125352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, 4126352f7f91STakashi Iwai spec->adc_nids[substream->number + 1]); 4127ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 4128ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 412997ec558aSTakashi Iwai return 0; 413097ec558aSTakashi Iwai } 413197ec558aSTakashi Iwai 4132352f7f91STakashi Iwai /* 4133352f7f91STakashi Iwai */ 4134352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_playback = { 4135352f7f91STakashi Iwai .substreams = 1, 4136352f7f91STakashi Iwai .channels_min = 2, 4137352f7f91STakashi Iwai .channels_max = 8, 4138352f7f91STakashi Iwai /* NID is set in build_pcms */ 4139352f7f91STakashi Iwai .ops = { 4140352f7f91STakashi Iwai .open = playback_pcm_open, 414138cf6f1aSTakashi Iwai .close = playback_pcm_close, 4142352f7f91STakashi Iwai .prepare = playback_pcm_prepare, 4143352f7f91STakashi Iwai .cleanup = playback_pcm_cleanup 4144352f7f91STakashi Iwai }, 4145352f7f91STakashi Iwai }; 4146352f7f91STakashi Iwai 4147352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_capture = { 4148352f7f91STakashi Iwai .substreams = 1, 4149352f7f91STakashi Iwai .channels_min = 2, 4150352f7f91STakashi Iwai .channels_max = 2, 4151352f7f91STakashi Iwai /* NID is set in build_pcms */ 4152ac2e8736STakashi Iwai .ops = { 4153ac2e8736STakashi Iwai .open = capture_pcm_open, 4154ac2e8736STakashi Iwai .close = capture_pcm_close, 4155ac2e8736STakashi Iwai .prepare = capture_pcm_prepare, 4156ac2e8736STakashi Iwai .cleanup = capture_pcm_cleanup 4157ac2e8736STakashi Iwai }, 4158352f7f91STakashi Iwai }; 4159352f7f91STakashi Iwai 4160352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_playback = { 4161352f7f91STakashi Iwai .substreams = 1, 4162352f7f91STakashi Iwai .channels_min = 2, 4163352f7f91STakashi Iwai .channels_max = 2, 4164352f7f91STakashi Iwai /* NID is set in build_pcms */ 416538cf6f1aSTakashi Iwai .ops = { 416638cf6f1aSTakashi Iwai .open = alt_playback_pcm_open, 4167e6b85f3cSTakashi Iwai .close = alt_playback_pcm_close, 4168e6b85f3cSTakashi Iwai .prepare = alt_playback_pcm_prepare, 4169e6b85f3cSTakashi Iwai .cleanup = alt_playback_pcm_cleanup 417038cf6f1aSTakashi Iwai }, 4171352f7f91STakashi Iwai }; 4172352f7f91STakashi Iwai 4173352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_capture = { 4174352f7f91STakashi Iwai .substreams = 2, /* can be overridden */ 4175352f7f91STakashi Iwai .channels_min = 2, 4176352f7f91STakashi Iwai .channels_max = 2, 4177352f7f91STakashi Iwai /* NID is set in build_pcms */ 4178352f7f91STakashi Iwai .ops = { 4179ac2e8736STakashi Iwai .open = alt_capture_pcm_open, 4180ac2e8736STakashi Iwai .close = alt_capture_pcm_close, 4181352f7f91STakashi Iwai .prepare = alt_capture_pcm_prepare, 4182352f7f91STakashi Iwai .cleanup = alt_capture_pcm_cleanup 4183352f7f91STakashi Iwai }, 4184352f7f91STakashi Iwai }; 4185352f7f91STakashi Iwai 4186352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_playback = { 4187352f7f91STakashi Iwai .substreams = 1, 4188352f7f91STakashi Iwai .channels_min = 2, 4189352f7f91STakashi Iwai .channels_max = 2, 4190352f7f91STakashi Iwai /* NID is set in build_pcms */ 4191352f7f91STakashi Iwai .ops = { 4192352f7f91STakashi Iwai .open = dig_playback_pcm_open, 4193352f7f91STakashi Iwai .close = dig_playback_pcm_close, 4194352f7f91STakashi Iwai .prepare = dig_playback_pcm_prepare, 4195352f7f91STakashi Iwai .cleanup = dig_playback_pcm_cleanup 4196352f7f91STakashi Iwai }, 4197352f7f91STakashi Iwai }; 4198352f7f91STakashi Iwai 4199352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_capture = { 4200352f7f91STakashi Iwai .substreams = 1, 4201352f7f91STakashi Iwai .channels_min = 2, 4202352f7f91STakashi Iwai .channels_max = 2, 4203352f7f91STakashi Iwai /* NID is set in build_pcms */ 4204352f7f91STakashi Iwai }; 4205352f7f91STakashi Iwai 4206352f7f91STakashi Iwai /* Used by build_pcms to flag that a PCM has no playback stream */ 4207352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_null_stream = { 4208352f7f91STakashi Iwai .substreams = 0, 4209352f7f91STakashi Iwai .channels_min = 0, 4210352f7f91STakashi Iwai .channels_max = 0, 4211352f7f91STakashi Iwai }; 4212352f7f91STakashi Iwai 4213352f7f91STakashi Iwai /* 4214352f7f91STakashi Iwai * dynamic changing ADC PCM streams 4215352f7f91STakashi Iwai */ 4216352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) 42171da177e4SLinus Torvalds { 4218352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4219352f7f91STakashi Iwai hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]]; 42201da177e4SLinus Torvalds 4221352f7f91STakashi Iwai if (spec->cur_adc && spec->cur_adc != new_adc) { 4222352f7f91STakashi Iwai /* stream is running, let's swap the current ADC */ 4223352f7f91STakashi Iwai __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); 4224352f7f91STakashi Iwai spec->cur_adc = new_adc; 4225352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, new_adc, 4226352f7f91STakashi Iwai spec->cur_adc_stream_tag, 0, 4227352f7f91STakashi Iwai spec->cur_adc_format); 4228352f7f91STakashi Iwai return true; 4229352f7f91STakashi Iwai } 4230352f7f91STakashi Iwai return false; 4231352f7f91STakashi Iwai } 4232352f7f91STakashi Iwai 4233352f7f91STakashi Iwai /* analog capture with dynamic dual-adc changes */ 4234352f7f91STakashi Iwai static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 4235352f7f91STakashi Iwai struct hda_codec *codec, 4236352f7f91STakashi Iwai unsigned int stream_tag, 4237352f7f91STakashi Iwai unsigned int format, 4238352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4239352f7f91STakashi Iwai { 4240352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4241352f7f91STakashi Iwai spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]]; 4242352f7f91STakashi Iwai spec->cur_adc_stream_tag = stream_tag; 4243352f7f91STakashi Iwai spec->cur_adc_format = format; 4244352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); 42451da177e4SLinus Torvalds return 0; 42461da177e4SLinus Torvalds } 42471da177e4SLinus Torvalds 4248352f7f91STakashi Iwai static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 4249352f7f91STakashi Iwai struct hda_codec *codec, 4250352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4251352f7f91STakashi Iwai { 4252352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4253352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, spec->cur_adc); 4254352f7f91STakashi Iwai spec->cur_adc = 0; 4255352f7f91STakashi Iwai return 0; 4256352f7f91STakashi Iwai } 4257352f7f91STakashi Iwai 4258352f7f91STakashi Iwai static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = { 4259352f7f91STakashi Iwai .substreams = 1, 4260352f7f91STakashi Iwai .channels_min = 2, 4261352f7f91STakashi Iwai .channels_max = 2, 4262352f7f91STakashi Iwai .nid = 0, /* fill later */ 4263352f7f91STakashi Iwai .ops = { 4264352f7f91STakashi Iwai .prepare = dyn_adc_capture_pcm_prepare, 4265352f7f91STakashi Iwai .cleanup = dyn_adc_capture_pcm_cleanup 4266352f7f91STakashi Iwai }, 4267352f7f91STakashi Iwai }; 4268352f7f91STakashi Iwai 4269f873e536STakashi Iwai static void fill_pcm_stream_name(char *str, size_t len, const char *sfx, 4270f873e536STakashi Iwai const char *chip_name) 4271f873e536STakashi Iwai { 4272f873e536STakashi Iwai char *p; 4273f873e536STakashi Iwai 4274f873e536STakashi Iwai if (*str) 4275f873e536STakashi Iwai return; 4276f873e536STakashi Iwai strlcpy(str, chip_name, len); 4277f873e536STakashi Iwai 4278f873e536STakashi Iwai /* drop non-alnum chars after a space */ 4279f873e536STakashi Iwai for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) { 4280f873e536STakashi Iwai if (!isalnum(p[1])) { 4281f873e536STakashi Iwai *p = 0; 4282f873e536STakashi Iwai break; 4283f873e536STakashi Iwai } 4284f873e536STakashi Iwai } 4285f873e536STakashi Iwai strlcat(str, sfx, len); 4286f873e536STakashi Iwai } 4287f873e536STakashi Iwai 4288352f7f91STakashi Iwai /* build PCM streams based on the parsed results */ 4289352f7f91STakashi Iwai int snd_hda_gen_build_pcms(struct hda_codec *codec) 4290352f7f91STakashi Iwai { 4291352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4292352f7f91STakashi Iwai struct hda_pcm *info = spec->pcm_rec; 4293352f7f91STakashi Iwai const struct hda_pcm_stream *p; 4294352f7f91STakashi Iwai bool have_multi_adcs; 4295352f7f91STakashi Iwai 42961da177e4SLinus Torvalds codec->num_pcms = 1; 42971da177e4SLinus Torvalds codec->pcm_info = info; 42981da177e4SLinus Torvalds 4299352f7f91STakashi Iwai if (spec->no_analog) 4300352f7f91STakashi Iwai goto skip_analog; 4301352f7f91STakashi Iwai 4302f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_analog, 4303f873e536STakashi Iwai sizeof(spec->stream_name_analog), 4304f873e536STakashi Iwai " Analog", codec->chip_name); 4305352f7f91STakashi Iwai info->name = spec->stream_name_analog; 4306352f7f91STakashi Iwai 4307352f7f91STakashi Iwai if (spec->multiout.num_dacs > 0) { 4308352f7f91STakashi Iwai p = spec->stream_analog_playback; 4309352f7f91STakashi Iwai if (!p) 4310352f7f91STakashi Iwai p = &pcm_analog_playback; 4311352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 4312352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; 4313352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 4314352f7f91STakashi Iwai spec->multiout.max_channels; 4315352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT && 4316352f7f91STakashi Iwai spec->autocfg.line_outs == 2) 4317352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap = 4318352f7f91STakashi Iwai snd_pcm_2_1_chmaps; 4319352f7f91STakashi Iwai } 4320352f7f91STakashi Iwai if (spec->num_adc_nids) { 4321352f7f91STakashi Iwai p = spec->stream_analog_capture; 4322352f7f91STakashi Iwai if (!p) { 4323352f7f91STakashi Iwai if (spec->dyn_adc_switch) 4324352f7f91STakashi Iwai p = &dyn_adc_pcm_analog_capture; 4325352f7f91STakashi Iwai else 4326352f7f91STakashi Iwai p = &pcm_analog_capture; 4327352f7f91STakashi Iwai } 4328352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 4329352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; 4330352f7f91STakashi Iwai } 4331352f7f91STakashi Iwai 4332352f7f91STakashi Iwai skip_analog: 4333352f7f91STakashi Iwai /* SPDIF for stream index #1 */ 4334352f7f91STakashi Iwai if (spec->multiout.dig_out_nid || spec->dig_in_nid) { 4335f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_digital, 4336352f7f91STakashi Iwai sizeof(spec->stream_name_digital), 4337f873e536STakashi Iwai " Digital", codec->chip_name); 4338352f7f91STakashi Iwai codec->num_pcms = 2; 4339352f7f91STakashi Iwai codec->slave_dig_outs = spec->multiout.slave_dig_outs; 4340352f7f91STakashi Iwai info = spec->pcm_rec + 1; 4341352f7f91STakashi Iwai info->name = spec->stream_name_digital; 4342352f7f91STakashi Iwai if (spec->dig_out_type) 4343352f7f91STakashi Iwai info->pcm_type = spec->dig_out_type; 4344352f7f91STakashi Iwai else 4345352f7f91STakashi Iwai info->pcm_type = HDA_PCM_TYPE_SPDIF; 4346352f7f91STakashi Iwai if (spec->multiout.dig_out_nid) { 4347352f7f91STakashi Iwai p = spec->stream_digital_playback; 4348352f7f91STakashi Iwai if (!p) 4349352f7f91STakashi Iwai p = &pcm_digital_playback; 4350352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 4351352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; 4352352f7f91STakashi Iwai } 4353352f7f91STakashi Iwai if (spec->dig_in_nid) { 4354352f7f91STakashi Iwai p = spec->stream_digital_capture; 4355352f7f91STakashi Iwai if (!p) 4356352f7f91STakashi Iwai p = &pcm_digital_capture; 4357352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 4358352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; 4359352f7f91STakashi Iwai } 4360352f7f91STakashi Iwai } 4361352f7f91STakashi Iwai 4362352f7f91STakashi Iwai if (spec->no_analog) 4363352f7f91STakashi Iwai return 0; 4364352f7f91STakashi Iwai 4365352f7f91STakashi Iwai /* If the use of more than one ADC is requested for the current 4366352f7f91STakashi Iwai * model, configure a second analog capture-only PCM. 4367352f7f91STakashi Iwai */ 4368352f7f91STakashi Iwai have_multi_adcs = (spec->num_adc_nids > 1) && 4369352f7f91STakashi Iwai !spec->dyn_adc_switch && !spec->auto_mic; 4370352f7f91STakashi Iwai /* Additional Analaog capture for index #2 */ 4371352f7f91STakashi Iwai if (spec->alt_dac_nid || have_multi_adcs) { 4372352f7f91STakashi Iwai codec->num_pcms = 3; 4373352f7f91STakashi Iwai info = spec->pcm_rec + 2; 4374352f7f91STakashi Iwai info->name = spec->stream_name_analog; 4375352f7f91STakashi Iwai if (spec->alt_dac_nid) { 4376352f7f91STakashi Iwai p = spec->stream_analog_alt_playback; 4377352f7f91STakashi Iwai if (!p) 4378352f7f91STakashi Iwai p = &pcm_analog_alt_playback; 4379352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 4380352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 4381352f7f91STakashi Iwai spec->alt_dac_nid; 4382352f7f91STakashi Iwai } else { 4383352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = 4384352f7f91STakashi Iwai pcm_null_stream; 4385352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; 4386352f7f91STakashi Iwai } 4387352f7f91STakashi Iwai if (have_multi_adcs) { 4388352f7f91STakashi Iwai p = spec->stream_analog_alt_capture; 4389352f7f91STakashi Iwai if (!p) 4390352f7f91STakashi Iwai p = &pcm_analog_alt_capture; 4391352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 4392352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 4393352f7f91STakashi Iwai spec->adc_nids[1]; 4394352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 4395352f7f91STakashi Iwai spec->num_adc_nids - 1; 4396352f7f91STakashi Iwai } else { 4397352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = 4398352f7f91STakashi Iwai pcm_null_stream; 4399352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0; 4400352f7f91STakashi Iwai } 44011da177e4SLinus Torvalds } 44021da177e4SLinus Torvalds 44031da177e4SLinus Torvalds return 0; 44041da177e4SLinus Torvalds } 4405352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_pcms); 4406352f7f91STakashi Iwai 4407352f7f91STakashi Iwai 4408352f7f91STakashi Iwai /* 4409352f7f91STakashi Iwai * Standard auto-parser initializations 4410352f7f91STakashi Iwai */ 4411352f7f91STakashi Iwai 4412d4156930STakashi Iwai /* configure the given path as a proper output */ 44132c12c30dSTakashi Iwai static void set_output_and_unmute(struct hda_codec *codec, int path_idx) 4414352f7f91STakashi Iwai { 4415352f7f91STakashi Iwai struct nid_path *path; 4416d4156930STakashi Iwai hda_nid_t pin; 4417352f7f91STakashi Iwai 4418196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 4419d4156930STakashi Iwai if (!path || !path->depth) 4420352f7f91STakashi Iwai return; 4421d4156930STakashi Iwai pin = path->path[path->depth - 1]; 44222c12c30dSTakashi Iwai restore_pin_ctl(codec, pin); 4423e1284af7STakashi Iwai snd_hda_activate_path(codec, path, path->active, true); 4424e1284af7STakashi Iwai set_pin_eapd(codec, pin, path->active); 4425352f7f91STakashi Iwai } 4426352f7f91STakashi Iwai 4427352f7f91STakashi Iwai /* initialize primary output paths */ 4428352f7f91STakashi Iwai static void init_multi_out(struct hda_codec *codec) 4429352f7f91STakashi Iwai { 4430352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4431352f7f91STakashi Iwai int i; 4432352f7f91STakashi Iwai 4433d4156930STakashi Iwai for (i = 0; i < spec->autocfg.line_outs; i++) 44342c12c30dSTakashi Iwai set_output_and_unmute(codec, spec->out_paths[i]); 4435352f7f91STakashi Iwai } 4436352f7f91STakashi Iwai 4437db23fd19STakashi Iwai 44382c12c30dSTakashi Iwai static void __init_extra_out(struct hda_codec *codec, int num_outs, int *paths) 4439352f7f91STakashi Iwai { 4440352f7f91STakashi Iwai int i; 4441352f7f91STakashi Iwai 4442d4156930STakashi Iwai for (i = 0; i < num_outs; i++) 44432c12c30dSTakashi Iwai set_output_and_unmute(codec, paths[i]); 4444352f7f91STakashi Iwai } 4445db23fd19STakashi Iwai 4446db23fd19STakashi Iwai /* initialize hp and speaker paths */ 4447db23fd19STakashi Iwai static void init_extra_out(struct hda_codec *codec) 4448db23fd19STakashi Iwai { 4449db23fd19STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4450db23fd19STakashi Iwai 4451db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) 44522c12c30dSTakashi Iwai __init_extra_out(codec, spec->autocfg.hp_outs, spec->hp_paths); 4453db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) 4454db23fd19STakashi Iwai __init_extra_out(codec, spec->autocfg.speaker_outs, 44552c12c30dSTakashi Iwai spec->speaker_paths); 4456352f7f91STakashi Iwai } 4457352f7f91STakashi Iwai 4458352f7f91STakashi Iwai /* initialize multi-io paths */ 4459352f7f91STakashi Iwai static void init_multi_io(struct hda_codec *codec) 4460352f7f91STakashi Iwai { 4461352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4462352f7f91STakashi Iwai int i; 4463352f7f91STakashi Iwai 4464352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++) { 4465352f7f91STakashi Iwai hda_nid_t pin = spec->multi_io[i].pin; 4466352f7f91STakashi Iwai struct nid_path *path; 4467196c1766STakashi Iwai path = get_multiio_path(codec, i); 4468352f7f91STakashi Iwai if (!path) 4469352f7f91STakashi Iwai continue; 4470352f7f91STakashi Iwai if (!spec->multi_io[i].ctl_in) 4471352f7f91STakashi Iwai spec->multi_io[i].ctl_in = 44722c12c30dSTakashi Iwai snd_hda_codec_get_pin_target(codec, pin); 4473352f7f91STakashi Iwai snd_hda_activate_path(codec, path, path->active, true); 4474352f7f91STakashi Iwai } 4475352f7f91STakashi Iwai } 4476352f7f91STakashi Iwai 4477352f7f91STakashi Iwai /* set up input pins and loopback paths */ 4478352f7f91STakashi Iwai static void init_analog_input(struct hda_codec *codec) 4479352f7f91STakashi Iwai { 4480352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4481352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 4482352f7f91STakashi Iwai int i; 4483352f7f91STakashi Iwai 4484352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 4485352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 4486352f7f91STakashi Iwai if (is_input_pin(codec, nid)) 44872c12c30dSTakashi Iwai restore_pin_ctl(codec, nid); 4488352f7f91STakashi Iwai 4489352f7f91STakashi Iwai /* init loopback inputs */ 4490352f7f91STakashi Iwai if (spec->mixer_nid) { 4491352f7f91STakashi Iwai struct nid_path *path; 4492196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->loopback_paths[i]); 4493352f7f91STakashi Iwai if (path) 4494352f7f91STakashi Iwai snd_hda_activate_path(codec, path, 4495352f7f91STakashi Iwai path->active, false); 4496352f7f91STakashi Iwai } 4497352f7f91STakashi Iwai } 4498352f7f91STakashi Iwai } 4499352f7f91STakashi Iwai 4500352f7f91STakashi Iwai /* initialize ADC paths */ 4501352f7f91STakashi Iwai static void init_input_src(struct hda_codec *codec) 4502352f7f91STakashi Iwai { 4503352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4504352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 4505352f7f91STakashi Iwai struct nid_path *path; 4506352f7f91STakashi Iwai int i, c, nums; 4507352f7f91STakashi Iwai 4508352f7f91STakashi Iwai if (spec->dyn_adc_switch) 4509352f7f91STakashi Iwai nums = 1; 4510352f7f91STakashi Iwai else 4511352f7f91STakashi Iwai nums = spec->num_adc_nids; 4512352f7f91STakashi Iwai 4513352f7f91STakashi Iwai for (c = 0; c < nums; c++) { 4514352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 4515c697b716STakashi Iwai path = get_input_path(codec, c, i); 4516352f7f91STakashi Iwai if (path) { 4517352f7f91STakashi Iwai bool active = path->active; 4518352f7f91STakashi Iwai if (i == spec->cur_mux[c]) 4519352f7f91STakashi Iwai active = true; 4520352f7f91STakashi Iwai snd_hda_activate_path(codec, path, active, false); 4521352f7f91STakashi Iwai } 4522352f7f91STakashi Iwai } 4523352f7f91STakashi Iwai } 4524352f7f91STakashi Iwai 4525352f7f91STakashi Iwai if (spec->shared_mic_hp) 4526352f7f91STakashi Iwai update_shared_mic_hp(codec, spec->cur_mux[0]); 4527352f7f91STakashi Iwai 4528352f7f91STakashi Iwai if (spec->cap_sync_hook) 4529352f7f91STakashi Iwai spec->cap_sync_hook(codec); 4530352f7f91STakashi Iwai } 4531352f7f91STakashi Iwai 4532352f7f91STakashi Iwai /* set right pin controls for digital I/O */ 4533352f7f91STakashi Iwai static void init_digital(struct hda_codec *codec) 4534352f7f91STakashi Iwai { 4535352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4536352f7f91STakashi Iwai int i; 4537352f7f91STakashi Iwai hda_nid_t pin; 4538352f7f91STakashi Iwai 4539d4156930STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) 45402c12c30dSTakashi Iwai set_output_and_unmute(codec, spec->digout_paths[i]); 4541352f7f91STakashi Iwai pin = spec->autocfg.dig_in_pin; 45422430d7b7STakashi Iwai if (pin) { 45432430d7b7STakashi Iwai struct nid_path *path; 45442c12c30dSTakashi Iwai restore_pin_ctl(codec, pin); 45452430d7b7STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->digin_path); 45462430d7b7STakashi Iwai if (path) 45472430d7b7STakashi Iwai snd_hda_activate_path(codec, path, path->active, false); 45482430d7b7STakashi Iwai } 4549352f7f91STakashi Iwai } 4550352f7f91STakashi Iwai 4551973e4972STakashi Iwai /* clear unsol-event tags on unused pins; Conexant codecs seem to leave 4552973e4972STakashi Iwai * invalid unsol tags by some reason 4553973e4972STakashi Iwai */ 4554973e4972STakashi Iwai static void clear_unsol_on_unused_pins(struct hda_codec *codec) 4555973e4972STakashi Iwai { 4556973e4972STakashi Iwai int i; 4557973e4972STakashi Iwai 4558973e4972STakashi Iwai for (i = 0; i < codec->init_pins.used; i++) { 4559973e4972STakashi Iwai struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); 4560973e4972STakashi Iwai hda_nid_t nid = pin->nid; 4561973e4972STakashi Iwai if (is_jack_detectable(codec, nid) && 4562973e4972STakashi Iwai !snd_hda_jack_tbl_get(codec, nid)) 4563973e4972STakashi Iwai snd_hda_codec_update_cache(codec, nid, 0, 4564973e4972STakashi Iwai AC_VERB_SET_UNSOLICITED_ENABLE, 0); 4565973e4972STakashi Iwai } 4566973e4972STakashi Iwai } 4567973e4972STakashi Iwai 45685187ac16STakashi Iwai /* 45695187ac16STakashi Iwai * initialize the generic spec; 45705187ac16STakashi Iwai * this can be put as patch_ops.init function 45715187ac16STakashi Iwai */ 4572352f7f91STakashi Iwai int snd_hda_gen_init(struct hda_codec *codec) 4573352f7f91STakashi Iwai { 4574352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4575352f7f91STakashi Iwai 4576352f7f91STakashi Iwai if (spec->init_hook) 4577352f7f91STakashi Iwai spec->init_hook(codec); 4578352f7f91STakashi Iwai 4579352f7f91STakashi Iwai snd_hda_apply_verbs(codec); 4580352f7f91STakashi Iwai 45813bbcd274STakashi Iwai codec->cached_write = 1; 45823bbcd274STakashi Iwai 4583352f7f91STakashi Iwai init_multi_out(codec); 4584352f7f91STakashi Iwai init_extra_out(codec); 4585352f7f91STakashi Iwai init_multi_io(codec); 4586352f7f91STakashi Iwai init_analog_input(codec); 4587352f7f91STakashi Iwai init_input_src(codec); 4588352f7f91STakashi Iwai init_digital(codec); 4589352f7f91STakashi Iwai 4590973e4972STakashi Iwai clear_unsol_on_unused_pins(codec); 4591973e4972STakashi Iwai 4592352f7f91STakashi Iwai /* call init functions of standard auto-mute helpers */ 4593a5cc2509STakashi Iwai update_automute_all(codec); 4594352f7f91STakashi Iwai 45953bbcd274STakashi Iwai snd_hda_codec_flush_amp_cache(codec); 45963bbcd274STakashi Iwai snd_hda_codec_flush_cmd_cache(codec); 45973bbcd274STakashi Iwai 4598352f7f91STakashi Iwai if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook) 4599352f7f91STakashi Iwai snd_hda_sync_vmaster_hook(&spec->vmaster_mute); 4600352f7f91STakashi Iwai 4601352f7f91STakashi Iwai hda_call_check_power_status(codec, 0x01); 4602352f7f91STakashi Iwai return 0; 4603352f7f91STakashi Iwai } 4604fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_init); 4605fce52a3bSTakashi Iwai 46065187ac16STakashi Iwai /* 46075187ac16STakashi Iwai * free the generic spec; 46085187ac16STakashi Iwai * this can be put as patch_ops.free function 46095187ac16STakashi Iwai */ 4610fce52a3bSTakashi Iwai void snd_hda_gen_free(struct hda_codec *codec) 4611fce52a3bSTakashi Iwai { 4612fce52a3bSTakashi Iwai snd_hda_gen_spec_free(codec->spec); 4613fce52a3bSTakashi Iwai kfree(codec->spec); 4614fce52a3bSTakashi Iwai codec->spec = NULL; 4615fce52a3bSTakashi Iwai } 4616fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_free); 4617fce52a3bSTakashi Iwai 4618fce52a3bSTakashi Iwai #ifdef CONFIG_PM 46195187ac16STakashi Iwai /* 46205187ac16STakashi Iwai * check the loopback power save state; 46215187ac16STakashi Iwai * this can be put as patch_ops.check_power_status function 46225187ac16STakashi Iwai */ 4623fce52a3bSTakashi Iwai int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid) 4624fce52a3bSTakashi Iwai { 4625fce52a3bSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 4626fce52a3bSTakashi Iwai return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); 4627fce52a3bSTakashi Iwai } 4628fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_check_power_status); 4629fce52a3bSTakashi Iwai #endif 4630352f7f91STakashi Iwai 4631352f7f91STakashi Iwai 4632352f7f91STakashi Iwai /* 4633352f7f91STakashi Iwai * the generic codec support 4634352f7f91STakashi Iwai */ 46351da177e4SLinus Torvalds 4636352f7f91STakashi Iwai static const struct hda_codec_ops generic_patch_ops = { 4637352f7f91STakashi Iwai .build_controls = snd_hda_gen_build_controls, 4638352f7f91STakashi Iwai .build_pcms = snd_hda_gen_build_pcms, 4639352f7f91STakashi Iwai .init = snd_hda_gen_init, 4640fce52a3bSTakashi Iwai .free = snd_hda_gen_free, 4641352f7f91STakashi Iwai .unsol_event = snd_hda_jack_unsol_event, 464283012a7cSTakashi Iwai #ifdef CONFIG_PM 4643fce52a3bSTakashi Iwai .check_power_status = snd_hda_gen_check_power_status, 4644cb53c626STakashi Iwai #endif 46451da177e4SLinus Torvalds }; 46461da177e4SLinus Torvalds 46471da177e4SLinus Torvalds int snd_hda_parse_generic_codec(struct hda_codec *codec) 46481da177e4SLinus Torvalds { 4649352f7f91STakashi Iwai struct hda_gen_spec *spec; 46501da177e4SLinus Torvalds int err; 46511da177e4SLinus Torvalds 4652e560d8d8STakashi Iwai spec = kzalloc(sizeof(*spec), GFP_KERNEL); 4653352f7f91STakashi Iwai if (!spec) 46541da177e4SLinus Torvalds return -ENOMEM; 4655352f7f91STakashi Iwai snd_hda_gen_spec_init(spec); 46561da177e4SLinus Torvalds codec->spec = spec; 46571da177e4SLinus Torvalds 46589eb413e5STakashi Iwai err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0); 46599eb413e5STakashi Iwai if (err < 0) 46609eb413e5STakashi Iwai return err; 46619eb413e5STakashi Iwai 46629eb413e5STakashi Iwai err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg); 4663352f7f91STakashi Iwai if (err < 0) 46641da177e4SLinus Torvalds goto error; 46651da177e4SLinus Torvalds 46661da177e4SLinus Torvalds codec->patch_ops = generic_patch_ops; 46671da177e4SLinus Torvalds return 0; 46681da177e4SLinus Torvalds 46691da177e4SLinus Torvalds error: 4670fce52a3bSTakashi Iwai snd_hda_gen_free(codec); 46711da177e4SLinus Torvalds return err; 46721da177e4SLinus Torvalds } 4673fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_parse_generic_codec); 4674