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, 318cb53c626STakashi Iwai int dir, int idx) 319cb53c626STakashi Iwai { 320352f7f91STakashi Iwai unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir); 321352f7f91STakashi Iwai return is_ctl_used(codec, val, NID_PATH_VOL_CTL) || 322352f7f91STakashi Iwai is_ctl_used(codec, val, NID_PATH_MUTE_CTL); 323cb53c626STakashi Iwai } 324352f7f91STakashi Iwai 3250c8c0f56STakashi Iwai static void print_nid_path(const char *pfx, struct nid_path *path) 3260c8c0f56STakashi Iwai { 3270c8c0f56STakashi Iwai char buf[40]; 3280c8c0f56STakashi Iwai int i; 3290c8c0f56STakashi Iwai 3300c8c0f56STakashi Iwai 3310c8c0f56STakashi Iwai buf[0] = 0; 3320c8c0f56STakashi Iwai for (i = 0; i < path->depth; i++) { 3330c8c0f56STakashi Iwai char tmp[4]; 3340c8c0f56STakashi Iwai sprintf(tmp, ":%02x", path->path[i]); 3350c8c0f56STakashi Iwai strlcat(buf, tmp, sizeof(buf)); 3360c8c0f56STakashi Iwai } 3370c8c0f56STakashi Iwai snd_printdd("%s path: depth=%d %s\n", pfx, path->depth, buf); 3380c8c0f56STakashi Iwai } 3390c8c0f56STakashi Iwai 340352f7f91STakashi Iwai /* called recursively */ 341352f7f91STakashi Iwai static bool __parse_nid_path(struct hda_codec *codec, 342352f7f91STakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid, 3433ca529d3STakashi Iwai int anchor_nid, struct nid_path *path, 3443ca529d3STakashi Iwai int depth) 345352f7f91STakashi Iwai { 346ee8e765bSTakashi Iwai const hda_nid_t *conn; 347352f7f91STakashi Iwai int i, nums; 348352f7f91STakashi Iwai 3493ca529d3STakashi Iwai if (to_nid == anchor_nid) 3503ca529d3STakashi Iwai anchor_nid = 0; /* anchor passed */ 3513ca529d3STakashi Iwai else if (to_nid == (hda_nid_t)(-anchor_nid)) 3523ca529d3STakashi Iwai return false; /* hit the exclusive nid */ 353352f7f91STakashi Iwai 354ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, to_nid, &conn); 355352f7f91STakashi Iwai for (i = 0; i < nums; i++) { 356352f7f91STakashi Iwai if (conn[i] != from_nid) { 357352f7f91STakashi Iwai /* special case: when from_nid is 0, 358352f7f91STakashi Iwai * try to find an empty DAC 359352f7f91STakashi Iwai */ 360352f7f91STakashi Iwai if (from_nid || 361352f7f91STakashi Iwai get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT || 362352f7f91STakashi Iwai is_dac_already_used(codec, conn[i])) 363352f7f91STakashi Iwai continue; 364352f7f91STakashi Iwai } 3653ca529d3STakashi Iwai /* anchor is not requested or already passed? */ 3663ca529d3STakashi Iwai if (anchor_nid <= 0) 367352f7f91STakashi Iwai goto found; 368352f7f91STakashi Iwai } 369352f7f91STakashi Iwai if (depth >= MAX_NID_PATH_DEPTH) 370352f7f91STakashi Iwai return false; 371352f7f91STakashi Iwai for (i = 0; i < nums; i++) { 372352f7f91STakashi Iwai unsigned int type; 373352f7f91STakashi Iwai type = get_wcaps_type(get_wcaps(codec, conn[i])); 374352f7f91STakashi Iwai if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN || 375352f7f91STakashi Iwai type == AC_WID_PIN) 376352f7f91STakashi Iwai continue; 377352f7f91STakashi Iwai if (__parse_nid_path(codec, from_nid, conn[i], 3783ca529d3STakashi Iwai anchor_nid, path, depth + 1)) 379352f7f91STakashi Iwai goto found; 380352f7f91STakashi Iwai } 381352f7f91STakashi Iwai return false; 382352f7f91STakashi Iwai 383352f7f91STakashi Iwai found: 384352f7f91STakashi Iwai path->path[path->depth] = conn[i]; 385352f7f91STakashi Iwai path->idx[path->depth + 1] = i; 386352f7f91STakashi Iwai if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX) 387352f7f91STakashi Iwai path->multi[path->depth + 1] = 1; 388352f7f91STakashi Iwai path->depth++; 389352f7f91STakashi Iwai return true; 390352f7f91STakashi Iwai } 391352f7f91STakashi Iwai 392352f7f91STakashi Iwai /* parse the widget path from the given nid to the target nid; 393352f7f91STakashi Iwai * when @from_nid is 0, try to find an empty DAC; 3943ca529d3STakashi Iwai * when @anchor_nid is set to a positive value, only paths through the widget 3953ca529d3STakashi Iwai * with the given value are evaluated. 3963ca529d3STakashi Iwai * when @anchor_nid is set to a negative value, paths through the widget 3973ca529d3STakashi Iwai * with the negative of given value are excluded, only other paths are chosen. 3983ca529d3STakashi Iwai * when @anchor_nid is zero, no special handling about path selection. 399352f7f91STakashi Iwai */ 400352f7f91STakashi Iwai bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, 4013ca529d3STakashi Iwai hda_nid_t to_nid, int anchor_nid, 402352f7f91STakashi Iwai struct nid_path *path) 403352f7f91STakashi Iwai { 4043ca529d3STakashi Iwai if (__parse_nid_path(codec, from_nid, to_nid, anchor_nid, path, 1)) { 405352f7f91STakashi Iwai path->path[path->depth] = to_nid; 406352f7f91STakashi Iwai path->depth++; 407352f7f91STakashi Iwai return true; 408352f7f91STakashi Iwai } 409352f7f91STakashi Iwai return false; 410352f7f91STakashi Iwai } 411352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_parse_nid_path); 412352f7f91STakashi Iwai 413352f7f91STakashi Iwai /* 414352f7f91STakashi Iwai * parse the path between the given NIDs and add to the path list. 415352f7f91STakashi Iwai * if no valid path is found, return NULL 416352f7f91STakashi Iwai */ 417352f7f91STakashi Iwai struct nid_path * 418352f7f91STakashi Iwai snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid, 4193ca529d3STakashi Iwai hda_nid_t to_nid, int anchor_nid) 420352f7f91STakashi Iwai { 421352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 422352f7f91STakashi Iwai struct nid_path *path; 423352f7f91STakashi Iwai 424352f7f91STakashi Iwai if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid)) 425352f7f91STakashi Iwai return NULL; 426352f7f91STakashi Iwai 427f5172a7eSTakashi Iwai /* check whether the path has been already added */ 4283ca529d3STakashi Iwai path = get_nid_path(codec, from_nid, to_nid, anchor_nid); 429f5172a7eSTakashi Iwai if (path) 430f5172a7eSTakashi Iwai return path; 431f5172a7eSTakashi Iwai 432352f7f91STakashi Iwai path = snd_array_new(&spec->paths); 433352f7f91STakashi Iwai if (!path) 434352f7f91STakashi Iwai return NULL; 435352f7f91STakashi Iwai memset(path, 0, sizeof(*path)); 4363ca529d3STakashi Iwai if (snd_hda_parse_nid_path(codec, from_nid, to_nid, anchor_nid, path)) 437352f7f91STakashi Iwai return path; 438352f7f91STakashi Iwai /* push back */ 439352f7f91STakashi Iwai spec->paths.used--; 440352f7f91STakashi Iwai return NULL; 441352f7f91STakashi Iwai } 442352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_add_new_path); 443352f7f91STakashi Iwai 444980428ceSTakashi Iwai /* clear the given path as invalid so that it won't be picked up later */ 445980428ceSTakashi Iwai static void invalidate_nid_path(struct hda_codec *codec, int idx) 446980428ceSTakashi Iwai { 447980428ceSTakashi Iwai struct nid_path *path = snd_hda_get_path_from_idx(codec, idx); 448980428ceSTakashi Iwai if (!path) 449980428ceSTakashi Iwai return; 450980428ceSTakashi Iwai memset(path, 0, sizeof(*path)); 451980428ceSTakashi Iwai } 452980428ceSTakashi Iwai 453352f7f91STakashi Iwai /* look for an empty DAC slot */ 454352f7f91STakashi Iwai static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin, 455352f7f91STakashi Iwai bool is_digital) 456352f7f91STakashi Iwai { 457352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 458352f7f91STakashi Iwai bool cap_digital; 459352f7f91STakashi Iwai int i; 460352f7f91STakashi Iwai 461352f7f91STakashi Iwai for (i = 0; i < spec->num_all_dacs; i++) { 462352f7f91STakashi Iwai hda_nid_t nid = spec->all_dacs[i]; 463352f7f91STakashi Iwai if (!nid || is_dac_already_used(codec, nid)) 464352f7f91STakashi Iwai continue; 465352f7f91STakashi Iwai cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL); 466352f7f91STakashi Iwai if (is_digital != cap_digital) 467352f7f91STakashi Iwai continue; 468352f7f91STakashi Iwai if (is_reachable_path(codec, nid, pin)) 469352f7f91STakashi Iwai return nid; 470352f7f91STakashi Iwai } 471352f7f91STakashi Iwai return 0; 472352f7f91STakashi Iwai } 473352f7f91STakashi Iwai 474352f7f91STakashi Iwai /* replace the channels in the composed amp value with the given number */ 475352f7f91STakashi Iwai static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs) 476352f7f91STakashi Iwai { 477352f7f91STakashi Iwai val &= ~(0x3U << 16); 478352f7f91STakashi Iwai val |= chs << 16; 479352f7f91STakashi Iwai return val; 480352f7f91STakashi Iwai } 481352f7f91STakashi Iwai 482352f7f91STakashi Iwai /* check whether the widget has the given amp capability for the direction */ 483352f7f91STakashi Iwai static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, 484352f7f91STakashi Iwai int dir, unsigned int bits) 485352f7f91STakashi Iwai { 486352f7f91STakashi Iwai if (!nid) 487352f7f91STakashi Iwai return false; 488352f7f91STakashi Iwai if (get_wcaps(codec, nid) & (1 << (dir + 1))) 489352f7f91STakashi Iwai if (query_amp_caps(codec, nid, dir) & bits) 490352f7f91STakashi Iwai return true; 491352f7f91STakashi Iwai return false; 492352f7f91STakashi Iwai } 493352f7f91STakashi Iwai 49499a5592dSDavid Henningsson static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1, 49599a5592dSDavid Henningsson hda_nid_t nid2, int dir) 49699a5592dSDavid Henningsson { 49799a5592dSDavid Henningsson if (!(get_wcaps(codec, nid1) & (1 << (dir + 1)))) 49899a5592dSDavid Henningsson return !(get_wcaps(codec, nid2) & (1 << (dir + 1))); 49999a5592dSDavid Henningsson return (query_amp_caps(codec, nid1, dir) == 50099a5592dSDavid Henningsson query_amp_caps(codec, nid2, dir)); 50199a5592dSDavid Henningsson } 50299a5592dSDavid Henningsson 503352f7f91STakashi Iwai #define nid_has_mute(codec, nid, dir) \ 504352f7f91STakashi Iwai check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE) 505352f7f91STakashi Iwai #define nid_has_volume(codec, nid, dir) \ 506352f7f91STakashi Iwai check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS) 507352f7f91STakashi Iwai 508352f7f91STakashi Iwai /* look for a widget suitable for assigning a mute switch in the path */ 509352f7f91STakashi Iwai static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec, 510352f7f91STakashi Iwai struct nid_path *path) 511352f7f91STakashi Iwai { 512352f7f91STakashi Iwai int i; 513352f7f91STakashi Iwai 514352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 515352f7f91STakashi Iwai if (nid_has_mute(codec, path->path[i], HDA_OUTPUT)) 516352f7f91STakashi Iwai return path->path[i]; 517352f7f91STakashi Iwai if (i != path->depth - 1 && i != 0 && 518352f7f91STakashi Iwai nid_has_mute(codec, path->path[i], HDA_INPUT)) 519352f7f91STakashi Iwai return path->path[i]; 520352f7f91STakashi Iwai } 521352f7f91STakashi Iwai return 0; 522352f7f91STakashi Iwai } 523352f7f91STakashi Iwai 524352f7f91STakashi Iwai /* look for a widget suitable for assigning a volume ctl in the path */ 525352f7f91STakashi Iwai static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec, 526352f7f91STakashi Iwai struct nid_path *path) 527352f7f91STakashi Iwai { 528352f7f91STakashi Iwai int i; 529352f7f91STakashi Iwai 530352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 531352f7f91STakashi Iwai if (nid_has_volume(codec, path->path[i], HDA_OUTPUT)) 532352f7f91STakashi Iwai return path->path[i]; 533352f7f91STakashi Iwai } 534352f7f91STakashi Iwai return 0; 535352f7f91STakashi Iwai } 536352f7f91STakashi Iwai 537352f7f91STakashi Iwai /* 538352f7f91STakashi Iwai * path activation / deactivation 539352f7f91STakashi Iwai */ 540352f7f91STakashi Iwai 541352f7f91STakashi Iwai /* can have the amp-in capability? */ 542352f7f91STakashi Iwai static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx) 543352f7f91STakashi Iwai { 544352f7f91STakashi Iwai hda_nid_t nid = path->path[idx]; 545352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 546352f7f91STakashi Iwai unsigned int type = get_wcaps_type(caps); 547352f7f91STakashi Iwai 548352f7f91STakashi Iwai if (!(caps & AC_WCAP_IN_AMP)) 549352f7f91STakashi Iwai return false; 550352f7f91STakashi Iwai if (type == AC_WID_PIN && idx > 0) /* only for input pins */ 551352f7f91STakashi Iwai return false; 552352f7f91STakashi Iwai return true; 553352f7f91STakashi Iwai } 554352f7f91STakashi Iwai 555352f7f91STakashi Iwai /* can have the amp-out capability? */ 556352f7f91STakashi Iwai static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx) 557352f7f91STakashi Iwai { 558352f7f91STakashi Iwai hda_nid_t nid = path->path[idx]; 559352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 560352f7f91STakashi Iwai unsigned int type = get_wcaps_type(caps); 561352f7f91STakashi Iwai 562352f7f91STakashi Iwai if (!(caps & AC_WCAP_OUT_AMP)) 563352f7f91STakashi Iwai return false; 564352f7f91STakashi Iwai if (type == AC_WID_PIN && !idx) /* only for output pins */ 565352f7f91STakashi Iwai return false; 566352f7f91STakashi Iwai return true; 567352f7f91STakashi Iwai } 568352f7f91STakashi Iwai 569352f7f91STakashi Iwai /* check whether the given (nid,dir,idx) is active */ 570352f7f91STakashi Iwai static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid, 571352f7f91STakashi Iwai unsigned int idx, unsigned int dir) 572352f7f91STakashi Iwai { 573352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 574352f7f91STakashi Iwai int i, n; 575352f7f91STakashi Iwai 576352f7f91STakashi Iwai for (n = 0; n < spec->paths.used; n++) { 577352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, n); 578352f7f91STakashi Iwai if (!path->active) 579352f7f91STakashi Iwai continue; 580352f7f91STakashi Iwai for (i = 0; i < path->depth; i++) { 581352f7f91STakashi Iwai if (path->path[i] == nid) { 582352f7f91STakashi Iwai if (dir == HDA_OUTPUT || path->idx[i] == idx) 583352f7f91STakashi Iwai return true; 584352f7f91STakashi Iwai break; 585352f7f91STakashi Iwai } 586352f7f91STakashi Iwai } 587352f7f91STakashi Iwai } 588352f7f91STakashi Iwai return false; 589352f7f91STakashi Iwai } 590352f7f91STakashi Iwai 591352f7f91STakashi Iwai /* get the default amp value for the target state */ 592352f7f91STakashi Iwai static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid, 593352f7f91STakashi Iwai int dir, bool enable) 594352f7f91STakashi Iwai { 595352f7f91STakashi Iwai unsigned int caps; 596352f7f91STakashi Iwai unsigned int val = 0; 597352f7f91STakashi Iwai 598352f7f91STakashi Iwai caps = query_amp_caps(codec, nid, dir); 599352f7f91STakashi Iwai if (caps & AC_AMPCAP_NUM_STEPS) { 600352f7f91STakashi Iwai /* set to 0dB */ 601352f7f91STakashi Iwai if (enable) 602352f7f91STakashi Iwai val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; 603352f7f91STakashi Iwai } 604352f7f91STakashi Iwai if (caps & AC_AMPCAP_MUTE) { 605352f7f91STakashi Iwai if (!enable) 606352f7f91STakashi Iwai val |= HDA_AMP_MUTE; 607352f7f91STakashi Iwai } 608352f7f91STakashi Iwai return val; 609352f7f91STakashi Iwai } 610352f7f91STakashi Iwai 611352f7f91STakashi Iwai /* initialize the amp value (only at the first time) */ 612352f7f91STakashi Iwai static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx) 613352f7f91STakashi Iwai { 614352f7f91STakashi Iwai int val = get_amp_val_to_activate(codec, nid, dir, false); 615352f7f91STakashi Iwai snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); 616352f7f91STakashi Iwai } 617352f7f91STakashi Iwai 618352f7f91STakashi Iwai static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, 619352f7f91STakashi Iwai int idx, bool enable) 620352f7f91STakashi Iwai { 621352f7f91STakashi Iwai int val; 622352f7f91STakashi Iwai if (is_ctl_associated(codec, nid, dir, idx) || 623985803caSTakashi Iwai (!enable && is_active_nid(codec, nid, dir, idx))) 624352f7f91STakashi Iwai return; 625352f7f91STakashi Iwai val = get_amp_val_to_activate(codec, nid, dir, enable); 626352f7f91STakashi Iwai snd_hda_codec_amp_stereo(codec, nid, dir, idx, 0xff, val); 627352f7f91STakashi Iwai } 628352f7f91STakashi Iwai 629352f7f91STakashi Iwai static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, 630352f7f91STakashi Iwai int i, bool enable) 631352f7f91STakashi Iwai { 632352f7f91STakashi Iwai hda_nid_t nid = path->path[i]; 633352f7f91STakashi Iwai init_amp(codec, nid, HDA_OUTPUT, 0); 634352f7f91STakashi Iwai activate_amp(codec, nid, HDA_OUTPUT, 0, enable); 635352f7f91STakashi Iwai } 636352f7f91STakashi Iwai 637352f7f91STakashi Iwai static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, 638352f7f91STakashi Iwai int i, bool enable, bool add_aamix) 639352f7f91STakashi Iwai { 640352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 641ee8e765bSTakashi Iwai const hda_nid_t *conn; 642352f7f91STakashi Iwai int n, nums, idx; 643352f7f91STakashi Iwai int type; 644352f7f91STakashi Iwai hda_nid_t nid = path->path[i]; 645352f7f91STakashi Iwai 646ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, nid, &conn); 647352f7f91STakashi Iwai type = get_wcaps_type(get_wcaps(codec, nid)); 648352f7f91STakashi Iwai if (type == AC_WID_PIN || 649352f7f91STakashi Iwai (type == AC_WID_AUD_IN && codec->single_adc_amp)) { 650352f7f91STakashi Iwai nums = 1; 651352f7f91STakashi Iwai idx = 0; 652352f7f91STakashi Iwai } else 653352f7f91STakashi Iwai idx = path->idx[i]; 654352f7f91STakashi Iwai 655352f7f91STakashi Iwai for (n = 0; n < nums; n++) 656352f7f91STakashi Iwai init_amp(codec, nid, HDA_INPUT, n); 657352f7f91STakashi Iwai 658352f7f91STakashi Iwai if (is_ctl_associated(codec, nid, HDA_INPUT, idx)) 659352f7f91STakashi Iwai return; 660352f7f91STakashi Iwai 661352f7f91STakashi Iwai /* here is a little bit tricky in comparison with activate_amp_out(); 662352f7f91STakashi Iwai * when aa-mixer is available, we need to enable the path as well 663352f7f91STakashi Iwai */ 664352f7f91STakashi Iwai for (n = 0; n < nums; n++) { 665352f7f91STakashi Iwai if (n != idx && (!add_aamix || conn[n] != spec->mixer_nid)) 666352f7f91STakashi Iwai continue; 667352f7f91STakashi Iwai activate_amp(codec, nid, HDA_INPUT, n, enable); 668352f7f91STakashi Iwai } 669352f7f91STakashi Iwai } 670352f7f91STakashi Iwai 671352f7f91STakashi Iwai /* activate or deactivate the given path 672352f7f91STakashi Iwai * if @add_aamix is set, enable the input from aa-mix NID as well (if any) 673352f7f91STakashi Iwai */ 674352f7f91STakashi Iwai void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path, 675352f7f91STakashi Iwai bool enable, bool add_aamix) 676352f7f91STakashi Iwai { 677352f7f91STakashi Iwai int i; 678352f7f91STakashi Iwai 679352f7f91STakashi Iwai if (!enable) 680352f7f91STakashi Iwai path->active = false; 681352f7f91STakashi Iwai 682352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 683352f7f91STakashi Iwai if (enable && path->multi[i]) 684352f7f91STakashi Iwai snd_hda_codec_write_cache(codec, path->path[i], 0, 685352f7f91STakashi Iwai AC_VERB_SET_CONNECT_SEL, 686352f7f91STakashi Iwai path->idx[i]); 687352f7f91STakashi Iwai if (has_amp_in(codec, path, i)) 688352f7f91STakashi Iwai activate_amp_in(codec, path, i, enable, add_aamix); 689352f7f91STakashi Iwai if (has_amp_out(codec, path, i)) 690352f7f91STakashi Iwai activate_amp_out(codec, path, i, enable); 691352f7f91STakashi Iwai } 692352f7f91STakashi Iwai 693352f7f91STakashi Iwai if (enable) 694352f7f91STakashi Iwai path->active = true; 695352f7f91STakashi Iwai } 696352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_activate_path); 697352f7f91STakashi Iwai 698d5a9f1bbSTakashi Iwai /* turn on/off EAPD on the given pin */ 699d5a9f1bbSTakashi Iwai static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable) 700d5a9f1bbSTakashi Iwai { 701d5a9f1bbSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 702d5a9f1bbSTakashi Iwai if (spec->own_eapd_ctl || 703d5a9f1bbSTakashi Iwai !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD)) 704d5a9f1bbSTakashi Iwai return; 705ecac3ed1STakashi Iwai if (codec->inv_eapd) 706ecac3ed1STakashi Iwai enable = !enable; 707d5a9f1bbSTakashi Iwai snd_hda_codec_update_cache(codec, pin, 0, 708d5a9f1bbSTakashi Iwai AC_VERB_SET_EAPD_BTLENABLE, 709d5a9f1bbSTakashi Iwai enable ? 0x02 : 0x00); 710d5a9f1bbSTakashi Iwai } 711d5a9f1bbSTakashi Iwai 712352f7f91STakashi Iwai 713352f7f91STakashi Iwai /* 714352f7f91STakashi Iwai * Helper functions for creating mixer ctl elements 715352f7f91STakashi Iwai */ 716352f7f91STakashi Iwai 717352f7f91STakashi Iwai enum { 718352f7f91STakashi Iwai HDA_CTL_WIDGET_VOL, 719352f7f91STakashi Iwai HDA_CTL_WIDGET_MUTE, 720352f7f91STakashi Iwai HDA_CTL_BIND_MUTE, 721352f7f91STakashi Iwai }; 722352f7f91STakashi Iwai static const struct snd_kcontrol_new control_templates[] = { 723352f7f91STakashi Iwai HDA_CODEC_VOLUME(NULL, 0, 0, 0), 724352f7f91STakashi Iwai HDA_CODEC_MUTE(NULL, 0, 0, 0), 725352f7f91STakashi Iwai HDA_BIND_MUTE(NULL, 0, 0, 0), 726352f7f91STakashi Iwai }; 727352f7f91STakashi Iwai 728352f7f91STakashi Iwai /* add dynamic controls from template */ 729352f7f91STakashi Iwai static int add_control(struct hda_gen_spec *spec, int type, const char *name, 730352f7f91STakashi Iwai int cidx, unsigned long val) 731352f7f91STakashi Iwai { 732352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 733352f7f91STakashi Iwai 73412c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]); 735352f7f91STakashi Iwai if (!knew) 736352f7f91STakashi Iwai return -ENOMEM; 737352f7f91STakashi Iwai knew->index = cidx; 738352f7f91STakashi Iwai if (get_amp_nid_(val)) 739352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 740352f7f91STakashi Iwai knew->private_value = val; 741352f7f91STakashi Iwai return 0; 742352f7f91STakashi Iwai } 743352f7f91STakashi Iwai 744352f7f91STakashi Iwai static int add_control_with_pfx(struct hda_gen_spec *spec, int type, 745352f7f91STakashi Iwai const char *pfx, const char *dir, 746352f7f91STakashi Iwai const char *sfx, int cidx, unsigned long val) 747352f7f91STakashi Iwai { 748352f7f91STakashi Iwai char name[32]; 749352f7f91STakashi Iwai snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); 750352f7f91STakashi Iwai return add_control(spec, type, name, cidx, val); 751352f7f91STakashi Iwai } 752352f7f91STakashi Iwai 753352f7f91STakashi Iwai #define add_pb_vol_ctrl(spec, type, pfx, val) \ 754352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val) 755352f7f91STakashi Iwai #define add_pb_sw_ctrl(spec, type, pfx, val) \ 756352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val) 757352f7f91STakashi Iwai #define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \ 758352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val) 759352f7f91STakashi Iwai #define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ 760352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) 761352f7f91STakashi Iwai 762352f7f91STakashi Iwai static int add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx, 763352f7f91STakashi Iwai unsigned int chs, struct nid_path *path) 764352f7f91STakashi Iwai { 765352f7f91STakashi Iwai unsigned int val; 766352f7f91STakashi Iwai if (!path) 767352f7f91STakashi Iwai return 0; 768352f7f91STakashi Iwai val = path->ctls[NID_PATH_VOL_CTL]; 769352f7f91STakashi Iwai if (!val) 770352f7f91STakashi Iwai return 0; 771352f7f91STakashi Iwai val = amp_val_replace_channels(val, chs); 772352f7f91STakashi Iwai return __add_pb_vol_ctrl(codec->spec, HDA_CTL_WIDGET_VOL, pfx, cidx, val); 773352f7f91STakashi Iwai } 774352f7f91STakashi Iwai 775352f7f91STakashi Iwai /* return the channel bits suitable for the given path->ctls[] */ 776352f7f91STakashi Iwai static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path, 777352f7f91STakashi Iwai int type) 778352f7f91STakashi Iwai { 779352f7f91STakashi Iwai int chs = 1; /* mono (left only) */ 780352f7f91STakashi Iwai if (path) { 781352f7f91STakashi Iwai hda_nid_t nid = get_amp_nid_(path->ctls[type]); 782352f7f91STakashi Iwai if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO)) 783352f7f91STakashi Iwai chs = 3; /* stereo */ 784352f7f91STakashi Iwai } 785352f7f91STakashi Iwai return chs; 786352f7f91STakashi Iwai } 787352f7f91STakashi Iwai 788352f7f91STakashi Iwai static int add_stereo_vol(struct hda_codec *codec, const char *pfx, int cidx, 789352f7f91STakashi Iwai struct nid_path *path) 790352f7f91STakashi Iwai { 791352f7f91STakashi Iwai int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL); 792352f7f91STakashi Iwai return add_vol_ctl(codec, pfx, cidx, chs, path); 793352f7f91STakashi Iwai } 794352f7f91STakashi Iwai 795352f7f91STakashi Iwai /* create a mute-switch for the given mixer widget; 796352f7f91STakashi Iwai * if it has multiple sources (e.g. DAC and loopback), create a bind-mute 797352f7f91STakashi Iwai */ 798352f7f91STakashi Iwai static int add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx, 799352f7f91STakashi Iwai unsigned int chs, struct nid_path *path) 800352f7f91STakashi Iwai { 801352f7f91STakashi Iwai unsigned int val; 802352f7f91STakashi Iwai int type = HDA_CTL_WIDGET_MUTE; 803352f7f91STakashi Iwai 804352f7f91STakashi Iwai if (!path) 805352f7f91STakashi Iwai return 0; 806352f7f91STakashi Iwai val = path->ctls[NID_PATH_MUTE_CTL]; 807352f7f91STakashi Iwai if (!val) 808352f7f91STakashi Iwai return 0; 809352f7f91STakashi Iwai val = amp_val_replace_channels(val, chs); 810352f7f91STakashi Iwai if (get_amp_direction_(val) == HDA_INPUT) { 811352f7f91STakashi Iwai hda_nid_t nid = get_amp_nid_(val); 812352f7f91STakashi Iwai int nums = snd_hda_get_num_conns(codec, nid); 813352f7f91STakashi Iwai if (nums > 1) { 814352f7f91STakashi Iwai type = HDA_CTL_BIND_MUTE; 815352f7f91STakashi Iwai val |= nums << 19; 816352f7f91STakashi Iwai } 817352f7f91STakashi Iwai } 818352f7f91STakashi Iwai return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val); 819352f7f91STakashi Iwai } 820352f7f91STakashi Iwai 821352f7f91STakashi Iwai static int add_stereo_sw(struct hda_codec *codec, const char *pfx, 822352f7f91STakashi Iwai int cidx, struct nid_path *path) 823352f7f91STakashi Iwai { 824352f7f91STakashi Iwai int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL); 825352f7f91STakashi Iwai return add_sw_ctl(codec, pfx, cidx, chs, path); 826352f7f91STakashi Iwai } 827352f7f91STakashi Iwai 828247d85eeSTakashi Iwai /* any ctl assigned to the path with the given index? */ 829247d85eeSTakashi Iwai static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type) 830247d85eeSTakashi Iwai { 831247d85eeSTakashi Iwai struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx); 832247d85eeSTakashi Iwai return path && path->ctls[ctl_type]; 833247d85eeSTakashi Iwai } 834247d85eeSTakashi Iwai 835352f7f91STakashi Iwai static const char * const channel_name[4] = { 836352f7f91STakashi Iwai "Front", "Surround", "CLFE", "Side" 837352f7f91STakashi Iwai }; 838352f7f91STakashi Iwai 839352f7f91STakashi Iwai /* give some appropriate ctl name prefix for the given line out channel */ 840247d85eeSTakashi Iwai static const char *get_line_out_pfx(struct hda_codec *codec, int ch, 841247d85eeSTakashi Iwai int *index, int ctl_type) 842352f7f91STakashi Iwai { 843247d85eeSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 844352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 845352f7f91STakashi Iwai 846352f7f91STakashi Iwai *index = 0; 847352f7f91STakashi Iwai if (cfg->line_outs == 1 && !spec->multi_ios && 848247d85eeSTakashi Iwai !cfg->hp_outs && !cfg->speaker_outs) 849352f7f91STakashi Iwai return spec->vmaster_mute.hook ? "PCM" : "Master"; 850352f7f91STakashi Iwai 851352f7f91STakashi Iwai /* if there is really a single DAC used in the whole output paths, 852352f7f91STakashi Iwai * use it master (or "PCM" if a vmaster hook is present) 853352f7f91STakashi Iwai */ 854352f7f91STakashi Iwai if (spec->multiout.num_dacs == 1 && !spec->mixer_nid && 855352f7f91STakashi Iwai !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0]) 856352f7f91STakashi Iwai return spec->vmaster_mute.hook ? "PCM" : "Master"; 857352f7f91STakashi Iwai 858247d85eeSTakashi Iwai /* multi-io channels */ 859247d85eeSTakashi Iwai if (ch >= cfg->line_outs) 860247d85eeSTakashi Iwai return channel_name[ch]; 861247d85eeSTakashi Iwai 862352f7f91STakashi Iwai switch (cfg->line_out_type) { 863352f7f91STakashi Iwai case AUTO_PIN_SPEAKER_OUT: 864247d85eeSTakashi Iwai /* if the primary channel vol/mute is shared with HP volume, 865247d85eeSTakashi Iwai * don't name it as Speaker 866247d85eeSTakashi Iwai */ 867247d85eeSTakashi Iwai if (!ch && cfg->hp_outs && 868247d85eeSTakashi Iwai !path_has_mixer(codec, spec->hp_paths[0], ctl_type)) 869247d85eeSTakashi Iwai break; 870352f7f91STakashi Iwai if (cfg->line_outs == 1) 871352f7f91STakashi Iwai return "Speaker"; 872352f7f91STakashi Iwai if (cfg->line_outs == 2) 873352f7f91STakashi Iwai return ch ? "Bass Speaker" : "Speaker"; 874352f7f91STakashi Iwai break; 875352f7f91STakashi Iwai case AUTO_PIN_HP_OUT: 876247d85eeSTakashi Iwai /* if the primary channel vol/mute is shared with spk volume, 877247d85eeSTakashi Iwai * don't name it as Headphone 878247d85eeSTakashi Iwai */ 879247d85eeSTakashi Iwai if (!ch && cfg->speaker_outs && 880247d85eeSTakashi Iwai !path_has_mixer(codec, spec->speaker_paths[0], ctl_type)) 881247d85eeSTakashi Iwai break; 882352f7f91STakashi Iwai /* for multi-io case, only the primary out */ 883352f7f91STakashi Iwai if (ch && spec->multi_ios) 884352f7f91STakashi Iwai break; 885352f7f91STakashi Iwai *index = ch; 886352f7f91STakashi Iwai return "Headphone"; 887247d85eeSTakashi Iwai } 888247d85eeSTakashi Iwai 889247d85eeSTakashi Iwai /* for a single channel output, we don't have to name the channel */ 890352f7f91STakashi Iwai if (cfg->line_outs == 1 && !spec->multi_ios) 891352f7f91STakashi Iwai return "PCM"; 892247d85eeSTakashi Iwai 893352f7f91STakashi Iwai if (ch >= ARRAY_SIZE(channel_name)) { 894352f7f91STakashi Iwai snd_BUG(); 895352f7f91STakashi Iwai return "PCM"; 896352f7f91STakashi Iwai } 897352f7f91STakashi Iwai 898352f7f91STakashi Iwai return channel_name[ch]; 899352f7f91STakashi Iwai } 900352f7f91STakashi Iwai 901352f7f91STakashi Iwai /* 902352f7f91STakashi Iwai * Parse output paths 903352f7f91STakashi Iwai */ 904352f7f91STakashi Iwai 905352f7f91STakashi Iwai /* badness definition */ 906352f7f91STakashi Iwai enum { 907352f7f91STakashi Iwai /* No primary DAC is found for the main output */ 908352f7f91STakashi Iwai BAD_NO_PRIMARY_DAC = 0x10000, 909352f7f91STakashi Iwai /* No DAC is found for the extra output */ 910352f7f91STakashi Iwai BAD_NO_DAC = 0x4000, 911352f7f91STakashi Iwai /* No possible multi-ios */ 912352f7f91STakashi Iwai BAD_MULTI_IO = 0x103, 913352f7f91STakashi Iwai /* No individual DAC for extra output */ 914352f7f91STakashi Iwai BAD_NO_EXTRA_DAC = 0x102, 915352f7f91STakashi Iwai /* No individual DAC for extra surrounds */ 916352f7f91STakashi Iwai BAD_NO_EXTRA_SURR_DAC = 0x101, 917352f7f91STakashi Iwai /* Primary DAC shared with main surrounds */ 918352f7f91STakashi Iwai BAD_SHARED_SURROUND = 0x100, 919352f7f91STakashi Iwai /* Primary DAC shared with main CLFE */ 920352f7f91STakashi Iwai BAD_SHARED_CLFE = 0x10, 921352f7f91STakashi Iwai /* Primary DAC shared with extra surrounds */ 922352f7f91STakashi Iwai BAD_SHARED_EXTRA_SURROUND = 0x10, 923352f7f91STakashi Iwai /* Volume widget is shared */ 924352f7f91STakashi Iwai BAD_SHARED_VOL = 0x10, 925352f7f91STakashi Iwai }; 926352f7f91STakashi Iwai 9270e614dd0STakashi Iwai /* look for widgets in the given path which are appropriate for 928352f7f91STakashi Iwai * volume and mute controls, and assign the values to ctls[]. 929352f7f91STakashi Iwai * 930352f7f91STakashi Iwai * When no appropriate widget is found in the path, the badness value 931352f7f91STakashi Iwai * is incremented depending on the situation. The function returns the 932352f7f91STakashi Iwai * total badness for both volume and mute controls. 933352f7f91STakashi Iwai */ 9340e614dd0STakashi Iwai static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path) 935352f7f91STakashi Iwai { 936352f7f91STakashi Iwai hda_nid_t nid; 937352f7f91STakashi Iwai unsigned int val; 938352f7f91STakashi Iwai int badness = 0; 939352f7f91STakashi Iwai 940352f7f91STakashi Iwai if (!path) 941352f7f91STakashi Iwai return BAD_SHARED_VOL * 2; 9420e614dd0STakashi Iwai 9430e614dd0STakashi Iwai if (path->ctls[NID_PATH_VOL_CTL] || 9440e614dd0STakashi Iwai path->ctls[NID_PATH_MUTE_CTL]) 9450e614dd0STakashi Iwai return 0; /* already evaluated */ 9460e614dd0STakashi Iwai 947352f7f91STakashi Iwai nid = look_for_out_vol_nid(codec, path); 948352f7f91STakashi Iwai if (nid) { 949352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 950352f7f91STakashi Iwai if (is_ctl_used(codec, val, NID_PATH_VOL_CTL)) 951352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 952352f7f91STakashi Iwai else 953352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = val; 954352f7f91STakashi Iwai } else 955352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 956352f7f91STakashi Iwai nid = look_for_out_mute_nid(codec, path); 957352f7f91STakashi Iwai if (nid) { 958352f7f91STakashi Iwai unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid)); 959352f7f91STakashi Iwai if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT || 960352f7f91STakashi Iwai nid_has_mute(codec, nid, HDA_OUTPUT)) 961352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 962352f7f91STakashi Iwai else 963352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); 964352f7f91STakashi Iwai if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL)) 965352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 966352f7f91STakashi Iwai else 967352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = val; 968352f7f91STakashi Iwai } else 969352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 970352f7f91STakashi Iwai return badness; 971352f7f91STakashi Iwai } 972352f7f91STakashi Iwai 973352f7f91STakashi Iwai struct badness_table { 974352f7f91STakashi Iwai int no_primary_dac; /* no primary DAC */ 975352f7f91STakashi Iwai int no_dac; /* no secondary DACs */ 976352f7f91STakashi Iwai int shared_primary; /* primary DAC is shared with main output */ 977352f7f91STakashi Iwai int shared_surr; /* secondary DAC shared with main or primary */ 978352f7f91STakashi Iwai int shared_clfe; /* third DAC shared with main or primary */ 979352f7f91STakashi Iwai int shared_surr_main; /* secondary DAC sahred with main/DAC0 */ 980352f7f91STakashi Iwai }; 981352f7f91STakashi Iwai 982352f7f91STakashi Iwai static struct badness_table main_out_badness = { 983352f7f91STakashi Iwai .no_primary_dac = BAD_NO_PRIMARY_DAC, 984352f7f91STakashi Iwai .no_dac = BAD_NO_DAC, 985352f7f91STakashi Iwai .shared_primary = BAD_NO_PRIMARY_DAC, 986352f7f91STakashi Iwai .shared_surr = BAD_SHARED_SURROUND, 987352f7f91STakashi Iwai .shared_clfe = BAD_SHARED_CLFE, 988352f7f91STakashi Iwai .shared_surr_main = BAD_SHARED_SURROUND, 989352f7f91STakashi Iwai }; 990352f7f91STakashi Iwai 991352f7f91STakashi Iwai static struct badness_table extra_out_badness = { 992352f7f91STakashi Iwai .no_primary_dac = BAD_NO_DAC, 993352f7f91STakashi Iwai .no_dac = BAD_NO_DAC, 994352f7f91STakashi Iwai .shared_primary = BAD_NO_EXTRA_DAC, 995352f7f91STakashi Iwai .shared_surr = BAD_SHARED_EXTRA_SURROUND, 996352f7f91STakashi Iwai .shared_clfe = BAD_SHARED_EXTRA_SURROUND, 997352f7f91STakashi Iwai .shared_surr_main = BAD_NO_EXTRA_SURR_DAC, 998352f7f91STakashi Iwai }; 999352f7f91STakashi Iwai 10007385df61STakashi Iwai /* get the DAC of the primary output corresponding to the given array index */ 10017385df61STakashi Iwai static hda_nid_t get_primary_out(struct hda_codec *codec, int idx) 10027385df61STakashi Iwai { 10037385df61STakashi Iwai struct hda_gen_spec *spec = codec->spec; 10047385df61STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 10057385df61STakashi Iwai 10067385df61STakashi Iwai if (cfg->line_outs > idx) 10077385df61STakashi Iwai return spec->private_dac_nids[idx]; 10087385df61STakashi Iwai idx -= cfg->line_outs; 10097385df61STakashi Iwai if (spec->multi_ios > idx) 10107385df61STakashi Iwai return spec->multi_io[idx].dac; 10117385df61STakashi Iwai return 0; 10127385df61STakashi Iwai } 10137385df61STakashi Iwai 10147385df61STakashi Iwai /* return the DAC if it's reachable, otherwise zero */ 10157385df61STakashi Iwai static inline hda_nid_t try_dac(struct hda_codec *codec, 10167385df61STakashi Iwai hda_nid_t dac, hda_nid_t pin) 10177385df61STakashi Iwai { 10187385df61STakashi Iwai return is_reachable_path(codec, dac, pin) ? dac : 0; 10197385df61STakashi Iwai } 10207385df61STakashi Iwai 1021352f7f91STakashi Iwai /* try to assign DACs to pins and return the resultant badness */ 1022352f7f91STakashi Iwai static int try_assign_dacs(struct hda_codec *codec, int num_outs, 1023352f7f91STakashi Iwai const hda_nid_t *pins, hda_nid_t *dacs, 1024196c1766STakashi Iwai int *path_idx, 1025352f7f91STakashi Iwai const struct badness_table *bad) 1026352f7f91STakashi Iwai { 1027352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1028352f7f91STakashi Iwai int i, j; 1029352f7f91STakashi Iwai int badness = 0; 1030352f7f91STakashi Iwai hda_nid_t dac; 1031352f7f91STakashi Iwai 1032352f7f91STakashi Iwai if (!num_outs) 1033352f7f91STakashi Iwai return 0; 1034352f7f91STakashi Iwai 1035352f7f91STakashi Iwai for (i = 0; i < num_outs; i++) { 10360c8c0f56STakashi Iwai struct nid_path *path; 1037352f7f91STakashi Iwai hda_nid_t pin = pins[i]; 10381e0b5286STakashi Iwai 10390e614dd0STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx[i]); 10400e614dd0STakashi Iwai if (path) { 10410e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path); 10421e0b5286STakashi Iwai continue; 10431e0b5286STakashi Iwai } 10441e0b5286STakashi Iwai 1045352f7f91STakashi Iwai dacs[i] = look_for_dac(codec, pin, false); 1046352f7f91STakashi Iwai if (!dacs[i] && !i) { 1047980428ceSTakashi Iwai /* try to steal the DAC of surrounds for the front */ 1048352f7f91STakashi Iwai for (j = 1; j < num_outs; j++) { 1049352f7f91STakashi Iwai if (is_reachable_path(codec, dacs[j], pin)) { 1050352f7f91STakashi Iwai dacs[0] = dacs[j]; 1051352f7f91STakashi Iwai dacs[j] = 0; 1052980428ceSTakashi Iwai invalidate_nid_path(codec, path_idx[j]); 1053196c1766STakashi Iwai path_idx[j] = 0; 1054352f7f91STakashi Iwai break; 1055352f7f91STakashi Iwai } 1056352f7f91STakashi Iwai } 1057352f7f91STakashi Iwai } 1058352f7f91STakashi Iwai dac = dacs[i]; 1059352f7f91STakashi Iwai if (!dac) { 10607385df61STakashi Iwai if (num_outs > 2) 10617385df61STakashi Iwai dac = try_dac(codec, get_primary_out(codec, i), pin); 10627385df61STakashi Iwai if (!dac) 10637385df61STakashi Iwai dac = try_dac(codec, dacs[0], pin); 10647385df61STakashi Iwai if (!dac) 10657385df61STakashi Iwai dac = try_dac(codec, get_primary_out(codec, i), pin); 1066352f7f91STakashi Iwai if (dac) { 1067352f7f91STakashi Iwai if (!i) 1068352f7f91STakashi Iwai badness += bad->shared_primary; 1069352f7f91STakashi Iwai else if (i == 1) 1070352f7f91STakashi Iwai badness += bad->shared_surr; 1071352f7f91STakashi Iwai else 1072352f7f91STakashi Iwai badness += bad->shared_clfe; 1073352f7f91STakashi Iwai } else if (is_reachable_path(codec, spec->private_dac_nids[0], pin)) { 1074352f7f91STakashi Iwai dac = spec->private_dac_nids[0]; 1075352f7f91STakashi Iwai badness += bad->shared_surr_main; 1076352f7f91STakashi Iwai } else if (!i) 1077352f7f91STakashi Iwai badness += bad->no_primary_dac; 1078352f7f91STakashi Iwai else 1079352f7f91STakashi Iwai badness += bad->no_dac; 1080352f7f91STakashi Iwai } 10813ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, -spec->mixer_nid); 1082117688a9STakashi Iwai if (!path && !i && spec->mixer_nid) { 1083b3a8c745STakashi Iwai /* try with aamix */ 10843ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, 0); 1085b3a8c745STakashi Iwai } 10860c8c0f56STakashi Iwai if (!path) 1087352f7f91STakashi Iwai dac = dacs[i] = 0; 1088e1284af7STakashi Iwai else { 10890c8c0f56STakashi Iwai print_nid_path("output", path); 1090e1284af7STakashi Iwai path->active = true; 1091196c1766STakashi Iwai path_idx[i] = snd_hda_get_path_idx(codec, path); 10920e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path); 1093e1284af7STakashi Iwai } 1094352f7f91STakashi Iwai } 1095352f7f91STakashi Iwai 1096352f7f91STakashi Iwai return badness; 1097352f7f91STakashi Iwai } 1098352f7f91STakashi Iwai 1099352f7f91STakashi Iwai /* return NID if the given pin has only a single connection to a certain DAC */ 1100352f7f91STakashi Iwai static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) 1101352f7f91STakashi Iwai { 1102352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1103352f7f91STakashi Iwai int i; 1104352f7f91STakashi Iwai hda_nid_t nid_found = 0; 1105352f7f91STakashi Iwai 1106352f7f91STakashi Iwai for (i = 0; i < spec->num_all_dacs; i++) { 1107352f7f91STakashi Iwai hda_nid_t nid = spec->all_dacs[i]; 1108352f7f91STakashi Iwai if (!nid || is_dac_already_used(codec, nid)) 1109352f7f91STakashi Iwai continue; 1110352f7f91STakashi Iwai if (is_reachable_path(codec, nid, pin)) { 1111352f7f91STakashi Iwai if (nid_found) 1112352f7f91STakashi Iwai return 0; 1113352f7f91STakashi Iwai nid_found = nid; 1114352f7f91STakashi Iwai } 1115352f7f91STakashi Iwai } 1116352f7f91STakashi Iwai return nid_found; 1117352f7f91STakashi Iwai } 1118352f7f91STakashi Iwai 1119352f7f91STakashi Iwai /* check whether the given pin can be a multi-io pin */ 1120352f7f91STakashi Iwai static bool can_be_multiio_pin(struct hda_codec *codec, 1121352f7f91STakashi Iwai unsigned int location, hda_nid_t nid) 1122352f7f91STakashi Iwai { 1123352f7f91STakashi Iwai unsigned int defcfg, caps; 1124352f7f91STakashi Iwai 1125352f7f91STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, nid); 1126352f7f91STakashi Iwai if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) 1127352f7f91STakashi Iwai return false; 1128352f7f91STakashi Iwai if (location && get_defcfg_location(defcfg) != location) 1129352f7f91STakashi Iwai return false; 1130352f7f91STakashi Iwai caps = snd_hda_query_pin_caps(codec, nid); 1131352f7f91STakashi Iwai if (!(caps & AC_PINCAP_OUT)) 1132352f7f91STakashi Iwai return false; 1133352f7f91STakashi Iwai return true; 1134352f7f91STakashi Iwai } 1135352f7f91STakashi Iwai 1136e22aab7dSTakashi Iwai /* count the number of input pins that are capable to be multi-io */ 1137e22aab7dSTakashi Iwai static int count_multiio_pins(struct hda_codec *codec, hda_nid_t reference_pin) 1138e22aab7dSTakashi Iwai { 1139e22aab7dSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 1140e22aab7dSTakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1141e22aab7dSTakashi Iwai unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); 1142e22aab7dSTakashi Iwai unsigned int location = get_defcfg_location(defcfg); 1143e22aab7dSTakashi Iwai int type, i; 1144e22aab7dSTakashi Iwai int num_pins = 0; 1145e22aab7dSTakashi Iwai 1146e22aab7dSTakashi Iwai for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { 1147e22aab7dSTakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 1148e22aab7dSTakashi Iwai if (cfg->inputs[i].type != type) 1149e22aab7dSTakashi Iwai continue; 1150e22aab7dSTakashi Iwai if (can_be_multiio_pin(codec, location, 1151e22aab7dSTakashi Iwai cfg->inputs[i].pin)) 1152e22aab7dSTakashi Iwai num_pins++; 1153e22aab7dSTakashi Iwai } 1154e22aab7dSTakashi Iwai } 1155e22aab7dSTakashi Iwai return num_pins; 1156e22aab7dSTakashi Iwai } 1157e22aab7dSTakashi Iwai 1158352f7f91STakashi Iwai /* 1159352f7f91STakashi Iwai * multi-io helper 1160352f7f91STakashi Iwai * 1161352f7f91STakashi Iwai * When hardwired is set, try to fill ony hardwired pins, and returns 1162352f7f91STakashi Iwai * zero if any pins are filled, non-zero if nothing found. 1163352f7f91STakashi Iwai * When hardwired is off, try to fill possible input pins, and returns 1164352f7f91STakashi Iwai * the badness value. 1165352f7f91STakashi Iwai */ 1166352f7f91STakashi Iwai static int fill_multi_ios(struct hda_codec *codec, 1167352f7f91STakashi Iwai hda_nid_t reference_pin, 1168e22aab7dSTakashi Iwai bool hardwired) 1169352f7f91STakashi Iwai { 1170352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1171352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1172e22aab7dSTakashi Iwai int type, i, j, num_pins, old_pins; 1173352f7f91STakashi Iwai unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); 1174352f7f91STakashi Iwai unsigned int location = get_defcfg_location(defcfg); 1175352f7f91STakashi Iwai int badness = 0; 11760e614dd0STakashi Iwai struct nid_path *path; 1177352f7f91STakashi Iwai 1178352f7f91STakashi Iwai old_pins = spec->multi_ios; 1179352f7f91STakashi Iwai if (old_pins >= 2) 1180352f7f91STakashi Iwai goto end_fill; 1181352f7f91STakashi Iwai 1182e22aab7dSTakashi Iwai num_pins = count_multiio_pins(codec, reference_pin); 1183352f7f91STakashi Iwai if (num_pins < 2) 1184352f7f91STakashi Iwai goto end_fill; 1185352f7f91STakashi Iwai 1186352f7f91STakashi Iwai for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { 1187352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 1188352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 1189352f7f91STakashi Iwai hda_nid_t dac = 0; 1190352f7f91STakashi Iwai 1191352f7f91STakashi Iwai if (cfg->inputs[i].type != type) 1192352f7f91STakashi Iwai continue; 1193352f7f91STakashi Iwai if (!can_be_multiio_pin(codec, location, nid)) 1194352f7f91STakashi Iwai continue; 1195352f7f91STakashi Iwai for (j = 0; j < spec->multi_ios; j++) { 1196352f7f91STakashi Iwai if (nid == spec->multi_io[j].pin) 1197352f7f91STakashi Iwai break; 1198352f7f91STakashi Iwai } 1199352f7f91STakashi Iwai if (j < spec->multi_ios) 1200352f7f91STakashi Iwai continue; 1201352f7f91STakashi Iwai 1202352f7f91STakashi Iwai if (hardwired) 1203352f7f91STakashi Iwai dac = get_dac_if_single(codec, nid); 1204352f7f91STakashi Iwai else if (!dac) 1205352f7f91STakashi Iwai dac = look_for_dac(codec, nid, false); 1206352f7f91STakashi Iwai if (!dac) { 1207352f7f91STakashi Iwai badness++; 1208352f7f91STakashi Iwai continue; 1209352f7f91STakashi Iwai } 12103ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, nid, 12113ca529d3STakashi Iwai -spec->mixer_nid); 12120c8c0f56STakashi Iwai if (!path) { 1213352f7f91STakashi Iwai badness++; 1214352f7f91STakashi Iwai continue; 1215352f7f91STakashi Iwai } 12160c8c0f56STakashi Iwai print_nid_path("multiio", path); 1217352f7f91STakashi Iwai spec->multi_io[spec->multi_ios].pin = nid; 1218352f7f91STakashi Iwai spec->multi_io[spec->multi_ios].dac = dac; 1219196c1766STakashi Iwai spec->out_paths[cfg->line_outs + spec->multi_ios] = 1220196c1766STakashi Iwai snd_hda_get_path_idx(codec, path); 1221352f7f91STakashi Iwai spec->multi_ios++; 1222352f7f91STakashi Iwai if (spec->multi_ios >= 2) 1223352f7f91STakashi Iwai break; 1224352f7f91STakashi Iwai } 1225352f7f91STakashi Iwai } 1226352f7f91STakashi Iwai end_fill: 1227352f7f91STakashi Iwai if (badness) 1228352f7f91STakashi Iwai badness = BAD_MULTI_IO; 1229352f7f91STakashi Iwai if (old_pins == spec->multi_ios) { 1230352f7f91STakashi Iwai if (hardwired) 1231352f7f91STakashi Iwai return 1; /* nothing found */ 1232352f7f91STakashi Iwai else 1233352f7f91STakashi Iwai return badness; /* no badness if nothing found */ 1234352f7f91STakashi Iwai } 1235352f7f91STakashi Iwai if (!hardwired && spec->multi_ios < 2) { 1236352f7f91STakashi Iwai /* cancel newly assigned paths */ 1237352f7f91STakashi Iwai spec->paths.used -= spec->multi_ios - old_pins; 1238352f7f91STakashi Iwai spec->multi_ios = old_pins; 1239352f7f91STakashi Iwai return badness; 1240352f7f91STakashi Iwai } 1241352f7f91STakashi Iwai 1242352f7f91STakashi Iwai /* assign volume and mute controls */ 12430e614dd0STakashi Iwai for (i = old_pins; i < spec->multi_ios; i++) { 12440e614dd0STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[cfg->line_outs + i]); 12450e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path); 12460e614dd0STakashi Iwai } 1247352f7f91STakashi Iwai 1248352f7f91STakashi Iwai return badness; 1249352f7f91STakashi Iwai } 1250352f7f91STakashi Iwai 1251352f7f91STakashi Iwai /* map DACs for all pins in the list if they are single connections */ 1252352f7f91STakashi Iwai static bool map_singles(struct hda_codec *codec, int outs, 1253196c1766STakashi Iwai const hda_nid_t *pins, hda_nid_t *dacs, int *path_idx) 1254352f7f91STakashi Iwai { 1255b3a8c745STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1256352f7f91STakashi Iwai int i; 1257352f7f91STakashi Iwai bool found = false; 1258352f7f91STakashi Iwai for (i = 0; i < outs; i++) { 12590c8c0f56STakashi Iwai struct nid_path *path; 1260352f7f91STakashi Iwai hda_nid_t dac; 1261352f7f91STakashi Iwai if (dacs[i]) 1262352f7f91STakashi Iwai continue; 1263352f7f91STakashi Iwai dac = get_dac_if_single(codec, pins[i]); 1264352f7f91STakashi Iwai if (!dac) 1265352f7f91STakashi Iwai continue; 12663ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pins[i], 12673ca529d3STakashi Iwai -spec->mixer_nid); 1268117688a9STakashi Iwai if (!path && !i && spec->mixer_nid) 12693ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pins[i], 0); 12700c8c0f56STakashi Iwai if (path) { 1271352f7f91STakashi Iwai dacs[i] = dac; 1272352f7f91STakashi Iwai found = true; 12730c8c0f56STakashi Iwai print_nid_path("output", path); 1274e1284af7STakashi Iwai path->active = true; 1275196c1766STakashi Iwai path_idx[i] = snd_hda_get_path_idx(codec, path); 1276352f7f91STakashi Iwai } 1277352f7f91STakashi Iwai } 1278352f7f91STakashi Iwai return found; 1279352f7f91STakashi Iwai } 1280352f7f91STakashi Iwai 1281c30aa7b2STakashi Iwai /* create a new path including aamix if available, and return its index */ 1282c30aa7b2STakashi Iwai static int check_aamix_out_path(struct hda_codec *codec, int path_idx) 1283c30aa7b2STakashi Iwai { 12843ca529d3STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1285c30aa7b2STakashi Iwai struct nid_path *path; 1286c30aa7b2STakashi Iwai 1287c30aa7b2STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 12883ca529d3STakashi Iwai if (!path || !path->depth || 12893ca529d3STakashi Iwai is_nid_contained(path, spec->mixer_nid)) 1290c30aa7b2STakashi Iwai return 0; 1291c30aa7b2STakashi Iwai path = snd_hda_add_new_path(codec, path->path[0], 1292c30aa7b2STakashi Iwai path->path[path->depth - 1], 12933ca529d3STakashi Iwai spec->mixer_nid); 1294c30aa7b2STakashi Iwai if (!path) 1295c30aa7b2STakashi Iwai return 0; 1296c30aa7b2STakashi Iwai print_nid_path("output-aamix", path); 1297c30aa7b2STakashi Iwai path->active = false; /* unused as default */ 1298c30aa7b2STakashi Iwai return snd_hda_get_path_idx(codec, path); 1299c30aa7b2STakashi Iwai } 1300c30aa7b2STakashi Iwai 1301a07a949bSTakashi Iwai /* fill the empty entries in the dac array for speaker/hp with the 1302a07a949bSTakashi Iwai * shared dac pointed by the paths 1303a07a949bSTakashi Iwai */ 1304a07a949bSTakashi Iwai static void refill_shared_dacs(struct hda_codec *codec, int num_outs, 1305a07a949bSTakashi Iwai hda_nid_t *dacs, int *path_idx) 1306a07a949bSTakashi Iwai { 1307a07a949bSTakashi Iwai struct nid_path *path; 1308a07a949bSTakashi Iwai int i; 1309a07a949bSTakashi Iwai 1310a07a949bSTakashi Iwai for (i = 0; i < num_outs; i++) { 1311a07a949bSTakashi Iwai if (dacs[i]) 1312a07a949bSTakashi Iwai continue; 1313a07a949bSTakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx[i]); 1314a07a949bSTakashi Iwai if (!path) 1315a07a949bSTakashi Iwai continue; 1316a07a949bSTakashi Iwai dacs[i] = path->path[0]; 1317a07a949bSTakashi Iwai } 1318a07a949bSTakashi Iwai } 1319a07a949bSTakashi Iwai 1320352f7f91STakashi Iwai /* fill in the dac_nids table from the parsed pin configuration */ 1321352f7f91STakashi Iwai static int fill_and_eval_dacs(struct hda_codec *codec, 1322352f7f91STakashi Iwai bool fill_hardwired, 1323352f7f91STakashi Iwai bool fill_mio_first) 1324352f7f91STakashi Iwai { 1325352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1326352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1327352f7f91STakashi Iwai int i, err, badness; 1328ea46c3c8STakashi Iwai unsigned int val; 1329352f7f91STakashi Iwai 1330352f7f91STakashi Iwai /* set num_dacs once to full for look_for_dac() */ 1331352f7f91STakashi Iwai spec->multiout.num_dacs = cfg->line_outs; 1332352f7f91STakashi Iwai spec->multiout.dac_nids = spec->private_dac_nids; 1333352f7f91STakashi Iwai memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); 1334352f7f91STakashi Iwai memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid)); 1335352f7f91STakashi Iwai memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid)); 1336352f7f91STakashi Iwai spec->multi_ios = 0; 1337352f7f91STakashi Iwai snd_array_free(&spec->paths); 1338cd5be3f9STakashi Iwai 1339cd5be3f9STakashi Iwai /* clear path indices */ 1340cd5be3f9STakashi Iwai memset(spec->out_paths, 0, sizeof(spec->out_paths)); 1341cd5be3f9STakashi Iwai memset(spec->hp_paths, 0, sizeof(spec->hp_paths)); 1342cd5be3f9STakashi Iwai memset(spec->speaker_paths, 0, sizeof(spec->speaker_paths)); 1343cd5be3f9STakashi Iwai memset(spec->aamix_out_paths, 0, sizeof(spec->aamix_out_paths)); 1344cd5be3f9STakashi Iwai memset(spec->digout_paths, 0, sizeof(spec->digout_paths)); 1345c697b716STakashi Iwai memset(spec->input_paths, 0, sizeof(spec->input_paths)); 1346cd5be3f9STakashi Iwai memset(spec->loopback_paths, 0, sizeof(spec->loopback_paths)); 1347cd5be3f9STakashi Iwai memset(&spec->digin_path, 0, sizeof(spec->digin_path)); 1348cd5be3f9STakashi Iwai 1349352f7f91STakashi Iwai badness = 0; 1350352f7f91STakashi Iwai 1351352f7f91STakashi Iwai /* fill hard-wired DACs first */ 1352352f7f91STakashi Iwai if (fill_hardwired) { 1353352f7f91STakashi Iwai bool mapped; 1354352f7f91STakashi Iwai do { 1355352f7f91STakashi Iwai mapped = map_singles(codec, cfg->line_outs, 1356352f7f91STakashi Iwai cfg->line_out_pins, 1357196c1766STakashi Iwai spec->private_dac_nids, 1358196c1766STakashi Iwai spec->out_paths); 1359352f7f91STakashi Iwai mapped |= map_singles(codec, cfg->hp_outs, 1360352f7f91STakashi Iwai cfg->hp_pins, 1361196c1766STakashi Iwai spec->multiout.hp_out_nid, 1362196c1766STakashi Iwai spec->hp_paths); 1363352f7f91STakashi Iwai mapped |= map_singles(codec, cfg->speaker_outs, 1364352f7f91STakashi Iwai cfg->speaker_pins, 1365196c1766STakashi Iwai spec->multiout.extra_out_nid, 1366196c1766STakashi Iwai spec->speaker_paths); 1367352f7f91STakashi Iwai if (fill_mio_first && cfg->line_outs == 1 && 1368352f7f91STakashi Iwai cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1369e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], true); 1370352f7f91STakashi Iwai if (!err) 1371352f7f91STakashi Iwai mapped = true; 1372352f7f91STakashi Iwai } 1373352f7f91STakashi Iwai } while (mapped); 1374352f7f91STakashi Iwai } 1375352f7f91STakashi Iwai 1376352f7f91STakashi Iwai badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins, 1377196c1766STakashi Iwai spec->private_dac_nids, spec->out_paths, 1378352f7f91STakashi Iwai &main_out_badness); 1379352f7f91STakashi Iwai 1380352f7f91STakashi Iwai if (fill_mio_first && 1381352f7f91STakashi Iwai cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1382352f7f91STakashi Iwai /* try to fill multi-io first */ 1383e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], false); 1384352f7f91STakashi Iwai if (err < 0) 1385352f7f91STakashi Iwai return err; 1386352f7f91STakashi Iwai /* we don't count badness at this stage yet */ 1387352f7f91STakashi Iwai } 1388352f7f91STakashi Iwai 1389352f7f91STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) { 1390352f7f91STakashi Iwai err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins, 1391352f7f91STakashi Iwai spec->multiout.hp_out_nid, 1392196c1766STakashi Iwai spec->hp_paths, 1393352f7f91STakashi Iwai &extra_out_badness); 1394352f7f91STakashi Iwai if (err < 0) 1395352f7f91STakashi Iwai return err; 1396352f7f91STakashi Iwai badness += err; 1397352f7f91STakashi Iwai } 1398352f7f91STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1399352f7f91STakashi Iwai err = try_assign_dacs(codec, cfg->speaker_outs, 1400352f7f91STakashi Iwai cfg->speaker_pins, 1401352f7f91STakashi Iwai spec->multiout.extra_out_nid, 1402196c1766STakashi Iwai spec->speaker_paths, 1403352f7f91STakashi Iwai &extra_out_badness); 1404352f7f91STakashi Iwai if (err < 0) 1405352f7f91STakashi Iwai return err; 1406352f7f91STakashi Iwai badness += err; 1407352f7f91STakashi Iwai } 1408352f7f91STakashi Iwai if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1409e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], false); 1410352f7f91STakashi Iwai if (err < 0) 1411352f7f91STakashi Iwai return err; 1412352f7f91STakashi Iwai badness += err; 1413352f7f91STakashi Iwai } 1414e22aab7dSTakashi Iwai 1415c30aa7b2STakashi Iwai if (spec->mixer_nid) { 1416c30aa7b2STakashi Iwai spec->aamix_out_paths[0] = 1417c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->out_paths[0]); 1418c30aa7b2STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 1419c30aa7b2STakashi Iwai spec->aamix_out_paths[1] = 1420c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->hp_paths[0]); 1421c30aa7b2STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 1422c30aa7b2STakashi Iwai spec->aamix_out_paths[2] = 1423c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->speaker_paths[0]); 1424c30aa7b2STakashi Iwai } 1425c30aa7b2STakashi Iwai 1426e22aab7dSTakashi Iwai if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) 1427e22aab7dSTakashi Iwai if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2) 1428e22aab7dSTakashi Iwai spec->multi_ios = 1; /* give badness */ 1429352f7f91STakashi Iwai 1430a07a949bSTakashi Iwai /* re-count num_dacs and squash invalid entries */ 1431a07a949bSTakashi Iwai spec->multiout.num_dacs = 0; 1432a07a949bSTakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 1433a07a949bSTakashi Iwai if (spec->private_dac_nids[i]) 1434a07a949bSTakashi Iwai spec->multiout.num_dacs++; 1435a07a949bSTakashi Iwai else { 1436a07a949bSTakashi Iwai memmove(spec->private_dac_nids + i, 1437a07a949bSTakashi Iwai spec->private_dac_nids + i + 1, 1438a07a949bSTakashi Iwai sizeof(hda_nid_t) * (cfg->line_outs - i - 1)); 1439a07a949bSTakashi Iwai spec->private_dac_nids[cfg->line_outs - 1] = 0; 1440a07a949bSTakashi Iwai } 1441a07a949bSTakashi Iwai } 1442a07a949bSTakashi Iwai 1443a07a949bSTakashi Iwai spec->ext_channel_count = spec->min_channel_count = 1444c0f3b216SDavid Henningsson spec->multiout.num_dacs * 2; 1445a07a949bSTakashi Iwai 1446352f7f91STakashi Iwai if (spec->multi_ios == 2) { 1447352f7f91STakashi Iwai for (i = 0; i < 2; i++) 1448352f7f91STakashi Iwai spec->private_dac_nids[spec->multiout.num_dacs++] = 1449352f7f91STakashi Iwai spec->multi_io[i].dac; 1450352f7f91STakashi Iwai } else if (spec->multi_ios) { 1451352f7f91STakashi Iwai spec->multi_ios = 0; 1452352f7f91STakashi Iwai badness += BAD_MULTI_IO; 1453352f7f91STakashi Iwai } 1454352f7f91STakashi Iwai 1455a07a949bSTakashi Iwai /* re-fill the shared DAC for speaker / headphone */ 1456a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 1457a07a949bSTakashi Iwai refill_shared_dacs(codec, cfg->hp_outs, 1458a07a949bSTakashi Iwai spec->multiout.hp_out_nid, 1459a07a949bSTakashi Iwai spec->hp_paths); 1460a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 1461a07a949bSTakashi Iwai refill_shared_dacs(codec, cfg->speaker_outs, 1462a07a949bSTakashi Iwai spec->multiout.extra_out_nid, 1463a07a949bSTakashi Iwai spec->speaker_paths); 1464a07a949bSTakashi Iwai 14652c12c30dSTakashi Iwai /* set initial pinctl targets */ 1466ea46c3c8STakashi Iwai if (spec->prefer_hp_amp || cfg->line_out_type == AUTO_PIN_HP_OUT) 1467ea46c3c8STakashi Iwai val = PIN_HP; 1468ea46c3c8STakashi Iwai else 1469ea46c3c8STakashi Iwai val = PIN_OUT; 1470ea46c3c8STakashi Iwai set_pin_targets(codec, cfg->line_outs, cfg->line_out_pins, val); 14712c12c30dSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 14722c12c30dSTakashi Iwai set_pin_targets(codec, cfg->hp_outs, cfg->hp_pins, PIN_HP); 1473ea46c3c8STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1474ea46c3c8STakashi Iwai val = spec->prefer_hp_amp ? PIN_HP : PIN_OUT; 14752c12c30dSTakashi Iwai set_pin_targets(codec, cfg->speaker_outs, 1476ea46c3c8STakashi Iwai cfg->speaker_pins, val); 1477ea46c3c8STakashi Iwai } 14782c12c30dSTakashi Iwai 1479352f7f91STakashi Iwai return badness; 1480352f7f91STakashi Iwai } 1481352f7f91STakashi Iwai 1482352f7f91STakashi Iwai #define DEBUG_BADNESS 1483352f7f91STakashi Iwai 1484352f7f91STakashi Iwai #ifdef DEBUG_BADNESS 1485352f7f91STakashi Iwai #define debug_badness snd_printdd 1486352f7f91STakashi Iwai #else 1487352f7f91STakashi Iwai #define debug_badness(...) 1488352f7f91STakashi Iwai #endif 1489352f7f91STakashi Iwai 1490352f7f91STakashi Iwai static void debug_show_configs(struct hda_gen_spec *spec, struct auto_pin_cfg *cfg) 1491352f7f91STakashi Iwai { 1492352f7f91STakashi Iwai debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1493352f7f91STakashi Iwai cfg->line_out_pins[0], cfg->line_out_pins[1], 1494708122e8STakashi Iwai cfg->line_out_pins[2], cfg->line_out_pins[3], 1495352f7f91STakashi Iwai spec->multiout.dac_nids[0], 1496352f7f91STakashi Iwai spec->multiout.dac_nids[1], 1497352f7f91STakashi Iwai spec->multiout.dac_nids[2], 1498352f7f91STakashi Iwai spec->multiout.dac_nids[3]); 1499352f7f91STakashi Iwai if (spec->multi_ios > 0) 1500352f7f91STakashi Iwai debug_badness("multi_ios(%d) = %x/%x : %x/%x\n", 1501352f7f91STakashi Iwai spec->multi_ios, 1502352f7f91STakashi Iwai spec->multi_io[0].pin, spec->multi_io[1].pin, 1503352f7f91STakashi Iwai spec->multi_io[0].dac, spec->multi_io[1].dac); 1504352f7f91STakashi Iwai debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1505352f7f91STakashi Iwai cfg->hp_pins[0], cfg->hp_pins[1], 1506708122e8STakashi Iwai cfg->hp_pins[2], cfg->hp_pins[3], 1507352f7f91STakashi Iwai spec->multiout.hp_out_nid[0], 1508352f7f91STakashi Iwai spec->multiout.hp_out_nid[1], 1509352f7f91STakashi Iwai spec->multiout.hp_out_nid[2], 1510352f7f91STakashi Iwai spec->multiout.hp_out_nid[3]); 1511352f7f91STakashi Iwai debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1512352f7f91STakashi Iwai cfg->speaker_pins[0], cfg->speaker_pins[1], 1513352f7f91STakashi Iwai cfg->speaker_pins[2], cfg->speaker_pins[3], 1514352f7f91STakashi Iwai spec->multiout.extra_out_nid[0], 1515352f7f91STakashi Iwai spec->multiout.extra_out_nid[1], 1516352f7f91STakashi Iwai spec->multiout.extra_out_nid[2], 1517352f7f91STakashi Iwai spec->multiout.extra_out_nid[3]); 1518352f7f91STakashi Iwai } 1519352f7f91STakashi Iwai 1520352f7f91STakashi Iwai /* find all available DACs of the codec */ 1521352f7f91STakashi Iwai static void fill_all_dac_nids(struct hda_codec *codec) 1522352f7f91STakashi Iwai { 1523352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1524352f7f91STakashi Iwai int i; 1525352f7f91STakashi Iwai hda_nid_t nid = codec->start_nid; 1526352f7f91STakashi Iwai 1527352f7f91STakashi Iwai spec->num_all_dacs = 0; 1528352f7f91STakashi Iwai memset(spec->all_dacs, 0, sizeof(spec->all_dacs)); 1529352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) { 1530352f7f91STakashi Iwai if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT) 1531352f7f91STakashi Iwai continue; 1532352f7f91STakashi Iwai if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) { 1533352f7f91STakashi Iwai snd_printk(KERN_ERR "hda: Too many DACs!\n"); 1534352f7f91STakashi Iwai break; 1535352f7f91STakashi Iwai } 1536352f7f91STakashi Iwai spec->all_dacs[spec->num_all_dacs++] = nid; 1537352f7f91STakashi Iwai } 1538352f7f91STakashi Iwai } 1539352f7f91STakashi Iwai 1540352f7f91STakashi Iwai static int parse_output_paths(struct hda_codec *codec) 1541352f7f91STakashi Iwai { 1542352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1543352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1544352f7f91STakashi Iwai struct auto_pin_cfg *best_cfg; 1545352f7f91STakashi Iwai int best_badness = INT_MAX; 1546352f7f91STakashi Iwai int badness; 1547352f7f91STakashi Iwai bool fill_hardwired = true, fill_mio_first = true; 1548352f7f91STakashi Iwai bool best_wired = true, best_mio = true; 1549352f7f91STakashi Iwai bool hp_spk_swapped = false; 1550352f7f91STakashi Iwai 1551352f7f91STakashi Iwai best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL); 1552352f7f91STakashi Iwai if (!best_cfg) 1553352f7f91STakashi Iwai return -ENOMEM; 1554352f7f91STakashi Iwai *best_cfg = *cfg; 1555352f7f91STakashi Iwai 1556352f7f91STakashi Iwai for (;;) { 1557352f7f91STakashi Iwai badness = fill_and_eval_dacs(codec, fill_hardwired, 1558352f7f91STakashi Iwai fill_mio_first); 1559352f7f91STakashi Iwai if (badness < 0) { 1560352f7f91STakashi Iwai kfree(best_cfg); 1561352f7f91STakashi Iwai return badness; 1562352f7f91STakashi Iwai } 1563352f7f91STakashi Iwai debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n", 1564352f7f91STakashi Iwai cfg->line_out_type, fill_hardwired, fill_mio_first, 1565352f7f91STakashi Iwai badness); 1566352f7f91STakashi Iwai debug_show_configs(spec, cfg); 1567352f7f91STakashi Iwai if (badness < best_badness) { 1568352f7f91STakashi Iwai best_badness = badness; 1569352f7f91STakashi Iwai *best_cfg = *cfg; 1570352f7f91STakashi Iwai best_wired = fill_hardwired; 1571352f7f91STakashi Iwai best_mio = fill_mio_first; 1572352f7f91STakashi Iwai } 1573352f7f91STakashi Iwai if (!badness) 1574352f7f91STakashi Iwai break; 1575352f7f91STakashi Iwai fill_mio_first = !fill_mio_first; 1576352f7f91STakashi Iwai if (!fill_mio_first) 1577352f7f91STakashi Iwai continue; 1578352f7f91STakashi Iwai fill_hardwired = !fill_hardwired; 1579352f7f91STakashi Iwai if (!fill_hardwired) 1580352f7f91STakashi Iwai continue; 1581352f7f91STakashi Iwai if (hp_spk_swapped) 1582352f7f91STakashi Iwai break; 1583352f7f91STakashi Iwai hp_spk_swapped = true; 1584352f7f91STakashi Iwai if (cfg->speaker_outs > 0 && 1585352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) { 1586352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs; 1587352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins, 1588352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 1589352f7f91STakashi Iwai cfg->line_outs = cfg->speaker_outs; 1590352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->speaker_pins, 1591352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 1592352f7f91STakashi Iwai cfg->speaker_outs = 0; 1593352f7f91STakashi Iwai memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); 1594352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; 1595352f7f91STakashi Iwai fill_hardwired = true; 1596352f7f91STakashi Iwai continue; 1597352f7f91STakashi Iwai } 1598352f7f91STakashi Iwai if (cfg->hp_outs > 0 && 1599352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { 1600352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 1601352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 1602352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 1603352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs; 1604352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins, 1605352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 1606352f7f91STakashi Iwai cfg->hp_outs = 0; 1607352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 1608352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT; 1609352f7f91STakashi Iwai fill_hardwired = true; 1610352f7f91STakashi Iwai continue; 1611352f7f91STakashi Iwai } 1612352f7f91STakashi Iwai break; 1613352f7f91STakashi Iwai } 1614352f7f91STakashi Iwai 1615352f7f91STakashi Iwai if (badness) { 16160c8c0f56STakashi Iwai debug_badness("==> restoring best_cfg\n"); 1617352f7f91STakashi Iwai *cfg = *best_cfg; 1618352f7f91STakashi Iwai fill_and_eval_dacs(codec, best_wired, best_mio); 1619352f7f91STakashi Iwai } 1620352f7f91STakashi Iwai debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n", 1621352f7f91STakashi Iwai cfg->line_out_type, best_wired, best_mio); 1622352f7f91STakashi Iwai debug_show_configs(spec, cfg); 1623352f7f91STakashi Iwai 1624352f7f91STakashi Iwai if (cfg->line_out_pins[0]) { 1625352f7f91STakashi Iwai struct nid_path *path; 1626196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]); 1627352f7f91STakashi Iwai if (path) 1628352f7f91STakashi Iwai spec->vmaster_nid = look_for_out_vol_nid(codec, path); 16297a71bbf3STakashi Iwai if (spec->vmaster_nid) 16307a71bbf3STakashi Iwai snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, 16317a71bbf3STakashi Iwai HDA_OUTPUT, spec->vmaster_tlv); 1632352f7f91STakashi Iwai } 1633352f7f91STakashi Iwai 1634352f7f91STakashi Iwai kfree(best_cfg); 1635352f7f91STakashi Iwai return 0; 1636352f7f91STakashi Iwai } 1637352f7f91STakashi Iwai 1638352f7f91STakashi Iwai /* add playback controls from the parsed DAC table */ 1639352f7f91STakashi Iwai static int create_multi_out_ctls(struct hda_codec *codec, 1640352f7f91STakashi Iwai const struct auto_pin_cfg *cfg) 1641352f7f91STakashi Iwai { 1642352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1643352f7f91STakashi Iwai int i, err, noutputs; 1644352f7f91STakashi Iwai 1645352f7f91STakashi Iwai noutputs = cfg->line_outs; 1646352f7f91STakashi Iwai if (spec->multi_ios > 0 && cfg->line_outs < 3) 1647352f7f91STakashi Iwai noutputs += spec->multi_ios; 1648352f7f91STakashi Iwai 1649352f7f91STakashi Iwai for (i = 0; i < noutputs; i++) { 1650352f7f91STakashi Iwai const char *name; 1651352f7f91STakashi Iwai int index; 1652352f7f91STakashi Iwai struct nid_path *path; 1653352f7f91STakashi Iwai 1654196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]); 1655352f7f91STakashi Iwai if (!path) 1656352f7f91STakashi Iwai continue; 1657247d85eeSTakashi Iwai 1658247d85eeSTakashi Iwai name = get_line_out_pfx(codec, i, &index, NID_PATH_VOL_CTL); 1659352f7f91STakashi Iwai if (!name || !strcmp(name, "CLFE")) { 1660352f7f91STakashi Iwai /* Center/LFE */ 1661352f7f91STakashi Iwai err = add_vol_ctl(codec, "Center", 0, 1, path); 1662352f7f91STakashi Iwai if (err < 0) 1663352f7f91STakashi Iwai return err; 1664352f7f91STakashi Iwai err = add_vol_ctl(codec, "LFE", 0, 2, path); 1665352f7f91STakashi Iwai if (err < 0) 1666352f7f91STakashi Iwai return err; 1667247d85eeSTakashi Iwai } else { 1668247d85eeSTakashi Iwai err = add_stereo_vol(codec, name, index, path); 1669247d85eeSTakashi Iwai if (err < 0) 1670247d85eeSTakashi Iwai return err; 1671247d85eeSTakashi Iwai } 1672247d85eeSTakashi Iwai 1673247d85eeSTakashi Iwai name = get_line_out_pfx(codec, i, &index, NID_PATH_MUTE_CTL); 1674247d85eeSTakashi Iwai if (!name || !strcmp(name, "CLFE")) { 1675352f7f91STakashi Iwai err = add_sw_ctl(codec, "Center", 0, 1, path); 1676352f7f91STakashi Iwai if (err < 0) 1677352f7f91STakashi Iwai return err; 1678352f7f91STakashi Iwai err = add_sw_ctl(codec, "LFE", 0, 2, path); 1679352f7f91STakashi Iwai if (err < 0) 1680352f7f91STakashi Iwai return err; 1681352f7f91STakashi Iwai } else { 1682352f7f91STakashi Iwai err = add_stereo_sw(codec, name, index, path); 1683352f7f91STakashi Iwai if (err < 0) 1684352f7f91STakashi Iwai return err; 1685352f7f91STakashi Iwai } 1686352f7f91STakashi Iwai } 1687352f7f91STakashi Iwai return 0; 1688352f7f91STakashi Iwai } 1689352f7f91STakashi Iwai 1690c2c80383STakashi Iwai static int create_extra_out(struct hda_codec *codec, int path_idx, 1691196c1766STakashi Iwai const char *pfx, int cidx) 1692352f7f91STakashi Iwai { 1693352f7f91STakashi Iwai struct nid_path *path; 1694352f7f91STakashi Iwai int err; 1695352f7f91STakashi Iwai 1696196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 1697352f7f91STakashi Iwai if (!path) 1698352f7f91STakashi Iwai return 0; 1699352f7f91STakashi Iwai err = add_stereo_vol(codec, pfx, cidx, path); 1700352f7f91STakashi Iwai if (err < 0) 1701352f7f91STakashi Iwai return err; 1702352f7f91STakashi Iwai err = add_stereo_sw(codec, pfx, cidx, path); 1703352f7f91STakashi Iwai if (err < 0) 1704352f7f91STakashi Iwai return err; 1705352f7f91STakashi Iwai return 0; 1706352f7f91STakashi Iwai } 1707352f7f91STakashi Iwai 1708352f7f91STakashi Iwai /* add playback controls for speaker and HP outputs */ 1709352f7f91STakashi Iwai static int create_extra_outs(struct hda_codec *codec, int num_pins, 1710196c1766STakashi Iwai const int *paths, const char *pfx) 1711352f7f91STakashi Iwai { 1712c2c80383STakashi Iwai int i; 1713352f7f91STakashi Iwai 1714352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 1715c2c80383STakashi Iwai const char *name; 1716c2c80383STakashi Iwai char tmp[44]; 1717c2c80383STakashi Iwai int err, idx = 0; 1718c2c80383STakashi Iwai 1719c2c80383STakashi Iwai if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) 1720c2c80383STakashi Iwai name = "Bass Speaker"; 1721c2c80383STakashi Iwai else if (num_pins >= 3) { 1722c2c80383STakashi Iwai snprintf(tmp, sizeof(tmp), "%s %s", 1723352f7f91STakashi Iwai pfx, channel_name[i]); 1724c2c80383STakashi Iwai name = tmp; 1725352f7f91STakashi Iwai } else { 1726c2c80383STakashi Iwai name = pfx; 1727c2c80383STakashi Iwai idx = i; 1728352f7f91STakashi Iwai } 1729c2c80383STakashi Iwai err = create_extra_out(codec, paths[i], name, idx); 1730352f7f91STakashi Iwai if (err < 0) 1731352f7f91STakashi Iwai return err; 1732352f7f91STakashi Iwai } 1733352f7f91STakashi Iwai return 0; 1734352f7f91STakashi Iwai } 1735352f7f91STakashi Iwai 1736352f7f91STakashi Iwai static int create_hp_out_ctls(struct hda_codec *codec) 1737352f7f91STakashi Iwai { 1738352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1739352f7f91STakashi Iwai return create_extra_outs(codec, spec->autocfg.hp_outs, 1740196c1766STakashi Iwai spec->hp_paths, 1741352f7f91STakashi Iwai "Headphone"); 1742352f7f91STakashi Iwai } 1743352f7f91STakashi Iwai 1744352f7f91STakashi Iwai static int create_speaker_out_ctls(struct hda_codec *codec) 1745352f7f91STakashi Iwai { 1746352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1747352f7f91STakashi Iwai return create_extra_outs(codec, spec->autocfg.speaker_outs, 1748196c1766STakashi Iwai spec->speaker_paths, 1749352f7f91STakashi Iwai "Speaker"); 1750352f7f91STakashi Iwai } 1751352f7f91STakashi Iwai 1752352f7f91STakashi Iwai /* 175338cf6f1aSTakashi Iwai * independent HP controls 175438cf6f1aSTakashi Iwai */ 175538cf6f1aSTakashi Iwai 175638cf6f1aSTakashi Iwai static int indep_hp_info(struct snd_kcontrol *kcontrol, 175738cf6f1aSTakashi Iwai struct snd_ctl_elem_info *uinfo) 175838cf6f1aSTakashi Iwai { 175938cf6f1aSTakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo); 176038cf6f1aSTakashi Iwai } 176138cf6f1aSTakashi Iwai 176238cf6f1aSTakashi Iwai static int indep_hp_get(struct snd_kcontrol *kcontrol, 176338cf6f1aSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 176438cf6f1aSTakashi Iwai { 176538cf6f1aSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 176638cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 176738cf6f1aSTakashi Iwai ucontrol->value.enumerated.item[0] = spec->indep_hp_enabled; 176838cf6f1aSTakashi Iwai return 0; 176938cf6f1aSTakashi Iwai } 177038cf6f1aSTakashi Iwai 177138cf6f1aSTakashi Iwai static int indep_hp_put(struct snd_kcontrol *kcontrol, 177238cf6f1aSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 177338cf6f1aSTakashi Iwai { 177438cf6f1aSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 177538cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 177638cf6f1aSTakashi Iwai unsigned int select = ucontrol->value.enumerated.item[0]; 177738cf6f1aSTakashi Iwai int ret = 0; 177838cf6f1aSTakashi Iwai 177938cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 178038cf6f1aSTakashi Iwai if (spec->active_streams) { 178138cf6f1aSTakashi Iwai ret = -EBUSY; 178238cf6f1aSTakashi Iwai goto unlock; 178338cf6f1aSTakashi Iwai } 178438cf6f1aSTakashi Iwai 178538cf6f1aSTakashi Iwai if (spec->indep_hp_enabled != select) { 178638cf6f1aSTakashi Iwai spec->indep_hp_enabled = select; 178738cf6f1aSTakashi Iwai if (spec->indep_hp_enabled) 178838cf6f1aSTakashi Iwai spec->multiout.hp_out_nid[0] = 0; 178938cf6f1aSTakashi Iwai else 179038cf6f1aSTakashi Iwai spec->multiout.hp_out_nid[0] = spec->alt_dac_nid; 179138cf6f1aSTakashi Iwai ret = 1; 179238cf6f1aSTakashi Iwai } 179338cf6f1aSTakashi Iwai unlock: 179438cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 179538cf6f1aSTakashi Iwai return ret; 179638cf6f1aSTakashi Iwai } 179738cf6f1aSTakashi Iwai 179838cf6f1aSTakashi Iwai static const struct snd_kcontrol_new indep_hp_ctl = { 179938cf6f1aSTakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 180038cf6f1aSTakashi Iwai .name = "Independent HP", 180138cf6f1aSTakashi Iwai .info = indep_hp_info, 180238cf6f1aSTakashi Iwai .get = indep_hp_get, 180338cf6f1aSTakashi Iwai .put = indep_hp_put, 180438cf6f1aSTakashi Iwai }; 180538cf6f1aSTakashi Iwai 180638cf6f1aSTakashi Iwai 180738cf6f1aSTakashi Iwai static int create_indep_hp_ctls(struct hda_codec *codec) 180838cf6f1aSTakashi Iwai { 180938cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 181038cf6f1aSTakashi Iwai 181138cf6f1aSTakashi Iwai if (!spec->indep_hp) 181238cf6f1aSTakashi Iwai return 0; 181338cf6f1aSTakashi Iwai if (!spec->multiout.hp_out_nid[0]) { 181438cf6f1aSTakashi Iwai spec->indep_hp = 0; 181538cf6f1aSTakashi Iwai return 0; 181638cf6f1aSTakashi Iwai } 181738cf6f1aSTakashi Iwai 181838cf6f1aSTakashi Iwai spec->indep_hp_enabled = false; 181938cf6f1aSTakashi Iwai spec->alt_dac_nid = spec->multiout.hp_out_nid[0]; 182038cf6f1aSTakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl)) 182138cf6f1aSTakashi Iwai return -ENOMEM; 182238cf6f1aSTakashi Iwai return 0; 182338cf6f1aSTakashi Iwai } 182438cf6f1aSTakashi Iwai 182538cf6f1aSTakashi Iwai /* 1826352f7f91STakashi Iwai * channel mode enum control 1827352f7f91STakashi Iwai */ 1828352f7f91STakashi Iwai 1829352f7f91STakashi Iwai static int ch_mode_info(struct snd_kcontrol *kcontrol, 1830352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 1831352f7f91STakashi Iwai { 1832352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1833352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1834a07a949bSTakashi Iwai int chs; 1835352f7f91STakashi Iwai 1836352f7f91STakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 1837352f7f91STakashi Iwai uinfo->count = 1; 1838352f7f91STakashi Iwai uinfo->value.enumerated.items = spec->multi_ios + 1; 1839352f7f91STakashi Iwai if (uinfo->value.enumerated.item > spec->multi_ios) 1840352f7f91STakashi Iwai uinfo->value.enumerated.item = spec->multi_ios; 1841a07a949bSTakashi Iwai chs = uinfo->value.enumerated.item * 2 + spec->min_channel_count; 1842a07a949bSTakashi Iwai sprintf(uinfo->value.enumerated.name, "%dch", chs); 1843352f7f91STakashi Iwai return 0; 1844352f7f91STakashi Iwai } 1845352f7f91STakashi Iwai 1846352f7f91STakashi Iwai static int ch_mode_get(struct snd_kcontrol *kcontrol, 1847352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1848352f7f91STakashi Iwai { 1849352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1850352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1851a07a949bSTakashi Iwai ucontrol->value.enumerated.item[0] = 1852a07a949bSTakashi Iwai (spec->ext_channel_count - spec->min_channel_count) / 2; 1853352f7f91STakashi Iwai return 0; 1854352f7f91STakashi Iwai } 1855352f7f91STakashi Iwai 1856196c1766STakashi Iwai static inline struct nid_path * 1857196c1766STakashi Iwai get_multiio_path(struct hda_codec *codec, int idx) 1858196c1766STakashi Iwai { 1859196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1860196c1766STakashi Iwai return snd_hda_get_path_from_idx(codec, 1861196c1766STakashi Iwai spec->out_paths[spec->autocfg.line_outs + idx]); 1862196c1766STakashi Iwai } 1863196c1766STakashi Iwai 1864a5cc2509STakashi Iwai static void update_automute_all(struct hda_codec *codec); 1865a5cc2509STakashi Iwai 1866352f7f91STakashi Iwai static int set_multi_io(struct hda_codec *codec, int idx, bool output) 1867352f7f91STakashi Iwai { 1868352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1869352f7f91STakashi Iwai hda_nid_t nid = spec->multi_io[idx].pin; 1870352f7f91STakashi Iwai struct nid_path *path; 1871352f7f91STakashi Iwai 1872196c1766STakashi Iwai path = get_multiio_path(codec, idx); 1873352f7f91STakashi Iwai if (!path) 1874352f7f91STakashi Iwai return -EINVAL; 1875352f7f91STakashi Iwai 1876352f7f91STakashi Iwai if (path->active == output) 1877352f7f91STakashi Iwai return 0; 1878352f7f91STakashi Iwai 1879352f7f91STakashi Iwai if (output) { 18802c12c30dSTakashi Iwai set_pin_target(codec, nid, PIN_OUT, true); 1881352f7f91STakashi Iwai snd_hda_activate_path(codec, path, true, true); 1882d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, true); 1883352f7f91STakashi Iwai } else { 1884d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, false); 1885352f7f91STakashi Iwai snd_hda_activate_path(codec, path, false, true); 18862c12c30dSTakashi Iwai set_pin_target(codec, nid, spec->multi_io[idx].ctl_in, true); 1887352f7f91STakashi Iwai } 1888a365fed9STakashi Iwai 1889a365fed9STakashi Iwai /* update jack retasking in case it modifies any of them */ 1890a5cc2509STakashi Iwai update_automute_all(codec); 1891a365fed9STakashi Iwai 1892352f7f91STakashi Iwai return 0; 1893352f7f91STakashi Iwai } 1894352f7f91STakashi Iwai 1895352f7f91STakashi Iwai static int ch_mode_put(struct snd_kcontrol *kcontrol, 1896352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1897352f7f91STakashi Iwai { 1898352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1899352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1900352f7f91STakashi Iwai int i, ch; 1901352f7f91STakashi Iwai 1902352f7f91STakashi Iwai ch = ucontrol->value.enumerated.item[0]; 1903352f7f91STakashi Iwai if (ch < 0 || ch > spec->multi_ios) 1904352f7f91STakashi Iwai return -EINVAL; 1905a07a949bSTakashi Iwai if (ch == (spec->ext_channel_count - spec->min_channel_count) / 2) 1906352f7f91STakashi Iwai return 0; 1907a07a949bSTakashi Iwai spec->ext_channel_count = ch * 2 + spec->min_channel_count; 1908352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++) 1909352f7f91STakashi Iwai set_multi_io(codec, i, i < ch); 1910352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count, 1911352f7f91STakashi Iwai spec->const_channel_count); 1912352f7f91STakashi Iwai if (spec->need_dac_fix) 1913352f7f91STakashi Iwai spec->multiout.num_dacs = spec->multiout.max_channels / 2; 1914352f7f91STakashi Iwai return 1; 1915352f7f91STakashi Iwai } 1916352f7f91STakashi Iwai 1917352f7f91STakashi Iwai static const struct snd_kcontrol_new channel_mode_enum = { 1918352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1919352f7f91STakashi Iwai .name = "Channel Mode", 1920352f7f91STakashi Iwai .info = ch_mode_info, 1921352f7f91STakashi Iwai .get = ch_mode_get, 1922352f7f91STakashi Iwai .put = ch_mode_put, 1923352f7f91STakashi Iwai }; 1924352f7f91STakashi Iwai 1925352f7f91STakashi Iwai static int create_multi_channel_mode(struct hda_codec *codec) 1926352f7f91STakashi Iwai { 1927352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1928352f7f91STakashi Iwai 1929352f7f91STakashi Iwai if (spec->multi_ios > 0) { 193012c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &channel_mode_enum)) 1931352f7f91STakashi Iwai return -ENOMEM; 1932352f7f91STakashi Iwai } 1933352f7f91STakashi Iwai return 0; 1934352f7f91STakashi Iwai } 1935352f7f91STakashi Iwai 1936352f7f91STakashi Iwai /* 1937c30aa7b2STakashi Iwai * aamix loopback enable/disable switch 1938c30aa7b2STakashi Iwai */ 1939c30aa7b2STakashi Iwai 1940c30aa7b2STakashi Iwai #define loopback_mixing_info indep_hp_info 1941c30aa7b2STakashi Iwai 1942c30aa7b2STakashi Iwai static int loopback_mixing_get(struct snd_kcontrol *kcontrol, 1943c30aa7b2STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1944c30aa7b2STakashi Iwai { 1945c30aa7b2STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1946c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1947c30aa7b2STakashi Iwai ucontrol->value.enumerated.item[0] = spec->aamix_mode; 1948c30aa7b2STakashi Iwai return 0; 1949c30aa7b2STakashi Iwai } 1950c30aa7b2STakashi Iwai 1951c30aa7b2STakashi Iwai static void update_aamix_paths(struct hda_codec *codec, bool do_mix, 1952c30aa7b2STakashi Iwai int nomix_path_idx, int mix_path_idx) 1953c30aa7b2STakashi Iwai { 1954c30aa7b2STakashi Iwai struct nid_path *nomix_path, *mix_path; 1955c30aa7b2STakashi Iwai 1956c30aa7b2STakashi Iwai nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx); 1957c30aa7b2STakashi Iwai mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx); 1958c30aa7b2STakashi Iwai if (!nomix_path || !mix_path) 1959c30aa7b2STakashi Iwai return; 1960c30aa7b2STakashi Iwai if (do_mix) { 1961c30aa7b2STakashi Iwai snd_hda_activate_path(codec, nomix_path, false, true); 1962c30aa7b2STakashi Iwai snd_hda_activate_path(codec, mix_path, true, true); 1963c30aa7b2STakashi Iwai } else { 1964c30aa7b2STakashi Iwai snd_hda_activate_path(codec, mix_path, false, true); 1965c30aa7b2STakashi Iwai snd_hda_activate_path(codec, nomix_path, true, true); 1966c30aa7b2STakashi Iwai } 1967c30aa7b2STakashi Iwai } 1968c30aa7b2STakashi Iwai 1969c30aa7b2STakashi Iwai static int loopback_mixing_put(struct snd_kcontrol *kcontrol, 1970c30aa7b2STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1971c30aa7b2STakashi Iwai { 1972c30aa7b2STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1973c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1974c30aa7b2STakashi Iwai unsigned int val = ucontrol->value.enumerated.item[0]; 1975c30aa7b2STakashi Iwai 1976c30aa7b2STakashi Iwai if (val == spec->aamix_mode) 1977c30aa7b2STakashi Iwai return 0; 1978c30aa7b2STakashi Iwai spec->aamix_mode = val; 1979c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->out_paths[0], 1980c30aa7b2STakashi Iwai spec->aamix_out_paths[0]); 1981c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->hp_paths[0], 1982c30aa7b2STakashi Iwai spec->aamix_out_paths[1]); 1983c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->speaker_paths[0], 1984c30aa7b2STakashi Iwai spec->aamix_out_paths[2]); 1985c30aa7b2STakashi Iwai return 1; 1986c30aa7b2STakashi Iwai } 1987c30aa7b2STakashi Iwai 1988c30aa7b2STakashi Iwai static const struct snd_kcontrol_new loopback_mixing_enum = { 1989c30aa7b2STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1990c30aa7b2STakashi Iwai .name = "Loopback Mixing", 1991c30aa7b2STakashi Iwai .info = loopback_mixing_info, 1992c30aa7b2STakashi Iwai .get = loopback_mixing_get, 1993c30aa7b2STakashi Iwai .put = loopback_mixing_put, 1994c30aa7b2STakashi Iwai }; 1995c30aa7b2STakashi Iwai 1996c30aa7b2STakashi Iwai static int create_loopback_mixing_ctl(struct hda_codec *codec) 1997c30aa7b2STakashi Iwai { 1998c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1999c30aa7b2STakashi Iwai 2000c30aa7b2STakashi Iwai if (!spec->mixer_nid) 2001c30aa7b2STakashi Iwai return 0; 2002c30aa7b2STakashi Iwai if (!(spec->aamix_out_paths[0] || spec->aamix_out_paths[1] || 2003c30aa7b2STakashi Iwai spec->aamix_out_paths[2])) 2004c30aa7b2STakashi Iwai return 0; 2005c30aa7b2STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum)) 2006c30aa7b2STakashi Iwai return -ENOMEM; 2007c30aa7b2STakashi Iwai return 0; 2008c30aa7b2STakashi Iwai } 2009c30aa7b2STakashi Iwai 2010c30aa7b2STakashi Iwai /* 2011352f7f91STakashi Iwai * shared headphone/mic handling 2012352f7f91STakashi Iwai */ 2013352f7f91STakashi Iwai 2014352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec); 2015352f7f91STakashi Iwai 2016352f7f91STakashi Iwai /* for shared I/O, change the pin-control accordingly */ 2017352f7f91STakashi Iwai static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic) 2018352f7f91STakashi Iwai { 2019352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2020352f7f91STakashi Iwai unsigned int val; 2021352f7f91STakashi Iwai hda_nid_t pin = spec->autocfg.inputs[1].pin; 2022352f7f91STakashi Iwai /* NOTE: this assumes that there are only two inputs, the 2023352f7f91STakashi Iwai * first is the real internal mic and the second is HP/mic jack. 2024352f7f91STakashi Iwai */ 2025352f7f91STakashi Iwai 2026352f7f91STakashi Iwai val = snd_hda_get_default_vref(codec, pin); 2027352f7f91STakashi Iwai 2028352f7f91STakashi Iwai /* This pin does not have vref caps - let's enable vref on pin 0x18 2029352f7f91STakashi Iwai instead, as suggested by Realtek */ 2030352f7f91STakashi Iwai if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) { 2031352f7f91STakashi Iwai const hda_nid_t vref_pin = spec->shared_mic_vref_pin; 2032352f7f91STakashi Iwai unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin); 2033352f7f91STakashi Iwai if (vref_val != AC_PINCTL_VREF_HIZ) 20347594aa33STakashi Iwai snd_hda_set_pin_ctl_cache(codec, vref_pin, 20357594aa33STakashi Iwai PIN_IN | (set_as_mic ? vref_val : 0)); 2036352f7f91STakashi Iwai } 2037352f7f91STakashi Iwai 2038352f7f91STakashi Iwai val = set_as_mic ? val | PIN_IN : PIN_HP; 20392c12c30dSTakashi Iwai set_pin_target(codec, pin, val, true); 2040352f7f91STakashi Iwai 2041352f7f91STakashi Iwai spec->automute_speaker = !set_as_mic; 2042352f7f91STakashi Iwai call_update_outputs(codec); 2043352f7f91STakashi Iwai } 2044352f7f91STakashi Iwai 2045352f7f91STakashi Iwai /* create a shared input with the headphone out */ 2046352f7f91STakashi Iwai static int create_shared_input(struct hda_codec *codec) 2047352f7f91STakashi Iwai { 2048352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2049352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 2050352f7f91STakashi Iwai unsigned int defcfg; 2051352f7f91STakashi Iwai hda_nid_t nid; 2052352f7f91STakashi Iwai 2053352f7f91STakashi Iwai /* only one internal input pin? */ 2054352f7f91STakashi Iwai if (cfg->num_inputs != 1) 2055352f7f91STakashi Iwai return 0; 2056352f7f91STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); 2057352f7f91STakashi Iwai if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) 2058352f7f91STakashi Iwai return 0; 2059352f7f91STakashi Iwai 2060352f7f91STakashi Iwai if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) 2061352f7f91STakashi Iwai nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */ 2062352f7f91STakashi Iwai else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT) 2063352f7f91STakashi Iwai nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */ 2064352f7f91STakashi Iwai else 2065352f7f91STakashi Iwai return 0; /* both not available */ 2066352f7f91STakashi Iwai 2067352f7f91STakashi Iwai if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN)) 2068352f7f91STakashi Iwai return 0; /* no input */ 2069352f7f91STakashi Iwai 2070352f7f91STakashi Iwai cfg->inputs[1].pin = nid; 2071352f7f91STakashi Iwai cfg->inputs[1].type = AUTO_PIN_MIC; 2072352f7f91STakashi Iwai cfg->num_inputs = 2; 2073352f7f91STakashi Iwai spec->shared_mic_hp = 1; 2074352f7f91STakashi Iwai snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid); 2075352f7f91STakashi Iwai return 0; 2076352f7f91STakashi Iwai } 2077352f7f91STakashi Iwai 2078978e77e7STakashi Iwai /* 2079978e77e7STakashi Iwai * output jack mode 2080978e77e7STakashi Iwai */ 2081978e77e7STakashi Iwai static int out_jack_mode_info(struct snd_kcontrol *kcontrol, 2082978e77e7STakashi Iwai struct snd_ctl_elem_info *uinfo) 2083978e77e7STakashi Iwai { 2084978e77e7STakashi Iwai static const char * const texts[] = { 2085978e77e7STakashi Iwai "Line Out", "Headphone Out", 2086978e77e7STakashi Iwai }; 2087978e77e7STakashi Iwai return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts); 2088978e77e7STakashi Iwai } 2089978e77e7STakashi Iwai 2090978e77e7STakashi Iwai static int out_jack_mode_get(struct snd_kcontrol *kcontrol, 2091978e77e7STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2092978e77e7STakashi Iwai { 2093978e77e7STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2094978e77e7STakashi Iwai hda_nid_t nid = kcontrol->private_value; 2095978e77e7STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) == PIN_HP) 2096978e77e7STakashi Iwai ucontrol->value.enumerated.item[0] = 1; 2097978e77e7STakashi Iwai else 2098978e77e7STakashi Iwai ucontrol->value.enumerated.item[0] = 0; 2099978e77e7STakashi Iwai return 0; 2100978e77e7STakashi Iwai } 2101978e77e7STakashi Iwai 2102978e77e7STakashi Iwai static int out_jack_mode_put(struct snd_kcontrol *kcontrol, 2103978e77e7STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2104978e77e7STakashi Iwai { 2105978e77e7STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2106978e77e7STakashi Iwai hda_nid_t nid = kcontrol->private_value; 2107978e77e7STakashi Iwai unsigned int val; 2108978e77e7STakashi Iwai 2109978e77e7STakashi Iwai val = ucontrol->value.enumerated.item[0] ? PIN_HP : PIN_OUT; 2110978e77e7STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) == val) 2111978e77e7STakashi Iwai return 0; 2112978e77e7STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, val); 2113978e77e7STakashi Iwai return 1; 2114978e77e7STakashi Iwai } 2115978e77e7STakashi Iwai 2116978e77e7STakashi Iwai static const struct snd_kcontrol_new out_jack_mode_enum = { 2117978e77e7STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2118978e77e7STakashi Iwai .info = out_jack_mode_info, 2119978e77e7STakashi Iwai .get = out_jack_mode_get, 2120978e77e7STakashi Iwai .put = out_jack_mode_put, 2121978e77e7STakashi Iwai }; 2122978e77e7STakashi Iwai 2123978e77e7STakashi Iwai static bool find_kctl_name(struct hda_codec *codec, const char *name, int idx) 2124978e77e7STakashi Iwai { 2125978e77e7STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2126978e77e7STakashi Iwai int i; 2127978e77e7STakashi Iwai 2128978e77e7STakashi Iwai for (i = 0; i < spec->kctls.used; i++) { 2129978e77e7STakashi Iwai struct snd_kcontrol_new *kctl = snd_array_elem(&spec->kctls, i); 2130978e77e7STakashi Iwai if (!strcmp(kctl->name, name) && kctl->index == idx) 2131978e77e7STakashi Iwai return true; 2132978e77e7STakashi Iwai } 2133978e77e7STakashi Iwai return false; 2134978e77e7STakashi Iwai } 2135978e77e7STakashi Iwai 2136978e77e7STakashi Iwai static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin, 2137978e77e7STakashi Iwai char *name, size_t name_len) 2138978e77e7STakashi Iwai { 2139978e77e7STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2140978e77e7STakashi Iwai int idx = 0; 2141978e77e7STakashi Iwai 2142978e77e7STakashi Iwai snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len, &idx); 2143978e77e7STakashi Iwai strlcat(name, " Jack Mode", name_len); 2144978e77e7STakashi Iwai 2145978e77e7STakashi Iwai for (; find_kctl_name(codec, name, idx); idx++) 2146978e77e7STakashi Iwai ; 2147978e77e7STakashi Iwai } 2148978e77e7STakashi Iwai 2149978e77e7STakashi Iwai static int create_out_jack_modes(struct hda_codec *codec, int num_pins, 2150978e77e7STakashi Iwai hda_nid_t *pins) 2151978e77e7STakashi Iwai { 2152978e77e7STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2153978e77e7STakashi Iwai int i; 2154978e77e7STakashi Iwai 2155978e77e7STakashi Iwai for (i = 0; i < num_pins; i++) { 2156978e77e7STakashi Iwai hda_nid_t pin = pins[i]; 2157978e77e7STakashi Iwai unsigned int pincap = snd_hda_query_pin_caps(codec, pin); 2158978e77e7STakashi Iwai if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV)) { 2159978e77e7STakashi Iwai struct snd_kcontrol_new *knew; 2160978e77e7STakashi Iwai char name[44]; 2161978e77e7STakashi Iwai get_jack_mode_name(codec, pin, name, sizeof(name)); 2162978e77e7STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, 2163978e77e7STakashi Iwai &out_jack_mode_enum); 2164978e77e7STakashi Iwai if (!knew) 2165978e77e7STakashi Iwai return -ENOMEM; 2166978e77e7STakashi Iwai knew->private_value = pin; 2167978e77e7STakashi Iwai } 2168978e77e7STakashi Iwai } 2169978e77e7STakashi Iwai 2170978e77e7STakashi Iwai return 0; 2171978e77e7STakashi Iwai } 2172978e77e7STakashi Iwai 217329476558STakashi Iwai /* 217429476558STakashi Iwai * input jack mode 217529476558STakashi Iwai */ 217629476558STakashi Iwai 217729476558STakashi Iwai /* from AC_PINCTL_VREF_HIZ to AC_PINCTL_VREF_100 */ 217829476558STakashi Iwai #define NUM_VREFS 6 217929476558STakashi Iwai 218029476558STakashi Iwai static const char * const vref_texts[NUM_VREFS] = { 218129476558STakashi Iwai "Line In", "Mic 50pc Bias", "Mic 0V Bias", 218229476558STakashi Iwai "", "Mic 80pc Bias", "Mic 100pc Bias" 218329476558STakashi Iwai }; 218429476558STakashi Iwai 218529476558STakashi Iwai static unsigned int get_vref_caps(struct hda_codec *codec, hda_nid_t pin) 218629476558STakashi Iwai { 218729476558STakashi Iwai unsigned int pincap; 218829476558STakashi Iwai 218929476558STakashi Iwai pincap = snd_hda_query_pin_caps(codec, pin); 219029476558STakashi Iwai pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; 219129476558STakashi Iwai /* filter out unusual vrefs */ 219229476558STakashi Iwai pincap &= ~(AC_PINCAP_VREF_GRD | AC_PINCAP_VREF_100); 219329476558STakashi Iwai return pincap; 219429476558STakashi Iwai } 219529476558STakashi Iwai 219629476558STakashi Iwai /* convert from the enum item index to the vref ctl index (0=HIZ, 1=50%...) */ 219729476558STakashi Iwai static int get_vref_idx(unsigned int vref_caps, unsigned int item_idx) 219829476558STakashi Iwai { 219929476558STakashi Iwai unsigned int i, n = 0; 220029476558STakashi Iwai 220129476558STakashi Iwai for (i = 0; i < NUM_VREFS; i++) { 220229476558STakashi Iwai if (vref_caps & (1 << i)) { 220329476558STakashi Iwai if (n == item_idx) 220429476558STakashi Iwai return i; 220529476558STakashi Iwai n++; 220629476558STakashi Iwai } 220729476558STakashi Iwai } 220829476558STakashi Iwai return 0; 220929476558STakashi Iwai } 221029476558STakashi Iwai 221129476558STakashi Iwai /* convert back from the vref ctl index to the enum item index */ 221229476558STakashi Iwai static int cvt_from_vref_idx(unsigned int vref_caps, unsigned int idx) 221329476558STakashi Iwai { 221429476558STakashi Iwai unsigned int i, n = 0; 221529476558STakashi Iwai 221629476558STakashi Iwai for (i = 0; i < NUM_VREFS; i++) { 221729476558STakashi Iwai if (i == idx) 221829476558STakashi Iwai return n; 221929476558STakashi Iwai if (vref_caps & (1 << i)) 222029476558STakashi Iwai n++; 222129476558STakashi Iwai } 222229476558STakashi Iwai return 0; 222329476558STakashi Iwai } 222429476558STakashi Iwai 222529476558STakashi Iwai static int in_jack_mode_info(struct snd_kcontrol *kcontrol, 222629476558STakashi Iwai struct snd_ctl_elem_info *uinfo) 222729476558STakashi Iwai { 222829476558STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 222929476558STakashi Iwai hda_nid_t nid = kcontrol->private_value; 223029476558STakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid); 223129476558STakashi Iwai 223229476558STakashi Iwai snd_hda_enum_helper_info(kcontrol, uinfo, hweight32(vref_caps), 223329476558STakashi Iwai vref_texts); 223429476558STakashi Iwai /* set the right text */ 223529476558STakashi Iwai strcpy(uinfo->value.enumerated.name, 223629476558STakashi Iwai vref_texts[get_vref_idx(vref_caps, uinfo->value.enumerated.item)]); 223729476558STakashi Iwai return 0; 223829476558STakashi Iwai } 223929476558STakashi Iwai 224029476558STakashi Iwai static int in_jack_mode_get(struct snd_kcontrol *kcontrol, 224129476558STakashi Iwai struct snd_ctl_elem_value *ucontrol) 224229476558STakashi Iwai { 224329476558STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 224429476558STakashi Iwai hda_nid_t nid = kcontrol->private_value; 224529476558STakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid); 224629476558STakashi Iwai unsigned int idx; 224729476558STakashi Iwai 224829476558STakashi Iwai idx = snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_VREFEN; 224929476558STakashi Iwai ucontrol->value.enumerated.item[0] = cvt_from_vref_idx(vref_caps, idx); 225029476558STakashi Iwai return 0; 225129476558STakashi Iwai } 225229476558STakashi Iwai 225329476558STakashi Iwai static int in_jack_mode_put(struct snd_kcontrol *kcontrol, 225429476558STakashi Iwai struct snd_ctl_elem_value *ucontrol) 225529476558STakashi Iwai { 225629476558STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 225729476558STakashi Iwai hda_nid_t nid = kcontrol->private_value; 225829476558STakashi Iwai unsigned int vref_caps = get_vref_caps(codec, nid); 225929476558STakashi Iwai unsigned int val, idx; 226029476558STakashi Iwai 226129476558STakashi Iwai val = snd_hda_codec_get_pin_target(codec, nid); 226229476558STakashi Iwai idx = cvt_from_vref_idx(vref_caps, val & AC_PINCTL_VREFEN); 226329476558STakashi Iwai if (idx == ucontrol->value.enumerated.item[0]) 226429476558STakashi Iwai return 0; 226529476558STakashi Iwai 226629476558STakashi Iwai val &= ~AC_PINCTL_VREFEN; 226729476558STakashi Iwai val |= get_vref_idx(vref_caps, ucontrol->value.enumerated.item[0]); 226829476558STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, val); 226929476558STakashi Iwai return 1; 227029476558STakashi Iwai } 227129476558STakashi Iwai 227229476558STakashi Iwai static const struct snd_kcontrol_new in_jack_mode_enum = { 227329476558STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 227429476558STakashi Iwai .info = in_jack_mode_info, 227529476558STakashi Iwai .get = in_jack_mode_get, 227629476558STakashi Iwai .put = in_jack_mode_put, 227729476558STakashi Iwai }; 227829476558STakashi Iwai 227929476558STakashi Iwai static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin) 228029476558STakashi Iwai { 228129476558STakashi Iwai struct hda_gen_spec *spec = codec->spec; 228229476558STakashi Iwai unsigned int defcfg; 228329476558STakashi Iwai struct snd_kcontrol_new *knew; 228429476558STakashi Iwai char name[44]; 228529476558STakashi Iwai 228629476558STakashi Iwai /* no jack mode for fixed pins */ 228729476558STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, pin); 228829476558STakashi Iwai if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT) 228929476558STakashi Iwai return 0; 229029476558STakashi Iwai 229129476558STakashi Iwai /* no multiple vref caps? */ 229229476558STakashi Iwai if (hweight32(get_vref_caps(codec, pin)) <= 1) 229329476558STakashi Iwai return 0; 229429476558STakashi Iwai 229529476558STakashi Iwai get_jack_mode_name(codec, pin, name, sizeof(name)); 229629476558STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &in_jack_mode_enum); 229729476558STakashi Iwai if (!knew) 229829476558STakashi Iwai return -ENOMEM; 229929476558STakashi Iwai knew->private_value = pin; 230029476558STakashi Iwai return 0; 230129476558STakashi Iwai } 230229476558STakashi Iwai 2303352f7f91STakashi Iwai 2304352f7f91STakashi Iwai /* 2305352f7f91STakashi Iwai * Parse input paths 2306352f7f91STakashi Iwai */ 2307352f7f91STakashi Iwai 2308352f7f91STakashi Iwai #ifdef CONFIG_PM 2309352f7f91STakashi Iwai /* add the powersave loopback-list entry */ 2310352f7f91STakashi Iwai static void add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx) 2311352f7f91STakashi Iwai { 2312352f7f91STakashi Iwai struct hda_amp_list *list; 2313352f7f91STakashi Iwai 2314352f7f91STakashi Iwai if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1) 2315352f7f91STakashi Iwai return; 2316352f7f91STakashi Iwai list = spec->loopback_list + spec->num_loopbacks; 2317352f7f91STakashi Iwai list->nid = mix; 2318352f7f91STakashi Iwai list->dir = HDA_INPUT; 2319352f7f91STakashi Iwai list->idx = idx; 2320352f7f91STakashi Iwai spec->num_loopbacks++; 2321cb53c626STakashi Iwai spec->loopback.amplist = spec->loopback_list; 2322cb53c626STakashi Iwai } 2323cb53c626STakashi Iwai #else 2324352f7f91STakashi Iwai #define add_loopback_list(spec, mix, idx) /* NOP */ 2325cb53c626STakashi Iwai #endif 2326cb53c626STakashi Iwai 2327352f7f91STakashi Iwai /* create input playback/capture controls for the given pin */ 2328196c1766STakashi Iwai static int new_analog_input(struct hda_codec *codec, int input_idx, 2329196c1766STakashi Iwai hda_nid_t pin, const char *ctlname, int ctlidx, 2330352f7f91STakashi Iwai hda_nid_t mix_nid) 23311da177e4SLinus Torvalds { 2332352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2333352f7f91STakashi Iwai struct nid_path *path; 2334352f7f91STakashi Iwai unsigned int val; 2335352f7f91STakashi Iwai int err, idx; 23361da177e4SLinus Torvalds 2337352f7f91STakashi Iwai if (!nid_has_volume(codec, mix_nid, HDA_INPUT) && 2338352f7f91STakashi Iwai !nid_has_mute(codec, mix_nid, HDA_INPUT)) 2339352f7f91STakashi Iwai return 0; /* no need for analog loopback */ 2340352f7f91STakashi Iwai 23413ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, pin, mix_nid, 0); 2342352f7f91STakashi Iwai if (!path) 2343352f7f91STakashi Iwai return -EINVAL; 23440c8c0f56STakashi Iwai print_nid_path("loopback", path); 2345196c1766STakashi Iwai spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path); 2346352f7f91STakashi Iwai 2347352f7f91STakashi Iwai idx = path->idx[path->depth - 1]; 2348352f7f91STakashi Iwai if (nid_has_volume(codec, mix_nid, HDA_INPUT)) { 2349352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); 2350352f7f91STakashi Iwai err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, val); 2351d13bd412STakashi Iwai if (err < 0) 23521da177e4SLinus Torvalds return err; 2353352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = val; 23541da177e4SLinus Torvalds } 23551da177e4SLinus Torvalds 2356352f7f91STakashi Iwai if (nid_has_mute(codec, mix_nid, HDA_INPUT)) { 2357352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); 2358352f7f91STakashi Iwai err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, val); 2359d13bd412STakashi Iwai if (err < 0) 23601da177e4SLinus Torvalds return err; 2361352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = val; 23621da177e4SLinus Torvalds } 23631da177e4SLinus Torvalds 2364352f7f91STakashi Iwai path->active = true; 2365352f7f91STakashi Iwai add_loopback_list(spec, mix_nid, idx); 2366352f7f91STakashi Iwai return 0; 23671da177e4SLinus Torvalds } 23681da177e4SLinus Torvalds 2369352f7f91STakashi Iwai static int is_input_pin(struct hda_codec *codec, hda_nid_t nid) 23701da177e4SLinus Torvalds { 2371352f7f91STakashi Iwai unsigned int pincap = snd_hda_query_pin_caps(codec, nid); 2372352f7f91STakashi Iwai return (pincap & AC_PINCAP_IN) != 0; 2373352f7f91STakashi Iwai } 2374352f7f91STakashi Iwai 2375352f7f91STakashi Iwai /* Parse the codec tree and retrieve ADCs */ 2376352f7f91STakashi Iwai static int fill_adc_nids(struct hda_codec *codec) 2377352f7f91STakashi Iwai { 2378352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2379352f7f91STakashi Iwai hda_nid_t nid; 2380352f7f91STakashi Iwai hda_nid_t *adc_nids = spec->adc_nids; 2381352f7f91STakashi Iwai int max_nums = ARRAY_SIZE(spec->adc_nids); 2382352f7f91STakashi Iwai int i, nums = 0; 2383352f7f91STakashi Iwai 2384352f7f91STakashi Iwai nid = codec->start_nid; 2385352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) { 2386352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 2387352f7f91STakashi Iwai int type = get_wcaps_type(caps); 2388352f7f91STakashi Iwai 2389352f7f91STakashi Iwai if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL)) 2390352f7f91STakashi Iwai continue; 2391352f7f91STakashi Iwai adc_nids[nums] = nid; 2392352f7f91STakashi Iwai if (++nums >= max_nums) 2393352f7f91STakashi Iwai break; 2394352f7f91STakashi Iwai } 2395352f7f91STakashi Iwai spec->num_adc_nids = nums; 23960ffd534eSTakashi Iwai 23970ffd534eSTakashi Iwai /* copy the detected ADCs to all_adcs[] */ 23980ffd534eSTakashi Iwai spec->num_all_adcs = nums; 23990ffd534eSTakashi Iwai memcpy(spec->all_adcs, spec->adc_nids, nums * sizeof(hda_nid_t)); 24000ffd534eSTakashi Iwai 2401352f7f91STakashi Iwai return nums; 2402352f7f91STakashi Iwai } 2403352f7f91STakashi Iwai 2404352f7f91STakashi Iwai /* filter out invalid adc_nids that don't give all active input pins; 2405352f7f91STakashi Iwai * if needed, check whether dynamic ADC-switching is available 2406352f7f91STakashi Iwai */ 2407352f7f91STakashi Iwai static int check_dyn_adc_switch(struct hda_codec *codec) 2408352f7f91STakashi Iwai { 2409352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2410352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 24113a65bcdcSTakashi Iwai unsigned int ok_bits; 2412352f7f91STakashi Iwai int i, n, nums; 2413352f7f91STakashi Iwai 2414352f7f91STakashi Iwai again: 2415352f7f91STakashi Iwai nums = 0; 24163a65bcdcSTakashi Iwai ok_bits = 0; 2417352f7f91STakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 2418352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 24193a65bcdcSTakashi Iwai if (!spec->input_paths[i][n]) 2420352f7f91STakashi Iwai break; 2421352f7f91STakashi Iwai } 24223a65bcdcSTakashi Iwai if (i >= imux->num_items) { 24233a65bcdcSTakashi Iwai ok_bits |= (1 << n); 24243a65bcdcSTakashi Iwai nums++; 24253a65bcdcSTakashi Iwai } 2426352f7f91STakashi Iwai } 2427352f7f91STakashi Iwai 24283a65bcdcSTakashi Iwai if (!ok_bits) { 2429352f7f91STakashi Iwai if (spec->shared_mic_hp) { 2430352f7f91STakashi Iwai spec->shared_mic_hp = 0; 2431352f7f91STakashi Iwai imux->num_items = 1; 2432352f7f91STakashi Iwai goto again; 2433352f7f91STakashi Iwai } 2434352f7f91STakashi Iwai 2435352f7f91STakashi Iwai /* check whether ADC-switch is possible */ 2436352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2437352f7f91STakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 24383a65bcdcSTakashi Iwai if (spec->input_paths[i][n]) { 2439352f7f91STakashi Iwai spec->dyn_adc_idx[i] = n; 2440352f7f91STakashi Iwai break; 2441352f7f91STakashi Iwai } 2442352f7f91STakashi Iwai } 2443352f7f91STakashi Iwai } 2444352f7f91STakashi Iwai 2445352f7f91STakashi Iwai snd_printdd("hda-codec: enabling ADC switching\n"); 2446352f7f91STakashi Iwai spec->dyn_adc_switch = 1; 2447352f7f91STakashi Iwai } else if (nums != spec->num_adc_nids) { 24483a65bcdcSTakashi Iwai /* shrink the invalid adcs and input paths */ 24493a65bcdcSTakashi Iwai nums = 0; 24503a65bcdcSTakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 24513a65bcdcSTakashi Iwai if (!(ok_bits & (1 << n))) 24523a65bcdcSTakashi Iwai continue; 24533a65bcdcSTakashi Iwai if (n != nums) { 24543a65bcdcSTakashi Iwai spec->adc_nids[nums] = spec->adc_nids[n]; 2455980428ceSTakashi Iwai for (i = 0; i < imux->num_items; i++) { 2456980428ceSTakashi Iwai invalidate_nid_path(codec, 2457980428ceSTakashi Iwai spec->input_paths[i][nums]); 24583a65bcdcSTakashi Iwai spec->input_paths[i][nums] = 24593a65bcdcSTakashi Iwai spec->input_paths[i][n]; 24603a65bcdcSTakashi Iwai } 2461980428ceSTakashi Iwai } 24623a65bcdcSTakashi Iwai nums++; 24633a65bcdcSTakashi Iwai } 2464352f7f91STakashi Iwai spec->num_adc_nids = nums; 2465352f7f91STakashi Iwai } 2466352f7f91STakashi Iwai 2467352f7f91STakashi Iwai if (imux->num_items == 1 || spec->shared_mic_hp) { 2468352f7f91STakashi Iwai snd_printdd("hda-codec: reducing to a single ADC\n"); 2469352f7f91STakashi Iwai spec->num_adc_nids = 1; /* reduce to a single ADC */ 2470352f7f91STakashi Iwai } 2471352f7f91STakashi Iwai 2472352f7f91STakashi Iwai /* single index for individual volumes ctls */ 2473352f7f91STakashi Iwai if (!spec->dyn_adc_switch && spec->multi_cap_vol) 2474352f7f91STakashi Iwai spec->num_adc_nids = 1; 2475352f7f91STakashi Iwai 24761da177e4SLinus Torvalds return 0; 24771da177e4SLinus Torvalds } 24781da177e4SLinus Torvalds 2479f3fc0b0bSTakashi Iwai /* parse capture source paths from the given pin and create imux items */ 2480f3fc0b0bSTakashi Iwai static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin, 24819dba205bSTakashi Iwai int cfg_idx, int num_adcs, 24829dba205bSTakashi Iwai const char *label, int anchor) 2483f3fc0b0bSTakashi Iwai { 2484f3fc0b0bSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 2485f3fc0b0bSTakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 2486f3fc0b0bSTakashi Iwai int imux_idx = imux->num_items; 2487f3fc0b0bSTakashi Iwai bool imux_added = false; 2488f3fc0b0bSTakashi Iwai int c; 2489f3fc0b0bSTakashi Iwai 2490f3fc0b0bSTakashi Iwai for (c = 0; c < num_adcs; c++) { 2491f3fc0b0bSTakashi Iwai struct nid_path *path; 2492f3fc0b0bSTakashi Iwai hda_nid_t adc = spec->adc_nids[c]; 2493f3fc0b0bSTakashi Iwai 2494f3fc0b0bSTakashi Iwai if (!is_reachable_path(codec, pin, adc)) 2495f3fc0b0bSTakashi Iwai continue; 2496f3fc0b0bSTakashi Iwai path = snd_hda_add_new_path(codec, pin, adc, anchor); 2497f3fc0b0bSTakashi Iwai if (!path) 2498f3fc0b0bSTakashi Iwai continue; 2499f3fc0b0bSTakashi Iwai print_nid_path("input", path); 2500f3fc0b0bSTakashi Iwai spec->input_paths[imux_idx][c] = 2501f3fc0b0bSTakashi Iwai snd_hda_get_path_idx(codec, path); 2502f3fc0b0bSTakashi Iwai 2503f3fc0b0bSTakashi Iwai if (!imux_added) { 2504f3fc0b0bSTakashi Iwai spec->imux_pins[imux->num_items] = pin; 25059dba205bSTakashi Iwai snd_hda_add_imux_item(imux, label, cfg_idx, NULL); 2506f3fc0b0bSTakashi Iwai imux_added = true; 2507f3fc0b0bSTakashi Iwai } 2508f3fc0b0bSTakashi Iwai } 2509f3fc0b0bSTakashi Iwai 2510f3fc0b0bSTakashi Iwai return 0; 2511f3fc0b0bSTakashi Iwai } 2512f3fc0b0bSTakashi Iwai 25131da177e4SLinus Torvalds /* 2514352f7f91STakashi Iwai * create playback/capture controls for input pins 25151da177e4SLinus Torvalds */ 25169dba205bSTakashi Iwai 25179dba205bSTakashi Iwai #define CFG_IDX_MIX 99 /* a dummy cfg->input idx for stereo mix */ 25189dba205bSTakashi Iwai 2519352f7f91STakashi Iwai static int create_input_ctls(struct hda_codec *codec) 2520a7da6ce5STakashi Iwai { 2521352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2522352f7f91STakashi Iwai const struct auto_pin_cfg *cfg = &spec->autocfg; 2523352f7f91STakashi Iwai hda_nid_t mixer = spec->mixer_nid; 2524352f7f91STakashi Iwai int num_adcs; 2525f3fc0b0bSTakashi Iwai int i, err, type_idx = 0; 2526352f7f91STakashi Iwai const char *prev_label = NULL; 25272c12c30dSTakashi Iwai unsigned int val; 2528a7da6ce5STakashi Iwai 2529352f7f91STakashi Iwai num_adcs = fill_adc_nids(codec); 2530352f7f91STakashi Iwai if (num_adcs < 0) 2531352f7f91STakashi Iwai return 0; 2532352f7f91STakashi Iwai 2533352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 2534352f7f91STakashi Iwai hda_nid_t pin; 2535352f7f91STakashi Iwai const char *label; 2536352f7f91STakashi Iwai 2537352f7f91STakashi Iwai pin = cfg->inputs[i].pin; 2538352f7f91STakashi Iwai if (!is_input_pin(codec, pin)) 2539352f7f91STakashi Iwai continue; 2540352f7f91STakashi Iwai 2541352f7f91STakashi Iwai label = hda_get_autocfg_input_label(codec, cfg, i); 2542352f7f91STakashi Iwai if (prev_label && !strcmp(label, prev_label)) 2543352f7f91STakashi Iwai type_idx++; 2544352f7f91STakashi Iwai else 2545352f7f91STakashi Iwai type_idx = 0; 2546352f7f91STakashi Iwai prev_label = label; 2547352f7f91STakashi Iwai 25482c12c30dSTakashi Iwai val = PIN_IN; 25492c12c30dSTakashi Iwai if (cfg->inputs[i].type == AUTO_PIN_MIC) 25502c12c30dSTakashi Iwai val |= snd_hda_get_default_vref(codec, pin); 25512c12c30dSTakashi Iwai set_pin_target(codec, pin, val, false); 25522c12c30dSTakashi Iwai 2553352f7f91STakashi Iwai if (mixer) { 2554352f7f91STakashi Iwai if (is_reachable_path(codec, pin, mixer)) { 2555196c1766STakashi Iwai err = new_analog_input(codec, i, pin, 2556352f7f91STakashi Iwai label, type_idx, mixer); 2557a7da6ce5STakashi Iwai if (err < 0) 2558a7da6ce5STakashi Iwai return err; 2559a7da6ce5STakashi Iwai } 2560352f7f91STakashi Iwai } 2561352f7f91STakashi Iwai 25629dba205bSTakashi Iwai err = parse_capture_source(codec, pin, i, 25639dba205bSTakashi Iwai num_adcs, label, -mixer); 2564f3fc0b0bSTakashi Iwai if (err < 0) 2565f3fc0b0bSTakashi Iwai return err; 256629476558STakashi Iwai 256729476558STakashi Iwai if (spec->add_in_jack_modes) { 256829476558STakashi Iwai err = create_in_jack_mode(codec, pin); 256929476558STakashi Iwai if (err < 0) 257029476558STakashi Iwai return err; 257129476558STakashi Iwai } 2572352f7f91STakashi Iwai } 2573f3fc0b0bSTakashi Iwai 2574f3fc0b0bSTakashi Iwai if (mixer && spec->add_stereo_mix_input) { 25759dba205bSTakashi Iwai err = parse_capture_source(codec, mixer, CFG_IDX_MIX, num_adcs, 2576f3fc0b0bSTakashi Iwai "Stereo Mix", 0); 2577f3fc0b0bSTakashi Iwai if (err < 0) 2578f3fc0b0bSTakashi Iwai return err; 2579352f7f91STakashi Iwai } 2580352f7f91STakashi Iwai 2581a7da6ce5STakashi Iwai return 0; 2582a7da6ce5STakashi Iwai } 2583a7da6ce5STakashi Iwai 25841da177e4SLinus Torvalds 2585352f7f91STakashi Iwai /* 2586352f7f91STakashi Iwai * input source mux 2587352f7f91STakashi Iwai */ 2588352f7f91STakashi Iwai 2589c697b716STakashi Iwai /* get the input path specified by the given adc and imux indices */ 2590c697b716STakashi Iwai static struct nid_path *get_input_path(struct hda_codec *codec, int adc_idx, int imux_idx) 2591352f7f91STakashi Iwai { 2592352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2593b56fa1edSDavid Henningsson if (imux_idx < 0 || imux_idx >= HDA_MAX_NUM_INPUTS) { 2594b56fa1edSDavid Henningsson snd_BUG(); 2595b56fa1edSDavid Henningsson return NULL; 2596b56fa1edSDavid Henningsson } 2597352f7f91STakashi Iwai if (spec->dyn_adc_switch) 2598352f7f91STakashi Iwai adc_idx = spec->dyn_adc_idx[imux_idx]; 2599b56fa1edSDavid Henningsson if (adc_idx < 0 || adc_idx >= AUTO_CFG_MAX_OUTS) { 2600b56fa1edSDavid Henningsson snd_BUG(); 2601b56fa1edSDavid Henningsson return NULL; 2602b56fa1edSDavid Henningsson } 2603c697b716STakashi Iwai return snd_hda_get_path_from_idx(codec, spec->input_paths[imux_idx][adc_idx]); 260497ec558aSTakashi Iwai } 2605352f7f91STakashi Iwai 2606352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx, 2607352f7f91STakashi Iwai unsigned int idx); 2608352f7f91STakashi Iwai 2609352f7f91STakashi Iwai static int mux_enum_info(struct snd_kcontrol *kcontrol, 2610352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 2611352f7f91STakashi Iwai { 2612352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2613352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2614352f7f91STakashi Iwai return snd_hda_input_mux_info(&spec->input_mux, uinfo); 2615352f7f91STakashi Iwai } 2616352f7f91STakashi Iwai 2617352f7f91STakashi Iwai static int mux_enum_get(struct snd_kcontrol *kcontrol, 2618352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2619352f7f91STakashi Iwai { 2620352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2621352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2622a053d1e3SDavid Henningsson unsigned int adc_idx = kcontrol->id.index; 2623352f7f91STakashi Iwai 2624352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; 26251da177e4SLinus Torvalds return 0; 26261da177e4SLinus Torvalds } 26271da177e4SLinus Torvalds 2628352f7f91STakashi Iwai static int mux_enum_put(struct snd_kcontrol *kcontrol, 2629352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 26301da177e4SLinus Torvalds { 2631352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2632a053d1e3SDavid Henningsson unsigned int adc_idx = kcontrol->id.index; 2633352f7f91STakashi Iwai return mux_select(codec, adc_idx, 2634352f7f91STakashi Iwai ucontrol->value.enumerated.item[0]); 2635352f7f91STakashi Iwai } 2636352f7f91STakashi Iwai 2637352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_src_temp = { 26381da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2639352f7f91STakashi Iwai .name = "Input Source", 2640352f7f91STakashi Iwai .info = mux_enum_info, 2641352f7f91STakashi Iwai .get = mux_enum_get, 2642352f7f91STakashi Iwai .put = mux_enum_put, 26431da177e4SLinus Torvalds }; 2644071c73adSTakashi Iwai 264547d46abbSTakashi Iwai /* 264647d46abbSTakashi Iwai * capture volume and capture switch ctls 264747d46abbSTakashi Iwai */ 264847d46abbSTakashi Iwai 2649352f7f91STakashi Iwai typedef int (*put_call_t)(struct snd_kcontrol *kcontrol, 2650352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol); 2651071c73adSTakashi Iwai 265247d46abbSTakashi Iwai /* call the given amp update function for all amps in the imux list at once */ 2653352f7f91STakashi Iwai static int cap_put_caller(struct snd_kcontrol *kcontrol, 2654352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol, 2655352f7f91STakashi Iwai put_call_t func, int type) 2656352f7f91STakashi Iwai { 2657352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2658352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2659352f7f91STakashi Iwai const struct hda_input_mux *imux; 2660352f7f91STakashi Iwai struct nid_path *path; 2661352f7f91STakashi Iwai int i, adc_idx, err = 0; 2662071c73adSTakashi Iwai 2663352f7f91STakashi Iwai imux = &spec->input_mux; 2664a053d1e3SDavid Henningsson adc_idx = kcontrol->id.index; 2665352f7f91STakashi Iwai mutex_lock(&codec->control_mutex); 266647d46abbSTakashi Iwai /* we use the cache-only update at first since multiple input paths 266747d46abbSTakashi Iwai * may shared the same amp; by updating only caches, the redundant 266847d46abbSTakashi Iwai * writes to hardware can be reduced. 266947d46abbSTakashi Iwai */ 2670352f7f91STakashi Iwai codec->cached_write = 1; 2671352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2672c697b716STakashi Iwai path = get_input_path(codec, adc_idx, i); 2673c697b716STakashi Iwai if (!path || !path->ctls[type]) 2674352f7f91STakashi Iwai continue; 2675352f7f91STakashi Iwai kcontrol->private_value = path->ctls[type]; 2676352f7f91STakashi Iwai err = func(kcontrol, ucontrol); 2677352f7f91STakashi Iwai if (err < 0) 2678352f7f91STakashi Iwai goto error; 2679352f7f91STakashi Iwai } 2680352f7f91STakashi Iwai error: 2681352f7f91STakashi Iwai codec->cached_write = 0; 2682352f7f91STakashi Iwai mutex_unlock(&codec->control_mutex); 268347d46abbSTakashi Iwai snd_hda_codec_flush_amp_cache(codec); /* flush the updates */ 2684352f7f91STakashi Iwai if (err >= 0 && spec->cap_sync_hook) 2685352f7f91STakashi Iwai spec->cap_sync_hook(codec); 2686352f7f91STakashi Iwai return err; 2687352f7f91STakashi Iwai } 2688352f7f91STakashi Iwai 2689352f7f91STakashi Iwai /* capture volume ctl callbacks */ 2690352f7f91STakashi Iwai #define cap_vol_info snd_hda_mixer_amp_volume_info 2691352f7f91STakashi Iwai #define cap_vol_get snd_hda_mixer_amp_volume_get 2692352f7f91STakashi Iwai #define cap_vol_tlv snd_hda_mixer_amp_tlv 2693352f7f91STakashi Iwai 2694352f7f91STakashi Iwai static int cap_vol_put(struct snd_kcontrol *kcontrol, 2695352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2696352f7f91STakashi Iwai { 2697352f7f91STakashi Iwai return cap_put_caller(kcontrol, ucontrol, 2698352f7f91STakashi Iwai snd_hda_mixer_amp_volume_put, 2699352f7f91STakashi Iwai NID_PATH_VOL_CTL); 2700352f7f91STakashi Iwai } 2701352f7f91STakashi Iwai 2702352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_vol_temp = { 2703352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2704352f7f91STakashi Iwai .name = "Capture Volume", 2705352f7f91STakashi Iwai .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 2706352f7f91STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ | 2707352f7f91STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), 2708352f7f91STakashi Iwai .info = cap_vol_info, 2709352f7f91STakashi Iwai .get = cap_vol_get, 2710352f7f91STakashi Iwai .put = cap_vol_put, 2711352f7f91STakashi Iwai .tlv = { .c = cap_vol_tlv }, 2712352f7f91STakashi Iwai }; 2713352f7f91STakashi Iwai 2714352f7f91STakashi Iwai /* capture switch ctl callbacks */ 2715352f7f91STakashi Iwai #define cap_sw_info snd_ctl_boolean_stereo_info 2716352f7f91STakashi Iwai #define cap_sw_get snd_hda_mixer_amp_switch_get 2717352f7f91STakashi Iwai 2718352f7f91STakashi Iwai static int cap_sw_put(struct snd_kcontrol *kcontrol, 2719352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2720352f7f91STakashi Iwai { 2721ae177c3fSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2722ae177c3fSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 2723ae177c3fSTakashi Iwai int ret; 2724ae177c3fSTakashi Iwai 2725ae177c3fSTakashi Iwai ret = cap_put_caller(kcontrol, ucontrol, 2726352f7f91STakashi Iwai snd_hda_mixer_amp_switch_put, 2727352f7f91STakashi Iwai NID_PATH_MUTE_CTL); 2728ae177c3fSTakashi Iwai if (ret < 0) 2729ae177c3fSTakashi Iwai return ret; 2730ae177c3fSTakashi Iwai 2731ae177c3fSTakashi Iwai if (spec->capture_switch_hook) { 2732ae177c3fSTakashi Iwai bool enable = (ucontrol->value.integer.value[0] || 2733ae177c3fSTakashi Iwai ucontrol->value.integer.value[1]); 2734ae177c3fSTakashi Iwai spec->capture_switch_hook(codec, enable); 2735ae177c3fSTakashi Iwai } 2736ae177c3fSTakashi Iwai 2737ae177c3fSTakashi Iwai return ret; 2738352f7f91STakashi Iwai } 2739352f7f91STakashi Iwai 2740352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_sw_temp = { 2741352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2742352f7f91STakashi Iwai .name = "Capture Switch", 2743352f7f91STakashi Iwai .info = cap_sw_info, 2744352f7f91STakashi Iwai .get = cap_sw_get, 2745352f7f91STakashi Iwai .put = cap_sw_put, 2746352f7f91STakashi Iwai }; 2747352f7f91STakashi Iwai 2748352f7f91STakashi Iwai static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path) 2749352f7f91STakashi Iwai { 2750352f7f91STakashi Iwai hda_nid_t nid; 2751352f7f91STakashi Iwai int i, depth; 2752352f7f91STakashi Iwai 2753352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = path->ctls[NID_PATH_MUTE_CTL] = 0; 2754352f7f91STakashi Iwai for (depth = 0; depth < 3; depth++) { 2755352f7f91STakashi Iwai if (depth >= path->depth) 2756352f7f91STakashi Iwai return -EINVAL; 2757352f7f91STakashi Iwai i = path->depth - depth - 1; 2758352f7f91STakashi Iwai nid = path->path[i]; 2759352f7f91STakashi Iwai if (!path->ctls[NID_PATH_VOL_CTL]) { 2760352f7f91STakashi Iwai if (nid_has_volume(codec, nid, HDA_OUTPUT)) 2761352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = 2762352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 2763352f7f91STakashi Iwai else if (nid_has_volume(codec, nid, HDA_INPUT)) { 2764352f7f91STakashi Iwai int idx = path->idx[i]; 2765352f7f91STakashi Iwai if (!depth && codec->single_adc_amp) 2766352f7f91STakashi Iwai idx = 0; 2767352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = 2768352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); 2769352f7f91STakashi Iwai } 2770352f7f91STakashi Iwai } 2771352f7f91STakashi Iwai if (!path->ctls[NID_PATH_MUTE_CTL]) { 2772352f7f91STakashi Iwai if (nid_has_mute(codec, nid, HDA_OUTPUT)) 2773352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = 2774352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 2775352f7f91STakashi Iwai else if (nid_has_mute(codec, nid, HDA_INPUT)) { 2776352f7f91STakashi Iwai int idx = path->idx[i]; 2777352f7f91STakashi Iwai if (!depth && codec->single_adc_amp) 2778352f7f91STakashi Iwai idx = 0; 2779352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = 2780352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); 2781352f7f91STakashi Iwai } 2782352f7f91STakashi Iwai } 2783352f7f91STakashi Iwai } 2784352f7f91STakashi Iwai return 0; 2785352f7f91STakashi Iwai } 2786352f7f91STakashi Iwai 2787352f7f91STakashi Iwai static bool is_inv_dmic_pin(struct hda_codec *codec, hda_nid_t nid) 2788352f7f91STakashi Iwai { 2789352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2790352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 2791352f7f91STakashi Iwai unsigned int val; 2792352f7f91STakashi Iwai int i; 2793352f7f91STakashi Iwai 2794352f7f91STakashi Iwai if (!spec->inv_dmic_split) 2795352f7f91STakashi Iwai return false; 2796352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 2797352f7f91STakashi Iwai if (cfg->inputs[i].pin != nid) 2798352f7f91STakashi Iwai continue; 2799352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC) 2800352f7f91STakashi Iwai return false; 2801352f7f91STakashi Iwai val = snd_hda_codec_get_pincfg(codec, nid); 2802352f7f91STakashi Iwai return snd_hda_get_input_pin_attr(val) == INPUT_PIN_ATTR_INT; 2803352f7f91STakashi Iwai } 2804352f7f91STakashi Iwai return false; 2805352f7f91STakashi Iwai } 2806352f7f91STakashi Iwai 2807352f7f91STakashi Iwai static int add_single_cap_ctl(struct hda_codec *codec, const char *label, 2808352f7f91STakashi Iwai int idx, bool is_switch, unsigned int ctl, 2809352f7f91STakashi Iwai bool inv_dmic) 2810352f7f91STakashi Iwai { 2811352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2812352f7f91STakashi Iwai char tmpname[44]; 2813352f7f91STakashi Iwai int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL; 2814352f7f91STakashi Iwai const char *sfx = is_switch ? "Switch" : "Volume"; 2815352f7f91STakashi Iwai unsigned int chs = inv_dmic ? 1 : 3; 2816352f7f91STakashi Iwai int err; 2817352f7f91STakashi Iwai 2818352f7f91STakashi Iwai if (!ctl) 2819352f7f91STakashi Iwai return 0; 2820352f7f91STakashi Iwai 2821352f7f91STakashi Iwai if (label) 2822352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2823352f7f91STakashi Iwai "%s Capture %s", label, sfx); 2824352f7f91STakashi Iwai else 2825352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2826352f7f91STakashi Iwai "Capture %s", sfx); 2827352f7f91STakashi Iwai err = add_control(spec, type, tmpname, idx, 2828352f7f91STakashi Iwai amp_val_replace_channels(ctl, chs)); 2829352f7f91STakashi Iwai if (err < 0 || !inv_dmic) 2830352f7f91STakashi Iwai return err; 2831352f7f91STakashi Iwai 2832352f7f91STakashi Iwai /* Make independent right kcontrol */ 2833352f7f91STakashi Iwai if (label) 2834352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2835352f7f91STakashi Iwai "Inverted %s Capture %s", label, sfx); 2836352f7f91STakashi Iwai else 2837352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2838352f7f91STakashi Iwai "Inverted Capture %s", sfx); 2839352f7f91STakashi Iwai return add_control(spec, type, tmpname, idx, 2840352f7f91STakashi Iwai amp_val_replace_channels(ctl, 2)); 2841352f7f91STakashi Iwai } 2842352f7f91STakashi Iwai 2843352f7f91STakashi Iwai /* create single (and simple) capture volume and switch controls */ 2844352f7f91STakashi Iwai static int create_single_cap_vol_ctl(struct hda_codec *codec, int idx, 2845352f7f91STakashi Iwai unsigned int vol_ctl, unsigned int sw_ctl, 2846352f7f91STakashi Iwai bool inv_dmic) 2847352f7f91STakashi Iwai { 2848352f7f91STakashi Iwai int err; 2849352f7f91STakashi Iwai err = add_single_cap_ctl(codec, NULL, idx, false, vol_ctl, inv_dmic); 2850352f7f91STakashi Iwai if (err < 0) 2851352f7f91STakashi Iwai return err; 2852352f7f91STakashi Iwai err = add_single_cap_ctl(codec, NULL, idx, true, sw_ctl, inv_dmic); 2853071c73adSTakashi Iwai if (err < 0) 2854071c73adSTakashi Iwai return err; 2855071c73adSTakashi Iwai return 0; 28561da177e4SLinus Torvalds } 2857071c73adSTakashi Iwai 2858352f7f91STakashi Iwai /* create bound capture volume and switch controls */ 2859352f7f91STakashi Iwai static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx, 2860352f7f91STakashi Iwai unsigned int vol_ctl, unsigned int sw_ctl) 2861352f7f91STakashi Iwai { 2862352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2863352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 2864352f7f91STakashi Iwai 2865352f7f91STakashi Iwai if (vol_ctl) { 286612c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, NULL, &cap_vol_temp); 2867352f7f91STakashi Iwai if (!knew) 2868352f7f91STakashi Iwai return -ENOMEM; 2869352f7f91STakashi Iwai knew->index = idx; 2870352f7f91STakashi Iwai knew->private_value = vol_ctl; 2871352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 2872352f7f91STakashi Iwai } 2873352f7f91STakashi Iwai if (sw_ctl) { 287412c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, NULL, &cap_sw_temp); 2875352f7f91STakashi Iwai if (!knew) 2876352f7f91STakashi Iwai return -ENOMEM; 2877352f7f91STakashi Iwai knew->index = idx; 2878352f7f91STakashi Iwai knew->private_value = sw_ctl; 2879352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 2880352f7f91STakashi Iwai } 2881352f7f91STakashi Iwai return 0; 2882352f7f91STakashi Iwai } 2883352f7f91STakashi Iwai 2884352f7f91STakashi Iwai /* return the vol ctl when used first in the imux list */ 2885352f7f91STakashi Iwai static unsigned int get_first_cap_ctl(struct hda_codec *codec, int idx, int type) 2886352f7f91STakashi Iwai { 2887352f7f91STakashi Iwai struct nid_path *path; 2888352f7f91STakashi Iwai unsigned int ctl; 2889352f7f91STakashi Iwai int i; 2890352f7f91STakashi Iwai 2891c697b716STakashi Iwai path = get_input_path(codec, 0, idx); 2892352f7f91STakashi Iwai if (!path) 2893352f7f91STakashi Iwai return 0; 2894352f7f91STakashi Iwai ctl = path->ctls[type]; 2895352f7f91STakashi Iwai if (!ctl) 2896352f7f91STakashi Iwai return 0; 2897352f7f91STakashi Iwai for (i = 0; i < idx - 1; i++) { 2898c697b716STakashi Iwai path = get_input_path(codec, 0, i); 2899352f7f91STakashi Iwai if (path && path->ctls[type] == ctl) 2900352f7f91STakashi Iwai return 0; 2901352f7f91STakashi Iwai } 2902352f7f91STakashi Iwai return ctl; 2903352f7f91STakashi Iwai } 2904352f7f91STakashi Iwai 2905352f7f91STakashi Iwai /* create individual capture volume and switch controls per input */ 2906352f7f91STakashi Iwai static int create_multi_cap_vol_ctl(struct hda_codec *codec) 2907352f7f91STakashi Iwai { 2908352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2909352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 2910352f7f91STakashi Iwai int i, err, type, type_idx = 0; 2911352f7f91STakashi Iwai const char *prev_label = NULL; 2912352f7f91STakashi Iwai 2913352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2914352f7f91STakashi Iwai const char *label; 2915352f7f91STakashi Iwai bool inv_dmic; 29169dba205bSTakashi Iwai 29179dba205bSTakashi Iwai if (imux->items[i].index >= spec->autocfg.num_inputs) 29189dba205bSTakashi Iwai continue; 29199dba205bSTakashi Iwai label = hda_get_autocfg_input_label(codec, &spec->autocfg, 29209dba205bSTakashi Iwai imux->items[i].index); 2921352f7f91STakashi Iwai if (prev_label && !strcmp(label, prev_label)) 2922352f7f91STakashi Iwai type_idx++; 2923352f7f91STakashi Iwai else 2924352f7f91STakashi Iwai type_idx = 0; 2925352f7f91STakashi Iwai prev_label = label; 2926352f7f91STakashi Iwai inv_dmic = is_inv_dmic_pin(codec, spec->imux_pins[i]); 2927352f7f91STakashi Iwai 2928352f7f91STakashi Iwai for (type = 0; type < 2; type++) { 2929352f7f91STakashi Iwai err = add_single_cap_ctl(codec, label, type_idx, type, 2930352f7f91STakashi Iwai get_first_cap_ctl(codec, i, type), 2931352f7f91STakashi Iwai inv_dmic); 2932d13bd412STakashi Iwai if (err < 0) 2933071c73adSTakashi Iwai return err; 2934352f7f91STakashi Iwai } 2935352f7f91STakashi Iwai } 2936071c73adSTakashi Iwai return 0; 2937352f7f91STakashi Iwai } 2938071c73adSTakashi Iwai 2939352f7f91STakashi Iwai static int create_capture_mixers(struct hda_codec *codec) 2940352f7f91STakashi Iwai { 2941352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2942352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 2943352f7f91STakashi Iwai int i, n, nums, err; 2944352f7f91STakashi Iwai 2945352f7f91STakashi Iwai if (spec->dyn_adc_switch) 2946352f7f91STakashi Iwai nums = 1; 2947352f7f91STakashi Iwai else 2948352f7f91STakashi Iwai nums = spec->num_adc_nids; 2949352f7f91STakashi Iwai 2950352f7f91STakashi Iwai if (!spec->auto_mic && imux->num_items > 1) { 2951352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 2952624d914dSTakashi Iwai const char *name; 2953624d914dSTakashi Iwai name = nums > 1 ? "Input Source" : "Capture Source"; 2954624d914dSTakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &cap_src_temp); 2955352f7f91STakashi Iwai if (!knew) 2956352f7f91STakashi Iwai return -ENOMEM; 2957352f7f91STakashi Iwai knew->count = nums; 2958352f7f91STakashi Iwai } 2959352f7f91STakashi Iwai 2960352f7f91STakashi Iwai for (n = 0; n < nums; n++) { 2961352f7f91STakashi Iwai bool multi = false; 296299a5592dSDavid Henningsson bool multi_cap_vol = spec->multi_cap_vol; 2963352f7f91STakashi Iwai bool inv_dmic = false; 2964352f7f91STakashi Iwai int vol, sw; 2965352f7f91STakashi Iwai 2966352f7f91STakashi Iwai vol = sw = 0; 2967352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2968352f7f91STakashi Iwai struct nid_path *path; 2969c697b716STakashi Iwai path = get_input_path(codec, n, i); 2970352f7f91STakashi Iwai if (!path) 2971352f7f91STakashi Iwai continue; 2972352f7f91STakashi Iwai parse_capvol_in_path(codec, path); 2973352f7f91STakashi Iwai if (!vol) 2974352f7f91STakashi Iwai vol = path->ctls[NID_PATH_VOL_CTL]; 297599a5592dSDavid Henningsson else if (vol != path->ctls[NID_PATH_VOL_CTL]) { 2976352f7f91STakashi Iwai multi = true; 297799a5592dSDavid Henningsson if (!same_amp_caps(codec, vol, 297899a5592dSDavid Henningsson path->ctls[NID_PATH_VOL_CTL], HDA_INPUT)) 297999a5592dSDavid Henningsson multi_cap_vol = true; 298099a5592dSDavid Henningsson } 2981352f7f91STakashi Iwai if (!sw) 2982352f7f91STakashi Iwai sw = path->ctls[NID_PATH_MUTE_CTL]; 298399a5592dSDavid Henningsson else if (sw != path->ctls[NID_PATH_MUTE_CTL]) { 2984352f7f91STakashi Iwai multi = true; 298599a5592dSDavid Henningsson if (!same_amp_caps(codec, sw, 298699a5592dSDavid Henningsson path->ctls[NID_PATH_MUTE_CTL], HDA_INPUT)) 298799a5592dSDavid Henningsson multi_cap_vol = true; 298899a5592dSDavid Henningsson } 2989352f7f91STakashi Iwai if (is_inv_dmic_pin(codec, spec->imux_pins[i])) 2990352f7f91STakashi Iwai inv_dmic = true; 2991352f7f91STakashi Iwai } 2992352f7f91STakashi Iwai 2993352f7f91STakashi Iwai if (!multi) 2994352f7f91STakashi Iwai err = create_single_cap_vol_ctl(codec, n, vol, sw, 2995352f7f91STakashi Iwai inv_dmic); 299699a5592dSDavid Henningsson else if (!multi_cap_vol) 2997352f7f91STakashi Iwai err = create_bind_cap_vol_ctl(codec, n, vol, sw); 2998352f7f91STakashi Iwai else 2999352f7f91STakashi Iwai err = create_multi_cap_vol_ctl(codec); 3000d13bd412STakashi Iwai if (err < 0) 3001071c73adSTakashi Iwai return err; 3002071c73adSTakashi Iwai } 3003071c73adSTakashi Iwai 30041da177e4SLinus Torvalds return 0; 30051da177e4SLinus Torvalds } 30061da177e4SLinus Torvalds 3007352f7f91STakashi Iwai /* 3008352f7f91STakashi Iwai * add mic boosts if needed 3009352f7f91STakashi Iwai */ 3010352f7f91STakashi Iwai static int parse_mic_boost(struct hda_codec *codec) 3011352f7f91STakashi Iwai { 3012352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3013352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 3014352f7f91STakashi Iwai int i, err; 3015352f7f91STakashi Iwai int type_idx = 0; 3016352f7f91STakashi Iwai hda_nid_t nid; 3017352f7f91STakashi Iwai const char *prev_label = NULL; 3018352f7f91STakashi Iwai 3019352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 3020352f7f91STakashi Iwai if (cfg->inputs[i].type > AUTO_PIN_MIC) 3021352f7f91STakashi Iwai break; 3022352f7f91STakashi Iwai nid = cfg->inputs[i].pin; 3023352f7f91STakashi Iwai if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { 3024352f7f91STakashi Iwai const char *label; 30255abd4888STakashi Iwai char boost_label[44]; 3026352f7f91STakashi Iwai struct nid_path *path; 3027352f7f91STakashi Iwai unsigned int val; 3028352f7f91STakashi Iwai 302902aba550SDavid Henningsson if (!nid_has_volume(codec, nid, HDA_INPUT)) 303002aba550SDavid Henningsson continue; 303102aba550SDavid Henningsson 3032352f7f91STakashi Iwai label = hda_get_autocfg_input_label(codec, cfg, i); 3033352f7f91STakashi Iwai if (prev_label && !strcmp(label, prev_label)) 3034352f7f91STakashi Iwai type_idx++; 3035352f7f91STakashi Iwai else 3036352f7f91STakashi Iwai type_idx = 0; 3037352f7f91STakashi Iwai prev_label = label; 3038352f7f91STakashi Iwai 3039352f7f91STakashi Iwai snprintf(boost_label, sizeof(boost_label), 3040352f7f91STakashi Iwai "%s Boost Volume", label); 3041352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); 3042352f7f91STakashi Iwai err = add_control(spec, HDA_CTL_WIDGET_VOL, 3043352f7f91STakashi Iwai boost_label, type_idx, val); 3044352f7f91STakashi Iwai if (err < 0) 3045352f7f91STakashi Iwai return err; 3046352f7f91STakashi Iwai 3047352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, nid, 0); 3048352f7f91STakashi Iwai if (path) 3049352f7f91STakashi Iwai path->ctls[NID_PATH_BOOST_CTL] = val; 3050352f7f91STakashi Iwai } 3051352f7f91STakashi Iwai } 3052352f7f91STakashi Iwai return 0; 3053352f7f91STakashi Iwai } 3054352f7f91STakashi Iwai 3055352f7f91STakashi Iwai /* 3056352f7f91STakashi Iwai * parse digital I/Os and set up NIDs in BIOS auto-parse mode 3057352f7f91STakashi Iwai */ 3058352f7f91STakashi Iwai static void parse_digital(struct hda_codec *codec) 3059352f7f91STakashi Iwai { 3060352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 30610c8c0f56STakashi Iwai struct nid_path *path; 3062352f7f91STakashi Iwai int i, nums; 30632c12c30dSTakashi Iwai hda_nid_t dig_nid, pin; 3064352f7f91STakashi Iwai 3065352f7f91STakashi Iwai /* support multiple SPDIFs; the secondary is set up as a slave */ 3066352f7f91STakashi Iwai nums = 0; 3067352f7f91STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) { 30682c12c30dSTakashi Iwai pin = spec->autocfg.dig_out_pins[i]; 3069352f7f91STakashi Iwai dig_nid = look_for_dac(codec, pin, true); 3070352f7f91STakashi Iwai if (!dig_nid) 3071352f7f91STakashi Iwai continue; 30723ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dig_nid, pin, 0); 30730c8c0f56STakashi Iwai if (!path) 3074352f7f91STakashi Iwai continue; 30750c8c0f56STakashi Iwai print_nid_path("digout", path); 3076e1284af7STakashi Iwai path->active = true; 3077196c1766STakashi Iwai spec->digout_paths[i] = snd_hda_get_path_idx(codec, path); 30782c12c30dSTakashi Iwai set_pin_target(codec, pin, PIN_OUT, false); 3079352f7f91STakashi Iwai if (!nums) { 3080352f7f91STakashi Iwai spec->multiout.dig_out_nid = dig_nid; 3081352f7f91STakashi Iwai spec->dig_out_type = spec->autocfg.dig_out_type[0]; 3082352f7f91STakashi Iwai } else { 3083352f7f91STakashi Iwai spec->multiout.slave_dig_outs = spec->slave_dig_outs; 3084352f7f91STakashi Iwai if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) 3085352f7f91STakashi Iwai break; 3086352f7f91STakashi Iwai spec->slave_dig_outs[nums - 1] = dig_nid; 3087352f7f91STakashi Iwai } 3088352f7f91STakashi Iwai nums++; 3089352f7f91STakashi Iwai } 3090352f7f91STakashi Iwai 3091352f7f91STakashi Iwai if (spec->autocfg.dig_in_pin) { 30922c12c30dSTakashi Iwai pin = spec->autocfg.dig_in_pin; 3093352f7f91STakashi Iwai dig_nid = codec->start_nid; 3094352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, dig_nid++) { 3095352f7f91STakashi Iwai unsigned int wcaps = get_wcaps(codec, dig_nid); 3096352f7f91STakashi Iwai if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) 3097352f7f91STakashi Iwai continue; 3098352f7f91STakashi Iwai if (!(wcaps & AC_WCAP_DIGITAL)) 3099352f7f91STakashi Iwai continue; 31002c12c30dSTakashi Iwai path = snd_hda_add_new_path(codec, pin, dig_nid, 0); 3101352f7f91STakashi Iwai if (path) { 31020c8c0f56STakashi Iwai print_nid_path("digin", path); 3103352f7f91STakashi Iwai path->active = true; 3104352f7f91STakashi Iwai spec->dig_in_nid = dig_nid; 31052430d7b7STakashi Iwai spec->digin_path = snd_hda_get_path_idx(codec, path); 31062c12c30dSTakashi Iwai set_pin_target(codec, pin, PIN_IN, false); 3107352f7f91STakashi Iwai break; 3108352f7f91STakashi Iwai } 3109352f7f91STakashi Iwai } 3110352f7f91STakashi Iwai } 3111352f7f91STakashi Iwai } 3112352f7f91STakashi Iwai 31131da177e4SLinus Torvalds 31141da177e4SLinus Torvalds /* 3115352f7f91STakashi Iwai * input MUX handling 31161da177e4SLinus Torvalds */ 31171da177e4SLinus Torvalds 3118352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur); 3119352f7f91STakashi Iwai 3120352f7f91STakashi Iwai /* select the given imux item; either unmute exclusively or select the route */ 3121352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx, 3122352f7f91STakashi Iwai unsigned int idx) 3123352f7f91STakashi Iwai { 3124352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3125352f7f91STakashi Iwai const struct hda_input_mux *imux; 3126352f7f91STakashi Iwai struct nid_path *path; 3127352f7f91STakashi Iwai 3128352f7f91STakashi Iwai imux = &spec->input_mux; 3129352f7f91STakashi Iwai if (!imux->num_items) 31301da177e4SLinus Torvalds return 0; 31311da177e4SLinus Torvalds 3132352f7f91STakashi Iwai if (idx >= imux->num_items) 3133352f7f91STakashi Iwai idx = imux->num_items - 1; 3134352f7f91STakashi Iwai if (spec->cur_mux[adc_idx] == idx) 3135352f7f91STakashi Iwai return 0; 3136352f7f91STakashi Iwai 3137c697b716STakashi Iwai path = get_input_path(codec, adc_idx, spec->cur_mux[adc_idx]); 3138352f7f91STakashi Iwai if (!path) 3139352f7f91STakashi Iwai return 0; 3140352f7f91STakashi Iwai if (path->active) 3141352f7f91STakashi Iwai snd_hda_activate_path(codec, path, false, false); 3142352f7f91STakashi Iwai 3143352f7f91STakashi Iwai spec->cur_mux[adc_idx] = idx; 3144352f7f91STakashi Iwai 3145352f7f91STakashi Iwai if (spec->shared_mic_hp) 3146352f7f91STakashi Iwai update_shared_mic_hp(codec, spec->cur_mux[adc_idx]); 3147352f7f91STakashi Iwai 3148352f7f91STakashi Iwai if (spec->dyn_adc_switch) 3149352f7f91STakashi Iwai dyn_adc_pcm_resetup(codec, idx); 3150352f7f91STakashi Iwai 3151c697b716STakashi Iwai path = get_input_path(codec, adc_idx, idx); 3152352f7f91STakashi Iwai if (!path) 3153352f7f91STakashi Iwai return 0; 3154352f7f91STakashi Iwai if (path->active) 3155352f7f91STakashi Iwai return 0; 3156352f7f91STakashi Iwai snd_hda_activate_path(codec, path, true, false); 3157352f7f91STakashi Iwai if (spec->cap_sync_hook) 3158352f7f91STakashi Iwai spec->cap_sync_hook(codec); 31591da177e4SLinus Torvalds return 1; 31601da177e4SLinus Torvalds } 31611da177e4SLinus Torvalds 31621da177e4SLinus Torvalds 31631da177e4SLinus Torvalds /* 3164352f7f91STakashi Iwai * Jack detections for HP auto-mute and mic-switch 31651da177e4SLinus Torvalds */ 3166352f7f91STakashi Iwai 3167352f7f91STakashi Iwai /* check each pin in the given array; returns true if any of them is plugged */ 3168352f7f91STakashi Iwai static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) 31691da177e4SLinus Torvalds { 3170352f7f91STakashi Iwai int i, present = 0; 31711da177e4SLinus Torvalds 3172352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 3173352f7f91STakashi Iwai hda_nid_t nid = pins[i]; 3174352f7f91STakashi Iwai if (!nid) 3175352f7f91STakashi Iwai break; 31760b4df931STakashi Iwai /* don't detect pins retasked as inputs */ 31770b4df931STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN) 31780b4df931STakashi Iwai continue; 3179352f7f91STakashi Iwai present |= snd_hda_jack_detect(codec, nid); 31801da177e4SLinus Torvalds } 3181352f7f91STakashi Iwai return present; 31821da177e4SLinus Torvalds } 31831da177e4SLinus Torvalds 3184352f7f91STakashi Iwai /* standard HP/line-out auto-mute helper */ 3185352f7f91STakashi Iwai static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, 31862c12c30dSTakashi Iwai bool mute) 31871da177e4SLinus Torvalds { 3188352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3189352f7f91STakashi Iwai int i; 31901da177e4SLinus Torvalds 3191352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 3192352f7f91STakashi Iwai hda_nid_t nid = pins[i]; 3193352f7f91STakashi Iwai unsigned int val; 3194352f7f91STakashi Iwai if (!nid) 3195352f7f91STakashi Iwai break; 3196352f7f91STakashi Iwai /* don't reset VREF value in case it's controlling 3197352f7f91STakashi Iwai * the amp (see alc861_fixup_asus_amp_vref_0f()) 3198352f7f91STakashi Iwai */ 31992c12c30dSTakashi Iwai if (spec->keep_vref_in_automute) 32002c12c30dSTakashi Iwai val = snd_hda_codec_get_pin_target(codec, nid) & ~PIN_HP; 32012c12c30dSTakashi Iwai else 3202352f7f91STakashi Iwai val = 0; 32032c12c30dSTakashi Iwai if (!mute) 32042c12c30dSTakashi Iwai val |= snd_hda_codec_get_pin_target(codec, nid); 32052c12c30dSTakashi Iwai /* here we call update_pin_ctl() so that the pinctl is changed 32062c12c30dSTakashi Iwai * without changing the pinctl target value; 32072c12c30dSTakashi Iwai * the original target value will be still referred at the 32082c12c30dSTakashi Iwai * init / resume again 32092c12c30dSTakashi Iwai */ 32102c12c30dSTakashi Iwai update_pin_ctl(codec, nid, val); 3211d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, !mute); 3212352f7f91STakashi Iwai } 3213352f7f91STakashi Iwai } 32141da177e4SLinus Torvalds 3215352f7f91STakashi Iwai /* Toggle outputs muting */ 32165d550e15STakashi Iwai void snd_hda_gen_update_outputs(struct hda_codec *codec) 3217352f7f91STakashi Iwai { 3218352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3219352f7f91STakashi Iwai int on; 3220352f7f91STakashi Iwai 3221352f7f91STakashi Iwai /* Control HP pins/amps depending on master_mute state; 3222352f7f91STakashi Iwai * in general, HP pins/amps control should be enabled in all cases, 3223352f7f91STakashi Iwai * but currently set only for master_mute, just to be safe 3224352f7f91STakashi Iwai */ 3225352f7f91STakashi Iwai if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */ 3226352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), 32272c12c30dSTakashi Iwai spec->autocfg.hp_pins, spec->master_mute); 3228352f7f91STakashi Iwai 3229352f7f91STakashi Iwai if (!spec->automute_speaker) 3230352f7f91STakashi Iwai on = 0; 3231352f7f91STakashi Iwai else 3232352f7f91STakashi Iwai on = spec->hp_jack_present | spec->line_jack_present; 3233352f7f91STakashi Iwai on |= spec->master_mute; 323447b9ddb8STakashi Iwai spec->speaker_muted = on; 3235352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), 32362c12c30dSTakashi Iwai spec->autocfg.speaker_pins, on); 3237352f7f91STakashi Iwai 3238352f7f91STakashi Iwai /* toggle line-out mutes if needed, too */ 3239352f7f91STakashi Iwai /* if LO is a copy of either HP or Speaker, don't need to handle it */ 3240352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] || 3241352f7f91STakashi Iwai spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0]) 3242352f7f91STakashi Iwai return; 3243352f7f91STakashi Iwai if (!spec->automute_lo) 3244352f7f91STakashi Iwai on = 0; 3245352f7f91STakashi Iwai else 3246352f7f91STakashi Iwai on = spec->hp_jack_present; 3247352f7f91STakashi Iwai on |= spec->master_mute; 324847b9ddb8STakashi Iwai spec->line_out_muted = on; 3249352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), 32502c12c30dSTakashi Iwai spec->autocfg.line_out_pins, on); 3251352f7f91STakashi Iwai } 32525d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs); 3253352f7f91STakashi Iwai 3254352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec) 3255352f7f91STakashi Iwai { 3256352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3257352f7f91STakashi Iwai if (spec->automute_hook) 3258352f7f91STakashi Iwai spec->automute_hook(codec); 3259352f7f91STakashi Iwai else 32605d550e15STakashi Iwai snd_hda_gen_update_outputs(codec); 3261352f7f91STakashi Iwai } 3262352f7f91STakashi Iwai 3263352f7f91STakashi Iwai /* standard HP-automute helper */ 32645d550e15STakashi Iwai void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) 3265352f7f91STakashi Iwai { 3266352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3267352f7f91STakashi Iwai 3268352f7f91STakashi Iwai spec->hp_jack_present = 3269352f7f91STakashi Iwai detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins), 3270352f7f91STakashi Iwai spec->autocfg.hp_pins); 3271352f7f91STakashi Iwai if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo)) 3272352f7f91STakashi Iwai return; 3273352f7f91STakashi Iwai call_update_outputs(codec); 3274352f7f91STakashi Iwai } 32755d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_hp_automute); 3276352f7f91STakashi Iwai 3277352f7f91STakashi Iwai /* standard line-out-automute helper */ 32785d550e15STakashi Iwai void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) 3279352f7f91STakashi Iwai { 3280352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3281352f7f91STakashi Iwai 3282352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) 3283352f7f91STakashi Iwai return; 3284352f7f91STakashi Iwai /* check LO jack only when it's different from HP */ 3285352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0]) 3286352f7f91STakashi Iwai return; 3287352f7f91STakashi Iwai 3288352f7f91STakashi Iwai spec->line_jack_present = 3289352f7f91STakashi Iwai detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), 3290352f7f91STakashi Iwai spec->autocfg.line_out_pins); 3291352f7f91STakashi Iwai if (!spec->automute_speaker || !spec->detect_lo) 3292352f7f91STakashi Iwai return; 3293352f7f91STakashi Iwai call_update_outputs(codec); 3294352f7f91STakashi Iwai } 32955d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_line_automute); 3296352f7f91STakashi Iwai 3297352f7f91STakashi Iwai /* standard mic auto-switch helper */ 32985d550e15STakashi Iwai void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *jack) 3299352f7f91STakashi Iwai { 3300352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3301352f7f91STakashi Iwai int i; 3302352f7f91STakashi Iwai 3303352f7f91STakashi Iwai if (!spec->auto_mic) 3304352f7f91STakashi Iwai return; 3305352f7f91STakashi Iwai 3306352f7f91STakashi Iwai for (i = spec->am_num_entries - 1; i > 0; i--) { 33070b4df931STakashi Iwai hda_nid_t pin = spec->am_entry[i].pin; 33080b4df931STakashi Iwai /* don't detect pins retasked as outputs */ 33090b4df931STakashi Iwai if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN) 33100b4df931STakashi Iwai continue; 33110b4df931STakashi Iwai if (snd_hda_jack_detect(codec, pin)) { 3312352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[i].idx); 3313352f7f91STakashi Iwai return; 3314352f7f91STakashi Iwai } 3315352f7f91STakashi Iwai } 3316352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[0].idx); 33171da177e4SLinus Torvalds } 33185d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_mic_autoswitch); 33191da177e4SLinus Torvalds 3320a5cc2509STakashi Iwai /* update jack retasking */ 3321a5cc2509STakashi Iwai static void update_automute_all(struct hda_codec *codec) 3322a5cc2509STakashi Iwai { 3323a5cc2509STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3324a5cc2509STakashi Iwai 3325a5cc2509STakashi Iwai if (spec->hp_automute_hook) 3326a5cc2509STakashi Iwai spec->hp_automute_hook(codec, NULL); 3327a5cc2509STakashi Iwai else 3328a5cc2509STakashi Iwai snd_hda_gen_hp_automute(codec, NULL); 3329a5cc2509STakashi Iwai if (spec->line_automute_hook) 3330a5cc2509STakashi Iwai spec->line_automute_hook(codec, NULL); 3331a5cc2509STakashi Iwai else 3332a5cc2509STakashi Iwai snd_hda_gen_line_automute(codec, NULL); 3333a5cc2509STakashi Iwai if (spec->mic_autoswitch_hook) 3334a5cc2509STakashi Iwai spec->mic_autoswitch_hook(codec, NULL); 3335a5cc2509STakashi Iwai else 3336a5cc2509STakashi Iwai snd_hda_gen_mic_autoswitch(codec, NULL); 3337a5cc2509STakashi Iwai } 3338a5cc2509STakashi Iwai 33391da177e4SLinus Torvalds /* 3340352f7f91STakashi Iwai * Auto-Mute mode mixer enum support 33411da177e4SLinus Torvalds */ 3342352f7f91STakashi Iwai static int automute_mode_info(struct snd_kcontrol *kcontrol, 3343352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 3344352f7f91STakashi Iwai { 3345352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3346352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3347352f7f91STakashi Iwai static const char * const texts3[] = { 3348352f7f91STakashi Iwai "Disabled", "Speaker Only", "Line Out+Speaker" 33491da177e4SLinus Torvalds }; 33501da177e4SLinus Torvalds 3351352f7f91STakashi Iwai if (spec->automute_speaker_possible && spec->automute_lo_possible) 3352352f7f91STakashi Iwai return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3); 3353352f7f91STakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo); 3354352f7f91STakashi Iwai } 3355352f7f91STakashi Iwai 3356352f7f91STakashi Iwai static int automute_mode_get(struct snd_kcontrol *kcontrol, 3357352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3358352f7f91STakashi Iwai { 3359352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3360352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3361352f7f91STakashi Iwai unsigned int val = 0; 3362352f7f91STakashi Iwai if (spec->automute_speaker) 3363352f7f91STakashi Iwai val++; 3364352f7f91STakashi Iwai if (spec->automute_lo) 3365352f7f91STakashi Iwai val++; 3366352f7f91STakashi Iwai 3367352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = val; 3368352f7f91STakashi Iwai return 0; 3369352f7f91STakashi Iwai } 3370352f7f91STakashi Iwai 3371352f7f91STakashi Iwai static int automute_mode_put(struct snd_kcontrol *kcontrol, 3372352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3373352f7f91STakashi Iwai { 3374352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3375352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3376352f7f91STakashi Iwai 3377352f7f91STakashi Iwai switch (ucontrol->value.enumerated.item[0]) { 3378352f7f91STakashi Iwai case 0: 3379352f7f91STakashi Iwai if (!spec->automute_speaker && !spec->automute_lo) 3380352f7f91STakashi Iwai return 0; 3381352f7f91STakashi Iwai spec->automute_speaker = 0; 3382352f7f91STakashi Iwai spec->automute_lo = 0; 3383352f7f91STakashi Iwai break; 3384352f7f91STakashi Iwai case 1: 3385352f7f91STakashi Iwai if (spec->automute_speaker_possible) { 3386352f7f91STakashi Iwai if (!spec->automute_lo && spec->automute_speaker) 3387352f7f91STakashi Iwai return 0; 3388352f7f91STakashi Iwai spec->automute_speaker = 1; 3389352f7f91STakashi Iwai spec->automute_lo = 0; 3390352f7f91STakashi Iwai } else if (spec->automute_lo_possible) { 3391352f7f91STakashi Iwai if (spec->automute_lo) 3392352f7f91STakashi Iwai return 0; 3393352f7f91STakashi Iwai spec->automute_lo = 1; 3394352f7f91STakashi Iwai } else 3395352f7f91STakashi Iwai return -EINVAL; 3396352f7f91STakashi Iwai break; 3397352f7f91STakashi Iwai case 2: 3398352f7f91STakashi Iwai if (!spec->automute_lo_possible || !spec->automute_speaker_possible) 3399352f7f91STakashi Iwai return -EINVAL; 3400352f7f91STakashi Iwai if (spec->automute_speaker && spec->automute_lo) 3401352f7f91STakashi Iwai return 0; 3402352f7f91STakashi Iwai spec->automute_speaker = 1; 3403352f7f91STakashi Iwai spec->automute_lo = 1; 3404352f7f91STakashi Iwai break; 3405352f7f91STakashi Iwai default: 3406352f7f91STakashi Iwai return -EINVAL; 3407352f7f91STakashi Iwai } 3408352f7f91STakashi Iwai call_update_outputs(codec); 3409352f7f91STakashi Iwai return 1; 3410352f7f91STakashi Iwai } 3411352f7f91STakashi Iwai 3412352f7f91STakashi Iwai static const struct snd_kcontrol_new automute_mode_enum = { 3413352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3414352f7f91STakashi Iwai .name = "Auto-Mute Mode", 3415352f7f91STakashi Iwai .info = automute_mode_info, 3416352f7f91STakashi Iwai .get = automute_mode_get, 3417352f7f91STakashi Iwai .put = automute_mode_put, 3418352f7f91STakashi Iwai }; 3419352f7f91STakashi Iwai 3420352f7f91STakashi Iwai static int add_automute_mode_enum(struct hda_codec *codec) 3421352f7f91STakashi Iwai { 3422352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3423352f7f91STakashi Iwai 342412c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &automute_mode_enum)) 3425352f7f91STakashi Iwai return -ENOMEM; 3426352f7f91STakashi Iwai return 0; 3427352f7f91STakashi Iwai } 3428352f7f91STakashi Iwai 3429352f7f91STakashi Iwai /* 3430352f7f91STakashi Iwai * Check the availability of HP/line-out auto-mute; 3431352f7f91STakashi Iwai * Set up appropriately if really supported 3432352f7f91STakashi Iwai */ 3433352f7f91STakashi Iwai static int check_auto_mute_availability(struct hda_codec *codec) 3434352f7f91STakashi Iwai { 3435352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3436352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 3437352f7f91STakashi Iwai int present = 0; 3438352f7f91STakashi Iwai int i, err; 3439352f7f91STakashi Iwai 3440f72706beSTakashi Iwai if (spec->suppress_auto_mute) 3441f72706beSTakashi Iwai return 0; 3442f72706beSTakashi Iwai 3443352f7f91STakashi Iwai if (cfg->hp_pins[0]) 3444352f7f91STakashi Iwai present++; 3445352f7f91STakashi Iwai if (cfg->line_out_pins[0]) 3446352f7f91STakashi Iwai present++; 3447352f7f91STakashi Iwai if (cfg->speaker_pins[0]) 3448352f7f91STakashi Iwai present++; 3449352f7f91STakashi Iwai if (present < 2) /* need two different output types */ 3450352f7f91STakashi Iwai return 0; 3451352f7f91STakashi Iwai 3452352f7f91STakashi Iwai if (!cfg->speaker_pins[0] && 3453352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { 3454352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 3455352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 3456352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 3457352f7f91STakashi Iwai } 3458352f7f91STakashi Iwai 3459352f7f91STakashi Iwai if (!cfg->hp_pins[0] && 3460352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) { 3461352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins, 3462352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 3463352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs; 3464352f7f91STakashi Iwai } 3465352f7f91STakashi Iwai 3466352f7f91STakashi Iwai for (i = 0; i < cfg->hp_outs; i++) { 3467352f7f91STakashi Iwai hda_nid_t nid = cfg->hp_pins[i]; 3468352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 3469352f7f91STakashi Iwai continue; 3470352f7f91STakashi Iwai snd_printdd("hda-codec: Enable HP auto-muting on NID 0x%x\n", 3471352f7f91STakashi Iwai nid); 3472352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid, HDA_GEN_HP_EVENT, 34732e03e952STakashi Iwai spec->hp_automute_hook ? 34742e03e952STakashi Iwai spec->hp_automute_hook : 34755d550e15STakashi Iwai snd_hda_gen_hp_automute); 3476352f7f91STakashi Iwai spec->detect_hp = 1; 3477352f7f91STakashi Iwai } 3478352f7f91STakashi Iwai 3479352f7f91STakashi Iwai if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) { 3480352f7f91STakashi Iwai if (cfg->speaker_outs) 3481352f7f91STakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 3482352f7f91STakashi Iwai hda_nid_t nid = cfg->line_out_pins[i]; 3483352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 3484352f7f91STakashi Iwai continue; 3485352f7f91STakashi Iwai snd_printdd("hda-codec: Enable Line-Out auto-muting on NID 0x%x\n", nid); 3486352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid, 3487352f7f91STakashi Iwai HDA_GEN_FRONT_EVENT, 34882e03e952STakashi Iwai spec->line_automute_hook ? 34892e03e952STakashi Iwai spec->line_automute_hook : 34905d550e15STakashi Iwai snd_hda_gen_line_automute); 3491352f7f91STakashi Iwai spec->detect_lo = 1; 3492352f7f91STakashi Iwai } 3493352f7f91STakashi Iwai spec->automute_lo_possible = spec->detect_hp; 3494352f7f91STakashi Iwai } 3495352f7f91STakashi Iwai 3496352f7f91STakashi Iwai spec->automute_speaker_possible = cfg->speaker_outs && 3497352f7f91STakashi Iwai (spec->detect_hp || spec->detect_lo); 3498352f7f91STakashi Iwai 3499352f7f91STakashi Iwai spec->automute_lo = spec->automute_lo_possible; 3500352f7f91STakashi Iwai spec->automute_speaker = spec->automute_speaker_possible; 3501352f7f91STakashi Iwai 3502352f7f91STakashi Iwai if (spec->automute_speaker_possible || spec->automute_lo_possible) { 3503352f7f91STakashi Iwai /* create a control for automute mode */ 3504352f7f91STakashi Iwai err = add_automute_mode_enum(codec); 3505352f7f91STakashi Iwai if (err < 0) 3506352f7f91STakashi Iwai return err; 3507352f7f91STakashi Iwai } 3508352f7f91STakashi Iwai return 0; 3509352f7f91STakashi Iwai } 3510352f7f91STakashi Iwai 3511352f7f91STakashi Iwai /* check whether all auto-mic pins are valid; setup indices if OK */ 3512352f7f91STakashi Iwai static bool auto_mic_check_imux(struct hda_codec *codec) 3513352f7f91STakashi Iwai { 3514352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3515352f7f91STakashi Iwai const struct hda_input_mux *imux; 3516352f7f91STakashi Iwai int i; 3517352f7f91STakashi Iwai 3518352f7f91STakashi Iwai imux = &spec->input_mux; 3519352f7f91STakashi Iwai for (i = 0; i < spec->am_num_entries; i++) { 3520352f7f91STakashi Iwai spec->am_entry[i].idx = 3521352f7f91STakashi Iwai find_idx_in_nid_list(spec->am_entry[i].pin, 3522352f7f91STakashi Iwai spec->imux_pins, imux->num_items); 3523352f7f91STakashi Iwai if (spec->am_entry[i].idx < 0) 3524352f7f91STakashi Iwai return false; /* no corresponding imux */ 3525352f7f91STakashi Iwai } 3526352f7f91STakashi Iwai 3527352f7f91STakashi Iwai /* we don't need the jack detection for the first pin */ 3528352f7f91STakashi Iwai for (i = 1; i < spec->am_num_entries; i++) 3529352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, 3530352f7f91STakashi Iwai spec->am_entry[i].pin, 3531352f7f91STakashi Iwai HDA_GEN_MIC_EVENT, 35322e03e952STakashi Iwai spec->mic_autoswitch_hook ? 35332e03e952STakashi Iwai spec->mic_autoswitch_hook : 35345d550e15STakashi Iwai snd_hda_gen_mic_autoswitch); 3535352f7f91STakashi Iwai return true; 3536352f7f91STakashi Iwai } 3537352f7f91STakashi Iwai 3538352f7f91STakashi Iwai static int compare_attr(const void *ap, const void *bp) 3539352f7f91STakashi Iwai { 3540352f7f91STakashi Iwai const struct automic_entry *a = ap; 3541352f7f91STakashi Iwai const struct automic_entry *b = bp; 3542352f7f91STakashi Iwai return (int)(a->attr - b->attr); 3543352f7f91STakashi Iwai } 3544352f7f91STakashi Iwai 3545352f7f91STakashi Iwai /* 3546352f7f91STakashi Iwai * Check the availability of auto-mic switch; 3547352f7f91STakashi Iwai * Set up if really supported 3548352f7f91STakashi Iwai */ 3549352f7f91STakashi Iwai static int check_auto_mic_availability(struct hda_codec *codec) 3550352f7f91STakashi Iwai { 3551352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3552352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 3553352f7f91STakashi Iwai unsigned int types; 3554352f7f91STakashi Iwai int i, num_pins; 3555352f7f91STakashi Iwai 3556d12daf6fSTakashi Iwai if (spec->suppress_auto_mic) 3557d12daf6fSTakashi Iwai return 0; 3558d12daf6fSTakashi Iwai 3559352f7f91STakashi Iwai types = 0; 3560352f7f91STakashi Iwai num_pins = 0; 3561352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 3562352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 3563352f7f91STakashi Iwai unsigned int attr; 3564352f7f91STakashi Iwai attr = snd_hda_codec_get_pincfg(codec, nid); 3565352f7f91STakashi Iwai attr = snd_hda_get_input_pin_attr(attr); 3566352f7f91STakashi Iwai if (types & (1 << attr)) 3567352f7f91STakashi Iwai return 0; /* already occupied */ 3568352f7f91STakashi Iwai switch (attr) { 3569352f7f91STakashi Iwai case INPUT_PIN_ATTR_INT: 3570352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC) 3571352f7f91STakashi Iwai return 0; /* invalid type */ 3572352f7f91STakashi Iwai break; 3573352f7f91STakashi Iwai case INPUT_PIN_ATTR_UNUSED: 3574352f7f91STakashi Iwai return 0; /* invalid entry */ 3575352f7f91STakashi Iwai default: 3576352f7f91STakashi Iwai if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) 3577352f7f91STakashi Iwai return 0; /* invalid type */ 3578352f7f91STakashi Iwai if (!spec->line_in_auto_switch && 3579352f7f91STakashi Iwai cfg->inputs[i].type != AUTO_PIN_MIC) 3580352f7f91STakashi Iwai return 0; /* only mic is allowed */ 3581352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 3582352f7f91STakashi Iwai return 0; /* no unsol support */ 3583352f7f91STakashi Iwai break; 3584352f7f91STakashi Iwai } 3585352f7f91STakashi Iwai if (num_pins >= MAX_AUTO_MIC_PINS) 3586352f7f91STakashi Iwai return 0; 3587352f7f91STakashi Iwai types |= (1 << attr); 3588352f7f91STakashi Iwai spec->am_entry[num_pins].pin = nid; 3589352f7f91STakashi Iwai spec->am_entry[num_pins].attr = attr; 3590352f7f91STakashi Iwai num_pins++; 3591352f7f91STakashi Iwai } 3592352f7f91STakashi Iwai 3593352f7f91STakashi Iwai if (num_pins < 2) 3594352f7f91STakashi Iwai return 0; 3595352f7f91STakashi Iwai 3596352f7f91STakashi Iwai spec->am_num_entries = num_pins; 3597352f7f91STakashi Iwai /* sort the am_entry in the order of attr so that the pin with a 3598352f7f91STakashi Iwai * higher attr will be selected when the jack is plugged. 3599352f7f91STakashi Iwai */ 3600352f7f91STakashi Iwai sort(spec->am_entry, num_pins, sizeof(spec->am_entry[0]), 3601352f7f91STakashi Iwai compare_attr, NULL); 3602352f7f91STakashi Iwai 3603352f7f91STakashi Iwai if (!auto_mic_check_imux(codec)) 3604352f7f91STakashi Iwai return 0; 3605352f7f91STakashi Iwai 3606352f7f91STakashi Iwai spec->auto_mic = 1; 3607352f7f91STakashi Iwai spec->num_adc_nids = 1; 3608352f7f91STakashi Iwai spec->cur_mux[0] = spec->am_entry[0].idx; 3609352f7f91STakashi Iwai snd_printdd("hda-codec: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", 3610352f7f91STakashi Iwai spec->am_entry[0].pin, 3611352f7f91STakashi Iwai spec->am_entry[1].pin, 3612352f7f91STakashi Iwai spec->am_entry[2].pin); 3613352f7f91STakashi Iwai 3614352f7f91STakashi Iwai return 0; 3615352f7f91STakashi Iwai } 3616352f7f91STakashi Iwai 3617352f7f91STakashi Iwai 36189eb413e5STakashi Iwai /* 36199eb413e5STakashi Iwai * Parse the given BIOS configuration and set up the hda_gen_spec 36209eb413e5STakashi Iwai * 36219eb413e5STakashi Iwai * return 1 if successful, 0 if the proper config is not found, 3622352f7f91STakashi Iwai * or a negative error code 3623352f7f91STakashi Iwai */ 3624352f7f91STakashi Iwai int snd_hda_gen_parse_auto_config(struct hda_codec *codec, 36259eb413e5STakashi Iwai struct auto_pin_cfg *cfg) 3626352f7f91STakashi Iwai { 3627352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3628352f7f91STakashi Iwai int err; 3629352f7f91STakashi Iwai 36301c70a583STakashi Iwai parse_user_hints(codec); 36311c70a583STakashi Iwai 36329eb413e5STakashi Iwai if (cfg != &spec->autocfg) { 36339eb413e5STakashi Iwai spec->autocfg = *cfg; 36349eb413e5STakashi Iwai cfg = &spec->autocfg; 36359eb413e5STakashi Iwai } 36369eb413e5STakashi Iwai 36376fc4cb97SDavid Henningsson fill_all_dac_nids(codec); 36386fc4cb97SDavid Henningsson 3639352f7f91STakashi Iwai if (!cfg->line_outs) { 3640352f7f91STakashi Iwai if (cfg->dig_outs || cfg->dig_in_pin) { 3641352f7f91STakashi Iwai spec->multiout.max_channels = 2; 3642352f7f91STakashi Iwai spec->no_analog = 1; 3643352f7f91STakashi Iwai goto dig_only; 3644352f7f91STakashi Iwai } 3645352f7f91STakashi Iwai return 0; /* can't find valid BIOS pin config */ 3646352f7f91STakashi Iwai } 3647352f7f91STakashi Iwai 3648352f7f91STakashi Iwai if (!spec->no_primary_hp && 3649352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && 3650352f7f91STakashi Iwai cfg->line_outs <= cfg->hp_outs) { 3651352f7f91STakashi Iwai /* use HP as primary out */ 3652352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 3653352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 3654352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 3655352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs; 3656352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); 3657352f7f91STakashi Iwai cfg->hp_outs = 0; 3658352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 3659352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT; 3660352f7f91STakashi Iwai } 3661352f7f91STakashi Iwai 3662352f7f91STakashi Iwai err = parse_output_paths(codec); 3663352f7f91STakashi Iwai if (err < 0) 3664352f7f91STakashi Iwai return err; 3665352f7f91STakashi Iwai err = create_multi_channel_mode(codec); 3666352f7f91STakashi Iwai if (err < 0) 3667352f7f91STakashi Iwai return err; 3668352f7f91STakashi Iwai err = create_multi_out_ctls(codec, cfg); 3669352f7f91STakashi Iwai if (err < 0) 3670352f7f91STakashi Iwai return err; 3671352f7f91STakashi Iwai err = create_hp_out_ctls(codec); 3672352f7f91STakashi Iwai if (err < 0) 3673352f7f91STakashi Iwai return err; 3674352f7f91STakashi Iwai err = create_speaker_out_ctls(codec); 3675352f7f91STakashi Iwai if (err < 0) 3676352f7f91STakashi Iwai return err; 367738cf6f1aSTakashi Iwai err = create_indep_hp_ctls(codec); 367838cf6f1aSTakashi Iwai if (err < 0) 367938cf6f1aSTakashi Iwai return err; 3680c30aa7b2STakashi Iwai err = create_loopback_mixing_ctl(codec); 3681c30aa7b2STakashi Iwai if (err < 0) 3682c30aa7b2STakashi Iwai return err; 3683352f7f91STakashi Iwai err = create_shared_input(codec); 3684352f7f91STakashi Iwai if (err < 0) 3685352f7f91STakashi Iwai return err; 3686352f7f91STakashi Iwai err = create_input_ctls(codec); 3687352f7f91STakashi Iwai if (err < 0) 3688352f7f91STakashi Iwai return err; 3689352f7f91STakashi Iwai 3690a07a949bSTakashi Iwai spec->const_channel_count = spec->ext_channel_count; 3691a07a949bSTakashi Iwai /* check the multiple speaker and headphone pins */ 3692a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 3693a07a949bSTakashi Iwai spec->const_channel_count = max(spec->const_channel_count, 3694a07a949bSTakashi Iwai cfg->speaker_outs * 2); 3695a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 3696a07a949bSTakashi Iwai spec->const_channel_count = max(spec->const_channel_count, 3697a07a949bSTakashi Iwai cfg->hp_outs * 2); 3698352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count, 3699352f7f91STakashi Iwai spec->const_channel_count); 3700352f7f91STakashi Iwai 3701352f7f91STakashi Iwai err = check_auto_mute_availability(codec); 3702352f7f91STakashi Iwai if (err < 0) 3703352f7f91STakashi Iwai return err; 3704352f7f91STakashi Iwai 3705352f7f91STakashi Iwai err = check_dyn_adc_switch(codec); 3706352f7f91STakashi Iwai if (err < 0) 3707352f7f91STakashi Iwai return err; 3708352f7f91STakashi Iwai 3709352f7f91STakashi Iwai if (!spec->shared_mic_hp) { 3710352f7f91STakashi Iwai err = check_auto_mic_availability(codec); 3711352f7f91STakashi Iwai if (err < 0) 3712352f7f91STakashi Iwai return err; 3713352f7f91STakashi Iwai } 3714352f7f91STakashi Iwai 3715352f7f91STakashi Iwai err = create_capture_mixers(codec); 3716352f7f91STakashi Iwai if (err < 0) 3717352f7f91STakashi Iwai return err; 3718352f7f91STakashi Iwai 3719352f7f91STakashi Iwai err = parse_mic_boost(codec); 3720352f7f91STakashi Iwai if (err < 0) 3721352f7f91STakashi Iwai return err; 3722352f7f91STakashi Iwai 3723978e77e7STakashi Iwai if (spec->add_out_jack_modes) { 3724978e77e7STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 3725978e77e7STakashi Iwai err = create_out_jack_modes(codec, cfg->line_outs, 3726978e77e7STakashi Iwai cfg->line_out_pins); 3727978e77e7STakashi Iwai if (err < 0) 3728978e77e7STakashi Iwai return err; 3729978e77e7STakashi Iwai } 3730978e77e7STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) { 3731978e77e7STakashi Iwai err = create_out_jack_modes(codec, cfg->hp_outs, 3732978e77e7STakashi Iwai cfg->hp_pins); 3733978e77e7STakashi Iwai if (err < 0) 3734978e77e7STakashi Iwai return err; 3735978e77e7STakashi Iwai } 3736978e77e7STakashi Iwai } 3737978e77e7STakashi Iwai 3738352f7f91STakashi Iwai dig_only: 3739352f7f91STakashi Iwai parse_digital(codec); 3740352f7f91STakashi Iwai 3741352f7f91STakashi Iwai return 1; 3742352f7f91STakashi Iwai } 3743352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_parse_auto_config); 3744352f7f91STakashi Iwai 3745352f7f91STakashi Iwai 3746352f7f91STakashi Iwai /* 3747352f7f91STakashi Iwai * Build control elements 3748352f7f91STakashi Iwai */ 3749352f7f91STakashi Iwai 3750352f7f91STakashi Iwai /* slave controls for virtual master */ 3751352f7f91STakashi Iwai static const char * const slave_pfxs[] = { 3752352f7f91STakashi Iwai "Front", "Surround", "Center", "LFE", "Side", 3753352f7f91STakashi Iwai "Headphone", "Speaker", "Mono", "Line Out", 3754352f7f91STakashi Iwai "CLFE", "Bass Speaker", "PCM", 3755ee79c69aSTakashi Iwai "Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side", 3756ee79c69aSTakashi Iwai "Headphone Front", "Headphone Surround", "Headphone CLFE", 3757ee79c69aSTakashi Iwai "Headphone Side", 3758352f7f91STakashi Iwai NULL, 3759352f7f91STakashi Iwai }; 3760352f7f91STakashi Iwai 3761352f7f91STakashi Iwai int snd_hda_gen_build_controls(struct hda_codec *codec) 3762352f7f91STakashi Iwai { 3763352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3764352f7f91STakashi Iwai int err; 3765352f7f91STakashi Iwai 376636502d02STakashi Iwai if (spec->kctls.used) { 3767352f7f91STakashi Iwai err = snd_hda_add_new_ctls(codec, spec->kctls.list); 3768352f7f91STakashi Iwai if (err < 0) 3769352f7f91STakashi Iwai return err; 377036502d02STakashi Iwai } 3771352f7f91STakashi Iwai 3772352f7f91STakashi Iwai if (spec->multiout.dig_out_nid) { 3773352f7f91STakashi Iwai err = snd_hda_create_dig_out_ctls(codec, 3774352f7f91STakashi Iwai spec->multiout.dig_out_nid, 3775352f7f91STakashi Iwai spec->multiout.dig_out_nid, 3776352f7f91STakashi Iwai spec->pcm_rec[1].pcm_type); 3777352f7f91STakashi Iwai if (err < 0) 3778352f7f91STakashi Iwai return err; 3779352f7f91STakashi Iwai if (!spec->no_analog) { 3780352f7f91STakashi Iwai err = snd_hda_create_spdif_share_sw(codec, 3781352f7f91STakashi Iwai &spec->multiout); 3782352f7f91STakashi Iwai if (err < 0) 3783352f7f91STakashi Iwai return err; 3784352f7f91STakashi Iwai spec->multiout.share_spdif = 1; 3785352f7f91STakashi Iwai } 3786352f7f91STakashi Iwai } 3787352f7f91STakashi Iwai if (spec->dig_in_nid) { 3788352f7f91STakashi Iwai err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 3789352f7f91STakashi Iwai if (err < 0) 3790352f7f91STakashi Iwai return err; 3791352f7f91STakashi Iwai } 3792352f7f91STakashi Iwai 3793352f7f91STakashi Iwai /* if we have no master control, let's create it */ 3794352f7f91STakashi Iwai if (!spec->no_analog && 3795352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { 3796352f7f91STakashi Iwai err = snd_hda_add_vmaster(codec, "Master Playback Volume", 37977a71bbf3STakashi Iwai spec->vmaster_tlv, slave_pfxs, 3798352f7f91STakashi Iwai "Playback Volume"); 3799352f7f91STakashi Iwai if (err < 0) 3800352f7f91STakashi Iwai return err; 3801352f7f91STakashi Iwai } 3802352f7f91STakashi Iwai if (!spec->no_analog && 3803352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { 3804352f7f91STakashi Iwai err = __snd_hda_add_vmaster(codec, "Master Playback Switch", 3805352f7f91STakashi Iwai NULL, slave_pfxs, 3806352f7f91STakashi Iwai "Playback Switch", 3807352f7f91STakashi Iwai true, &spec->vmaster_mute.sw_kctl); 3808352f7f91STakashi Iwai if (err < 0) 3809352f7f91STakashi Iwai return err; 3810352f7f91STakashi Iwai if (spec->vmaster_mute.hook) 3811fd25a97aSTakashi Iwai snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, 3812fd25a97aSTakashi Iwai spec->vmaster_mute_enum); 3813352f7f91STakashi Iwai } 3814352f7f91STakashi Iwai 3815352f7f91STakashi Iwai free_kctls(spec); /* no longer needed */ 3816352f7f91STakashi Iwai 3817352f7f91STakashi Iwai if (spec->shared_mic_hp) { 3818352f7f91STakashi Iwai int err; 3819352f7f91STakashi Iwai int nid = spec->autocfg.inputs[1].pin; 3820352f7f91STakashi Iwai err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0); 3821352f7f91STakashi Iwai if (err < 0) 3822352f7f91STakashi Iwai return err; 3823352f7f91STakashi Iwai err = snd_hda_jack_detect_enable(codec, nid, 0); 3824352f7f91STakashi Iwai if (err < 0) 3825352f7f91STakashi Iwai return err; 3826352f7f91STakashi Iwai } 3827352f7f91STakashi Iwai 3828352f7f91STakashi Iwai err = snd_hda_jack_add_kctls(codec, &spec->autocfg); 3829352f7f91STakashi Iwai if (err < 0) 3830352f7f91STakashi Iwai return err; 3831352f7f91STakashi Iwai 3832352f7f91STakashi Iwai return 0; 3833352f7f91STakashi Iwai } 3834352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_controls); 3835352f7f91STakashi Iwai 3836352f7f91STakashi Iwai 3837352f7f91STakashi Iwai /* 3838352f7f91STakashi Iwai * PCM definitions 3839352f7f91STakashi Iwai */ 3840352f7f91STakashi Iwai 3841e6b85f3cSTakashi Iwai static void call_pcm_playback_hook(struct hda_pcm_stream *hinfo, 3842e6b85f3cSTakashi Iwai struct hda_codec *codec, 3843e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream, 3844e6b85f3cSTakashi Iwai int action) 3845e6b85f3cSTakashi Iwai { 3846e6b85f3cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 3847e6b85f3cSTakashi Iwai if (spec->pcm_playback_hook) 3848e6b85f3cSTakashi Iwai spec->pcm_playback_hook(hinfo, codec, substream, action); 3849e6b85f3cSTakashi Iwai } 3850e6b85f3cSTakashi Iwai 3851ac2e8736STakashi Iwai static void call_pcm_capture_hook(struct hda_pcm_stream *hinfo, 3852ac2e8736STakashi Iwai struct hda_codec *codec, 3853ac2e8736STakashi Iwai struct snd_pcm_substream *substream, 3854ac2e8736STakashi Iwai int action) 3855ac2e8736STakashi Iwai { 3856ac2e8736STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3857ac2e8736STakashi Iwai if (spec->pcm_capture_hook) 3858ac2e8736STakashi Iwai spec->pcm_capture_hook(hinfo, codec, substream, action); 3859ac2e8736STakashi Iwai } 3860ac2e8736STakashi Iwai 3861352f7f91STakashi Iwai /* 3862352f7f91STakashi Iwai * Analog playback callbacks 3863352f7f91STakashi Iwai */ 3864352f7f91STakashi Iwai static int playback_pcm_open(struct hda_pcm_stream *hinfo, 3865352f7f91STakashi Iwai struct hda_codec *codec, 3866352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3867352f7f91STakashi Iwai { 3868352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 386938cf6f1aSTakashi Iwai int err; 387038cf6f1aSTakashi Iwai 387138cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 387238cf6f1aSTakashi Iwai err = snd_hda_multi_out_analog_open(codec, 387338cf6f1aSTakashi Iwai &spec->multiout, substream, 3874352f7f91STakashi Iwai hinfo); 3875e6b85f3cSTakashi Iwai if (!err) { 387638cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_MULTI_OUT; 3877e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3878e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_OPEN); 3879e6b85f3cSTakashi Iwai } 388038cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 388138cf6f1aSTakashi Iwai return err; 3882352f7f91STakashi Iwai } 3883352f7f91STakashi Iwai 3884352f7f91STakashi Iwai static int playback_pcm_prepare(struct hda_pcm_stream *hinfo, 388597ec558aSTakashi Iwai struct hda_codec *codec, 388697ec558aSTakashi Iwai unsigned int stream_tag, 388797ec558aSTakashi Iwai unsigned int format, 388897ec558aSTakashi Iwai struct snd_pcm_substream *substream) 388997ec558aSTakashi Iwai { 3890352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3891e6b85f3cSTakashi Iwai int err; 3892e6b85f3cSTakashi Iwai 3893e6b85f3cSTakashi Iwai err = snd_hda_multi_out_analog_prepare(codec, &spec->multiout, 3894352f7f91STakashi Iwai stream_tag, format, substream); 3895e6b85f3cSTakashi Iwai if (!err) 3896e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3897e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 3898e6b85f3cSTakashi Iwai return err; 3899352f7f91STakashi Iwai } 390097ec558aSTakashi Iwai 3901352f7f91STakashi Iwai static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 3902352f7f91STakashi Iwai struct hda_codec *codec, 3903352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3904352f7f91STakashi Iwai { 3905352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3906e6b85f3cSTakashi Iwai int err; 3907e6b85f3cSTakashi Iwai 3908e6b85f3cSTakashi Iwai err = snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); 3909e6b85f3cSTakashi Iwai if (!err) 3910e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3911e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 3912e6b85f3cSTakashi Iwai return err; 3913352f7f91STakashi Iwai } 3914352f7f91STakashi Iwai 391538cf6f1aSTakashi Iwai static int playback_pcm_close(struct hda_pcm_stream *hinfo, 391638cf6f1aSTakashi Iwai struct hda_codec *codec, 391738cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 391838cf6f1aSTakashi Iwai { 391938cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 392038cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 392138cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_MULTI_OUT); 3922e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3923e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLOSE); 392438cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 392538cf6f1aSTakashi Iwai return 0; 392638cf6f1aSTakashi Iwai } 392738cf6f1aSTakashi Iwai 3928ac2e8736STakashi Iwai static int capture_pcm_open(struct hda_pcm_stream *hinfo, 3929ac2e8736STakashi Iwai struct hda_codec *codec, 3930ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 3931ac2e8736STakashi Iwai { 3932ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_OPEN); 3933ac2e8736STakashi Iwai return 0; 3934ac2e8736STakashi Iwai } 3935ac2e8736STakashi Iwai 3936ac2e8736STakashi Iwai static int capture_pcm_prepare(struct hda_pcm_stream *hinfo, 3937ac2e8736STakashi Iwai struct hda_codec *codec, 3938ac2e8736STakashi Iwai unsigned int stream_tag, 3939ac2e8736STakashi Iwai unsigned int format, 3940ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 3941ac2e8736STakashi Iwai { 3942ac2e8736STakashi Iwai snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); 3943ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 3944ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 3945ac2e8736STakashi Iwai return 0; 3946ac2e8736STakashi Iwai } 3947ac2e8736STakashi Iwai 3948ac2e8736STakashi Iwai static int capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 3949ac2e8736STakashi Iwai struct hda_codec *codec, 3950ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 3951ac2e8736STakashi Iwai { 3952ac2e8736STakashi Iwai snd_hda_codec_cleanup_stream(codec, hinfo->nid); 3953ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 3954ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 3955ac2e8736STakashi Iwai return 0; 3956ac2e8736STakashi Iwai } 3957ac2e8736STakashi Iwai 3958ac2e8736STakashi Iwai static int capture_pcm_close(struct hda_pcm_stream *hinfo, 3959ac2e8736STakashi Iwai struct hda_codec *codec, 3960ac2e8736STakashi Iwai struct snd_pcm_substream *substream) 3961ac2e8736STakashi Iwai { 3962ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLOSE); 3963ac2e8736STakashi Iwai return 0; 3964ac2e8736STakashi Iwai } 3965ac2e8736STakashi Iwai 396638cf6f1aSTakashi Iwai static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo, 396738cf6f1aSTakashi Iwai struct hda_codec *codec, 396838cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 396938cf6f1aSTakashi Iwai { 397038cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 397138cf6f1aSTakashi Iwai int err = 0; 397238cf6f1aSTakashi Iwai 397338cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 397438cf6f1aSTakashi Iwai if (!spec->indep_hp_enabled) 397538cf6f1aSTakashi Iwai err = -EBUSY; 397638cf6f1aSTakashi Iwai else 397738cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_INDEP_HP; 3978e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3979e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_OPEN); 398038cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 398138cf6f1aSTakashi Iwai return err; 398238cf6f1aSTakashi Iwai } 398338cf6f1aSTakashi Iwai 398438cf6f1aSTakashi Iwai static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo, 398538cf6f1aSTakashi Iwai struct hda_codec *codec, 398638cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 398738cf6f1aSTakashi Iwai { 398838cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 398938cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 399038cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_INDEP_HP); 3991e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3992e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLOSE); 399338cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 399438cf6f1aSTakashi Iwai return 0; 399538cf6f1aSTakashi Iwai } 399638cf6f1aSTakashi Iwai 3997e6b85f3cSTakashi Iwai static int alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 3998e6b85f3cSTakashi Iwai struct hda_codec *codec, 3999e6b85f3cSTakashi Iwai unsigned int stream_tag, 4000e6b85f3cSTakashi Iwai unsigned int format, 4001e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream) 4002e6b85f3cSTakashi Iwai { 4003e6b85f3cSTakashi Iwai snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); 4004e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 4005e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 4006e6b85f3cSTakashi Iwai return 0; 4007e6b85f3cSTakashi Iwai } 4008e6b85f3cSTakashi Iwai 4009e6b85f3cSTakashi Iwai static int alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 4010e6b85f3cSTakashi Iwai struct hda_codec *codec, 4011e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream) 4012e6b85f3cSTakashi Iwai { 4013e6b85f3cSTakashi Iwai snd_hda_codec_cleanup_stream(codec, hinfo->nid); 4014e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 4015e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 4016e6b85f3cSTakashi Iwai return 0; 4017e6b85f3cSTakashi Iwai } 4018e6b85f3cSTakashi Iwai 4019352f7f91STakashi Iwai /* 4020352f7f91STakashi Iwai * Digital out 4021352f7f91STakashi Iwai */ 4022352f7f91STakashi Iwai static int dig_playback_pcm_open(struct hda_pcm_stream *hinfo, 4023352f7f91STakashi Iwai struct hda_codec *codec, 4024352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4025352f7f91STakashi Iwai { 4026352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4027352f7f91STakashi Iwai return snd_hda_multi_out_dig_open(codec, &spec->multiout); 4028352f7f91STakashi Iwai } 4029352f7f91STakashi Iwai 4030352f7f91STakashi Iwai static int dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 4031352f7f91STakashi Iwai struct hda_codec *codec, 4032352f7f91STakashi Iwai unsigned int stream_tag, 4033352f7f91STakashi Iwai unsigned int format, 4034352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4035352f7f91STakashi Iwai { 4036352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4037352f7f91STakashi Iwai return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, 4038352f7f91STakashi Iwai stream_tag, format, substream); 4039352f7f91STakashi Iwai } 4040352f7f91STakashi Iwai 4041352f7f91STakashi Iwai static int dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 4042352f7f91STakashi Iwai struct hda_codec *codec, 4043352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4044352f7f91STakashi Iwai { 4045352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4046352f7f91STakashi Iwai return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); 4047352f7f91STakashi Iwai } 4048352f7f91STakashi Iwai 4049352f7f91STakashi Iwai static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo, 4050352f7f91STakashi Iwai struct hda_codec *codec, 4051352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4052352f7f91STakashi Iwai { 4053352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4054352f7f91STakashi Iwai return snd_hda_multi_out_dig_close(codec, &spec->multiout); 4055352f7f91STakashi Iwai } 4056352f7f91STakashi Iwai 4057352f7f91STakashi Iwai /* 4058352f7f91STakashi Iwai * Analog capture 4059352f7f91STakashi Iwai */ 4060ac2e8736STakashi Iwai #define alt_capture_pcm_open capture_pcm_open 4061ac2e8736STakashi Iwai #define alt_capture_pcm_close capture_pcm_close 4062ac2e8736STakashi Iwai 4063352f7f91STakashi Iwai static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 4064352f7f91STakashi Iwai struct hda_codec *codec, 4065352f7f91STakashi Iwai unsigned int stream_tag, 4066352f7f91STakashi Iwai unsigned int format, 4067352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4068352f7f91STakashi Iwai { 4069352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4070352f7f91STakashi Iwai 4071352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], 407297ec558aSTakashi Iwai stream_tag, 0, format); 4073ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 4074ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 407597ec558aSTakashi Iwai return 0; 407697ec558aSTakashi Iwai } 407797ec558aSTakashi Iwai 4078352f7f91STakashi Iwai static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 407997ec558aSTakashi Iwai struct hda_codec *codec, 408097ec558aSTakashi Iwai struct snd_pcm_substream *substream) 408197ec558aSTakashi Iwai { 4082352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 408397ec558aSTakashi Iwai 4084352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, 4085352f7f91STakashi Iwai spec->adc_nids[substream->number + 1]); 4086ac2e8736STakashi Iwai call_pcm_capture_hook(hinfo, codec, substream, 4087ac2e8736STakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 408897ec558aSTakashi Iwai return 0; 408997ec558aSTakashi Iwai } 409097ec558aSTakashi Iwai 4091352f7f91STakashi Iwai /* 4092352f7f91STakashi Iwai */ 4093352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_playback = { 4094352f7f91STakashi Iwai .substreams = 1, 4095352f7f91STakashi Iwai .channels_min = 2, 4096352f7f91STakashi Iwai .channels_max = 8, 4097352f7f91STakashi Iwai /* NID is set in build_pcms */ 4098352f7f91STakashi Iwai .ops = { 4099352f7f91STakashi Iwai .open = playback_pcm_open, 410038cf6f1aSTakashi Iwai .close = playback_pcm_close, 4101352f7f91STakashi Iwai .prepare = playback_pcm_prepare, 4102352f7f91STakashi Iwai .cleanup = playback_pcm_cleanup 4103352f7f91STakashi Iwai }, 4104352f7f91STakashi Iwai }; 4105352f7f91STakashi Iwai 4106352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_capture = { 4107352f7f91STakashi Iwai .substreams = 1, 4108352f7f91STakashi Iwai .channels_min = 2, 4109352f7f91STakashi Iwai .channels_max = 2, 4110352f7f91STakashi Iwai /* NID is set in build_pcms */ 4111ac2e8736STakashi Iwai .ops = { 4112ac2e8736STakashi Iwai .open = capture_pcm_open, 4113ac2e8736STakashi Iwai .close = capture_pcm_close, 4114ac2e8736STakashi Iwai .prepare = capture_pcm_prepare, 4115ac2e8736STakashi Iwai .cleanup = capture_pcm_cleanup 4116ac2e8736STakashi Iwai }, 4117352f7f91STakashi Iwai }; 4118352f7f91STakashi Iwai 4119352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_playback = { 4120352f7f91STakashi Iwai .substreams = 1, 4121352f7f91STakashi Iwai .channels_min = 2, 4122352f7f91STakashi Iwai .channels_max = 2, 4123352f7f91STakashi Iwai /* NID is set in build_pcms */ 412438cf6f1aSTakashi Iwai .ops = { 412538cf6f1aSTakashi Iwai .open = alt_playback_pcm_open, 4126e6b85f3cSTakashi Iwai .close = alt_playback_pcm_close, 4127e6b85f3cSTakashi Iwai .prepare = alt_playback_pcm_prepare, 4128e6b85f3cSTakashi Iwai .cleanup = alt_playback_pcm_cleanup 412938cf6f1aSTakashi Iwai }, 4130352f7f91STakashi Iwai }; 4131352f7f91STakashi Iwai 4132352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_capture = { 4133352f7f91STakashi Iwai .substreams = 2, /* can be overridden */ 4134352f7f91STakashi Iwai .channels_min = 2, 4135352f7f91STakashi Iwai .channels_max = 2, 4136352f7f91STakashi Iwai /* NID is set in build_pcms */ 4137352f7f91STakashi Iwai .ops = { 4138ac2e8736STakashi Iwai .open = alt_capture_pcm_open, 4139ac2e8736STakashi Iwai .close = alt_capture_pcm_close, 4140352f7f91STakashi Iwai .prepare = alt_capture_pcm_prepare, 4141352f7f91STakashi Iwai .cleanup = alt_capture_pcm_cleanup 4142352f7f91STakashi Iwai }, 4143352f7f91STakashi Iwai }; 4144352f7f91STakashi Iwai 4145352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_playback = { 4146352f7f91STakashi Iwai .substreams = 1, 4147352f7f91STakashi Iwai .channels_min = 2, 4148352f7f91STakashi Iwai .channels_max = 2, 4149352f7f91STakashi Iwai /* NID is set in build_pcms */ 4150352f7f91STakashi Iwai .ops = { 4151352f7f91STakashi Iwai .open = dig_playback_pcm_open, 4152352f7f91STakashi Iwai .close = dig_playback_pcm_close, 4153352f7f91STakashi Iwai .prepare = dig_playback_pcm_prepare, 4154352f7f91STakashi Iwai .cleanup = dig_playback_pcm_cleanup 4155352f7f91STakashi Iwai }, 4156352f7f91STakashi Iwai }; 4157352f7f91STakashi Iwai 4158352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_capture = { 4159352f7f91STakashi Iwai .substreams = 1, 4160352f7f91STakashi Iwai .channels_min = 2, 4161352f7f91STakashi Iwai .channels_max = 2, 4162352f7f91STakashi Iwai /* NID is set in build_pcms */ 4163352f7f91STakashi Iwai }; 4164352f7f91STakashi Iwai 4165352f7f91STakashi Iwai /* Used by build_pcms to flag that a PCM has no playback stream */ 4166352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_null_stream = { 4167352f7f91STakashi Iwai .substreams = 0, 4168352f7f91STakashi Iwai .channels_min = 0, 4169352f7f91STakashi Iwai .channels_max = 0, 4170352f7f91STakashi Iwai }; 4171352f7f91STakashi Iwai 4172352f7f91STakashi Iwai /* 4173352f7f91STakashi Iwai * dynamic changing ADC PCM streams 4174352f7f91STakashi Iwai */ 4175352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) 41761da177e4SLinus Torvalds { 4177352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4178352f7f91STakashi Iwai hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]]; 41791da177e4SLinus Torvalds 4180352f7f91STakashi Iwai if (spec->cur_adc && spec->cur_adc != new_adc) { 4181352f7f91STakashi Iwai /* stream is running, let's swap the current ADC */ 4182352f7f91STakashi Iwai __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); 4183352f7f91STakashi Iwai spec->cur_adc = new_adc; 4184352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, new_adc, 4185352f7f91STakashi Iwai spec->cur_adc_stream_tag, 0, 4186352f7f91STakashi Iwai spec->cur_adc_format); 4187352f7f91STakashi Iwai return true; 4188352f7f91STakashi Iwai } 4189352f7f91STakashi Iwai return false; 4190352f7f91STakashi Iwai } 4191352f7f91STakashi Iwai 4192352f7f91STakashi Iwai /* analog capture with dynamic dual-adc changes */ 4193352f7f91STakashi Iwai static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 4194352f7f91STakashi Iwai struct hda_codec *codec, 4195352f7f91STakashi Iwai unsigned int stream_tag, 4196352f7f91STakashi Iwai unsigned int format, 4197352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4198352f7f91STakashi Iwai { 4199352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4200352f7f91STakashi Iwai spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]]; 4201352f7f91STakashi Iwai spec->cur_adc_stream_tag = stream_tag; 4202352f7f91STakashi Iwai spec->cur_adc_format = format; 4203352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); 42041da177e4SLinus Torvalds return 0; 42051da177e4SLinus Torvalds } 42061da177e4SLinus Torvalds 4207352f7f91STakashi Iwai static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 4208352f7f91STakashi Iwai struct hda_codec *codec, 4209352f7f91STakashi Iwai struct snd_pcm_substream *substream) 4210352f7f91STakashi Iwai { 4211352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4212352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, spec->cur_adc); 4213352f7f91STakashi Iwai spec->cur_adc = 0; 4214352f7f91STakashi Iwai return 0; 4215352f7f91STakashi Iwai } 4216352f7f91STakashi Iwai 4217352f7f91STakashi Iwai static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = { 4218352f7f91STakashi Iwai .substreams = 1, 4219352f7f91STakashi Iwai .channels_min = 2, 4220352f7f91STakashi Iwai .channels_max = 2, 4221352f7f91STakashi Iwai .nid = 0, /* fill later */ 4222352f7f91STakashi Iwai .ops = { 4223352f7f91STakashi Iwai .prepare = dyn_adc_capture_pcm_prepare, 4224352f7f91STakashi Iwai .cleanup = dyn_adc_capture_pcm_cleanup 4225352f7f91STakashi Iwai }, 4226352f7f91STakashi Iwai }; 4227352f7f91STakashi Iwai 4228f873e536STakashi Iwai static void fill_pcm_stream_name(char *str, size_t len, const char *sfx, 4229f873e536STakashi Iwai const char *chip_name) 4230f873e536STakashi Iwai { 4231f873e536STakashi Iwai char *p; 4232f873e536STakashi Iwai 4233f873e536STakashi Iwai if (*str) 4234f873e536STakashi Iwai return; 4235f873e536STakashi Iwai strlcpy(str, chip_name, len); 4236f873e536STakashi Iwai 4237f873e536STakashi Iwai /* drop non-alnum chars after a space */ 4238f873e536STakashi Iwai for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) { 4239f873e536STakashi Iwai if (!isalnum(p[1])) { 4240f873e536STakashi Iwai *p = 0; 4241f873e536STakashi Iwai break; 4242f873e536STakashi Iwai } 4243f873e536STakashi Iwai } 4244f873e536STakashi Iwai strlcat(str, sfx, len); 4245f873e536STakashi Iwai } 4246f873e536STakashi Iwai 4247352f7f91STakashi Iwai /* build PCM streams based on the parsed results */ 4248352f7f91STakashi Iwai int snd_hda_gen_build_pcms(struct hda_codec *codec) 4249352f7f91STakashi Iwai { 4250352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4251352f7f91STakashi Iwai struct hda_pcm *info = spec->pcm_rec; 4252352f7f91STakashi Iwai const struct hda_pcm_stream *p; 4253352f7f91STakashi Iwai bool have_multi_adcs; 4254352f7f91STakashi Iwai 42551da177e4SLinus Torvalds codec->num_pcms = 1; 42561da177e4SLinus Torvalds codec->pcm_info = info; 42571da177e4SLinus Torvalds 4258352f7f91STakashi Iwai if (spec->no_analog) 4259352f7f91STakashi Iwai goto skip_analog; 4260352f7f91STakashi Iwai 4261f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_analog, 4262f873e536STakashi Iwai sizeof(spec->stream_name_analog), 4263f873e536STakashi Iwai " Analog", codec->chip_name); 4264352f7f91STakashi Iwai info->name = spec->stream_name_analog; 4265352f7f91STakashi Iwai 4266352f7f91STakashi Iwai if (spec->multiout.num_dacs > 0) { 4267352f7f91STakashi Iwai p = spec->stream_analog_playback; 4268352f7f91STakashi Iwai if (!p) 4269352f7f91STakashi Iwai p = &pcm_analog_playback; 4270352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 4271352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; 4272352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 4273352f7f91STakashi Iwai spec->multiout.max_channels; 4274352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT && 4275352f7f91STakashi Iwai spec->autocfg.line_outs == 2) 4276352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap = 4277352f7f91STakashi Iwai snd_pcm_2_1_chmaps; 4278352f7f91STakashi Iwai } 4279352f7f91STakashi Iwai if (spec->num_adc_nids) { 4280352f7f91STakashi Iwai p = spec->stream_analog_capture; 4281352f7f91STakashi Iwai if (!p) { 4282352f7f91STakashi Iwai if (spec->dyn_adc_switch) 4283352f7f91STakashi Iwai p = &dyn_adc_pcm_analog_capture; 4284352f7f91STakashi Iwai else 4285352f7f91STakashi Iwai p = &pcm_analog_capture; 4286352f7f91STakashi Iwai } 4287352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 4288352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; 4289352f7f91STakashi Iwai } 4290352f7f91STakashi Iwai 4291352f7f91STakashi Iwai skip_analog: 4292352f7f91STakashi Iwai /* SPDIF for stream index #1 */ 4293352f7f91STakashi Iwai if (spec->multiout.dig_out_nid || spec->dig_in_nid) { 4294f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_digital, 4295352f7f91STakashi Iwai sizeof(spec->stream_name_digital), 4296f873e536STakashi Iwai " Digital", codec->chip_name); 4297352f7f91STakashi Iwai codec->num_pcms = 2; 4298352f7f91STakashi Iwai codec->slave_dig_outs = spec->multiout.slave_dig_outs; 4299352f7f91STakashi Iwai info = spec->pcm_rec + 1; 4300352f7f91STakashi Iwai info->name = spec->stream_name_digital; 4301352f7f91STakashi Iwai if (spec->dig_out_type) 4302352f7f91STakashi Iwai info->pcm_type = spec->dig_out_type; 4303352f7f91STakashi Iwai else 4304352f7f91STakashi Iwai info->pcm_type = HDA_PCM_TYPE_SPDIF; 4305352f7f91STakashi Iwai if (spec->multiout.dig_out_nid) { 4306352f7f91STakashi Iwai p = spec->stream_digital_playback; 4307352f7f91STakashi Iwai if (!p) 4308352f7f91STakashi Iwai p = &pcm_digital_playback; 4309352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 4310352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; 4311352f7f91STakashi Iwai } 4312352f7f91STakashi Iwai if (spec->dig_in_nid) { 4313352f7f91STakashi Iwai p = spec->stream_digital_capture; 4314352f7f91STakashi Iwai if (!p) 4315352f7f91STakashi Iwai p = &pcm_digital_capture; 4316352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 4317352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; 4318352f7f91STakashi Iwai } 4319352f7f91STakashi Iwai } 4320352f7f91STakashi Iwai 4321352f7f91STakashi Iwai if (spec->no_analog) 4322352f7f91STakashi Iwai return 0; 4323352f7f91STakashi Iwai 4324352f7f91STakashi Iwai /* If the use of more than one ADC is requested for the current 4325352f7f91STakashi Iwai * model, configure a second analog capture-only PCM. 4326352f7f91STakashi Iwai */ 4327352f7f91STakashi Iwai have_multi_adcs = (spec->num_adc_nids > 1) && 4328352f7f91STakashi Iwai !spec->dyn_adc_switch && !spec->auto_mic; 4329352f7f91STakashi Iwai /* Additional Analaog capture for index #2 */ 4330352f7f91STakashi Iwai if (spec->alt_dac_nid || have_multi_adcs) { 4331352f7f91STakashi Iwai codec->num_pcms = 3; 4332352f7f91STakashi Iwai info = spec->pcm_rec + 2; 4333352f7f91STakashi Iwai info->name = spec->stream_name_analog; 4334352f7f91STakashi Iwai if (spec->alt_dac_nid) { 4335352f7f91STakashi Iwai p = spec->stream_analog_alt_playback; 4336352f7f91STakashi Iwai if (!p) 4337352f7f91STakashi Iwai p = &pcm_analog_alt_playback; 4338352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 4339352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 4340352f7f91STakashi Iwai spec->alt_dac_nid; 4341352f7f91STakashi Iwai } else { 4342352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = 4343352f7f91STakashi Iwai pcm_null_stream; 4344352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; 4345352f7f91STakashi Iwai } 4346352f7f91STakashi Iwai if (have_multi_adcs) { 4347352f7f91STakashi Iwai p = spec->stream_analog_alt_capture; 4348352f7f91STakashi Iwai if (!p) 4349352f7f91STakashi Iwai p = &pcm_analog_alt_capture; 4350352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 4351352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 4352352f7f91STakashi Iwai spec->adc_nids[1]; 4353352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 4354352f7f91STakashi Iwai spec->num_adc_nids - 1; 4355352f7f91STakashi Iwai } else { 4356352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = 4357352f7f91STakashi Iwai pcm_null_stream; 4358352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0; 4359352f7f91STakashi Iwai } 43601da177e4SLinus Torvalds } 43611da177e4SLinus Torvalds 43621da177e4SLinus Torvalds return 0; 43631da177e4SLinus Torvalds } 4364352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_pcms); 4365352f7f91STakashi Iwai 4366352f7f91STakashi Iwai 4367352f7f91STakashi Iwai /* 4368352f7f91STakashi Iwai * Standard auto-parser initializations 4369352f7f91STakashi Iwai */ 4370352f7f91STakashi Iwai 4371d4156930STakashi Iwai /* configure the given path as a proper output */ 43722c12c30dSTakashi Iwai static void set_output_and_unmute(struct hda_codec *codec, int path_idx) 4373352f7f91STakashi Iwai { 4374352f7f91STakashi Iwai struct nid_path *path; 4375d4156930STakashi Iwai hda_nid_t pin; 4376352f7f91STakashi Iwai 4377196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 4378d4156930STakashi Iwai if (!path || !path->depth) 4379352f7f91STakashi Iwai return; 4380d4156930STakashi Iwai pin = path->path[path->depth - 1]; 43812c12c30dSTakashi Iwai restore_pin_ctl(codec, pin); 4382e1284af7STakashi Iwai snd_hda_activate_path(codec, path, path->active, true); 4383e1284af7STakashi Iwai set_pin_eapd(codec, pin, path->active); 4384352f7f91STakashi Iwai } 4385352f7f91STakashi Iwai 4386352f7f91STakashi Iwai /* initialize primary output paths */ 4387352f7f91STakashi Iwai static void init_multi_out(struct hda_codec *codec) 4388352f7f91STakashi Iwai { 4389352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4390352f7f91STakashi Iwai int i; 4391352f7f91STakashi Iwai 4392d4156930STakashi Iwai for (i = 0; i < spec->autocfg.line_outs; i++) 43932c12c30dSTakashi Iwai set_output_and_unmute(codec, spec->out_paths[i]); 4394352f7f91STakashi Iwai } 4395352f7f91STakashi Iwai 4396db23fd19STakashi Iwai 43972c12c30dSTakashi Iwai static void __init_extra_out(struct hda_codec *codec, int num_outs, int *paths) 4398352f7f91STakashi Iwai { 4399352f7f91STakashi Iwai int i; 4400352f7f91STakashi Iwai 4401d4156930STakashi Iwai for (i = 0; i < num_outs; i++) 44022c12c30dSTakashi Iwai set_output_and_unmute(codec, paths[i]); 4403352f7f91STakashi Iwai } 4404db23fd19STakashi Iwai 4405db23fd19STakashi Iwai /* initialize hp and speaker paths */ 4406db23fd19STakashi Iwai static void init_extra_out(struct hda_codec *codec) 4407db23fd19STakashi Iwai { 4408db23fd19STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4409db23fd19STakashi Iwai 4410db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) 44112c12c30dSTakashi Iwai __init_extra_out(codec, spec->autocfg.hp_outs, spec->hp_paths); 4412db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) 4413db23fd19STakashi Iwai __init_extra_out(codec, spec->autocfg.speaker_outs, 44142c12c30dSTakashi Iwai spec->speaker_paths); 4415352f7f91STakashi Iwai } 4416352f7f91STakashi Iwai 4417352f7f91STakashi Iwai /* initialize multi-io paths */ 4418352f7f91STakashi Iwai static void init_multi_io(struct hda_codec *codec) 4419352f7f91STakashi Iwai { 4420352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4421352f7f91STakashi Iwai int i; 4422352f7f91STakashi Iwai 4423352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++) { 4424352f7f91STakashi Iwai hda_nid_t pin = spec->multi_io[i].pin; 4425352f7f91STakashi Iwai struct nid_path *path; 4426196c1766STakashi Iwai path = get_multiio_path(codec, i); 4427352f7f91STakashi Iwai if (!path) 4428352f7f91STakashi Iwai continue; 4429352f7f91STakashi Iwai if (!spec->multi_io[i].ctl_in) 4430352f7f91STakashi Iwai spec->multi_io[i].ctl_in = 44312c12c30dSTakashi Iwai snd_hda_codec_get_pin_target(codec, pin); 4432352f7f91STakashi Iwai snd_hda_activate_path(codec, path, path->active, true); 4433352f7f91STakashi Iwai } 4434352f7f91STakashi Iwai } 4435352f7f91STakashi Iwai 4436352f7f91STakashi Iwai /* set up input pins and loopback paths */ 4437352f7f91STakashi Iwai static void init_analog_input(struct hda_codec *codec) 4438352f7f91STakashi Iwai { 4439352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4440352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 4441352f7f91STakashi Iwai int i; 4442352f7f91STakashi Iwai 4443352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 4444352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 4445352f7f91STakashi Iwai if (is_input_pin(codec, nid)) 44462c12c30dSTakashi Iwai restore_pin_ctl(codec, nid); 4447352f7f91STakashi Iwai 4448352f7f91STakashi Iwai /* init loopback inputs */ 4449352f7f91STakashi Iwai if (spec->mixer_nid) { 4450352f7f91STakashi Iwai struct nid_path *path; 4451196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->loopback_paths[i]); 4452352f7f91STakashi Iwai if (path) 4453352f7f91STakashi Iwai snd_hda_activate_path(codec, path, 4454352f7f91STakashi Iwai path->active, false); 4455352f7f91STakashi Iwai } 4456352f7f91STakashi Iwai } 4457352f7f91STakashi Iwai } 4458352f7f91STakashi Iwai 4459352f7f91STakashi Iwai /* initialize ADC paths */ 4460352f7f91STakashi Iwai static void init_input_src(struct hda_codec *codec) 4461352f7f91STakashi Iwai { 4462352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4463352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 4464352f7f91STakashi Iwai struct nid_path *path; 4465352f7f91STakashi Iwai int i, c, nums; 4466352f7f91STakashi Iwai 4467352f7f91STakashi Iwai if (spec->dyn_adc_switch) 4468352f7f91STakashi Iwai nums = 1; 4469352f7f91STakashi Iwai else 4470352f7f91STakashi Iwai nums = spec->num_adc_nids; 4471352f7f91STakashi Iwai 4472352f7f91STakashi Iwai for (c = 0; c < nums; c++) { 4473352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 4474c697b716STakashi Iwai path = get_input_path(codec, c, i); 4475352f7f91STakashi Iwai if (path) { 4476352f7f91STakashi Iwai bool active = path->active; 4477352f7f91STakashi Iwai if (i == spec->cur_mux[c]) 4478352f7f91STakashi Iwai active = true; 4479352f7f91STakashi Iwai snd_hda_activate_path(codec, path, active, false); 4480352f7f91STakashi Iwai } 4481352f7f91STakashi Iwai } 4482352f7f91STakashi Iwai } 4483352f7f91STakashi Iwai 4484352f7f91STakashi Iwai if (spec->shared_mic_hp) 4485352f7f91STakashi Iwai update_shared_mic_hp(codec, spec->cur_mux[0]); 4486352f7f91STakashi Iwai 4487352f7f91STakashi Iwai if (spec->cap_sync_hook) 4488352f7f91STakashi Iwai spec->cap_sync_hook(codec); 4489352f7f91STakashi Iwai } 4490352f7f91STakashi Iwai 4491352f7f91STakashi Iwai /* set right pin controls for digital I/O */ 4492352f7f91STakashi Iwai static void init_digital(struct hda_codec *codec) 4493352f7f91STakashi Iwai { 4494352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4495352f7f91STakashi Iwai int i; 4496352f7f91STakashi Iwai hda_nid_t pin; 4497352f7f91STakashi Iwai 4498d4156930STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) 44992c12c30dSTakashi Iwai set_output_and_unmute(codec, spec->digout_paths[i]); 4500352f7f91STakashi Iwai pin = spec->autocfg.dig_in_pin; 45012430d7b7STakashi Iwai if (pin) { 45022430d7b7STakashi Iwai struct nid_path *path; 45032c12c30dSTakashi Iwai restore_pin_ctl(codec, pin); 45042430d7b7STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->digin_path); 45052430d7b7STakashi Iwai if (path) 45062430d7b7STakashi Iwai snd_hda_activate_path(codec, path, path->active, false); 45072430d7b7STakashi Iwai } 4508352f7f91STakashi Iwai } 4509352f7f91STakashi Iwai 4510973e4972STakashi Iwai /* clear unsol-event tags on unused pins; Conexant codecs seem to leave 4511973e4972STakashi Iwai * invalid unsol tags by some reason 4512973e4972STakashi Iwai */ 4513973e4972STakashi Iwai static void clear_unsol_on_unused_pins(struct hda_codec *codec) 4514973e4972STakashi Iwai { 4515973e4972STakashi Iwai int i; 4516973e4972STakashi Iwai 4517973e4972STakashi Iwai for (i = 0; i < codec->init_pins.used; i++) { 4518973e4972STakashi Iwai struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); 4519973e4972STakashi Iwai hda_nid_t nid = pin->nid; 4520973e4972STakashi Iwai if (is_jack_detectable(codec, nid) && 4521973e4972STakashi Iwai !snd_hda_jack_tbl_get(codec, nid)) 4522973e4972STakashi Iwai snd_hda_codec_update_cache(codec, nid, 0, 4523973e4972STakashi Iwai AC_VERB_SET_UNSOLICITED_ENABLE, 0); 4524973e4972STakashi Iwai } 4525973e4972STakashi Iwai } 4526973e4972STakashi Iwai 45275187ac16STakashi Iwai /* 45285187ac16STakashi Iwai * initialize the generic spec; 45295187ac16STakashi Iwai * this can be put as patch_ops.init function 45305187ac16STakashi Iwai */ 4531352f7f91STakashi Iwai int snd_hda_gen_init(struct hda_codec *codec) 4532352f7f91STakashi Iwai { 4533352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4534352f7f91STakashi Iwai 4535352f7f91STakashi Iwai if (spec->init_hook) 4536352f7f91STakashi Iwai spec->init_hook(codec); 4537352f7f91STakashi Iwai 4538352f7f91STakashi Iwai snd_hda_apply_verbs(codec); 4539352f7f91STakashi Iwai 45403bbcd274STakashi Iwai codec->cached_write = 1; 45413bbcd274STakashi Iwai 4542352f7f91STakashi Iwai init_multi_out(codec); 4543352f7f91STakashi Iwai init_extra_out(codec); 4544352f7f91STakashi Iwai init_multi_io(codec); 4545352f7f91STakashi Iwai init_analog_input(codec); 4546352f7f91STakashi Iwai init_input_src(codec); 4547352f7f91STakashi Iwai init_digital(codec); 4548352f7f91STakashi Iwai 4549973e4972STakashi Iwai clear_unsol_on_unused_pins(codec); 4550973e4972STakashi Iwai 4551352f7f91STakashi Iwai /* call init functions of standard auto-mute helpers */ 4552a5cc2509STakashi Iwai update_automute_all(codec); 4553352f7f91STakashi Iwai 45543bbcd274STakashi Iwai snd_hda_codec_flush_amp_cache(codec); 45553bbcd274STakashi Iwai snd_hda_codec_flush_cmd_cache(codec); 45563bbcd274STakashi Iwai 4557352f7f91STakashi Iwai if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook) 4558352f7f91STakashi Iwai snd_hda_sync_vmaster_hook(&spec->vmaster_mute); 4559352f7f91STakashi Iwai 4560352f7f91STakashi Iwai hda_call_check_power_status(codec, 0x01); 4561352f7f91STakashi Iwai return 0; 4562352f7f91STakashi Iwai } 4563fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_init); 4564fce52a3bSTakashi Iwai 45655187ac16STakashi Iwai /* 45665187ac16STakashi Iwai * free the generic spec; 45675187ac16STakashi Iwai * this can be put as patch_ops.free function 45685187ac16STakashi Iwai */ 4569fce52a3bSTakashi Iwai void snd_hda_gen_free(struct hda_codec *codec) 4570fce52a3bSTakashi Iwai { 4571fce52a3bSTakashi Iwai snd_hda_gen_spec_free(codec->spec); 4572fce52a3bSTakashi Iwai kfree(codec->spec); 4573fce52a3bSTakashi Iwai codec->spec = NULL; 4574fce52a3bSTakashi Iwai } 4575fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_free); 4576fce52a3bSTakashi Iwai 4577fce52a3bSTakashi Iwai #ifdef CONFIG_PM 45785187ac16STakashi Iwai /* 45795187ac16STakashi Iwai * check the loopback power save state; 45805187ac16STakashi Iwai * this can be put as patch_ops.check_power_status function 45815187ac16STakashi Iwai */ 4582fce52a3bSTakashi Iwai int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid) 4583fce52a3bSTakashi Iwai { 4584fce52a3bSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 4585fce52a3bSTakashi Iwai return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); 4586fce52a3bSTakashi Iwai } 4587fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_check_power_status); 4588fce52a3bSTakashi Iwai #endif 4589352f7f91STakashi Iwai 4590352f7f91STakashi Iwai 4591352f7f91STakashi Iwai /* 4592352f7f91STakashi Iwai * the generic codec support 4593352f7f91STakashi Iwai */ 45941da177e4SLinus Torvalds 4595352f7f91STakashi Iwai static const struct hda_codec_ops generic_patch_ops = { 4596352f7f91STakashi Iwai .build_controls = snd_hda_gen_build_controls, 4597352f7f91STakashi Iwai .build_pcms = snd_hda_gen_build_pcms, 4598352f7f91STakashi Iwai .init = snd_hda_gen_init, 4599fce52a3bSTakashi Iwai .free = snd_hda_gen_free, 4600352f7f91STakashi Iwai .unsol_event = snd_hda_jack_unsol_event, 460183012a7cSTakashi Iwai #ifdef CONFIG_PM 4602fce52a3bSTakashi Iwai .check_power_status = snd_hda_gen_check_power_status, 4603cb53c626STakashi Iwai #endif 46041da177e4SLinus Torvalds }; 46051da177e4SLinus Torvalds 46061da177e4SLinus Torvalds int snd_hda_parse_generic_codec(struct hda_codec *codec) 46071da177e4SLinus Torvalds { 4608352f7f91STakashi Iwai struct hda_gen_spec *spec; 46091da177e4SLinus Torvalds int err; 46101da177e4SLinus Torvalds 4611e560d8d8STakashi Iwai spec = kzalloc(sizeof(*spec), GFP_KERNEL); 4612352f7f91STakashi Iwai if (!spec) 46131da177e4SLinus Torvalds return -ENOMEM; 4614352f7f91STakashi Iwai snd_hda_gen_spec_init(spec); 46151da177e4SLinus Torvalds codec->spec = spec; 46161da177e4SLinus Torvalds 46179eb413e5STakashi Iwai err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0); 46189eb413e5STakashi Iwai if (err < 0) 46199eb413e5STakashi Iwai return err; 46209eb413e5STakashi Iwai 46219eb413e5STakashi Iwai err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg); 4622352f7f91STakashi Iwai if (err < 0) 46231da177e4SLinus Torvalds goto error; 46241da177e4SLinus Torvalds 46251da177e4SLinus Torvalds codec->patch_ops = generic_patch_ops; 46261da177e4SLinus Torvalds return 0; 46271da177e4SLinus Torvalds 46281da177e4SLinus Torvalds error: 4629fce52a3bSTakashi Iwai snd_hda_gen_free(codec); 46301da177e4SLinus Torvalds return err; 46311da177e4SLinus Torvalds } 4632fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_parse_generic_codec); 4633