11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Universal Interface for Intel High Definition Audio Codec 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Generic widget tree parser 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * This driver is free software; you can redistribute it and/or modify 91da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 101da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 111da177e4SLinus Torvalds * (at your option) any later version. 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * This driver is distributed in the hope that it will be useful, 141da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 151da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 161da177e4SLinus Torvalds * GNU General Public License for more details. 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 191da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 201da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 211da177e4SLinus Torvalds */ 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds #include <linux/init.h> 241da177e4SLinus Torvalds #include <linux/slab.h> 25d81a6d71SPaul Gortmaker #include <linux/export.h> 26352f7f91STakashi Iwai #include <linux/sort.h> 27f873e536STakashi Iwai #include <linux/ctype.h> 28f873e536STakashi Iwai #include <linux/string.h> 291da177e4SLinus Torvalds #include <sound/core.h> 30352f7f91STakashi Iwai #include <sound/jack.h> 311da177e4SLinus Torvalds #include "hda_codec.h" 321da177e4SLinus Torvalds #include "hda_local.h" 33352f7f91STakashi Iwai #include "hda_auto_parser.h" 34352f7f91STakashi Iwai #include "hda_jack.h" 35352f7f91STakashi Iwai #include "hda_generic.h" 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds 38352f7f91STakashi Iwai /* initialize hda_gen_spec struct */ 39352f7f91STakashi Iwai int snd_hda_gen_spec_init(struct hda_gen_spec *spec) 401da177e4SLinus Torvalds { 41352f7f91STakashi Iwai snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); 42352f7f91STakashi Iwai snd_array_init(&spec->paths, sizeof(struct nid_path), 8); 4338cf6f1aSTakashi Iwai mutex_init(&spec->pcm_mutex); 44352f7f91STakashi Iwai return 0; 45352f7f91STakashi Iwai } 46352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_spec_init); 471da177e4SLinus Torvalds 4812c93df6STakashi Iwai struct snd_kcontrol_new * 4912c93df6STakashi Iwai snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name, 50352f7f91STakashi Iwai const struct snd_kcontrol_new *temp) 51352f7f91STakashi Iwai { 52352f7f91STakashi Iwai struct snd_kcontrol_new *knew = snd_array_new(&spec->kctls); 53352f7f91STakashi Iwai if (!knew) 54352f7f91STakashi Iwai return NULL; 55352f7f91STakashi Iwai *knew = *temp; 56352f7f91STakashi Iwai if (name) 57352f7f91STakashi Iwai knew->name = kstrdup(name, GFP_KERNEL); 58352f7f91STakashi Iwai else if (knew->name) 59352f7f91STakashi Iwai knew->name = kstrdup(knew->name, GFP_KERNEL); 60352f7f91STakashi Iwai if (!knew->name) 61352f7f91STakashi Iwai return NULL; 62352f7f91STakashi Iwai return knew; 63352f7f91STakashi Iwai } 6412c93df6STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_add_kctl); 65352f7f91STakashi Iwai 66352f7f91STakashi Iwai static void free_kctls(struct hda_gen_spec *spec) 67352f7f91STakashi Iwai { 68352f7f91STakashi Iwai if (spec->kctls.list) { 69352f7f91STakashi Iwai struct snd_kcontrol_new *kctl = spec->kctls.list; 70352f7f91STakashi Iwai int i; 71352f7f91STakashi Iwai for (i = 0; i < spec->kctls.used; i++) 72352f7f91STakashi Iwai kfree(kctl[i].name); 73352f7f91STakashi Iwai } 74352f7f91STakashi Iwai snd_array_free(&spec->kctls); 75352f7f91STakashi Iwai } 76352f7f91STakashi Iwai 77352f7f91STakashi Iwai void snd_hda_gen_spec_free(struct hda_gen_spec *spec) 78352f7f91STakashi Iwai { 791da177e4SLinus Torvalds if (!spec) 801da177e4SLinus Torvalds return; 81352f7f91STakashi Iwai free_kctls(spec); 82352f7f91STakashi Iwai snd_array_free(&spec->paths); 831da177e4SLinus Torvalds } 84352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_spec_free); 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds /* 87*1c70a583STakashi Iwai * store user hints 88*1c70a583STakashi Iwai */ 89*1c70a583STakashi Iwai static void parse_user_hints(struct hda_codec *codec) 90*1c70a583STakashi Iwai { 91*1c70a583STakashi Iwai struct hda_gen_spec *spec = codec->spec; 92*1c70a583STakashi Iwai int val; 93*1c70a583STakashi Iwai 94*1c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "jack_detect"); 95*1c70a583STakashi Iwai if (val >= 0) 96*1c70a583STakashi Iwai codec->no_jack_detect = !val; 97*1c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "inv_jack_detect"); 98*1c70a583STakashi Iwai if (val >= 0) 99*1c70a583STakashi Iwai codec->inv_jack_detect = !!val; 100*1c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "trigger_sense"); 101*1c70a583STakashi Iwai if (val >= 0) 102*1c70a583STakashi Iwai codec->no_trigger_sense = !val; 103*1c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "inv_eapd"); 104*1c70a583STakashi Iwai if (val >= 0) 105*1c70a583STakashi Iwai codec->inv_eapd = !!val; 106*1c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "pcm_format_first"); 107*1c70a583STakashi Iwai if (val >= 0) 108*1c70a583STakashi Iwai codec->pcm_format_first = !!val; 109*1c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "sticky_stream"); 110*1c70a583STakashi Iwai if (val >= 0) 111*1c70a583STakashi Iwai codec->no_sticky_stream = !val; 112*1c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "spdif_status_reset"); 113*1c70a583STakashi Iwai if (val >= 0) 114*1c70a583STakashi Iwai codec->spdif_status_reset = !!val; 115*1c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "pin_amp_workaround"); 116*1c70a583STakashi Iwai if (val >= 0) 117*1c70a583STakashi Iwai codec->pin_amp_workaround = !!val; 118*1c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "single_adc_amp"); 119*1c70a583STakashi Iwai if (val >= 0) 120*1c70a583STakashi Iwai codec->single_adc_amp = !!val; 121*1c70a583STakashi Iwai 122*1c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "auto_mic"); 123*1c70a583STakashi Iwai if (val >= 0) 124*1c70a583STakashi Iwai spec->suppress_auto_mic = !val; 125*1c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "line_in_auto_switch"); 126*1c70a583STakashi Iwai if (val >= 0) 127*1c70a583STakashi Iwai spec->line_in_auto_switch = !!val; 128*1c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "need_dac_fix"); 129*1c70a583STakashi Iwai if (val >= 0) 130*1c70a583STakashi Iwai spec->need_dac_fix = !!val; 131*1c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "primary_hp"); 132*1c70a583STakashi Iwai if (val >= 0) 133*1c70a583STakashi Iwai spec->no_primary_hp = !val; 134*1c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "multi_cap_vol"); 135*1c70a583STakashi Iwai if (val >= 0) 136*1c70a583STakashi Iwai spec->multi_cap_vol = !!val; 137*1c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "inv_dmic_split"); 138*1c70a583STakashi Iwai if (val >= 0) 139*1c70a583STakashi Iwai spec->inv_dmic_split = !!val; 140*1c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "indep_hp"); 141*1c70a583STakashi Iwai if (val >= 0) 142*1c70a583STakashi Iwai spec->indep_hp = !!val; 143*1c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "add_stereo_mix_input"); 144*1c70a583STakashi Iwai if (val >= 0) 145*1c70a583STakashi Iwai spec->add_stereo_mix_input = !!val; 146*1c70a583STakashi Iwai val = snd_hda_get_bool_hint(codec, "add_out_jack_modes"); 147*1c70a583STakashi Iwai if (val >= 0) 148*1c70a583STakashi Iwai spec->add_out_jack_modes = !!val; 149*1c70a583STakashi Iwai 150*1c70a583STakashi Iwai if (!snd_hda_get_int_hint(codec, "mixer_nid", &val)) 151*1c70a583STakashi Iwai spec->mixer_nid = val; 152*1c70a583STakashi Iwai } 153*1c70a583STakashi Iwai 154*1c70a583STakashi Iwai /* 1552c12c30dSTakashi Iwai * pin control value accesses 1562c12c30dSTakashi Iwai */ 1572c12c30dSTakashi Iwai 1582c12c30dSTakashi Iwai #define update_pin_ctl(codec, pin, val) \ 1592c12c30dSTakashi Iwai snd_hda_codec_update_cache(codec, pin, 0, \ 1602c12c30dSTakashi Iwai AC_VERB_SET_PIN_WIDGET_CONTROL, val) 1612c12c30dSTakashi Iwai 1622c12c30dSTakashi Iwai /* restore the pinctl based on the cached value */ 1632c12c30dSTakashi Iwai static inline void restore_pin_ctl(struct hda_codec *codec, hda_nid_t pin) 1642c12c30dSTakashi Iwai { 1652c12c30dSTakashi Iwai update_pin_ctl(codec, pin, snd_hda_codec_get_pin_target(codec, pin)); 1662c12c30dSTakashi Iwai } 1672c12c30dSTakashi Iwai 1682c12c30dSTakashi Iwai /* set the pinctl target value and write it if requested */ 1692c12c30dSTakashi Iwai static void set_pin_target(struct hda_codec *codec, hda_nid_t pin, 1702c12c30dSTakashi Iwai unsigned int val, bool do_write) 1712c12c30dSTakashi Iwai { 1722c12c30dSTakashi Iwai if (!pin) 1732c12c30dSTakashi Iwai return; 1742c12c30dSTakashi Iwai val = snd_hda_correct_pin_ctl(codec, pin, val); 1752c12c30dSTakashi Iwai snd_hda_codec_set_pin_target(codec, pin, val); 1762c12c30dSTakashi Iwai if (do_write) 1772c12c30dSTakashi Iwai update_pin_ctl(codec, pin, val); 1782c12c30dSTakashi Iwai } 1792c12c30dSTakashi Iwai 1802c12c30dSTakashi Iwai /* set pinctl target values for all given pins */ 1812c12c30dSTakashi Iwai static void set_pin_targets(struct hda_codec *codec, int num_pins, 1822c12c30dSTakashi Iwai hda_nid_t *pins, unsigned int val) 1832c12c30dSTakashi Iwai { 1842c12c30dSTakashi Iwai int i; 1852c12c30dSTakashi Iwai for (i = 0; i < num_pins; i++) 1862c12c30dSTakashi Iwai set_pin_target(codec, pins[i], val, false); 1872c12c30dSTakashi Iwai } 1882c12c30dSTakashi Iwai 1892c12c30dSTakashi Iwai /* 190352f7f91STakashi Iwai * parsing paths 1911da177e4SLinus Torvalds */ 1921da177e4SLinus Torvalds 1933ca529d3STakashi Iwai /* return the position of NID in the list, or -1 if not found */ 1943ca529d3STakashi Iwai static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) 1953ca529d3STakashi Iwai { 1963ca529d3STakashi Iwai int i; 1973ca529d3STakashi Iwai for (i = 0; i < nums; i++) 1983ca529d3STakashi Iwai if (list[i] == nid) 1993ca529d3STakashi Iwai return i; 2003ca529d3STakashi Iwai return -1; 2013ca529d3STakashi Iwai } 2023ca529d3STakashi Iwai 2033ca529d3STakashi Iwai /* return true if the given NID is contained in the path */ 2043ca529d3STakashi Iwai static bool is_nid_contained(struct nid_path *path, hda_nid_t nid) 2053ca529d3STakashi Iwai { 2063ca529d3STakashi Iwai return find_idx_in_nid_list(nid, path->path, path->depth) >= 0; 2073ca529d3STakashi Iwai } 2083ca529d3STakashi Iwai 209f5172a7eSTakashi Iwai static struct nid_path *get_nid_path(struct hda_codec *codec, 210f5172a7eSTakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid, 2113ca529d3STakashi Iwai int anchor_nid) 2121da177e4SLinus Torvalds { 213352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 214352f7f91STakashi Iwai int i; 2151da177e4SLinus Torvalds 216352f7f91STakashi Iwai for (i = 0; i < spec->paths.used; i++) { 217352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, i); 218352f7f91STakashi Iwai if (path->depth <= 0) 219352f7f91STakashi Iwai continue; 220352f7f91STakashi Iwai if ((!from_nid || path->path[0] == from_nid) && 221f5172a7eSTakashi Iwai (!to_nid || path->path[path->depth - 1] == to_nid)) { 2223ca529d3STakashi Iwai if (!anchor_nid || 2233ca529d3STakashi Iwai (anchor_nid > 0 && is_nid_contained(path, anchor_nid)) || 2243ca529d3STakashi Iwai (anchor_nid < 0 && !is_nid_contained(path, anchor_nid))) 225352f7f91STakashi Iwai return path; 2261da177e4SLinus Torvalds } 227f5172a7eSTakashi Iwai } 2281da177e4SLinus Torvalds return NULL; 2291da177e4SLinus Torvalds } 230f5172a7eSTakashi Iwai 231f5172a7eSTakashi Iwai /* get the path between the given NIDs; 232f5172a7eSTakashi Iwai * passing 0 to either @pin or @dac behaves as a wildcard 233f5172a7eSTakashi Iwai */ 234f5172a7eSTakashi Iwai struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec, 235f5172a7eSTakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid) 236f5172a7eSTakashi Iwai { 2373ca529d3STakashi Iwai return get_nid_path(codec, from_nid, to_nid, 0); 238f5172a7eSTakashi Iwai } 239352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_nid_path); 2401da177e4SLinus Torvalds 241196c1766STakashi Iwai /* get the index number corresponding to the path instance; 242196c1766STakashi Iwai * the index starts from 1, for easier checking the invalid value 243196c1766STakashi Iwai */ 244196c1766STakashi Iwai int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path) 245196c1766STakashi Iwai { 246196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 247196c1766STakashi Iwai struct nid_path *array = spec->paths.list; 248196c1766STakashi Iwai ssize_t idx; 249196c1766STakashi Iwai 250196c1766STakashi Iwai if (!spec->paths.used) 251196c1766STakashi Iwai return 0; 252196c1766STakashi Iwai idx = path - array; 253196c1766STakashi Iwai if (idx < 0 || idx >= spec->paths.used) 254196c1766STakashi Iwai return 0; 255196c1766STakashi Iwai return idx + 1; 256196c1766STakashi Iwai } 257196c1766STakashi Iwai 258196c1766STakashi Iwai /* get the path instance corresponding to the given index number */ 259196c1766STakashi Iwai struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx) 260196c1766STakashi Iwai { 261196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 262196c1766STakashi Iwai 263196c1766STakashi Iwai if (idx <= 0 || idx > spec->paths.used) 264196c1766STakashi Iwai return NULL; 265196c1766STakashi Iwai return snd_array_elem(&spec->paths, idx - 1); 266196c1766STakashi Iwai } 267196c1766STakashi Iwai 268352f7f91STakashi Iwai /* check whether the given DAC is already found in any existing paths */ 269352f7f91STakashi Iwai static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid) 2701da177e4SLinus Torvalds { 271352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 272352f7f91STakashi Iwai int i; 273352f7f91STakashi Iwai 274352f7f91STakashi Iwai for (i = 0; i < spec->paths.used; i++) { 275352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, i); 276352f7f91STakashi Iwai if (path->path[0] == nid) 277352f7f91STakashi Iwai return true; 278352f7f91STakashi Iwai } 279352f7f91STakashi Iwai return false; 2801da177e4SLinus Torvalds } 2811da177e4SLinus Torvalds 282352f7f91STakashi Iwai /* check whether the given two widgets can be connected */ 283352f7f91STakashi Iwai static bool is_reachable_path(struct hda_codec *codec, 284352f7f91STakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid) 2851da177e4SLinus Torvalds { 286352f7f91STakashi Iwai if (!from_nid || !to_nid) 287352f7f91STakashi Iwai return false; 288352f7f91STakashi Iwai return snd_hda_get_conn_index(codec, to_nid, from_nid, true) >= 0; 2891da177e4SLinus Torvalds } 2901da177e4SLinus Torvalds 291352f7f91STakashi Iwai /* nid, dir and idx */ 292352f7f91STakashi Iwai #define AMP_VAL_COMPARE_MASK (0xffff | (1U << 18) | (0x0f << 19)) 293352f7f91STakashi Iwai 294352f7f91STakashi Iwai /* check whether the given ctl is already assigned in any path elements */ 295352f7f91STakashi Iwai static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type) 2961da177e4SLinus Torvalds { 297352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 298352f7f91STakashi Iwai int i; 299352f7f91STakashi Iwai 300352f7f91STakashi Iwai val &= AMP_VAL_COMPARE_MASK; 301352f7f91STakashi Iwai for (i = 0; i < spec->paths.used; i++) { 302352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, i); 303352f7f91STakashi Iwai if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val) 304352f7f91STakashi Iwai return true; 305352f7f91STakashi Iwai } 306352f7f91STakashi Iwai return false; 3071da177e4SLinus Torvalds } 3081da177e4SLinus Torvalds 309352f7f91STakashi Iwai /* check whether a control with the given (nid, dir, idx) was assigned */ 310352f7f91STakashi Iwai static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid, 311cb53c626STakashi Iwai int dir, int idx) 312cb53c626STakashi Iwai { 313352f7f91STakashi Iwai unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir); 314352f7f91STakashi Iwai return is_ctl_used(codec, val, NID_PATH_VOL_CTL) || 315352f7f91STakashi Iwai is_ctl_used(codec, val, NID_PATH_MUTE_CTL); 316cb53c626STakashi Iwai } 317352f7f91STakashi Iwai 3180c8c0f56STakashi Iwai static void print_nid_path(const char *pfx, struct nid_path *path) 3190c8c0f56STakashi Iwai { 3200c8c0f56STakashi Iwai char buf[40]; 3210c8c0f56STakashi Iwai int i; 3220c8c0f56STakashi Iwai 3230c8c0f56STakashi Iwai 3240c8c0f56STakashi Iwai buf[0] = 0; 3250c8c0f56STakashi Iwai for (i = 0; i < path->depth; i++) { 3260c8c0f56STakashi Iwai char tmp[4]; 3270c8c0f56STakashi Iwai sprintf(tmp, ":%02x", path->path[i]); 3280c8c0f56STakashi Iwai strlcat(buf, tmp, sizeof(buf)); 3290c8c0f56STakashi Iwai } 3300c8c0f56STakashi Iwai snd_printdd("%s path: depth=%d %s\n", pfx, path->depth, buf); 3310c8c0f56STakashi Iwai } 3320c8c0f56STakashi Iwai 333352f7f91STakashi Iwai /* called recursively */ 334352f7f91STakashi Iwai static bool __parse_nid_path(struct hda_codec *codec, 335352f7f91STakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid, 3363ca529d3STakashi Iwai int anchor_nid, struct nid_path *path, 3373ca529d3STakashi Iwai int depth) 338352f7f91STakashi Iwai { 339ee8e765bSTakashi Iwai const hda_nid_t *conn; 340352f7f91STakashi Iwai int i, nums; 341352f7f91STakashi Iwai 3423ca529d3STakashi Iwai if (to_nid == anchor_nid) 3433ca529d3STakashi Iwai anchor_nid = 0; /* anchor passed */ 3443ca529d3STakashi Iwai else if (to_nid == (hda_nid_t)(-anchor_nid)) 3453ca529d3STakashi Iwai return false; /* hit the exclusive nid */ 346352f7f91STakashi Iwai 347ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, to_nid, &conn); 348352f7f91STakashi Iwai for (i = 0; i < nums; i++) { 349352f7f91STakashi Iwai if (conn[i] != from_nid) { 350352f7f91STakashi Iwai /* special case: when from_nid is 0, 351352f7f91STakashi Iwai * try to find an empty DAC 352352f7f91STakashi Iwai */ 353352f7f91STakashi Iwai if (from_nid || 354352f7f91STakashi Iwai get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT || 355352f7f91STakashi Iwai is_dac_already_used(codec, conn[i])) 356352f7f91STakashi Iwai continue; 357352f7f91STakashi Iwai } 3583ca529d3STakashi Iwai /* anchor is not requested or already passed? */ 3593ca529d3STakashi Iwai if (anchor_nid <= 0) 360352f7f91STakashi Iwai goto found; 361352f7f91STakashi Iwai } 362352f7f91STakashi Iwai if (depth >= MAX_NID_PATH_DEPTH) 363352f7f91STakashi Iwai return false; 364352f7f91STakashi Iwai for (i = 0; i < nums; i++) { 365352f7f91STakashi Iwai unsigned int type; 366352f7f91STakashi Iwai type = get_wcaps_type(get_wcaps(codec, conn[i])); 367352f7f91STakashi Iwai if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN || 368352f7f91STakashi Iwai type == AC_WID_PIN) 369352f7f91STakashi Iwai continue; 370352f7f91STakashi Iwai if (__parse_nid_path(codec, from_nid, conn[i], 3713ca529d3STakashi Iwai anchor_nid, path, depth + 1)) 372352f7f91STakashi Iwai goto found; 373352f7f91STakashi Iwai } 374352f7f91STakashi Iwai return false; 375352f7f91STakashi Iwai 376352f7f91STakashi Iwai found: 377352f7f91STakashi Iwai path->path[path->depth] = conn[i]; 378352f7f91STakashi Iwai path->idx[path->depth + 1] = i; 379352f7f91STakashi Iwai if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX) 380352f7f91STakashi Iwai path->multi[path->depth + 1] = 1; 381352f7f91STakashi Iwai path->depth++; 382352f7f91STakashi Iwai return true; 383352f7f91STakashi Iwai } 384352f7f91STakashi Iwai 385352f7f91STakashi Iwai /* parse the widget path from the given nid to the target nid; 386352f7f91STakashi Iwai * when @from_nid is 0, try to find an empty DAC; 3873ca529d3STakashi Iwai * when @anchor_nid is set to a positive value, only paths through the widget 3883ca529d3STakashi Iwai * with the given value are evaluated. 3893ca529d3STakashi Iwai * when @anchor_nid is set to a negative value, paths through the widget 3903ca529d3STakashi Iwai * with the negative of given value are excluded, only other paths are chosen. 3913ca529d3STakashi Iwai * when @anchor_nid is zero, no special handling about path selection. 392352f7f91STakashi Iwai */ 393352f7f91STakashi Iwai bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, 3943ca529d3STakashi Iwai hda_nid_t to_nid, int anchor_nid, 395352f7f91STakashi Iwai struct nid_path *path) 396352f7f91STakashi Iwai { 3973ca529d3STakashi Iwai if (__parse_nid_path(codec, from_nid, to_nid, anchor_nid, path, 1)) { 398352f7f91STakashi Iwai path->path[path->depth] = to_nid; 399352f7f91STakashi Iwai path->depth++; 400352f7f91STakashi Iwai return true; 401352f7f91STakashi Iwai } 402352f7f91STakashi Iwai return false; 403352f7f91STakashi Iwai } 404352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_parse_nid_path); 405352f7f91STakashi Iwai 406352f7f91STakashi Iwai /* 407352f7f91STakashi Iwai * parse the path between the given NIDs and add to the path list. 408352f7f91STakashi Iwai * if no valid path is found, return NULL 409352f7f91STakashi Iwai */ 410352f7f91STakashi Iwai struct nid_path * 411352f7f91STakashi Iwai snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid, 4123ca529d3STakashi Iwai hda_nid_t to_nid, int anchor_nid) 413352f7f91STakashi Iwai { 414352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 415352f7f91STakashi Iwai struct nid_path *path; 416352f7f91STakashi Iwai 417352f7f91STakashi Iwai if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid)) 418352f7f91STakashi Iwai return NULL; 419352f7f91STakashi Iwai 420f5172a7eSTakashi Iwai /* check whether the path has been already added */ 4213ca529d3STakashi Iwai path = get_nid_path(codec, from_nid, to_nid, anchor_nid); 422f5172a7eSTakashi Iwai if (path) 423f5172a7eSTakashi Iwai return path; 424f5172a7eSTakashi Iwai 425352f7f91STakashi Iwai path = snd_array_new(&spec->paths); 426352f7f91STakashi Iwai if (!path) 427352f7f91STakashi Iwai return NULL; 428352f7f91STakashi Iwai memset(path, 0, sizeof(*path)); 4293ca529d3STakashi Iwai if (snd_hda_parse_nid_path(codec, from_nid, to_nid, anchor_nid, path)) 430352f7f91STakashi Iwai return path; 431352f7f91STakashi Iwai /* push back */ 432352f7f91STakashi Iwai spec->paths.used--; 433352f7f91STakashi Iwai return NULL; 434352f7f91STakashi Iwai } 435352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_add_new_path); 436352f7f91STakashi Iwai 437980428ceSTakashi Iwai /* clear the given path as invalid so that it won't be picked up later */ 438980428ceSTakashi Iwai static void invalidate_nid_path(struct hda_codec *codec, int idx) 439980428ceSTakashi Iwai { 440980428ceSTakashi Iwai struct nid_path *path = snd_hda_get_path_from_idx(codec, idx); 441980428ceSTakashi Iwai if (!path) 442980428ceSTakashi Iwai return; 443980428ceSTakashi Iwai memset(path, 0, sizeof(*path)); 444980428ceSTakashi Iwai } 445980428ceSTakashi Iwai 446352f7f91STakashi Iwai /* look for an empty DAC slot */ 447352f7f91STakashi Iwai static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin, 448352f7f91STakashi Iwai bool is_digital) 449352f7f91STakashi Iwai { 450352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 451352f7f91STakashi Iwai bool cap_digital; 452352f7f91STakashi Iwai int i; 453352f7f91STakashi Iwai 454352f7f91STakashi Iwai for (i = 0; i < spec->num_all_dacs; i++) { 455352f7f91STakashi Iwai hda_nid_t nid = spec->all_dacs[i]; 456352f7f91STakashi Iwai if (!nid || is_dac_already_used(codec, nid)) 457352f7f91STakashi Iwai continue; 458352f7f91STakashi Iwai cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL); 459352f7f91STakashi Iwai if (is_digital != cap_digital) 460352f7f91STakashi Iwai continue; 461352f7f91STakashi Iwai if (is_reachable_path(codec, nid, pin)) 462352f7f91STakashi Iwai return nid; 463352f7f91STakashi Iwai } 464352f7f91STakashi Iwai return 0; 465352f7f91STakashi Iwai } 466352f7f91STakashi Iwai 467352f7f91STakashi Iwai /* replace the channels in the composed amp value with the given number */ 468352f7f91STakashi Iwai static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs) 469352f7f91STakashi Iwai { 470352f7f91STakashi Iwai val &= ~(0x3U << 16); 471352f7f91STakashi Iwai val |= chs << 16; 472352f7f91STakashi Iwai return val; 473352f7f91STakashi Iwai } 474352f7f91STakashi Iwai 475352f7f91STakashi Iwai /* check whether the widget has the given amp capability for the direction */ 476352f7f91STakashi Iwai static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, 477352f7f91STakashi Iwai int dir, unsigned int bits) 478352f7f91STakashi Iwai { 479352f7f91STakashi Iwai if (!nid) 480352f7f91STakashi Iwai return false; 481352f7f91STakashi Iwai if (get_wcaps(codec, nid) & (1 << (dir + 1))) 482352f7f91STakashi Iwai if (query_amp_caps(codec, nid, dir) & bits) 483352f7f91STakashi Iwai return true; 484352f7f91STakashi Iwai return false; 485352f7f91STakashi Iwai } 486352f7f91STakashi Iwai 487352f7f91STakashi Iwai #define nid_has_mute(codec, nid, dir) \ 488352f7f91STakashi Iwai check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE) 489352f7f91STakashi Iwai #define nid_has_volume(codec, nid, dir) \ 490352f7f91STakashi Iwai check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS) 491352f7f91STakashi Iwai 492352f7f91STakashi Iwai /* look for a widget suitable for assigning a mute switch in the path */ 493352f7f91STakashi Iwai static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec, 494352f7f91STakashi Iwai struct nid_path *path) 495352f7f91STakashi Iwai { 496352f7f91STakashi Iwai int i; 497352f7f91STakashi Iwai 498352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 499352f7f91STakashi Iwai if (nid_has_mute(codec, path->path[i], HDA_OUTPUT)) 500352f7f91STakashi Iwai return path->path[i]; 501352f7f91STakashi Iwai if (i != path->depth - 1 && i != 0 && 502352f7f91STakashi Iwai nid_has_mute(codec, path->path[i], HDA_INPUT)) 503352f7f91STakashi Iwai return path->path[i]; 504352f7f91STakashi Iwai } 505352f7f91STakashi Iwai return 0; 506352f7f91STakashi Iwai } 507352f7f91STakashi Iwai 508352f7f91STakashi Iwai /* look for a widget suitable for assigning a volume ctl in the path */ 509352f7f91STakashi Iwai static hda_nid_t look_for_out_vol_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_volume(codec, path->path[i], HDA_OUTPUT)) 516352f7f91STakashi Iwai return path->path[i]; 517352f7f91STakashi Iwai } 518352f7f91STakashi Iwai return 0; 519352f7f91STakashi Iwai } 520352f7f91STakashi Iwai 521352f7f91STakashi Iwai /* 522352f7f91STakashi Iwai * path activation / deactivation 523352f7f91STakashi Iwai */ 524352f7f91STakashi Iwai 525352f7f91STakashi Iwai /* can have the amp-in capability? */ 526352f7f91STakashi Iwai static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx) 527352f7f91STakashi Iwai { 528352f7f91STakashi Iwai hda_nid_t nid = path->path[idx]; 529352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 530352f7f91STakashi Iwai unsigned int type = get_wcaps_type(caps); 531352f7f91STakashi Iwai 532352f7f91STakashi Iwai if (!(caps & AC_WCAP_IN_AMP)) 533352f7f91STakashi Iwai return false; 534352f7f91STakashi Iwai if (type == AC_WID_PIN && idx > 0) /* only for input pins */ 535352f7f91STakashi Iwai return false; 536352f7f91STakashi Iwai return true; 537352f7f91STakashi Iwai } 538352f7f91STakashi Iwai 539352f7f91STakashi Iwai /* can have the amp-out capability? */ 540352f7f91STakashi Iwai static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx) 541352f7f91STakashi Iwai { 542352f7f91STakashi Iwai hda_nid_t nid = path->path[idx]; 543352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 544352f7f91STakashi Iwai unsigned int type = get_wcaps_type(caps); 545352f7f91STakashi Iwai 546352f7f91STakashi Iwai if (!(caps & AC_WCAP_OUT_AMP)) 547352f7f91STakashi Iwai return false; 548352f7f91STakashi Iwai if (type == AC_WID_PIN && !idx) /* only for output pins */ 549352f7f91STakashi Iwai return false; 550352f7f91STakashi Iwai return true; 551352f7f91STakashi Iwai } 552352f7f91STakashi Iwai 553352f7f91STakashi Iwai /* check whether the given (nid,dir,idx) is active */ 554352f7f91STakashi Iwai static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid, 555352f7f91STakashi Iwai unsigned int idx, unsigned int dir) 556352f7f91STakashi Iwai { 557352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 558352f7f91STakashi Iwai int i, n; 559352f7f91STakashi Iwai 560352f7f91STakashi Iwai for (n = 0; n < spec->paths.used; n++) { 561352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, n); 562352f7f91STakashi Iwai if (!path->active) 563352f7f91STakashi Iwai continue; 564352f7f91STakashi Iwai for (i = 0; i < path->depth; i++) { 565352f7f91STakashi Iwai if (path->path[i] == nid) { 566352f7f91STakashi Iwai if (dir == HDA_OUTPUT || path->idx[i] == idx) 567352f7f91STakashi Iwai return true; 568352f7f91STakashi Iwai break; 569352f7f91STakashi Iwai } 570352f7f91STakashi Iwai } 571352f7f91STakashi Iwai } 572352f7f91STakashi Iwai return false; 573352f7f91STakashi Iwai } 574352f7f91STakashi Iwai 575352f7f91STakashi Iwai /* get the default amp value for the target state */ 576352f7f91STakashi Iwai static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid, 577352f7f91STakashi Iwai int dir, bool enable) 578352f7f91STakashi Iwai { 579352f7f91STakashi Iwai unsigned int caps; 580352f7f91STakashi Iwai unsigned int val = 0; 581352f7f91STakashi Iwai 582352f7f91STakashi Iwai caps = query_amp_caps(codec, nid, dir); 583352f7f91STakashi Iwai if (caps & AC_AMPCAP_NUM_STEPS) { 584352f7f91STakashi Iwai /* set to 0dB */ 585352f7f91STakashi Iwai if (enable) 586352f7f91STakashi Iwai val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; 587352f7f91STakashi Iwai } 588352f7f91STakashi Iwai if (caps & AC_AMPCAP_MUTE) { 589352f7f91STakashi Iwai if (!enable) 590352f7f91STakashi Iwai val |= HDA_AMP_MUTE; 591352f7f91STakashi Iwai } 592352f7f91STakashi Iwai return val; 593352f7f91STakashi Iwai } 594352f7f91STakashi Iwai 595352f7f91STakashi Iwai /* initialize the amp value (only at the first time) */ 596352f7f91STakashi Iwai static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx) 597352f7f91STakashi Iwai { 598352f7f91STakashi Iwai int val = get_amp_val_to_activate(codec, nid, dir, false); 599352f7f91STakashi Iwai snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); 600352f7f91STakashi Iwai } 601352f7f91STakashi Iwai 602352f7f91STakashi Iwai static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, 603352f7f91STakashi Iwai int idx, bool enable) 604352f7f91STakashi Iwai { 605352f7f91STakashi Iwai int val; 606352f7f91STakashi Iwai if (is_ctl_associated(codec, nid, dir, idx) || 607985803caSTakashi Iwai (!enable && is_active_nid(codec, nid, dir, idx))) 608352f7f91STakashi Iwai return; 609352f7f91STakashi Iwai val = get_amp_val_to_activate(codec, nid, dir, enable); 610352f7f91STakashi Iwai snd_hda_codec_amp_stereo(codec, nid, dir, idx, 0xff, val); 611352f7f91STakashi Iwai } 612352f7f91STakashi Iwai 613352f7f91STakashi Iwai static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, 614352f7f91STakashi Iwai int i, bool enable) 615352f7f91STakashi Iwai { 616352f7f91STakashi Iwai hda_nid_t nid = path->path[i]; 617352f7f91STakashi Iwai init_amp(codec, nid, HDA_OUTPUT, 0); 618352f7f91STakashi Iwai activate_amp(codec, nid, HDA_OUTPUT, 0, enable); 619352f7f91STakashi Iwai } 620352f7f91STakashi Iwai 621352f7f91STakashi Iwai static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, 622352f7f91STakashi Iwai int i, bool enable, bool add_aamix) 623352f7f91STakashi Iwai { 624352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 625ee8e765bSTakashi Iwai const hda_nid_t *conn; 626352f7f91STakashi Iwai int n, nums, idx; 627352f7f91STakashi Iwai int type; 628352f7f91STakashi Iwai hda_nid_t nid = path->path[i]; 629352f7f91STakashi Iwai 630ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, nid, &conn); 631352f7f91STakashi Iwai type = get_wcaps_type(get_wcaps(codec, nid)); 632352f7f91STakashi Iwai if (type == AC_WID_PIN || 633352f7f91STakashi Iwai (type == AC_WID_AUD_IN && codec->single_adc_amp)) { 634352f7f91STakashi Iwai nums = 1; 635352f7f91STakashi Iwai idx = 0; 636352f7f91STakashi Iwai } else 637352f7f91STakashi Iwai idx = path->idx[i]; 638352f7f91STakashi Iwai 639352f7f91STakashi Iwai for (n = 0; n < nums; n++) 640352f7f91STakashi Iwai init_amp(codec, nid, HDA_INPUT, n); 641352f7f91STakashi Iwai 642352f7f91STakashi Iwai if (is_ctl_associated(codec, nid, HDA_INPUT, idx)) 643352f7f91STakashi Iwai return; 644352f7f91STakashi Iwai 645352f7f91STakashi Iwai /* here is a little bit tricky in comparison with activate_amp_out(); 646352f7f91STakashi Iwai * when aa-mixer is available, we need to enable the path as well 647352f7f91STakashi Iwai */ 648352f7f91STakashi Iwai for (n = 0; n < nums; n++) { 649352f7f91STakashi Iwai if (n != idx && (!add_aamix || conn[n] != spec->mixer_nid)) 650352f7f91STakashi Iwai continue; 651352f7f91STakashi Iwai activate_amp(codec, nid, HDA_INPUT, n, enable); 652352f7f91STakashi Iwai } 653352f7f91STakashi Iwai } 654352f7f91STakashi Iwai 655352f7f91STakashi Iwai /* activate or deactivate the given path 656352f7f91STakashi Iwai * if @add_aamix is set, enable the input from aa-mix NID as well (if any) 657352f7f91STakashi Iwai */ 658352f7f91STakashi Iwai void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path, 659352f7f91STakashi Iwai bool enable, bool add_aamix) 660352f7f91STakashi Iwai { 661352f7f91STakashi Iwai int i; 662352f7f91STakashi Iwai 663352f7f91STakashi Iwai if (!enable) 664352f7f91STakashi Iwai path->active = false; 665352f7f91STakashi Iwai 666352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 667352f7f91STakashi Iwai if (enable && path->multi[i]) 668352f7f91STakashi Iwai snd_hda_codec_write_cache(codec, path->path[i], 0, 669352f7f91STakashi Iwai AC_VERB_SET_CONNECT_SEL, 670352f7f91STakashi Iwai path->idx[i]); 671352f7f91STakashi Iwai if (has_amp_in(codec, path, i)) 672352f7f91STakashi Iwai activate_amp_in(codec, path, i, enable, add_aamix); 673352f7f91STakashi Iwai if (has_amp_out(codec, path, i)) 674352f7f91STakashi Iwai activate_amp_out(codec, path, i, enable); 675352f7f91STakashi Iwai } 676352f7f91STakashi Iwai 677352f7f91STakashi Iwai if (enable) 678352f7f91STakashi Iwai path->active = true; 679352f7f91STakashi Iwai } 680352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_activate_path); 681352f7f91STakashi Iwai 682d5a9f1bbSTakashi Iwai /* turn on/off EAPD on the given pin */ 683d5a9f1bbSTakashi Iwai static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable) 684d5a9f1bbSTakashi Iwai { 685d5a9f1bbSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 686d5a9f1bbSTakashi Iwai if (spec->own_eapd_ctl || 687d5a9f1bbSTakashi Iwai !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD)) 688d5a9f1bbSTakashi Iwai return; 689ecac3ed1STakashi Iwai if (codec->inv_eapd) 690ecac3ed1STakashi Iwai enable = !enable; 691d5a9f1bbSTakashi Iwai snd_hda_codec_update_cache(codec, pin, 0, 692d5a9f1bbSTakashi Iwai AC_VERB_SET_EAPD_BTLENABLE, 693d5a9f1bbSTakashi Iwai enable ? 0x02 : 0x00); 694d5a9f1bbSTakashi Iwai } 695d5a9f1bbSTakashi Iwai 696352f7f91STakashi Iwai 697352f7f91STakashi Iwai /* 698352f7f91STakashi Iwai * Helper functions for creating mixer ctl elements 699352f7f91STakashi Iwai */ 700352f7f91STakashi Iwai 701352f7f91STakashi Iwai enum { 702352f7f91STakashi Iwai HDA_CTL_WIDGET_VOL, 703352f7f91STakashi Iwai HDA_CTL_WIDGET_MUTE, 704352f7f91STakashi Iwai HDA_CTL_BIND_MUTE, 705352f7f91STakashi Iwai }; 706352f7f91STakashi Iwai static const struct snd_kcontrol_new control_templates[] = { 707352f7f91STakashi Iwai HDA_CODEC_VOLUME(NULL, 0, 0, 0), 708352f7f91STakashi Iwai HDA_CODEC_MUTE(NULL, 0, 0, 0), 709352f7f91STakashi Iwai HDA_BIND_MUTE(NULL, 0, 0, 0), 710352f7f91STakashi Iwai }; 711352f7f91STakashi Iwai 712352f7f91STakashi Iwai /* add dynamic controls from template */ 713352f7f91STakashi Iwai static int add_control(struct hda_gen_spec *spec, int type, const char *name, 714352f7f91STakashi Iwai int cidx, unsigned long val) 715352f7f91STakashi Iwai { 716352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 717352f7f91STakashi Iwai 71812c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]); 719352f7f91STakashi Iwai if (!knew) 720352f7f91STakashi Iwai return -ENOMEM; 721352f7f91STakashi Iwai knew->index = cidx; 722352f7f91STakashi Iwai if (get_amp_nid_(val)) 723352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 724352f7f91STakashi Iwai knew->private_value = val; 725352f7f91STakashi Iwai return 0; 726352f7f91STakashi Iwai } 727352f7f91STakashi Iwai 728352f7f91STakashi Iwai static int add_control_with_pfx(struct hda_gen_spec *spec, int type, 729352f7f91STakashi Iwai const char *pfx, const char *dir, 730352f7f91STakashi Iwai const char *sfx, int cidx, unsigned long val) 731352f7f91STakashi Iwai { 732352f7f91STakashi Iwai char name[32]; 733352f7f91STakashi Iwai snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); 734352f7f91STakashi Iwai return add_control(spec, type, name, cidx, val); 735352f7f91STakashi Iwai } 736352f7f91STakashi Iwai 737352f7f91STakashi Iwai #define add_pb_vol_ctrl(spec, type, pfx, val) \ 738352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val) 739352f7f91STakashi Iwai #define add_pb_sw_ctrl(spec, type, pfx, val) \ 740352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val) 741352f7f91STakashi Iwai #define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \ 742352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val) 743352f7f91STakashi Iwai #define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ 744352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) 745352f7f91STakashi Iwai 746352f7f91STakashi Iwai static int add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx, 747352f7f91STakashi Iwai unsigned int chs, struct nid_path *path) 748352f7f91STakashi Iwai { 749352f7f91STakashi Iwai unsigned int val; 750352f7f91STakashi Iwai if (!path) 751352f7f91STakashi Iwai return 0; 752352f7f91STakashi Iwai val = path->ctls[NID_PATH_VOL_CTL]; 753352f7f91STakashi Iwai if (!val) 754352f7f91STakashi Iwai return 0; 755352f7f91STakashi Iwai val = amp_val_replace_channels(val, chs); 756352f7f91STakashi Iwai return __add_pb_vol_ctrl(codec->spec, HDA_CTL_WIDGET_VOL, pfx, cidx, val); 757352f7f91STakashi Iwai } 758352f7f91STakashi Iwai 759352f7f91STakashi Iwai /* return the channel bits suitable for the given path->ctls[] */ 760352f7f91STakashi Iwai static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path, 761352f7f91STakashi Iwai int type) 762352f7f91STakashi Iwai { 763352f7f91STakashi Iwai int chs = 1; /* mono (left only) */ 764352f7f91STakashi Iwai if (path) { 765352f7f91STakashi Iwai hda_nid_t nid = get_amp_nid_(path->ctls[type]); 766352f7f91STakashi Iwai if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO)) 767352f7f91STakashi Iwai chs = 3; /* stereo */ 768352f7f91STakashi Iwai } 769352f7f91STakashi Iwai return chs; 770352f7f91STakashi Iwai } 771352f7f91STakashi Iwai 772352f7f91STakashi Iwai static int add_stereo_vol(struct hda_codec *codec, const char *pfx, int cidx, 773352f7f91STakashi Iwai struct nid_path *path) 774352f7f91STakashi Iwai { 775352f7f91STakashi Iwai int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL); 776352f7f91STakashi Iwai return add_vol_ctl(codec, pfx, cidx, chs, path); 777352f7f91STakashi Iwai } 778352f7f91STakashi Iwai 779352f7f91STakashi Iwai /* create a mute-switch for the given mixer widget; 780352f7f91STakashi Iwai * if it has multiple sources (e.g. DAC and loopback), create a bind-mute 781352f7f91STakashi Iwai */ 782352f7f91STakashi Iwai static int add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx, 783352f7f91STakashi Iwai unsigned int chs, struct nid_path *path) 784352f7f91STakashi Iwai { 785352f7f91STakashi Iwai unsigned int val; 786352f7f91STakashi Iwai int type = HDA_CTL_WIDGET_MUTE; 787352f7f91STakashi Iwai 788352f7f91STakashi Iwai if (!path) 789352f7f91STakashi Iwai return 0; 790352f7f91STakashi Iwai val = path->ctls[NID_PATH_MUTE_CTL]; 791352f7f91STakashi Iwai if (!val) 792352f7f91STakashi Iwai return 0; 793352f7f91STakashi Iwai val = amp_val_replace_channels(val, chs); 794352f7f91STakashi Iwai if (get_amp_direction_(val) == HDA_INPUT) { 795352f7f91STakashi Iwai hda_nid_t nid = get_amp_nid_(val); 796352f7f91STakashi Iwai int nums = snd_hda_get_num_conns(codec, nid); 797352f7f91STakashi Iwai if (nums > 1) { 798352f7f91STakashi Iwai type = HDA_CTL_BIND_MUTE; 799352f7f91STakashi Iwai val |= nums << 19; 800352f7f91STakashi Iwai } 801352f7f91STakashi Iwai } 802352f7f91STakashi Iwai return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val); 803352f7f91STakashi Iwai } 804352f7f91STakashi Iwai 805352f7f91STakashi Iwai static int add_stereo_sw(struct hda_codec *codec, const char *pfx, 806352f7f91STakashi Iwai int cidx, struct nid_path *path) 807352f7f91STakashi Iwai { 808352f7f91STakashi Iwai int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL); 809352f7f91STakashi Iwai return add_sw_ctl(codec, pfx, cidx, chs, path); 810352f7f91STakashi Iwai } 811352f7f91STakashi Iwai 812352f7f91STakashi Iwai static const char * const channel_name[4] = { 813352f7f91STakashi Iwai "Front", "Surround", "CLFE", "Side" 814352f7f91STakashi Iwai }; 815352f7f91STakashi Iwai 816352f7f91STakashi Iwai /* give some appropriate ctl name prefix for the given line out channel */ 817352f7f91STakashi Iwai static const char *get_line_out_pfx(struct hda_gen_spec *spec, int ch, 818352f7f91STakashi Iwai bool can_be_master, int *index) 819352f7f91STakashi Iwai { 820352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 821352f7f91STakashi Iwai 822352f7f91STakashi Iwai *index = 0; 823352f7f91STakashi Iwai if (cfg->line_outs == 1 && !spec->multi_ios && 824352f7f91STakashi Iwai !cfg->hp_outs && !cfg->speaker_outs && can_be_master) 825352f7f91STakashi Iwai return spec->vmaster_mute.hook ? "PCM" : "Master"; 826352f7f91STakashi Iwai 827352f7f91STakashi Iwai /* if there is really a single DAC used in the whole output paths, 828352f7f91STakashi Iwai * use it master (or "PCM" if a vmaster hook is present) 829352f7f91STakashi Iwai */ 830352f7f91STakashi Iwai if (spec->multiout.num_dacs == 1 && !spec->mixer_nid && 831352f7f91STakashi Iwai !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0]) 832352f7f91STakashi Iwai return spec->vmaster_mute.hook ? "PCM" : "Master"; 833352f7f91STakashi Iwai 834352f7f91STakashi Iwai switch (cfg->line_out_type) { 835352f7f91STakashi Iwai case AUTO_PIN_SPEAKER_OUT: 836352f7f91STakashi Iwai if (cfg->line_outs == 1) 837352f7f91STakashi Iwai return "Speaker"; 838352f7f91STakashi Iwai if (cfg->line_outs == 2) 839352f7f91STakashi Iwai return ch ? "Bass Speaker" : "Speaker"; 840352f7f91STakashi Iwai break; 841352f7f91STakashi Iwai case AUTO_PIN_HP_OUT: 842352f7f91STakashi Iwai /* for multi-io case, only the primary out */ 843352f7f91STakashi Iwai if (ch && spec->multi_ios) 844352f7f91STakashi Iwai break; 845352f7f91STakashi Iwai *index = ch; 846352f7f91STakashi Iwai return "Headphone"; 847352f7f91STakashi Iwai default: 848352f7f91STakashi Iwai if (cfg->line_outs == 1 && !spec->multi_ios) 849352f7f91STakashi Iwai return "PCM"; 850352f7f91STakashi Iwai break; 851352f7f91STakashi Iwai } 852352f7f91STakashi Iwai if (ch >= ARRAY_SIZE(channel_name)) { 853352f7f91STakashi Iwai snd_BUG(); 854352f7f91STakashi Iwai return "PCM"; 855352f7f91STakashi Iwai } 856352f7f91STakashi Iwai 857352f7f91STakashi Iwai return channel_name[ch]; 858352f7f91STakashi Iwai } 859352f7f91STakashi Iwai 860352f7f91STakashi Iwai /* 861352f7f91STakashi Iwai * Parse output paths 862352f7f91STakashi Iwai */ 863352f7f91STakashi Iwai 864352f7f91STakashi Iwai /* badness definition */ 865352f7f91STakashi Iwai enum { 866352f7f91STakashi Iwai /* No primary DAC is found for the main output */ 867352f7f91STakashi Iwai BAD_NO_PRIMARY_DAC = 0x10000, 868352f7f91STakashi Iwai /* No DAC is found for the extra output */ 869352f7f91STakashi Iwai BAD_NO_DAC = 0x4000, 870352f7f91STakashi Iwai /* No possible multi-ios */ 871352f7f91STakashi Iwai BAD_MULTI_IO = 0x103, 872352f7f91STakashi Iwai /* No individual DAC for extra output */ 873352f7f91STakashi Iwai BAD_NO_EXTRA_DAC = 0x102, 874352f7f91STakashi Iwai /* No individual DAC for extra surrounds */ 875352f7f91STakashi Iwai BAD_NO_EXTRA_SURR_DAC = 0x101, 876352f7f91STakashi Iwai /* Primary DAC shared with main surrounds */ 877352f7f91STakashi Iwai BAD_SHARED_SURROUND = 0x100, 878352f7f91STakashi Iwai /* Primary DAC shared with main CLFE */ 879352f7f91STakashi Iwai BAD_SHARED_CLFE = 0x10, 880352f7f91STakashi Iwai /* Primary DAC shared with extra surrounds */ 881352f7f91STakashi Iwai BAD_SHARED_EXTRA_SURROUND = 0x10, 882352f7f91STakashi Iwai /* Volume widget is shared */ 883352f7f91STakashi Iwai BAD_SHARED_VOL = 0x10, 884352f7f91STakashi Iwai }; 885352f7f91STakashi Iwai 8860e614dd0STakashi Iwai /* look for widgets in the given path which are appropriate for 887352f7f91STakashi Iwai * volume and mute controls, and assign the values to ctls[]. 888352f7f91STakashi Iwai * 889352f7f91STakashi Iwai * When no appropriate widget is found in the path, the badness value 890352f7f91STakashi Iwai * is incremented depending on the situation. The function returns the 891352f7f91STakashi Iwai * total badness for both volume and mute controls. 892352f7f91STakashi Iwai */ 8930e614dd0STakashi Iwai static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path) 894352f7f91STakashi Iwai { 895352f7f91STakashi Iwai hda_nid_t nid; 896352f7f91STakashi Iwai unsigned int val; 897352f7f91STakashi Iwai int badness = 0; 898352f7f91STakashi Iwai 899352f7f91STakashi Iwai if (!path) 900352f7f91STakashi Iwai return BAD_SHARED_VOL * 2; 9010e614dd0STakashi Iwai 9020e614dd0STakashi Iwai if (path->ctls[NID_PATH_VOL_CTL] || 9030e614dd0STakashi Iwai path->ctls[NID_PATH_MUTE_CTL]) 9040e614dd0STakashi Iwai return 0; /* already evaluated */ 9050e614dd0STakashi Iwai 906352f7f91STakashi Iwai nid = look_for_out_vol_nid(codec, path); 907352f7f91STakashi Iwai if (nid) { 908352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 909352f7f91STakashi Iwai if (is_ctl_used(codec, val, NID_PATH_VOL_CTL)) 910352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 911352f7f91STakashi Iwai else 912352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = val; 913352f7f91STakashi Iwai } else 914352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 915352f7f91STakashi Iwai nid = look_for_out_mute_nid(codec, path); 916352f7f91STakashi Iwai if (nid) { 917352f7f91STakashi Iwai unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid)); 918352f7f91STakashi Iwai if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT || 919352f7f91STakashi Iwai nid_has_mute(codec, nid, HDA_OUTPUT)) 920352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 921352f7f91STakashi Iwai else 922352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); 923352f7f91STakashi Iwai if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL)) 924352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 925352f7f91STakashi Iwai else 926352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = val; 927352f7f91STakashi Iwai } else 928352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 929352f7f91STakashi Iwai return badness; 930352f7f91STakashi Iwai } 931352f7f91STakashi Iwai 932352f7f91STakashi Iwai struct badness_table { 933352f7f91STakashi Iwai int no_primary_dac; /* no primary DAC */ 934352f7f91STakashi Iwai int no_dac; /* no secondary DACs */ 935352f7f91STakashi Iwai int shared_primary; /* primary DAC is shared with main output */ 936352f7f91STakashi Iwai int shared_surr; /* secondary DAC shared with main or primary */ 937352f7f91STakashi Iwai int shared_clfe; /* third DAC shared with main or primary */ 938352f7f91STakashi Iwai int shared_surr_main; /* secondary DAC sahred with main/DAC0 */ 939352f7f91STakashi Iwai }; 940352f7f91STakashi Iwai 941352f7f91STakashi Iwai static struct badness_table main_out_badness = { 942352f7f91STakashi Iwai .no_primary_dac = BAD_NO_PRIMARY_DAC, 943352f7f91STakashi Iwai .no_dac = BAD_NO_DAC, 944352f7f91STakashi Iwai .shared_primary = BAD_NO_PRIMARY_DAC, 945352f7f91STakashi Iwai .shared_surr = BAD_SHARED_SURROUND, 946352f7f91STakashi Iwai .shared_clfe = BAD_SHARED_CLFE, 947352f7f91STakashi Iwai .shared_surr_main = BAD_SHARED_SURROUND, 948352f7f91STakashi Iwai }; 949352f7f91STakashi Iwai 950352f7f91STakashi Iwai static struct badness_table extra_out_badness = { 951352f7f91STakashi Iwai .no_primary_dac = BAD_NO_DAC, 952352f7f91STakashi Iwai .no_dac = BAD_NO_DAC, 953352f7f91STakashi Iwai .shared_primary = BAD_NO_EXTRA_DAC, 954352f7f91STakashi Iwai .shared_surr = BAD_SHARED_EXTRA_SURROUND, 955352f7f91STakashi Iwai .shared_clfe = BAD_SHARED_EXTRA_SURROUND, 956352f7f91STakashi Iwai .shared_surr_main = BAD_NO_EXTRA_SURR_DAC, 957352f7f91STakashi Iwai }; 958352f7f91STakashi Iwai 9597385df61STakashi Iwai /* get the DAC of the primary output corresponding to the given array index */ 9607385df61STakashi Iwai static hda_nid_t get_primary_out(struct hda_codec *codec, int idx) 9617385df61STakashi Iwai { 9627385df61STakashi Iwai struct hda_gen_spec *spec = codec->spec; 9637385df61STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 9647385df61STakashi Iwai 9657385df61STakashi Iwai if (cfg->line_outs > idx) 9667385df61STakashi Iwai return spec->private_dac_nids[idx]; 9677385df61STakashi Iwai idx -= cfg->line_outs; 9687385df61STakashi Iwai if (spec->multi_ios > idx) 9697385df61STakashi Iwai return spec->multi_io[idx].dac; 9707385df61STakashi Iwai return 0; 9717385df61STakashi Iwai } 9727385df61STakashi Iwai 9737385df61STakashi Iwai /* return the DAC if it's reachable, otherwise zero */ 9747385df61STakashi Iwai static inline hda_nid_t try_dac(struct hda_codec *codec, 9757385df61STakashi Iwai hda_nid_t dac, hda_nid_t pin) 9767385df61STakashi Iwai { 9777385df61STakashi Iwai return is_reachable_path(codec, dac, pin) ? dac : 0; 9787385df61STakashi Iwai } 9797385df61STakashi Iwai 980352f7f91STakashi Iwai /* try to assign DACs to pins and return the resultant badness */ 981352f7f91STakashi Iwai static int try_assign_dacs(struct hda_codec *codec, int num_outs, 982352f7f91STakashi Iwai const hda_nid_t *pins, hda_nid_t *dacs, 983196c1766STakashi Iwai int *path_idx, 984352f7f91STakashi Iwai const struct badness_table *bad) 985352f7f91STakashi Iwai { 986352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 987352f7f91STakashi Iwai int i, j; 988352f7f91STakashi Iwai int badness = 0; 989352f7f91STakashi Iwai hda_nid_t dac; 990352f7f91STakashi Iwai 991352f7f91STakashi Iwai if (!num_outs) 992352f7f91STakashi Iwai return 0; 993352f7f91STakashi Iwai 994352f7f91STakashi Iwai for (i = 0; i < num_outs; i++) { 9950c8c0f56STakashi Iwai struct nid_path *path; 996352f7f91STakashi Iwai hda_nid_t pin = pins[i]; 9971e0b5286STakashi Iwai 9980e614dd0STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx[i]); 9990e614dd0STakashi Iwai if (path) { 10000e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path); 10011e0b5286STakashi Iwai continue; 10021e0b5286STakashi Iwai } 10031e0b5286STakashi Iwai 1004352f7f91STakashi Iwai dacs[i] = look_for_dac(codec, pin, false); 1005352f7f91STakashi Iwai if (!dacs[i] && !i) { 1006980428ceSTakashi Iwai /* try to steal the DAC of surrounds for the front */ 1007352f7f91STakashi Iwai for (j = 1; j < num_outs; j++) { 1008352f7f91STakashi Iwai if (is_reachable_path(codec, dacs[j], pin)) { 1009352f7f91STakashi Iwai dacs[0] = dacs[j]; 1010352f7f91STakashi Iwai dacs[j] = 0; 1011980428ceSTakashi Iwai invalidate_nid_path(codec, path_idx[j]); 1012196c1766STakashi Iwai path_idx[j] = 0; 1013352f7f91STakashi Iwai break; 1014352f7f91STakashi Iwai } 1015352f7f91STakashi Iwai } 1016352f7f91STakashi Iwai } 1017352f7f91STakashi Iwai dac = dacs[i]; 1018352f7f91STakashi Iwai if (!dac) { 10197385df61STakashi Iwai if (num_outs > 2) 10207385df61STakashi Iwai dac = try_dac(codec, get_primary_out(codec, i), pin); 10217385df61STakashi Iwai if (!dac) 10227385df61STakashi Iwai dac = try_dac(codec, dacs[0], pin); 10237385df61STakashi Iwai if (!dac) 10247385df61STakashi Iwai dac = try_dac(codec, get_primary_out(codec, i), pin); 1025352f7f91STakashi Iwai if (dac) { 1026352f7f91STakashi Iwai if (!i) 1027352f7f91STakashi Iwai badness += bad->shared_primary; 1028352f7f91STakashi Iwai else if (i == 1) 1029352f7f91STakashi Iwai badness += bad->shared_surr; 1030352f7f91STakashi Iwai else 1031352f7f91STakashi Iwai badness += bad->shared_clfe; 1032352f7f91STakashi Iwai } else if (is_reachable_path(codec, spec->private_dac_nids[0], pin)) { 1033352f7f91STakashi Iwai dac = spec->private_dac_nids[0]; 1034352f7f91STakashi Iwai badness += bad->shared_surr_main; 1035352f7f91STakashi Iwai } else if (!i) 1036352f7f91STakashi Iwai badness += bad->no_primary_dac; 1037352f7f91STakashi Iwai else 1038352f7f91STakashi Iwai badness += bad->no_dac; 1039352f7f91STakashi Iwai } 10403ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, -spec->mixer_nid); 1041117688a9STakashi Iwai if (!path && !i && spec->mixer_nid) { 1042b3a8c745STakashi Iwai /* try with aamix */ 10433ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, 0); 1044b3a8c745STakashi Iwai } 10450c8c0f56STakashi Iwai if (!path) 1046352f7f91STakashi Iwai dac = dacs[i] = 0; 1047e1284af7STakashi Iwai else { 10480c8c0f56STakashi Iwai print_nid_path("output", path); 1049e1284af7STakashi Iwai path->active = true; 1050196c1766STakashi Iwai path_idx[i] = snd_hda_get_path_idx(codec, path); 10510e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path); 1052e1284af7STakashi Iwai } 1053352f7f91STakashi Iwai } 1054352f7f91STakashi Iwai 1055352f7f91STakashi Iwai return badness; 1056352f7f91STakashi Iwai } 1057352f7f91STakashi Iwai 1058352f7f91STakashi Iwai /* return NID if the given pin has only a single connection to a certain DAC */ 1059352f7f91STakashi Iwai static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) 1060352f7f91STakashi Iwai { 1061352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1062352f7f91STakashi Iwai int i; 1063352f7f91STakashi Iwai hda_nid_t nid_found = 0; 1064352f7f91STakashi Iwai 1065352f7f91STakashi Iwai for (i = 0; i < spec->num_all_dacs; i++) { 1066352f7f91STakashi Iwai hda_nid_t nid = spec->all_dacs[i]; 1067352f7f91STakashi Iwai if (!nid || is_dac_already_used(codec, nid)) 1068352f7f91STakashi Iwai continue; 1069352f7f91STakashi Iwai if (is_reachable_path(codec, nid, pin)) { 1070352f7f91STakashi Iwai if (nid_found) 1071352f7f91STakashi Iwai return 0; 1072352f7f91STakashi Iwai nid_found = nid; 1073352f7f91STakashi Iwai } 1074352f7f91STakashi Iwai } 1075352f7f91STakashi Iwai return nid_found; 1076352f7f91STakashi Iwai } 1077352f7f91STakashi Iwai 1078352f7f91STakashi Iwai /* check whether the given pin can be a multi-io pin */ 1079352f7f91STakashi Iwai static bool can_be_multiio_pin(struct hda_codec *codec, 1080352f7f91STakashi Iwai unsigned int location, hda_nid_t nid) 1081352f7f91STakashi Iwai { 1082352f7f91STakashi Iwai unsigned int defcfg, caps; 1083352f7f91STakashi Iwai 1084352f7f91STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, nid); 1085352f7f91STakashi Iwai if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) 1086352f7f91STakashi Iwai return false; 1087352f7f91STakashi Iwai if (location && get_defcfg_location(defcfg) != location) 1088352f7f91STakashi Iwai return false; 1089352f7f91STakashi Iwai caps = snd_hda_query_pin_caps(codec, nid); 1090352f7f91STakashi Iwai if (!(caps & AC_PINCAP_OUT)) 1091352f7f91STakashi Iwai return false; 1092352f7f91STakashi Iwai return true; 1093352f7f91STakashi Iwai } 1094352f7f91STakashi Iwai 1095e22aab7dSTakashi Iwai /* count the number of input pins that are capable to be multi-io */ 1096e22aab7dSTakashi Iwai static int count_multiio_pins(struct hda_codec *codec, hda_nid_t reference_pin) 1097e22aab7dSTakashi Iwai { 1098e22aab7dSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 1099e22aab7dSTakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1100e22aab7dSTakashi Iwai unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); 1101e22aab7dSTakashi Iwai unsigned int location = get_defcfg_location(defcfg); 1102e22aab7dSTakashi Iwai int type, i; 1103e22aab7dSTakashi Iwai int num_pins = 0; 1104e22aab7dSTakashi Iwai 1105e22aab7dSTakashi Iwai for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { 1106e22aab7dSTakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 1107e22aab7dSTakashi Iwai if (cfg->inputs[i].type != type) 1108e22aab7dSTakashi Iwai continue; 1109e22aab7dSTakashi Iwai if (can_be_multiio_pin(codec, location, 1110e22aab7dSTakashi Iwai cfg->inputs[i].pin)) 1111e22aab7dSTakashi Iwai num_pins++; 1112e22aab7dSTakashi Iwai } 1113e22aab7dSTakashi Iwai } 1114e22aab7dSTakashi Iwai return num_pins; 1115e22aab7dSTakashi Iwai } 1116e22aab7dSTakashi Iwai 1117352f7f91STakashi Iwai /* 1118352f7f91STakashi Iwai * multi-io helper 1119352f7f91STakashi Iwai * 1120352f7f91STakashi Iwai * When hardwired is set, try to fill ony hardwired pins, and returns 1121352f7f91STakashi Iwai * zero if any pins are filled, non-zero if nothing found. 1122352f7f91STakashi Iwai * When hardwired is off, try to fill possible input pins, and returns 1123352f7f91STakashi Iwai * the badness value. 1124352f7f91STakashi Iwai */ 1125352f7f91STakashi Iwai static int fill_multi_ios(struct hda_codec *codec, 1126352f7f91STakashi Iwai hda_nid_t reference_pin, 1127e22aab7dSTakashi Iwai bool hardwired) 1128352f7f91STakashi Iwai { 1129352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1130352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1131e22aab7dSTakashi Iwai int type, i, j, num_pins, old_pins; 1132352f7f91STakashi Iwai unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); 1133352f7f91STakashi Iwai unsigned int location = get_defcfg_location(defcfg); 1134352f7f91STakashi Iwai int badness = 0; 11350e614dd0STakashi Iwai struct nid_path *path; 1136352f7f91STakashi Iwai 1137352f7f91STakashi Iwai old_pins = spec->multi_ios; 1138352f7f91STakashi Iwai if (old_pins >= 2) 1139352f7f91STakashi Iwai goto end_fill; 1140352f7f91STakashi Iwai 1141e22aab7dSTakashi Iwai num_pins = count_multiio_pins(codec, reference_pin); 1142352f7f91STakashi Iwai if (num_pins < 2) 1143352f7f91STakashi Iwai goto end_fill; 1144352f7f91STakashi Iwai 1145352f7f91STakashi Iwai for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { 1146352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 1147352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 1148352f7f91STakashi Iwai hda_nid_t dac = 0; 1149352f7f91STakashi Iwai 1150352f7f91STakashi Iwai if (cfg->inputs[i].type != type) 1151352f7f91STakashi Iwai continue; 1152352f7f91STakashi Iwai if (!can_be_multiio_pin(codec, location, nid)) 1153352f7f91STakashi Iwai continue; 1154352f7f91STakashi Iwai for (j = 0; j < spec->multi_ios; j++) { 1155352f7f91STakashi Iwai if (nid == spec->multi_io[j].pin) 1156352f7f91STakashi Iwai break; 1157352f7f91STakashi Iwai } 1158352f7f91STakashi Iwai if (j < spec->multi_ios) 1159352f7f91STakashi Iwai continue; 1160352f7f91STakashi Iwai 1161352f7f91STakashi Iwai if (hardwired) 1162352f7f91STakashi Iwai dac = get_dac_if_single(codec, nid); 1163352f7f91STakashi Iwai else if (!dac) 1164352f7f91STakashi Iwai dac = look_for_dac(codec, nid, false); 1165352f7f91STakashi Iwai if (!dac) { 1166352f7f91STakashi Iwai badness++; 1167352f7f91STakashi Iwai continue; 1168352f7f91STakashi Iwai } 11693ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, nid, 11703ca529d3STakashi Iwai -spec->mixer_nid); 11710c8c0f56STakashi Iwai if (!path) { 1172352f7f91STakashi Iwai badness++; 1173352f7f91STakashi Iwai continue; 1174352f7f91STakashi Iwai } 11750c8c0f56STakashi Iwai print_nid_path("multiio", path); 1176352f7f91STakashi Iwai spec->multi_io[spec->multi_ios].pin = nid; 1177352f7f91STakashi Iwai spec->multi_io[spec->multi_ios].dac = dac; 1178196c1766STakashi Iwai spec->out_paths[cfg->line_outs + spec->multi_ios] = 1179196c1766STakashi Iwai snd_hda_get_path_idx(codec, path); 1180352f7f91STakashi Iwai spec->multi_ios++; 1181352f7f91STakashi Iwai if (spec->multi_ios >= 2) 1182352f7f91STakashi Iwai break; 1183352f7f91STakashi Iwai } 1184352f7f91STakashi Iwai } 1185352f7f91STakashi Iwai end_fill: 1186352f7f91STakashi Iwai if (badness) 1187352f7f91STakashi Iwai badness = BAD_MULTI_IO; 1188352f7f91STakashi Iwai if (old_pins == spec->multi_ios) { 1189352f7f91STakashi Iwai if (hardwired) 1190352f7f91STakashi Iwai return 1; /* nothing found */ 1191352f7f91STakashi Iwai else 1192352f7f91STakashi Iwai return badness; /* no badness if nothing found */ 1193352f7f91STakashi Iwai } 1194352f7f91STakashi Iwai if (!hardwired && spec->multi_ios < 2) { 1195352f7f91STakashi Iwai /* cancel newly assigned paths */ 1196352f7f91STakashi Iwai spec->paths.used -= spec->multi_ios - old_pins; 1197352f7f91STakashi Iwai spec->multi_ios = old_pins; 1198352f7f91STakashi Iwai return badness; 1199352f7f91STakashi Iwai } 1200352f7f91STakashi Iwai 1201352f7f91STakashi Iwai /* assign volume and mute controls */ 12020e614dd0STakashi Iwai for (i = old_pins; i < spec->multi_ios; i++) { 12030e614dd0STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[cfg->line_outs + i]); 12040e614dd0STakashi Iwai badness += assign_out_path_ctls(codec, path); 12050e614dd0STakashi Iwai } 1206352f7f91STakashi Iwai 1207352f7f91STakashi Iwai return badness; 1208352f7f91STakashi Iwai } 1209352f7f91STakashi Iwai 1210352f7f91STakashi Iwai /* map DACs for all pins in the list if they are single connections */ 1211352f7f91STakashi Iwai static bool map_singles(struct hda_codec *codec, int outs, 1212196c1766STakashi Iwai const hda_nid_t *pins, hda_nid_t *dacs, int *path_idx) 1213352f7f91STakashi Iwai { 1214b3a8c745STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1215352f7f91STakashi Iwai int i; 1216352f7f91STakashi Iwai bool found = false; 1217352f7f91STakashi Iwai for (i = 0; i < outs; i++) { 12180c8c0f56STakashi Iwai struct nid_path *path; 1219352f7f91STakashi Iwai hda_nid_t dac; 1220352f7f91STakashi Iwai if (dacs[i]) 1221352f7f91STakashi Iwai continue; 1222352f7f91STakashi Iwai dac = get_dac_if_single(codec, pins[i]); 1223352f7f91STakashi Iwai if (!dac) 1224352f7f91STakashi Iwai continue; 12253ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pins[i], 12263ca529d3STakashi Iwai -spec->mixer_nid); 1227117688a9STakashi Iwai if (!path && !i && spec->mixer_nid) 12283ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dac, pins[i], 0); 12290c8c0f56STakashi Iwai if (path) { 1230352f7f91STakashi Iwai dacs[i] = dac; 1231352f7f91STakashi Iwai found = true; 12320c8c0f56STakashi Iwai print_nid_path("output", path); 1233e1284af7STakashi Iwai path->active = true; 1234196c1766STakashi Iwai path_idx[i] = snd_hda_get_path_idx(codec, path); 1235352f7f91STakashi Iwai } 1236352f7f91STakashi Iwai } 1237352f7f91STakashi Iwai return found; 1238352f7f91STakashi Iwai } 1239352f7f91STakashi Iwai 1240c30aa7b2STakashi Iwai /* create a new path including aamix if available, and return its index */ 1241c30aa7b2STakashi Iwai static int check_aamix_out_path(struct hda_codec *codec, int path_idx) 1242c30aa7b2STakashi Iwai { 12433ca529d3STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1244c30aa7b2STakashi Iwai struct nid_path *path; 1245c30aa7b2STakashi Iwai 1246c30aa7b2STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 12473ca529d3STakashi Iwai if (!path || !path->depth || 12483ca529d3STakashi Iwai is_nid_contained(path, spec->mixer_nid)) 1249c30aa7b2STakashi Iwai return 0; 1250c30aa7b2STakashi Iwai path = snd_hda_add_new_path(codec, path->path[0], 1251c30aa7b2STakashi Iwai path->path[path->depth - 1], 12523ca529d3STakashi Iwai spec->mixer_nid); 1253c30aa7b2STakashi Iwai if (!path) 1254c30aa7b2STakashi Iwai return 0; 1255c30aa7b2STakashi Iwai print_nid_path("output-aamix", path); 1256c30aa7b2STakashi Iwai path->active = false; /* unused as default */ 1257c30aa7b2STakashi Iwai return snd_hda_get_path_idx(codec, path); 1258c30aa7b2STakashi Iwai } 1259c30aa7b2STakashi Iwai 1260a07a949bSTakashi Iwai /* fill the empty entries in the dac array for speaker/hp with the 1261a07a949bSTakashi Iwai * shared dac pointed by the paths 1262a07a949bSTakashi Iwai */ 1263a07a949bSTakashi Iwai static void refill_shared_dacs(struct hda_codec *codec, int num_outs, 1264a07a949bSTakashi Iwai hda_nid_t *dacs, int *path_idx) 1265a07a949bSTakashi Iwai { 1266a07a949bSTakashi Iwai struct nid_path *path; 1267a07a949bSTakashi Iwai int i; 1268a07a949bSTakashi Iwai 1269a07a949bSTakashi Iwai for (i = 0; i < num_outs; i++) { 1270a07a949bSTakashi Iwai if (dacs[i]) 1271a07a949bSTakashi Iwai continue; 1272a07a949bSTakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx[i]); 1273a07a949bSTakashi Iwai if (!path) 1274a07a949bSTakashi Iwai continue; 1275a07a949bSTakashi Iwai dacs[i] = path->path[0]; 1276a07a949bSTakashi Iwai } 1277a07a949bSTakashi Iwai } 1278a07a949bSTakashi Iwai 1279352f7f91STakashi Iwai /* fill in the dac_nids table from the parsed pin configuration */ 1280352f7f91STakashi Iwai static int fill_and_eval_dacs(struct hda_codec *codec, 1281352f7f91STakashi Iwai bool fill_hardwired, 1282352f7f91STakashi Iwai bool fill_mio_first) 1283352f7f91STakashi Iwai { 1284352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1285352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1286352f7f91STakashi Iwai int i, err, badness; 1287352f7f91STakashi Iwai 1288352f7f91STakashi Iwai /* set num_dacs once to full for look_for_dac() */ 1289352f7f91STakashi Iwai spec->multiout.num_dacs = cfg->line_outs; 1290352f7f91STakashi Iwai spec->multiout.dac_nids = spec->private_dac_nids; 1291352f7f91STakashi Iwai memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); 1292352f7f91STakashi Iwai memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid)); 1293352f7f91STakashi Iwai memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid)); 1294352f7f91STakashi Iwai spec->multi_ios = 0; 1295352f7f91STakashi Iwai snd_array_free(&spec->paths); 1296cd5be3f9STakashi Iwai 1297cd5be3f9STakashi Iwai /* clear path indices */ 1298cd5be3f9STakashi Iwai memset(spec->out_paths, 0, sizeof(spec->out_paths)); 1299cd5be3f9STakashi Iwai memset(spec->hp_paths, 0, sizeof(spec->hp_paths)); 1300cd5be3f9STakashi Iwai memset(spec->speaker_paths, 0, sizeof(spec->speaker_paths)); 1301cd5be3f9STakashi Iwai memset(spec->aamix_out_paths, 0, sizeof(spec->aamix_out_paths)); 1302cd5be3f9STakashi Iwai memset(spec->digout_paths, 0, sizeof(spec->digout_paths)); 1303c697b716STakashi Iwai memset(spec->input_paths, 0, sizeof(spec->input_paths)); 1304cd5be3f9STakashi Iwai memset(spec->loopback_paths, 0, sizeof(spec->loopback_paths)); 1305cd5be3f9STakashi Iwai memset(&spec->digin_path, 0, sizeof(spec->digin_path)); 1306cd5be3f9STakashi Iwai 1307352f7f91STakashi Iwai badness = 0; 1308352f7f91STakashi Iwai 1309352f7f91STakashi Iwai /* fill hard-wired DACs first */ 1310352f7f91STakashi Iwai if (fill_hardwired) { 1311352f7f91STakashi Iwai bool mapped; 1312352f7f91STakashi Iwai do { 1313352f7f91STakashi Iwai mapped = map_singles(codec, cfg->line_outs, 1314352f7f91STakashi Iwai cfg->line_out_pins, 1315196c1766STakashi Iwai spec->private_dac_nids, 1316196c1766STakashi Iwai spec->out_paths); 1317352f7f91STakashi Iwai mapped |= map_singles(codec, cfg->hp_outs, 1318352f7f91STakashi Iwai cfg->hp_pins, 1319196c1766STakashi Iwai spec->multiout.hp_out_nid, 1320196c1766STakashi Iwai spec->hp_paths); 1321352f7f91STakashi Iwai mapped |= map_singles(codec, cfg->speaker_outs, 1322352f7f91STakashi Iwai cfg->speaker_pins, 1323196c1766STakashi Iwai spec->multiout.extra_out_nid, 1324196c1766STakashi Iwai spec->speaker_paths); 1325352f7f91STakashi Iwai if (fill_mio_first && cfg->line_outs == 1 && 1326352f7f91STakashi Iwai cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1327e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], true); 1328352f7f91STakashi Iwai if (!err) 1329352f7f91STakashi Iwai mapped = true; 1330352f7f91STakashi Iwai } 1331352f7f91STakashi Iwai } while (mapped); 1332352f7f91STakashi Iwai } 1333352f7f91STakashi Iwai 1334352f7f91STakashi Iwai badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins, 1335196c1766STakashi Iwai spec->private_dac_nids, spec->out_paths, 1336352f7f91STakashi Iwai &main_out_badness); 1337352f7f91STakashi Iwai 1338352f7f91STakashi Iwai if (fill_mio_first && 1339352f7f91STakashi Iwai cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1340352f7f91STakashi Iwai /* try to fill multi-io first */ 1341e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], false); 1342352f7f91STakashi Iwai if (err < 0) 1343352f7f91STakashi Iwai return err; 1344352f7f91STakashi Iwai /* we don't count badness at this stage yet */ 1345352f7f91STakashi Iwai } 1346352f7f91STakashi Iwai 1347352f7f91STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) { 1348352f7f91STakashi Iwai err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins, 1349352f7f91STakashi Iwai spec->multiout.hp_out_nid, 1350196c1766STakashi Iwai spec->hp_paths, 1351352f7f91STakashi Iwai &extra_out_badness); 1352352f7f91STakashi Iwai if (err < 0) 1353352f7f91STakashi Iwai return err; 1354352f7f91STakashi Iwai badness += err; 1355352f7f91STakashi Iwai } 1356352f7f91STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1357352f7f91STakashi Iwai err = try_assign_dacs(codec, cfg->speaker_outs, 1358352f7f91STakashi Iwai cfg->speaker_pins, 1359352f7f91STakashi Iwai spec->multiout.extra_out_nid, 1360196c1766STakashi Iwai spec->speaker_paths, 1361352f7f91STakashi Iwai &extra_out_badness); 1362352f7f91STakashi Iwai if (err < 0) 1363352f7f91STakashi Iwai return err; 1364352f7f91STakashi Iwai badness += err; 1365352f7f91STakashi Iwai } 1366352f7f91STakashi Iwai if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1367e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], false); 1368352f7f91STakashi Iwai if (err < 0) 1369352f7f91STakashi Iwai return err; 1370352f7f91STakashi Iwai badness += err; 1371352f7f91STakashi Iwai } 1372e22aab7dSTakashi Iwai 1373c30aa7b2STakashi Iwai if (spec->mixer_nid) { 1374c30aa7b2STakashi Iwai spec->aamix_out_paths[0] = 1375c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->out_paths[0]); 1376c30aa7b2STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 1377c30aa7b2STakashi Iwai spec->aamix_out_paths[1] = 1378c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->hp_paths[0]); 1379c30aa7b2STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 1380c30aa7b2STakashi Iwai spec->aamix_out_paths[2] = 1381c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->speaker_paths[0]); 1382c30aa7b2STakashi Iwai } 1383c30aa7b2STakashi Iwai 1384e22aab7dSTakashi Iwai if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) 1385e22aab7dSTakashi Iwai if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2) 1386e22aab7dSTakashi Iwai spec->multi_ios = 1; /* give badness */ 1387352f7f91STakashi Iwai 1388a07a949bSTakashi Iwai /* re-count num_dacs and squash invalid entries */ 1389a07a949bSTakashi Iwai spec->multiout.num_dacs = 0; 1390a07a949bSTakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 1391a07a949bSTakashi Iwai if (spec->private_dac_nids[i]) 1392a07a949bSTakashi Iwai spec->multiout.num_dacs++; 1393a07a949bSTakashi Iwai else { 1394a07a949bSTakashi Iwai memmove(spec->private_dac_nids + i, 1395a07a949bSTakashi Iwai spec->private_dac_nids + i + 1, 1396a07a949bSTakashi Iwai sizeof(hda_nid_t) * (cfg->line_outs - i - 1)); 1397a07a949bSTakashi Iwai spec->private_dac_nids[cfg->line_outs - 1] = 0; 1398a07a949bSTakashi Iwai } 1399a07a949bSTakashi Iwai } 1400a07a949bSTakashi Iwai 1401a07a949bSTakashi Iwai spec->ext_channel_count = spec->min_channel_count = 1402a07a949bSTakashi Iwai spec->multiout.num_dacs; 1403a07a949bSTakashi Iwai 1404352f7f91STakashi Iwai if (spec->multi_ios == 2) { 1405352f7f91STakashi Iwai for (i = 0; i < 2; i++) 1406352f7f91STakashi Iwai spec->private_dac_nids[spec->multiout.num_dacs++] = 1407352f7f91STakashi Iwai spec->multi_io[i].dac; 1408352f7f91STakashi Iwai } else if (spec->multi_ios) { 1409352f7f91STakashi Iwai spec->multi_ios = 0; 1410352f7f91STakashi Iwai badness += BAD_MULTI_IO; 1411352f7f91STakashi Iwai } 1412352f7f91STakashi Iwai 1413a07a949bSTakashi Iwai /* re-fill the shared DAC for speaker / headphone */ 1414a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 1415a07a949bSTakashi Iwai refill_shared_dacs(codec, cfg->hp_outs, 1416a07a949bSTakashi Iwai spec->multiout.hp_out_nid, 1417a07a949bSTakashi Iwai spec->hp_paths); 1418a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 1419a07a949bSTakashi Iwai refill_shared_dacs(codec, cfg->speaker_outs, 1420a07a949bSTakashi Iwai spec->multiout.extra_out_nid, 1421a07a949bSTakashi Iwai spec->speaker_paths); 1422a07a949bSTakashi Iwai 14232c12c30dSTakashi Iwai /* set initial pinctl targets */ 14242c12c30dSTakashi Iwai set_pin_targets(codec, cfg->line_outs, cfg->line_out_pins, 14252c12c30dSTakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT ? PIN_HP : PIN_OUT); 14262c12c30dSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 14272c12c30dSTakashi Iwai set_pin_targets(codec, cfg->hp_outs, cfg->hp_pins, PIN_HP); 14282c12c30dSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 14292c12c30dSTakashi Iwai set_pin_targets(codec, cfg->speaker_outs, 14302c12c30dSTakashi Iwai cfg->speaker_pins, PIN_OUT); 14312c12c30dSTakashi Iwai 1432352f7f91STakashi Iwai return badness; 1433352f7f91STakashi Iwai } 1434352f7f91STakashi Iwai 1435352f7f91STakashi Iwai #define DEBUG_BADNESS 1436352f7f91STakashi Iwai 1437352f7f91STakashi Iwai #ifdef DEBUG_BADNESS 1438352f7f91STakashi Iwai #define debug_badness snd_printdd 1439352f7f91STakashi Iwai #else 1440352f7f91STakashi Iwai #define debug_badness(...) 1441352f7f91STakashi Iwai #endif 1442352f7f91STakashi Iwai 1443352f7f91STakashi Iwai static void debug_show_configs(struct hda_gen_spec *spec, struct auto_pin_cfg *cfg) 1444352f7f91STakashi Iwai { 1445352f7f91STakashi Iwai debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1446352f7f91STakashi Iwai cfg->line_out_pins[0], cfg->line_out_pins[1], 1447708122e8STakashi Iwai cfg->line_out_pins[2], cfg->line_out_pins[3], 1448352f7f91STakashi Iwai spec->multiout.dac_nids[0], 1449352f7f91STakashi Iwai spec->multiout.dac_nids[1], 1450352f7f91STakashi Iwai spec->multiout.dac_nids[2], 1451352f7f91STakashi Iwai spec->multiout.dac_nids[3]); 1452352f7f91STakashi Iwai if (spec->multi_ios > 0) 1453352f7f91STakashi Iwai debug_badness("multi_ios(%d) = %x/%x : %x/%x\n", 1454352f7f91STakashi Iwai spec->multi_ios, 1455352f7f91STakashi Iwai spec->multi_io[0].pin, spec->multi_io[1].pin, 1456352f7f91STakashi Iwai spec->multi_io[0].dac, spec->multi_io[1].dac); 1457352f7f91STakashi Iwai debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1458352f7f91STakashi Iwai cfg->hp_pins[0], cfg->hp_pins[1], 1459708122e8STakashi Iwai cfg->hp_pins[2], cfg->hp_pins[3], 1460352f7f91STakashi Iwai spec->multiout.hp_out_nid[0], 1461352f7f91STakashi Iwai spec->multiout.hp_out_nid[1], 1462352f7f91STakashi Iwai spec->multiout.hp_out_nid[2], 1463352f7f91STakashi Iwai spec->multiout.hp_out_nid[3]); 1464352f7f91STakashi Iwai debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1465352f7f91STakashi Iwai cfg->speaker_pins[0], cfg->speaker_pins[1], 1466352f7f91STakashi Iwai cfg->speaker_pins[2], cfg->speaker_pins[3], 1467352f7f91STakashi Iwai spec->multiout.extra_out_nid[0], 1468352f7f91STakashi Iwai spec->multiout.extra_out_nid[1], 1469352f7f91STakashi Iwai spec->multiout.extra_out_nid[2], 1470352f7f91STakashi Iwai spec->multiout.extra_out_nid[3]); 1471352f7f91STakashi Iwai } 1472352f7f91STakashi Iwai 1473352f7f91STakashi Iwai /* find all available DACs of the codec */ 1474352f7f91STakashi Iwai static void fill_all_dac_nids(struct hda_codec *codec) 1475352f7f91STakashi Iwai { 1476352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1477352f7f91STakashi Iwai int i; 1478352f7f91STakashi Iwai hda_nid_t nid = codec->start_nid; 1479352f7f91STakashi Iwai 1480352f7f91STakashi Iwai spec->num_all_dacs = 0; 1481352f7f91STakashi Iwai memset(spec->all_dacs, 0, sizeof(spec->all_dacs)); 1482352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) { 1483352f7f91STakashi Iwai if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT) 1484352f7f91STakashi Iwai continue; 1485352f7f91STakashi Iwai if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) { 1486352f7f91STakashi Iwai snd_printk(KERN_ERR "hda: Too many DACs!\n"); 1487352f7f91STakashi Iwai break; 1488352f7f91STakashi Iwai } 1489352f7f91STakashi Iwai spec->all_dacs[spec->num_all_dacs++] = nid; 1490352f7f91STakashi Iwai } 1491352f7f91STakashi Iwai } 1492352f7f91STakashi Iwai 1493352f7f91STakashi Iwai static int parse_output_paths(struct hda_codec *codec) 1494352f7f91STakashi Iwai { 1495352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1496352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1497352f7f91STakashi Iwai struct auto_pin_cfg *best_cfg; 1498352f7f91STakashi Iwai int best_badness = INT_MAX; 1499352f7f91STakashi Iwai int badness; 1500352f7f91STakashi Iwai bool fill_hardwired = true, fill_mio_first = true; 1501352f7f91STakashi Iwai bool best_wired = true, best_mio = true; 1502352f7f91STakashi Iwai bool hp_spk_swapped = false; 1503352f7f91STakashi Iwai 1504352f7f91STakashi Iwai fill_all_dac_nids(codec); 1505352f7f91STakashi Iwai 1506352f7f91STakashi Iwai best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL); 1507352f7f91STakashi Iwai if (!best_cfg) 1508352f7f91STakashi Iwai return -ENOMEM; 1509352f7f91STakashi Iwai *best_cfg = *cfg; 1510352f7f91STakashi Iwai 1511352f7f91STakashi Iwai for (;;) { 1512352f7f91STakashi Iwai badness = fill_and_eval_dacs(codec, fill_hardwired, 1513352f7f91STakashi Iwai fill_mio_first); 1514352f7f91STakashi Iwai if (badness < 0) { 1515352f7f91STakashi Iwai kfree(best_cfg); 1516352f7f91STakashi Iwai return badness; 1517352f7f91STakashi Iwai } 1518352f7f91STakashi Iwai debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n", 1519352f7f91STakashi Iwai cfg->line_out_type, fill_hardwired, fill_mio_first, 1520352f7f91STakashi Iwai badness); 1521352f7f91STakashi Iwai debug_show_configs(spec, cfg); 1522352f7f91STakashi Iwai if (badness < best_badness) { 1523352f7f91STakashi Iwai best_badness = badness; 1524352f7f91STakashi Iwai *best_cfg = *cfg; 1525352f7f91STakashi Iwai best_wired = fill_hardwired; 1526352f7f91STakashi Iwai best_mio = fill_mio_first; 1527352f7f91STakashi Iwai } 1528352f7f91STakashi Iwai if (!badness) 1529352f7f91STakashi Iwai break; 1530352f7f91STakashi Iwai fill_mio_first = !fill_mio_first; 1531352f7f91STakashi Iwai if (!fill_mio_first) 1532352f7f91STakashi Iwai continue; 1533352f7f91STakashi Iwai fill_hardwired = !fill_hardwired; 1534352f7f91STakashi Iwai if (!fill_hardwired) 1535352f7f91STakashi Iwai continue; 1536352f7f91STakashi Iwai if (hp_spk_swapped) 1537352f7f91STakashi Iwai break; 1538352f7f91STakashi Iwai hp_spk_swapped = true; 1539352f7f91STakashi Iwai if (cfg->speaker_outs > 0 && 1540352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) { 1541352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs; 1542352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins, 1543352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 1544352f7f91STakashi Iwai cfg->line_outs = cfg->speaker_outs; 1545352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->speaker_pins, 1546352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 1547352f7f91STakashi Iwai cfg->speaker_outs = 0; 1548352f7f91STakashi Iwai memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); 1549352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; 1550352f7f91STakashi Iwai fill_hardwired = true; 1551352f7f91STakashi Iwai continue; 1552352f7f91STakashi Iwai } 1553352f7f91STakashi Iwai if (cfg->hp_outs > 0 && 1554352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { 1555352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 1556352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 1557352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 1558352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs; 1559352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins, 1560352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 1561352f7f91STakashi Iwai cfg->hp_outs = 0; 1562352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 1563352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT; 1564352f7f91STakashi Iwai fill_hardwired = true; 1565352f7f91STakashi Iwai continue; 1566352f7f91STakashi Iwai } 1567352f7f91STakashi Iwai break; 1568352f7f91STakashi Iwai } 1569352f7f91STakashi Iwai 1570352f7f91STakashi Iwai if (badness) { 15710c8c0f56STakashi Iwai debug_badness("==> restoring best_cfg\n"); 1572352f7f91STakashi Iwai *cfg = *best_cfg; 1573352f7f91STakashi Iwai fill_and_eval_dacs(codec, best_wired, best_mio); 1574352f7f91STakashi Iwai } 1575352f7f91STakashi Iwai debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n", 1576352f7f91STakashi Iwai cfg->line_out_type, best_wired, best_mio); 1577352f7f91STakashi Iwai debug_show_configs(spec, cfg); 1578352f7f91STakashi Iwai 1579352f7f91STakashi Iwai if (cfg->line_out_pins[0]) { 1580352f7f91STakashi Iwai struct nid_path *path; 1581196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]); 1582352f7f91STakashi Iwai if (path) 1583352f7f91STakashi Iwai spec->vmaster_nid = look_for_out_vol_nid(codec, path); 1584352f7f91STakashi Iwai } 1585352f7f91STakashi Iwai 1586352f7f91STakashi Iwai kfree(best_cfg); 1587352f7f91STakashi Iwai return 0; 1588352f7f91STakashi Iwai } 1589352f7f91STakashi Iwai 1590352f7f91STakashi Iwai /* add playback controls from the parsed DAC table */ 1591352f7f91STakashi Iwai static int create_multi_out_ctls(struct hda_codec *codec, 1592352f7f91STakashi Iwai const struct auto_pin_cfg *cfg) 1593352f7f91STakashi Iwai { 1594352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1595352f7f91STakashi Iwai int i, err, noutputs; 1596352f7f91STakashi Iwai 1597352f7f91STakashi Iwai noutputs = cfg->line_outs; 1598352f7f91STakashi Iwai if (spec->multi_ios > 0 && cfg->line_outs < 3) 1599352f7f91STakashi Iwai noutputs += spec->multi_ios; 1600352f7f91STakashi Iwai 1601352f7f91STakashi Iwai for (i = 0; i < noutputs; i++) { 1602352f7f91STakashi Iwai const char *name; 1603352f7f91STakashi Iwai int index; 1604352f7f91STakashi Iwai struct nid_path *path; 1605352f7f91STakashi Iwai 1606352f7f91STakashi Iwai if (i >= cfg->line_outs) { 1607352f7f91STakashi Iwai index = 0; 1608352f7f91STakashi Iwai name = channel_name[i]; 1609352f7f91STakashi Iwai } else { 1610352f7f91STakashi Iwai name = get_line_out_pfx(spec, i, true, &index); 1611352f7f91STakashi Iwai } 1612352f7f91STakashi Iwai 1613196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]); 1614352f7f91STakashi Iwai if (!path) 1615352f7f91STakashi Iwai continue; 1616352f7f91STakashi Iwai if (!name || !strcmp(name, "CLFE")) { 1617352f7f91STakashi Iwai /* Center/LFE */ 1618352f7f91STakashi Iwai err = add_vol_ctl(codec, "Center", 0, 1, path); 1619352f7f91STakashi Iwai if (err < 0) 1620352f7f91STakashi Iwai return err; 1621352f7f91STakashi Iwai err = add_vol_ctl(codec, "LFE", 0, 2, path); 1622352f7f91STakashi Iwai if (err < 0) 1623352f7f91STakashi Iwai return err; 1624352f7f91STakashi Iwai err = add_sw_ctl(codec, "Center", 0, 1, path); 1625352f7f91STakashi Iwai if (err < 0) 1626352f7f91STakashi Iwai return err; 1627352f7f91STakashi Iwai err = add_sw_ctl(codec, "LFE", 0, 2, path); 1628352f7f91STakashi Iwai if (err < 0) 1629352f7f91STakashi Iwai return err; 1630352f7f91STakashi Iwai } else { 1631352f7f91STakashi Iwai err = add_stereo_vol(codec, name, index, path); 1632352f7f91STakashi Iwai if (err < 0) 1633352f7f91STakashi Iwai return err; 1634352f7f91STakashi Iwai err = add_stereo_sw(codec, name, index, path); 1635352f7f91STakashi Iwai if (err < 0) 1636352f7f91STakashi Iwai return err; 1637352f7f91STakashi Iwai } 1638352f7f91STakashi Iwai } 1639352f7f91STakashi Iwai return 0; 1640352f7f91STakashi Iwai } 1641352f7f91STakashi Iwai 1642c2c80383STakashi Iwai static int create_extra_out(struct hda_codec *codec, int path_idx, 1643196c1766STakashi Iwai const char *pfx, int cidx) 1644352f7f91STakashi Iwai { 1645352f7f91STakashi Iwai struct nid_path *path; 1646352f7f91STakashi Iwai int err; 1647352f7f91STakashi Iwai 1648196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 1649352f7f91STakashi Iwai if (!path) 1650352f7f91STakashi Iwai return 0; 1651352f7f91STakashi Iwai err = add_stereo_vol(codec, pfx, cidx, path); 1652352f7f91STakashi Iwai if (err < 0) 1653352f7f91STakashi Iwai return err; 1654352f7f91STakashi Iwai err = add_stereo_sw(codec, pfx, cidx, path); 1655352f7f91STakashi Iwai if (err < 0) 1656352f7f91STakashi Iwai return err; 1657352f7f91STakashi Iwai return 0; 1658352f7f91STakashi Iwai } 1659352f7f91STakashi Iwai 1660352f7f91STakashi Iwai /* add playback controls for speaker and HP outputs */ 1661352f7f91STakashi Iwai static int create_extra_outs(struct hda_codec *codec, int num_pins, 1662196c1766STakashi Iwai const int *paths, const char *pfx) 1663352f7f91STakashi Iwai { 1664c2c80383STakashi Iwai int i; 1665352f7f91STakashi Iwai 1666352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 1667c2c80383STakashi Iwai const char *name; 1668c2c80383STakashi Iwai char tmp[44]; 1669c2c80383STakashi Iwai int err, idx = 0; 1670c2c80383STakashi Iwai 1671c2c80383STakashi Iwai if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) 1672c2c80383STakashi Iwai name = "Bass Speaker"; 1673c2c80383STakashi Iwai else if (num_pins >= 3) { 1674c2c80383STakashi Iwai snprintf(tmp, sizeof(tmp), "%s %s", 1675352f7f91STakashi Iwai pfx, channel_name[i]); 1676c2c80383STakashi Iwai name = tmp; 1677352f7f91STakashi Iwai } else { 1678c2c80383STakashi Iwai name = pfx; 1679c2c80383STakashi Iwai idx = i; 1680352f7f91STakashi Iwai } 1681c2c80383STakashi Iwai err = create_extra_out(codec, paths[i], name, idx); 1682352f7f91STakashi Iwai if (err < 0) 1683352f7f91STakashi Iwai return err; 1684352f7f91STakashi Iwai } 1685352f7f91STakashi Iwai return 0; 1686352f7f91STakashi Iwai } 1687352f7f91STakashi Iwai 1688352f7f91STakashi Iwai static int create_hp_out_ctls(struct hda_codec *codec) 1689352f7f91STakashi Iwai { 1690352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1691352f7f91STakashi Iwai return create_extra_outs(codec, spec->autocfg.hp_outs, 1692196c1766STakashi Iwai spec->hp_paths, 1693352f7f91STakashi Iwai "Headphone"); 1694352f7f91STakashi Iwai } 1695352f7f91STakashi Iwai 1696352f7f91STakashi Iwai static int create_speaker_out_ctls(struct hda_codec *codec) 1697352f7f91STakashi Iwai { 1698352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1699352f7f91STakashi Iwai return create_extra_outs(codec, spec->autocfg.speaker_outs, 1700196c1766STakashi Iwai spec->speaker_paths, 1701352f7f91STakashi Iwai "Speaker"); 1702352f7f91STakashi Iwai } 1703352f7f91STakashi Iwai 1704352f7f91STakashi Iwai /* 170538cf6f1aSTakashi Iwai * independent HP controls 170638cf6f1aSTakashi Iwai */ 170738cf6f1aSTakashi Iwai 170838cf6f1aSTakashi Iwai static int indep_hp_info(struct snd_kcontrol *kcontrol, 170938cf6f1aSTakashi Iwai struct snd_ctl_elem_info *uinfo) 171038cf6f1aSTakashi Iwai { 171138cf6f1aSTakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo); 171238cf6f1aSTakashi Iwai } 171338cf6f1aSTakashi Iwai 171438cf6f1aSTakashi Iwai static int indep_hp_get(struct snd_kcontrol *kcontrol, 171538cf6f1aSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 171638cf6f1aSTakashi Iwai { 171738cf6f1aSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 171838cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 171938cf6f1aSTakashi Iwai ucontrol->value.enumerated.item[0] = spec->indep_hp_enabled; 172038cf6f1aSTakashi Iwai return 0; 172138cf6f1aSTakashi Iwai } 172238cf6f1aSTakashi Iwai 172338cf6f1aSTakashi Iwai static int indep_hp_put(struct snd_kcontrol *kcontrol, 172438cf6f1aSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 172538cf6f1aSTakashi Iwai { 172638cf6f1aSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 172738cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 172838cf6f1aSTakashi Iwai unsigned int select = ucontrol->value.enumerated.item[0]; 172938cf6f1aSTakashi Iwai int ret = 0; 173038cf6f1aSTakashi Iwai 173138cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 173238cf6f1aSTakashi Iwai if (spec->active_streams) { 173338cf6f1aSTakashi Iwai ret = -EBUSY; 173438cf6f1aSTakashi Iwai goto unlock; 173538cf6f1aSTakashi Iwai } 173638cf6f1aSTakashi Iwai 173738cf6f1aSTakashi Iwai if (spec->indep_hp_enabled != select) { 173838cf6f1aSTakashi Iwai spec->indep_hp_enabled = select; 173938cf6f1aSTakashi Iwai if (spec->indep_hp_enabled) 174038cf6f1aSTakashi Iwai spec->multiout.hp_out_nid[0] = 0; 174138cf6f1aSTakashi Iwai else 174238cf6f1aSTakashi Iwai spec->multiout.hp_out_nid[0] = spec->alt_dac_nid; 174338cf6f1aSTakashi Iwai ret = 1; 174438cf6f1aSTakashi Iwai } 174538cf6f1aSTakashi Iwai unlock: 174638cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 174738cf6f1aSTakashi Iwai return ret; 174838cf6f1aSTakashi Iwai } 174938cf6f1aSTakashi Iwai 175038cf6f1aSTakashi Iwai static const struct snd_kcontrol_new indep_hp_ctl = { 175138cf6f1aSTakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 175238cf6f1aSTakashi Iwai .name = "Independent HP", 175338cf6f1aSTakashi Iwai .info = indep_hp_info, 175438cf6f1aSTakashi Iwai .get = indep_hp_get, 175538cf6f1aSTakashi Iwai .put = indep_hp_put, 175638cf6f1aSTakashi Iwai }; 175738cf6f1aSTakashi Iwai 175838cf6f1aSTakashi Iwai 175938cf6f1aSTakashi Iwai static int create_indep_hp_ctls(struct hda_codec *codec) 176038cf6f1aSTakashi Iwai { 176138cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 176238cf6f1aSTakashi Iwai 176338cf6f1aSTakashi Iwai if (!spec->indep_hp) 176438cf6f1aSTakashi Iwai return 0; 176538cf6f1aSTakashi Iwai if (!spec->multiout.hp_out_nid[0]) { 176638cf6f1aSTakashi Iwai spec->indep_hp = 0; 176738cf6f1aSTakashi Iwai return 0; 176838cf6f1aSTakashi Iwai } 176938cf6f1aSTakashi Iwai 177038cf6f1aSTakashi Iwai spec->indep_hp_enabled = false; 177138cf6f1aSTakashi Iwai spec->alt_dac_nid = spec->multiout.hp_out_nid[0]; 177238cf6f1aSTakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl)) 177338cf6f1aSTakashi Iwai return -ENOMEM; 177438cf6f1aSTakashi Iwai return 0; 177538cf6f1aSTakashi Iwai } 177638cf6f1aSTakashi Iwai 177738cf6f1aSTakashi Iwai /* 1778352f7f91STakashi Iwai * channel mode enum control 1779352f7f91STakashi Iwai */ 1780352f7f91STakashi Iwai 1781352f7f91STakashi Iwai static int ch_mode_info(struct snd_kcontrol *kcontrol, 1782352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 1783352f7f91STakashi Iwai { 1784352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1785352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1786a07a949bSTakashi Iwai int chs; 1787352f7f91STakashi Iwai 1788352f7f91STakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 1789352f7f91STakashi Iwai uinfo->count = 1; 1790352f7f91STakashi Iwai uinfo->value.enumerated.items = spec->multi_ios + 1; 1791352f7f91STakashi Iwai if (uinfo->value.enumerated.item > spec->multi_ios) 1792352f7f91STakashi Iwai uinfo->value.enumerated.item = spec->multi_ios; 1793a07a949bSTakashi Iwai chs = uinfo->value.enumerated.item * 2 + spec->min_channel_count; 1794a07a949bSTakashi Iwai sprintf(uinfo->value.enumerated.name, "%dch", chs); 1795352f7f91STakashi Iwai return 0; 1796352f7f91STakashi Iwai } 1797352f7f91STakashi Iwai 1798352f7f91STakashi Iwai static int ch_mode_get(struct snd_kcontrol *kcontrol, 1799352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1800352f7f91STakashi Iwai { 1801352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1802352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1803a07a949bSTakashi Iwai ucontrol->value.enumerated.item[0] = 1804a07a949bSTakashi Iwai (spec->ext_channel_count - spec->min_channel_count) / 2; 1805352f7f91STakashi Iwai return 0; 1806352f7f91STakashi Iwai } 1807352f7f91STakashi Iwai 1808196c1766STakashi Iwai static inline struct nid_path * 1809196c1766STakashi Iwai get_multiio_path(struct hda_codec *codec, int idx) 1810196c1766STakashi Iwai { 1811196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1812196c1766STakashi Iwai return snd_hda_get_path_from_idx(codec, 1813196c1766STakashi Iwai spec->out_paths[spec->autocfg.line_outs + idx]); 1814196c1766STakashi Iwai } 1815196c1766STakashi Iwai 1816352f7f91STakashi Iwai static int set_multi_io(struct hda_codec *codec, int idx, bool output) 1817352f7f91STakashi Iwai { 1818352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1819352f7f91STakashi Iwai hda_nid_t nid = spec->multi_io[idx].pin; 1820352f7f91STakashi Iwai struct nid_path *path; 1821352f7f91STakashi Iwai 1822196c1766STakashi Iwai path = get_multiio_path(codec, idx); 1823352f7f91STakashi Iwai if (!path) 1824352f7f91STakashi Iwai return -EINVAL; 1825352f7f91STakashi Iwai 1826352f7f91STakashi Iwai if (path->active == output) 1827352f7f91STakashi Iwai return 0; 1828352f7f91STakashi Iwai 1829352f7f91STakashi Iwai if (output) { 18302c12c30dSTakashi Iwai set_pin_target(codec, nid, PIN_OUT, true); 1831352f7f91STakashi Iwai snd_hda_activate_path(codec, path, true, true); 1832d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, true); 1833352f7f91STakashi Iwai } else { 1834d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, false); 1835352f7f91STakashi Iwai snd_hda_activate_path(codec, path, false, true); 18362c12c30dSTakashi Iwai set_pin_target(codec, nid, spec->multi_io[idx].ctl_in, true); 1837352f7f91STakashi Iwai } 1838a365fed9STakashi Iwai 1839a365fed9STakashi Iwai /* update jack retasking in case it modifies any of them */ 1840a365fed9STakashi Iwai snd_hda_gen_hp_automute(codec, NULL); 1841a365fed9STakashi Iwai snd_hda_gen_line_automute(codec, NULL); 1842a365fed9STakashi Iwai snd_hda_gen_mic_autoswitch(codec, NULL); 1843a365fed9STakashi Iwai 1844352f7f91STakashi Iwai return 0; 1845352f7f91STakashi Iwai } 1846352f7f91STakashi Iwai 1847352f7f91STakashi Iwai static int ch_mode_put(struct snd_kcontrol *kcontrol, 1848352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1849352f7f91STakashi Iwai { 1850352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1851352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1852352f7f91STakashi Iwai int i, ch; 1853352f7f91STakashi Iwai 1854352f7f91STakashi Iwai ch = ucontrol->value.enumerated.item[0]; 1855352f7f91STakashi Iwai if (ch < 0 || ch > spec->multi_ios) 1856352f7f91STakashi Iwai return -EINVAL; 1857a07a949bSTakashi Iwai if (ch == (spec->ext_channel_count - spec->min_channel_count) / 2) 1858352f7f91STakashi Iwai return 0; 1859a07a949bSTakashi Iwai spec->ext_channel_count = ch * 2 + spec->min_channel_count; 1860352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++) 1861352f7f91STakashi Iwai set_multi_io(codec, i, i < ch); 1862352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count, 1863352f7f91STakashi Iwai spec->const_channel_count); 1864352f7f91STakashi Iwai if (spec->need_dac_fix) 1865352f7f91STakashi Iwai spec->multiout.num_dacs = spec->multiout.max_channels / 2; 1866352f7f91STakashi Iwai return 1; 1867352f7f91STakashi Iwai } 1868352f7f91STakashi Iwai 1869352f7f91STakashi Iwai static const struct snd_kcontrol_new channel_mode_enum = { 1870352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1871352f7f91STakashi Iwai .name = "Channel Mode", 1872352f7f91STakashi Iwai .info = ch_mode_info, 1873352f7f91STakashi Iwai .get = ch_mode_get, 1874352f7f91STakashi Iwai .put = ch_mode_put, 1875352f7f91STakashi Iwai }; 1876352f7f91STakashi Iwai 1877352f7f91STakashi Iwai static int create_multi_channel_mode(struct hda_codec *codec) 1878352f7f91STakashi Iwai { 1879352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1880352f7f91STakashi Iwai 1881352f7f91STakashi Iwai if (spec->multi_ios > 0) { 188212c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &channel_mode_enum)) 1883352f7f91STakashi Iwai return -ENOMEM; 1884352f7f91STakashi Iwai } 1885352f7f91STakashi Iwai return 0; 1886352f7f91STakashi Iwai } 1887352f7f91STakashi Iwai 1888352f7f91STakashi Iwai /* 1889c30aa7b2STakashi Iwai * aamix loopback enable/disable switch 1890c30aa7b2STakashi Iwai */ 1891c30aa7b2STakashi Iwai 1892c30aa7b2STakashi Iwai #define loopback_mixing_info indep_hp_info 1893c30aa7b2STakashi Iwai 1894c30aa7b2STakashi Iwai static int loopback_mixing_get(struct snd_kcontrol *kcontrol, 1895c30aa7b2STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1896c30aa7b2STakashi Iwai { 1897c30aa7b2STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1898c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1899c30aa7b2STakashi Iwai ucontrol->value.enumerated.item[0] = spec->aamix_mode; 1900c30aa7b2STakashi Iwai return 0; 1901c30aa7b2STakashi Iwai } 1902c30aa7b2STakashi Iwai 1903c30aa7b2STakashi Iwai static void update_aamix_paths(struct hda_codec *codec, bool do_mix, 1904c30aa7b2STakashi Iwai int nomix_path_idx, int mix_path_idx) 1905c30aa7b2STakashi Iwai { 1906c30aa7b2STakashi Iwai struct nid_path *nomix_path, *mix_path; 1907c30aa7b2STakashi Iwai 1908c30aa7b2STakashi Iwai nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx); 1909c30aa7b2STakashi Iwai mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx); 1910c30aa7b2STakashi Iwai if (!nomix_path || !mix_path) 1911c30aa7b2STakashi Iwai return; 1912c30aa7b2STakashi Iwai if (do_mix) { 1913c30aa7b2STakashi Iwai snd_hda_activate_path(codec, nomix_path, false, true); 1914c30aa7b2STakashi Iwai snd_hda_activate_path(codec, mix_path, true, true); 1915c30aa7b2STakashi Iwai } else { 1916c30aa7b2STakashi Iwai snd_hda_activate_path(codec, mix_path, false, true); 1917c30aa7b2STakashi Iwai snd_hda_activate_path(codec, nomix_path, true, true); 1918c30aa7b2STakashi Iwai } 1919c30aa7b2STakashi Iwai } 1920c30aa7b2STakashi Iwai 1921c30aa7b2STakashi Iwai static int loopback_mixing_put(struct snd_kcontrol *kcontrol, 1922c30aa7b2STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1923c30aa7b2STakashi Iwai { 1924c30aa7b2STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1925c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1926c30aa7b2STakashi Iwai unsigned int val = ucontrol->value.enumerated.item[0]; 1927c30aa7b2STakashi Iwai 1928c30aa7b2STakashi Iwai if (val == spec->aamix_mode) 1929c30aa7b2STakashi Iwai return 0; 1930c30aa7b2STakashi Iwai spec->aamix_mode = val; 1931c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->out_paths[0], 1932c30aa7b2STakashi Iwai spec->aamix_out_paths[0]); 1933c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->hp_paths[0], 1934c30aa7b2STakashi Iwai spec->aamix_out_paths[1]); 1935c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->speaker_paths[0], 1936c30aa7b2STakashi Iwai spec->aamix_out_paths[2]); 1937c30aa7b2STakashi Iwai return 1; 1938c30aa7b2STakashi Iwai } 1939c30aa7b2STakashi Iwai 1940c30aa7b2STakashi Iwai static const struct snd_kcontrol_new loopback_mixing_enum = { 1941c30aa7b2STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1942c30aa7b2STakashi Iwai .name = "Loopback Mixing", 1943c30aa7b2STakashi Iwai .info = loopback_mixing_info, 1944c30aa7b2STakashi Iwai .get = loopback_mixing_get, 1945c30aa7b2STakashi Iwai .put = loopback_mixing_put, 1946c30aa7b2STakashi Iwai }; 1947c30aa7b2STakashi Iwai 1948c30aa7b2STakashi Iwai static int create_loopback_mixing_ctl(struct hda_codec *codec) 1949c30aa7b2STakashi Iwai { 1950c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1951c30aa7b2STakashi Iwai 1952c30aa7b2STakashi Iwai if (!spec->mixer_nid) 1953c30aa7b2STakashi Iwai return 0; 1954c30aa7b2STakashi Iwai if (!(spec->aamix_out_paths[0] || spec->aamix_out_paths[1] || 1955c30aa7b2STakashi Iwai spec->aamix_out_paths[2])) 1956c30aa7b2STakashi Iwai return 0; 1957c30aa7b2STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum)) 1958c30aa7b2STakashi Iwai return -ENOMEM; 1959c30aa7b2STakashi Iwai return 0; 1960c30aa7b2STakashi Iwai } 1961c30aa7b2STakashi Iwai 1962c30aa7b2STakashi Iwai /* 1963352f7f91STakashi Iwai * shared headphone/mic handling 1964352f7f91STakashi Iwai */ 1965352f7f91STakashi Iwai 1966352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec); 1967352f7f91STakashi Iwai 1968352f7f91STakashi Iwai /* for shared I/O, change the pin-control accordingly */ 1969352f7f91STakashi Iwai static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic) 1970352f7f91STakashi Iwai { 1971352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1972352f7f91STakashi Iwai unsigned int val; 1973352f7f91STakashi Iwai hda_nid_t pin = spec->autocfg.inputs[1].pin; 1974352f7f91STakashi Iwai /* NOTE: this assumes that there are only two inputs, the 1975352f7f91STakashi Iwai * first is the real internal mic and the second is HP/mic jack. 1976352f7f91STakashi Iwai */ 1977352f7f91STakashi Iwai 1978352f7f91STakashi Iwai val = snd_hda_get_default_vref(codec, pin); 1979352f7f91STakashi Iwai 1980352f7f91STakashi Iwai /* This pin does not have vref caps - let's enable vref on pin 0x18 1981352f7f91STakashi Iwai instead, as suggested by Realtek */ 1982352f7f91STakashi Iwai if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) { 1983352f7f91STakashi Iwai const hda_nid_t vref_pin = spec->shared_mic_vref_pin; 1984352f7f91STakashi Iwai unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin); 1985352f7f91STakashi Iwai if (vref_val != AC_PINCTL_VREF_HIZ) 19867594aa33STakashi Iwai snd_hda_set_pin_ctl_cache(codec, vref_pin, 19877594aa33STakashi Iwai PIN_IN | (set_as_mic ? vref_val : 0)); 1988352f7f91STakashi Iwai } 1989352f7f91STakashi Iwai 1990352f7f91STakashi Iwai val = set_as_mic ? val | PIN_IN : PIN_HP; 19912c12c30dSTakashi Iwai set_pin_target(codec, pin, val, true); 1992352f7f91STakashi Iwai 1993352f7f91STakashi Iwai spec->automute_speaker = !set_as_mic; 1994352f7f91STakashi Iwai call_update_outputs(codec); 1995352f7f91STakashi Iwai } 1996352f7f91STakashi Iwai 1997352f7f91STakashi Iwai /* create a shared input with the headphone out */ 1998352f7f91STakashi Iwai static int create_shared_input(struct hda_codec *codec) 1999352f7f91STakashi Iwai { 2000352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2001352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 2002352f7f91STakashi Iwai unsigned int defcfg; 2003352f7f91STakashi Iwai hda_nid_t nid; 2004352f7f91STakashi Iwai 2005352f7f91STakashi Iwai /* only one internal input pin? */ 2006352f7f91STakashi Iwai if (cfg->num_inputs != 1) 2007352f7f91STakashi Iwai return 0; 2008352f7f91STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); 2009352f7f91STakashi Iwai if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) 2010352f7f91STakashi Iwai return 0; 2011352f7f91STakashi Iwai 2012352f7f91STakashi Iwai if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) 2013352f7f91STakashi Iwai nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */ 2014352f7f91STakashi Iwai else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT) 2015352f7f91STakashi Iwai nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */ 2016352f7f91STakashi Iwai else 2017352f7f91STakashi Iwai return 0; /* both not available */ 2018352f7f91STakashi Iwai 2019352f7f91STakashi Iwai if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN)) 2020352f7f91STakashi Iwai return 0; /* no input */ 2021352f7f91STakashi Iwai 2022352f7f91STakashi Iwai cfg->inputs[1].pin = nid; 2023352f7f91STakashi Iwai cfg->inputs[1].type = AUTO_PIN_MIC; 2024352f7f91STakashi Iwai cfg->num_inputs = 2; 2025352f7f91STakashi Iwai spec->shared_mic_hp = 1; 2026352f7f91STakashi Iwai snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid); 2027352f7f91STakashi Iwai return 0; 2028352f7f91STakashi Iwai } 2029352f7f91STakashi Iwai 2030978e77e7STakashi Iwai /* 2031978e77e7STakashi Iwai * output jack mode 2032978e77e7STakashi Iwai */ 2033978e77e7STakashi Iwai static int out_jack_mode_info(struct snd_kcontrol *kcontrol, 2034978e77e7STakashi Iwai struct snd_ctl_elem_info *uinfo) 2035978e77e7STakashi Iwai { 2036978e77e7STakashi Iwai static const char * const texts[] = { 2037978e77e7STakashi Iwai "Line Out", "Headphone Out", 2038978e77e7STakashi Iwai }; 2039978e77e7STakashi Iwai return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts); 2040978e77e7STakashi Iwai } 2041978e77e7STakashi Iwai 2042978e77e7STakashi Iwai static int out_jack_mode_get(struct snd_kcontrol *kcontrol, 2043978e77e7STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2044978e77e7STakashi Iwai { 2045978e77e7STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2046978e77e7STakashi Iwai hda_nid_t nid = kcontrol->private_value; 2047978e77e7STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) == PIN_HP) 2048978e77e7STakashi Iwai ucontrol->value.enumerated.item[0] = 1; 2049978e77e7STakashi Iwai else 2050978e77e7STakashi Iwai ucontrol->value.enumerated.item[0] = 0; 2051978e77e7STakashi Iwai return 0; 2052978e77e7STakashi Iwai } 2053978e77e7STakashi Iwai 2054978e77e7STakashi Iwai static int out_jack_mode_put(struct snd_kcontrol *kcontrol, 2055978e77e7STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2056978e77e7STakashi Iwai { 2057978e77e7STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2058978e77e7STakashi Iwai hda_nid_t nid = kcontrol->private_value; 2059978e77e7STakashi Iwai unsigned int val; 2060978e77e7STakashi Iwai 2061978e77e7STakashi Iwai val = ucontrol->value.enumerated.item[0] ? PIN_HP : PIN_OUT; 2062978e77e7STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) == val) 2063978e77e7STakashi Iwai return 0; 2064978e77e7STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, val); 2065978e77e7STakashi Iwai return 1; 2066978e77e7STakashi Iwai } 2067978e77e7STakashi Iwai 2068978e77e7STakashi Iwai static const struct snd_kcontrol_new out_jack_mode_enum = { 2069978e77e7STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2070978e77e7STakashi Iwai .info = out_jack_mode_info, 2071978e77e7STakashi Iwai .get = out_jack_mode_get, 2072978e77e7STakashi Iwai .put = out_jack_mode_put, 2073978e77e7STakashi Iwai }; 2074978e77e7STakashi Iwai 2075978e77e7STakashi Iwai static bool find_kctl_name(struct hda_codec *codec, const char *name, int idx) 2076978e77e7STakashi Iwai { 2077978e77e7STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2078978e77e7STakashi Iwai int i; 2079978e77e7STakashi Iwai 2080978e77e7STakashi Iwai for (i = 0; i < spec->kctls.used; i++) { 2081978e77e7STakashi Iwai struct snd_kcontrol_new *kctl = snd_array_elem(&spec->kctls, i); 2082978e77e7STakashi Iwai if (!strcmp(kctl->name, name) && kctl->index == idx) 2083978e77e7STakashi Iwai return true; 2084978e77e7STakashi Iwai } 2085978e77e7STakashi Iwai return false; 2086978e77e7STakashi Iwai } 2087978e77e7STakashi Iwai 2088978e77e7STakashi Iwai static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin, 2089978e77e7STakashi Iwai char *name, size_t name_len) 2090978e77e7STakashi Iwai { 2091978e77e7STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2092978e77e7STakashi Iwai int idx = 0; 2093978e77e7STakashi Iwai 2094978e77e7STakashi Iwai snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len, &idx); 2095978e77e7STakashi Iwai strlcat(name, " Jack Mode", name_len); 2096978e77e7STakashi Iwai 2097978e77e7STakashi Iwai for (; find_kctl_name(codec, name, idx); idx++) 2098978e77e7STakashi Iwai ; 2099978e77e7STakashi Iwai } 2100978e77e7STakashi Iwai 2101978e77e7STakashi Iwai static int create_out_jack_modes(struct hda_codec *codec, int num_pins, 2102978e77e7STakashi Iwai hda_nid_t *pins) 2103978e77e7STakashi Iwai { 2104978e77e7STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2105978e77e7STakashi Iwai int i; 2106978e77e7STakashi Iwai 2107978e77e7STakashi Iwai for (i = 0; i < num_pins; i++) { 2108978e77e7STakashi Iwai hda_nid_t pin = pins[i]; 2109978e77e7STakashi Iwai unsigned int pincap = snd_hda_query_pin_caps(codec, pin); 2110978e77e7STakashi Iwai if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV)) { 2111978e77e7STakashi Iwai struct snd_kcontrol_new *knew; 2112978e77e7STakashi Iwai char name[44]; 2113978e77e7STakashi Iwai get_jack_mode_name(codec, pin, name, sizeof(name)); 2114978e77e7STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, 2115978e77e7STakashi Iwai &out_jack_mode_enum); 2116978e77e7STakashi Iwai if (!knew) 2117978e77e7STakashi Iwai return -ENOMEM; 2118978e77e7STakashi Iwai knew->private_value = pin; 2119978e77e7STakashi Iwai } 2120978e77e7STakashi Iwai } 2121978e77e7STakashi Iwai 2122978e77e7STakashi Iwai return 0; 2123978e77e7STakashi Iwai } 2124978e77e7STakashi Iwai 2125352f7f91STakashi Iwai 2126352f7f91STakashi Iwai /* 2127352f7f91STakashi Iwai * Parse input paths 2128352f7f91STakashi Iwai */ 2129352f7f91STakashi Iwai 2130352f7f91STakashi Iwai #ifdef CONFIG_PM 2131352f7f91STakashi Iwai /* add the powersave loopback-list entry */ 2132352f7f91STakashi Iwai static void add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx) 2133352f7f91STakashi Iwai { 2134352f7f91STakashi Iwai struct hda_amp_list *list; 2135352f7f91STakashi Iwai 2136352f7f91STakashi Iwai if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1) 2137352f7f91STakashi Iwai return; 2138352f7f91STakashi Iwai list = spec->loopback_list + spec->num_loopbacks; 2139352f7f91STakashi Iwai list->nid = mix; 2140352f7f91STakashi Iwai list->dir = HDA_INPUT; 2141352f7f91STakashi Iwai list->idx = idx; 2142352f7f91STakashi Iwai spec->num_loopbacks++; 2143cb53c626STakashi Iwai spec->loopback.amplist = spec->loopback_list; 2144cb53c626STakashi Iwai } 2145cb53c626STakashi Iwai #else 2146352f7f91STakashi Iwai #define add_loopback_list(spec, mix, idx) /* NOP */ 2147cb53c626STakashi Iwai #endif 2148cb53c626STakashi Iwai 2149352f7f91STakashi Iwai /* create input playback/capture controls for the given pin */ 2150196c1766STakashi Iwai static int new_analog_input(struct hda_codec *codec, int input_idx, 2151196c1766STakashi Iwai hda_nid_t pin, const char *ctlname, int ctlidx, 2152352f7f91STakashi Iwai hda_nid_t mix_nid) 21531da177e4SLinus Torvalds { 2154352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2155352f7f91STakashi Iwai struct nid_path *path; 2156352f7f91STakashi Iwai unsigned int val; 2157352f7f91STakashi Iwai int err, idx; 21581da177e4SLinus Torvalds 2159352f7f91STakashi Iwai if (!nid_has_volume(codec, mix_nid, HDA_INPUT) && 2160352f7f91STakashi Iwai !nid_has_mute(codec, mix_nid, HDA_INPUT)) 2161352f7f91STakashi Iwai return 0; /* no need for analog loopback */ 2162352f7f91STakashi Iwai 21633ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, pin, mix_nid, 0); 2164352f7f91STakashi Iwai if (!path) 2165352f7f91STakashi Iwai return -EINVAL; 21660c8c0f56STakashi Iwai print_nid_path("loopback", path); 2167196c1766STakashi Iwai spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path); 2168352f7f91STakashi Iwai 2169352f7f91STakashi Iwai idx = path->idx[path->depth - 1]; 2170352f7f91STakashi Iwai if (nid_has_volume(codec, mix_nid, HDA_INPUT)) { 2171352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); 2172352f7f91STakashi Iwai err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, val); 2173d13bd412STakashi Iwai if (err < 0) 21741da177e4SLinus Torvalds return err; 2175352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = val; 21761da177e4SLinus Torvalds } 21771da177e4SLinus Torvalds 2178352f7f91STakashi Iwai if (nid_has_mute(codec, mix_nid, HDA_INPUT)) { 2179352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); 2180352f7f91STakashi Iwai err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, val); 2181d13bd412STakashi Iwai if (err < 0) 21821da177e4SLinus Torvalds return err; 2183352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = val; 21841da177e4SLinus Torvalds } 21851da177e4SLinus Torvalds 2186352f7f91STakashi Iwai path->active = true; 2187352f7f91STakashi Iwai add_loopback_list(spec, mix_nid, idx); 2188352f7f91STakashi Iwai return 0; 21891da177e4SLinus Torvalds } 21901da177e4SLinus Torvalds 2191352f7f91STakashi Iwai static int is_input_pin(struct hda_codec *codec, hda_nid_t nid) 21921da177e4SLinus Torvalds { 2193352f7f91STakashi Iwai unsigned int pincap = snd_hda_query_pin_caps(codec, nid); 2194352f7f91STakashi Iwai return (pincap & AC_PINCAP_IN) != 0; 2195352f7f91STakashi Iwai } 2196352f7f91STakashi Iwai 2197352f7f91STakashi Iwai /* Parse the codec tree and retrieve ADCs */ 2198352f7f91STakashi Iwai static int fill_adc_nids(struct hda_codec *codec) 2199352f7f91STakashi Iwai { 2200352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2201352f7f91STakashi Iwai hda_nid_t nid; 2202352f7f91STakashi Iwai hda_nid_t *adc_nids = spec->adc_nids; 2203352f7f91STakashi Iwai int max_nums = ARRAY_SIZE(spec->adc_nids); 2204352f7f91STakashi Iwai int i, nums = 0; 2205352f7f91STakashi Iwai 2206352f7f91STakashi Iwai nid = codec->start_nid; 2207352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) { 2208352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 2209352f7f91STakashi Iwai int type = get_wcaps_type(caps); 2210352f7f91STakashi Iwai 2211352f7f91STakashi Iwai if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL)) 2212352f7f91STakashi Iwai continue; 2213352f7f91STakashi Iwai adc_nids[nums] = nid; 2214352f7f91STakashi Iwai if (++nums >= max_nums) 2215352f7f91STakashi Iwai break; 2216352f7f91STakashi Iwai } 2217352f7f91STakashi Iwai spec->num_adc_nids = nums; 2218352f7f91STakashi Iwai return nums; 2219352f7f91STakashi Iwai } 2220352f7f91STakashi Iwai 2221352f7f91STakashi Iwai /* filter out invalid adc_nids that don't give all active input pins; 2222352f7f91STakashi Iwai * if needed, check whether dynamic ADC-switching is available 2223352f7f91STakashi Iwai */ 2224352f7f91STakashi Iwai static int check_dyn_adc_switch(struct hda_codec *codec) 2225352f7f91STakashi Iwai { 2226352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2227352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 22283a65bcdcSTakashi Iwai unsigned int ok_bits; 2229352f7f91STakashi Iwai int i, n, nums; 2230352f7f91STakashi Iwai 2231352f7f91STakashi Iwai again: 2232352f7f91STakashi Iwai nums = 0; 22333a65bcdcSTakashi Iwai ok_bits = 0; 2234352f7f91STakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 2235352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 22363a65bcdcSTakashi Iwai if (!spec->input_paths[i][n]) 2237352f7f91STakashi Iwai break; 2238352f7f91STakashi Iwai } 22393a65bcdcSTakashi Iwai if (i >= imux->num_items) { 22403a65bcdcSTakashi Iwai ok_bits |= (1 << n); 22413a65bcdcSTakashi Iwai nums++; 22423a65bcdcSTakashi Iwai } 2243352f7f91STakashi Iwai } 2244352f7f91STakashi Iwai 22453a65bcdcSTakashi Iwai if (!ok_bits) { 2246352f7f91STakashi Iwai if (spec->shared_mic_hp) { 2247352f7f91STakashi Iwai spec->shared_mic_hp = 0; 2248352f7f91STakashi Iwai imux->num_items = 1; 2249352f7f91STakashi Iwai goto again; 2250352f7f91STakashi Iwai } 2251352f7f91STakashi Iwai 2252352f7f91STakashi Iwai /* check whether ADC-switch is possible */ 2253352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2254352f7f91STakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 22553a65bcdcSTakashi Iwai if (spec->input_paths[i][n]) { 2256352f7f91STakashi Iwai spec->dyn_adc_idx[i] = n; 2257352f7f91STakashi Iwai break; 2258352f7f91STakashi Iwai } 2259352f7f91STakashi Iwai } 2260352f7f91STakashi Iwai } 2261352f7f91STakashi Iwai 2262352f7f91STakashi Iwai snd_printdd("hda-codec: enabling ADC switching\n"); 2263352f7f91STakashi Iwai spec->dyn_adc_switch = 1; 2264352f7f91STakashi Iwai } else if (nums != spec->num_adc_nids) { 22653a65bcdcSTakashi Iwai /* shrink the invalid adcs and input paths */ 22663a65bcdcSTakashi Iwai nums = 0; 22673a65bcdcSTakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 22683a65bcdcSTakashi Iwai if (!(ok_bits & (1 << n))) 22693a65bcdcSTakashi Iwai continue; 22703a65bcdcSTakashi Iwai if (n != nums) { 22713a65bcdcSTakashi Iwai spec->adc_nids[nums] = spec->adc_nids[n]; 2272980428ceSTakashi Iwai for (i = 0; i < imux->num_items; i++) { 2273980428ceSTakashi Iwai invalidate_nid_path(codec, 2274980428ceSTakashi Iwai spec->input_paths[i][nums]); 22753a65bcdcSTakashi Iwai spec->input_paths[i][nums] = 22763a65bcdcSTakashi Iwai spec->input_paths[i][n]; 22773a65bcdcSTakashi Iwai } 2278980428ceSTakashi Iwai } 22793a65bcdcSTakashi Iwai nums++; 22803a65bcdcSTakashi Iwai } 2281352f7f91STakashi Iwai spec->num_adc_nids = nums; 2282352f7f91STakashi Iwai } 2283352f7f91STakashi Iwai 2284352f7f91STakashi Iwai if (imux->num_items == 1 || spec->shared_mic_hp) { 2285352f7f91STakashi Iwai snd_printdd("hda-codec: reducing to a single ADC\n"); 2286352f7f91STakashi Iwai spec->num_adc_nids = 1; /* reduce to a single ADC */ 2287352f7f91STakashi Iwai } 2288352f7f91STakashi Iwai 2289352f7f91STakashi Iwai /* single index for individual volumes ctls */ 2290352f7f91STakashi Iwai if (!spec->dyn_adc_switch && spec->multi_cap_vol) 2291352f7f91STakashi Iwai spec->num_adc_nids = 1; 2292352f7f91STakashi Iwai 22931da177e4SLinus Torvalds return 0; 22941da177e4SLinus Torvalds } 22951da177e4SLinus Torvalds 2296f3fc0b0bSTakashi Iwai /* parse capture source paths from the given pin and create imux items */ 2297f3fc0b0bSTakashi Iwai static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin, 2298f3fc0b0bSTakashi Iwai int num_adcs, const char *label, int anchor) 2299f3fc0b0bSTakashi Iwai { 2300f3fc0b0bSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 2301f3fc0b0bSTakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 2302f3fc0b0bSTakashi Iwai int imux_idx = imux->num_items; 2303f3fc0b0bSTakashi Iwai bool imux_added = false; 2304f3fc0b0bSTakashi Iwai int c; 2305f3fc0b0bSTakashi Iwai 2306f3fc0b0bSTakashi Iwai for (c = 0; c < num_adcs; c++) { 2307f3fc0b0bSTakashi Iwai struct nid_path *path; 2308f3fc0b0bSTakashi Iwai hda_nid_t adc = spec->adc_nids[c]; 2309f3fc0b0bSTakashi Iwai 2310f3fc0b0bSTakashi Iwai if (!is_reachable_path(codec, pin, adc)) 2311f3fc0b0bSTakashi Iwai continue; 2312f3fc0b0bSTakashi Iwai path = snd_hda_add_new_path(codec, pin, adc, anchor); 2313f3fc0b0bSTakashi Iwai if (!path) 2314f3fc0b0bSTakashi Iwai continue; 2315f3fc0b0bSTakashi Iwai print_nid_path("input", path); 2316f3fc0b0bSTakashi Iwai spec->input_paths[imux_idx][c] = 2317f3fc0b0bSTakashi Iwai snd_hda_get_path_idx(codec, path); 2318f3fc0b0bSTakashi Iwai 2319f3fc0b0bSTakashi Iwai if (!imux_added) { 2320f3fc0b0bSTakashi Iwai spec->imux_pins[imux->num_items] = pin; 2321f3fc0b0bSTakashi Iwai snd_hda_add_imux_item(imux, label, 2322f3fc0b0bSTakashi Iwai imux->num_items, NULL); 2323f3fc0b0bSTakashi Iwai imux_added = true; 2324f3fc0b0bSTakashi Iwai } 2325f3fc0b0bSTakashi Iwai } 2326f3fc0b0bSTakashi Iwai 2327f3fc0b0bSTakashi Iwai return 0; 2328f3fc0b0bSTakashi Iwai } 2329f3fc0b0bSTakashi Iwai 23301da177e4SLinus Torvalds /* 2331352f7f91STakashi Iwai * create playback/capture controls for input pins 23321da177e4SLinus Torvalds */ 2333352f7f91STakashi Iwai static int create_input_ctls(struct hda_codec *codec) 2334a7da6ce5STakashi Iwai { 2335352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2336352f7f91STakashi Iwai const struct auto_pin_cfg *cfg = &spec->autocfg; 2337352f7f91STakashi Iwai hda_nid_t mixer = spec->mixer_nid; 2338352f7f91STakashi Iwai int num_adcs; 2339f3fc0b0bSTakashi Iwai int i, err, type_idx = 0; 2340352f7f91STakashi Iwai const char *prev_label = NULL; 23412c12c30dSTakashi Iwai unsigned int val; 2342a7da6ce5STakashi Iwai 2343352f7f91STakashi Iwai num_adcs = fill_adc_nids(codec); 2344352f7f91STakashi Iwai if (num_adcs < 0) 2345352f7f91STakashi Iwai return 0; 2346352f7f91STakashi Iwai 2347352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 2348352f7f91STakashi Iwai hda_nid_t pin; 2349352f7f91STakashi Iwai const char *label; 2350352f7f91STakashi Iwai 2351352f7f91STakashi Iwai pin = cfg->inputs[i].pin; 2352352f7f91STakashi Iwai if (!is_input_pin(codec, pin)) 2353352f7f91STakashi Iwai continue; 2354352f7f91STakashi Iwai 2355352f7f91STakashi Iwai label = hda_get_autocfg_input_label(codec, cfg, i); 2356352f7f91STakashi Iwai if (prev_label && !strcmp(label, prev_label)) 2357352f7f91STakashi Iwai type_idx++; 2358352f7f91STakashi Iwai else 2359352f7f91STakashi Iwai type_idx = 0; 2360352f7f91STakashi Iwai prev_label = label; 2361352f7f91STakashi Iwai 23622c12c30dSTakashi Iwai val = PIN_IN; 23632c12c30dSTakashi Iwai if (cfg->inputs[i].type == AUTO_PIN_MIC) 23642c12c30dSTakashi Iwai val |= snd_hda_get_default_vref(codec, pin); 23652c12c30dSTakashi Iwai set_pin_target(codec, pin, val, false); 23662c12c30dSTakashi Iwai 2367352f7f91STakashi Iwai if (mixer) { 2368352f7f91STakashi Iwai if (is_reachable_path(codec, pin, mixer)) { 2369196c1766STakashi Iwai err = new_analog_input(codec, i, pin, 2370352f7f91STakashi Iwai label, type_idx, mixer); 2371a7da6ce5STakashi Iwai if (err < 0) 2372a7da6ce5STakashi Iwai return err; 2373a7da6ce5STakashi Iwai } 2374352f7f91STakashi Iwai } 2375352f7f91STakashi Iwai 2376f3fc0b0bSTakashi Iwai err = parse_capture_source(codec, pin, num_adcs, label, -mixer); 2377f3fc0b0bSTakashi Iwai if (err < 0) 2378f3fc0b0bSTakashi Iwai return err; 2379352f7f91STakashi Iwai } 2380f3fc0b0bSTakashi Iwai 2381f3fc0b0bSTakashi Iwai if (mixer && spec->add_stereo_mix_input) { 2382f3fc0b0bSTakashi Iwai err = parse_capture_source(codec, mixer, num_adcs, 2383f3fc0b0bSTakashi Iwai "Stereo Mix", 0); 2384f3fc0b0bSTakashi Iwai if (err < 0) 2385f3fc0b0bSTakashi Iwai return err; 2386352f7f91STakashi Iwai } 2387352f7f91STakashi Iwai 2388a7da6ce5STakashi Iwai return 0; 2389a7da6ce5STakashi Iwai } 2390a7da6ce5STakashi Iwai 23911da177e4SLinus Torvalds 2392352f7f91STakashi Iwai /* 2393352f7f91STakashi Iwai * input source mux 2394352f7f91STakashi Iwai */ 2395352f7f91STakashi Iwai 2396c697b716STakashi Iwai /* get the input path specified by the given adc and imux indices */ 2397c697b716STakashi Iwai static struct nid_path *get_input_path(struct hda_codec *codec, int adc_idx, int imux_idx) 2398352f7f91STakashi Iwai { 2399352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2400352f7f91STakashi Iwai if (spec->dyn_adc_switch) 2401352f7f91STakashi Iwai adc_idx = spec->dyn_adc_idx[imux_idx]; 2402c697b716STakashi Iwai return snd_hda_get_path_from_idx(codec, spec->input_paths[imux_idx][adc_idx]); 240397ec558aSTakashi Iwai } 2404352f7f91STakashi Iwai 2405352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx, 2406352f7f91STakashi Iwai unsigned int idx); 2407352f7f91STakashi Iwai 2408352f7f91STakashi Iwai static int mux_enum_info(struct snd_kcontrol *kcontrol, 2409352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 2410352f7f91STakashi Iwai { 2411352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2412352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2413352f7f91STakashi Iwai return snd_hda_input_mux_info(&spec->input_mux, uinfo); 2414352f7f91STakashi Iwai } 2415352f7f91STakashi Iwai 2416352f7f91STakashi Iwai static int mux_enum_get(struct snd_kcontrol *kcontrol, 2417352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2418352f7f91STakashi Iwai { 2419352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2420352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2421352f7f91STakashi Iwai unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 2422352f7f91STakashi Iwai 2423352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; 24241da177e4SLinus Torvalds return 0; 24251da177e4SLinus Torvalds } 24261da177e4SLinus Torvalds 2427352f7f91STakashi Iwai static int mux_enum_put(struct snd_kcontrol *kcontrol, 2428352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 24291da177e4SLinus Torvalds { 2430352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2431352f7f91STakashi Iwai unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 2432352f7f91STakashi Iwai return mux_select(codec, adc_idx, 2433352f7f91STakashi Iwai ucontrol->value.enumerated.item[0]); 2434352f7f91STakashi Iwai } 2435352f7f91STakashi Iwai 2436352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_src_temp = { 24371da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2438352f7f91STakashi Iwai .name = "Input Source", 2439352f7f91STakashi Iwai .info = mux_enum_info, 2440352f7f91STakashi Iwai .get = mux_enum_get, 2441352f7f91STakashi Iwai .put = mux_enum_put, 24421da177e4SLinus Torvalds }; 2443071c73adSTakashi Iwai 244447d46abbSTakashi Iwai /* 244547d46abbSTakashi Iwai * capture volume and capture switch ctls 244647d46abbSTakashi Iwai */ 244747d46abbSTakashi Iwai 2448352f7f91STakashi Iwai typedef int (*put_call_t)(struct snd_kcontrol *kcontrol, 2449352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol); 2450071c73adSTakashi Iwai 245147d46abbSTakashi Iwai /* call the given amp update function for all amps in the imux list at once */ 2452352f7f91STakashi Iwai static int cap_put_caller(struct snd_kcontrol *kcontrol, 2453352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol, 2454352f7f91STakashi Iwai put_call_t func, int type) 2455352f7f91STakashi Iwai { 2456352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2457352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2458352f7f91STakashi Iwai const struct hda_input_mux *imux; 2459352f7f91STakashi Iwai struct nid_path *path; 2460352f7f91STakashi Iwai int i, adc_idx, err = 0; 2461071c73adSTakashi Iwai 2462352f7f91STakashi Iwai imux = &spec->input_mux; 2463352f7f91STakashi Iwai adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 2464352f7f91STakashi Iwai mutex_lock(&codec->control_mutex); 246547d46abbSTakashi Iwai /* we use the cache-only update at first since multiple input paths 246647d46abbSTakashi Iwai * may shared the same amp; by updating only caches, the redundant 246747d46abbSTakashi Iwai * writes to hardware can be reduced. 246847d46abbSTakashi Iwai */ 2469352f7f91STakashi Iwai codec->cached_write = 1; 2470352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2471c697b716STakashi Iwai path = get_input_path(codec, adc_idx, i); 2472c697b716STakashi Iwai if (!path || !path->ctls[type]) 2473352f7f91STakashi Iwai continue; 2474352f7f91STakashi Iwai kcontrol->private_value = path->ctls[type]; 2475352f7f91STakashi Iwai err = func(kcontrol, ucontrol); 2476352f7f91STakashi Iwai if (err < 0) 2477352f7f91STakashi Iwai goto error; 2478352f7f91STakashi Iwai } 2479352f7f91STakashi Iwai error: 2480352f7f91STakashi Iwai codec->cached_write = 0; 2481352f7f91STakashi Iwai mutex_unlock(&codec->control_mutex); 248247d46abbSTakashi Iwai snd_hda_codec_flush_amp_cache(codec); /* flush the updates */ 2483352f7f91STakashi Iwai if (err >= 0 && spec->cap_sync_hook) 2484352f7f91STakashi Iwai spec->cap_sync_hook(codec); 2485352f7f91STakashi Iwai return err; 2486352f7f91STakashi Iwai } 2487352f7f91STakashi Iwai 2488352f7f91STakashi Iwai /* capture volume ctl callbacks */ 2489352f7f91STakashi Iwai #define cap_vol_info snd_hda_mixer_amp_volume_info 2490352f7f91STakashi Iwai #define cap_vol_get snd_hda_mixer_amp_volume_get 2491352f7f91STakashi Iwai #define cap_vol_tlv snd_hda_mixer_amp_tlv 2492352f7f91STakashi Iwai 2493352f7f91STakashi Iwai static int cap_vol_put(struct snd_kcontrol *kcontrol, 2494352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2495352f7f91STakashi Iwai { 2496352f7f91STakashi Iwai return cap_put_caller(kcontrol, ucontrol, 2497352f7f91STakashi Iwai snd_hda_mixer_amp_volume_put, 2498352f7f91STakashi Iwai NID_PATH_VOL_CTL); 2499352f7f91STakashi Iwai } 2500352f7f91STakashi Iwai 2501352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_vol_temp = { 2502352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2503352f7f91STakashi Iwai .name = "Capture Volume", 2504352f7f91STakashi Iwai .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 2505352f7f91STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ | 2506352f7f91STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), 2507352f7f91STakashi Iwai .info = cap_vol_info, 2508352f7f91STakashi Iwai .get = cap_vol_get, 2509352f7f91STakashi Iwai .put = cap_vol_put, 2510352f7f91STakashi Iwai .tlv = { .c = cap_vol_tlv }, 2511352f7f91STakashi Iwai }; 2512352f7f91STakashi Iwai 2513352f7f91STakashi Iwai /* capture switch ctl callbacks */ 2514352f7f91STakashi Iwai #define cap_sw_info snd_ctl_boolean_stereo_info 2515352f7f91STakashi Iwai #define cap_sw_get snd_hda_mixer_amp_switch_get 2516352f7f91STakashi Iwai 2517352f7f91STakashi Iwai static int cap_sw_put(struct snd_kcontrol *kcontrol, 2518352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2519352f7f91STakashi Iwai { 2520352f7f91STakashi Iwai return cap_put_caller(kcontrol, ucontrol, 2521352f7f91STakashi Iwai snd_hda_mixer_amp_switch_put, 2522352f7f91STakashi Iwai NID_PATH_MUTE_CTL); 2523352f7f91STakashi Iwai } 2524352f7f91STakashi Iwai 2525352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_sw_temp = { 2526352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2527352f7f91STakashi Iwai .name = "Capture Switch", 2528352f7f91STakashi Iwai .info = cap_sw_info, 2529352f7f91STakashi Iwai .get = cap_sw_get, 2530352f7f91STakashi Iwai .put = cap_sw_put, 2531352f7f91STakashi Iwai }; 2532352f7f91STakashi Iwai 2533352f7f91STakashi Iwai static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path) 2534352f7f91STakashi Iwai { 2535352f7f91STakashi Iwai hda_nid_t nid; 2536352f7f91STakashi Iwai int i, depth; 2537352f7f91STakashi Iwai 2538352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = path->ctls[NID_PATH_MUTE_CTL] = 0; 2539352f7f91STakashi Iwai for (depth = 0; depth < 3; depth++) { 2540352f7f91STakashi Iwai if (depth >= path->depth) 2541352f7f91STakashi Iwai return -EINVAL; 2542352f7f91STakashi Iwai i = path->depth - depth - 1; 2543352f7f91STakashi Iwai nid = path->path[i]; 2544352f7f91STakashi Iwai if (!path->ctls[NID_PATH_VOL_CTL]) { 2545352f7f91STakashi Iwai if (nid_has_volume(codec, nid, HDA_OUTPUT)) 2546352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = 2547352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 2548352f7f91STakashi Iwai else if (nid_has_volume(codec, nid, HDA_INPUT)) { 2549352f7f91STakashi Iwai int idx = path->idx[i]; 2550352f7f91STakashi Iwai if (!depth && codec->single_adc_amp) 2551352f7f91STakashi Iwai idx = 0; 2552352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = 2553352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); 2554352f7f91STakashi Iwai } 2555352f7f91STakashi Iwai } 2556352f7f91STakashi Iwai if (!path->ctls[NID_PATH_MUTE_CTL]) { 2557352f7f91STakashi Iwai if (nid_has_mute(codec, nid, HDA_OUTPUT)) 2558352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = 2559352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 2560352f7f91STakashi Iwai else if (nid_has_mute(codec, nid, HDA_INPUT)) { 2561352f7f91STakashi Iwai int idx = path->idx[i]; 2562352f7f91STakashi Iwai if (!depth && codec->single_adc_amp) 2563352f7f91STakashi Iwai idx = 0; 2564352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = 2565352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); 2566352f7f91STakashi Iwai } 2567352f7f91STakashi Iwai } 2568352f7f91STakashi Iwai } 2569352f7f91STakashi Iwai return 0; 2570352f7f91STakashi Iwai } 2571352f7f91STakashi Iwai 2572352f7f91STakashi Iwai static bool is_inv_dmic_pin(struct hda_codec *codec, hda_nid_t nid) 2573352f7f91STakashi Iwai { 2574352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2575352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 2576352f7f91STakashi Iwai unsigned int val; 2577352f7f91STakashi Iwai int i; 2578352f7f91STakashi Iwai 2579352f7f91STakashi Iwai if (!spec->inv_dmic_split) 2580352f7f91STakashi Iwai return false; 2581352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 2582352f7f91STakashi Iwai if (cfg->inputs[i].pin != nid) 2583352f7f91STakashi Iwai continue; 2584352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC) 2585352f7f91STakashi Iwai return false; 2586352f7f91STakashi Iwai val = snd_hda_codec_get_pincfg(codec, nid); 2587352f7f91STakashi Iwai return snd_hda_get_input_pin_attr(val) == INPUT_PIN_ATTR_INT; 2588352f7f91STakashi Iwai } 2589352f7f91STakashi Iwai return false; 2590352f7f91STakashi Iwai } 2591352f7f91STakashi Iwai 2592352f7f91STakashi Iwai static int add_single_cap_ctl(struct hda_codec *codec, const char *label, 2593352f7f91STakashi Iwai int idx, bool is_switch, unsigned int ctl, 2594352f7f91STakashi Iwai bool inv_dmic) 2595352f7f91STakashi Iwai { 2596352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2597352f7f91STakashi Iwai char tmpname[44]; 2598352f7f91STakashi Iwai int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL; 2599352f7f91STakashi Iwai const char *sfx = is_switch ? "Switch" : "Volume"; 2600352f7f91STakashi Iwai unsigned int chs = inv_dmic ? 1 : 3; 2601352f7f91STakashi Iwai int err; 2602352f7f91STakashi Iwai 2603352f7f91STakashi Iwai if (!ctl) 2604352f7f91STakashi Iwai return 0; 2605352f7f91STakashi Iwai 2606352f7f91STakashi Iwai if (label) 2607352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2608352f7f91STakashi Iwai "%s Capture %s", label, sfx); 2609352f7f91STakashi Iwai else 2610352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2611352f7f91STakashi Iwai "Capture %s", sfx); 2612352f7f91STakashi Iwai err = add_control(spec, type, tmpname, idx, 2613352f7f91STakashi Iwai amp_val_replace_channels(ctl, chs)); 2614352f7f91STakashi Iwai if (err < 0 || !inv_dmic) 2615352f7f91STakashi Iwai return err; 2616352f7f91STakashi Iwai 2617352f7f91STakashi Iwai /* Make independent right kcontrol */ 2618352f7f91STakashi Iwai if (label) 2619352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2620352f7f91STakashi Iwai "Inverted %s Capture %s", label, sfx); 2621352f7f91STakashi Iwai else 2622352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2623352f7f91STakashi Iwai "Inverted Capture %s", sfx); 2624352f7f91STakashi Iwai return add_control(spec, type, tmpname, idx, 2625352f7f91STakashi Iwai amp_val_replace_channels(ctl, 2)); 2626352f7f91STakashi Iwai } 2627352f7f91STakashi Iwai 2628352f7f91STakashi Iwai /* create single (and simple) capture volume and switch controls */ 2629352f7f91STakashi Iwai static int create_single_cap_vol_ctl(struct hda_codec *codec, int idx, 2630352f7f91STakashi Iwai unsigned int vol_ctl, unsigned int sw_ctl, 2631352f7f91STakashi Iwai bool inv_dmic) 2632352f7f91STakashi Iwai { 2633352f7f91STakashi Iwai int err; 2634352f7f91STakashi Iwai err = add_single_cap_ctl(codec, NULL, idx, false, vol_ctl, inv_dmic); 2635352f7f91STakashi Iwai if (err < 0) 2636352f7f91STakashi Iwai return err; 2637352f7f91STakashi Iwai err = add_single_cap_ctl(codec, NULL, idx, true, sw_ctl, inv_dmic); 2638071c73adSTakashi Iwai if (err < 0) 2639071c73adSTakashi Iwai return err; 2640071c73adSTakashi Iwai return 0; 26411da177e4SLinus Torvalds } 2642071c73adSTakashi Iwai 2643352f7f91STakashi Iwai /* create bound capture volume and switch controls */ 2644352f7f91STakashi Iwai static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx, 2645352f7f91STakashi Iwai unsigned int vol_ctl, unsigned int sw_ctl) 2646352f7f91STakashi Iwai { 2647352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2648352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 2649352f7f91STakashi Iwai 2650352f7f91STakashi Iwai if (vol_ctl) { 265112c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, NULL, &cap_vol_temp); 2652352f7f91STakashi Iwai if (!knew) 2653352f7f91STakashi Iwai return -ENOMEM; 2654352f7f91STakashi Iwai knew->index = idx; 2655352f7f91STakashi Iwai knew->private_value = vol_ctl; 2656352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 2657352f7f91STakashi Iwai } 2658352f7f91STakashi Iwai if (sw_ctl) { 265912c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, NULL, &cap_sw_temp); 2660352f7f91STakashi Iwai if (!knew) 2661352f7f91STakashi Iwai return -ENOMEM; 2662352f7f91STakashi Iwai knew->index = idx; 2663352f7f91STakashi Iwai knew->private_value = sw_ctl; 2664352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 2665352f7f91STakashi Iwai } 2666352f7f91STakashi Iwai return 0; 2667352f7f91STakashi Iwai } 2668352f7f91STakashi Iwai 2669352f7f91STakashi Iwai /* return the vol ctl when used first in the imux list */ 2670352f7f91STakashi Iwai static unsigned int get_first_cap_ctl(struct hda_codec *codec, int idx, int type) 2671352f7f91STakashi Iwai { 2672352f7f91STakashi Iwai struct nid_path *path; 2673352f7f91STakashi Iwai unsigned int ctl; 2674352f7f91STakashi Iwai int i; 2675352f7f91STakashi Iwai 2676c697b716STakashi Iwai path = get_input_path(codec, 0, idx); 2677352f7f91STakashi Iwai if (!path) 2678352f7f91STakashi Iwai return 0; 2679352f7f91STakashi Iwai ctl = path->ctls[type]; 2680352f7f91STakashi Iwai if (!ctl) 2681352f7f91STakashi Iwai return 0; 2682352f7f91STakashi Iwai for (i = 0; i < idx - 1; i++) { 2683c697b716STakashi Iwai path = get_input_path(codec, 0, i); 2684352f7f91STakashi Iwai if (path && path->ctls[type] == ctl) 2685352f7f91STakashi Iwai return 0; 2686352f7f91STakashi Iwai } 2687352f7f91STakashi Iwai return ctl; 2688352f7f91STakashi Iwai } 2689352f7f91STakashi Iwai 2690352f7f91STakashi Iwai /* create individual capture volume and switch controls per input */ 2691352f7f91STakashi Iwai static int create_multi_cap_vol_ctl(struct hda_codec *codec) 2692352f7f91STakashi Iwai { 2693352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2694352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 2695352f7f91STakashi Iwai int i, err, type, type_idx = 0; 2696352f7f91STakashi Iwai const char *prev_label = NULL; 2697352f7f91STakashi Iwai 2698352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2699352f7f91STakashi Iwai const char *label; 2700352f7f91STakashi Iwai bool inv_dmic; 2701352f7f91STakashi Iwai label = hda_get_autocfg_input_label(codec, &spec->autocfg, i); 2702352f7f91STakashi Iwai if (prev_label && !strcmp(label, prev_label)) 2703352f7f91STakashi Iwai type_idx++; 2704352f7f91STakashi Iwai else 2705352f7f91STakashi Iwai type_idx = 0; 2706352f7f91STakashi Iwai prev_label = label; 2707352f7f91STakashi Iwai inv_dmic = is_inv_dmic_pin(codec, spec->imux_pins[i]); 2708352f7f91STakashi Iwai 2709352f7f91STakashi Iwai for (type = 0; type < 2; type++) { 2710352f7f91STakashi Iwai err = add_single_cap_ctl(codec, label, type_idx, type, 2711352f7f91STakashi Iwai get_first_cap_ctl(codec, i, type), 2712352f7f91STakashi Iwai inv_dmic); 2713d13bd412STakashi Iwai if (err < 0) 2714071c73adSTakashi Iwai return err; 2715352f7f91STakashi Iwai } 2716352f7f91STakashi Iwai } 2717071c73adSTakashi Iwai return 0; 2718352f7f91STakashi Iwai } 2719071c73adSTakashi Iwai 2720352f7f91STakashi Iwai static int create_capture_mixers(struct hda_codec *codec) 2721352f7f91STakashi Iwai { 2722352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2723352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 2724352f7f91STakashi Iwai int i, n, nums, err; 2725352f7f91STakashi Iwai 2726352f7f91STakashi Iwai if (spec->dyn_adc_switch) 2727352f7f91STakashi Iwai nums = 1; 2728352f7f91STakashi Iwai else 2729352f7f91STakashi Iwai nums = spec->num_adc_nids; 2730352f7f91STakashi Iwai 2731352f7f91STakashi Iwai if (!spec->auto_mic && imux->num_items > 1) { 2732352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 2733624d914dSTakashi Iwai const char *name; 2734624d914dSTakashi Iwai name = nums > 1 ? "Input Source" : "Capture Source"; 2735624d914dSTakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &cap_src_temp); 2736352f7f91STakashi Iwai if (!knew) 2737352f7f91STakashi Iwai return -ENOMEM; 2738352f7f91STakashi Iwai knew->count = nums; 2739352f7f91STakashi Iwai } 2740352f7f91STakashi Iwai 2741352f7f91STakashi Iwai for (n = 0; n < nums; n++) { 2742352f7f91STakashi Iwai bool multi = false; 2743352f7f91STakashi Iwai bool inv_dmic = false; 2744352f7f91STakashi Iwai int vol, sw; 2745352f7f91STakashi Iwai 2746352f7f91STakashi Iwai vol = sw = 0; 2747352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2748352f7f91STakashi Iwai struct nid_path *path; 2749c697b716STakashi Iwai path = get_input_path(codec, n, i); 2750352f7f91STakashi Iwai if (!path) 2751352f7f91STakashi Iwai continue; 2752352f7f91STakashi Iwai parse_capvol_in_path(codec, path); 2753352f7f91STakashi Iwai if (!vol) 2754352f7f91STakashi Iwai vol = path->ctls[NID_PATH_VOL_CTL]; 2755352f7f91STakashi Iwai else if (vol != path->ctls[NID_PATH_VOL_CTL]) 2756352f7f91STakashi Iwai multi = true; 2757352f7f91STakashi Iwai if (!sw) 2758352f7f91STakashi Iwai sw = path->ctls[NID_PATH_MUTE_CTL]; 2759352f7f91STakashi Iwai else if (sw != path->ctls[NID_PATH_MUTE_CTL]) 2760352f7f91STakashi Iwai multi = true; 2761352f7f91STakashi Iwai if (is_inv_dmic_pin(codec, spec->imux_pins[i])) 2762352f7f91STakashi Iwai inv_dmic = true; 2763352f7f91STakashi Iwai } 2764352f7f91STakashi Iwai 2765352f7f91STakashi Iwai if (!multi) 2766352f7f91STakashi Iwai err = create_single_cap_vol_ctl(codec, n, vol, sw, 2767352f7f91STakashi Iwai inv_dmic); 2768352f7f91STakashi Iwai else if (!spec->multi_cap_vol) 2769352f7f91STakashi Iwai err = create_bind_cap_vol_ctl(codec, n, vol, sw); 2770352f7f91STakashi Iwai else 2771352f7f91STakashi Iwai err = create_multi_cap_vol_ctl(codec); 2772d13bd412STakashi Iwai if (err < 0) 2773071c73adSTakashi Iwai return err; 2774071c73adSTakashi Iwai } 2775071c73adSTakashi Iwai 27761da177e4SLinus Torvalds return 0; 27771da177e4SLinus Torvalds } 27781da177e4SLinus Torvalds 2779352f7f91STakashi Iwai /* 2780352f7f91STakashi Iwai * add mic boosts if needed 2781352f7f91STakashi Iwai */ 2782352f7f91STakashi Iwai static int parse_mic_boost(struct hda_codec *codec) 2783352f7f91STakashi Iwai { 2784352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2785352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 2786352f7f91STakashi Iwai int i, err; 2787352f7f91STakashi Iwai int type_idx = 0; 2788352f7f91STakashi Iwai hda_nid_t nid; 2789352f7f91STakashi Iwai const char *prev_label = NULL; 2790352f7f91STakashi Iwai 2791352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 2792352f7f91STakashi Iwai if (cfg->inputs[i].type > AUTO_PIN_MIC) 2793352f7f91STakashi Iwai break; 2794352f7f91STakashi Iwai nid = cfg->inputs[i].pin; 2795352f7f91STakashi Iwai if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { 2796352f7f91STakashi Iwai const char *label; 27975abd4888STakashi Iwai char boost_label[44]; 2798352f7f91STakashi Iwai struct nid_path *path; 2799352f7f91STakashi Iwai unsigned int val; 2800352f7f91STakashi Iwai 2801352f7f91STakashi Iwai label = hda_get_autocfg_input_label(codec, cfg, i); 2802352f7f91STakashi Iwai if (prev_label && !strcmp(label, prev_label)) 2803352f7f91STakashi Iwai type_idx++; 2804352f7f91STakashi Iwai else 2805352f7f91STakashi Iwai type_idx = 0; 2806352f7f91STakashi Iwai prev_label = label; 2807352f7f91STakashi Iwai 2808352f7f91STakashi Iwai snprintf(boost_label, sizeof(boost_label), 2809352f7f91STakashi Iwai "%s Boost Volume", label); 2810352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); 2811352f7f91STakashi Iwai err = add_control(spec, HDA_CTL_WIDGET_VOL, 2812352f7f91STakashi Iwai boost_label, type_idx, val); 2813352f7f91STakashi Iwai if (err < 0) 2814352f7f91STakashi Iwai return err; 2815352f7f91STakashi Iwai 2816352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, nid, 0); 2817352f7f91STakashi Iwai if (path) 2818352f7f91STakashi Iwai path->ctls[NID_PATH_BOOST_CTL] = val; 2819352f7f91STakashi Iwai } 2820352f7f91STakashi Iwai } 2821352f7f91STakashi Iwai return 0; 2822352f7f91STakashi Iwai } 2823352f7f91STakashi Iwai 2824352f7f91STakashi Iwai /* 2825352f7f91STakashi Iwai * parse digital I/Os and set up NIDs in BIOS auto-parse mode 2826352f7f91STakashi Iwai */ 2827352f7f91STakashi Iwai static void parse_digital(struct hda_codec *codec) 2828352f7f91STakashi Iwai { 2829352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 28300c8c0f56STakashi Iwai struct nid_path *path; 2831352f7f91STakashi Iwai int i, nums; 28322c12c30dSTakashi Iwai hda_nid_t dig_nid, pin; 2833352f7f91STakashi Iwai 2834352f7f91STakashi Iwai /* support multiple SPDIFs; the secondary is set up as a slave */ 2835352f7f91STakashi Iwai nums = 0; 2836352f7f91STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) { 28372c12c30dSTakashi Iwai pin = spec->autocfg.dig_out_pins[i]; 2838352f7f91STakashi Iwai dig_nid = look_for_dac(codec, pin, true); 2839352f7f91STakashi Iwai if (!dig_nid) 2840352f7f91STakashi Iwai continue; 28413ca529d3STakashi Iwai path = snd_hda_add_new_path(codec, dig_nid, pin, 0); 28420c8c0f56STakashi Iwai if (!path) 2843352f7f91STakashi Iwai continue; 28440c8c0f56STakashi Iwai print_nid_path("digout", path); 2845e1284af7STakashi Iwai path->active = true; 2846196c1766STakashi Iwai spec->digout_paths[i] = snd_hda_get_path_idx(codec, path); 28472c12c30dSTakashi Iwai set_pin_target(codec, pin, PIN_OUT, false); 2848352f7f91STakashi Iwai if (!nums) { 2849352f7f91STakashi Iwai spec->multiout.dig_out_nid = dig_nid; 2850352f7f91STakashi Iwai spec->dig_out_type = spec->autocfg.dig_out_type[0]; 2851352f7f91STakashi Iwai } else { 2852352f7f91STakashi Iwai spec->multiout.slave_dig_outs = spec->slave_dig_outs; 2853352f7f91STakashi Iwai if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) 2854352f7f91STakashi Iwai break; 2855352f7f91STakashi Iwai spec->slave_dig_outs[nums - 1] = dig_nid; 2856352f7f91STakashi Iwai } 2857352f7f91STakashi Iwai nums++; 2858352f7f91STakashi Iwai } 2859352f7f91STakashi Iwai 2860352f7f91STakashi Iwai if (spec->autocfg.dig_in_pin) { 28612c12c30dSTakashi Iwai pin = spec->autocfg.dig_in_pin; 2862352f7f91STakashi Iwai dig_nid = codec->start_nid; 2863352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, dig_nid++) { 2864352f7f91STakashi Iwai unsigned int wcaps = get_wcaps(codec, dig_nid); 2865352f7f91STakashi Iwai if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) 2866352f7f91STakashi Iwai continue; 2867352f7f91STakashi Iwai if (!(wcaps & AC_WCAP_DIGITAL)) 2868352f7f91STakashi Iwai continue; 28692c12c30dSTakashi Iwai path = snd_hda_add_new_path(codec, pin, dig_nid, 0); 2870352f7f91STakashi Iwai if (path) { 28710c8c0f56STakashi Iwai print_nid_path("digin", path); 2872352f7f91STakashi Iwai path->active = true; 2873352f7f91STakashi Iwai spec->dig_in_nid = dig_nid; 28742430d7b7STakashi Iwai spec->digin_path = snd_hda_get_path_idx(codec, path); 28752c12c30dSTakashi Iwai set_pin_target(codec, pin, PIN_IN, false); 2876352f7f91STakashi Iwai break; 2877352f7f91STakashi Iwai } 2878352f7f91STakashi Iwai } 2879352f7f91STakashi Iwai } 2880352f7f91STakashi Iwai } 2881352f7f91STakashi Iwai 28821da177e4SLinus Torvalds 28831da177e4SLinus Torvalds /* 2884352f7f91STakashi Iwai * input MUX handling 28851da177e4SLinus Torvalds */ 28861da177e4SLinus Torvalds 2887352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur); 2888352f7f91STakashi Iwai 2889352f7f91STakashi Iwai /* select the given imux item; either unmute exclusively or select the route */ 2890352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx, 2891352f7f91STakashi Iwai unsigned int idx) 2892352f7f91STakashi Iwai { 2893352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2894352f7f91STakashi Iwai const struct hda_input_mux *imux; 2895352f7f91STakashi Iwai struct nid_path *path; 2896352f7f91STakashi Iwai 2897352f7f91STakashi Iwai imux = &spec->input_mux; 2898352f7f91STakashi Iwai if (!imux->num_items) 28991da177e4SLinus Torvalds return 0; 29001da177e4SLinus Torvalds 2901352f7f91STakashi Iwai if (idx >= imux->num_items) 2902352f7f91STakashi Iwai idx = imux->num_items - 1; 2903352f7f91STakashi Iwai if (spec->cur_mux[adc_idx] == idx) 2904352f7f91STakashi Iwai return 0; 2905352f7f91STakashi Iwai 2906c697b716STakashi Iwai path = get_input_path(codec, adc_idx, spec->cur_mux[adc_idx]); 2907352f7f91STakashi Iwai if (!path) 2908352f7f91STakashi Iwai return 0; 2909352f7f91STakashi Iwai if (path->active) 2910352f7f91STakashi Iwai snd_hda_activate_path(codec, path, false, false); 2911352f7f91STakashi Iwai 2912352f7f91STakashi Iwai spec->cur_mux[adc_idx] = idx; 2913352f7f91STakashi Iwai 2914352f7f91STakashi Iwai if (spec->shared_mic_hp) 2915352f7f91STakashi Iwai update_shared_mic_hp(codec, spec->cur_mux[adc_idx]); 2916352f7f91STakashi Iwai 2917352f7f91STakashi Iwai if (spec->dyn_adc_switch) 2918352f7f91STakashi Iwai dyn_adc_pcm_resetup(codec, idx); 2919352f7f91STakashi Iwai 2920c697b716STakashi Iwai path = get_input_path(codec, adc_idx, idx); 2921352f7f91STakashi Iwai if (!path) 2922352f7f91STakashi Iwai return 0; 2923352f7f91STakashi Iwai if (path->active) 2924352f7f91STakashi Iwai return 0; 2925352f7f91STakashi Iwai snd_hda_activate_path(codec, path, true, false); 2926352f7f91STakashi Iwai if (spec->cap_sync_hook) 2927352f7f91STakashi Iwai spec->cap_sync_hook(codec); 29281da177e4SLinus Torvalds return 1; 29291da177e4SLinus Torvalds } 29301da177e4SLinus Torvalds 29311da177e4SLinus Torvalds 29321da177e4SLinus Torvalds /* 2933352f7f91STakashi Iwai * Jack detections for HP auto-mute and mic-switch 29341da177e4SLinus Torvalds */ 2935352f7f91STakashi Iwai 2936352f7f91STakashi Iwai /* check each pin in the given array; returns true if any of them is plugged */ 2937352f7f91STakashi Iwai static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) 29381da177e4SLinus Torvalds { 2939352f7f91STakashi Iwai int i, present = 0; 29401da177e4SLinus Torvalds 2941352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 2942352f7f91STakashi Iwai hda_nid_t nid = pins[i]; 2943352f7f91STakashi Iwai if (!nid) 2944352f7f91STakashi Iwai break; 29450b4df931STakashi Iwai /* don't detect pins retasked as inputs */ 29460b4df931STakashi Iwai if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN) 29470b4df931STakashi Iwai continue; 2948352f7f91STakashi Iwai present |= snd_hda_jack_detect(codec, nid); 29491da177e4SLinus Torvalds } 2950352f7f91STakashi Iwai return present; 29511da177e4SLinus Torvalds } 29521da177e4SLinus Torvalds 2953352f7f91STakashi Iwai /* standard HP/line-out auto-mute helper */ 2954352f7f91STakashi Iwai static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, 29552c12c30dSTakashi Iwai bool mute) 29561da177e4SLinus Torvalds { 2957352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2958352f7f91STakashi Iwai int i; 29591da177e4SLinus Torvalds 2960352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 2961352f7f91STakashi Iwai hda_nid_t nid = pins[i]; 2962352f7f91STakashi Iwai unsigned int val; 2963352f7f91STakashi Iwai if (!nid) 2964352f7f91STakashi Iwai break; 2965352f7f91STakashi Iwai /* don't reset VREF value in case it's controlling 2966352f7f91STakashi Iwai * the amp (see alc861_fixup_asus_amp_vref_0f()) 2967352f7f91STakashi Iwai */ 29682c12c30dSTakashi Iwai if (spec->keep_vref_in_automute) 29692c12c30dSTakashi Iwai val = snd_hda_codec_get_pin_target(codec, nid) & ~PIN_HP; 29702c12c30dSTakashi Iwai else 2971352f7f91STakashi Iwai val = 0; 29722c12c30dSTakashi Iwai if (!mute) 29732c12c30dSTakashi Iwai val |= snd_hda_codec_get_pin_target(codec, nid); 29742c12c30dSTakashi Iwai /* here we call update_pin_ctl() so that the pinctl is changed 29752c12c30dSTakashi Iwai * without changing the pinctl target value; 29762c12c30dSTakashi Iwai * the original target value will be still referred at the 29772c12c30dSTakashi Iwai * init / resume again 29782c12c30dSTakashi Iwai */ 29792c12c30dSTakashi Iwai update_pin_ctl(codec, nid, val); 2980d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, !mute); 2981352f7f91STakashi Iwai } 2982352f7f91STakashi Iwai } 29831da177e4SLinus Torvalds 2984352f7f91STakashi Iwai /* Toggle outputs muting */ 29855d550e15STakashi Iwai void snd_hda_gen_update_outputs(struct hda_codec *codec) 2986352f7f91STakashi Iwai { 2987352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2988352f7f91STakashi Iwai int on; 2989352f7f91STakashi Iwai 2990352f7f91STakashi Iwai /* Control HP pins/amps depending on master_mute state; 2991352f7f91STakashi Iwai * in general, HP pins/amps control should be enabled in all cases, 2992352f7f91STakashi Iwai * but currently set only for master_mute, just to be safe 2993352f7f91STakashi Iwai */ 2994352f7f91STakashi Iwai if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */ 2995352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), 29962c12c30dSTakashi Iwai spec->autocfg.hp_pins, spec->master_mute); 2997352f7f91STakashi Iwai 2998352f7f91STakashi Iwai if (!spec->automute_speaker) 2999352f7f91STakashi Iwai on = 0; 3000352f7f91STakashi Iwai else 3001352f7f91STakashi Iwai on = spec->hp_jack_present | spec->line_jack_present; 3002352f7f91STakashi Iwai on |= spec->master_mute; 3003352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), 30042c12c30dSTakashi Iwai spec->autocfg.speaker_pins, on); 3005352f7f91STakashi Iwai 3006352f7f91STakashi Iwai /* toggle line-out mutes if needed, too */ 3007352f7f91STakashi Iwai /* if LO is a copy of either HP or Speaker, don't need to handle it */ 3008352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] || 3009352f7f91STakashi Iwai spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0]) 3010352f7f91STakashi Iwai return; 3011352f7f91STakashi Iwai if (!spec->automute_lo) 3012352f7f91STakashi Iwai on = 0; 3013352f7f91STakashi Iwai else 3014352f7f91STakashi Iwai on = spec->hp_jack_present; 3015352f7f91STakashi Iwai on |= spec->master_mute; 3016352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), 30172c12c30dSTakashi Iwai spec->autocfg.line_out_pins, on); 3018352f7f91STakashi Iwai } 30195d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs); 3020352f7f91STakashi Iwai 3021352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec) 3022352f7f91STakashi Iwai { 3023352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3024352f7f91STakashi Iwai if (spec->automute_hook) 3025352f7f91STakashi Iwai spec->automute_hook(codec); 3026352f7f91STakashi Iwai else 30275d550e15STakashi Iwai snd_hda_gen_update_outputs(codec); 3028352f7f91STakashi Iwai } 3029352f7f91STakashi Iwai 3030352f7f91STakashi Iwai /* standard HP-automute helper */ 30315d550e15STakashi Iwai void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) 3032352f7f91STakashi Iwai { 3033352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3034352f7f91STakashi Iwai 3035352f7f91STakashi Iwai spec->hp_jack_present = 3036352f7f91STakashi Iwai detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins), 3037352f7f91STakashi Iwai spec->autocfg.hp_pins); 3038352f7f91STakashi Iwai if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo)) 3039352f7f91STakashi Iwai return; 3040352f7f91STakashi Iwai call_update_outputs(codec); 3041352f7f91STakashi Iwai } 30425d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_hp_automute); 3043352f7f91STakashi Iwai 3044352f7f91STakashi Iwai /* standard line-out-automute helper */ 30455d550e15STakashi Iwai void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) 3046352f7f91STakashi Iwai { 3047352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3048352f7f91STakashi Iwai 3049352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) 3050352f7f91STakashi Iwai return; 3051352f7f91STakashi Iwai /* check LO jack only when it's different from HP */ 3052352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0]) 3053352f7f91STakashi Iwai return; 3054352f7f91STakashi Iwai 3055352f7f91STakashi Iwai spec->line_jack_present = 3056352f7f91STakashi Iwai detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), 3057352f7f91STakashi Iwai spec->autocfg.line_out_pins); 3058352f7f91STakashi Iwai if (!spec->automute_speaker || !spec->detect_lo) 3059352f7f91STakashi Iwai return; 3060352f7f91STakashi Iwai call_update_outputs(codec); 3061352f7f91STakashi Iwai } 30625d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_line_automute); 3063352f7f91STakashi Iwai 3064352f7f91STakashi Iwai /* standard mic auto-switch helper */ 30655d550e15STakashi Iwai void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *jack) 3066352f7f91STakashi Iwai { 3067352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3068352f7f91STakashi Iwai int i; 3069352f7f91STakashi Iwai 3070352f7f91STakashi Iwai if (!spec->auto_mic) 3071352f7f91STakashi Iwai return; 3072352f7f91STakashi Iwai 3073352f7f91STakashi Iwai for (i = spec->am_num_entries - 1; i > 0; i--) { 30740b4df931STakashi Iwai hda_nid_t pin = spec->am_entry[i].pin; 30750b4df931STakashi Iwai /* don't detect pins retasked as outputs */ 30760b4df931STakashi Iwai if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN) 30770b4df931STakashi Iwai continue; 30780b4df931STakashi Iwai if (snd_hda_jack_detect(codec, pin)) { 3079352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[i].idx); 3080352f7f91STakashi Iwai return; 3081352f7f91STakashi Iwai } 3082352f7f91STakashi Iwai } 3083352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[0].idx); 30841da177e4SLinus Torvalds } 30855d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_mic_autoswitch); 30861da177e4SLinus Torvalds 30871da177e4SLinus Torvalds /* 3088352f7f91STakashi Iwai * Auto-Mute mode mixer enum support 30891da177e4SLinus Torvalds */ 3090352f7f91STakashi Iwai static int automute_mode_info(struct snd_kcontrol *kcontrol, 3091352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 3092352f7f91STakashi Iwai { 3093352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3094352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3095352f7f91STakashi Iwai static const char * const texts3[] = { 3096352f7f91STakashi Iwai "Disabled", "Speaker Only", "Line Out+Speaker" 30971da177e4SLinus Torvalds }; 30981da177e4SLinus Torvalds 3099352f7f91STakashi Iwai if (spec->automute_speaker_possible && spec->automute_lo_possible) 3100352f7f91STakashi Iwai return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3); 3101352f7f91STakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo); 3102352f7f91STakashi Iwai } 3103352f7f91STakashi Iwai 3104352f7f91STakashi Iwai static int automute_mode_get(struct snd_kcontrol *kcontrol, 3105352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3106352f7f91STakashi Iwai { 3107352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3108352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3109352f7f91STakashi Iwai unsigned int val = 0; 3110352f7f91STakashi Iwai if (spec->automute_speaker) 3111352f7f91STakashi Iwai val++; 3112352f7f91STakashi Iwai if (spec->automute_lo) 3113352f7f91STakashi Iwai val++; 3114352f7f91STakashi Iwai 3115352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = val; 3116352f7f91STakashi Iwai return 0; 3117352f7f91STakashi Iwai } 3118352f7f91STakashi Iwai 3119352f7f91STakashi Iwai static int automute_mode_put(struct snd_kcontrol *kcontrol, 3120352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3121352f7f91STakashi Iwai { 3122352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3123352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3124352f7f91STakashi Iwai 3125352f7f91STakashi Iwai switch (ucontrol->value.enumerated.item[0]) { 3126352f7f91STakashi Iwai case 0: 3127352f7f91STakashi Iwai if (!spec->automute_speaker && !spec->automute_lo) 3128352f7f91STakashi Iwai return 0; 3129352f7f91STakashi Iwai spec->automute_speaker = 0; 3130352f7f91STakashi Iwai spec->automute_lo = 0; 3131352f7f91STakashi Iwai break; 3132352f7f91STakashi Iwai case 1: 3133352f7f91STakashi Iwai if (spec->automute_speaker_possible) { 3134352f7f91STakashi Iwai if (!spec->automute_lo && spec->automute_speaker) 3135352f7f91STakashi Iwai return 0; 3136352f7f91STakashi Iwai spec->automute_speaker = 1; 3137352f7f91STakashi Iwai spec->automute_lo = 0; 3138352f7f91STakashi Iwai } else if (spec->automute_lo_possible) { 3139352f7f91STakashi Iwai if (spec->automute_lo) 3140352f7f91STakashi Iwai return 0; 3141352f7f91STakashi Iwai spec->automute_lo = 1; 3142352f7f91STakashi Iwai } else 3143352f7f91STakashi Iwai return -EINVAL; 3144352f7f91STakashi Iwai break; 3145352f7f91STakashi Iwai case 2: 3146352f7f91STakashi Iwai if (!spec->automute_lo_possible || !spec->automute_speaker_possible) 3147352f7f91STakashi Iwai return -EINVAL; 3148352f7f91STakashi Iwai if (spec->automute_speaker && spec->automute_lo) 3149352f7f91STakashi Iwai return 0; 3150352f7f91STakashi Iwai spec->automute_speaker = 1; 3151352f7f91STakashi Iwai spec->automute_lo = 1; 3152352f7f91STakashi Iwai break; 3153352f7f91STakashi Iwai default: 3154352f7f91STakashi Iwai return -EINVAL; 3155352f7f91STakashi Iwai } 3156352f7f91STakashi Iwai call_update_outputs(codec); 3157352f7f91STakashi Iwai return 1; 3158352f7f91STakashi Iwai } 3159352f7f91STakashi Iwai 3160352f7f91STakashi Iwai static const struct snd_kcontrol_new automute_mode_enum = { 3161352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3162352f7f91STakashi Iwai .name = "Auto-Mute Mode", 3163352f7f91STakashi Iwai .info = automute_mode_info, 3164352f7f91STakashi Iwai .get = automute_mode_get, 3165352f7f91STakashi Iwai .put = automute_mode_put, 3166352f7f91STakashi Iwai }; 3167352f7f91STakashi Iwai 3168352f7f91STakashi Iwai static int add_automute_mode_enum(struct hda_codec *codec) 3169352f7f91STakashi Iwai { 3170352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3171352f7f91STakashi Iwai 317212c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &automute_mode_enum)) 3173352f7f91STakashi Iwai return -ENOMEM; 3174352f7f91STakashi Iwai return 0; 3175352f7f91STakashi Iwai } 3176352f7f91STakashi Iwai 3177352f7f91STakashi Iwai /* 3178352f7f91STakashi Iwai * Check the availability of HP/line-out auto-mute; 3179352f7f91STakashi Iwai * Set up appropriately if really supported 3180352f7f91STakashi Iwai */ 3181352f7f91STakashi Iwai static int check_auto_mute_availability(struct hda_codec *codec) 3182352f7f91STakashi Iwai { 3183352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3184352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 3185352f7f91STakashi Iwai int present = 0; 3186352f7f91STakashi Iwai int i, err; 3187352f7f91STakashi Iwai 3188352f7f91STakashi Iwai if (cfg->hp_pins[0]) 3189352f7f91STakashi Iwai present++; 3190352f7f91STakashi Iwai if (cfg->line_out_pins[0]) 3191352f7f91STakashi Iwai present++; 3192352f7f91STakashi Iwai if (cfg->speaker_pins[0]) 3193352f7f91STakashi Iwai present++; 3194352f7f91STakashi Iwai if (present < 2) /* need two different output types */ 3195352f7f91STakashi Iwai return 0; 3196352f7f91STakashi Iwai 3197352f7f91STakashi Iwai if (!cfg->speaker_pins[0] && 3198352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { 3199352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 3200352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 3201352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 3202352f7f91STakashi Iwai } 3203352f7f91STakashi Iwai 3204352f7f91STakashi Iwai if (!cfg->hp_pins[0] && 3205352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) { 3206352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins, 3207352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 3208352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs; 3209352f7f91STakashi Iwai } 3210352f7f91STakashi Iwai 3211352f7f91STakashi Iwai for (i = 0; i < cfg->hp_outs; i++) { 3212352f7f91STakashi Iwai hda_nid_t nid = cfg->hp_pins[i]; 3213352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 3214352f7f91STakashi Iwai continue; 3215352f7f91STakashi Iwai snd_printdd("hda-codec: Enable HP auto-muting on NID 0x%x\n", 3216352f7f91STakashi Iwai nid); 3217352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid, HDA_GEN_HP_EVENT, 32182e03e952STakashi Iwai spec->hp_automute_hook ? 32192e03e952STakashi Iwai spec->hp_automute_hook : 32205d550e15STakashi Iwai snd_hda_gen_hp_automute); 3221352f7f91STakashi Iwai spec->detect_hp = 1; 3222352f7f91STakashi Iwai } 3223352f7f91STakashi Iwai 3224352f7f91STakashi Iwai if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) { 3225352f7f91STakashi Iwai if (cfg->speaker_outs) 3226352f7f91STakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 3227352f7f91STakashi Iwai hda_nid_t nid = cfg->line_out_pins[i]; 3228352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 3229352f7f91STakashi Iwai continue; 3230352f7f91STakashi Iwai snd_printdd("hda-codec: Enable Line-Out auto-muting on NID 0x%x\n", nid); 3231352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid, 3232352f7f91STakashi Iwai HDA_GEN_FRONT_EVENT, 32332e03e952STakashi Iwai spec->line_automute_hook ? 32342e03e952STakashi Iwai spec->line_automute_hook : 32355d550e15STakashi Iwai snd_hda_gen_line_automute); 3236352f7f91STakashi Iwai spec->detect_lo = 1; 3237352f7f91STakashi Iwai } 3238352f7f91STakashi Iwai spec->automute_lo_possible = spec->detect_hp; 3239352f7f91STakashi Iwai } 3240352f7f91STakashi Iwai 3241352f7f91STakashi Iwai spec->automute_speaker_possible = cfg->speaker_outs && 3242352f7f91STakashi Iwai (spec->detect_hp || spec->detect_lo); 3243352f7f91STakashi Iwai 3244352f7f91STakashi Iwai spec->automute_lo = spec->automute_lo_possible; 3245352f7f91STakashi Iwai spec->automute_speaker = spec->automute_speaker_possible; 3246352f7f91STakashi Iwai 3247352f7f91STakashi Iwai if (spec->automute_speaker_possible || spec->automute_lo_possible) { 3248352f7f91STakashi Iwai /* create a control for automute mode */ 3249352f7f91STakashi Iwai err = add_automute_mode_enum(codec); 3250352f7f91STakashi Iwai if (err < 0) 3251352f7f91STakashi Iwai return err; 3252352f7f91STakashi Iwai } 3253352f7f91STakashi Iwai return 0; 3254352f7f91STakashi Iwai } 3255352f7f91STakashi Iwai 3256352f7f91STakashi Iwai /* check whether all auto-mic pins are valid; setup indices if OK */ 3257352f7f91STakashi Iwai static bool auto_mic_check_imux(struct hda_codec *codec) 3258352f7f91STakashi Iwai { 3259352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3260352f7f91STakashi Iwai const struct hda_input_mux *imux; 3261352f7f91STakashi Iwai int i; 3262352f7f91STakashi Iwai 3263352f7f91STakashi Iwai imux = &spec->input_mux; 3264352f7f91STakashi Iwai for (i = 0; i < spec->am_num_entries; i++) { 3265352f7f91STakashi Iwai spec->am_entry[i].idx = 3266352f7f91STakashi Iwai find_idx_in_nid_list(spec->am_entry[i].pin, 3267352f7f91STakashi Iwai spec->imux_pins, imux->num_items); 3268352f7f91STakashi Iwai if (spec->am_entry[i].idx < 0) 3269352f7f91STakashi Iwai return false; /* no corresponding imux */ 3270352f7f91STakashi Iwai } 3271352f7f91STakashi Iwai 3272352f7f91STakashi Iwai /* we don't need the jack detection for the first pin */ 3273352f7f91STakashi Iwai for (i = 1; i < spec->am_num_entries; i++) 3274352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, 3275352f7f91STakashi Iwai spec->am_entry[i].pin, 3276352f7f91STakashi Iwai HDA_GEN_MIC_EVENT, 32772e03e952STakashi Iwai spec->mic_autoswitch_hook ? 32782e03e952STakashi Iwai spec->mic_autoswitch_hook : 32795d550e15STakashi Iwai snd_hda_gen_mic_autoswitch); 3280352f7f91STakashi Iwai return true; 3281352f7f91STakashi Iwai } 3282352f7f91STakashi Iwai 3283352f7f91STakashi Iwai static int compare_attr(const void *ap, const void *bp) 3284352f7f91STakashi Iwai { 3285352f7f91STakashi Iwai const struct automic_entry *a = ap; 3286352f7f91STakashi Iwai const struct automic_entry *b = bp; 3287352f7f91STakashi Iwai return (int)(a->attr - b->attr); 3288352f7f91STakashi Iwai } 3289352f7f91STakashi Iwai 3290352f7f91STakashi Iwai /* 3291352f7f91STakashi Iwai * Check the availability of auto-mic switch; 3292352f7f91STakashi Iwai * Set up if really supported 3293352f7f91STakashi Iwai */ 3294352f7f91STakashi Iwai static int check_auto_mic_availability(struct hda_codec *codec) 3295352f7f91STakashi Iwai { 3296352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3297352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 3298352f7f91STakashi Iwai unsigned int types; 3299352f7f91STakashi Iwai int i, num_pins; 3300352f7f91STakashi Iwai 3301d12daf6fSTakashi Iwai if (spec->suppress_auto_mic) 3302d12daf6fSTakashi Iwai return 0; 3303d12daf6fSTakashi Iwai 3304352f7f91STakashi Iwai types = 0; 3305352f7f91STakashi Iwai num_pins = 0; 3306352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 3307352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 3308352f7f91STakashi Iwai unsigned int attr; 3309352f7f91STakashi Iwai attr = snd_hda_codec_get_pincfg(codec, nid); 3310352f7f91STakashi Iwai attr = snd_hda_get_input_pin_attr(attr); 3311352f7f91STakashi Iwai if (types & (1 << attr)) 3312352f7f91STakashi Iwai return 0; /* already occupied */ 3313352f7f91STakashi Iwai switch (attr) { 3314352f7f91STakashi Iwai case INPUT_PIN_ATTR_INT: 3315352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC) 3316352f7f91STakashi Iwai return 0; /* invalid type */ 3317352f7f91STakashi Iwai break; 3318352f7f91STakashi Iwai case INPUT_PIN_ATTR_UNUSED: 3319352f7f91STakashi Iwai return 0; /* invalid entry */ 3320352f7f91STakashi Iwai default: 3321352f7f91STakashi Iwai if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) 3322352f7f91STakashi Iwai return 0; /* invalid type */ 3323352f7f91STakashi Iwai if (!spec->line_in_auto_switch && 3324352f7f91STakashi Iwai cfg->inputs[i].type != AUTO_PIN_MIC) 3325352f7f91STakashi Iwai return 0; /* only mic is allowed */ 3326352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 3327352f7f91STakashi Iwai return 0; /* no unsol support */ 3328352f7f91STakashi Iwai break; 3329352f7f91STakashi Iwai } 3330352f7f91STakashi Iwai if (num_pins >= MAX_AUTO_MIC_PINS) 3331352f7f91STakashi Iwai return 0; 3332352f7f91STakashi Iwai types |= (1 << attr); 3333352f7f91STakashi Iwai spec->am_entry[num_pins].pin = nid; 3334352f7f91STakashi Iwai spec->am_entry[num_pins].attr = attr; 3335352f7f91STakashi Iwai num_pins++; 3336352f7f91STakashi Iwai } 3337352f7f91STakashi Iwai 3338352f7f91STakashi Iwai if (num_pins < 2) 3339352f7f91STakashi Iwai return 0; 3340352f7f91STakashi Iwai 3341352f7f91STakashi Iwai spec->am_num_entries = num_pins; 3342352f7f91STakashi Iwai /* sort the am_entry in the order of attr so that the pin with a 3343352f7f91STakashi Iwai * higher attr will be selected when the jack is plugged. 3344352f7f91STakashi Iwai */ 3345352f7f91STakashi Iwai sort(spec->am_entry, num_pins, sizeof(spec->am_entry[0]), 3346352f7f91STakashi Iwai compare_attr, NULL); 3347352f7f91STakashi Iwai 3348352f7f91STakashi Iwai if (!auto_mic_check_imux(codec)) 3349352f7f91STakashi Iwai return 0; 3350352f7f91STakashi Iwai 3351352f7f91STakashi Iwai spec->auto_mic = 1; 3352352f7f91STakashi Iwai spec->num_adc_nids = 1; 3353352f7f91STakashi Iwai spec->cur_mux[0] = spec->am_entry[0].idx; 3354352f7f91STakashi Iwai snd_printdd("hda-codec: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", 3355352f7f91STakashi Iwai spec->am_entry[0].pin, 3356352f7f91STakashi Iwai spec->am_entry[1].pin, 3357352f7f91STakashi Iwai spec->am_entry[2].pin); 3358352f7f91STakashi Iwai 3359352f7f91STakashi Iwai return 0; 3360352f7f91STakashi Iwai } 3361352f7f91STakashi Iwai 3362352f7f91STakashi Iwai 33639eb413e5STakashi Iwai /* 33649eb413e5STakashi Iwai * Parse the given BIOS configuration and set up the hda_gen_spec 33659eb413e5STakashi Iwai * 33669eb413e5STakashi Iwai * return 1 if successful, 0 if the proper config is not found, 3367352f7f91STakashi Iwai * or a negative error code 3368352f7f91STakashi Iwai */ 3369352f7f91STakashi Iwai int snd_hda_gen_parse_auto_config(struct hda_codec *codec, 33709eb413e5STakashi Iwai struct auto_pin_cfg *cfg) 3371352f7f91STakashi Iwai { 3372352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3373352f7f91STakashi Iwai int err; 3374352f7f91STakashi Iwai 3375*1c70a583STakashi Iwai parse_user_hints(codec); 3376*1c70a583STakashi Iwai 33779eb413e5STakashi Iwai if (cfg != &spec->autocfg) { 33789eb413e5STakashi Iwai spec->autocfg = *cfg; 33799eb413e5STakashi Iwai cfg = &spec->autocfg; 33809eb413e5STakashi Iwai } 33819eb413e5STakashi Iwai 3382352f7f91STakashi Iwai if (!cfg->line_outs) { 3383352f7f91STakashi Iwai if (cfg->dig_outs || cfg->dig_in_pin) { 3384352f7f91STakashi Iwai spec->multiout.max_channels = 2; 3385352f7f91STakashi Iwai spec->no_analog = 1; 3386352f7f91STakashi Iwai goto dig_only; 3387352f7f91STakashi Iwai } 3388352f7f91STakashi Iwai return 0; /* can't find valid BIOS pin config */ 3389352f7f91STakashi Iwai } 3390352f7f91STakashi Iwai 3391352f7f91STakashi Iwai if (!spec->no_primary_hp && 3392352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && 3393352f7f91STakashi Iwai cfg->line_outs <= cfg->hp_outs) { 3394352f7f91STakashi Iwai /* use HP as primary out */ 3395352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 3396352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 3397352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 3398352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs; 3399352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); 3400352f7f91STakashi Iwai cfg->hp_outs = 0; 3401352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 3402352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT; 3403352f7f91STakashi Iwai } 3404352f7f91STakashi Iwai 3405352f7f91STakashi Iwai err = parse_output_paths(codec); 3406352f7f91STakashi Iwai if (err < 0) 3407352f7f91STakashi Iwai return err; 3408352f7f91STakashi Iwai err = create_multi_channel_mode(codec); 3409352f7f91STakashi Iwai if (err < 0) 3410352f7f91STakashi Iwai return err; 3411352f7f91STakashi Iwai err = create_multi_out_ctls(codec, cfg); 3412352f7f91STakashi Iwai if (err < 0) 3413352f7f91STakashi Iwai return err; 3414352f7f91STakashi Iwai err = create_hp_out_ctls(codec); 3415352f7f91STakashi Iwai if (err < 0) 3416352f7f91STakashi Iwai return err; 3417352f7f91STakashi Iwai err = create_speaker_out_ctls(codec); 3418352f7f91STakashi Iwai if (err < 0) 3419352f7f91STakashi Iwai return err; 342038cf6f1aSTakashi Iwai err = create_indep_hp_ctls(codec); 342138cf6f1aSTakashi Iwai if (err < 0) 342238cf6f1aSTakashi Iwai return err; 3423c30aa7b2STakashi Iwai err = create_loopback_mixing_ctl(codec); 3424c30aa7b2STakashi Iwai if (err < 0) 3425c30aa7b2STakashi Iwai return err; 3426352f7f91STakashi Iwai err = create_shared_input(codec); 3427352f7f91STakashi Iwai if (err < 0) 3428352f7f91STakashi Iwai return err; 3429352f7f91STakashi Iwai err = create_input_ctls(codec); 3430352f7f91STakashi Iwai if (err < 0) 3431352f7f91STakashi Iwai return err; 3432352f7f91STakashi Iwai 3433a07a949bSTakashi Iwai spec->const_channel_count = spec->ext_channel_count; 3434a07a949bSTakashi Iwai /* check the multiple speaker and headphone pins */ 3435a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 3436a07a949bSTakashi Iwai spec->const_channel_count = max(spec->const_channel_count, 3437a07a949bSTakashi Iwai cfg->speaker_outs * 2); 3438a07a949bSTakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 3439a07a949bSTakashi Iwai spec->const_channel_count = max(spec->const_channel_count, 3440a07a949bSTakashi Iwai cfg->hp_outs * 2); 3441352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count, 3442352f7f91STakashi Iwai spec->const_channel_count); 3443352f7f91STakashi Iwai 3444352f7f91STakashi Iwai err = check_auto_mute_availability(codec); 3445352f7f91STakashi Iwai if (err < 0) 3446352f7f91STakashi Iwai return err; 3447352f7f91STakashi Iwai 3448352f7f91STakashi Iwai err = check_dyn_adc_switch(codec); 3449352f7f91STakashi Iwai if (err < 0) 3450352f7f91STakashi Iwai return err; 3451352f7f91STakashi Iwai 3452352f7f91STakashi Iwai if (!spec->shared_mic_hp) { 3453352f7f91STakashi Iwai err = check_auto_mic_availability(codec); 3454352f7f91STakashi Iwai if (err < 0) 3455352f7f91STakashi Iwai return err; 3456352f7f91STakashi Iwai } 3457352f7f91STakashi Iwai 3458352f7f91STakashi Iwai err = create_capture_mixers(codec); 3459352f7f91STakashi Iwai if (err < 0) 3460352f7f91STakashi Iwai return err; 3461352f7f91STakashi Iwai 3462352f7f91STakashi Iwai err = parse_mic_boost(codec); 3463352f7f91STakashi Iwai if (err < 0) 3464352f7f91STakashi Iwai return err; 3465352f7f91STakashi Iwai 3466978e77e7STakashi Iwai if (spec->add_out_jack_modes) { 3467978e77e7STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 3468978e77e7STakashi Iwai err = create_out_jack_modes(codec, cfg->line_outs, 3469978e77e7STakashi Iwai cfg->line_out_pins); 3470978e77e7STakashi Iwai if (err < 0) 3471978e77e7STakashi Iwai return err; 3472978e77e7STakashi Iwai } 3473978e77e7STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) { 3474978e77e7STakashi Iwai err = create_out_jack_modes(codec, cfg->hp_outs, 3475978e77e7STakashi Iwai cfg->hp_pins); 3476978e77e7STakashi Iwai if (err < 0) 3477978e77e7STakashi Iwai return err; 3478978e77e7STakashi Iwai } 3479978e77e7STakashi Iwai } 3480978e77e7STakashi Iwai 3481352f7f91STakashi Iwai dig_only: 3482352f7f91STakashi Iwai parse_digital(codec); 3483352f7f91STakashi Iwai 3484352f7f91STakashi Iwai return 1; 3485352f7f91STakashi Iwai } 3486352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_parse_auto_config); 3487352f7f91STakashi Iwai 3488352f7f91STakashi Iwai 3489352f7f91STakashi Iwai /* 3490352f7f91STakashi Iwai * Build control elements 3491352f7f91STakashi Iwai */ 3492352f7f91STakashi Iwai 3493352f7f91STakashi Iwai /* slave controls for virtual master */ 3494352f7f91STakashi Iwai static const char * const slave_pfxs[] = { 3495352f7f91STakashi Iwai "Front", "Surround", "Center", "LFE", "Side", 3496352f7f91STakashi Iwai "Headphone", "Speaker", "Mono", "Line Out", 3497352f7f91STakashi Iwai "CLFE", "Bass Speaker", "PCM", 3498ee79c69aSTakashi Iwai "Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side", 3499ee79c69aSTakashi Iwai "Headphone Front", "Headphone Surround", "Headphone CLFE", 3500ee79c69aSTakashi Iwai "Headphone Side", 3501352f7f91STakashi Iwai NULL, 3502352f7f91STakashi Iwai }; 3503352f7f91STakashi Iwai 3504352f7f91STakashi Iwai int snd_hda_gen_build_controls(struct hda_codec *codec) 3505352f7f91STakashi Iwai { 3506352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3507352f7f91STakashi Iwai int err; 3508352f7f91STakashi Iwai 350936502d02STakashi Iwai if (spec->kctls.used) { 3510352f7f91STakashi Iwai err = snd_hda_add_new_ctls(codec, spec->kctls.list); 3511352f7f91STakashi Iwai if (err < 0) 3512352f7f91STakashi Iwai return err; 351336502d02STakashi Iwai } 3514352f7f91STakashi Iwai 3515352f7f91STakashi Iwai if (spec->multiout.dig_out_nid) { 3516352f7f91STakashi Iwai err = snd_hda_create_dig_out_ctls(codec, 3517352f7f91STakashi Iwai spec->multiout.dig_out_nid, 3518352f7f91STakashi Iwai spec->multiout.dig_out_nid, 3519352f7f91STakashi Iwai spec->pcm_rec[1].pcm_type); 3520352f7f91STakashi Iwai if (err < 0) 3521352f7f91STakashi Iwai return err; 3522352f7f91STakashi Iwai if (!spec->no_analog) { 3523352f7f91STakashi Iwai err = snd_hda_create_spdif_share_sw(codec, 3524352f7f91STakashi Iwai &spec->multiout); 3525352f7f91STakashi Iwai if (err < 0) 3526352f7f91STakashi Iwai return err; 3527352f7f91STakashi Iwai spec->multiout.share_spdif = 1; 3528352f7f91STakashi Iwai } 3529352f7f91STakashi Iwai } 3530352f7f91STakashi Iwai if (spec->dig_in_nid) { 3531352f7f91STakashi Iwai err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 3532352f7f91STakashi Iwai if (err < 0) 3533352f7f91STakashi Iwai return err; 3534352f7f91STakashi Iwai } 3535352f7f91STakashi Iwai 3536352f7f91STakashi Iwai /* if we have no master control, let's create it */ 3537352f7f91STakashi Iwai if (!spec->no_analog && 3538352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { 3539352f7f91STakashi Iwai unsigned int vmaster_tlv[4]; 3540352f7f91STakashi Iwai snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, 3541352f7f91STakashi Iwai HDA_OUTPUT, vmaster_tlv); 3542352f7f91STakashi Iwai err = snd_hda_add_vmaster(codec, "Master Playback Volume", 3543352f7f91STakashi Iwai vmaster_tlv, slave_pfxs, 3544352f7f91STakashi Iwai "Playback Volume"); 3545352f7f91STakashi Iwai if (err < 0) 3546352f7f91STakashi Iwai return err; 3547352f7f91STakashi Iwai } 3548352f7f91STakashi Iwai if (!spec->no_analog && 3549352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { 3550352f7f91STakashi Iwai err = __snd_hda_add_vmaster(codec, "Master Playback Switch", 3551352f7f91STakashi Iwai NULL, slave_pfxs, 3552352f7f91STakashi Iwai "Playback Switch", 3553352f7f91STakashi Iwai true, &spec->vmaster_mute.sw_kctl); 3554352f7f91STakashi Iwai if (err < 0) 3555352f7f91STakashi Iwai return err; 3556352f7f91STakashi Iwai if (spec->vmaster_mute.hook) 3557fd25a97aSTakashi Iwai snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, 3558fd25a97aSTakashi Iwai spec->vmaster_mute_enum); 3559352f7f91STakashi Iwai } 3560352f7f91STakashi Iwai 3561352f7f91STakashi Iwai free_kctls(spec); /* no longer needed */ 3562352f7f91STakashi Iwai 3563352f7f91STakashi Iwai if (spec->shared_mic_hp) { 3564352f7f91STakashi Iwai int err; 3565352f7f91STakashi Iwai int nid = spec->autocfg.inputs[1].pin; 3566352f7f91STakashi Iwai err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0); 3567352f7f91STakashi Iwai if (err < 0) 3568352f7f91STakashi Iwai return err; 3569352f7f91STakashi Iwai err = snd_hda_jack_detect_enable(codec, nid, 0); 3570352f7f91STakashi Iwai if (err < 0) 3571352f7f91STakashi Iwai return err; 3572352f7f91STakashi Iwai } 3573352f7f91STakashi Iwai 3574352f7f91STakashi Iwai err = snd_hda_jack_add_kctls(codec, &spec->autocfg); 3575352f7f91STakashi Iwai if (err < 0) 3576352f7f91STakashi Iwai return err; 3577352f7f91STakashi Iwai 3578352f7f91STakashi Iwai return 0; 3579352f7f91STakashi Iwai } 3580352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_controls); 3581352f7f91STakashi Iwai 3582352f7f91STakashi Iwai 3583352f7f91STakashi Iwai /* 3584352f7f91STakashi Iwai * PCM definitions 3585352f7f91STakashi Iwai */ 3586352f7f91STakashi Iwai 3587e6b85f3cSTakashi Iwai static void call_pcm_playback_hook(struct hda_pcm_stream *hinfo, 3588e6b85f3cSTakashi Iwai struct hda_codec *codec, 3589e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream, 3590e6b85f3cSTakashi Iwai int action) 3591e6b85f3cSTakashi Iwai { 3592e6b85f3cSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 3593e6b85f3cSTakashi Iwai if (spec->pcm_playback_hook) 3594e6b85f3cSTakashi Iwai spec->pcm_playback_hook(hinfo, codec, substream, action); 3595e6b85f3cSTakashi Iwai } 3596e6b85f3cSTakashi Iwai 3597352f7f91STakashi Iwai /* 3598352f7f91STakashi Iwai * Analog playback callbacks 3599352f7f91STakashi Iwai */ 3600352f7f91STakashi Iwai static int playback_pcm_open(struct hda_pcm_stream *hinfo, 3601352f7f91STakashi Iwai struct hda_codec *codec, 3602352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3603352f7f91STakashi Iwai { 3604352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 360538cf6f1aSTakashi Iwai int err; 360638cf6f1aSTakashi Iwai 360738cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 360838cf6f1aSTakashi Iwai err = snd_hda_multi_out_analog_open(codec, 360938cf6f1aSTakashi Iwai &spec->multiout, substream, 3610352f7f91STakashi Iwai hinfo); 3611e6b85f3cSTakashi Iwai if (!err) { 361238cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_MULTI_OUT; 3613e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3614e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_OPEN); 3615e6b85f3cSTakashi Iwai } 361638cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 361738cf6f1aSTakashi Iwai return err; 3618352f7f91STakashi Iwai } 3619352f7f91STakashi Iwai 3620352f7f91STakashi Iwai static int playback_pcm_prepare(struct hda_pcm_stream *hinfo, 362197ec558aSTakashi Iwai struct hda_codec *codec, 362297ec558aSTakashi Iwai unsigned int stream_tag, 362397ec558aSTakashi Iwai unsigned int format, 362497ec558aSTakashi Iwai struct snd_pcm_substream *substream) 362597ec558aSTakashi Iwai { 3626352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3627e6b85f3cSTakashi Iwai int err; 3628e6b85f3cSTakashi Iwai 3629e6b85f3cSTakashi Iwai err = snd_hda_multi_out_analog_prepare(codec, &spec->multiout, 3630352f7f91STakashi Iwai stream_tag, format, substream); 3631e6b85f3cSTakashi Iwai if (!err) 3632e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3633e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 3634e6b85f3cSTakashi Iwai return err; 3635352f7f91STakashi Iwai } 363697ec558aSTakashi Iwai 3637352f7f91STakashi Iwai static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 3638352f7f91STakashi Iwai struct hda_codec *codec, 3639352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3640352f7f91STakashi Iwai { 3641352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3642e6b85f3cSTakashi Iwai int err; 3643e6b85f3cSTakashi Iwai 3644e6b85f3cSTakashi Iwai err = snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); 3645e6b85f3cSTakashi Iwai if (!err) 3646e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3647e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 3648e6b85f3cSTakashi Iwai return err; 3649352f7f91STakashi Iwai } 3650352f7f91STakashi Iwai 365138cf6f1aSTakashi Iwai static int playback_pcm_close(struct hda_pcm_stream *hinfo, 365238cf6f1aSTakashi Iwai struct hda_codec *codec, 365338cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 365438cf6f1aSTakashi Iwai { 365538cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 365638cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 365738cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_MULTI_OUT); 3658e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3659e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLOSE); 366038cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 366138cf6f1aSTakashi Iwai return 0; 366238cf6f1aSTakashi Iwai } 366338cf6f1aSTakashi Iwai 366438cf6f1aSTakashi Iwai static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo, 366538cf6f1aSTakashi Iwai struct hda_codec *codec, 366638cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 366738cf6f1aSTakashi Iwai { 366838cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 366938cf6f1aSTakashi Iwai int err = 0; 367038cf6f1aSTakashi Iwai 367138cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 367238cf6f1aSTakashi Iwai if (!spec->indep_hp_enabled) 367338cf6f1aSTakashi Iwai err = -EBUSY; 367438cf6f1aSTakashi Iwai else 367538cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_INDEP_HP; 3676e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3677e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_OPEN); 367838cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 367938cf6f1aSTakashi Iwai return err; 368038cf6f1aSTakashi Iwai } 368138cf6f1aSTakashi Iwai 368238cf6f1aSTakashi Iwai static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo, 368338cf6f1aSTakashi Iwai struct hda_codec *codec, 368438cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 368538cf6f1aSTakashi Iwai { 368638cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 368738cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 368838cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_INDEP_HP); 3689e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3690e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLOSE); 369138cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 369238cf6f1aSTakashi Iwai return 0; 369338cf6f1aSTakashi Iwai } 369438cf6f1aSTakashi Iwai 3695e6b85f3cSTakashi Iwai static int alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 3696e6b85f3cSTakashi Iwai struct hda_codec *codec, 3697e6b85f3cSTakashi Iwai unsigned int stream_tag, 3698e6b85f3cSTakashi Iwai unsigned int format, 3699e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream) 3700e6b85f3cSTakashi Iwai { 3701e6b85f3cSTakashi Iwai snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); 3702e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3703e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_PREPARE); 3704e6b85f3cSTakashi Iwai return 0; 3705e6b85f3cSTakashi Iwai } 3706e6b85f3cSTakashi Iwai 3707e6b85f3cSTakashi Iwai static int alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 3708e6b85f3cSTakashi Iwai struct hda_codec *codec, 3709e6b85f3cSTakashi Iwai struct snd_pcm_substream *substream) 3710e6b85f3cSTakashi Iwai { 3711e6b85f3cSTakashi Iwai snd_hda_codec_cleanup_stream(codec, hinfo->nid); 3712e6b85f3cSTakashi Iwai call_pcm_playback_hook(hinfo, codec, substream, 3713e6b85f3cSTakashi Iwai HDA_GEN_PCM_ACT_CLEANUP); 3714e6b85f3cSTakashi Iwai return 0; 3715e6b85f3cSTakashi Iwai } 3716e6b85f3cSTakashi Iwai 3717352f7f91STakashi Iwai /* 3718352f7f91STakashi Iwai * Digital out 3719352f7f91STakashi Iwai */ 3720352f7f91STakashi Iwai static int dig_playback_pcm_open(struct hda_pcm_stream *hinfo, 3721352f7f91STakashi Iwai struct hda_codec *codec, 3722352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3723352f7f91STakashi Iwai { 3724352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3725352f7f91STakashi Iwai return snd_hda_multi_out_dig_open(codec, &spec->multiout); 3726352f7f91STakashi Iwai } 3727352f7f91STakashi Iwai 3728352f7f91STakashi Iwai static int dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 3729352f7f91STakashi Iwai struct hda_codec *codec, 3730352f7f91STakashi Iwai unsigned int stream_tag, 3731352f7f91STakashi Iwai unsigned int format, 3732352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3733352f7f91STakashi Iwai { 3734352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3735352f7f91STakashi Iwai return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, 3736352f7f91STakashi Iwai stream_tag, format, substream); 3737352f7f91STakashi Iwai } 3738352f7f91STakashi Iwai 3739352f7f91STakashi Iwai static int dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 3740352f7f91STakashi Iwai struct hda_codec *codec, 3741352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3742352f7f91STakashi Iwai { 3743352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3744352f7f91STakashi Iwai return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); 3745352f7f91STakashi Iwai } 3746352f7f91STakashi Iwai 3747352f7f91STakashi Iwai static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo, 3748352f7f91STakashi Iwai struct hda_codec *codec, 3749352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3750352f7f91STakashi Iwai { 3751352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3752352f7f91STakashi Iwai return snd_hda_multi_out_dig_close(codec, &spec->multiout); 3753352f7f91STakashi Iwai } 3754352f7f91STakashi Iwai 3755352f7f91STakashi Iwai /* 3756352f7f91STakashi Iwai * Analog capture 3757352f7f91STakashi Iwai */ 3758352f7f91STakashi Iwai static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 3759352f7f91STakashi Iwai struct hda_codec *codec, 3760352f7f91STakashi Iwai unsigned int stream_tag, 3761352f7f91STakashi Iwai unsigned int format, 3762352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3763352f7f91STakashi Iwai { 3764352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3765352f7f91STakashi Iwai 3766352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], 376797ec558aSTakashi Iwai stream_tag, 0, format); 376897ec558aSTakashi Iwai return 0; 376997ec558aSTakashi Iwai } 377097ec558aSTakashi Iwai 3771352f7f91STakashi Iwai static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 377297ec558aSTakashi Iwai struct hda_codec *codec, 377397ec558aSTakashi Iwai struct snd_pcm_substream *substream) 377497ec558aSTakashi Iwai { 3775352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 377697ec558aSTakashi Iwai 3777352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, 3778352f7f91STakashi Iwai spec->adc_nids[substream->number + 1]); 377997ec558aSTakashi Iwai return 0; 378097ec558aSTakashi Iwai } 378197ec558aSTakashi Iwai 3782352f7f91STakashi Iwai /* 3783352f7f91STakashi Iwai */ 3784352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_playback = { 3785352f7f91STakashi Iwai .substreams = 1, 3786352f7f91STakashi Iwai .channels_min = 2, 3787352f7f91STakashi Iwai .channels_max = 8, 3788352f7f91STakashi Iwai /* NID is set in build_pcms */ 3789352f7f91STakashi Iwai .ops = { 3790352f7f91STakashi Iwai .open = playback_pcm_open, 379138cf6f1aSTakashi Iwai .close = playback_pcm_close, 3792352f7f91STakashi Iwai .prepare = playback_pcm_prepare, 3793352f7f91STakashi Iwai .cleanup = playback_pcm_cleanup 3794352f7f91STakashi Iwai }, 3795352f7f91STakashi Iwai }; 3796352f7f91STakashi Iwai 3797352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_capture = { 3798352f7f91STakashi Iwai .substreams = 1, 3799352f7f91STakashi Iwai .channels_min = 2, 3800352f7f91STakashi Iwai .channels_max = 2, 3801352f7f91STakashi Iwai /* NID is set in build_pcms */ 3802352f7f91STakashi Iwai }; 3803352f7f91STakashi Iwai 3804352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_playback = { 3805352f7f91STakashi Iwai .substreams = 1, 3806352f7f91STakashi Iwai .channels_min = 2, 3807352f7f91STakashi Iwai .channels_max = 2, 3808352f7f91STakashi Iwai /* NID is set in build_pcms */ 380938cf6f1aSTakashi Iwai .ops = { 381038cf6f1aSTakashi Iwai .open = alt_playback_pcm_open, 3811e6b85f3cSTakashi Iwai .close = alt_playback_pcm_close, 3812e6b85f3cSTakashi Iwai .prepare = alt_playback_pcm_prepare, 3813e6b85f3cSTakashi Iwai .cleanup = alt_playback_pcm_cleanup 381438cf6f1aSTakashi Iwai }, 3815352f7f91STakashi Iwai }; 3816352f7f91STakashi Iwai 3817352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_capture = { 3818352f7f91STakashi Iwai .substreams = 2, /* can be overridden */ 3819352f7f91STakashi Iwai .channels_min = 2, 3820352f7f91STakashi Iwai .channels_max = 2, 3821352f7f91STakashi Iwai /* NID is set in build_pcms */ 3822352f7f91STakashi Iwai .ops = { 3823352f7f91STakashi Iwai .prepare = alt_capture_pcm_prepare, 3824352f7f91STakashi Iwai .cleanup = alt_capture_pcm_cleanup 3825352f7f91STakashi Iwai }, 3826352f7f91STakashi Iwai }; 3827352f7f91STakashi Iwai 3828352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_playback = { 3829352f7f91STakashi Iwai .substreams = 1, 3830352f7f91STakashi Iwai .channels_min = 2, 3831352f7f91STakashi Iwai .channels_max = 2, 3832352f7f91STakashi Iwai /* NID is set in build_pcms */ 3833352f7f91STakashi Iwai .ops = { 3834352f7f91STakashi Iwai .open = dig_playback_pcm_open, 3835352f7f91STakashi Iwai .close = dig_playback_pcm_close, 3836352f7f91STakashi Iwai .prepare = dig_playback_pcm_prepare, 3837352f7f91STakashi Iwai .cleanup = dig_playback_pcm_cleanup 3838352f7f91STakashi Iwai }, 3839352f7f91STakashi Iwai }; 3840352f7f91STakashi Iwai 3841352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_capture = { 3842352f7f91STakashi Iwai .substreams = 1, 3843352f7f91STakashi Iwai .channels_min = 2, 3844352f7f91STakashi Iwai .channels_max = 2, 3845352f7f91STakashi Iwai /* NID is set in build_pcms */ 3846352f7f91STakashi Iwai }; 3847352f7f91STakashi Iwai 3848352f7f91STakashi Iwai /* Used by build_pcms to flag that a PCM has no playback stream */ 3849352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_null_stream = { 3850352f7f91STakashi Iwai .substreams = 0, 3851352f7f91STakashi Iwai .channels_min = 0, 3852352f7f91STakashi Iwai .channels_max = 0, 3853352f7f91STakashi Iwai }; 3854352f7f91STakashi Iwai 3855352f7f91STakashi Iwai /* 3856352f7f91STakashi Iwai * dynamic changing ADC PCM streams 3857352f7f91STakashi Iwai */ 3858352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) 38591da177e4SLinus Torvalds { 3860352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3861352f7f91STakashi Iwai hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]]; 38621da177e4SLinus Torvalds 3863352f7f91STakashi Iwai if (spec->cur_adc && spec->cur_adc != new_adc) { 3864352f7f91STakashi Iwai /* stream is running, let's swap the current ADC */ 3865352f7f91STakashi Iwai __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); 3866352f7f91STakashi Iwai spec->cur_adc = new_adc; 3867352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, new_adc, 3868352f7f91STakashi Iwai spec->cur_adc_stream_tag, 0, 3869352f7f91STakashi Iwai spec->cur_adc_format); 3870352f7f91STakashi Iwai return true; 3871352f7f91STakashi Iwai } 3872352f7f91STakashi Iwai return false; 3873352f7f91STakashi Iwai } 3874352f7f91STakashi Iwai 3875352f7f91STakashi Iwai /* analog capture with dynamic dual-adc changes */ 3876352f7f91STakashi Iwai static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 3877352f7f91STakashi Iwai struct hda_codec *codec, 3878352f7f91STakashi Iwai unsigned int stream_tag, 3879352f7f91STakashi Iwai unsigned int format, 3880352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3881352f7f91STakashi Iwai { 3882352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3883352f7f91STakashi Iwai spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]]; 3884352f7f91STakashi Iwai spec->cur_adc_stream_tag = stream_tag; 3885352f7f91STakashi Iwai spec->cur_adc_format = format; 3886352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); 38871da177e4SLinus Torvalds return 0; 38881da177e4SLinus Torvalds } 38891da177e4SLinus Torvalds 3890352f7f91STakashi Iwai static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 3891352f7f91STakashi Iwai struct hda_codec *codec, 3892352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3893352f7f91STakashi Iwai { 3894352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3895352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, spec->cur_adc); 3896352f7f91STakashi Iwai spec->cur_adc = 0; 3897352f7f91STakashi Iwai return 0; 3898352f7f91STakashi Iwai } 3899352f7f91STakashi Iwai 3900352f7f91STakashi Iwai static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = { 3901352f7f91STakashi Iwai .substreams = 1, 3902352f7f91STakashi Iwai .channels_min = 2, 3903352f7f91STakashi Iwai .channels_max = 2, 3904352f7f91STakashi Iwai .nid = 0, /* fill later */ 3905352f7f91STakashi Iwai .ops = { 3906352f7f91STakashi Iwai .prepare = dyn_adc_capture_pcm_prepare, 3907352f7f91STakashi Iwai .cleanup = dyn_adc_capture_pcm_cleanup 3908352f7f91STakashi Iwai }, 3909352f7f91STakashi Iwai }; 3910352f7f91STakashi Iwai 3911f873e536STakashi Iwai static void fill_pcm_stream_name(char *str, size_t len, const char *sfx, 3912f873e536STakashi Iwai const char *chip_name) 3913f873e536STakashi Iwai { 3914f873e536STakashi Iwai char *p; 3915f873e536STakashi Iwai 3916f873e536STakashi Iwai if (*str) 3917f873e536STakashi Iwai return; 3918f873e536STakashi Iwai strlcpy(str, chip_name, len); 3919f873e536STakashi Iwai 3920f873e536STakashi Iwai /* drop non-alnum chars after a space */ 3921f873e536STakashi Iwai for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) { 3922f873e536STakashi Iwai if (!isalnum(p[1])) { 3923f873e536STakashi Iwai *p = 0; 3924f873e536STakashi Iwai break; 3925f873e536STakashi Iwai } 3926f873e536STakashi Iwai } 3927f873e536STakashi Iwai strlcat(str, sfx, len); 3928f873e536STakashi Iwai } 3929f873e536STakashi Iwai 3930352f7f91STakashi Iwai /* build PCM streams based on the parsed results */ 3931352f7f91STakashi Iwai int snd_hda_gen_build_pcms(struct hda_codec *codec) 3932352f7f91STakashi Iwai { 3933352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3934352f7f91STakashi Iwai struct hda_pcm *info = spec->pcm_rec; 3935352f7f91STakashi Iwai const struct hda_pcm_stream *p; 3936352f7f91STakashi Iwai bool have_multi_adcs; 3937352f7f91STakashi Iwai 39381da177e4SLinus Torvalds codec->num_pcms = 1; 39391da177e4SLinus Torvalds codec->pcm_info = info; 39401da177e4SLinus Torvalds 3941352f7f91STakashi Iwai if (spec->no_analog) 3942352f7f91STakashi Iwai goto skip_analog; 3943352f7f91STakashi Iwai 3944f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_analog, 3945f873e536STakashi Iwai sizeof(spec->stream_name_analog), 3946f873e536STakashi Iwai " Analog", codec->chip_name); 3947352f7f91STakashi Iwai info->name = spec->stream_name_analog; 3948352f7f91STakashi Iwai 3949352f7f91STakashi Iwai if (spec->multiout.num_dacs > 0) { 3950352f7f91STakashi Iwai p = spec->stream_analog_playback; 3951352f7f91STakashi Iwai if (!p) 3952352f7f91STakashi Iwai p = &pcm_analog_playback; 3953352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 3954352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; 3955352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 3956352f7f91STakashi Iwai spec->multiout.max_channels; 3957352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT && 3958352f7f91STakashi Iwai spec->autocfg.line_outs == 2) 3959352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap = 3960352f7f91STakashi Iwai snd_pcm_2_1_chmaps; 3961352f7f91STakashi Iwai } 3962352f7f91STakashi Iwai if (spec->num_adc_nids) { 3963352f7f91STakashi Iwai p = spec->stream_analog_capture; 3964352f7f91STakashi Iwai if (!p) { 3965352f7f91STakashi Iwai if (spec->dyn_adc_switch) 3966352f7f91STakashi Iwai p = &dyn_adc_pcm_analog_capture; 3967352f7f91STakashi Iwai else 3968352f7f91STakashi Iwai p = &pcm_analog_capture; 3969352f7f91STakashi Iwai } 3970352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 3971352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; 3972352f7f91STakashi Iwai } 3973352f7f91STakashi Iwai 3974352f7f91STakashi Iwai skip_analog: 3975352f7f91STakashi Iwai /* SPDIF for stream index #1 */ 3976352f7f91STakashi Iwai if (spec->multiout.dig_out_nid || spec->dig_in_nid) { 3977f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_digital, 3978352f7f91STakashi Iwai sizeof(spec->stream_name_digital), 3979f873e536STakashi Iwai " Digital", codec->chip_name); 3980352f7f91STakashi Iwai codec->num_pcms = 2; 3981352f7f91STakashi Iwai codec->slave_dig_outs = spec->multiout.slave_dig_outs; 3982352f7f91STakashi Iwai info = spec->pcm_rec + 1; 3983352f7f91STakashi Iwai info->name = spec->stream_name_digital; 3984352f7f91STakashi Iwai if (spec->dig_out_type) 3985352f7f91STakashi Iwai info->pcm_type = spec->dig_out_type; 3986352f7f91STakashi Iwai else 3987352f7f91STakashi Iwai info->pcm_type = HDA_PCM_TYPE_SPDIF; 3988352f7f91STakashi Iwai if (spec->multiout.dig_out_nid) { 3989352f7f91STakashi Iwai p = spec->stream_digital_playback; 3990352f7f91STakashi Iwai if (!p) 3991352f7f91STakashi Iwai p = &pcm_digital_playback; 3992352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 3993352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; 3994352f7f91STakashi Iwai } 3995352f7f91STakashi Iwai if (spec->dig_in_nid) { 3996352f7f91STakashi Iwai p = spec->stream_digital_capture; 3997352f7f91STakashi Iwai if (!p) 3998352f7f91STakashi Iwai p = &pcm_digital_capture; 3999352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 4000352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; 4001352f7f91STakashi Iwai } 4002352f7f91STakashi Iwai } 4003352f7f91STakashi Iwai 4004352f7f91STakashi Iwai if (spec->no_analog) 4005352f7f91STakashi Iwai return 0; 4006352f7f91STakashi Iwai 4007352f7f91STakashi Iwai /* If the use of more than one ADC is requested for the current 4008352f7f91STakashi Iwai * model, configure a second analog capture-only PCM. 4009352f7f91STakashi Iwai */ 4010352f7f91STakashi Iwai have_multi_adcs = (spec->num_adc_nids > 1) && 4011352f7f91STakashi Iwai !spec->dyn_adc_switch && !spec->auto_mic; 4012352f7f91STakashi Iwai /* Additional Analaog capture for index #2 */ 4013352f7f91STakashi Iwai if (spec->alt_dac_nid || have_multi_adcs) { 4014352f7f91STakashi Iwai codec->num_pcms = 3; 4015352f7f91STakashi Iwai info = spec->pcm_rec + 2; 4016352f7f91STakashi Iwai info->name = spec->stream_name_analog; 4017352f7f91STakashi Iwai if (spec->alt_dac_nid) { 4018352f7f91STakashi Iwai p = spec->stream_analog_alt_playback; 4019352f7f91STakashi Iwai if (!p) 4020352f7f91STakashi Iwai p = &pcm_analog_alt_playback; 4021352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 4022352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 4023352f7f91STakashi Iwai spec->alt_dac_nid; 4024352f7f91STakashi Iwai } else { 4025352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = 4026352f7f91STakashi Iwai pcm_null_stream; 4027352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; 4028352f7f91STakashi Iwai } 4029352f7f91STakashi Iwai if (have_multi_adcs) { 4030352f7f91STakashi Iwai p = spec->stream_analog_alt_capture; 4031352f7f91STakashi Iwai if (!p) 4032352f7f91STakashi Iwai p = &pcm_analog_alt_capture; 4033352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 4034352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 4035352f7f91STakashi Iwai spec->adc_nids[1]; 4036352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 4037352f7f91STakashi Iwai spec->num_adc_nids - 1; 4038352f7f91STakashi Iwai } else { 4039352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = 4040352f7f91STakashi Iwai pcm_null_stream; 4041352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0; 4042352f7f91STakashi Iwai } 40431da177e4SLinus Torvalds } 40441da177e4SLinus Torvalds 40451da177e4SLinus Torvalds return 0; 40461da177e4SLinus Torvalds } 4047352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_pcms); 4048352f7f91STakashi Iwai 4049352f7f91STakashi Iwai 4050352f7f91STakashi Iwai /* 4051352f7f91STakashi Iwai * Standard auto-parser initializations 4052352f7f91STakashi Iwai */ 4053352f7f91STakashi Iwai 4054d4156930STakashi Iwai /* configure the given path as a proper output */ 40552c12c30dSTakashi Iwai static void set_output_and_unmute(struct hda_codec *codec, int path_idx) 4056352f7f91STakashi Iwai { 4057352f7f91STakashi Iwai struct nid_path *path; 4058d4156930STakashi Iwai hda_nid_t pin; 4059352f7f91STakashi Iwai 4060196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 4061d4156930STakashi Iwai if (!path || !path->depth) 4062352f7f91STakashi Iwai return; 4063d4156930STakashi Iwai pin = path->path[path->depth - 1]; 40642c12c30dSTakashi Iwai restore_pin_ctl(codec, pin); 4065e1284af7STakashi Iwai snd_hda_activate_path(codec, path, path->active, true); 4066e1284af7STakashi Iwai set_pin_eapd(codec, pin, path->active); 4067352f7f91STakashi Iwai } 4068352f7f91STakashi Iwai 4069352f7f91STakashi Iwai /* initialize primary output paths */ 4070352f7f91STakashi Iwai static void init_multi_out(struct hda_codec *codec) 4071352f7f91STakashi Iwai { 4072352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4073352f7f91STakashi Iwai int i; 4074352f7f91STakashi Iwai 4075d4156930STakashi Iwai for (i = 0; i < spec->autocfg.line_outs; i++) 40762c12c30dSTakashi Iwai set_output_and_unmute(codec, spec->out_paths[i]); 4077352f7f91STakashi Iwai } 4078352f7f91STakashi Iwai 4079db23fd19STakashi Iwai 40802c12c30dSTakashi Iwai static void __init_extra_out(struct hda_codec *codec, int num_outs, int *paths) 4081352f7f91STakashi Iwai { 4082352f7f91STakashi Iwai int i; 4083352f7f91STakashi Iwai 4084d4156930STakashi Iwai for (i = 0; i < num_outs; i++) 40852c12c30dSTakashi Iwai set_output_and_unmute(codec, paths[i]); 4086352f7f91STakashi Iwai } 4087db23fd19STakashi Iwai 4088db23fd19STakashi Iwai /* initialize hp and speaker paths */ 4089db23fd19STakashi Iwai static void init_extra_out(struct hda_codec *codec) 4090db23fd19STakashi Iwai { 4091db23fd19STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4092db23fd19STakashi Iwai 4093db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) 40942c12c30dSTakashi Iwai __init_extra_out(codec, spec->autocfg.hp_outs, spec->hp_paths); 4095db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) 4096db23fd19STakashi Iwai __init_extra_out(codec, spec->autocfg.speaker_outs, 40972c12c30dSTakashi Iwai spec->speaker_paths); 4098352f7f91STakashi Iwai } 4099352f7f91STakashi Iwai 4100352f7f91STakashi Iwai /* initialize multi-io paths */ 4101352f7f91STakashi Iwai static void init_multi_io(struct hda_codec *codec) 4102352f7f91STakashi Iwai { 4103352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4104352f7f91STakashi Iwai int i; 4105352f7f91STakashi Iwai 4106352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++) { 4107352f7f91STakashi Iwai hda_nid_t pin = spec->multi_io[i].pin; 4108352f7f91STakashi Iwai struct nid_path *path; 4109196c1766STakashi Iwai path = get_multiio_path(codec, i); 4110352f7f91STakashi Iwai if (!path) 4111352f7f91STakashi Iwai continue; 4112352f7f91STakashi Iwai if (!spec->multi_io[i].ctl_in) 4113352f7f91STakashi Iwai spec->multi_io[i].ctl_in = 41142c12c30dSTakashi Iwai snd_hda_codec_get_pin_target(codec, pin); 4115352f7f91STakashi Iwai snd_hda_activate_path(codec, path, path->active, true); 4116352f7f91STakashi Iwai } 4117352f7f91STakashi Iwai } 4118352f7f91STakashi Iwai 4119352f7f91STakashi Iwai /* set up input pins and loopback paths */ 4120352f7f91STakashi Iwai static void init_analog_input(struct hda_codec *codec) 4121352f7f91STakashi Iwai { 4122352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4123352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 4124352f7f91STakashi Iwai int i; 4125352f7f91STakashi Iwai 4126352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 4127352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 4128352f7f91STakashi Iwai if (is_input_pin(codec, nid)) 41292c12c30dSTakashi Iwai restore_pin_ctl(codec, nid); 4130352f7f91STakashi Iwai 4131352f7f91STakashi Iwai /* init loopback inputs */ 4132352f7f91STakashi Iwai if (spec->mixer_nid) { 4133352f7f91STakashi Iwai struct nid_path *path; 4134196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->loopback_paths[i]); 4135352f7f91STakashi Iwai if (path) 4136352f7f91STakashi Iwai snd_hda_activate_path(codec, path, 4137352f7f91STakashi Iwai path->active, false); 4138352f7f91STakashi Iwai } 4139352f7f91STakashi Iwai } 4140352f7f91STakashi Iwai } 4141352f7f91STakashi Iwai 4142352f7f91STakashi Iwai /* initialize ADC paths */ 4143352f7f91STakashi Iwai static void init_input_src(struct hda_codec *codec) 4144352f7f91STakashi Iwai { 4145352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4146352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 4147352f7f91STakashi Iwai struct nid_path *path; 4148352f7f91STakashi Iwai int i, c, nums; 4149352f7f91STakashi Iwai 4150352f7f91STakashi Iwai if (spec->dyn_adc_switch) 4151352f7f91STakashi Iwai nums = 1; 4152352f7f91STakashi Iwai else 4153352f7f91STakashi Iwai nums = spec->num_adc_nids; 4154352f7f91STakashi Iwai 4155352f7f91STakashi Iwai for (c = 0; c < nums; c++) { 4156352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 4157c697b716STakashi Iwai path = get_input_path(codec, c, i); 4158352f7f91STakashi Iwai if (path) { 4159352f7f91STakashi Iwai bool active = path->active; 4160352f7f91STakashi Iwai if (i == spec->cur_mux[c]) 4161352f7f91STakashi Iwai active = true; 4162352f7f91STakashi Iwai snd_hda_activate_path(codec, path, active, false); 4163352f7f91STakashi Iwai } 4164352f7f91STakashi Iwai } 4165352f7f91STakashi Iwai } 4166352f7f91STakashi Iwai 4167352f7f91STakashi Iwai if (spec->shared_mic_hp) 4168352f7f91STakashi Iwai update_shared_mic_hp(codec, spec->cur_mux[0]); 4169352f7f91STakashi Iwai 4170352f7f91STakashi Iwai if (spec->cap_sync_hook) 4171352f7f91STakashi Iwai spec->cap_sync_hook(codec); 4172352f7f91STakashi Iwai } 4173352f7f91STakashi Iwai 4174352f7f91STakashi Iwai /* set right pin controls for digital I/O */ 4175352f7f91STakashi Iwai static void init_digital(struct hda_codec *codec) 4176352f7f91STakashi Iwai { 4177352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4178352f7f91STakashi Iwai int i; 4179352f7f91STakashi Iwai hda_nid_t pin; 4180352f7f91STakashi Iwai 4181d4156930STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) 41822c12c30dSTakashi Iwai set_output_and_unmute(codec, spec->digout_paths[i]); 4183352f7f91STakashi Iwai pin = spec->autocfg.dig_in_pin; 41842430d7b7STakashi Iwai if (pin) { 41852430d7b7STakashi Iwai struct nid_path *path; 41862c12c30dSTakashi Iwai restore_pin_ctl(codec, pin); 41872430d7b7STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->digin_path); 41882430d7b7STakashi Iwai if (path) 41892430d7b7STakashi Iwai snd_hda_activate_path(codec, path, path->active, false); 41902430d7b7STakashi Iwai } 4191352f7f91STakashi Iwai } 4192352f7f91STakashi Iwai 4193973e4972STakashi Iwai /* clear unsol-event tags on unused pins; Conexant codecs seem to leave 4194973e4972STakashi Iwai * invalid unsol tags by some reason 4195973e4972STakashi Iwai */ 4196973e4972STakashi Iwai static void clear_unsol_on_unused_pins(struct hda_codec *codec) 4197973e4972STakashi Iwai { 4198973e4972STakashi Iwai int i; 4199973e4972STakashi Iwai 4200973e4972STakashi Iwai for (i = 0; i < codec->init_pins.used; i++) { 4201973e4972STakashi Iwai struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); 4202973e4972STakashi Iwai hda_nid_t nid = pin->nid; 4203973e4972STakashi Iwai if (is_jack_detectable(codec, nid) && 4204973e4972STakashi Iwai !snd_hda_jack_tbl_get(codec, nid)) 4205973e4972STakashi Iwai snd_hda_codec_update_cache(codec, nid, 0, 4206973e4972STakashi Iwai AC_VERB_SET_UNSOLICITED_ENABLE, 0); 4207973e4972STakashi Iwai } 4208973e4972STakashi Iwai } 4209973e4972STakashi Iwai 42105187ac16STakashi Iwai /* 42115187ac16STakashi Iwai * initialize the generic spec; 42125187ac16STakashi Iwai * this can be put as patch_ops.init function 42135187ac16STakashi Iwai */ 4214352f7f91STakashi Iwai int snd_hda_gen_init(struct hda_codec *codec) 4215352f7f91STakashi Iwai { 4216352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 4217352f7f91STakashi Iwai 4218352f7f91STakashi Iwai if (spec->init_hook) 4219352f7f91STakashi Iwai spec->init_hook(codec); 4220352f7f91STakashi Iwai 4221352f7f91STakashi Iwai snd_hda_apply_verbs(codec); 4222352f7f91STakashi Iwai 42233bbcd274STakashi Iwai codec->cached_write = 1; 42243bbcd274STakashi Iwai 4225352f7f91STakashi Iwai init_multi_out(codec); 4226352f7f91STakashi Iwai init_extra_out(codec); 4227352f7f91STakashi Iwai init_multi_io(codec); 4228352f7f91STakashi Iwai init_analog_input(codec); 4229352f7f91STakashi Iwai init_input_src(codec); 4230352f7f91STakashi Iwai init_digital(codec); 4231352f7f91STakashi Iwai 4232973e4972STakashi Iwai clear_unsol_on_unused_pins(codec); 4233973e4972STakashi Iwai 4234352f7f91STakashi Iwai /* call init functions of standard auto-mute helpers */ 42355d550e15STakashi Iwai snd_hda_gen_hp_automute(codec, NULL); 42365d550e15STakashi Iwai snd_hda_gen_line_automute(codec, NULL); 42375d550e15STakashi Iwai snd_hda_gen_mic_autoswitch(codec, NULL); 4238352f7f91STakashi Iwai 42393bbcd274STakashi Iwai snd_hda_codec_flush_amp_cache(codec); 42403bbcd274STakashi Iwai snd_hda_codec_flush_cmd_cache(codec); 42413bbcd274STakashi Iwai 4242352f7f91STakashi Iwai if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook) 4243352f7f91STakashi Iwai snd_hda_sync_vmaster_hook(&spec->vmaster_mute); 4244352f7f91STakashi Iwai 4245352f7f91STakashi Iwai hda_call_check_power_status(codec, 0x01); 4246352f7f91STakashi Iwai return 0; 4247352f7f91STakashi Iwai } 4248fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_init); 4249fce52a3bSTakashi Iwai 42505187ac16STakashi Iwai /* 42515187ac16STakashi Iwai * free the generic spec; 42525187ac16STakashi Iwai * this can be put as patch_ops.free function 42535187ac16STakashi Iwai */ 4254fce52a3bSTakashi Iwai void snd_hda_gen_free(struct hda_codec *codec) 4255fce52a3bSTakashi Iwai { 4256fce52a3bSTakashi Iwai snd_hda_gen_spec_free(codec->spec); 4257fce52a3bSTakashi Iwai kfree(codec->spec); 4258fce52a3bSTakashi Iwai codec->spec = NULL; 4259fce52a3bSTakashi Iwai } 4260fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_free); 4261fce52a3bSTakashi Iwai 4262fce52a3bSTakashi Iwai #ifdef CONFIG_PM 42635187ac16STakashi Iwai /* 42645187ac16STakashi Iwai * check the loopback power save state; 42655187ac16STakashi Iwai * this can be put as patch_ops.check_power_status function 42665187ac16STakashi Iwai */ 4267fce52a3bSTakashi Iwai int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid) 4268fce52a3bSTakashi Iwai { 4269fce52a3bSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 4270fce52a3bSTakashi Iwai return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); 4271fce52a3bSTakashi Iwai } 4272fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_check_power_status); 4273fce52a3bSTakashi Iwai #endif 4274352f7f91STakashi Iwai 4275352f7f91STakashi Iwai 4276352f7f91STakashi Iwai /* 4277352f7f91STakashi Iwai * the generic codec support 4278352f7f91STakashi Iwai */ 42791da177e4SLinus Torvalds 4280352f7f91STakashi Iwai static const struct hda_codec_ops generic_patch_ops = { 4281352f7f91STakashi Iwai .build_controls = snd_hda_gen_build_controls, 4282352f7f91STakashi Iwai .build_pcms = snd_hda_gen_build_pcms, 4283352f7f91STakashi Iwai .init = snd_hda_gen_init, 4284fce52a3bSTakashi Iwai .free = snd_hda_gen_free, 4285352f7f91STakashi Iwai .unsol_event = snd_hda_jack_unsol_event, 428683012a7cSTakashi Iwai #ifdef CONFIG_PM 4287fce52a3bSTakashi Iwai .check_power_status = snd_hda_gen_check_power_status, 4288cb53c626STakashi Iwai #endif 42891da177e4SLinus Torvalds }; 42901da177e4SLinus Torvalds 42911da177e4SLinus Torvalds int snd_hda_parse_generic_codec(struct hda_codec *codec) 42921da177e4SLinus Torvalds { 4293352f7f91STakashi Iwai struct hda_gen_spec *spec; 42941da177e4SLinus Torvalds int err; 42951da177e4SLinus Torvalds 4296e560d8d8STakashi Iwai spec = kzalloc(sizeof(*spec), GFP_KERNEL); 4297352f7f91STakashi Iwai if (!spec) 42981da177e4SLinus Torvalds return -ENOMEM; 4299352f7f91STakashi Iwai snd_hda_gen_spec_init(spec); 43001da177e4SLinus Torvalds codec->spec = spec; 43011da177e4SLinus Torvalds 43029eb413e5STakashi Iwai err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0); 43039eb413e5STakashi Iwai if (err < 0) 43049eb413e5STakashi Iwai return err; 43059eb413e5STakashi Iwai 43069eb413e5STakashi Iwai err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg); 4307352f7f91STakashi Iwai if (err < 0) 43081da177e4SLinus Torvalds goto error; 43091da177e4SLinus Torvalds 43101da177e4SLinus Torvalds codec->patch_ops = generic_patch_ops; 43111da177e4SLinus Torvalds return 0; 43121da177e4SLinus Torvalds 43131da177e4SLinus Torvalds error: 4314fce52a3bSTakashi Iwai snd_hda_gen_free(codec); 43151da177e4SLinus Torvalds return err; 43161da177e4SLinus Torvalds } 4317fce52a3bSTakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_parse_generic_codec); 4318