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->bind_ctls, sizeof(struct hda_bind_ctls *), 8); 43352f7f91STakashi Iwai snd_array_init(&spec->paths, sizeof(struct nid_path), 8); 4438cf6f1aSTakashi Iwai mutex_init(&spec->pcm_mutex); 45352f7f91STakashi Iwai return 0; 46352f7f91STakashi Iwai } 47352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_spec_init); 481da177e4SLinus Torvalds 4912c93df6STakashi Iwai struct snd_kcontrol_new * 5012c93df6STakashi Iwai snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name, 51352f7f91STakashi Iwai const struct snd_kcontrol_new *temp) 52352f7f91STakashi Iwai { 53352f7f91STakashi Iwai struct snd_kcontrol_new *knew = snd_array_new(&spec->kctls); 54352f7f91STakashi Iwai if (!knew) 55352f7f91STakashi Iwai return NULL; 56352f7f91STakashi Iwai *knew = *temp; 57352f7f91STakashi Iwai if (name) 58352f7f91STakashi Iwai knew->name = kstrdup(name, GFP_KERNEL); 59352f7f91STakashi Iwai else if (knew->name) 60352f7f91STakashi Iwai knew->name = kstrdup(knew->name, GFP_KERNEL); 61352f7f91STakashi Iwai if (!knew->name) 62352f7f91STakashi Iwai return NULL; 63352f7f91STakashi Iwai return knew; 64352f7f91STakashi Iwai } 6512c93df6STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_add_kctl); 66352f7f91STakashi Iwai 67352f7f91STakashi Iwai static void free_kctls(struct hda_gen_spec *spec) 68352f7f91STakashi Iwai { 69352f7f91STakashi Iwai if (spec->kctls.list) { 70352f7f91STakashi Iwai struct snd_kcontrol_new *kctl = spec->kctls.list; 71352f7f91STakashi Iwai int i; 72352f7f91STakashi Iwai for (i = 0; i < spec->kctls.used; i++) 73352f7f91STakashi Iwai kfree(kctl[i].name); 74352f7f91STakashi Iwai } 75352f7f91STakashi Iwai snd_array_free(&spec->kctls); 76352f7f91STakashi Iwai } 77352f7f91STakashi Iwai 78352f7f91STakashi Iwai static struct hda_bind_ctls *new_bind_ctl(struct hda_codec *codec, 79352f7f91STakashi Iwai unsigned int nums, 80352f7f91STakashi Iwai struct hda_ctl_ops *ops) 81352f7f91STakashi Iwai { 82352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 83352f7f91STakashi Iwai struct hda_bind_ctls **ctlp, *ctl; 84352f7f91STakashi Iwai ctlp = snd_array_new(&spec->bind_ctls); 85352f7f91STakashi Iwai if (!ctlp) 86352f7f91STakashi Iwai return NULL; 87352f7f91STakashi Iwai ctl = kzalloc(sizeof(*ctl) + sizeof(long) * (nums + 1), GFP_KERNEL); 88352f7f91STakashi Iwai *ctlp = ctl; 89352f7f91STakashi Iwai if (ctl) 90352f7f91STakashi Iwai ctl->ops = ops; 91352f7f91STakashi Iwai return ctl; 92352f7f91STakashi Iwai } 93352f7f91STakashi Iwai 94352f7f91STakashi Iwai static void free_bind_ctls(struct hda_gen_spec *spec) 95352f7f91STakashi Iwai { 96352f7f91STakashi Iwai if (spec->bind_ctls.list) { 97352f7f91STakashi Iwai struct hda_bind_ctls **ctl = spec->bind_ctls.list; 98352f7f91STakashi Iwai int i; 99352f7f91STakashi Iwai for (i = 0; i < spec->bind_ctls.used; i++) 100352f7f91STakashi Iwai kfree(ctl[i]); 101352f7f91STakashi Iwai } 102352f7f91STakashi Iwai snd_array_free(&spec->bind_ctls); 103352f7f91STakashi Iwai } 104352f7f91STakashi Iwai 105352f7f91STakashi Iwai void snd_hda_gen_spec_free(struct hda_gen_spec *spec) 106352f7f91STakashi Iwai { 1071da177e4SLinus Torvalds if (!spec) 1081da177e4SLinus Torvalds return; 109352f7f91STakashi Iwai free_kctls(spec); 110352f7f91STakashi Iwai free_bind_ctls(spec); 111352f7f91STakashi Iwai snd_array_free(&spec->paths); 1121da177e4SLinus Torvalds } 113352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_spec_free); 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds /* 116352f7f91STakashi Iwai * parsing paths 1171da177e4SLinus Torvalds */ 1181da177e4SLinus Torvalds 119f5172a7eSTakashi Iwai static struct nid_path *get_nid_path(struct hda_codec *codec, 120f5172a7eSTakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid, 121f5172a7eSTakashi Iwai int with_aa_mix) 1221da177e4SLinus Torvalds { 123352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 124352f7f91STakashi Iwai int i; 1251da177e4SLinus Torvalds 126352f7f91STakashi Iwai for (i = 0; i < spec->paths.used; i++) { 127352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, i); 128352f7f91STakashi Iwai if (path->depth <= 0) 129352f7f91STakashi Iwai continue; 130352f7f91STakashi Iwai if ((!from_nid || path->path[0] == from_nid) && 131f5172a7eSTakashi Iwai (!to_nid || path->path[path->depth - 1] == to_nid)) { 132f5172a7eSTakashi Iwai if (with_aa_mix == HDA_PARSE_ALL || 133f5172a7eSTakashi Iwai path->with_aa_mix == with_aa_mix) 134352f7f91STakashi Iwai return path; 1351da177e4SLinus Torvalds } 136f5172a7eSTakashi Iwai } 1371da177e4SLinus Torvalds return NULL; 1381da177e4SLinus Torvalds } 139f5172a7eSTakashi Iwai 140f5172a7eSTakashi Iwai /* get the path between the given NIDs; 141f5172a7eSTakashi Iwai * passing 0 to either @pin or @dac behaves as a wildcard 142f5172a7eSTakashi Iwai */ 143f5172a7eSTakashi Iwai struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec, 144f5172a7eSTakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid) 145f5172a7eSTakashi Iwai { 146f5172a7eSTakashi Iwai return get_nid_path(codec, from_nid, to_nid, HDA_PARSE_ALL); 147f5172a7eSTakashi Iwai } 148352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_get_nid_path); 1491da177e4SLinus Torvalds 150196c1766STakashi Iwai /* get the index number corresponding to the path instance; 151196c1766STakashi Iwai * the index starts from 1, for easier checking the invalid value 152196c1766STakashi Iwai */ 153196c1766STakashi Iwai int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path) 154196c1766STakashi Iwai { 155196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 156196c1766STakashi Iwai struct nid_path *array = spec->paths.list; 157196c1766STakashi Iwai ssize_t idx; 158196c1766STakashi Iwai 159196c1766STakashi Iwai if (!spec->paths.used) 160196c1766STakashi Iwai return 0; 161196c1766STakashi Iwai idx = path - array; 162196c1766STakashi Iwai if (idx < 0 || idx >= spec->paths.used) 163196c1766STakashi Iwai return 0; 164196c1766STakashi Iwai return idx + 1; 165196c1766STakashi Iwai } 166196c1766STakashi Iwai 167196c1766STakashi Iwai /* get the path instance corresponding to the given index number */ 168196c1766STakashi Iwai struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx) 169196c1766STakashi Iwai { 170196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 171196c1766STakashi Iwai 172196c1766STakashi Iwai if (idx <= 0 || idx > spec->paths.used) 173196c1766STakashi Iwai return NULL; 174196c1766STakashi Iwai return snd_array_elem(&spec->paths, idx - 1); 175196c1766STakashi Iwai } 176196c1766STakashi Iwai 177352f7f91STakashi Iwai /* check whether the given DAC is already found in any existing paths */ 178352f7f91STakashi Iwai static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid) 1791da177e4SLinus Torvalds { 180352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 181352f7f91STakashi Iwai int i; 182352f7f91STakashi Iwai 183352f7f91STakashi Iwai for (i = 0; i < spec->paths.used; i++) { 184352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, i); 185352f7f91STakashi Iwai if (path->path[0] == nid) 186352f7f91STakashi Iwai return true; 187352f7f91STakashi Iwai } 188352f7f91STakashi Iwai return false; 1891da177e4SLinus Torvalds } 1901da177e4SLinus Torvalds 191352f7f91STakashi Iwai /* check whether the given two widgets can be connected */ 192352f7f91STakashi Iwai static bool is_reachable_path(struct hda_codec *codec, 193352f7f91STakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid) 1941da177e4SLinus Torvalds { 195352f7f91STakashi Iwai if (!from_nid || !to_nid) 196352f7f91STakashi Iwai return false; 197352f7f91STakashi Iwai return snd_hda_get_conn_index(codec, to_nid, from_nid, true) >= 0; 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds 200352f7f91STakashi Iwai /* nid, dir and idx */ 201352f7f91STakashi Iwai #define AMP_VAL_COMPARE_MASK (0xffff | (1U << 18) | (0x0f << 19)) 202352f7f91STakashi Iwai 203352f7f91STakashi Iwai /* check whether the given ctl is already assigned in any path elements */ 204352f7f91STakashi Iwai static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type) 2051da177e4SLinus Torvalds { 206352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 207352f7f91STakashi Iwai int i; 208352f7f91STakashi Iwai 209352f7f91STakashi Iwai val &= AMP_VAL_COMPARE_MASK; 210352f7f91STakashi Iwai for (i = 0; i < spec->paths.used; i++) { 211352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, i); 212352f7f91STakashi Iwai if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val) 213352f7f91STakashi Iwai return true; 214352f7f91STakashi Iwai } 215352f7f91STakashi Iwai return false; 2161da177e4SLinus Torvalds } 2171da177e4SLinus Torvalds 218352f7f91STakashi Iwai /* check whether a control with the given (nid, dir, idx) was assigned */ 219352f7f91STakashi Iwai static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid, 220cb53c626STakashi Iwai int dir, int idx) 221cb53c626STakashi Iwai { 222352f7f91STakashi Iwai unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir); 223352f7f91STakashi Iwai return is_ctl_used(codec, val, NID_PATH_VOL_CTL) || 224352f7f91STakashi Iwai is_ctl_used(codec, val, NID_PATH_MUTE_CTL); 225cb53c626STakashi Iwai } 226352f7f91STakashi Iwai 2270c8c0f56STakashi Iwai static void print_nid_path(const char *pfx, struct nid_path *path) 2280c8c0f56STakashi Iwai { 2290c8c0f56STakashi Iwai char buf[40]; 2300c8c0f56STakashi Iwai int i; 2310c8c0f56STakashi Iwai 2320c8c0f56STakashi Iwai 2330c8c0f56STakashi Iwai buf[0] = 0; 2340c8c0f56STakashi Iwai for (i = 0; i < path->depth; i++) { 2350c8c0f56STakashi Iwai char tmp[4]; 2360c8c0f56STakashi Iwai sprintf(tmp, ":%02x", path->path[i]); 2370c8c0f56STakashi Iwai strlcat(buf, tmp, sizeof(buf)); 2380c8c0f56STakashi Iwai } 2390c8c0f56STakashi Iwai snd_printdd("%s path: depth=%d %s\n", pfx, path->depth, buf); 2400c8c0f56STakashi Iwai } 2410c8c0f56STakashi Iwai 242352f7f91STakashi Iwai /* called recursively */ 243352f7f91STakashi Iwai static bool __parse_nid_path(struct hda_codec *codec, 244352f7f91STakashi Iwai hda_nid_t from_nid, hda_nid_t to_nid, 245352f7f91STakashi Iwai int with_aa_mix, struct nid_path *path, int depth) 246352f7f91STakashi Iwai { 247352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 248ee8e765bSTakashi Iwai const hda_nid_t *conn; 249352f7f91STakashi Iwai int i, nums; 250352f7f91STakashi Iwai 251352f7f91STakashi Iwai if (to_nid == spec->mixer_nid) { 2524ac0eefaSTakashi Iwai if (with_aa_mix == HDA_PARSE_NO_AAMIX) 253352f7f91STakashi Iwai return false; 2544ac0eefaSTakashi Iwai with_aa_mix = HDA_PARSE_ALL; /* mark aa-mix is included */ 255352f7f91STakashi Iwai } 256352f7f91STakashi Iwai 257ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, to_nid, &conn); 258352f7f91STakashi Iwai for (i = 0; i < nums; i++) { 259352f7f91STakashi Iwai if (conn[i] != from_nid) { 260352f7f91STakashi Iwai /* special case: when from_nid is 0, 261352f7f91STakashi Iwai * try to find an empty DAC 262352f7f91STakashi Iwai */ 263352f7f91STakashi Iwai if (from_nid || 264352f7f91STakashi Iwai get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT || 265352f7f91STakashi Iwai is_dac_already_used(codec, conn[i])) 266352f7f91STakashi Iwai continue; 267352f7f91STakashi Iwai } 268352f7f91STakashi Iwai /* aa-mix is requested but not included? */ 2694ac0eefaSTakashi Iwai if (!(spec->mixer_nid && with_aa_mix == HDA_PARSE_ONLY_AAMIX)) 270352f7f91STakashi Iwai goto found; 271352f7f91STakashi Iwai } 272352f7f91STakashi Iwai if (depth >= MAX_NID_PATH_DEPTH) 273352f7f91STakashi Iwai return false; 274352f7f91STakashi Iwai for (i = 0; i < nums; i++) { 275352f7f91STakashi Iwai unsigned int type; 276352f7f91STakashi Iwai type = get_wcaps_type(get_wcaps(codec, conn[i])); 277352f7f91STakashi Iwai if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN || 278352f7f91STakashi Iwai type == AC_WID_PIN) 279352f7f91STakashi Iwai continue; 280352f7f91STakashi Iwai if (__parse_nid_path(codec, from_nid, conn[i], 281352f7f91STakashi Iwai with_aa_mix, path, depth + 1)) 282352f7f91STakashi Iwai goto found; 283352f7f91STakashi Iwai } 284352f7f91STakashi Iwai return false; 285352f7f91STakashi Iwai 286352f7f91STakashi Iwai found: 287352f7f91STakashi Iwai path->path[path->depth] = conn[i]; 288f5172a7eSTakashi Iwai if (conn[i] == spec->mixer_nid) 289f5172a7eSTakashi Iwai path->with_aa_mix = true; 290352f7f91STakashi Iwai path->idx[path->depth + 1] = i; 291352f7f91STakashi Iwai if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX) 292352f7f91STakashi Iwai path->multi[path->depth + 1] = 1; 293352f7f91STakashi Iwai path->depth++; 294352f7f91STakashi Iwai return true; 295352f7f91STakashi Iwai } 296352f7f91STakashi Iwai 297352f7f91STakashi Iwai /* parse the widget path from the given nid to the target nid; 298352f7f91STakashi Iwai * when @from_nid is 0, try to find an empty DAC; 2994ac0eefaSTakashi Iwai * when @with_aa_mix is HDA_PARSE_NO_AAMIX, paths with spec->mixer_nid are 3004ac0eefaSTakashi Iwai * excluded, only the paths that don't go through the mixer will be chosen. 3014ac0eefaSTakashi Iwai * when @with_aa_mix is HDA_PARSE_ONLY_AAMIX, only the paths going through 3024ac0eefaSTakashi Iwai * spec->mixer_nid will be chosen. 3034ac0eefaSTakashi Iwai * when @with_aa_mix is HDA_PARSE_ALL, no special handling about mixer widget. 304352f7f91STakashi Iwai */ 305352f7f91STakashi Iwai bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, 306352f7f91STakashi Iwai hda_nid_t to_nid, int with_aa_mix, 307352f7f91STakashi Iwai struct nid_path *path) 308352f7f91STakashi Iwai { 309352f7f91STakashi Iwai if (__parse_nid_path(codec, from_nid, to_nid, with_aa_mix, path, 1)) { 310352f7f91STakashi Iwai path->path[path->depth] = to_nid; 311352f7f91STakashi Iwai path->depth++; 312352f7f91STakashi Iwai return true; 313352f7f91STakashi Iwai } 314352f7f91STakashi Iwai return false; 315352f7f91STakashi Iwai } 316352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_parse_nid_path); 317352f7f91STakashi Iwai 318352f7f91STakashi Iwai /* 319352f7f91STakashi Iwai * parse the path between the given NIDs and add to the path list. 320352f7f91STakashi Iwai * if no valid path is found, return NULL 321352f7f91STakashi Iwai */ 322352f7f91STakashi Iwai struct nid_path * 323352f7f91STakashi Iwai snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid, 324352f7f91STakashi Iwai hda_nid_t to_nid, int with_aa_mix) 325352f7f91STakashi Iwai { 326352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 327352f7f91STakashi Iwai struct nid_path *path; 328352f7f91STakashi Iwai 329352f7f91STakashi Iwai if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid)) 330352f7f91STakashi Iwai return NULL; 331352f7f91STakashi Iwai 332f5172a7eSTakashi Iwai /* check whether the path has been already added */ 333f5172a7eSTakashi Iwai path = get_nid_path(codec, from_nid, to_nid, with_aa_mix); 334f5172a7eSTakashi Iwai if (path) 335f5172a7eSTakashi Iwai return path; 336f5172a7eSTakashi Iwai 337352f7f91STakashi Iwai path = snd_array_new(&spec->paths); 338352f7f91STakashi Iwai if (!path) 339352f7f91STakashi Iwai return NULL; 340352f7f91STakashi Iwai memset(path, 0, sizeof(*path)); 341352f7f91STakashi Iwai if (snd_hda_parse_nid_path(codec, from_nid, to_nid, with_aa_mix, path)) 342352f7f91STakashi Iwai return path; 343352f7f91STakashi Iwai /* push back */ 344352f7f91STakashi Iwai spec->paths.used--; 345352f7f91STakashi Iwai return NULL; 346352f7f91STakashi Iwai } 347352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_add_new_path); 348352f7f91STakashi Iwai 349352f7f91STakashi Iwai /* look for an empty DAC slot */ 350352f7f91STakashi Iwai static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin, 351352f7f91STakashi Iwai bool is_digital) 352352f7f91STakashi Iwai { 353352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 354352f7f91STakashi Iwai bool cap_digital; 355352f7f91STakashi Iwai int i; 356352f7f91STakashi Iwai 357352f7f91STakashi Iwai for (i = 0; i < spec->num_all_dacs; i++) { 358352f7f91STakashi Iwai hda_nid_t nid = spec->all_dacs[i]; 359352f7f91STakashi Iwai if (!nid || is_dac_already_used(codec, nid)) 360352f7f91STakashi Iwai continue; 361352f7f91STakashi Iwai cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL); 362352f7f91STakashi Iwai if (is_digital != cap_digital) 363352f7f91STakashi Iwai continue; 364352f7f91STakashi Iwai if (is_reachable_path(codec, nid, pin)) 365352f7f91STakashi Iwai return nid; 366352f7f91STakashi Iwai } 367352f7f91STakashi Iwai return 0; 368352f7f91STakashi Iwai } 369352f7f91STakashi Iwai 370352f7f91STakashi Iwai /* replace the channels in the composed amp value with the given number */ 371352f7f91STakashi Iwai static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs) 372352f7f91STakashi Iwai { 373352f7f91STakashi Iwai val &= ~(0x3U << 16); 374352f7f91STakashi Iwai val |= chs << 16; 375352f7f91STakashi Iwai return val; 376352f7f91STakashi Iwai } 377352f7f91STakashi Iwai 378352f7f91STakashi Iwai /* check whether the widget has the given amp capability for the direction */ 379352f7f91STakashi Iwai static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, 380352f7f91STakashi Iwai int dir, unsigned int bits) 381352f7f91STakashi Iwai { 382352f7f91STakashi Iwai if (!nid) 383352f7f91STakashi Iwai return false; 384352f7f91STakashi Iwai if (get_wcaps(codec, nid) & (1 << (dir + 1))) 385352f7f91STakashi Iwai if (query_amp_caps(codec, nid, dir) & bits) 386352f7f91STakashi Iwai return true; 387352f7f91STakashi Iwai return false; 388352f7f91STakashi Iwai } 389352f7f91STakashi Iwai 390352f7f91STakashi Iwai #define nid_has_mute(codec, nid, dir) \ 391352f7f91STakashi Iwai check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE) 392352f7f91STakashi Iwai #define nid_has_volume(codec, nid, dir) \ 393352f7f91STakashi Iwai check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS) 394352f7f91STakashi Iwai 395352f7f91STakashi Iwai /* look for a widget suitable for assigning a mute switch in the path */ 396352f7f91STakashi Iwai static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec, 397352f7f91STakashi Iwai struct nid_path *path) 398352f7f91STakashi Iwai { 399352f7f91STakashi Iwai int i; 400352f7f91STakashi Iwai 401352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 402352f7f91STakashi Iwai if (nid_has_mute(codec, path->path[i], HDA_OUTPUT)) 403352f7f91STakashi Iwai return path->path[i]; 404352f7f91STakashi Iwai if (i != path->depth - 1 && i != 0 && 405352f7f91STakashi Iwai nid_has_mute(codec, path->path[i], HDA_INPUT)) 406352f7f91STakashi Iwai return path->path[i]; 407352f7f91STakashi Iwai } 408352f7f91STakashi Iwai return 0; 409352f7f91STakashi Iwai } 410352f7f91STakashi Iwai 411352f7f91STakashi Iwai /* look for a widget suitable for assigning a volume ctl in the path */ 412352f7f91STakashi Iwai static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec, 413352f7f91STakashi Iwai struct nid_path *path) 414352f7f91STakashi Iwai { 415352f7f91STakashi Iwai int i; 416352f7f91STakashi Iwai 417352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 418352f7f91STakashi Iwai if (nid_has_volume(codec, path->path[i], HDA_OUTPUT)) 419352f7f91STakashi Iwai return path->path[i]; 420352f7f91STakashi Iwai } 421352f7f91STakashi Iwai return 0; 422352f7f91STakashi Iwai } 423352f7f91STakashi Iwai 424352f7f91STakashi Iwai /* 425352f7f91STakashi Iwai * path activation / deactivation 426352f7f91STakashi Iwai */ 427352f7f91STakashi Iwai 428352f7f91STakashi Iwai /* can have the amp-in capability? */ 429352f7f91STakashi Iwai static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx) 430352f7f91STakashi Iwai { 431352f7f91STakashi Iwai hda_nid_t nid = path->path[idx]; 432352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 433352f7f91STakashi Iwai unsigned int type = get_wcaps_type(caps); 434352f7f91STakashi Iwai 435352f7f91STakashi Iwai if (!(caps & AC_WCAP_IN_AMP)) 436352f7f91STakashi Iwai return false; 437352f7f91STakashi Iwai if (type == AC_WID_PIN && idx > 0) /* only for input pins */ 438352f7f91STakashi Iwai return false; 439352f7f91STakashi Iwai return true; 440352f7f91STakashi Iwai } 441352f7f91STakashi Iwai 442352f7f91STakashi Iwai /* can have the amp-out capability? */ 443352f7f91STakashi Iwai static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx) 444352f7f91STakashi Iwai { 445352f7f91STakashi Iwai hda_nid_t nid = path->path[idx]; 446352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 447352f7f91STakashi Iwai unsigned int type = get_wcaps_type(caps); 448352f7f91STakashi Iwai 449352f7f91STakashi Iwai if (!(caps & AC_WCAP_OUT_AMP)) 450352f7f91STakashi Iwai return false; 451352f7f91STakashi Iwai if (type == AC_WID_PIN && !idx) /* only for output pins */ 452352f7f91STakashi Iwai return false; 453352f7f91STakashi Iwai return true; 454352f7f91STakashi Iwai } 455352f7f91STakashi Iwai 456352f7f91STakashi Iwai /* check whether the given (nid,dir,idx) is active */ 457352f7f91STakashi Iwai static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid, 458352f7f91STakashi Iwai unsigned int idx, unsigned int dir) 459352f7f91STakashi Iwai { 460352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 461352f7f91STakashi Iwai int i, n; 462352f7f91STakashi Iwai 463352f7f91STakashi Iwai for (n = 0; n < spec->paths.used; n++) { 464352f7f91STakashi Iwai struct nid_path *path = snd_array_elem(&spec->paths, n); 465352f7f91STakashi Iwai if (!path->active) 466352f7f91STakashi Iwai continue; 467352f7f91STakashi Iwai for (i = 0; i < path->depth; i++) { 468352f7f91STakashi Iwai if (path->path[i] == nid) { 469352f7f91STakashi Iwai if (dir == HDA_OUTPUT || path->idx[i] == idx) 470352f7f91STakashi Iwai return true; 471352f7f91STakashi Iwai break; 472352f7f91STakashi Iwai } 473352f7f91STakashi Iwai } 474352f7f91STakashi Iwai } 475352f7f91STakashi Iwai return false; 476352f7f91STakashi Iwai } 477352f7f91STakashi Iwai 478352f7f91STakashi Iwai /* get the default amp value for the target state */ 479352f7f91STakashi Iwai static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid, 480352f7f91STakashi Iwai int dir, bool enable) 481352f7f91STakashi Iwai { 482352f7f91STakashi Iwai unsigned int caps; 483352f7f91STakashi Iwai unsigned int val = 0; 484352f7f91STakashi Iwai 485352f7f91STakashi Iwai caps = query_amp_caps(codec, nid, dir); 486352f7f91STakashi Iwai if (caps & AC_AMPCAP_NUM_STEPS) { 487352f7f91STakashi Iwai /* set to 0dB */ 488352f7f91STakashi Iwai if (enable) 489352f7f91STakashi Iwai val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; 490352f7f91STakashi Iwai } 491352f7f91STakashi Iwai if (caps & AC_AMPCAP_MUTE) { 492352f7f91STakashi Iwai if (!enable) 493352f7f91STakashi Iwai val |= HDA_AMP_MUTE; 494352f7f91STakashi Iwai } 495352f7f91STakashi Iwai return val; 496352f7f91STakashi Iwai } 497352f7f91STakashi Iwai 498352f7f91STakashi Iwai /* initialize the amp value (only at the first time) */ 499352f7f91STakashi Iwai static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx) 500352f7f91STakashi Iwai { 501352f7f91STakashi Iwai int val = get_amp_val_to_activate(codec, nid, dir, false); 502352f7f91STakashi Iwai snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); 503352f7f91STakashi Iwai } 504352f7f91STakashi Iwai 505352f7f91STakashi Iwai static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, 506352f7f91STakashi Iwai int idx, bool enable) 507352f7f91STakashi Iwai { 508352f7f91STakashi Iwai int val; 509352f7f91STakashi Iwai if (is_ctl_associated(codec, nid, dir, idx) || 510985803caSTakashi Iwai (!enable && is_active_nid(codec, nid, dir, idx))) 511352f7f91STakashi Iwai return; 512352f7f91STakashi Iwai val = get_amp_val_to_activate(codec, nid, dir, enable); 513352f7f91STakashi Iwai snd_hda_codec_amp_stereo(codec, nid, dir, idx, 0xff, val); 514352f7f91STakashi Iwai } 515352f7f91STakashi Iwai 516352f7f91STakashi Iwai static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, 517352f7f91STakashi Iwai int i, bool enable) 518352f7f91STakashi Iwai { 519352f7f91STakashi Iwai hda_nid_t nid = path->path[i]; 520352f7f91STakashi Iwai init_amp(codec, nid, HDA_OUTPUT, 0); 521352f7f91STakashi Iwai activate_amp(codec, nid, HDA_OUTPUT, 0, enable); 522352f7f91STakashi Iwai } 523352f7f91STakashi Iwai 524352f7f91STakashi Iwai static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, 525352f7f91STakashi Iwai int i, bool enable, bool add_aamix) 526352f7f91STakashi Iwai { 527352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 528ee8e765bSTakashi Iwai const hda_nid_t *conn; 529352f7f91STakashi Iwai int n, nums, idx; 530352f7f91STakashi Iwai int type; 531352f7f91STakashi Iwai hda_nid_t nid = path->path[i]; 532352f7f91STakashi Iwai 533ee8e765bSTakashi Iwai nums = snd_hda_get_conn_list(codec, nid, &conn); 534352f7f91STakashi Iwai type = get_wcaps_type(get_wcaps(codec, nid)); 535352f7f91STakashi Iwai if (type == AC_WID_PIN || 536352f7f91STakashi Iwai (type == AC_WID_AUD_IN && codec->single_adc_amp)) { 537352f7f91STakashi Iwai nums = 1; 538352f7f91STakashi Iwai idx = 0; 539352f7f91STakashi Iwai } else 540352f7f91STakashi Iwai idx = path->idx[i]; 541352f7f91STakashi Iwai 542352f7f91STakashi Iwai for (n = 0; n < nums; n++) 543352f7f91STakashi Iwai init_amp(codec, nid, HDA_INPUT, n); 544352f7f91STakashi Iwai 545352f7f91STakashi Iwai if (is_ctl_associated(codec, nid, HDA_INPUT, idx)) 546352f7f91STakashi Iwai return; 547352f7f91STakashi Iwai 548352f7f91STakashi Iwai /* here is a little bit tricky in comparison with activate_amp_out(); 549352f7f91STakashi Iwai * when aa-mixer is available, we need to enable the path as well 550352f7f91STakashi Iwai */ 551352f7f91STakashi Iwai for (n = 0; n < nums; n++) { 552352f7f91STakashi Iwai if (n != idx && (!add_aamix || conn[n] != spec->mixer_nid)) 553352f7f91STakashi Iwai continue; 554352f7f91STakashi Iwai activate_amp(codec, nid, HDA_INPUT, n, enable); 555352f7f91STakashi Iwai } 556352f7f91STakashi Iwai } 557352f7f91STakashi Iwai 558352f7f91STakashi Iwai /* activate or deactivate the given path 559352f7f91STakashi Iwai * if @add_aamix is set, enable the input from aa-mix NID as well (if any) 560352f7f91STakashi Iwai */ 561352f7f91STakashi Iwai void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path, 562352f7f91STakashi Iwai bool enable, bool add_aamix) 563352f7f91STakashi Iwai { 564352f7f91STakashi Iwai int i; 565352f7f91STakashi Iwai 566352f7f91STakashi Iwai if (!enable) 567352f7f91STakashi Iwai path->active = false; 568352f7f91STakashi Iwai 569352f7f91STakashi Iwai for (i = path->depth - 1; i >= 0; i--) { 570352f7f91STakashi Iwai if (enable && path->multi[i]) 571352f7f91STakashi Iwai snd_hda_codec_write_cache(codec, path->path[i], 0, 572352f7f91STakashi Iwai AC_VERB_SET_CONNECT_SEL, 573352f7f91STakashi Iwai path->idx[i]); 574352f7f91STakashi Iwai if (has_amp_in(codec, path, i)) 575352f7f91STakashi Iwai activate_amp_in(codec, path, i, enable, add_aamix); 576352f7f91STakashi Iwai if (has_amp_out(codec, path, i)) 577352f7f91STakashi Iwai activate_amp_out(codec, path, i, enable); 578352f7f91STakashi Iwai } 579352f7f91STakashi Iwai 580352f7f91STakashi Iwai if (enable) 581352f7f91STakashi Iwai path->active = true; 582352f7f91STakashi Iwai } 583352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_activate_path); 584352f7f91STakashi Iwai 585d5a9f1bbSTakashi Iwai /* turn on/off EAPD on the given pin */ 586d5a9f1bbSTakashi Iwai static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable) 587d5a9f1bbSTakashi Iwai { 588d5a9f1bbSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 589d5a9f1bbSTakashi Iwai if (spec->own_eapd_ctl || 590d5a9f1bbSTakashi Iwai !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD)) 591d5a9f1bbSTakashi Iwai return; 592ecac3ed1STakashi Iwai if (codec->inv_eapd) 593ecac3ed1STakashi Iwai enable = !enable; 594d5a9f1bbSTakashi Iwai snd_hda_codec_update_cache(codec, pin, 0, 595d5a9f1bbSTakashi Iwai AC_VERB_SET_EAPD_BTLENABLE, 596d5a9f1bbSTakashi Iwai enable ? 0x02 : 0x00); 597d5a9f1bbSTakashi Iwai } 598d5a9f1bbSTakashi Iwai 599352f7f91STakashi Iwai 600352f7f91STakashi Iwai /* 601352f7f91STakashi Iwai * Helper functions for creating mixer ctl elements 602352f7f91STakashi Iwai */ 603352f7f91STakashi Iwai 604352f7f91STakashi Iwai enum { 605352f7f91STakashi Iwai HDA_CTL_WIDGET_VOL, 606352f7f91STakashi Iwai HDA_CTL_WIDGET_MUTE, 607352f7f91STakashi Iwai HDA_CTL_BIND_MUTE, 608352f7f91STakashi Iwai HDA_CTL_BIND_VOL, 609352f7f91STakashi Iwai HDA_CTL_BIND_SW, 610352f7f91STakashi Iwai }; 611352f7f91STakashi Iwai static const struct snd_kcontrol_new control_templates[] = { 612352f7f91STakashi Iwai HDA_CODEC_VOLUME(NULL, 0, 0, 0), 613352f7f91STakashi Iwai HDA_CODEC_MUTE(NULL, 0, 0, 0), 614352f7f91STakashi Iwai HDA_BIND_MUTE(NULL, 0, 0, 0), 615352f7f91STakashi Iwai HDA_BIND_VOL(NULL, 0), 616352f7f91STakashi Iwai HDA_BIND_SW(NULL, 0), 617352f7f91STakashi Iwai }; 618352f7f91STakashi Iwai 619352f7f91STakashi Iwai /* add dynamic controls from template */ 620352f7f91STakashi Iwai static int add_control(struct hda_gen_spec *spec, int type, const char *name, 621352f7f91STakashi Iwai int cidx, unsigned long val) 622352f7f91STakashi Iwai { 623352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 624352f7f91STakashi Iwai 62512c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]); 626352f7f91STakashi Iwai if (!knew) 627352f7f91STakashi Iwai return -ENOMEM; 628352f7f91STakashi Iwai knew->index = cidx; 629352f7f91STakashi Iwai if (get_amp_nid_(val)) 630352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 631352f7f91STakashi Iwai knew->private_value = val; 632352f7f91STakashi Iwai return 0; 633352f7f91STakashi Iwai } 634352f7f91STakashi Iwai 635352f7f91STakashi Iwai static int add_control_with_pfx(struct hda_gen_spec *spec, int type, 636352f7f91STakashi Iwai const char *pfx, const char *dir, 637352f7f91STakashi Iwai const char *sfx, int cidx, unsigned long val) 638352f7f91STakashi Iwai { 639352f7f91STakashi Iwai char name[32]; 640352f7f91STakashi Iwai snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); 641352f7f91STakashi Iwai return add_control(spec, type, name, cidx, val); 642352f7f91STakashi Iwai } 643352f7f91STakashi Iwai 644352f7f91STakashi Iwai #define add_pb_vol_ctrl(spec, type, pfx, val) \ 645352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val) 646352f7f91STakashi Iwai #define add_pb_sw_ctrl(spec, type, pfx, val) \ 647352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val) 648352f7f91STakashi Iwai #define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \ 649352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val) 650352f7f91STakashi Iwai #define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ 651352f7f91STakashi Iwai add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) 652352f7f91STakashi Iwai 653352f7f91STakashi Iwai static int add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx, 654352f7f91STakashi Iwai unsigned int chs, struct nid_path *path) 655352f7f91STakashi Iwai { 656352f7f91STakashi Iwai unsigned int val; 657352f7f91STakashi Iwai if (!path) 658352f7f91STakashi Iwai return 0; 659352f7f91STakashi Iwai val = path->ctls[NID_PATH_VOL_CTL]; 660352f7f91STakashi Iwai if (!val) 661352f7f91STakashi Iwai return 0; 662352f7f91STakashi Iwai val = amp_val_replace_channels(val, chs); 663352f7f91STakashi Iwai return __add_pb_vol_ctrl(codec->spec, HDA_CTL_WIDGET_VOL, pfx, cidx, val); 664352f7f91STakashi Iwai } 665352f7f91STakashi Iwai 666352f7f91STakashi Iwai /* return the channel bits suitable for the given path->ctls[] */ 667352f7f91STakashi Iwai static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path, 668352f7f91STakashi Iwai int type) 669352f7f91STakashi Iwai { 670352f7f91STakashi Iwai int chs = 1; /* mono (left only) */ 671352f7f91STakashi Iwai if (path) { 672352f7f91STakashi Iwai hda_nid_t nid = get_amp_nid_(path->ctls[type]); 673352f7f91STakashi Iwai if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO)) 674352f7f91STakashi Iwai chs = 3; /* stereo */ 675352f7f91STakashi Iwai } 676352f7f91STakashi Iwai return chs; 677352f7f91STakashi Iwai } 678352f7f91STakashi Iwai 679352f7f91STakashi Iwai static int add_stereo_vol(struct hda_codec *codec, const char *pfx, int cidx, 680352f7f91STakashi Iwai struct nid_path *path) 681352f7f91STakashi Iwai { 682352f7f91STakashi Iwai int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL); 683352f7f91STakashi Iwai return add_vol_ctl(codec, pfx, cidx, chs, path); 684352f7f91STakashi Iwai } 685352f7f91STakashi Iwai 686352f7f91STakashi Iwai /* create a mute-switch for the given mixer widget; 687352f7f91STakashi Iwai * if it has multiple sources (e.g. DAC and loopback), create a bind-mute 688352f7f91STakashi Iwai */ 689352f7f91STakashi Iwai static int add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx, 690352f7f91STakashi Iwai unsigned int chs, struct nid_path *path) 691352f7f91STakashi Iwai { 692352f7f91STakashi Iwai unsigned int val; 693352f7f91STakashi Iwai int type = HDA_CTL_WIDGET_MUTE; 694352f7f91STakashi Iwai 695352f7f91STakashi Iwai if (!path) 696352f7f91STakashi Iwai return 0; 697352f7f91STakashi Iwai val = path->ctls[NID_PATH_MUTE_CTL]; 698352f7f91STakashi Iwai if (!val) 699352f7f91STakashi Iwai return 0; 700352f7f91STakashi Iwai val = amp_val_replace_channels(val, chs); 701352f7f91STakashi Iwai if (get_amp_direction_(val) == HDA_INPUT) { 702352f7f91STakashi Iwai hda_nid_t nid = get_amp_nid_(val); 703352f7f91STakashi Iwai int nums = snd_hda_get_num_conns(codec, nid); 704352f7f91STakashi Iwai if (nums > 1) { 705352f7f91STakashi Iwai type = HDA_CTL_BIND_MUTE; 706352f7f91STakashi Iwai val |= nums << 19; 707352f7f91STakashi Iwai } 708352f7f91STakashi Iwai } 709352f7f91STakashi Iwai return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val); 710352f7f91STakashi Iwai } 711352f7f91STakashi Iwai 712352f7f91STakashi Iwai static int add_stereo_sw(struct hda_codec *codec, const char *pfx, 713352f7f91STakashi Iwai int cidx, struct nid_path *path) 714352f7f91STakashi Iwai { 715352f7f91STakashi Iwai int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL); 716352f7f91STakashi Iwai return add_sw_ctl(codec, pfx, cidx, chs, path); 717352f7f91STakashi Iwai } 718352f7f91STakashi Iwai 719352f7f91STakashi Iwai static const char * const channel_name[4] = { 720352f7f91STakashi Iwai "Front", "Surround", "CLFE", "Side" 721352f7f91STakashi Iwai }; 722352f7f91STakashi Iwai 723352f7f91STakashi Iwai /* give some appropriate ctl name prefix for the given line out channel */ 724352f7f91STakashi Iwai static const char *get_line_out_pfx(struct hda_gen_spec *spec, int ch, 725352f7f91STakashi Iwai bool can_be_master, int *index) 726352f7f91STakashi Iwai { 727352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 728352f7f91STakashi Iwai 729352f7f91STakashi Iwai *index = 0; 730352f7f91STakashi Iwai if (cfg->line_outs == 1 && !spec->multi_ios && 731352f7f91STakashi Iwai !cfg->hp_outs && !cfg->speaker_outs && can_be_master) 732352f7f91STakashi Iwai return spec->vmaster_mute.hook ? "PCM" : "Master"; 733352f7f91STakashi Iwai 734352f7f91STakashi Iwai /* if there is really a single DAC used in the whole output paths, 735352f7f91STakashi Iwai * use it master (or "PCM" if a vmaster hook is present) 736352f7f91STakashi Iwai */ 737352f7f91STakashi Iwai if (spec->multiout.num_dacs == 1 && !spec->mixer_nid && 738352f7f91STakashi Iwai !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0]) 739352f7f91STakashi Iwai return spec->vmaster_mute.hook ? "PCM" : "Master"; 740352f7f91STakashi Iwai 741352f7f91STakashi Iwai switch (cfg->line_out_type) { 742352f7f91STakashi Iwai case AUTO_PIN_SPEAKER_OUT: 743352f7f91STakashi Iwai if (cfg->line_outs == 1) 744352f7f91STakashi Iwai return "Speaker"; 745352f7f91STakashi Iwai if (cfg->line_outs == 2) 746352f7f91STakashi Iwai return ch ? "Bass Speaker" : "Speaker"; 747352f7f91STakashi Iwai break; 748352f7f91STakashi Iwai case AUTO_PIN_HP_OUT: 749352f7f91STakashi Iwai /* for multi-io case, only the primary out */ 750352f7f91STakashi Iwai if (ch && spec->multi_ios) 751352f7f91STakashi Iwai break; 752352f7f91STakashi Iwai *index = ch; 753352f7f91STakashi Iwai return "Headphone"; 754352f7f91STakashi Iwai default: 755352f7f91STakashi Iwai if (cfg->line_outs == 1 && !spec->multi_ios) 756352f7f91STakashi Iwai return "PCM"; 757352f7f91STakashi Iwai break; 758352f7f91STakashi Iwai } 759352f7f91STakashi Iwai if (ch >= ARRAY_SIZE(channel_name)) { 760352f7f91STakashi Iwai snd_BUG(); 761352f7f91STakashi Iwai return "PCM"; 762352f7f91STakashi Iwai } 763352f7f91STakashi Iwai 764352f7f91STakashi Iwai return channel_name[ch]; 765352f7f91STakashi Iwai } 766352f7f91STakashi Iwai 767352f7f91STakashi Iwai /* 768352f7f91STakashi Iwai * Parse output paths 769352f7f91STakashi Iwai */ 770352f7f91STakashi Iwai 771352f7f91STakashi Iwai /* badness definition */ 772352f7f91STakashi Iwai enum { 773352f7f91STakashi Iwai /* No primary DAC is found for the main output */ 774352f7f91STakashi Iwai BAD_NO_PRIMARY_DAC = 0x10000, 775352f7f91STakashi Iwai /* No DAC is found for the extra output */ 776352f7f91STakashi Iwai BAD_NO_DAC = 0x4000, 777352f7f91STakashi Iwai /* No possible multi-ios */ 778352f7f91STakashi Iwai BAD_MULTI_IO = 0x103, 779352f7f91STakashi Iwai /* No individual DAC for extra output */ 780352f7f91STakashi Iwai BAD_NO_EXTRA_DAC = 0x102, 781352f7f91STakashi Iwai /* No individual DAC for extra surrounds */ 782352f7f91STakashi Iwai BAD_NO_EXTRA_SURR_DAC = 0x101, 783352f7f91STakashi Iwai /* Primary DAC shared with main surrounds */ 784352f7f91STakashi Iwai BAD_SHARED_SURROUND = 0x100, 785352f7f91STakashi Iwai /* Primary DAC shared with main CLFE */ 786352f7f91STakashi Iwai BAD_SHARED_CLFE = 0x10, 787352f7f91STakashi Iwai /* Primary DAC shared with extra surrounds */ 788352f7f91STakashi Iwai BAD_SHARED_EXTRA_SURROUND = 0x10, 789352f7f91STakashi Iwai /* Volume widget is shared */ 790352f7f91STakashi Iwai BAD_SHARED_VOL = 0x10, 791352f7f91STakashi Iwai }; 792352f7f91STakashi Iwai 793352f7f91STakashi Iwai /* look for widgets in the path between the given NIDs appropriate for 794352f7f91STakashi Iwai * volume and mute controls, and assign the values to ctls[]. 795352f7f91STakashi Iwai * 796352f7f91STakashi Iwai * When no appropriate widget is found in the path, the badness value 797352f7f91STakashi Iwai * is incremented depending on the situation. The function returns the 798352f7f91STakashi Iwai * total badness for both volume and mute controls. 799352f7f91STakashi Iwai */ 800352f7f91STakashi Iwai static int assign_out_path_ctls(struct hda_codec *codec, hda_nid_t pin, 801352f7f91STakashi Iwai hda_nid_t dac) 802352f7f91STakashi Iwai { 803352f7f91STakashi Iwai struct nid_path *path = snd_hda_get_nid_path(codec, dac, pin); 804352f7f91STakashi Iwai hda_nid_t nid; 805352f7f91STakashi Iwai unsigned int val; 806352f7f91STakashi Iwai int badness = 0; 807352f7f91STakashi Iwai 808352f7f91STakashi Iwai if (!path) 809352f7f91STakashi Iwai return BAD_SHARED_VOL * 2; 810352f7f91STakashi Iwai nid = look_for_out_vol_nid(codec, path); 811352f7f91STakashi Iwai if (nid) { 812352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 813352f7f91STakashi Iwai if (is_ctl_used(codec, val, NID_PATH_VOL_CTL)) 814352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 815352f7f91STakashi Iwai else 816352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = val; 817352f7f91STakashi Iwai } else 818352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 819352f7f91STakashi Iwai nid = look_for_out_mute_nid(codec, path); 820352f7f91STakashi Iwai if (nid) { 821352f7f91STakashi Iwai unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid)); 822352f7f91STakashi Iwai if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT || 823352f7f91STakashi Iwai nid_has_mute(codec, nid, HDA_OUTPUT)) 824352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 825352f7f91STakashi Iwai else 826352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); 827352f7f91STakashi Iwai if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL)) 828352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 829352f7f91STakashi Iwai else 830352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = val; 831352f7f91STakashi Iwai } else 832352f7f91STakashi Iwai badness += BAD_SHARED_VOL; 833352f7f91STakashi Iwai return badness; 834352f7f91STakashi Iwai } 835352f7f91STakashi Iwai 836352f7f91STakashi Iwai struct badness_table { 837352f7f91STakashi Iwai int no_primary_dac; /* no primary DAC */ 838352f7f91STakashi Iwai int no_dac; /* no secondary DACs */ 839352f7f91STakashi Iwai int shared_primary; /* primary DAC is shared with main output */ 840352f7f91STakashi Iwai int shared_surr; /* secondary DAC shared with main or primary */ 841352f7f91STakashi Iwai int shared_clfe; /* third DAC shared with main or primary */ 842352f7f91STakashi Iwai int shared_surr_main; /* secondary DAC sahred with main/DAC0 */ 843352f7f91STakashi Iwai }; 844352f7f91STakashi Iwai 845352f7f91STakashi Iwai static struct badness_table main_out_badness = { 846352f7f91STakashi Iwai .no_primary_dac = BAD_NO_PRIMARY_DAC, 847352f7f91STakashi Iwai .no_dac = BAD_NO_DAC, 848352f7f91STakashi Iwai .shared_primary = BAD_NO_PRIMARY_DAC, 849352f7f91STakashi Iwai .shared_surr = BAD_SHARED_SURROUND, 850352f7f91STakashi Iwai .shared_clfe = BAD_SHARED_CLFE, 851352f7f91STakashi Iwai .shared_surr_main = BAD_SHARED_SURROUND, 852352f7f91STakashi Iwai }; 853352f7f91STakashi Iwai 854352f7f91STakashi Iwai static struct badness_table extra_out_badness = { 855352f7f91STakashi Iwai .no_primary_dac = BAD_NO_DAC, 856352f7f91STakashi Iwai .no_dac = BAD_NO_DAC, 857352f7f91STakashi Iwai .shared_primary = BAD_NO_EXTRA_DAC, 858352f7f91STakashi Iwai .shared_surr = BAD_SHARED_EXTRA_SURROUND, 859352f7f91STakashi Iwai .shared_clfe = BAD_SHARED_EXTRA_SURROUND, 860352f7f91STakashi Iwai .shared_surr_main = BAD_NO_EXTRA_SURR_DAC, 861352f7f91STakashi Iwai }; 862352f7f91STakashi Iwai 8637385df61STakashi Iwai /* get the DAC of the primary output corresponding to the given array index */ 8647385df61STakashi Iwai static hda_nid_t get_primary_out(struct hda_codec *codec, int idx) 8657385df61STakashi Iwai { 8667385df61STakashi Iwai struct hda_gen_spec *spec = codec->spec; 8677385df61STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 8687385df61STakashi Iwai 8697385df61STakashi Iwai if (cfg->line_outs > idx) 8707385df61STakashi Iwai return spec->private_dac_nids[idx]; 8717385df61STakashi Iwai idx -= cfg->line_outs; 8727385df61STakashi Iwai if (spec->multi_ios > idx) 8737385df61STakashi Iwai return spec->multi_io[idx].dac; 8747385df61STakashi Iwai return 0; 8757385df61STakashi Iwai } 8767385df61STakashi Iwai 8777385df61STakashi Iwai /* return the DAC if it's reachable, otherwise zero */ 8787385df61STakashi Iwai static inline hda_nid_t try_dac(struct hda_codec *codec, 8797385df61STakashi Iwai hda_nid_t dac, hda_nid_t pin) 8807385df61STakashi Iwai { 8817385df61STakashi Iwai return is_reachable_path(codec, dac, pin) ? dac : 0; 8827385df61STakashi Iwai } 8837385df61STakashi Iwai 884352f7f91STakashi Iwai /* try to assign DACs to pins and return the resultant badness */ 885352f7f91STakashi Iwai static int try_assign_dacs(struct hda_codec *codec, int num_outs, 886352f7f91STakashi Iwai const hda_nid_t *pins, hda_nid_t *dacs, 887196c1766STakashi Iwai int *path_idx, 888352f7f91STakashi Iwai const struct badness_table *bad) 889352f7f91STakashi Iwai { 890352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 891352f7f91STakashi Iwai int i, j; 892352f7f91STakashi Iwai int badness = 0; 893352f7f91STakashi Iwai hda_nid_t dac; 894352f7f91STakashi Iwai 895352f7f91STakashi Iwai if (!num_outs) 896352f7f91STakashi Iwai return 0; 897352f7f91STakashi Iwai 898352f7f91STakashi Iwai for (i = 0; i < num_outs; i++) { 8990c8c0f56STakashi Iwai struct nid_path *path; 900352f7f91STakashi Iwai hda_nid_t pin = pins[i]; 9011e0b5286STakashi Iwai 9021e0b5286STakashi Iwai if (dacs[i]) { 9031e0b5286STakashi Iwai badness += assign_out_path_ctls(codec, pin, dacs[i]); 9041e0b5286STakashi Iwai continue; 9051e0b5286STakashi Iwai } 9061e0b5286STakashi Iwai 907352f7f91STakashi Iwai dacs[i] = look_for_dac(codec, pin, false); 908352f7f91STakashi Iwai if (!dacs[i] && !i) { 909352f7f91STakashi Iwai for (j = 1; j < num_outs; j++) { 910352f7f91STakashi Iwai if (is_reachable_path(codec, dacs[j], pin)) { 911352f7f91STakashi Iwai dacs[0] = dacs[j]; 912352f7f91STakashi Iwai dacs[j] = 0; 913196c1766STakashi Iwai path_idx[j] = 0; 914352f7f91STakashi Iwai break; 915352f7f91STakashi Iwai } 916352f7f91STakashi Iwai } 917352f7f91STakashi Iwai } 918352f7f91STakashi Iwai dac = dacs[i]; 919352f7f91STakashi Iwai if (!dac) { 9207385df61STakashi Iwai if (num_outs > 2) 9217385df61STakashi Iwai dac = try_dac(codec, get_primary_out(codec, i), pin); 9227385df61STakashi Iwai if (!dac) 9237385df61STakashi Iwai dac = try_dac(codec, dacs[0], pin); 9247385df61STakashi Iwai if (!dac) 9257385df61STakashi Iwai dac = try_dac(codec, get_primary_out(codec, i), pin); 926352f7f91STakashi Iwai if (dac) { 927352f7f91STakashi Iwai if (!i) 928352f7f91STakashi Iwai badness += bad->shared_primary; 929352f7f91STakashi Iwai else if (i == 1) 930352f7f91STakashi Iwai badness += bad->shared_surr; 931352f7f91STakashi Iwai else 932352f7f91STakashi Iwai badness += bad->shared_clfe; 933352f7f91STakashi Iwai } else if (is_reachable_path(codec, spec->private_dac_nids[0], pin)) { 934352f7f91STakashi Iwai dac = spec->private_dac_nids[0]; 935352f7f91STakashi Iwai badness += bad->shared_surr_main; 936352f7f91STakashi Iwai } else if (!i) 937352f7f91STakashi Iwai badness += bad->no_primary_dac; 938352f7f91STakashi Iwai else 939352f7f91STakashi Iwai badness += bad->no_dac; 940352f7f91STakashi Iwai } 9414ac0eefaSTakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, HDA_PARSE_NO_AAMIX); 942117688a9STakashi Iwai if (!path && !i && spec->mixer_nid) { 943b3a8c745STakashi Iwai /* try with aamix */ 944b3a8c745STakashi Iwai path = snd_hda_add_new_path(codec, dac, pin, HDA_PARSE_ALL); 945b3a8c745STakashi Iwai } 9460c8c0f56STakashi Iwai if (!path) 947352f7f91STakashi Iwai dac = dacs[i] = 0; 948e1284af7STakashi Iwai else { 9490c8c0f56STakashi Iwai print_nid_path("output", path); 950e1284af7STakashi Iwai path->active = true; 951196c1766STakashi Iwai path_idx[i] = snd_hda_get_path_idx(codec, path); 952e1284af7STakashi Iwai } 953352f7f91STakashi Iwai if (dac) 954352f7f91STakashi Iwai badness += assign_out_path_ctls(codec, pin, dac); 955352f7f91STakashi Iwai } 956352f7f91STakashi Iwai 957352f7f91STakashi Iwai return badness; 958352f7f91STakashi Iwai } 959352f7f91STakashi Iwai 960352f7f91STakashi Iwai /* return NID if the given pin has only a single connection to a certain DAC */ 961352f7f91STakashi Iwai static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) 962352f7f91STakashi Iwai { 963352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 964352f7f91STakashi Iwai int i; 965352f7f91STakashi Iwai hda_nid_t nid_found = 0; 966352f7f91STakashi Iwai 967352f7f91STakashi Iwai for (i = 0; i < spec->num_all_dacs; i++) { 968352f7f91STakashi Iwai hda_nid_t nid = spec->all_dacs[i]; 969352f7f91STakashi Iwai if (!nid || is_dac_already_used(codec, nid)) 970352f7f91STakashi Iwai continue; 971352f7f91STakashi Iwai if (is_reachable_path(codec, nid, pin)) { 972352f7f91STakashi Iwai if (nid_found) 973352f7f91STakashi Iwai return 0; 974352f7f91STakashi Iwai nid_found = nid; 975352f7f91STakashi Iwai } 976352f7f91STakashi Iwai } 977352f7f91STakashi Iwai return nid_found; 978352f7f91STakashi Iwai } 979352f7f91STakashi Iwai 980352f7f91STakashi Iwai /* check whether the given pin can be a multi-io pin */ 981352f7f91STakashi Iwai static bool can_be_multiio_pin(struct hda_codec *codec, 982352f7f91STakashi Iwai unsigned int location, hda_nid_t nid) 983352f7f91STakashi Iwai { 984352f7f91STakashi Iwai unsigned int defcfg, caps; 985352f7f91STakashi Iwai 986352f7f91STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, nid); 987352f7f91STakashi Iwai if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) 988352f7f91STakashi Iwai return false; 989352f7f91STakashi Iwai if (location && get_defcfg_location(defcfg) != location) 990352f7f91STakashi Iwai return false; 991352f7f91STakashi Iwai caps = snd_hda_query_pin_caps(codec, nid); 992352f7f91STakashi Iwai if (!(caps & AC_PINCAP_OUT)) 993352f7f91STakashi Iwai return false; 994352f7f91STakashi Iwai return true; 995352f7f91STakashi Iwai } 996352f7f91STakashi Iwai 997e22aab7dSTakashi Iwai /* count the number of input pins that are capable to be multi-io */ 998e22aab7dSTakashi Iwai static int count_multiio_pins(struct hda_codec *codec, hda_nid_t reference_pin) 999e22aab7dSTakashi Iwai { 1000e22aab7dSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 1001e22aab7dSTakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1002e22aab7dSTakashi Iwai unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); 1003e22aab7dSTakashi Iwai unsigned int location = get_defcfg_location(defcfg); 1004e22aab7dSTakashi Iwai int type, i; 1005e22aab7dSTakashi Iwai int num_pins = 0; 1006e22aab7dSTakashi Iwai 1007e22aab7dSTakashi Iwai for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { 1008e22aab7dSTakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 1009e22aab7dSTakashi Iwai if (cfg->inputs[i].type != type) 1010e22aab7dSTakashi Iwai continue; 1011e22aab7dSTakashi Iwai if (can_be_multiio_pin(codec, location, 1012e22aab7dSTakashi Iwai cfg->inputs[i].pin)) 1013e22aab7dSTakashi Iwai num_pins++; 1014e22aab7dSTakashi Iwai } 1015e22aab7dSTakashi Iwai } 1016e22aab7dSTakashi Iwai return num_pins; 1017e22aab7dSTakashi Iwai } 1018e22aab7dSTakashi Iwai 1019352f7f91STakashi Iwai /* 1020352f7f91STakashi Iwai * multi-io helper 1021352f7f91STakashi Iwai * 1022352f7f91STakashi Iwai * When hardwired is set, try to fill ony hardwired pins, and returns 1023352f7f91STakashi Iwai * zero if any pins are filled, non-zero if nothing found. 1024352f7f91STakashi Iwai * When hardwired is off, try to fill possible input pins, and returns 1025352f7f91STakashi Iwai * the badness value. 1026352f7f91STakashi Iwai */ 1027352f7f91STakashi Iwai static int fill_multi_ios(struct hda_codec *codec, 1028352f7f91STakashi Iwai hda_nid_t reference_pin, 1029e22aab7dSTakashi Iwai bool hardwired) 1030352f7f91STakashi Iwai { 1031352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1032352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1033e22aab7dSTakashi Iwai int type, i, j, num_pins, old_pins; 1034352f7f91STakashi Iwai unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); 1035352f7f91STakashi Iwai unsigned int location = get_defcfg_location(defcfg); 1036352f7f91STakashi Iwai int badness = 0; 1037352f7f91STakashi Iwai 1038352f7f91STakashi Iwai old_pins = spec->multi_ios; 1039352f7f91STakashi Iwai if (old_pins >= 2) 1040352f7f91STakashi Iwai goto end_fill; 1041352f7f91STakashi Iwai 1042e22aab7dSTakashi Iwai num_pins = count_multiio_pins(codec, reference_pin); 1043352f7f91STakashi Iwai if (num_pins < 2) 1044352f7f91STakashi Iwai goto end_fill; 1045352f7f91STakashi Iwai 1046352f7f91STakashi Iwai for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { 1047352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 10480c8c0f56STakashi Iwai struct nid_path *path; 1049352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 1050352f7f91STakashi Iwai hda_nid_t dac = 0; 1051352f7f91STakashi Iwai 1052352f7f91STakashi Iwai if (cfg->inputs[i].type != type) 1053352f7f91STakashi Iwai continue; 1054352f7f91STakashi Iwai if (!can_be_multiio_pin(codec, location, nid)) 1055352f7f91STakashi Iwai continue; 1056352f7f91STakashi Iwai for (j = 0; j < spec->multi_ios; j++) { 1057352f7f91STakashi Iwai if (nid == spec->multi_io[j].pin) 1058352f7f91STakashi Iwai break; 1059352f7f91STakashi Iwai } 1060352f7f91STakashi Iwai if (j < spec->multi_ios) 1061352f7f91STakashi Iwai continue; 1062352f7f91STakashi Iwai 1063352f7f91STakashi Iwai if (hardwired) 1064352f7f91STakashi Iwai dac = get_dac_if_single(codec, nid); 1065352f7f91STakashi Iwai else if (!dac) 1066352f7f91STakashi Iwai dac = look_for_dac(codec, nid, false); 1067352f7f91STakashi Iwai if (!dac) { 1068352f7f91STakashi Iwai badness++; 1069352f7f91STakashi Iwai continue; 1070352f7f91STakashi Iwai } 10714ac0eefaSTakashi Iwai path = snd_hda_add_new_path(codec, dac, nid, HDA_PARSE_NO_AAMIX); 10720c8c0f56STakashi Iwai if (!path) { 1073352f7f91STakashi Iwai badness++; 1074352f7f91STakashi Iwai continue; 1075352f7f91STakashi Iwai } 10760c8c0f56STakashi Iwai print_nid_path("multiio", path); 1077352f7f91STakashi Iwai spec->multi_io[spec->multi_ios].pin = nid; 1078352f7f91STakashi Iwai spec->multi_io[spec->multi_ios].dac = dac; 1079196c1766STakashi Iwai spec->out_paths[cfg->line_outs + spec->multi_ios] = 1080196c1766STakashi Iwai snd_hda_get_path_idx(codec, path); 1081352f7f91STakashi Iwai spec->multi_ios++; 1082352f7f91STakashi Iwai if (spec->multi_ios >= 2) 1083352f7f91STakashi Iwai break; 1084352f7f91STakashi Iwai } 1085352f7f91STakashi Iwai } 1086352f7f91STakashi Iwai end_fill: 1087352f7f91STakashi Iwai if (badness) 1088352f7f91STakashi Iwai badness = BAD_MULTI_IO; 1089352f7f91STakashi Iwai if (old_pins == spec->multi_ios) { 1090352f7f91STakashi Iwai if (hardwired) 1091352f7f91STakashi Iwai return 1; /* nothing found */ 1092352f7f91STakashi Iwai else 1093352f7f91STakashi Iwai return badness; /* no badness if nothing found */ 1094352f7f91STakashi Iwai } 1095352f7f91STakashi Iwai if (!hardwired && spec->multi_ios < 2) { 1096352f7f91STakashi Iwai /* cancel newly assigned paths */ 1097352f7f91STakashi Iwai spec->paths.used -= spec->multi_ios - old_pins; 1098352f7f91STakashi Iwai spec->multi_ios = old_pins; 1099352f7f91STakashi Iwai return badness; 1100352f7f91STakashi Iwai } 1101352f7f91STakashi Iwai 1102352f7f91STakashi Iwai /* assign volume and mute controls */ 1103352f7f91STakashi Iwai for (i = old_pins; i < spec->multi_ios; i++) 1104352f7f91STakashi Iwai badness += assign_out_path_ctls(codec, spec->multi_io[i].pin, 1105352f7f91STakashi Iwai spec->multi_io[i].dac); 1106352f7f91STakashi Iwai 1107352f7f91STakashi Iwai return badness; 1108352f7f91STakashi Iwai } 1109352f7f91STakashi Iwai 1110352f7f91STakashi Iwai /* map DACs for all pins in the list if they are single connections */ 1111352f7f91STakashi Iwai static bool map_singles(struct hda_codec *codec, int outs, 1112196c1766STakashi Iwai const hda_nid_t *pins, hda_nid_t *dacs, int *path_idx) 1113352f7f91STakashi Iwai { 1114b3a8c745STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1115352f7f91STakashi Iwai int i; 1116352f7f91STakashi Iwai bool found = false; 1117352f7f91STakashi Iwai for (i = 0; i < outs; i++) { 11180c8c0f56STakashi Iwai struct nid_path *path; 1119352f7f91STakashi Iwai hda_nid_t dac; 1120352f7f91STakashi Iwai if (dacs[i]) 1121352f7f91STakashi Iwai continue; 1122352f7f91STakashi Iwai dac = get_dac_if_single(codec, pins[i]); 1123352f7f91STakashi Iwai if (!dac) 1124352f7f91STakashi Iwai continue; 11254ac0eefaSTakashi Iwai path = snd_hda_add_new_path(codec, dac, pins[i], HDA_PARSE_NO_AAMIX); 1126117688a9STakashi Iwai if (!path && !i && spec->mixer_nid) 1127b3a8c745STakashi Iwai path = snd_hda_add_new_path(codec, dac, pins[i], HDA_PARSE_ALL); 11280c8c0f56STakashi Iwai if (path) { 1129352f7f91STakashi Iwai dacs[i] = dac; 1130352f7f91STakashi Iwai found = true; 11310c8c0f56STakashi Iwai print_nid_path("output", path); 1132e1284af7STakashi Iwai path->active = true; 1133196c1766STakashi Iwai path_idx[i] = snd_hda_get_path_idx(codec, path); 1134352f7f91STakashi Iwai } 1135352f7f91STakashi Iwai } 1136352f7f91STakashi Iwai return found; 1137352f7f91STakashi Iwai } 1138352f7f91STakashi Iwai 1139c30aa7b2STakashi Iwai /* create a new path including aamix if available, and return its index */ 1140c30aa7b2STakashi Iwai static int check_aamix_out_path(struct hda_codec *codec, int path_idx) 1141c30aa7b2STakashi Iwai { 1142c30aa7b2STakashi Iwai struct nid_path *path; 1143c30aa7b2STakashi Iwai 1144c30aa7b2STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 1145c30aa7b2STakashi Iwai if (!path || !path->depth || path->with_aa_mix) 1146c30aa7b2STakashi Iwai return 0; 1147c30aa7b2STakashi Iwai path = snd_hda_add_new_path(codec, path->path[0], 1148c30aa7b2STakashi Iwai path->path[path->depth - 1], 1149c30aa7b2STakashi Iwai HDA_PARSE_ONLY_AAMIX); 1150c30aa7b2STakashi Iwai if (!path) 1151c30aa7b2STakashi Iwai return 0; 1152c30aa7b2STakashi Iwai print_nid_path("output-aamix", path); 1153c30aa7b2STakashi Iwai path->active = false; /* unused as default */ 1154c30aa7b2STakashi Iwai return snd_hda_get_path_idx(codec, path); 1155c30aa7b2STakashi Iwai } 1156c30aa7b2STakashi Iwai 1157352f7f91STakashi Iwai /* fill in the dac_nids table from the parsed pin configuration */ 1158352f7f91STakashi Iwai static int fill_and_eval_dacs(struct hda_codec *codec, 1159352f7f91STakashi Iwai bool fill_hardwired, 1160352f7f91STakashi Iwai bool fill_mio_first) 1161352f7f91STakashi Iwai { 1162352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1163352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1164352f7f91STakashi Iwai int i, err, badness; 1165352f7f91STakashi Iwai 1166352f7f91STakashi Iwai /* set num_dacs once to full for look_for_dac() */ 1167352f7f91STakashi Iwai spec->multiout.num_dacs = cfg->line_outs; 1168352f7f91STakashi Iwai spec->multiout.dac_nids = spec->private_dac_nids; 1169352f7f91STakashi Iwai memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); 1170352f7f91STakashi Iwai memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid)); 1171352f7f91STakashi Iwai memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid)); 1172352f7f91STakashi Iwai spec->multi_ios = 0; 1173352f7f91STakashi Iwai snd_array_free(&spec->paths); 1174352f7f91STakashi Iwai badness = 0; 1175352f7f91STakashi Iwai 1176352f7f91STakashi Iwai /* fill hard-wired DACs first */ 1177352f7f91STakashi Iwai if (fill_hardwired) { 1178352f7f91STakashi Iwai bool mapped; 1179352f7f91STakashi Iwai do { 1180352f7f91STakashi Iwai mapped = map_singles(codec, cfg->line_outs, 1181352f7f91STakashi Iwai cfg->line_out_pins, 1182196c1766STakashi Iwai spec->private_dac_nids, 1183196c1766STakashi Iwai spec->out_paths); 1184352f7f91STakashi Iwai mapped |= map_singles(codec, cfg->hp_outs, 1185352f7f91STakashi Iwai cfg->hp_pins, 1186196c1766STakashi Iwai spec->multiout.hp_out_nid, 1187196c1766STakashi Iwai spec->hp_paths); 1188352f7f91STakashi Iwai mapped |= map_singles(codec, cfg->speaker_outs, 1189352f7f91STakashi Iwai cfg->speaker_pins, 1190196c1766STakashi Iwai spec->multiout.extra_out_nid, 1191196c1766STakashi Iwai spec->speaker_paths); 1192352f7f91STakashi Iwai if (fill_mio_first && cfg->line_outs == 1 && 1193352f7f91STakashi Iwai cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1194e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], true); 1195352f7f91STakashi Iwai if (!err) 1196352f7f91STakashi Iwai mapped = true; 1197352f7f91STakashi Iwai } 1198352f7f91STakashi Iwai } while (mapped); 1199352f7f91STakashi Iwai } 1200352f7f91STakashi Iwai 1201352f7f91STakashi Iwai badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins, 1202196c1766STakashi Iwai spec->private_dac_nids, spec->out_paths, 1203352f7f91STakashi Iwai &main_out_badness); 1204352f7f91STakashi Iwai 1205352f7f91STakashi Iwai /* re-count num_dacs and squash invalid entries */ 1206352f7f91STakashi Iwai spec->multiout.num_dacs = 0; 1207352f7f91STakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 1208352f7f91STakashi Iwai if (spec->private_dac_nids[i]) 1209352f7f91STakashi Iwai spec->multiout.num_dacs++; 1210352f7f91STakashi Iwai else { 1211352f7f91STakashi Iwai memmove(spec->private_dac_nids + i, 1212352f7f91STakashi Iwai spec->private_dac_nids + i + 1, 1213352f7f91STakashi Iwai sizeof(hda_nid_t) * (cfg->line_outs - i - 1)); 1214352f7f91STakashi Iwai spec->private_dac_nids[cfg->line_outs - 1] = 0; 1215352f7f91STakashi Iwai } 1216352f7f91STakashi Iwai } 1217352f7f91STakashi Iwai 1218352f7f91STakashi Iwai if (fill_mio_first && 1219352f7f91STakashi Iwai cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1220352f7f91STakashi Iwai /* try to fill multi-io first */ 1221e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], false); 1222352f7f91STakashi Iwai if (err < 0) 1223352f7f91STakashi Iwai return err; 1224352f7f91STakashi Iwai /* we don't count badness at this stage yet */ 1225352f7f91STakashi Iwai } 1226352f7f91STakashi Iwai 1227352f7f91STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) { 1228352f7f91STakashi Iwai err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins, 1229352f7f91STakashi Iwai spec->multiout.hp_out_nid, 1230196c1766STakashi Iwai spec->hp_paths, 1231352f7f91STakashi Iwai &extra_out_badness); 1232352f7f91STakashi Iwai if (err < 0) 1233352f7f91STakashi Iwai return err; 1234352f7f91STakashi Iwai badness += err; 1235352f7f91STakashi Iwai } 1236352f7f91STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1237352f7f91STakashi Iwai err = try_assign_dacs(codec, cfg->speaker_outs, 1238352f7f91STakashi Iwai cfg->speaker_pins, 1239352f7f91STakashi Iwai spec->multiout.extra_out_nid, 1240196c1766STakashi Iwai spec->speaker_paths, 1241352f7f91STakashi Iwai &extra_out_badness); 1242352f7f91STakashi Iwai if (err < 0) 1243352f7f91STakashi Iwai return err; 1244352f7f91STakashi Iwai badness += err; 1245352f7f91STakashi Iwai } 1246352f7f91STakashi Iwai if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { 1247e22aab7dSTakashi Iwai err = fill_multi_ios(codec, cfg->line_out_pins[0], false); 1248352f7f91STakashi Iwai if (err < 0) 1249352f7f91STakashi Iwai return err; 1250352f7f91STakashi Iwai badness += err; 1251352f7f91STakashi Iwai } 1252e22aab7dSTakashi Iwai 1253c30aa7b2STakashi Iwai if (spec->mixer_nid) { 1254c30aa7b2STakashi Iwai spec->aamix_out_paths[0] = 1255c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->out_paths[0]); 1256c30aa7b2STakashi Iwai if (cfg->line_out_type != AUTO_PIN_HP_OUT) 1257c30aa7b2STakashi Iwai spec->aamix_out_paths[1] = 1258c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->hp_paths[0]); 1259c30aa7b2STakashi Iwai if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) 1260c30aa7b2STakashi Iwai spec->aamix_out_paths[2] = 1261c30aa7b2STakashi Iwai check_aamix_out_path(codec, spec->speaker_paths[0]); 1262c30aa7b2STakashi Iwai } 1263c30aa7b2STakashi Iwai 1264e22aab7dSTakashi Iwai if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) 1265e22aab7dSTakashi Iwai if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2) 1266e22aab7dSTakashi Iwai spec->multi_ios = 1; /* give badness */ 1267352f7f91STakashi Iwai 1268352f7f91STakashi Iwai if (spec->multi_ios == 2) { 1269352f7f91STakashi Iwai for (i = 0; i < 2; i++) 1270352f7f91STakashi Iwai spec->private_dac_nids[spec->multiout.num_dacs++] = 1271352f7f91STakashi Iwai spec->multi_io[i].dac; 1272352f7f91STakashi Iwai spec->ext_channel_count = 2; 1273352f7f91STakashi Iwai } else if (spec->multi_ios) { 1274352f7f91STakashi Iwai spec->multi_ios = 0; 1275352f7f91STakashi Iwai badness += BAD_MULTI_IO; 1276352f7f91STakashi Iwai } 1277352f7f91STakashi Iwai 1278352f7f91STakashi Iwai return badness; 1279352f7f91STakashi Iwai } 1280352f7f91STakashi Iwai 1281352f7f91STakashi Iwai #define DEBUG_BADNESS 1282352f7f91STakashi Iwai 1283352f7f91STakashi Iwai #ifdef DEBUG_BADNESS 1284352f7f91STakashi Iwai #define debug_badness snd_printdd 1285352f7f91STakashi Iwai #else 1286352f7f91STakashi Iwai #define debug_badness(...) 1287352f7f91STakashi Iwai #endif 1288352f7f91STakashi Iwai 1289352f7f91STakashi Iwai static void debug_show_configs(struct hda_gen_spec *spec, struct auto_pin_cfg *cfg) 1290352f7f91STakashi Iwai { 1291352f7f91STakashi Iwai debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1292352f7f91STakashi Iwai cfg->line_out_pins[0], cfg->line_out_pins[1], 1293708122e8STakashi Iwai cfg->line_out_pins[2], cfg->line_out_pins[3], 1294352f7f91STakashi Iwai spec->multiout.dac_nids[0], 1295352f7f91STakashi Iwai spec->multiout.dac_nids[1], 1296352f7f91STakashi Iwai spec->multiout.dac_nids[2], 1297352f7f91STakashi Iwai spec->multiout.dac_nids[3]); 1298352f7f91STakashi Iwai if (spec->multi_ios > 0) 1299352f7f91STakashi Iwai debug_badness("multi_ios(%d) = %x/%x : %x/%x\n", 1300352f7f91STakashi Iwai spec->multi_ios, 1301352f7f91STakashi Iwai spec->multi_io[0].pin, spec->multi_io[1].pin, 1302352f7f91STakashi Iwai spec->multi_io[0].dac, spec->multi_io[1].dac); 1303352f7f91STakashi Iwai debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1304352f7f91STakashi Iwai cfg->hp_pins[0], cfg->hp_pins[1], 1305708122e8STakashi Iwai cfg->hp_pins[2], cfg->hp_pins[3], 1306352f7f91STakashi Iwai spec->multiout.hp_out_nid[0], 1307352f7f91STakashi Iwai spec->multiout.hp_out_nid[1], 1308352f7f91STakashi Iwai spec->multiout.hp_out_nid[2], 1309352f7f91STakashi Iwai spec->multiout.hp_out_nid[3]); 1310352f7f91STakashi Iwai debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", 1311352f7f91STakashi Iwai cfg->speaker_pins[0], cfg->speaker_pins[1], 1312352f7f91STakashi Iwai cfg->speaker_pins[2], cfg->speaker_pins[3], 1313352f7f91STakashi Iwai spec->multiout.extra_out_nid[0], 1314352f7f91STakashi Iwai spec->multiout.extra_out_nid[1], 1315352f7f91STakashi Iwai spec->multiout.extra_out_nid[2], 1316352f7f91STakashi Iwai spec->multiout.extra_out_nid[3]); 1317352f7f91STakashi Iwai } 1318352f7f91STakashi Iwai 1319352f7f91STakashi Iwai /* find all available DACs of the codec */ 1320352f7f91STakashi Iwai static void fill_all_dac_nids(struct hda_codec *codec) 1321352f7f91STakashi Iwai { 1322352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1323352f7f91STakashi Iwai int i; 1324352f7f91STakashi Iwai hda_nid_t nid = codec->start_nid; 1325352f7f91STakashi Iwai 1326352f7f91STakashi Iwai spec->num_all_dacs = 0; 1327352f7f91STakashi Iwai memset(spec->all_dacs, 0, sizeof(spec->all_dacs)); 1328352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) { 1329352f7f91STakashi Iwai if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT) 1330352f7f91STakashi Iwai continue; 1331352f7f91STakashi Iwai if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) { 1332352f7f91STakashi Iwai snd_printk(KERN_ERR "hda: Too many DACs!\n"); 1333352f7f91STakashi Iwai break; 1334352f7f91STakashi Iwai } 1335352f7f91STakashi Iwai spec->all_dacs[spec->num_all_dacs++] = nid; 1336352f7f91STakashi Iwai } 1337352f7f91STakashi Iwai } 1338352f7f91STakashi Iwai 1339352f7f91STakashi Iwai static int parse_output_paths(struct hda_codec *codec) 1340352f7f91STakashi Iwai { 1341352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1342352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1343352f7f91STakashi Iwai struct auto_pin_cfg *best_cfg; 1344352f7f91STakashi Iwai int best_badness = INT_MAX; 1345352f7f91STakashi Iwai int badness; 1346352f7f91STakashi Iwai bool fill_hardwired = true, fill_mio_first = true; 1347352f7f91STakashi Iwai bool best_wired = true, best_mio = true; 1348352f7f91STakashi Iwai bool hp_spk_swapped = false; 1349352f7f91STakashi Iwai 1350352f7f91STakashi Iwai fill_all_dac_nids(codec); 1351352f7f91STakashi Iwai 1352352f7f91STakashi Iwai best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL); 1353352f7f91STakashi Iwai if (!best_cfg) 1354352f7f91STakashi Iwai return -ENOMEM; 1355352f7f91STakashi Iwai *best_cfg = *cfg; 1356352f7f91STakashi Iwai 1357352f7f91STakashi Iwai for (;;) { 1358352f7f91STakashi Iwai badness = fill_and_eval_dacs(codec, fill_hardwired, 1359352f7f91STakashi Iwai fill_mio_first); 1360352f7f91STakashi Iwai if (badness < 0) { 1361352f7f91STakashi Iwai kfree(best_cfg); 1362352f7f91STakashi Iwai return badness; 1363352f7f91STakashi Iwai } 1364352f7f91STakashi Iwai debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n", 1365352f7f91STakashi Iwai cfg->line_out_type, fill_hardwired, fill_mio_first, 1366352f7f91STakashi Iwai badness); 1367352f7f91STakashi Iwai debug_show_configs(spec, cfg); 1368352f7f91STakashi Iwai if (badness < best_badness) { 1369352f7f91STakashi Iwai best_badness = badness; 1370352f7f91STakashi Iwai *best_cfg = *cfg; 1371352f7f91STakashi Iwai best_wired = fill_hardwired; 1372352f7f91STakashi Iwai best_mio = fill_mio_first; 1373352f7f91STakashi Iwai } 1374352f7f91STakashi Iwai if (!badness) 1375352f7f91STakashi Iwai break; 1376352f7f91STakashi Iwai fill_mio_first = !fill_mio_first; 1377352f7f91STakashi Iwai if (!fill_mio_first) 1378352f7f91STakashi Iwai continue; 1379352f7f91STakashi Iwai fill_hardwired = !fill_hardwired; 1380352f7f91STakashi Iwai if (!fill_hardwired) 1381352f7f91STakashi Iwai continue; 1382352f7f91STakashi Iwai if (hp_spk_swapped) 1383352f7f91STakashi Iwai break; 1384352f7f91STakashi Iwai hp_spk_swapped = true; 1385352f7f91STakashi Iwai if (cfg->speaker_outs > 0 && 1386352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) { 1387352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs; 1388352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins, 1389352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 1390352f7f91STakashi Iwai cfg->line_outs = cfg->speaker_outs; 1391352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->speaker_pins, 1392352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 1393352f7f91STakashi Iwai cfg->speaker_outs = 0; 1394352f7f91STakashi Iwai memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); 1395352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; 1396352f7f91STakashi Iwai fill_hardwired = true; 1397352f7f91STakashi Iwai continue; 1398352f7f91STakashi Iwai } 1399352f7f91STakashi Iwai if (cfg->hp_outs > 0 && 1400352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { 1401352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 1402352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 1403352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 1404352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs; 1405352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins, 1406352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 1407352f7f91STakashi Iwai cfg->hp_outs = 0; 1408352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 1409352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT; 1410352f7f91STakashi Iwai fill_hardwired = true; 1411352f7f91STakashi Iwai continue; 1412352f7f91STakashi Iwai } 1413352f7f91STakashi Iwai break; 1414352f7f91STakashi Iwai } 1415352f7f91STakashi Iwai 1416352f7f91STakashi Iwai if (badness) { 14170c8c0f56STakashi Iwai debug_badness("==> restoring best_cfg\n"); 1418352f7f91STakashi Iwai *cfg = *best_cfg; 1419352f7f91STakashi Iwai fill_and_eval_dacs(codec, best_wired, best_mio); 1420352f7f91STakashi Iwai } 1421352f7f91STakashi Iwai debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n", 1422352f7f91STakashi Iwai cfg->line_out_type, best_wired, best_mio); 1423352f7f91STakashi Iwai debug_show_configs(spec, cfg); 1424352f7f91STakashi Iwai 1425352f7f91STakashi Iwai if (cfg->line_out_pins[0]) { 1426352f7f91STakashi Iwai struct nid_path *path; 1427196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]); 1428352f7f91STakashi Iwai if (path) 1429352f7f91STakashi Iwai spec->vmaster_nid = look_for_out_vol_nid(codec, path); 1430352f7f91STakashi Iwai } 1431352f7f91STakashi Iwai 1432352f7f91STakashi Iwai kfree(best_cfg); 1433352f7f91STakashi Iwai return 0; 1434352f7f91STakashi Iwai } 1435352f7f91STakashi Iwai 1436352f7f91STakashi Iwai /* add playback controls from the parsed DAC table */ 1437352f7f91STakashi Iwai static int create_multi_out_ctls(struct hda_codec *codec, 1438352f7f91STakashi Iwai const struct auto_pin_cfg *cfg) 1439352f7f91STakashi Iwai { 1440352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1441352f7f91STakashi Iwai int i, err, noutputs; 1442352f7f91STakashi Iwai 1443352f7f91STakashi Iwai noutputs = cfg->line_outs; 1444352f7f91STakashi Iwai if (spec->multi_ios > 0 && cfg->line_outs < 3) 1445352f7f91STakashi Iwai noutputs += spec->multi_ios; 1446352f7f91STakashi Iwai 1447352f7f91STakashi Iwai for (i = 0; i < noutputs; i++) { 1448352f7f91STakashi Iwai const char *name; 1449352f7f91STakashi Iwai int index; 1450196c1766STakashi Iwai hda_nid_t dac; 1451352f7f91STakashi Iwai struct nid_path *path; 1452352f7f91STakashi Iwai 1453352f7f91STakashi Iwai dac = spec->multiout.dac_nids[i]; 1454352f7f91STakashi Iwai if (!dac) 1455352f7f91STakashi Iwai continue; 1456352f7f91STakashi Iwai if (i >= cfg->line_outs) { 1457352f7f91STakashi Iwai index = 0; 1458352f7f91STakashi Iwai name = channel_name[i]; 1459352f7f91STakashi Iwai } else { 1460352f7f91STakashi Iwai name = get_line_out_pfx(spec, i, true, &index); 1461352f7f91STakashi Iwai } 1462352f7f91STakashi Iwai 1463196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]); 1464352f7f91STakashi Iwai if (!path) 1465352f7f91STakashi Iwai continue; 1466352f7f91STakashi Iwai if (!name || !strcmp(name, "CLFE")) { 1467352f7f91STakashi Iwai /* Center/LFE */ 1468352f7f91STakashi Iwai err = add_vol_ctl(codec, "Center", 0, 1, path); 1469352f7f91STakashi Iwai if (err < 0) 1470352f7f91STakashi Iwai return err; 1471352f7f91STakashi Iwai err = add_vol_ctl(codec, "LFE", 0, 2, path); 1472352f7f91STakashi Iwai if (err < 0) 1473352f7f91STakashi Iwai return err; 1474352f7f91STakashi Iwai err = add_sw_ctl(codec, "Center", 0, 1, path); 1475352f7f91STakashi Iwai if (err < 0) 1476352f7f91STakashi Iwai return err; 1477352f7f91STakashi Iwai err = add_sw_ctl(codec, "LFE", 0, 2, path); 1478352f7f91STakashi Iwai if (err < 0) 1479352f7f91STakashi Iwai return err; 1480352f7f91STakashi Iwai } else { 1481352f7f91STakashi Iwai err = add_stereo_vol(codec, name, index, path); 1482352f7f91STakashi Iwai if (err < 0) 1483352f7f91STakashi Iwai return err; 1484352f7f91STakashi Iwai err = add_stereo_sw(codec, name, index, path); 1485352f7f91STakashi Iwai if (err < 0) 1486352f7f91STakashi Iwai return err; 1487352f7f91STakashi Iwai } 1488352f7f91STakashi Iwai } 1489352f7f91STakashi Iwai return 0; 1490352f7f91STakashi Iwai } 1491352f7f91STakashi Iwai 1492352f7f91STakashi Iwai static int create_extra_out(struct hda_codec *codec, hda_nid_t pin, 1493196c1766STakashi Iwai hda_nid_t dac, int path_idx, 1494196c1766STakashi Iwai const char *pfx, int cidx) 1495352f7f91STakashi Iwai { 1496352f7f91STakashi Iwai struct nid_path *path; 1497352f7f91STakashi Iwai int err; 1498352f7f91STakashi Iwai 1499196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 1500352f7f91STakashi Iwai if (!path) 1501352f7f91STakashi Iwai return 0; 1502352f7f91STakashi Iwai /* bind volume control will be created in the case of dac = 0 */ 1503352f7f91STakashi Iwai if (dac) { 1504352f7f91STakashi Iwai err = add_stereo_vol(codec, pfx, cidx, path); 1505352f7f91STakashi Iwai if (err < 0) 1506352f7f91STakashi Iwai return err; 1507352f7f91STakashi Iwai } 1508352f7f91STakashi Iwai err = add_stereo_sw(codec, pfx, cidx, path); 1509352f7f91STakashi Iwai if (err < 0) 1510352f7f91STakashi Iwai return err; 1511352f7f91STakashi Iwai return 0; 1512352f7f91STakashi Iwai } 1513352f7f91STakashi Iwai 1514352f7f91STakashi Iwai /* add playback controls for speaker and HP outputs */ 1515352f7f91STakashi Iwai static int create_extra_outs(struct hda_codec *codec, int num_pins, 1516352f7f91STakashi Iwai const hda_nid_t *pins, const hda_nid_t *dacs, 1517196c1766STakashi Iwai const int *paths, const char *pfx) 1518352f7f91STakashi Iwai { 1519352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1520352f7f91STakashi Iwai struct hda_bind_ctls *ctl; 15215abd4888STakashi Iwai char name[44]; 1522352f7f91STakashi Iwai int i, n, err; 1523352f7f91STakashi Iwai 1524352f7f91STakashi Iwai if (!num_pins || !pins[0]) 1525352f7f91STakashi Iwai return 0; 1526352f7f91STakashi Iwai 1527352f7f91STakashi Iwai if (num_pins == 1) { 1528352f7f91STakashi Iwai hda_nid_t dac = *dacs; 1529352f7f91STakashi Iwai if (!dac) 1530352f7f91STakashi Iwai dac = spec->multiout.dac_nids[0]; 1531196c1766STakashi Iwai return create_extra_out(codec, *pins, dac, paths[0], pfx, 0); 1532352f7f91STakashi Iwai } 1533352f7f91STakashi Iwai 1534352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 1535352f7f91STakashi Iwai hda_nid_t dac; 1536352f7f91STakashi Iwai if (dacs[num_pins - 1]) 1537352f7f91STakashi Iwai dac = dacs[i]; /* with individual volumes */ 1538352f7f91STakashi Iwai else 1539352f7f91STakashi Iwai dac = 0; 1540352f7f91STakashi Iwai if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) { 1541196c1766STakashi Iwai err = create_extra_out(codec, pins[i], dac, paths[i], 1542352f7f91STakashi Iwai "Bass Speaker", 0); 1543352f7f91STakashi Iwai } else if (num_pins >= 3) { 1544352f7f91STakashi Iwai snprintf(name, sizeof(name), "%s %s", 1545352f7f91STakashi Iwai pfx, channel_name[i]); 1546196c1766STakashi Iwai err = create_extra_out(codec, pins[i], dac, paths[i], 1547196c1766STakashi Iwai name, 0); 1548352f7f91STakashi Iwai } else { 1549196c1766STakashi Iwai err = create_extra_out(codec, pins[i], dac, paths[i], 1550196c1766STakashi Iwai pfx, i); 1551352f7f91STakashi Iwai } 1552352f7f91STakashi Iwai if (err < 0) 1553352f7f91STakashi Iwai return err; 1554352f7f91STakashi Iwai } 1555352f7f91STakashi Iwai if (dacs[num_pins - 1]) 1556352f7f91STakashi Iwai return 0; 1557352f7f91STakashi Iwai 1558352f7f91STakashi Iwai /* Let's create a bind-controls for volumes */ 1559352f7f91STakashi Iwai ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_vol); 1560352f7f91STakashi Iwai if (!ctl) 1561352f7f91STakashi Iwai return -ENOMEM; 1562352f7f91STakashi Iwai n = 0; 1563352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 1564352f7f91STakashi Iwai hda_nid_t vol; 1565352f7f91STakashi Iwai struct nid_path *path; 1566352f7f91STakashi Iwai if (!pins[i] || !dacs[i]) 1567352f7f91STakashi Iwai continue; 1568196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, paths[i]); 1569352f7f91STakashi Iwai if (!path) 1570352f7f91STakashi Iwai continue; 1571352f7f91STakashi Iwai vol = look_for_out_vol_nid(codec, path); 1572352f7f91STakashi Iwai if (vol) 1573352f7f91STakashi Iwai ctl->values[n++] = 1574352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(vol, 3, 0, HDA_OUTPUT); 1575352f7f91STakashi Iwai } 1576352f7f91STakashi Iwai if (n) { 1577352f7f91STakashi Iwai snprintf(name, sizeof(name), "%s Playback Volume", pfx); 1578352f7f91STakashi Iwai err = add_control(spec, HDA_CTL_BIND_VOL, name, 0, (long)ctl); 1579352f7f91STakashi Iwai if (err < 0) 1580352f7f91STakashi Iwai return err; 1581352f7f91STakashi Iwai } 1582352f7f91STakashi Iwai return 0; 1583352f7f91STakashi Iwai } 1584352f7f91STakashi Iwai 1585352f7f91STakashi Iwai static int create_hp_out_ctls(struct hda_codec *codec) 1586352f7f91STakashi Iwai { 1587352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1588352f7f91STakashi Iwai return create_extra_outs(codec, spec->autocfg.hp_outs, 1589352f7f91STakashi Iwai spec->autocfg.hp_pins, 1590352f7f91STakashi Iwai spec->multiout.hp_out_nid, 1591196c1766STakashi Iwai spec->hp_paths, 1592352f7f91STakashi Iwai "Headphone"); 1593352f7f91STakashi Iwai } 1594352f7f91STakashi Iwai 1595352f7f91STakashi Iwai static int create_speaker_out_ctls(struct hda_codec *codec) 1596352f7f91STakashi Iwai { 1597352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1598352f7f91STakashi Iwai return create_extra_outs(codec, spec->autocfg.speaker_outs, 1599352f7f91STakashi Iwai spec->autocfg.speaker_pins, 1600352f7f91STakashi Iwai spec->multiout.extra_out_nid, 1601196c1766STakashi Iwai spec->speaker_paths, 1602352f7f91STakashi Iwai "Speaker"); 1603352f7f91STakashi Iwai } 1604352f7f91STakashi Iwai 1605352f7f91STakashi Iwai /* 160638cf6f1aSTakashi Iwai * independent HP controls 160738cf6f1aSTakashi Iwai */ 160838cf6f1aSTakashi Iwai 160938cf6f1aSTakashi Iwai static int indep_hp_info(struct snd_kcontrol *kcontrol, 161038cf6f1aSTakashi Iwai struct snd_ctl_elem_info *uinfo) 161138cf6f1aSTakashi Iwai { 161238cf6f1aSTakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo); 161338cf6f1aSTakashi Iwai } 161438cf6f1aSTakashi Iwai 161538cf6f1aSTakashi Iwai static int indep_hp_get(struct snd_kcontrol *kcontrol, 161638cf6f1aSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 161738cf6f1aSTakashi Iwai { 161838cf6f1aSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 161938cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 162038cf6f1aSTakashi Iwai ucontrol->value.enumerated.item[0] = spec->indep_hp_enabled; 162138cf6f1aSTakashi Iwai return 0; 162238cf6f1aSTakashi Iwai } 162338cf6f1aSTakashi Iwai 162438cf6f1aSTakashi Iwai static int indep_hp_put(struct snd_kcontrol *kcontrol, 162538cf6f1aSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 162638cf6f1aSTakashi Iwai { 162738cf6f1aSTakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 162838cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 162938cf6f1aSTakashi Iwai unsigned int select = ucontrol->value.enumerated.item[0]; 163038cf6f1aSTakashi Iwai int ret = 0; 163138cf6f1aSTakashi Iwai 163238cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 163338cf6f1aSTakashi Iwai if (spec->active_streams) { 163438cf6f1aSTakashi Iwai ret = -EBUSY; 163538cf6f1aSTakashi Iwai goto unlock; 163638cf6f1aSTakashi Iwai } 163738cf6f1aSTakashi Iwai 163838cf6f1aSTakashi Iwai if (spec->indep_hp_enabled != select) { 163938cf6f1aSTakashi Iwai spec->indep_hp_enabled = select; 164038cf6f1aSTakashi Iwai if (spec->indep_hp_enabled) 164138cf6f1aSTakashi Iwai spec->multiout.hp_out_nid[0] = 0; 164238cf6f1aSTakashi Iwai else 164338cf6f1aSTakashi Iwai spec->multiout.hp_out_nid[0] = spec->alt_dac_nid; 164438cf6f1aSTakashi Iwai ret = 1; 164538cf6f1aSTakashi Iwai } 164638cf6f1aSTakashi Iwai unlock: 164738cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 164838cf6f1aSTakashi Iwai return ret; 164938cf6f1aSTakashi Iwai } 165038cf6f1aSTakashi Iwai 165138cf6f1aSTakashi Iwai static const struct snd_kcontrol_new indep_hp_ctl = { 165238cf6f1aSTakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 165338cf6f1aSTakashi Iwai .name = "Independent HP", 165438cf6f1aSTakashi Iwai .info = indep_hp_info, 165538cf6f1aSTakashi Iwai .get = indep_hp_get, 165638cf6f1aSTakashi Iwai .put = indep_hp_put, 165738cf6f1aSTakashi Iwai }; 165838cf6f1aSTakashi Iwai 165938cf6f1aSTakashi Iwai 166038cf6f1aSTakashi Iwai static int create_indep_hp_ctls(struct hda_codec *codec) 166138cf6f1aSTakashi Iwai { 166238cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 166338cf6f1aSTakashi Iwai 166438cf6f1aSTakashi Iwai if (!spec->indep_hp) 166538cf6f1aSTakashi Iwai return 0; 166638cf6f1aSTakashi Iwai if (!spec->multiout.hp_out_nid[0]) { 166738cf6f1aSTakashi Iwai spec->indep_hp = 0; 166838cf6f1aSTakashi Iwai return 0; 166938cf6f1aSTakashi Iwai } 167038cf6f1aSTakashi Iwai 167138cf6f1aSTakashi Iwai spec->indep_hp_enabled = false; 167238cf6f1aSTakashi Iwai spec->alt_dac_nid = spec->multiout.hp_out_nid[0]; 167338cf6f1aSTakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl)) 167438cf6f1aSTakashi Iwai return -ENOMEM; 167538cf6f1aSTakashi Iwai return 0; 167638cf6f1aSTakashi Iwai } 167738cf6f1aSTakashi Iwai 167838cf6f1aSTakashi Iwai /* 1679352f7f91STakashi Iwai * channel mode enum control 1680352f7f91STakashi Iwai */ 1681352f7f91STakashi Iwai 1682352f7f91STakashi Iwai static int ch_mode_info(struct snd_kcontrol *kcontrol, 1683352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 1684352f7f91STakashi Iwai { 1685352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1686352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1687352f7f91STakashi Iwai 1688352f7f91STakashi Iwai uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 1689352f7f91STakashi Iwai uinfo->count = 1; 1690352f7f91STakashi Iwai uinfo->value.enumerated.items = spec->multi_ios + 1; 1691352f7f91STakashi Iwai if (uinfo->value.enumerated.item > spec->multi_ios) 1692352f7f91STakashi Iwai uinfo->value.enumerated.item = spec->multi_ios; 1693352f7f91STakashi Iwai sprintf(uinfo->value.enumerated.name, "%dch", 1694352f7f91STakashi Iwai (uinfo->value.enumerated.item + 1) * 2); 1695352f7f91STakashi Iwai return 0; 1696352f7f91STakashi Iwai } 1697352f7f91STakashi Iwai 1698352f7f91STakashi Iwai static int ch_mode_get(struct snd_kcontrol *kcontrol, 1699352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1700352f7f91STakashi Iwai { 1701352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1702352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1703352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2; 1704352f7f91STakashi Iwai return 0; 1705352f7f91STakashi Iwai } 1706352f7f91STakashi Iwai 1707196c1766STakashi Iwai static inline struct nid_path * 1708196c1766STakashi Iwai get_multiio_path(struct hda_codec *codec, int idx) 1709196c1766STakashi Iwai { 1710196c1766STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1711196c1766STakashi Iwai return snd_hda_get_path_from_idx(codec, 1712196c1766STakashi Iwai spec->out_paths[spec->autocfg.line_outs + idx]); 1713196c1766STakashi Iwai } 1714196c1766STakashi Iwai 1715352f7f91STakashi Iwai static int set_multi_io(struct hda_codec *codec, int idx, bool output) 1716352f7f91STakashi Iwai { 1717352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1718352f7f91STakashi Iwai hda_nid_t nid = spec->multi_io[idx].pin; 1719352f7f91STakashi Iwai struct nid_path *path; 1720352f7f91STakashi Iwai 1721196c1766STakashi Iwai path = get_multiio_path(codec, idx); 1722352f7f91STakashi Iwai if (!path) 1723352f7f91STakashi Iwai return -EINVAL; 1724352f7f91STakashi Iwai 1725352f7f91STakashi Iwai if (path->active == output) 1726352f7f91STakashi Iwai return 0; 1727352f7f91STakashi Iwai 1728352f7f91STakashi Iwai if (output) { 1729352f7f91STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, PIN_OUT); 1730352f7f91STakashi Iwai snd_hda_activate_path(codec, path, true, true); 1731d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, true); 1732352f7f91STakashi Iwai } else { 1733d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, false); 1734352f7f91STakashi Iwai snd_hda_activate_path(codec, path, false, true); 1735352f7f91STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, 1736352f7f91STakashi Iwai spec->multi_io[idx].ctl_in); 1737352f7f91STakashi Iwai } 1738352f7f91STakashi Iwai return 0; 1739352f7f91STakashi Iwai } 1740352f7f91STakashi Iwai 1741352f7f91STakashi Iwai static int ch_mode_put(struct snd_kcontrol *kcontrol, 1742352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1743352f7f91STakashi Iwai { 1744352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1745352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1746352f7f91STakashi Iwai int i, ch; 1747352f7f91STakashi Iwai 1748352f7f91STakashi Iwai ch = ucontrol->value.enumerated.item[0]; 1749352f7f91STakashi Iwai if (ch < 0 || ch > spec->multi_ios) 1750352f7f91STakashi Iwai return -EINVAL; 1751352f7f91STakashi Iwai if (ch == (spec->ext_channel_count - 1) / 2) 1752352f7f91STakashi Iwai return 0; 1753352f7f91STakashi Iwai spec->ext_channel_count = (ch + 1) * 2; 1754352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++) 1755352f7f91STakashi Iwai set_multi_io(codec, i, i < ch); 1756352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count, 1757352f7f91STakashi Iwai spec->const_channel_count); 1758352f7f91STakashi Iwai if (spec->need_dac_fix) 1759352f7f91STakashi Iwai spec->multiout.num_dacs = spec->multiout.max_channels / 2; 1760352f7f91STakashi Iwai return 1; 1761352f7f91STakashi Iwai } 1762352f7f91STakashi Iwai 1763352f7f91STakashi Iwai static const struct snd_kcontrol_new channel_mode_enum = { 1764352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1765352f7f91STakashi Iwai .name = "Channel Mode", 1766352f7f91STakashi Iwai .info = ch_mode_info, 1767352f7f91STakashi Iwai .get = ch_mode_get, 1768352f7f91STakashi Iwai .put = ch_mode_put, 1769352f7f91STakashi Iwai }; 1770352f7f91STakashi Iwai 1771352f7f91STakashi Iwai static int create_multi_channel_mode(struct hda_codec *codec) 1772352f7f91STakashi Iwai { 1773352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1774352f7f91STakashi Iwai 1775352f7f91STakashi Iwai if (spec->multi_ios > 0) { 177612c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &channel_mode_enum)) 1777352f7f91STakashi Iwai return -ENOMEM; 1778352f7f91STakashi Iwai } 1779352f7f91STakashi Iwai return 0; 1780352f7f91STakashi Iwai } 1781352f7f91STakashi Iwai 1782352f7f91STakashi Iwai /* 1783c30aa7b2STakashi Iwai * aamix loopback enable/disable switch 1784c30aa7b2STakashi Iwai */ 1785c30aa7b2STakashi Iwai 1786c30aa7b2STakashi Iwai #define loopback_mixing_info indep_hp_info 1787c30aa7b2STakashi Iwai 1788c30aa7b2STakashi Iwai static int loopback_mixing_get(struct snd_kcontrol *kcontrol, 1789c30aa7b2STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1790c30aa7b2STakashi Iwai { 1791c30aa7b2STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1792c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1793c30aa7b2STakashi Iwai ucontrol->value.enumerated.item[0] = spec->aamix_mode; 1794c30aa7b2STakashi Iwai return 0; 1795c30aa7b2STakashi Iwai } 1796c30aa7b2STakashi Iwai 1797c30aa7b2STakashi Iwai static void update_aamix_paths(struct hda_codec *codec, bool do_mix, 1798c30aa7b2STakashi Iwai int nomix_path_idx, int mix_path_idx) 1799c30aa7b2STakashi Iwai { 1800c30aa7b2STakashi Iwai struct nid_path *nomix_path, *mix_path; 1801c30aa7b2STakashi Iwai 1802c30aa7b2STakashi Iwai nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx); 1803c30aa7b2STakashi Iwai mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx); 1804c30aa7b2STakashi Iwai if (!nomix_path || !mix_path) 1805c30aa7b2STakashi Iwai return; 1806c30aa7b2STakashi Iwai if (do_mix) { 1807c30aa7b2STakashi Iwai snd_hda_activate_path(codec, nomix_path, false, true); 1808c30aa7b2STakashi Iwai snd_hda_activate_path(codec, mix_path, true, true); 1809c30aa7b2STakashi Iwai } else { 1810c30aa7b2STakashi Iwai snd_hda_activate_path(codec, mix_path, false, true); 1811c30aa7b2STakashi Iwai snd_hda_activate_path(codec, nomix_path, true, true); 1812c30aa7b2STakashi Iwai } 1813c30aa7b2STakashi Iwai } 1814c30aa7b2STakashi Iwai 1815c30aa7b2STakashi Iwai static int loopback_mixing_put(struct snd_kcontrol *kcontrol, 1816c30aa7b2STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1817c30aa7b2STakashi Iwai { 1818c30aa7b2STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1819c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1820c30aa7b2STakashi Iwai unsigned int val = ucontrol->value.enumerated.item[0]; 1821c30aa7b2STakashi Iwai 1822c30aa7b2STakashi Iwai if (val == spec->aamix_mode) 1823c30aa7b2STakashi Iwai return 0; 1824c30aa7b2STakashi Iwai spec->aamix_mode = val; 1825c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->out_paths[0], 1826c30aa7b2STakashi Iwai spec->aamix_out_paths[0]); 1827c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->hp_paths[0], 1828c30aa7b2STakashi Iwai spec->aamix_out_paths[1]); 1829c30aa7b2STakashi Iwai update_aamix_paths(codec, val, spec->speaker_paths[0], 1830c30aa7b2STakashi Iwai spec->aamix_out_paths[2]); 1831c30aa7b2STakashi Iwai return 1; 1832c30aa7b2STakashi Iwai } 1833c30aa7b2STakashi Iwai 1834c30aa7b2STakashi Iwai static const struct snd_kcontrol_new loopback_mixing_enum = { 1835c30aa7b2STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1836c30aa7b2STakashi Iwai .name = "Loopback Mixing", 1837c30aa7b2STakashi Iwai .info = loopback_mixing_info, 1838c30aa7b2STakashi Iwai .get = loopback_mixing_get, 1839c30aa7b2STakashi Iwai .put = loopback_mixing_put, 1840c30aa7b2STakashi Iwai }; 1841c30aa7b2STakashi Iwai 1842c30aa7b2STakashi Iwai static int create_loopback_mixing_ctl(struct hda_codec *codec) 1843c30aa7b2STakashi Iwai { 1844c30aa7b2STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1845c30aa7b2STakashi Iwai 1846c30aa7b2STakashi Iwai if (!spec->mixer_nid) 1847c30aa7b2STakashi Iwai return 0; 1848c30aa7b2STakashi Iwai if (!(spec->aamix_out_paths[0] || spec->aamix_out_paths[1] || 1849c30aa7b2STakashi Iwai spec->aamix_out_paths[2])) 1850c30aa7b2STakashi Iwai return 0; 1851c30aa7b2STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum)) 1852c30aa7b2STakashi Iwai return -ENOMEM; 1853c30aa7b2STakashi Iwai return 0; 1854c30aa7b2STakashi Iwai } 1855c30aa7b2STakashi Iwai 1856c30aa7b2STakashi Iwai /* 1857352f7f91STakashi Iwai * shared headphone/mic handling 1858352f7f91STakashi Iwai */ 1859352f7f91STakashi Iwai 1860352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec); 1861352f7f91STakashi Iwai 1862352f7f91STakashi Iwai /* for shared I/O, change the pin-control accordingly */ 1863352f7f91STakashi Iwai static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic) 1864352f7f91STakashi Iwai { 1865352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1866352f7f91STakashi Iwai unsigned int val; 1867352f7f91STakashi Iwai hda_nid_t pin = spec->autocfg.inputs[1].pin; 1868352f7f91STakashi Iwai /* NOTE: this assumes that there are only two inputs, the 1869352f7f91STakashi Iwai * first is the real internal mic and the second is HP/mic jack. 1870352f7f91STakashi Iwai */ 1871352f7f91STakashi Iwai 1872352f7f91STakashi Iwai val = snd_hda_get_default_vref(codec, pin); 1873352f7f91STakashi Iwai 1874352f7f91STakashi Iwai /* This pin does not have vref caps - let's enable vref on pin 0x18 1875352f7f91STakashi Iwai instead, as suggested by Realtek */ 1876352f7f91STakashi Iwai if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) { 1877352f7f91STakashi Iwai const hda_nid_t vref_pin = spec->shared_mic_vref_pin; 1878352f7f91STakashi Iwai unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin); 1879352f7f91STakashi Iwai if (vref_val != AC_PINCTL_VREF_HIZ) 18807594aa33STakashi Iwai snd_hda_set_pin_ctl_cache(codec, vref_pin, 18817594aa33STakashi Iwai PIN_IN | (set_as_mic ? vref_val : 0)); 1882352f7f91STakashi Iwai } 1883352f7f91STakashi Iwai 1884352f7f91STakashi Iwai val = set_as_mic ? val | PIN_IN : PIN_HP; 18857594aa33STakashi Iwai snd_hda_set_pin_ctl_cache(codec, pin, val); 1886352f7f91STakashi Iwai 1887352f7f91STakashi Iwai spec->automute_speaker = !set_as_mic; 1888352f7f91STakashi Iwai call_update_outputs(codec); 1889352f7f91STakashi Iwai } 1890352f7f91STakashi Iwai 1891352f7f91STakashi Iwai /* create a shared input with the headphone out */ 1892352f7f91STakashi Iwai static int create_shared_input(struct hda_codec *codec) 1893352f7f91STakashi Iwai { 1894352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1895352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 1896352f7f91STakashi Iwai unsigned int defcfg; 1897352f7f91STakashi Iwai hda_nid_t nid; 1898352f7f91STakashi Iwai 1899352f7f91STakashi Iwai /* only one internal input pin? */ 1900352f7f91STakashi Iwai if (cfg->num_inputs != 1) 1901352f7f91STakashi Iwai return 0; 1902352f7f91STakashi Iwai defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); 1903352f7f91STakashi Iwai if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) 1904352f7f91STakashi Iwai return 0; 1905352f7f91STakashi Iwai 1906352f7f91STakashi Iwai if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) 1907352f7f91STakashi Iwai nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */ 1908352f7f91STakashi Iwai else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT) 1909352f7f91STakashi Iwai nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */ 1910352f7f91STakashi Iwai else 1911352f7f91STakashi Iwai return 0; /* both not available */ 1912352f7f91STakashi Iwai 1913352f7f91STakashi Iwai if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN)) 1914352f7f91STakashi Iwai return 0; /* no input */ 1915352f7f91STakashi Iwai 1916352f7f91STakashi Iwai cfg->inputs[1].pin = nid; 1917352f7f91STakashi Iwai cfg->inputs[1].type = AUTO_PIN_MIC; 1918352f7f91STakashi Iwai cfg->num_inputs = 2; 1919352f7f91STakashi Iwai spec->shared_mic_hp = 1; 1920352f7f91STakashi Iwai snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid); 1921352f7f91STakashi Iwai return 0; 1922352f7f91STakashi Iwai } 1923352f7f91STakashi Iwai 1924352f7f91STakashi Iwai 1925352f7f91STakashi Iwai /* 1926352f7f91STakashi Iwai * Parse input paths 1927352f7f91STakashi Iwai */ 1928352f7f91STakashi Iwai 1929352f7f91STakashi Iwai #ifdef CONFIG_PM 1930352f7f91STakashi Iwai /* add the powersave loopback-list entry */ 1931352f7f91STakashi Iwai static void add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx) 1932352f7f91STakashi Iwai { 1933352f7f91STakashi Iwai struct hda_amp_list *list; 1934352f7f91STakashi Iwai 1935352f7f91STakashi Iwai if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1) 1936352f7f91STakashi Iwai return; 1937352f7f91STakashi Iwai list = spec->loopback_list + spec->num_loopbacks; 1938352f7f91STakashi Iwai list->nid = mix; 1939352f7f91STakashi Iwai list->dir = HDA_INPUT; 1940352f7f91STakashi Iwai list->idx = idx; 1941352f7f91STakashi Iwai spec->num_loopbacks++; 1942cb53c626STakashi Iwai spec->loopback.amplist = spec->loopback_list; 1943cb53c626STakashi Iwai } 1944cb53c626STakashi Iwai #else 1945352f7f91STakashi Iwai #define add_loopback_list(spec, mix, idx) /* NOP */ 1946cb53c626STakashi Iwai #endif 1947cb53c626STakashi Iwai 1948352f7f91STakashi Iwai /* create input playback/capture controls for the given pin */ 1949196c1766STakashi Iwai static int new_analog_input(struct hda_codec *codec, int input_idx, 1950196c1766STakashi Iwai hda_nid_t pin, const char *ctlname, int ctlidx, 1951352f7f91STakashi Iwai hda_nid_t mix_nid) 19521da177e4SLinus Torvalds { 1953352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 1954352f7f91STakashi Iwai struct nid_path *path; 1955352f7f91STakashi Iwai unsigned int val; 1956352f7f91STakashi Iwai int err, idx; 19571da177e4SLinus Torvalds 1958352f7f91STakashi Iwai if (!nid_has_volume(codec, mix_nid, HDA_INPUT) && 1959352f7f91STakashi Iwai !nid_has_mute(codec, mix_nid, HDA_INPUT)) 1960352f7f91STakashi Iwai return 0; /* no need for analog loopback */ 1961352f7f91STakashi Iwai 19624ac0eefaSTakashi Iwai path = snd_hda_add_new_path(codec, pin, mix_nid, HDA_PARSE_ALL); 1963352f7f91STakashi Iwai if (!path) 1964352f7f91STakashi Iwai return -EINVAL; 19650c8c0f56STakashi Iwai print_nid_path("loopback", path); 1966196c1766STakashi Iwai spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path); 1967352f7f91STakashi Iwai 1968352f7f91STakashi Iwai idx = path->idx[path->depth - 1]; 1969352f7f91STakashi Iwai if (nid_has_volume(codec, mix_nid, HDA_INPUT)) { 1970352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); 1971352f7f91STakashi Iwai err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, val); 1972d13bd412STakashi Iwai if (err < 0) 19731da177e4SLinus Torvalds return err; 1974352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = val; 19751da177e4SLinus Torvalds } 19761da177e4SLinus Torvalds 1977352f7f91STakashi Iwai if (nid_has_mute(codec, mix_nid, HDA_INPUT)) { 1978352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); 1979352f7f91STakashi Iwai err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, val); 1980d13bd412STakashi Iwai if (err < 0) 19811da177e4SLinus Torvalds return err; 1982352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = val; 19831da177e4SLinus Torvalds } 19841da177e4SLinus Torvalds 1985352f7f91STakashi Iwai path->active = true; 1986352f7f91STakashi Iwai add_loopback_list(spec, mix_nid, idx); 1987352f7f91STakashi Iwai return 0; 19881da177e4SLinus Torvalds } 19891da177e4SLinus Torvalds 1990352f7f91STakashi Iwai static int is_input_pin(struct hda_codec *codec, hda_nid_t nid) 19911da177e4SLinus Torvalds { 1992352f7f91STakashi Iwai unsigned int pincap = snd_hda_query_pin_caps(codec, nid); 1993352f7f91STakashi Iwai return (pincap & AC_PINCAP_IN) != 0; 1994352f7f91STakashi Iwai } 1995352f7f91STakashi Iwai 1996352f7f91STakashi Iwai /* Parse the codec tree and retrieve ADCs */ 1997352f7f91STakashi Iwai static int fill_adc_nids(struct hda_codec *codec) 1998352f7f91STakashi Iwai { 1999352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2000352f7f91STakashi Iwai hda_nid_t nid; 2001352f7f91STakashi Iwai hda_nid_t *adc_nids = spec->adc_nids; 2002352f7f91STakashi Iwai int max_nums = ARRAY_SIZE(spec->adc_nids); 2003352f7f91STakashi Iwai int i, nums = 0; 2004352f7f91STakashi Iwai 2005352f7f91STakashi Iwai nid = codec->start_nid; 2006352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, nid++) { 2007352f7f91STakashi Iwai unsigned int caps = get_wcaps(codec, nid); 2008352f7f91STakashi Iwai int type = get_wcaps_type(caps); 2009352f7f91STakashi Iwai 2010352f7f91STakashi Iwai if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL)) 2011352f7f91STakashi Iwai continue; 2012352f7f91STakashi Iwai adc_nids[nums] = nid; 2013352f7f91STakashi Iwai if (++nums >= max_nums) 2014352f7f91STakashi Iwai break; 2015352f7f91STakashi Iwai } 2016352f7f91STakashi Iwai spec->num_adc_nids = nums; 2017352f7f91STakashi Iwai return nums; 2018352f7f91STakashi Iwai } 2019352f7f91STakashi Iwai 2020352f7f91STakashi Iwai /* filter out invalid adc_nids that don't give all active input pins; 2021352f7f91STakashi Iwai * if needed, check whether dynamic ADC-switching is available 2022352f7f91STakashi Iwai */ 2023352f7f91STakashi Iwai static int check_dyn_adc_switch(struct hda_codec *codec) 2024352f7f91STakashi Iwai { 2025352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2026352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 2027352f7f91STakashi Iwai hda_nid_t adc_nids[ARRAY_SIZE(spec->adc_nids)]; 2028352f7f91STakashi Iwai int i, n, nums; 2029352f7f91STakashi Iwai hda_nid_t pin, adc; 2030352f7f91STakashi Iwai 2031352f7f91STakashi Iwai again: 2032352f7f91STakashi Iwai nums = 0; 2033352f7f91STakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 2034352f7f91STakashi Iwai adc = spec->adc_nids[n]; 2035352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2036352f7f91STakashi Iwai pin = spec->imux_pins[i]; 2037352f7f91STakashi Iwai if (!is_reachable_path(codec, pin, adc)) 2038352f7f91STakashi Iwai break; 2039352f7f91STakashi Iwai } 2040352f7f91STakashi Iwai if (i >= imux->num_items) 2041352f7f91STakashi Iwai adc_nids[nums++] = adc; 2042352f7f91STakashi Iwai } 2043352f7f91STakashi Iwai 2044352f7f91STakashi Iwai if (!nums) { 2045352f7f91STakashi Iwai if (spec->shared_mic_hp) { 2046352f7f91STakashi Iwai spec->shared_mic_hp = 0; 2047352f7f91STakashi Iwai imux->num_items = 1; 2048352f7f91STakashi Iwai goto again; 2049352f7f91STakashi Iwai } 2050352f7f91STakashi Iwai 2051352f7f91STakashi Iwai /* check whether ADC-switch is possible */ 2052352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2053352f7f91STakashi Iwai pin = spec->imux_pins[i]; 2054352f7f91STakashi Iwai for (n = 0; n < spec->num_adc_nids; n++) { 2055352f7f91STakashi Iwai adc = spec->adc_nids[n]; 2056352f7f91STakashi Iwai if (is_reachable_path(codec, pin, adc)) { 2057352f7f91STakashi Iwai spec->dyn_adc_idx[i] = n; 2058352f7f91STakashi Iwai break; 2059352f7f91STakashi Iwai } 2060352f7f91STakashi Iwai } 2061352f7f91STakashi Iwai } 2062352f7f91STakashi Iwai 2063352f7f91STakashi Iwai snd_printdd("hda-codec: enabling ADC switching\n"); 2064352f7f91STakashi Iwai spec->dyn_adc_switch = 1; 2065352f7f91STakashi Iwai } else if (nums != spec->num_adc_nids) { 2066352f7f91STakashi Iwai memcpy(spec->adc_nids, adc_nids, nums * sizeof(hda_nid_t)); 2067352f7f91STakashi Iwai spec->num_adc_nids = nums; 2068352f7f91STakashi Iwai } 2069352f7f91STakashi Iwai 2070352f7f91STakashi Iwai if (imux->num_items == 1 || spec->shared_mic_hp) { 2071352f7f91STakashi Iwai snd_printdd("hda-codec: reducing to a single ADC\n"); 2072352f7f91STakashi Iwai spec->num_adc_nids = 1; /* reduce to a single ADC */ 2073352f7f91STakashi Iwai } 2074352f7f91STakashi Iwai 2075352f7f91STakashi Iwai /* single index for individual volumes ctls */ 2076352f7f91STakashi Iwai if (!spec->dyn_adc_switch && spec->multi_cap_vol) 2077352f7f91STakashi Iwai spec->num_adc_nids = 1; 2078352f7f91STakashi Iwai 20791da177e4SLinus Torvalds return 0; 20801da177e4SLinus Torvalds } 20811da177e4SLinus Torvalds 20821da177e4SLinus Torvalds /* 2083352f7f91STakashi Iwai * create playback/capture controls for input pins 20841da177e4SLinus Torvalds */ 2085352f7f91STakashi Iwai static int create_input_ctls(struct hda_codec *codec) 2086a7da6ce5STakashi Iwai { 2087352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2088352f7f91STakashi Iwai const struct auto_pin_cfg *cfg = &spec->autocfg; 2089352f7f91STakashi Iwai hda_nid_t mixer = spec->mixer_nid; 2090352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 2091352f7f91STakashi Iwai int num_adcs; 2092352f7f91STakashi Iwai int i, c, err, type_idx = 0; 2093352f7f91STakashi Iwai const char *prev_label = NULL; 2094a7da6ce5STakashi Iwai 2095352f7f91STakashi Iwai num_adcs = fill_adc_nids(codec); 2096352f7f91STakashi Iwai if (num_adcs < 0) 2097352f7f91STakashi Iwai return 0; 2098352f7f91STakashi Iwai 2099352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 2100352f7f91STakashi Iwai hda_nid_t pin; 2101352f7f91STakashi Iwai const char *label; 2102352f7f91STakashi Iwai bool imux_added; 2103352f7f91STakashi Iwai 2104352f7f91STakashi Iwai pin = cfg->inputs[i].pin; 2105352f7f91STakashi Iwai if (!is_input_pin(codec, pin)) 2106352f7f91STakashi Iwai continue; 2107352f7f91STakashi Iwai 2108352f7f91STakashi Iwai label = hda_get_autocfg_input_label(codec, cfg, i); 2109352f7f91STakashi Iwai if (spec->shared_mic_hp && !strcmp(label, "Misc")) 2110352f7f91STakashi Iwai label = "Headphone Mic"; 2111352f7f91STakashi Iwai if (prev_label && !strcmp(label, prev_label)) 2112352f7f91STakashi Iwai type_idx++; 2113352f7f91STakashi Iwai else 2114352f7f91STakashi Iwai type_idx = 0; 2115352f7f91STakashi Iwai prev_label = label; 2116352f7f91STakashi Iwai 2117352f7f91STakashi Iwai if (mixer) { 2118352f7f91STakashi Iwai if (is_reachable_path(codec, pin, mixer)) { 2119196c1766STakashi Iwai err = new_analog_input(codec, i, pin, 2120352f7f91STakashi Iwai label, type_idx, mixer); 2121a7da6ce5STakashi Iwai if (err < 0) 2122a7da6ce5STakashi Iwai return err; 2123a7da6ce5STakashi Iwai } 2124352f7f91STakashi Iwai } 2125352f7f91STakashi Iwai 2126352f7f91STakashi Iwai imux_added = false; 2127352f7f91STakashi Iwai for (c = 0; c < num_adcs; c++) { 2128352f7f91STakashi Iwai struct nid_path *path; 2129352f7f91STakashi Iwai hda_nid_t adc = spec->adc_nids[c]; 2130352f7f91STakashi Iwai 2131352f7f91STakashi Iwai if (!is_reachable_path(codec, pin, adc)) 2132352f7f91STakashi Iwai continue; 2133352f7f91STakashi Iwai path = snd_array_new(&spec->paths); 2134352f7f91STakashi Iwai if (!path) 2135352f7f91STakashi Iwai return -ENOMEM; 2136352f7f91STakashi Iwai memset(path, 0, sizeof(*path)); 21374ac0eefaSTakashi Iwai if (!snd_hda_parse_nid_path(codec, pin, adc, HDA_PARSE_ALL, path)) { 2138352f7f91STakashi Iwai snd_printd(KERN_ERR 2139352f7f91STakashi Iwai "invalid input path 0x%x -> 0x%x\n", 2140352f7f91STakashi Iwai pin, adc); 2141352f7f91STakashi Iwai spec->paths.used--; 2142352f7f91STakashi Iwai continue; 2143352f7f91STakashi Iwai } 21440c8c0f56STakashi Iwai print_nid_path("input", path); 2145352f7f91STakashi Iwai 2146352f7f91STakashi Iwai if (!imux_added) { 2147352f7f91STakashi Iwai spec->imux_pins[imux->num_items] = pin; 2148352f7f91STakashi Iwai snd_hda_add_imux_item(imux, label, 2149352f7f91STakashi Iwai imux->num_items, NULL); 2150352f7f91STakashi Iwai imux_added = true; 2151352f7f91STakashi Iwai } 2152352f7f91STakashi Iwai } 2153352f7f91STakashi Iwai } 2154352f7f91STakashi Iwai 2155a7da6ce5STakashi Iwai return 0; 2156a7da6ce5STakashi Iwai } 2157a7da6ce5STakashi Iwai 21581da177e4SLinus Torvalds 2159352f7f91STakashi Iwai /* 2160352f7f91STakashi Iwai * input source mux 2161352f7f91STakashi Iwai */ 2162352f7f91STakashi Iwai 2163352f7f91STakashi Iwai /* get the ADC NID corresponding to the given index */ 2164352f7f91STakashi Iwai static hda_nid_t get_adc_nid(struct hda_codec *codec, int adc_idx, int imux_idx) 2165352f7f91STakashi Iwai { 2166352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2167352f7f91STakashi Iwai if (spec->dyn_adc_switch) 2168352f7f91STakashi Iwai adc_idx = spec->dyn_adc_idx[imux_idx]; 2169352f7f91STakashi Iwai return spec->adc_nids[adc_idx]; 217097ec558aSTakashi Iwai } 2171352f7f91STakashi Iwai 2172352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx, 2173352f7f91STakashi Iwai unsigned int idx); 2174352f7f91STakashi Iwai 2175352f7f91STakashi Iwai static int mux_enum_info(struct snd_kcontrol *kcontrol, 2176352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 2177352f7f91STakashi Iwai { 2178352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2179352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2180352f7f91STakashi Iwai return snd_hda_input_mux_info(&spec->input_mux, uinfo); 2181352f7f91STakashi Iwai } 2182352f7f91STakashi Iwai 2183352f7f91STakashi Iwai static int mux_enum_get(struct snd_kcontrol *kcontrol, 2184352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2185352f7f91STakashi Iwai { 2186352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2187352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2188352f7f91STakashi Iwai unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 2189352f7f91STakashi Iwai 2190352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; 21911da177e4SLinus Torvalds return 0; 21921da177e4SLinus Torvalds } 21931da177e4SLinus Torvalds 2194352f7f91STakashi Iwai static int mux_enum_put(struct snd_kcontrol *kcontrol, 2195352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 21961da177e4SLinus Torvalds { 2197352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2198352f7f91STakashi Iwai unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 2199352f7f91STakashi Iwai return mux_select(codec, adc_idx, 2200352f7f91STakashi Iwai ucontrol->value.enumerated.item[0]); 2201352f7f91STakashi Iwai } 2202352f7f91STakashi Iwai 2203352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_src_temp = { 22041da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2205352f7f91STakashi Iwai .name = "Input Source", 2206352f7f91STakashi Iwai .info = mux_enum_info, 2207352f7f91STakashi Iwai .get = mux_enum_get, 2208352f7f91STakashi Iwai .put = mux_enum_put, 22091da177e4SLinus Torvalds }; 2210071c73adSTakashi Iwai 221147d46abbSTakashi Iwai /* 221247d46abbSTakashi Iwai * capture volume and capture switch ctls 221347d46abbSTakashi Iwai */ 221447d46abbSTakashi Iwai 2215352f7f91STakashi Iwai typedef int (*put_call_t)(struct snd_kcontrol *kcontrol, 2216352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol); 2217071c73adSTakashi Iwai 221847d46abbSTakashi Iwai /* call the given amp update function for all amps in the imux list at once */ 2219352f7f91STakashi Iwai static int cap_put_caller(struct snd_kcontrol *kcontrol, 2220352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol, 2221352f7f91STakashi Iwai put_call_t func, int type) 2222352f7f91STakashi Iwai { 2223352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2224352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2225352f7f91STakashi Iwai const struct hda_input_mux *imux; 2226352f7f91STakashi Iwai struct nid_path *path; 2227352f7f91STakashi Iwai int i, adc_idx, err = 0; 2228071c73adSTakashi Iwai 2229352f7f91STakashi Iwai imux = &spec->input_mux; 2230352f7f91STakashi Iwai adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 2231352f7f91STakashi Iwai mutex_lock(&codec->control_mutex); 223247d46abbSTakashi Iwai /* we use the cache-only update at first since multiple input paths 223347d46abbSTakashi Iwai * may shared the same amp; by updating only caches, the redundant 223447d46abbSTakashi Iwai * writes to hardware can be reduced. 223547d46abbSTakashi Iwai */ 2236352f7f91STakashi Iwai codec->cached_write = 1; 2237352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2238352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, spec->imux_pins[i], 2239352f7f91STakashi Iwai get_adc_nid(codec, adc_idx, i)); 2240352f7f91STakashi Iwai if (!path->ctls[type]) 2241352f7f91STakashi Iwai continue; 2242352f7f91STakashi Iwai kcontrol->private_value = path->ctls[type]; 2243352f7f91STakashi Iwai err = func(kcontrol, ucontrol); 2244352f7f91STakashi Iwai if (err < 0) 2245352f7f91STakashi Iwai goto error; 2246352f7f91STakashi Iwai } 2247352f7f91STakashi Iwai error: 2248352f7f91STakashi Iwai codec->cached_write = 0; 2249352f7f91STakashi Iwai mutex_unlock(&codec->control_mutex); 225047d46abbSTakashi Iwai snd_hda_codec_flush_amp_cache(codec); /* flush the updates */ 2251352f7f91STakashi Iwai if (err >= 0 && spec->cap_sync_hook) 2252352f7f91STakashi Iwai spec->cap_sync_hook(codec); 2253352f7f91STakashi Iwai return err; 2254352f7f91STakashi Iwai } 2255352f7f91STakashi Iwai 2256352f7f91STakashi Iwai /* capture volume ctl callbacks */ 2257352f7f91STakashi Iwai #define cap_vol_info snd_hda_mixer_amp_volume_info 2258352f7f91STakashi Iwai #define cap_vol_get snd_hda_mixer_amp_volume_get 2259352f7f91STakashi Iwai #define cap_vol_tlv snd_hda_mixer_amp_tlv 2260352f7f91STakashi Iwai 2261352f7f91STakashi Iwai static int cap_vol_put(struct snd_kcontrol *kcontrol, 2262352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2263352f7f91STakashi Iwai { 2264352f7f91STakashi Iwai return cap_put_caller(kcontrol, ucontrol, 2265352f7f91STakashi Iwai snd_hda_mixer_amp_volume_put, 2266352f7f91STakashi Iwai NID_PATH_VOL_CTL); 2267352f7f91STakashi Iwai } 2268352f7f91STakashi Iwai 2269352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_vol_temp = { 2270352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2271352f7f91STakashi Iwai .name = "Capture Volume", 2272352f7f91STakashi Iwai .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 2273352f7f91STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ | 2274352f7f91STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), 2275352f7f91STakashi Iwai .info = cap_vol_info, 2276352f7f91STakashi Iwai .get = cap_vol_get, 2277352f7f91STakashi Iwai .put = cap_vol_put, 2278352f7f91STakashi Iwai .tlv = { .c = cap_vol_tlv }, 2279352f7f91STakashi Iwai }; 2280352f7f91STakashi Iwai 2281352f7f91STakashi Iwai /* capture switch ctl callbacks */ 2282352f7f91STakashi Iwai #define cap_sw_info snd_ctl_boolean_stereo_info 2283352f7f91STakashi Iwai #define cap_sw_get snd_hda_mixer_amp_switch_get 2284352f7f91STakashi Iwai 2285352f7f91STakashi Iwai static int cap_sw_put(struct snd_kcontrol *kcontrol, 2286352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2287352f7f91STakashi Iwai { 2288352f7f91STakashi Iwai return cap_put_caller(kcontrol, ucontrol, 2289352f7f91STakashi Iwai snd_hda_mixer_amp_switch_put, 2290352f7f91STakashi Iwai NID_PATH_MUTE_CTL); 2291352f7f91STakashi Iwai } 2292352f7f91STakashi Iwai 2293352f7f91STakashi Iwai static const struct snd_kcontrol_new cap_sw_temp = { 2294352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2295352f7f91STakashi Iwai .name = "Capture Switch", 2296352f7f91STakashi Iwai .info = cap_sw_info, 2297352f7f91STakashi Iwai .get = cap_sw_get, 2298352f7f91STakashi Iwai .put = cap_sw_put, 2299352f7f91STakashi Iwai }; 2300352f7f91STakashi Iwai 2301352f7f91STakashi Iwai static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path) 2302352f7f91STakashi Iwai { 2303352f7f91STakashi Iwai hda_nid_t nid; 2304352f7f91STakashi Iwai int i, depth; 2305352f7f91STakashi Iwai 2306352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = path->ctls[NID_PATH_MUTE_CTL] = 0; 2307352f7f91STakashi Iwai for (depth = 0; depth < 3; depth++) { 2308352f7f91STakashi Iwai if (depth >= path->depth) 2309352f7f91STakashi Iwai return -EINVAL; 2310352f7f91STakashi Iwai i = path->depth - depth - 1; 2311352f7f91STakashi Iwai nid = path->path[i]; 2312352f7f91STakashi Iwai if (!path->ctls[NID_PATH_VOL_CTL]) { 2313352f7f91STakashi Iwai if (nid_has_volume(codec, nid, HDA_OUTPUT)) 2314352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = 2315352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 2316352f7f91STakashi Iwai else if (nid_has_volume(codec, nid, HDA_INPUT)) { 2317352f7f91STakashi Iwai int idx = path->idx[i]; 2318352f7f91STakashi Iwai if (!depth && codec->single_adc_amp) 2319352f7f91STakashi Iwai idx = 0; 2320352f7f91STakashi Iwai path->ctls[NID_PATH_VOL_CTL] = 2321352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); 2322352f7f91STakashi Iwai } 2323352f7f91STakashi Iwai } 2324352f7f91STakashi Iwai if (!path->ctls[NID_PATH_MUTE_CTL]) { 2325352f7f91STakashi Iwai if (nid_has_mute(codec, nid, HDA_OUTPUT)) 2326352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = 2327352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); 2328352f7f91STakashi Iwai else if (nid_has_mute(codec, nid, HDA_INPUT)) { 2329352f7f91STakashi Iwai int idx = path->idx[i]; 2330352f7f91STakashi Iwai if (!depth && codec->single_adc_amp) 2331352f7f91STakashi Iwai idx = 0; 2332352f7f91STakashi Iwai path->ctls[NID_PATH_MUTE_CTL] = 2333352f7f91STakashi Iwai HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); 2334352f7f91STakashi Iwai } 2335352f7f91STakashi Iwai } 2336352f7f91STakashi Iwai } 2337352f7f91STakashi Iwai return 0; 2338352f7f91STakashi Iwai } 2339352f7f91STakashi Iwai 2340352f7f91STakashi Iwai static bool is_inv_dmic_pin(struct hda_codec *codec, hda_nid_t nid) 2341352f7f91STakashi Iwai { 2342352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2343352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 2344352f7f91STakashi Iwai unsigned int val; 2345352f7f91STakashi Iwai int i; 2346352f7f91STakashi Iwai 2347352f7f91STakashi Iwai if (!spec->inv_dmic_split) 2348352f7f91STakashi Iwai return false; 2349352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 2350352f7f91STakashi Iwai if (cfg->inputs[i].pin != nid) 2351352f7f91STakashi Iwai continue; 2352352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC) 2353352f7f91STakashi Iwai return false; 2354352f7f91STakashi Iwai val = snd_hda_codec_get_pincfg(codec, nid); 2355352f7f91STakashi Iwai return snd_hda_get_input_pin_attr(val) == INPUT_PIN_ATTR_INT; 2356352f7f91STakashi Iwai } 2357352f7f91STakashi Iwai return false; 2358352f7f91STakashi Iwai } 2359352f7f91STakashi Iwai 2360352f7f91STakashi Iwai static int add_single_cap_ctl(struct hda_codec *codec, const char *label, 2361352f7f91STakashi Iwai int idx, bool is_switch, unsigned int ctl, 2362352f7f91STakashi Iwai bool inv_dmic) 2363352f7f91STakashi Iwai { 2364352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2365352f7f91STakashi Iwai char tmpname[44]; 2366352f7f91STakashi Iwai int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL; 2367352f7f91STakashi Iwai const char *sfx = is_switch ? "Switch" : "Volume"; 2368352f7f91STakashi Iwai unsigned int chs = inv_dmic ? 1 : 3; 2369352f7f91STakashi Iwai int err; 2370352f7f91STakashi Iwai 2371352f7f91STakashi Iwai if (!ctl) 2372352f7f91STakashi Iwai return 0; 2373352f7f91STakashi Iwai 2374352f7f91STakashi Iwai if (label) 2375352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2376352f7f91STakashi Iwai "%s Capture %s", label, sfx); 2377352f7f91STakashi Iwai else 2378352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2379352f7f91STakashi Iwai "Capture %s", sfx); 2380352f7f91STakashi Iwai err = add_control(spec, type, tmpname, idx, 2381352f7f91STakashi Iwai amp_val_replace_channels(ctl, chs)); 2382352f7f91STakashi Iwai if (err < 0 || !inv_dmic) 2383352f7f91STakashi Iwai return err; 2384352f7f91STakashi Iwai 2385352f7f91STakashi Iwai /* Make independent right kcontrol */ 2386352f7f91STakashi Iwai if (label) 2387352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2388352f7f91STakashi Iwai "Inverted %s Capture %s", label, sfx); 2389352f7f91STakashi Iwai else 2390352f7f91STakashi Iwai snprintf(tmpname, sizeof(tmpname), 2391352f7f91STakashi Iwai "Inverted Capture %s", sfx); 2392352f7f91STakashi Iwai return add_control(spec, type, tmpname, idx, 2393352f7f91STakashi Iwai amp_val_replace_channels(ctl, 2)); 2394352f7f91STakashi Iwai } 2395352f7f91STakashi Iwai 2396352f7f91STakashi Iwai /* create single (and simple) capture volume and switch controls */ 2397352f7f91STakashi Iwai static int create_single_cap_vol_ctl(struct hda_codec *codec, int idx, 2398352f7f91STakashi Iwai unsigned int vol_ctl, unsigned int sw_ctl, 2399352f7f91STakashi Iwai bool inv_dmic) 2400352f7f91STakashi Iwai { 2401352f7f91STakashi Iwai int err; 2402352f7f91STakashi Iwai err = add_single_cap_ctl(codec, NULL, idx, false, vol_ctl, inv_dmic); 2403352f7f91STakashi Iwai if (err < 0) 2404352f7f91STakashi Iwai return err; 2405352f7f91STakashi Iwai err = add_single_cap_ctl(codec, NULL, idx, true, sw_ctl, inv_dmic); 2406071c73adSTakashi Iwai if (err < 0) 2407071c73adSTakashi Iwai return err; 2408071c73adSTakashi Iwai return 0; 24091da177e4SLinus Torvalds } 2410071c73adSTakashi Iwai 2411352f7f91STakashi Iwai /* create bound capture volume and switch controls */ 2412352f7f91STakashi Iwai static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx, 2413352f7f91STakashi Iwai unsigned int vol_ctl, unsigned int sw_ctl) 2414352f7f91STakashi Iwai { 2415352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2416352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 2417352f7f91STakashi Iwai 2418352f7f91STakashi Iwai if (vol_ctl) { 241912c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, NULL, &cap_vol_temp); 2420352f7f91STakashi Iwai if (!knew) 2421352f7f91STakashi Iwai return -ENOMEM; 2422352f7f91STakashi Iwai knew->index = idx; 2423352f7f91STakashi Iwai knew->private_value = vol_ctl; 2424352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 2425352f7f91STakashi Iwai } 2426352f7f91STakashi Iwai if (sw_ctl) { 242712c93df6STakashi Iwai knew = snd_hda_gen_add_kctl(spec, NULL, &cap_sw_temp); 2428352f7f91STakashi Iwai if (!knew) 2429352f7f91STakashi Iwai return -ENOMEM; 2430352f7f91STakashi Iwai knew->index = idx; 2431352f7f91STakashi Iwai knew->private_value = sw_ctl; 2432352f7f91STakashi Iwai knew->subdevice = HDA_SUBDEV_AMP_FLAG; 2433352f7f91STakashi Iwai } 2434352f7f91STakashi Iwai return 0; 2435352f7f91STakashi Iwai } 2436352f7f91STakashi Iwai 2437352f7f91STakashi Iwai /* return the vol ctl when used first in the imux list */ 2438352f7f91STakashi Iwai static unsigned int get_first_cap_ctl(struct hda_codec *codec, int idx, int type) 2439352f7f91STakashi Iwai { 2440352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2441352f7f91STakashi Iwai struct nid_path *path; 2442352f7f91STakashi Iwai unsigned int ctl; 2443352f7f91STakashi Iwai int i; 2444352f7f91STakashi Iwai 2445352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, spec->imux_pins[idx], 2446352f7f91STakashi Iwai get_adc_nid(codec, 0, idx)); 2447352f7f91STakashi Iwai if (!path) 2448352f7f91STakashi Iwai return 0; 2449352f7f91STakashi Iwai ctl = path->ctls[type]; 2450352f7f91STakashi Iwai if (!ctl) 2451352f7f91STakashi Iwai return 0; 2452352f7f91STakashi Iwai for (i = 0; i < idx - 1; i++) { 2453352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, spec->imux_pins[i], 2454352f7f91STakashi Iwai get_adc_nid(codec, 0, i)); 2455352f7f91STakashi Iwai if (path && path->ctls[type] == ctl) 2456352f7f91STakashi Iwai return 0; 2457352f7f91STakashi Iwai } 2458352f7f91STakashi Iwai return ctl; 2459352f7f91STakashi Iwai } 2460352f7f91STakashi Iwai 2461352f7f91STakashi Iwai /* create individual capture volume and switch controls per input */ 2462352f7f91STakashi Iwai static int create_multi_cap_vol_ctl(struct hda_codec *codec) 2463352f7f91STakashi Iwai { 2464352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2465352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 2466352f7f91STakashi Iwai int i, err, type, type_idx = 0; 2467352f7f91STakashi Iwai const char *prev_label = NULL; 2468352f7f91STakashi Iwai 2469352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2470352f7f91STakashi Iwai const char *label; 2471352f7f91STakashi Iwai bool inv_dmic; 2472352f7f91STakashi Iwai label = hda_get_autocfg_input_label(codec, &spec->autocfg, i); 2473352f7f91STakashi Iwai if (prev_label && !strcmp(label, prev_label)) 2474352f7f91STakashi Iwai type_idx++; 2475352f7f91STakashi Iwai else 2476352f7f91STakashi Iwai type_idx = 0; 2477352f7f91STakashi Iwai prev_label = label; 2478352f7f91STakashi Iwai inv_dmic = is_inv_dmic_pin(codec, spec->imux_pins[i]); 2479352f7f91STakashi Iwai 2480352f7f91STakashi Iwai for (type = 0; type < 2; type++) { 2481352f7f91STakashi Iwai err = add_single_cap_ctl(codec, label, type_idx, type, 2482352f7f91STakashi Iwai get_first_cap_ctl(codec, i, type), 2483352f7f91STakashi Iwai inv_dmic); 2484d13bd412STakashi Iwai if (err < 0) 2485071c73adSTakashi Iwai return err; 2486352f7f91STakashi Iwai } 2487352f7f91STakashi Iwai } 2488071c73adSTakashi Iwai return 0; 2489352f7f91STakashi Iwai } 2490071c73adSTakashi Iwai 2491352f7f91STakashi Iwai static int create_capture_mixers(struct hda_codec *codec) 2492352f7f91STakashi Iwai { 2493352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2494352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 2495352f7f91STakashi Iwai int i, n, nums, err; 2496352f7f91STakashi Iwai 2497352f7f91STakashi Iwai if (spec->dyn_adc_switch) 2498352f7f91STakashi Iwai nums = 1; 2499352f7f91STakashi Iwai else 2500352f7f91STakashi Iwai nums = spec->num_adc_nids; 2501352f7f91STakashi Iwai 2502352f7f91STakashi Iwai if (!spec->auto_mic && imux->num_items > 1) { 2503352f7f91STakashi Iwai struct snd_kcontrol_new *knew; 2504624d914dSTakashi Iwai const char *name; 2505624d914dSTakashi Iwai name = nums > 1 ? "Input Source" : "Capture Source"; 2506624d914dSTakashi Iwai knew = snd_hda_gen_add_kctl(spec, name, &cap_src_temp); 2507352f7f91STakashi Iwai if (!knew) 2508352f7f91STakashi Iwai return -ENOMEM; 2509352f7f91STakashi Iwai knew->count = nums; 2510352f7f91STakashi Iwai } 2511352f7f91STakashi Iwai 2512352f7f91STakashi Iwai for (n = 0; n < nums; n++) { 2513352f7f91STakashi Iwai bool multi = false; 2514352f7f91STakashi Iwai bool inv_dmic = false; 2515352f7f91STakashi Iwai int vol, sw; 2516352f7f91STakashi Iwai 2517352f7f91STakashi Iwai vol = sw = 0; 2518352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 2519352f7f91STakashi Iwai struct nid_path *path; 2520352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, spec->imux_pins[i], 2521352f7f91STakashi Iwai get_adc_nid(codec, n, i)); 2522352f7f91STakashi Iwai if (!path) 2523352f7f91STakashi Iwai continue; 2524352f7f91STakashi Iwai parse_capvol_in_path(codec, path); 2525352f7f91STakashi Iwai if (!vol) 2526352f7f91STakashi Iwai vol = path->ctls[NID_PATH_VOL_CTL]; 2527352f7f91STakashi Iwai else if (vol != path->ctls[NID_PATH_VOL_CTL]) 2528352f7f91STakashi Iwai multi = true; 2529352f7f91STakashi Iwai if (!sw) 2530352f7f91STakashi Iwai sw = path->ctls[NID_PATH_MUTE_CTL]; 2531352f7f91STakashi Iwai else if (sw != path->ctls[NID_PATH_MUTE_CTL]) 2532352f7f91STakashi Iwai multi = true; 2533352f7f91STakashi Iwai if (is_inv_dmic_pin(codec, spec->imux_pins[i])) 2534352f7f91STakashi Iwai inv_dmic = true; 2535352f7f91STakashi Iwai } 2536352f7f91STakashi Iwai 2537352f7f91STakashi Iwai if (!multi) 2538352f7f91STakashi Iwai err = create_single_cap_vol_ctl(codec, n, vol, sw, 2539352f7f91STakashi Iwai inv_dmic); 2540352f7f91STakashi Iwai else if (!spec->multi_cap_vol) 2541352f7f91STakashi Iwai err = create_bind_cap_vol_ctl(codec, n, vol, sw); 2542352f7f91STakashi Iwai else 2543352f7f91STakashi Iwai err = create_multi_cap_vol_ctl(codec); 2544d13bd412STakashi Iwai if (err < 0) 2545071c73adSTakashi Iwai return err; 2546071c73adSTakashi Iwai } 2547071c73adSTakashi Iwai 25481da177e4SLinus Torvalds return 0; 25491da177e4SLinus Torvalds } 25501da177e4SLinus Torvalds 2551352f7f91STakashi Iwai /* 2552352f7f91STakashi Iwai * add mic boosts if needed 2553352f7f91STakashi Iwai */ 2554352f7f91STakashi Iwai static int parse_mic_boost(struct hda_codec *codec) 2555352f7f91STakashi Iwai { 2556352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2557352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 2558352f7f91STakashi Iwai int i, err; 2559352f7f91STakashi Iwai int type_idx = 0; 2560352f7f91STakashi Iwai hda_nid_t nid; 2561352f7f91STakashi Iwai const char *prev_label = NULL; 2562352f7f91STakashi Iwai 2563352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 2564352f7f91STakashi Iwai if (cfg->inputs[i].type > AUTO_PIN_MIC) 2565352f7f91STakashi Iwai break; 2566352f7f91STakashi Iwai nid = cfg->inputs[i].pin; 2567352f7f91STakashi Iwai if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { 2568352f7f91STakashi Iwai const char *label; 25695abd4888STakashi Iwai char boost_label[44]; 2570352f7f91STakashi Iwai struct nid_path *path; 2571352f7f91STakashi Iwai unsigned int val; 2572352f7f91STakashi Iwai 2573352f7f91STakashi Iwai label = hda_get_autocfg_input_label(codec, cfg, i); 2574352f7f91STakashi Iwai if (spec->shared_mic_hp && !strcmp(label, "Misc")) 2575352f7f91STakashi Iwai label = "Headphone Mic"; 2576352f7f91STakashi Iwai if (prev_label && !strcmp(label, prev_label)) 2577352f7f91STakashi Iwai type_idx++; 2578352f7f91STakashi Iwai else 2579352f7f91STakashi Iwai type_idx = 0; 2580352f7f91STakashi Iwai prev_label = label; 2581352f7f91STakashi Iwai 2582352f7f91STakashi Iwai snprintf(boost_label, sizeof(boost_label), 2583352f7f91STakashi Iwai "%s Boost Volume", label); 2584352f7f91STakashi Iwai val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); 2585352f7f91STakashi Iwai err = add_control(spec, HDA_CTL_WIDGET_VOL, 2586352f7f91STakashi Iwai boost_label, type_idx, val); 2587352f7f91STakashi Iwai if (err < 0) 2588352f7f91STakashi Iwai return err; 2589352f7f91STakashi Iwai 2590352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, nid, 0); 2591352f7f91STakashi Iwai if (path) 2592352f7f91STakashi Iwai path->ctls[NID_PATH_BOOST_CTL] = val; 2593352f7f91STakashi Iwai } 2594352f7f91STakashi Iwai } 2595352f7f91STakashi Iwai return 0; 2596352f7f91STakashi Iwai } 2597352f7f91STakashi Iwai 2598352f7f91STakashi Iwai /* 2599352f7f91STakashi Iwai * parse digital I/Os and set up NIDs in BIOS auto-parse mode 2600352f7f91STakashi Iwai */ 2601352f7f91STakashi Iwai static void parse_digital(struct hda_codec *codec) 2602352f7f91STakashi Iwai { 2603352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 26040c8c0f56STakashi Iwai struct nid_path *path; 2605352f7f91STakashi Iwai int i, nums; 2606352f7f91STakashi Iwai hda_nid_t dig_nid; 2607352f7f91STakashi Iwai 2608352f7f91STakashi Iwai /* support multiple SPDIFs; the secondary is set up as a slave */ 2609352f7f91STakashi Iwai nums = 0; 2610352f7f91STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) { 2611352f7f91STakashi Iwai hda_nid_t pin = spec->autocfg.dig_out_pins[i]; 2612352f7f91STakashi Iwai dig_nid = look_for_dac(codec, pin, true); 2613352f7f91STakashi Iwai if (!dig_nid) 2614352f7f91STakashi Iwai continue; 26154ac0eefaSTakashi Iwai path = snd_hda_add_new_path(codec, dig_nid, pin, HDA_PARSE_ALL); 26160c8c0f56STakashi Iwai if (!path) 2617352f7f91STakashi Iwai continue; 26180c8c0f56STakashi Iwai print_nid_path("digout", path); 2619e1284af7STakashi Iwai path->active = true; 2620196c1766STakashi Iwai spec->digout_paths[i] = snd_hda_get_path_idx(codec, path); 2621352f7f91STakashi Iwai if (!nums) { 2622352f7f91STakashi Iwai spec->multiout.dig_out_nid = dig_nid; 2623352f7f91STakashi Iwai spec->dig_out_type = spec->autocfg.dig_out_type[0]; 2624352f7f91STakashi Iwai } else { 2625352f7f91STakashi Iwai spec->multiout.slave_dig_outs = spec->slave_dig_outs; 2626352f7f91STakashi Iwai if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) 2627352f7f91STakashi Iwai break; 2628352f7f91STakashi Iwai spec->slave_dig_outs[nums - 1] = dig_nid; 2629352f7f91STakashi Iwai } 2630352f7f91STakashi Iwai nums++; 2631352f7f91STakashi Iwai } 2632352f7f91STakashi Iwai 2633352f7f91STakashi Iwai if (spec->autocfg.dig_in_pin) { 2634352f7f91STakashi Iwai dig_nid = codec->start_nid; 2635352f7f91STakashi Iwai for (i = 0; i < codec->num_nodes; i++, dig_nid++) { 2636352f7f91STakashi Iwai unsigned int wcaps = get_wcaps(codec, dig_nid); 2637352f7f91STakashi Iwai if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) 2638352f7f91STakashi Iwai continue; 2639352f7f91STakashi Iwai if (!(wcaps & AC_WCAP_DIGITAL)) 2640352f7f91STakashi Iwai continue; 2641352f7f91STakashi Iwai path = snd_hda_add_new_path(codec, 2642352f7f91STakashi Iwai spec->autocfg.dig_in_pin, 26434ac0eefaSTakashi Iwai dig_nid, HDA_PARSE_ALL); 2644352f7f91STakashi Iwai if (path) { 26450c8c0f56STakashi Iwai print_nid_path("digin", path); 2646352f7f91STakashi Iwai path->active = true; 2647352f7f91STakashi Iwai spec->dig_in_nid = dig_nid; 26482430d7b7STakashi Iwai spec->digin_path = snd_hda_get_path_idx(codec, path); 2649352f7f91STakashi Iwai break; 2650352f7f91STakashi Iwai } 2651352f7f91STakashi Iwai } 2652352f7f91STakashi Iwai } 2653352f7f91STakashi Iwai } 2654352f7f91STakashi Iwai 26551da177e4SLinus Torvalds 26561da177e4SLinus Torvalds /* 2657352f7f91STakashi Iwai * input MUX handling 26581da177e4SLinus Torvalds */ 26591da177e4SLinus Torvalds 2660352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur); 2661352f7f91STakashi Iwai 2662352f7f91STakashi Iwai /* select the given imux item; either unmute exclusively or select the route */ 2663352f7f91STakashi Iwai static int mux_select(struct hda_codec *codec, unsigned int adc_idx, 2664352f7f91STakashi Iwai unsigned int idx) 2665352f7f91STakashi Iwai { 2666352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2667352f7f91STakashi Iwai const struct hda_input_mux *imux; 2668352f7f91STakashi Iwai struct nid_path *path; 2669352f7f91STakashi Iwai 2670352f7f91STakashi Iwai imux = &spec->input_mux; 2671352f7f91STakashi Iwai if (!imux->num_items) 26721da177e4SLinus Torvalds return 0; 26731da177e4SLinus Torvalds 2674352f7f91STakashi Iwai if (idx >= imux->num_items) 2675352f7f91STakashi Iwai idx = imux->num_items - 1; 2676352f7f91STakashi Iwai if (spec->cur_mux[adc_idx] == idx) 2677352f7f91STakashi Iwai return 0; 2678352f7f91STakashi Iwai 2679352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, 2680352f7f91STakashi Iwai spec->imux_pins[spec->cur_mux[adc_idx]], 2681352f7f91STakashi Iwai spec->adc_nids[adc_idx]); 2682352f7f91STakashi Iwai if (!path) 2683352f7f91STakashi Iwai return 0; 2684352f7f91STakashi Iwai if (path->active) 2685352f7f91STakashi Iwai snd_hda_activate_path(codec, path, false, false); 2686352f7f91STakashi Iwai 2687352f7f91STakashi Iwai spec->cur_mux[adc_idx] = idx; 2688352f7f91STakashi Iwai 2689352f7f91STakashi Iwai if (spec->shared_mic_hp) 2690352f7f91STakashi Iwai update_shared_mic_hp(codec, spec->cur_mux[adc_idx]); 2691352f7f91STakashi Iwai 2692352f7f91STakashi Iwai if (spec->dyn_adc_switch) 2693352f7f91STakashi Iwai dyn_adc_pcm_resetup(codec, idx); 2694352f7f91STakashi Iwai 2695352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, spec->imux_pins[idx], 2696352f7f91STakashi Iwai get_adc_nid(codec, adc_idx, idx)); 2697352f7f91STakashi Iwai if (!path) 2698352f7f91STakashi Iwai return 0; 2699352f7f91STakashi Iwai if (path->active) 2700352f7f91STakashi Iwai return 0; 2701352f7f91STakashi Iwai snd_hda_activate_path(codec, path, true, false); 2702352f7f91STakashi Iwai if (spec->cap_sync_hook) 2703352f7f91STakashi Iwai spec->cap_sync_hook(codec); 27041da177e4SLinus Torvalds return 1; 27051da177e4SLinus Torvalds } 27061da177e4SLinus Torvalds 27071da177e4SLinus Torvalds 27081da177e4SLinus Torvalds /* 2709352f7f91STakashi Iwai * Jack detections for HP auto-mute and mic-switch 27101da177e4SLinus Torvalds */ 2711352f7f91STakashi Iwai 2712352f7f91STakashi Iwai /* check each pin in the given array; returns true if any of them is plugged */ 2713352f7f91STakashi Iwai static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) 27141da177e4SLinus Torvalds { 2715352f7f91STakashi Iwai int i, present = 0; 27161da177e4SLinus Torvalds 2717352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 2718352f7f91STakashi Iwai hda_nid_t nid = pins[i]; 2719352f7f91STakashi Iwai if (!nid) 2720352f7f91STakashi Iwai break; 2721352f7f91STakashi Iwai present |= snd_hda_jack_detect(codec, nid); 27221da177e4SLinus Torvalds } 2723352f7f91STakashi Iwai return present; 27241da177e4SLinus Torvalds } 27251da177e4SLinus Torvalds 2726352f7f91STakashi Iwai /* standard HP/line-out auto-mute helper */ 2727352f7f91STakashi Iwai static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, 2728352f7f91STakashi Iwai bool mute, bool hp_out) 27291da177e4SLinus Torvalds { 2730352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2731352f7f91STakashi Iwai unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT); 2732352f7f91STakashi Iwai int i; 27331da177e4SLinus Torvalds 2734352f7f91STakashi Iwai for (i = 0; i < num_pins; i++) { 2735352f7f91STakashi Iwai hda_nid_t nid = pins[i]; 2736352f7f91STakashi Iwai unsigned int val; 2737352f7f91STakashi Iwai if (!nid) 2738352f7f91STakashi Iwai break; 2739352f7f91STakashi Iwai /* don't reset VREF value in case it's controlling 2740352f7f91STakashi Iwai * the amp (see alc861_fixup_asus_amp_vref_0f()) 2741352f7f91STakashi Iwai */ 2742352f7f91STakashi Iwai if (spec->keep_vref_in_automute) { 2743352f7f91STakashi Iwai val = snd_hda_codec_read(codec, nid, 0, 2744352f7f91STakashi Iwai AC_VERB_GET_PIN_WIDGET_CONTROL, 0); 2745352f7f91STakashi Iwai val &= ~PIN_HP; 2746352f7f91STakashi Iwai } else 2747352f7f91STakashi Iwai val = 0; 2748352f7f91STakashi Iwai val |= pin_bits; 27497594aa33STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, val); 2750d5a9f1bbSTakashi Iwai set_pin_eapd(codec, nid, !mute); 2751352f7f91STakashi Iwai } 2752352f7f91STakashi Iwai } 27531da177e4SLinus Torvalds 2754352f7f91STakashi Iwai /* Toggle outputs muting */ 27555d550e15STakashi Iwai void snd_hda_gen_update_outputs(struct hda_codec *codec) 2756352f7f91STakashi Iwai { 2757352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2758352f7f91STakashi Iwai int on; 2759352f7f91STakashi Iwai 2760352f7f91STakashi Iwai /* Control HP pins/amps depending on master_mute state; 2761352f7f91STakashi Iwai * in general, HP pins/amps control should be enabled in all cases, 2762352f7f91STakashi Iwai * but currently set only for master_mute, just to be safe 2763352f7f91STakashi Iwai */ 2764352f7f91STakashi Iwai if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */ 2765352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), 2766352f7f91STakashi Iwai spec->autocfg.hp_pins, spec->master_mute, true); 2767352f7f91STakashi Iwai 2768352f7f91STakashi Iwai if (!spec->automute_speaker) 2769352f7f91STakashi Iwai on = 0; 2770352f7f91STakashi Iwai else 2771352f7f91STakashi Iwai on = spec->hp_jack_present | spec->line_jack_present; 2772352f7f91STakashi Iwai on |= spec->master_mute; 2773352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), 2774352f7f91STakashi Iwai spec->autocfg.speaker_pins, on, false); 2775352f7f91STakashi Iwai 2776352f7f91STakashi Iwai /* toggle line-out mutes if needed, too */ 2777352f7f91STakashi Iwai /* if LO is a copy of either HP or Speaker, don't need to handle it */ 2778352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] || 2779352f7f91STakashi Iwai spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0]) 2780352f7f91STakashi Iwai return; 2781352f7f91STakashi Iwai if (!spec->automute_lo) 2782352f7f91STakashi Iwai on = 0; 2783352f7f91STakashi Iwai else 2784352f7f91STakashi Iwai on = spec->hp_jack_present; 2785352f7f91STakashi Iwai on |= spec->master_mute; 2786352f7f91STakashi Iwai do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), 2787352f7f91STakashi Iwai spec->autocfg.line_out_pins, on, false); 2788352f7f91STakashi Iwai } 27895d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs); 2790352f7f91STakashi Iwai 2791352f7f91STakashi Iwai static void call_update_outputs(struct hda_codec *codec) 2792352f7f91STakashi Iwai { 2793352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2794352f7f91STakashi Iwai if (spec->automute_hook) 2795352f7f91STakashi Iwai spec->automute_hook(codec); 2796352f7f91STakashi Iwai else 27975d550e15STakashi Iwai snd_hda_gen_update_outputs(codec); 2798352f7f91STakashi Iwai } 2799352f7f91STakashi Iwai 2800352f7f91STakashi Iwai /* standard HP-automute helper */ 28015d550e15STakashi Iwai void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) 2802352f7f91STakashi Iwai { 2803352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2804352f7f91STakashi Iwai 2805352f7f91STakashi Iwai spec->hp_jack_present = 2806352f7f91STakashi Iwai detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins), 2807352f7f91STakashi Iwai spec->autocfg.hp_pins); 2808352f7f91STakashi Iwai if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo)) 2809352f7f91STakashi Iwai return; 2810352f7f91STakashi Iwai call_update_outputs(codec); 2811352f7f91STakashi Iwai } 28125d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_hp_automute); 2813352f7f91STakashi Iwai 2814352f7f91STakashi Iwai /* standard line-out-automute helper */ 28155d550e15STakashi Iwai void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) 2816352f7f91STakashi Iwai { 2817352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2818352f7f91STakashi Iwai 2819352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) 2820352f7f91STakashi Iwai return; 2821352f7f91STakashi Iwai /* check LO jack only when it's different from HP */ 2822352f7f91STakashi Iwai if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0]) 2823352f7f91STakashi Iwai return; 2824352f7f91STakashi Iwai 2825352f7f91STakashi Iwai spec->line_jack_present = 2826352f7f91STakashi Iwai detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), 2827352f7f91STakashi Iwai spec->autocfg.line_out_pins); 2828352f7f91STakashi Iwai if (!spec->automute_speaker || !spec->detect_lo) 2829352f7f91STakashi Iwai return; 2830352f7f91STakashi Iwai call_update_outputs(codec); 2831352f7f91STakashi Iwai } 28325d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_line_automute); 2833352f7f91STakashi Iwai 2834352f7f91STakashi Iwai /* standard mic auto-switch helper */ 28355d550e15STakashi Iwai void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *jack) 2836352f7f91STakashi Iwai { 2837352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2838352f7f91STakashi Iwai int i; 2839352f7f91STakashi Iwai 2840352f7f91STakashi Iwai if (!spec->auto_mic) 2841352f7f91STakashi Iwai return; 2842352f7f91STakashi Iwai 2843352f7f91STakashi Iwai for (i = spec->am_num_entries - 1; i > 0; i--) { 2844352f7f91STakashi Iwai if (snd_hda_jack_detect(codec, spec->am_entry[i].pin)) { 2845352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[i].idx); 2846352f7f91STakashi Iwai return; 2847352f7f91STakashi Iwai } 2848352f7f91STakashi Iwai } 2849352f7f91STakashi Iwai mux_select(codec, 0, spec->am_entry[0].idx); 28501da177e4SLinus Torvalds } 28515d550e15STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_mic_autoswitch); 28521da177e4SLinus Torvalds 28531da177e4SLinus Torvalds /* 2854352f7f91STakashi Iwai * Auto-Mute mode mixer enum support 28551da177e4SLinus Torvalds */ 2856352f7f91STakashi Iwai static int automute_mode_info(struct snd_kcontrol *kcontrol, 2857352f7f91STakashi Iwai struct snd_ctl_elem_info *uinfo) 2858352f7f91STakashi Iwai { 2859352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2860352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2861352f7f91STakashi Iwai static const char * const texts3[] = { 2862352f7f91STakashi Iwai "Disabled", "Speaker Only", "Line Out+Speaker" 28631da177e4SLinus Torvalds }; 28641da177e4SLinus Torvalds 2865352f7f91STakashi Iwai if (spec->automute_speaker_possible && spec->automute_lo_possible) 2866352f7f91STakashi Iwai return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3); 2867352f7f91STakashi Iwai return snd_hda_enum_bool_helper_info(kcontrol, uinfo); 2868352f7f91STakashi Iwai } 2869352f7f91STakashi Iwai 2870352f7f91STakashi Iwai static int automute_mode_get(struct snd_kcontrol *kcontrol, 2871352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2872352f7f91STakashi Iwai { 2873352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2874352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2875352f7f91STakashi Iwai unsigned int val = 0; 2876352f7f91STakashi Iwai if (spec->automute_speaker) 2877352f7f91STakashi Iwai val++; 2878352f7f91STakashi Iwai if (spec->automute_lo) 2879352f7f91STakashi Iwai val++; 2880352f7f91STakashi Iwai 2881352f7f91STakashi Iwai ucontrol->value.enumerated.item[0] = val; 2882352f7f91STakashi Iwai return 0; 2883352f7f91STakashi Iwai } 2884352f7f91STakashi Iwai 2885352f7f91STakashi Iwai static int automute_mode_put(struct snd_kcontrol *kcontrol, 2886352f7f91STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2887352f7f91STakashi Iwai { 2888352f7f91STakashi Iwai struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2889352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2890352f7f91STakashi Iwai 2891352f7f91STakashi Iwai switch (ucontrol->value.enumerated.item[0]) { 2892352f7f91STakashi Iwai case 0: 2893352f7f91STakashi Iwai if (!spec->automute_speaker && !spec->automute_lo) 2894352f7f91STakashi Iwai return 0; 2895352f7f91STakashi Iwai spec->automute_speaker = 0; 2896352f7f91STakashi Iwai spec->automute_lo = 0; 2897352f7f91STakashi Iwai break; 2898352f7f91STakashi Iwai case 1: 2899352f7f91STakashi Iwai if (spec->automute_speaker_possible) { 2900352f7f91STakashi Iwai if (!spec->automute_lo && spec->automute_speaker) 2901352f7f91STakashi Iwai return 0; 2902352f7f91STakashi Iwai spec->automute_speaker = 1; 2903352f7f91STakashi Iwai spec->automute_lo = 0; 2904352f7f91STakashi Iwai } else if (spec->automute_lo_possible) { 2905352f7f91STakashi Iwai if (spec->automute_lo) 2906352f7f91STakashi Iwai return 0; 2907352f7f91STakashi Iwai spec->automute_lo = 1; 2908352f7f91STakashi Iwai } else 2909352f7f91STakashi Iwai return -EINVAL; 2910352f7f91STakashi Iwai break; 2911352f7f91STakashi Iwai case 2: 2912352f7f91STakashi Iwai if (!spec->automute_lo_possible || !spec->automute_speaker_possible) 2913352f7f91STakashi Iwai return -EINVAL; 2914352f7f91STakashi Iwai if (spec->automute_speaker && spec->automute_lo) 2915352f7f91STakashi Iwai return 0; 2916352f7f91STakashi Iwai spec->automute_speaker = 1; 2917352f7f91STakashi Iwai spec->automute_lo = 1; 2918352f7f91STakashi Iwai break; 2919352f7f91STakashi Iwai default: 2920352f7f91STakashi Iwai return -EINVAL; 2921352f7f91STakashi Iwai } 2922352f7f91STakashi Iwai call_update_outputs(codec); 2923352f7f91STakashi Iwai return 1; 2924352f7f91STakashi Iwai } 2925352f7f91STakashi Iwai 2926352f7f91STakashi Iwai static const struct snd_kcontrol_new automute_mode_enum = { 2927352f7f91STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2928352f7f91STakashi Iwai .name = "Auto-Mute Mode", 2929352f7f91STakashi Iwai .info = automute_mode_info, 2930352f7f91STakashi Iwai .get = automute_mode_get, 2931352f7f91STakashi Iwai .put = automute_mode_put, 2932352f7f91STakashi Iwai }; 2933352f7f91STakashi Iwai 2934352f7f91STakashi Iwai static int add_automute_mode_enum(struct hda_codec *codec) 2935352f7f91STakashi Iwai { 2936352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2937352f7f91STakashi Iwai 293812c93df6STakashi Iwai if (!snd_hda_gen_add_kctl(spec, NULL, &automute_mode_enum)) 2939352f7f91STakashi Iwai return -ENOMEM; 2940352f7f91STakashi Iwai return 0; 2941352f7f91STakashi Iwai } 2942352f7f91STakashi Iwai 2943352f7f91STakashi Iwai /* 2944352f7f91STakashi Iwai * Check the availability of HP/line-out auto-mute; 2945352f7f91STakashi Iwai * Set up appropriately if really supported 2946352f7f91STakashi Iwai */ 2947352f7f91STakashi Iwai static int check_auto_mute_availability(struct hda_codec *codec) 2948352f7f91STakashi Iwai { 2949352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 2950352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 2951352f7f91STakashi Iwai int present = 0; 2952352f7f91STakashi Iwai int i, err; 2953352f7f91STakashi Iwai 2954352f7f91STakashi Iwai if (cfg->hp_pins[0]) 2955352f7f91STakashi Iwai present++; 2956352f7f91STakashi Iwai if (cfg->line_out_pins[0]) 2957352f7f91STakashi Iwai present++; 2958352f7f91STakashi Iwai if (cfg->speaker_pins[0]) 2959352f7f91STakashi Iwai present++; 2960352f7f91STakashi Iwai if (present < 2) /* need two different output types */ 2961352f7f91STakashi Iwai return 0; 2962352f7f91STakashi Iwai 2963352f7f91STakashi Iwai if (!cfg->speaker_pins[0] && 2964352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { 2965352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 2966352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 2967352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 2968352f7f91STakashi Iwai } 2969352f7f91STakashi Iwai 2970352f7f91STakashi Iwai if (!cfg->hp_pins[0] && 2971352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_HP_OUT) { 2972352f7f91STakashi Iwai memcpy(cfg->hp_pins, cfg->line_out_pins, 2973352f7f91STakashi Iwai sizeof(cfg->hp_pins)); 2974352f7f91STakashi Iwai cfg->hp_outs = cfg->line_outs; 2975352f7f91STakashi Iwai } 2976352f7f91STakashi Iwai 2977352f7f91STakashi Iwai for (i = 0; i < cfg->hp_outs; i++) { 2978352f7f91STakashi Iwai hda_nid_t nid = cfg->hp_pins[i]; 2979352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 2980352f7f91STakashi Iwai continue; 2981352f7f91STakashi Iwai snd_printdd("hda-codec: Enable HP auto-muting on NID 0x%x\n", 2982352f7f91STakashi Iwai nid); 2983352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid, HDA_GEN_HP_EVENT, 29842e03e952STakashi Iwai spec->hp_automute_hook ? 29852e03e952STakashi Iwai spec->hp_automute_hook : 29865d550e15STakashi Iwai snd_hda_gen_hp_automute); 2987352f7f91STakashi Iwai spec->detect_hp = 1; 2988352f7f91STakashi Iwai } 2989352f7f91STakashi Iwai 2990352f7f91STakashi Iwai if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) { 2991352f7f91STakashi Iwai if (cfg->speaker_outs) 2992352f7f91STakashi Iwai for (i = 0; i < cfg->line_outs; i++) { 2993352f7f91STakashi Iwai hda_nid_t nid = cfg->line_out_pins[i]; 2994352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 2995352f7f91STakashi Iwai continue; 2996352f7f91STakashi Iwai snd_printdd("hda-codec: Enable Line-Out auto-muting on NID 0x%x\n", nid); 2997352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, nid, 2998352f7f91STakashi Iwai HDA_GEN_FRONT_EVENT, 29992e03e952STakashi Iwai spec->line_automute_hook ? 30002e03e952STakashi Iwai spec->line_automute_hook : 30015d550e15STakashi Iwai snd_hda_gen_line_automute); 3002352f7f91STakashi Iwai spec->detect_lo = 1; 3003352f7f91STakashi Iwai } 3004352f7f91STakashi Iwai spec->automute_lo_possible = spec->detect_hp; 3005352f7f91STakashi Iwai } 3006352f7f91STakashi Iwai 3007352f7f91STakashi Iwai spec->automute_speaker_possible = cfg->speaker_outs && 3008352f7f91STakashi Iwai (spec->detect_hp || spec->detect_lo); 3009352f7f91STakashi Iwai 3010352f7f91STakashi Iwai spec->automute_lo = spec->automute_lo_possible; 3011352f7f91STakashi Iwai spec->automute_speaker = spec->automute_speaker_possible; 3012352f7f91STakashi Iwai 3013352f7f91STakashi Iwai if (spec->automute_speaker_possible || spec->automute_lo_possible) { 3014352f7f91STakashi Iwai /* create a control for automute mode */ 3015352f7f91STakashi Iwai err = add_automute_mode_enum(codec); 3016352f7f91STakashi Iwai if (err < 0) 3017352f7f91STakashi Iwai return err; 3018352f7f91STakashi Iwai } 3019352f7f91STakashi Iwai return 0; 3020352f7f91STakashi Iwai } 3021352f7f91STakashi Iwai 3022352f7f91STakashi Iwai /* return the position of NID in the list, or -1 if not found */ 3023352f7f91STakashi Iwai static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) 3024352f7f91STakashi Iwai { 3025352f7f91STakashi Iwai int i; 3026352f7f91STakashi Iwai for (i = 0; i < nums; i++) 3027352f7f91STakashi Iwai if (list[i] == nid) 3028352f7f91STakashi Iwai return i; 3029352f7f91STakashi Iwai return -1; 3030352f7f91STakashi Iwai } 3031352f7f91STakashi Iwai 3032352f7f91STakashi Iwai /* check whether all auto-mic pins are valid; setup indices if OK */ 3033352f7f91STakashi Iwai static bool auto_mic_check_imux(struct hda_codec *codec) 3034352f7f91STakashi Iwai { 3035352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3036352f7f91STakashi Iwai const struct hda_input_mux *imux; 3037352f7f91STakashi Iwai int i; 3038352f7f91STakashi Iwai 3039352f7f91STakashi Iwai imux = &spec->input_mux; 3040352f7f91STakashi Iwai for (i = 0; i < spec->am_num_entries; i++) { 3041352f7f91STakashi Iwai spec->am_entry[i].idx = 3042352f7f91STakashi Iwai find_idx_in_nid_list(spec->am_entry[i].pin, 3043352f7f91STakashi Iwai spec->imux_pins, imux->num_items); 3044352f7f91STakashi Iwai if (spec->am_entry[i].idx < 0) 3045352f7f91STakashi Iwai return false; /* no corresponding imux */ 3046352f7f91STakashi Iwai } 3047352f7f91STakashi Iwai 3048352f7f91STakashi Iwai /* we don't need the jack detection for the first pin */ 3049352f7f91STakashi Iwai for (i = 1; i < spec->am_num_entries; i++) 3050352f7f91STakashi Iwai snd_hda_jack_detect_enable_callback(codec, 3051352f7f91STakashi Iwai spec->am_entry[i].pin, 3052352f7f91STakashi Iwai HDA_GEN_MIC_EVENT, 30532e03e952STakashi Iwai spec->mic_autoswitch_hook ? 30542e03e952STakashi Iwai spec->mic_autoswitch_hook : 30555d550e15STakashi Iwai snd_hda_gen_mic_autoswitch); 3056352f7f91STakashi Iwai return true; 3057352f7f91STakashi Iwai } 3058352f7f91STakashi Iwai 3059352f7f91STakashi Iwai static int compare_attr(const void *ap, const void *bp) 3060352f7f91STakashi Iwai { 3061352f7f91STakashi Iwai const struct automic_entry *a = ap; 3062352f7f91STakashi Iwai const struct automic_entry *b = bp; 3063352f7f91STakashi Iwai return (int)(a->attr - b->attr); 3064352f7f91STakashi Iwai } 3065352f7f91STakashi Iwai 3066352f7f91STakashi Iwai /* 3067352f7f91STakashi Iwai * Check the availability of auto-mic switch; 3068352f7f91STakashi Iwai * Set up if really supported 3069352f7f91STakashi Iwai */ 3070352f7f91STakashi Iwai static int check_auto_mic_availability(struct hda_codec *codec) 3071352f7f91STakashi Iwai { 3072352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3073352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 3074352f7f91STakashi Iwai unsigned int types; 3075352f7f91STakashi Iwai int i, num_pins; 3076352f7f91STakashi Iwai 3077352f7f91STakashi Iwai types = 0; 3078352f7f91STakashi Iwai num_pins = 0; 3079352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 3080352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 3081352f7f91STakashi Iwai unsigned int attr; 3082352f7f91STakashi Iwai attr = snd_hda_codec_get_pincfg(codec, nid); 3083352f7f91STakashi Iwai attr = snd_hda_get_input_pin_attr(attr); 3084352f7f91STakashi Iwai if (types & (1 << attr)) 3085352f7f91STakashi Iwai return 0; /* already occupied */ 3086352f7f91STakashi Iwai switch (attr) { 3087352f7f91STakashi Iwai case INPUT_PIN_ATTR_INT: 3088352f7f91STakashi Iwai if (cfg->inputs[i].type != AUTO_PIN_MIC) 3089352f7f91STakashi Iwai return 0; /* invalid type */ 3090352f7f91STakashi Iwai break; 3091352f7f91STakashi Iwai case INPUT_PIN_ATTR_UNUSED: 3092352f7f91STakashi Iwai return 0; /* invalid entry */ 3093352f7f91STakashi Iwai default: 3094352f7f91STakashi Iwai if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) 3095352f7f91STakashi Iwai return 0; /* invalid type */ 3096352f7f91STakashi Iwai if (!spec->line_in_auto_switch && 3097352f7f91STakashi Iwai cfg->inputs[i].type != AUTO_PIN_MIC) 3098352f7f91STakashi Iwai return 0; /* only mic is allowed */ 3099352f7f91STakashi Iwai if (!is_jack_detectable(codec, nid)) 3100352f7f91STakashi Iwai return 0; /* no unsol support */ 3101352f7f91STakashi Iwai break; 3102352f7f91STakashi Iwai } 3103352f7f91STakashi Iwai if (num_pins >= MAX_AUTO_MIC_PINS) 3104352f7f91STakashi Iwai return 0; 3105352f7f91STakashi Iwai types |= (1 << attr); 3106352f7f91STakashi Iwai spec->am_entry[num_pins].pin = nid; 3107352f7f91STakashi Iwai spec->am_entry[num_pins].attr = attr; 3108352f7f91STakashi Iwai num_pins++; 3109352f7f91STakashi Iwai } 3110352f7f91STakashi Iwai 3111352f7f91STakashi Iwai if (num_pins < 2) 3112352f7f91STakashi Iwai return 0; 3113352f7f91STakashi Iwai 3114352f7f91STakashi Iwai spec->am_num_entries = num_pins; 3115352f7f91STakashi Iwai /* sort the am_entry in the order of attr so that the pin with a 3116352f7f91STakashi Iwai * higher attr will be selected when the jack is plugged. 3117352f7f91STakashi Iwai */ 3118352f7f91STakashi Iwai sort(spec->am_entry, num_pins, sizeof(spec->am_entry[0]), 3119352f7f91STakashi Iwai compare_attr, NULL); 3120352f7f91STakashi Iwai 3121352f7f91STakashi Iwai if (!auto_mic_check_imux(codec)) 3122352f7f91STakashi Iwai return 0; 3123352f7f91STakashi Iwai 3124352f7f91STakashi Iwai spec->auto_mic = 1; 3125352f7f91STakashi Iwai spec->num_adc_nids = 1; 3126352f7f91STakashi Iwai spec->cur_mux[0] = spec->am_entry[0].idx; 3127352f7f91STakashi Iwai snd_printdd("hda-codec: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", 3128352f7f91STakashi Iwai spec->am_entry[0].pin, 3129352f7f91STakashi Iwai spec->am_entry[1].pin, 3130352f7f91STakashi Iwai spec->am_entry[2].pin); 3131352f7f91STakashi Iwai 3132352f7f91STakashi Iwai return 0; 3133352f7f91STakashi Iwai } 3134352f7f91STakashi Iwai 3135352f7f91STakashi Iwai 31369eb413e5STakashi Iwai /* 31379eb413e5STakashi Iwai * Parse the given BIOS configuration and set up the hda_gen_spec 31389eb413e5STakashi Iwai * 31399eb413e5STakashi Iwai * return 1 if successful, 0 if the proper config is not found, 3140352f7f91STakashi Iwai * or a negative error code 3141352f7f91STakashi Iwai */ 3142352f7f91STakashi Iwai int snd_hda_gen_parse_auto_config(struct hda_codec *codec, 31439eb413e5STakashi Iwai struct auto_pin_cfg *cfg) 3144352f7f91STakashi Iwai { 3145352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3146352f7f91STakashi Iwai int err; 3147352f7f91STakashi Iwai 31489eb413e5STakashi Iwai if (cfg != &spec->autocfg) { 31499eb413e5STakashi Iwai spec->autocfg = *cfg; 31509eb413e5STakashi Iwai cfg = &spec->autocfg; 31519eb413e5STakashi Iwai } 31529eb413e5STakashi Iwai 3153352f7f91STakashi Iwai if (!cfg->line_outs) { 3154352f7f91STakashi Iwai if (cfg->dig_outs || cfg->dig_in_pin) { 3155352f7f91STakashi Iwai spec->multiout.max_channels = 2; 3156352f7f91STakashi Iwai spec->no_analog = 1; 3157352f7f91STakashi Iwai goto dig_only; 3158352f7f91STakashi Iwai } 3159352f7f91STakashi Iwai return 0; /* can't find valid BIOS pin config */ 3160352f7f91STakashi Iwai } 3161352f7f91STakashi Iwai 3162352f7f91STakashi Iwai if (!spec->no_primary_hp && 3163352f7f91STakashi Iwai cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && 3164352f7f91STakashi Iwai cfg->line_outs <= cfg->hp_outs) { 3165352f7f91STakashi Iwai /* use HP as primary out */ 3166352f7f91STakashi Iwai cfg->speaker_outs = cfg->line_outs; 3167352f7f91STakashi Iwai memcpy(cfg->speaker_pins, cfg->line_out_pins, 3168352f7f91STakashi Iwai sizeof(cfg->speaker_pins)); 3169352f7f91STakashi Iwai cfg->line_outs = cfg->hp_outs; 3170352f7f91STakashi Iwai memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); 3171352f7f91STakashi Iwai cfg->hp_outs = 0; 3172352f7f91STakashi Iwai memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); 3173352f7f91STakashi Iwai cfg->line_out_type = AUTO_PIN_HP_OUT; 3174352f7f91STakashi Iwai } 3175352f7f91STakashi Iwai 3176352f7f91STakashi Iwai err = parse_output_paths(codec); 3177352f7f91STakashi Iwai if (err < 0) 3178352f7f91STakashi Iwai return err; 3179352f7f91STakashi Iwai err = create_multi_channel_mode(codec); 3180352f7f91STakashi Iwai if (err < 0) 3181352f7f91STakashi Iwai return err; 3182352f7f91STakashi Iwai err = create_multi_out_ctls(codec, cfg); 3183352f7f91STakashi Iwai if (err < 0) 3184352f7f91STakashi Iwai return err; 3185352f7f91STakashi Iwai err = create_hp_out_ctls(codec); 3186352f7f91STakashi Iwai if (err < 0) 3187352f7f91STakashi Iwai return err; 3188352f7f91STakashi Iwai err = create_speaker_out_ctls(codec); 3189352f7f91STakashi Iwai if (err < 0) 3190352f7f91STakashi Iwai return err; 319138cf6f1aSTakashi Iwai err = create_indep_hp_ctls(codec); 319238cf6f1aSTakashi Iwai if (err < 0) 319338cf6f1aSTakashi Iwai return err; 3194c30aa7b2STakashi Iwai err = create_loopback_mixing_ctl(codec); 3195c30aa7b2STakashi Iwai if (err < 0) 3196c30aa7b2STakashi Iwai return err; 3197352f7f91STakashi Iwai err = create_shared_input(codec); 3198352f7f91STakashi Iwai if (err < 0) 3199352f7f91STakashi Iwai return err; 3200352f7f91STakashi Iwai err = create_input_ctls(codec); 3201352f7f91STakashi Iwai if (err < 0) 3202352f7f91STakashi Iwai return err; 3203352f7f91STakashi Iwai 3204352f7f91STakashi Iwai /* check the multiple speaker pins */ 3205352f7f91STakashi Iwai if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) 3206352f7f91STakashi Iwai spec->const_channel_count = cfg->line_outs * 2; 3207352f7f91STakashi Iwai else 3208352f7f91STakashi Iwai spec->const_channel_count = cfg->speaker_outs * 2; 3209352f7f91STakashi Iwai 3210352f7f91STakashi Iwai if (spec->multi_ios > 0) 3211352f7f91STakashi Iwai spec->multiout.max_channels = max(spec->ext_channel_count, 3212352f7f91STakashi Iwai spec->const_channel_count); 3213352f7f91STakashi Iwai else 3214352f7f91STakashi Iwai spec->multiout.max_channels = spec->multiout.num_dacs * 2; 3215352f7f91STakashi Iwai 3216352f7f91STakashi Iwai err = check_auto_mute_availability(codec); 3217352f7f91STakashi Iwai if (err < 0) 3218352f7f91STakashi Iwai return err; 3219352f7f91STakashi Iwai 3220352f7f91STakashi Iwai err = check_dyn_adc_switch(codec); 3221352f7f91STakashi Iwai if (err < 0) 3222352f7f91STakashi Iwai return err; 3223352f7f91STakashi Iwai 3224352f7f91STakashi Iwai if (!spec->shared_mic_hp) { 3225352f7f91STakashi Iwai err = check_auto_mic_availability(codec); 3226352f7f91STakashi Iwai if (err < 0) 3227352f7f91STakashi Iwai return err; 3228352f7f91STakashi Iwai } 3229352f7f91STakashi Iwai 3230352f7f91STakashi Iwai err = create_capture_mixers(codec); 3231352f7f91STakashi Iwai if (err < 0) 3232352f7f91STakashi Iwai return err; 3233352f7f91STakashi Iwai 3234352f7f91STakashi Iwai err = parse_mic_boost(codec); 3235352f7f91STakashi Iwai if (err < 0) 3236352f7f91STakashi Iwai return err; 3237352f7f91STakashi Iwai 3238352f7f91STakashi Iwai dig_only: 3239352f7f91STakashi Iwai parse_digital(codec); 3240352f7f91STakashi Iwai 3241352f7f91STakashi Iwai return 1; 3242352f7f91STakashi Iwai } 3243352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_parse_auto_config); 3244352f7f91STakashi Iwai 3245352f7f91STakashi Iwai 3246352f7f91STakashi Iwai /* 3247352f7f91STakashi Iwai * Build control elements 3248352f7f91STakashi Iwai */ 3249352f7f91STakashi Iwai 3250352f7f91STakashi Iwai /* slave controls for virtual master */ 3251352f7f91STakashi Iwai static const char * const slave_pfxs[] = { 3252352f7f91STakashi Iwai "Front", "Surround", "Center", "LFE", "Side", 3253352f7f91STakashi Iwai "Headphone", "Speaker", "Mono", "Line Out", 3254352f7f91STakashi Iwai "CLFE", "Bass Speaker", "PCM", 3255ee79c69aSTakashi Iwai "Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side", 3256ee79c69aSTakashi Iwai "Headphone Front", "Headphone Surround", "Headphone CLFE", 3257ee79c69aSTakashi Iwai "Headphone Side", 3258352f7f91STakashi Iwai NULL, 3259352f7f91STakashi Iwai }; 3260352f7f91STakashi Iwai 3261352f7f91STakashi Iwai int snd_hda_gen_build_controls(struct hda_codec *codec) 3262352f7f91STakashi Iwai { 3263352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3264352f7f91STakashi Iwai int err; 3265352f7f91STakashi Iwai 326636502d02STakashi Iwai if (spec->kctls.used) { 3267352f7f91STakashi Iwai err = snd_hda_add_new_ctls(codec, spec->kctls.list); 3268352f7f91STakashi Iwai if (err < 0) 3269352f7f91STakashi Iwai return err; 327036502d02STakashi Iwai } 3271352f7f91STakashi Iwai 3272352f7f91STakashi Iwai if (spec->multiout.dig_out_nid) { 3273352f7f91STakashi Iwai err = snd_hda_create_dig_out_ctls(codec, 3274352f7f91STakashi Iwai spec->multiout.dig_out_nid, 3275352f7f91STakashi Iwai spec->multiout.dig_out_nid, 3276352f7f91STakashi Iwai spec->pcm_rec[1].pcm_type); 3277352f7f91STakashi Iwai if (err < 0) 3278352f7f91STakashi Iwai return err; 3279352f7f91STakashi Iwai if (!spec->no_analog) { 3280352f7f91STakashi Iwai err = snd_hda_create_spdif_share_sw(codec, 3281352f7f91STakashi Iwai &spec->multiout); 3282352f7f91STakashi Iwai if (err < 0) 3283352f7f91STakashi Iwai return err; 3284352f7f91STakashi Iwai spec->multiout.share_spdif = 1; 3285352f7f91STakashi Iwai } 3286352f7f91STakashi Iwai } 3287352f7f91STakashi Iwai if (spec->dig_in_nid) { 3288352f7f91STakashi Iwai err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 3289352f7f91STakashi Iwai if (err < 0) 3290352f7f91STakashi Iwai return err; 3291352f7f91STakashi Iwai } 3292352f7f91STakashi Iwai 3293352f7f91STakashi Iwai /* if we have no master control, let's create it */ 3294352f7f91STakashi Iwai if (!spec->no_analog && 3295352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { 3296352f7f91STakashi Iwai unsigned int vmaster_tlv[4]; 3297352f7f91STakashi Iwai snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, 3298352f7f91STakashi Iwai HDA_OUTPUT, vmaster_tlv); 3299352f7f91STakashi Iwai err = snd_hda_add_vmaster(codec, "Master Playback Volume", 3300352f7f91STakashi Iwai vmaster_tlv, slave_pfxs, 3301352f7f91STakashi Iwai "Playback Volume"); 3302352f7f91STakashi Iwai if (err < 0) 3303352f7f91STakashi Iwai return err; 3304352f7f91STakashi Iwai } 3305352f7f91STakashi Iwai if (!spec->no_analog && 3306352f7f91STakashi Iwai !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { 3307352f7f91STakashi Iwai err = __snd_hda_add_vmaster(codec, "Master Playback Switch", 3308352f7f91STakashi Iwai NULL, slave_pfxs, 3309352f7f91STakashi Iwai "Playback Switch", 3310352f7f91STakashi Iwai true, &spec->vmaster_mute.sw_kctl); 3311352f7f91STakashi Iwai if (err < 0) 3312352f7f91STakashi Iwai return err; 3313352f7f91STakashi Iwai if (spec->vmaster_mute.hook) 3314fd25a97aSTakashi Iwai snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, 3315fd25a97aSTakashi Iwai spec->vmaster_mute_enum); 3316352f7f91STakashi Iwai } 3317352f7f91STakashi Iwai 3318352f7f91STakashi Iwai free_kctls(spec); /* no longer needed */ 3319352f7f91STakashi Iwai 3320352f7f91STakashi Iwai if (spec->shared_mic_hp) { 3321352f7f91STakashi Iwai int err; 3322352f7f91STakashi Iwai int nid = spec->autocfg.inputs[1].pin; 3323352f7f91STakashi Iwai err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0); 3324352f7f91STakashi Iwai if (err < 0) 3325352f7f91STakashi Iwai return err; 3326352f7f91STakashi Iwai err = snd_hda_jack_detect_enable(codec, nid, 0); 3327352f7f91STakashi Iwai if (err < 0) 3328352f7f91STakashi Iwai return err; 3329352f7f91STakashi Iwai } 3330352f7f91STakashi Iwai 3331352f7f91STakashi Iwai err = snd_hda_jack_add_kctls(codec, &spec->autocfg); 3332352f7f91STakashi Iwai if (err < 0) 3333352f7f91STakashi Iwai return err; 3334352f7f91STakashi Iwai 3335352f7f91STakashi Iwai return 0; 3336352f7f91STakashi Iwai } 3337352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_controls); 3338352f7f91STakashi Iwai 3339352f7f91STakashi Iwai 3340352f7f91STakashi Iwai /* 3341352f7f91STakashi Iwai * PCM definitions 3342352f7f91STakashi Iwai */ 3343352f7f91STakashi Iwai 3344352f7f91STakashi Iwai /* 3345352f7f91STakashi Iwai * Analog playback callbacks 3346352f7f91STakashi Iwai */ 3347352f7f91STakashi Iwai static int playback_pcm_open(struct hda_pcm_stream *hinfo, 3348352f7f91STakashi Iwai struct hda_codec *codec, 3349352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3350352f7f91STakashi Iwai { 3351352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 335238cf6f1aSTakashi Iwai int err; 335338cf6f1aSTakashi Iwai 335438cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 335538cf6f1aSTakashi Iwai err = snd_hda_multi_out_analog_open(codec, 335638cf6f1aSTakashi Iwai &spec->multiout, substream, 3357352f7f91STakashi Iwai hinfo); 335838cf6f1aSTakashi Iwai if (!err) 335938cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_MULTI_OUT; 336038cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 336138cf6f1aSTakashi Iwai return err; 3362352f7f91STakashi Iwai } 3363352f7f91STakashi Iwai 3364352f7f91STakashi Iwai static int playback_pcm_prepare(struct hda_pcm_stream *hinfo, 336597ec558aSTakashi Iwai struct hda_codec *codec, 336697ec558aSTakashi Iwai unsigned int stream_tag, 336797ec558aSTakashi Iwai unsigned int format, 336897ec558aSTakashi Iwai struct snd_pcm_substream *substream) 336997ec558aSTakashi Iwai { 3370352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3371352f7f91STakashi Iwai return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, 3372352f7f91STakashi Iwai stream_tag, format, substream); 3373352f7f91STakashi Iwai } 337497ec558aSTakashi Iwai 3375352f7f91STakashi Iwai static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 3376352f7f91STakashi Iwai struct hda_codec *codec, 3377352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3378352f7f91STakashi Iwai { 3379352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3380352f7f91STakashi Iwai return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); 3381352f7f91STakashi Iwai } 3382352f7f91STakashi Iwai 338338cf6f1aSTakashi Iwai static int playback_pcm_close(struct hda_pcm_stream *hinfo, 338438cf6f1aSTakashi Iwai struct hda_codec *codec, 338538cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 338638cf6f1aSTakashi Iwai { 338738cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 338838cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 338938cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_MULTI_OUT); 339038cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 339138cf6f1aSTakashi Iwai return 0; 339238cf6f1aSTakashi Iwai } 339338cf6f1aSTakashi Iwai 339438cf6f1aSTakashi Iwai static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo, 339538cf6f1aSTakashi Iwai struct hda_codec *codec, 339638cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 339738cf6f1aSTakashi Iwai { 339838cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 339938cf6f1aSTakashi Iwai int err = 0; 340038cf6f1aSTakashi Iwai 340138cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 340238cf6f1aSTakashi Iwai if (!spec->indep_hp_enabled) 340338cf6f1aSTakashi Iwai err = -EBUSY; 340438cf6f1aSTakashi Iwai else 340538cf6f1aSTakashi Iwai spec->active_streams |= 1 << STREAM_INDEP_HP; 340638cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 340738cf6f1aSTakashi Iwai return err; 340838cf6f1aSTakashi Iwai } 340938cf6f1aSTakashi Iwai 341038cf6f1aSTakashi Iwai static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo, 341138cf6f1aSTakashi Iwai struct hda_codec *codec, 341238cf6f1aSTakashi Iwai struct snd_pcm_substream *substream) 341338cf6f1aSTakashi Iwai { 341438cf6f1aSTakashi Iwai struct hda_gen_spec *spec = codec->spec; 341538cf6f1aSTakashi Iwai mutex_lock(&spec->pcm_mutex); 341638cf6f1aSTakashi Iwai spec->active_streams &= ~(1 << STREAM_INDEP_HP); 341738cf6f1aSTakashi Iwai mutex_unlock(&spec->pcm_mutex); 341838cf6f1aSTakashi Iwai return 0; 341938cf6f1aSTakashi Iwai } 342038cf6f1aSTakashi Iwai 3421352f7f91STakashi Iwai /* 3422352f7f91STakashi Iwai * Digital out 3423352f7f91STakashi Iwai */ 3424352f7f91STakashi Iwai static int dig_playback_pcm_open(struct hda_pcm_stream *hinfo, 3425352f7f91STakashi Iwai struct hda_codec *codec, 3426352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3427352f7f91STakashi Iwai { 3428352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3429352f7f91STakashi Iwai return snd_hda_multi_out_dig_open(codec, &spec->multiout); 3430352f7f91STakashi Iwai } 3431352f7f91STakashi Iwai 3432352f7f91STakashi Iwai static int dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 3433352f7f91STakashi Iwai struct hda_codec *codec, 3434352f7f91STakashi Iwai unsigned int stream_tag, 3435352f7f91STakashi Iwai unsigned int format, 3436352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3437352f7f91STakashi Iwai { 3438352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3439352f7f91STakashi Iwai return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, 3440352f7f91STakashi Iwai stream_tag, format, substream); 3441352f7f91STakashi Iwai } 3442352f7f91STakashi Iwai 3443352f7f91STakashi Iwai static int dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 3444352f7f91STakashi Iwai struct hda_codec *codec, 3445352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3446352f7f91STakashi Iwai { 3447352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3448352f7f91STakashi Iwai return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); 3449352f7f91STakashi Iwai } 3450352f7f91STakashi Iwai 3451352f7f91STakashi Iwai static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo, 3452352f7f91STakashi Iwai struct hda_codec *codec, 3453352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3454352f7f91STakashi Iwai { 3455352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3456352f7f91STakashi Iwai return snd_hda_multi_out_dig_close(codec, &spec->multiout); 3457352f7f91STakashi Iwai } 3458352f7f91STakashi Iwai 3459352f7f91STakashi Iwai /* 3460352f7f91STakashi Iwai * Analog capture 3461352f7f91STakashi Iwai */ 3462352f7f91STakashi Iwai static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 3463352f7f91STakashi Iwai struct hda_codec *codec, 3464352f7f91STakashi Iwai unsigned int stream_tag, 3465352f7f91STakashi Iwai unsigned int format, 3466352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3467352f7f91STakashi Iwai { 3468352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3469352f7f91STakashi Iwai 3470352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], 347197ec558aSTakashi Iwai stream_tag, 0, format); 347297ec558aSTakashi Iwai return 0; 347397ec558aSTakashi Iwai } 347497ec558aSTakashi Iwai 3475352f7f91STakashi Iwai static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 347697ec558aSTakashi Iwai struct hda_codec *codec, 347797ec558aSTakashi Iwai struct snd_pcm_substream *substream) 347897ec558aSTakashi Iwai { 3479352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 348097ec558aSTakashi Iwai 3481352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, 3482352f7f91STakashi Iwai spec->adc_nids[substream->number + 1]); 348397ec558aSTakashi Iwai return 0; 348497ec558aSTakashi Iwai } 348597ec558aSTakashi Iwai 3486352f7f91STakashi Iwai /* 3487352f7f91STakashi Iwai */ 3488352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_playback = { 3489352f7f91STakashi Iwai .substreams = 1, 3490352f7f91STakashi Iwai .channels_min = 2, 3491352f7f91STakashi Iwai .channels_max = 8, 3492352f7f91STakashi Iwai /* NID is set in build_pcms */ 3493352f7f91STakashi Iwai .ops = { 3494352f7f91STakashi Iwai .open = playback_pcm_open, 349538cf6f1aSTakashi Iwai .close = playback_pcm_close, 3496352f7f91STakashi Iwai .prepare = playback_pcm_prepare, 3497352f7f91STakashi Iwai .cleanup = playback_pcm_cleanup 3498352f7f91STakashi Iwai }, 3499352f7f91STakashi Iwai }; 3500352f7f91STakashi Iwai 3501352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_capture = { 3502352f7f91STakashi Iwai .substreams = 1, 3503352f7f91STakashi Iwai .channels_min = 2, 3504352f7f91STakashi Iwai .channels_max = 2, 3505352f7f91STakashi Iwai /* NID is set in build_pcms */ 3506352f7f91STakashi Iwai }; 3507352f7f91STakashi Iwai 3508352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_playback = { 3509352f7f91STakashi Iwai .substreams = 1, 3510352f7f91STakashi Iwai .channels_min = 2, 3511352f7f91STakashi Iwai .channels_max = 2, 3512352f7f91STakashi Iwai /* NID is set in build_pcms */ 351338cf6f1aSTakashi Iwai .ops = { 351438cf6f1aSTakashi Iwai .open = alt_playback_pcm_open, 351538cf6f1aSTakashi Iwai .close = alt_playback_pcm_close 351638cf6f1aSTakashi Iwai }, 3517352f7f91STakashi Iwai }; 3518352f7f91STakashi Iwai 3519352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_analog_alt_capture = { 3520352f7f91STakashi Iwai .substreams = 2, /* can be overridden */ 3521352f7f91STakashi Iwai .channels_min = 2, 3522352f7f91STakashi Iwai .channels_max = 2, 3523352f7f91STakashi Iwai /* NID is set in build_pcms */ 3524352f7f91STakashi Iwai .ops = { 3525352f7f91STakashi Iwai .prepare = alt_capture_pcm_prepare, 3526352f7f91STakashi Iwai .cleanup = alt_capture_pcm_cleanup 3527352f7f91STakashi Iwai }, 3528352f7f91STakashi Iwai }; 3529352f7f91STakashi Iwai 3530352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_playback = { 3531352f7f91STakashi Iwai .substreams = 1, 3532352f7f91STakashi Iwai .channels_min = 2, 3533352f7f91STakashi Iwai .channels_max = 2, 3534352f7f91STakashi Iwai /* NID is set in build_pcms */ 3535352f7f91STakashi Iwai .ops = { 3536352f7f91STakashi Iwai .open = dig_playback_pcm_open, 3537352f7f91STakashi Iwai .close = dig_playback_pcm_close, 3538352f7f91STakashi Iwai .prepare = dig_playback_pcm_prepare, 3539352f7f91STakashi Iwai .cleanup = dig_playback_pcm_cleanup 3540352f7f91STakashi Iwai }, 3541352f7f91STakashi Iwai }; 3542352f7f91STakashi Iwai 3543352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_digital_capture = { 3544352f7f91STakashi Iwai .substreams = 1, 3545352f7f91STakashi Iwai .channels_min = 2, 3546352f7f91STakashi Iwai .channels_max = 2, 3547352f7f91STakashi Iwai /* NID is set in build_pcms */ 3548352f7f91STakashi Iwai }; 3549352f7f91STakashi Iwai 3550352f7f91STakashi Iwai /* Used by build_pcms to flag that a PCM has no playback stream */ 3551352f7f91STakashi Iwai static const struct hda_pcm_stream pcm_null_stream = { 3552352f7f91STakashi Iwai .substreams = 0, 3553352f7f91STakashi Iwai .channels_min = 0, 3554352f7f91STakashi Iwai .channels_max = 0, 3555352f7f91STakashi Iwai }; 3556352f7f91STakashi Iwai 3557352f7f91STakashi Iwai /* 3558352f7f91STakashi Iwai * dynamic changing ADC PCM streams 3559352f7f91STakashi Iwai */ 3560352f7f91STakashi Iwai static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) 35611da177e4SLinus Torvalds { 3562352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3563352f7f91STakashi Iwai hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]]; 35641da177e4SLinus Torvalds 3565352f7f91STakashi Iwai if (spec->cur_adc && spec->cur_adc != new_adc) { 3566352f7f91STakashi Iwai /* stream is running, let's swap the current ADC */ 3567352f7f91STakashi Iwai __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); 3568352f7f91STakashi Iwai spec->cur_adc = new_adc; 3569352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, new_adc, 3570352f7f91STakashi Iwai spec->cur_adc_stream_tag, 0, 3571352f7f91STakashi Iwai spec->cur_adc_format); 3572352f7f91STakashi Iwai return true; 3573352f7f91STakashi Iwai } 3574352f7f91STakashi Iwai return false; 3575352f7f91STakashi Iwai } 3576352f7f91STakashi Iwai 3577352f7f91STakashi Iwai /* analog capture with dynamic dual-adc changes */ 3578352f7f91STakashi Iwai static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 3579352f7f91STakashi Iwai struct hda_codec *codec, 3580352f7f91STakashi Iwai unsigned int stream_tag, 3581352f7f91STakashi Iwai unsigned int format, 3582352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3583352f7f91STakashi Iwai { 3584352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3585352f7f91STakashi Iwai spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]]; 3586352f7f91STakashi Iwai spec->cur_adc_stream_tag = stream_tag; 3587352f7f91STakashi Iwai spec->cur_adc_format = format; 3588352f7f91STakashi Iwai snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); 35891da177e4SLinus Torvalds return 0; 35901da177e4SLinus Torvalds } 35911da177e4SLinus Torvalds 3592352f7f91STakashi Iwai static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 3593352f7f91STakashi Iwai struct hda_codec *codec, 3594352f7f91STakashi Iwai struct snd_pcm_substream *substream) 3595352f7f91STakashi Iwai { 3596352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3597352f7f91STakashi Iwai snd_hda_codec_cleanup_stream(codec, spec->cur_adc); 3598352f7f91STakashi Iwai spec->cur_adc = 0; 3599352f7f91STakashi Iwai return 0; 3600352f7f91STakashi Iwai } 3601352f7f91STakashi Iwai 3602352f7f91STakashi Iwai static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = { 3603352f7f91STakashi Iwai .substreams = 1, 3604352f7f91STakashi Iwai .channels_min = 2, 3605352f7f91STakashi Iwai .channels_max = 2, 3606352f7f91STakashi Iwai .nid = 0, /* fill later */ 3607352f7f91STakashi Iwai .ops = { 3608352f7f91STakashi Iwai .prepare = dyn_adc_capture_pcm_prepare, 3609352f7f91STakashi Iwai .cleanup = dyn_adc_capture_pcm_cleanup 3610352f7f91STakashi Iwai }, 3611352f7f91STakashi Iwai }; 3612352f7f91STakashi Iwai 3613f873e536STakashi Iwai static void fill_pcm_stream_name(char *str, size_t len, const char *sfx, 3614f873e536STakashi Iwai const char *chip_name) 3615f873e536STakashi Iwai { 3616f873e536STakashi Iwai char *p; 3617f873e536STakashi Iwai 3618f873e536STakashi Iwai if (*str) 3619f873e536STakashi Iwai return; 3620f873e536STakashi Iwai strlcpy(str, chip_name, len); 3621f873e536STakashi Iwai 3622f873e536STakashi Iwai /* drop non-alnum chars after a space */ 3623f873e536STakashi Iwai for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) { 3624f873e536STakashi Iwai if (!isalnum(p[1])) { 3625f873e536STakashi Iwai *p = 0; 3626f873e536STakashi Iwai break; 3627f873e536STakashi Iwai } 3628f873e536STakashi Iwai } 3629f873e536STakashi Iwai strlcat(str, sfx, len); 3630f873e536STakashi Iwai } 3631f873e536STakashi Iwai 3632352f7f91STakashi Iwai /* build PCM streams based on the parsed results */ 3633352f7f91STakashi Iwai int snd_hda_gen_build_pcms(struct hda_codec *codec) 3634352f7f91STakashi Iwai { 3635352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3636352f7f91STakashi Iwai struct hda_pcm *info = spec->pcm_rec; 3637352f7f91STakashi Iwai const struct hda_pcm_stream *p; 3638352f7f91STakashi Iwai bool have_multi_adcs; 3639352f7f91STakashi Iwai 36401da177e4SLinus Torvalds codec->num_pcms = 1; 36411da177e4SLinus Torvalds codec->pcm_info = info; 36421da177e4SLinus Torvalds 3643352f7f91STakashi Iwai if (spec->no_analog) 3644352f7f91STakashi Iwai goto skip_analog; 3645352f7f91STakashi Iwai 3646f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_analog, 3647f873e536STakashi Iwai sizeof(spec->stream_name_analog), 3648f873e536STakashi Iwai " Analog", codec->chip_name); 3649352f7f91STakashi Iwai info->name = spec->stream_name_analog; 3650352f7f91STakashi Iwai 3651352f7f91STakashi Iwai if (spec->multiout.num_dacs > 0) { 3652352f7f91STakashi Iwai p = spec->stream_analog_playback; 3653352f7f91STakashi Iwai if (!p) 3654352f7f91STakashi Iwai p = &pcm_analog_playback; 3655352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 3656352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; 3657352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 3658352f7f91STakashi Iwai spec->multiout.max_channels; 3659352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT && 3660352f7f91STakashi Iwai spec->autocfg.line_outs == 2) 3661352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap = 3662352f7f91STakashi Iwai snd_pcm_2_1_chmaps; 3663352f7f91STakashi Iwai } 3664352f7f91STakashi Iwai if (spec->num_adc_nids) { 3665352f7f91STakashi Iwai p = spec->stream_analog_capture; 3666352f7f91STakashi Iwai if (!p) { 3667352f7f91STakashi Iwai if (spec->dyn_adc_switch) 3668352f7f91STakashi Iwai p = &dyn_adc_pcm_analog_capture; 3669352f7f91STakashi Iwai else 3670352f7f91STakashi Iwai p = &pcm_analog_capture; 3671352f7f91STakashi Iwai } 3672352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 3673352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; 3674352f7f91STakashi Iwai } 3675352f7f91STakashi Iwai 3676352f7f91STakashi Iwai skip_analog: 3677352f7f91STakashi Iwai /* SPDIF for stream index #1 */ 3678352f7f91STakashi Iwai if (spec->multiout.dig_out_nid || spec->dig_in_nid) { 3679f873e536STakashi Iwai fill_pcm_stream_name(spec->stream_name_digital, 3680352f7f91STakashi Iwai sizeof(spec->stream_name_digital), 3681f873e536STakashi Iwai " Digital", codec->chip_name); 3682352f7f91STakashi Iwai codec->num_pcms = 2; 3683352f7f91STakashi Iwai codec->slave_dig_outs = spec->multiout.slave_dig_outs; 3684352f7f91STakashi Iwai info = spec->pcm_rec + 1; 3685352f7f91STakashi Iwai info->name = spec->stream_name_digital; 3686352f7f91STakashi Iwai if (spec->dig_out_type) 3687352f7f91STakashi Iwai info->pcm_type = spec->dig_out_type; 3688352f7f91STakashi Iwai else 3689352f7f91STakashi Iwai info->pcm_type = HDA_PCM_TYPE_SPDIF; 3690352f7f91STakashi Iwai if (spec->multiout.dig_out_nid) { 3691352f7f91STakashi Iwai p = spec->stream_digital_playback; 3692352f7f91STakashi Iwai if (!p) 3693352f7f91STakashi Iwai p = &pcm_digital_playback; 3694352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 3695352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; 3696352f7f91STakashi Iwai } 3697352f7f91STakashi Iwai if (spec->dig_in_nid) { 3698352f7f91STakashi Iwai p = spec->stream_digital_capture; 3699352f7f91STakashi Iwai if (!p) 3700352f7f91STakashi Iwai p = &pcm_digital_capture; 3701352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 3702352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; 3703352f7f91STakashi Iwai } 3704352f7f91STakashi Iwai } 3705352f7f91STakashi Iwai 3706352f7f91STakashi Iwai if (spec->no_analog) 3707352f7f91STakashi Iwai return 0; 3708352f7f91STakashi Iwai 3709352f7f91STakashi Iwai /* If the use of more than one ADC is requested for the current 3710352f7f91STakashi Iwai * model, configure a second analog capture-only PCM. 3711352f7f91STakashi Iwai */ 3712352f7f91STakashi Iwai have_multi_adcs = (spec->num_adc_nids > 1) && 3713352f7f91STakashi Iwai !spec->dyn_adc_switch && !spec->auto_mic; 3714352f7f91STakashi Iwai /* Additional Analaog capture for index #2 */ 3715352f7f91STakashi Iwai if (spec->alt_dac_nid || have_multi_adcs) { 3716352f7f91STakashi Iwai codec->num_pcms = 3; 3717352f7f91STakashi Iwai info = spec->pcm_rec + 2; 3718352f7f91STakashi Iwai info->name = spec->stream_name_analog; 3719352f7f91STakashi Iwai if (spec->alt_dac_nid) { 3720352f7f91STakashi Iwai p = spec->stream_analog_alt_playback; 3721352f7f91STakashi Iwai if (!p) 3722352f7f91STakashi Iwai p = &pcm_analog_alt_playback; 3723352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; 3724352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 3725352f7f91STakashi Iwai spec->alt_dac_nid; 3726352f7f91STakashi Iwai } else { 3727352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK] = 3728352f7f91STakashi Iwai pcm_null_stream; 3729352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; 3730352f7f91STakashi Iwai } 3731352f7f91STakashi Iwai if (have_multi_adcs) { 3732352f7f91STakashi Iwai p = spec->stream_analog_alt_capture; 3733352f7f91STakashi Iwai if (!p) 3734352f7f91STakashi Iwai p = &pcm_analog_alt_capture; 3735352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; 3736352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 3737352f7f91STakashi Iwai spec->adc_nids[1]; 3738352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 3739352f7f91STakashi Iwai spec->num_adc_nids - 1; 3740352f7f91STakashi Iwai } else { 3741352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE] = 3742352f7f91STakashi Iwai pcm_null_stream; 3743352f7f91STakashi Iwai info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0; 3744352f7f91STakashi Iwai } 37451da177e4SLinus Torvalds } 37461da177e4SLinus Torvalds 37471da177e4SLinus Torvalds return 0; 37481da177e4SLinus Torvalds } 3749352f7f91STakashi Iwai EXPORT_SYMBOL_HDA(snd_hda_gen_build_pcms); 3750352f7f91STakashi Iwai 3751352f7f91STakashi Iwai 3752352f7f91STakashi Iwai /* 3753352f7f91STakashi Iwai * Standard auto-parser initializations 3754352f7f91STakashi Iwai */ 3755352f7f91STakashi Iwai 3756352f7f91STakashi Iwai /* configure the path from the given dac to the pin as the proper output */ 3757352f7f91STakashi Iwai static void set_output_and_unmute(struct hda_codec *codec, hda_nid_t pin, 3758196c1766STakashi Iwai int pin_type, int path_idx) 3759352f7f91STakashi Iwai { 3760352f7f91STakashi Iwai struct nid_path *path; 3761352f7f91STakashi Iwai 3762352f7f91STakashi Iwai snd_hda_set_pin_ctl_cache(codec, pin, pin_type); 3763196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, path_idx); 3764352f7f91STakashi Iwai if (!path) 3765352f7f91STakashi Iwai return; 3766e1284af7STakashi Iwai snd_hda_activate_path(codec, path, path->active, true); 3767e1284af7STakashi Iwai set_pin_eapd(codec, pin, path->active); 3768352f7f91STakashi Iwai } 3769352f7f91STakashi Iwai 3770352f7f91STakashi Iwai /* initialize primary output paths */ 3771352f7f91STakashi Iwai static void init_multi_out(struct hda_codec *codec) 3772352f7f91STakashi Iwai { 3773352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3774196c1766STakashi Iwai hda_nid_t nid; 3775352f7f91STakashi Iwai int pin_type; 3776352f7f91STakashi Iwai int i; 3777352f7f91STakashi Iwai 3778352f7f91STakashi Iwai if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) 3779352f7f91STakashi Iwai pin_type = PIN_HP; 3780352f7f91STakashi Iwai else 3781352f7f91STakashi Iwai pin_type = PIN_OUT; 3782352f7f91STakashi Iwai 378364049c81STakashi Iwai for (i = 0; i < spec->autocfg.line_outs; i++) { 378464049c81STakashi Iwai nid = spec->autocfg.line_out_pins[i]; 3785196c1766STakashi Iwai if (nid) 3786196c1766STakashi Iwai set_output_and_unmute(codec, nid, pin_type, 3787196c1766STakashi Iwai spec->out_paths[i]); 3788352f7f91STakashi Iwai } 3789352f7f91STakashi Iwai } 3790352f7f91STakashi Iwai 3791db23fd19STakashi Iwai 3792db23fd19STakashi Iwai static void __init_extra_out(struct hda_codec *codec, int num_outs, 3793196c1766STakashi Iwai hda_nid_t *pins, int *paths, int type) 3794352f7f91STakashi Iwai { 3795352f7f91STakashi Iwai int i; 3796196c1766STakashi Iwai hda_nid_t pin; 3797352f7f91STakashi Iwai 3798db23fd19STakashi Iwai for (i = 0; i < num_outs; i++) { 3799db23fd19STakashi Iwai pin = pins[i]; 3800352f7f91STakashi Iwai if (!pin) 3801352f7f91STakashi Iwai break; 3802196c1766STakashi Iwai set_output_and_unmute(codec, pin, type, paths[i]); 3803352f7f91STakashi Iwai } 3804352f7f91STakashi Iwai } 3805db23fd19STakashi Iwai 3806db23fd19STakashi Iwai /* initialize hp and speaker paths */ 3807db23fd19STakashi Iwai static void init_extra_out(struct hda_codec *codec) 3808db23fd19STakashi Iwai { 3809db23fd19STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3810db23fd19STakashi Iwai 3811db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) 3812db23fd19STakashi Iwai __init_extra_out(codec, spec->autocfg.hp_outs, 3813db23fd19STakashi Iwai spec->autocfg.hp_pins, 3814196c1766STakashi Iwai spec->hp_paths, PIN_HP); 3815db23fd19STakashi Iwai if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) 3816db23fd19STakashi Iwai __init_extra_out(codec, spec->autocfg.speaker_outs, 3817db23fd19STakashi Iwai spec->autocfg.speaker_pins, 3818196c1766STakashi Iwai spec->speaker_paths, PIN_OUT); 3819352f7f91STakashi Iwai } 3820352f7f91STakashi Iwai 3821352f7f91STakashi Iwai /* initialize multi-io paths */ 3822352f7f91STakashi Iwai static void init_multi_io(struct hda_codec *codec) 3823352f7f91STakashi Iwai { 3824352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3825352f7f91STakashi Iwai int i; 3826352f7f91STakashi Iwai 3827352f7f91STakashi Iwai for (i = 0; i < spec->multi_ios; i++) { 3828352f7f91STakashi Iwai hda_nid_t pin = spec->multi_io[i].pin; 3829352f7f91STakashi Iwai struct nid_path *path; 3830196c1766STakashi Iwai path = get_multiio_path(codec, i); 3831352f7f91STakashi Iwai if (!path) 3832352f7f91STakashi Iwai continue; 3833352f7f91STakashi Iwai if (!spec->multi_io[i].ctl_in) 3834352f7f91STakashi Iwai spec->multi_io[i].ctl_in = 3835352f7f91STakashi Iwai snd_hda_codec_update_cache(codec, pin, 0, 3836352f7f91STakashi Iwai AC_VERB_GET_PIN_WIDGET_CONTROL, 0); 3837352f7f91STakashi Iwai snd_hda_activate_path(codec, path, path->active, true); 3838352f7f91STakashi Iwai } 3839352f7f91STakashi Iwai } 3840352f7f91STakashi Iwai 3841352f7f91STakashi Iwai /* set up the input pin config, depending on the given auto-pin type */ 3842352f7f91STakashi Iwai static void set_input_pin(struct hda_codec *codec, hda_nid_t nid, 3843352f7f91STakashi Iwai int auto_pin_type) 3844352f7f91STakashi Iwai { 3845352f7f91STakashi Iwai unsigned int val = PIN_IN; 3846352f7f91STakashi Iwai if (auto_pin_type == AUTO_PIN_MIC) 3847352f7f91STakashi Iwai val |= snd_hda_get_default_vref(codec, nid); 38487594aa33STakashi Iwai snd_hda_set_pin_ctl_cache(codec, nid, val); 3849352f7f91STakashi Iwai } 3850352f7f91STakashi Iwai 3851352f7f91STakashi Iwai /* set up input pins and loopback paths */ 3852352f7f91STakashi Iwai static void init_analog_input(struct hda_codec *codec) 3853352f7f91STakashi Iwai { 3854352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3855352f7f91STakashi Iwai struct auto_pin_cfg *cfg = &spec->autocfg; 3856352f7f91STakashi Iwai int i; 3857352f7f91STakashi Iwai 3858352f7f91STakashi Iwai for (i = 0; i < cfg->num_inputs; i++) { 3859352f7f91STakashi Iwai hda_nid_t nid = cfg->inputs[i].pin; 3860352f7f91STakashi Iwai if (is_input_pin(codec, nid)) 3861352f7f91STakashi Iwai set_input_pin(codec, nid, cfg->inputs[i].type); 3862352f7f91STakashi Iwai 3863352f7f91STakashi Iwai /* init loopback inputs */ 3864352f7f91STakashi Iwai if (spec->mixer_nid) { 3865352f7f91STakashi Iwai struct nid_path *path; 3866196c1766STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->loopback_paths[i]); 3867352f7f91STakashi Iwai if (path) 3868352f7f91STakashi Iwai snd_hda_activate_path(codec, path, 3869352f7f91STakashi Iwai path->active, false); 3870352f7f91STakashi Iwai } 3871352f7f91STakashi Iwai } 3872352f7f91STakashi Iwai } 3873352f7f91STakashi Iwai 3874352f7f91STakashi Iwai /* initialize ADC paths */ 3875352f7f91STakashi Iwai static void init_input_src(struct hda_codec *codec) 3876352f7f91STakashi Iwai { 3877352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3878352f7f91STakashi Iwai struct hda_input_mux *imux = &spec->input_mux; 3879352f7f91STakashi Iwai struct nid_path *path; 3880352f7f91STakashi Iwai int i, c, nums; 3881352f7f91STakashi Iwai 3882352f7f91STakashi Iwai if (spec->dyn_adc_switch) 3883352f7f91STakashi Iwai nums = 1; 3884352f7f91STakashi Iwai else 3885352f7f91STakashi Iwai nums = spec->num_adc_nids; 3886352f7f91STakashi Iwai 3887352f7f91STakashi Iwai for (c = 0; c < nums; c++) { 3888352f7f91STakashi Iwai for (i = 0; i < imux->num_items; i++) { 3889352f7f91STakashi Iwai path = snd_hda_get_nid_path(codec, spec->imux_pins[i], 3890352f7f91STakashi Iwai get_adc_nid(codec, c, i)); 3891352f7f91STakashi Iwai if (path) { 3892352f7f91STakashi Iwai bool active = path->active; 3893352f7f91STakashi Iwai if (i == spec->cur_mux[c]) 3894352f7f91STakashi Iwai active = true; 3895352f7f91STakashi Iwai snd_hda_activate_path(codec, path, active, false); 3896352f7f91STakashi Iwai } 3897352f7f91STakashi Iwai } 3898352f7f91STakashi Iwai } 3899352f7f91STakashi Iwai 3900352f7f91STakashi Iwai if (spec->shared_mic_hp) 3901352f7f91STakashi Iwai update_shared_mic_hp(codec, spec->cur_mux[0]); 3902352f7f91STakashi Iwai 3903352f7f91STakashi Iwai if (spec->cap_sync_hook) 3904352f7f91STakashi Iwai spec->cap_sync_hook(codec); 3905352f7f91STakashi Iwai } 3906352f7f91STakashi Iwai 3907352f7f91STakashi Iwai /* set right pin controls for digital I/O */ 3908352f7f91STakashi Iwai static void init_digital(struct hda_codec *codec) 3909352f7f91STakashi Iwai { 3910352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3911352f7f91STakashi Iwai int i; 3912352f7f91STakashi Iwai hda_nid_t pin; 3913352f7f91STakashi Iwai 3914352f7f91STakashi Iwai for (i = 0; i < spec->autocfg.dig_outs; i++) { 3915352f7f91STakashi Iwai pin = spec->autocfg.dig_out_pins[i]; 3916352f7f91STakashi Iwai if (!pin) 3917352f7f91STakashi Iwai continue; 3918196c1766STakashi Iwai set_output_and_unmute(codec, pin, PIN_OUT, 3919196c1766STakashi Iwai spec->digout_paths[i]); 3920352f7f91STakashi Iwai } 3921352f7f91STakashi Iwai pin = spec->autocfg.dig_in_pin; 39222430d7b7STakashi Iwai if (pin) { 39232430d7b7STakashi Iwai struct nid_path *path; 39247594aa33STakashi Iwai snd_hda_set_pin_ctl_cache(codec, pin, PIN_IN); 39252430d7b7STakashi Iwai path = snd_hda_get_path_from_idx(codec, spec->digin_path); 39262430d7b7STakashi Iwai if (path) 39272430d7b7STakashi Iwai snd_hda_activate_path(codec, path, path->active, false); 39282430d7b7STakashi Iwai } 3929352f7f91STakashi Iwai } 3930352f7f91STakashi Iwai 3931973e4972STakashi Iwai /* clear unsol-event tags on unused pins; Conexant codecs seem to leave 3932973e4972STakashi Iwai * invalid unsol tags by some reason 3933973e4972STakashi Iwai */ 3934973e4972STakashi Iwai static void clear_unsol_on_unused_pins(struct hda_codec *codec) 3935973e4972STakashi Iwai { 3936973e4972STakashi Iwai int i; 3937973e4972STakashi Iwai 3938973e4972STakashi Iwai for (i = 0; i < codec->init_pins.used; i++) { 3939973e4972STakashi Iwai struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); 3940973e4972STakashi Iwai hda_nid_t nid = pin->nid; 3941973e4972STakashi Iwai if (is_jack_detectable(codec, nid) && 3942973e4972STakashi Iwai !snd_hda_jack_tbl_get(codec, nid)) 3943973e4972STakashi Iwai snd_hda_codec_update_cache(codec, nid, 0, 3944973e4972STakashi Iwai AC_VERB_SET_UNSOLICITED_ENABLE, 0); 3945973e4972STakashi Iwai } 3946973e4972STakashi Iwai } 3947973e4972STakashi Iwai 3948352f7f91STakashi Iwai int snd_hda_gen_init(struct hda_codec *codec) 3949352f7f91STakashi Iwai { 3950352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3951352f7f91STakashi Iwai 3952352f7f91STakashi Iwai if (spec->init_hook) 3953352f7f91STakashi Iwai spec->init_hook(codec); 3954352f7f91STakashi Iwai 3955352f7f91STakashi Iwai snd_hda_apply_verbs(codec); 3956352f7f91STakashi Iwai 39573bbcd274STakashi Iwai codec->cached_write = 1; 39583bbcd274STakashi Iwai 3959352f7f91STakashi Iwai init_multi_out(codec); 3960352f7f91STakashi Iwai init_extra_out(codec); 3961352f7f91STakashi Iwai init_multi_io(codec); 3962352f7f91STakashi Iwai init_analog_input(codec); 3963352f7f91STakashi Iwai init_input_src(codec); 3964352f7f91STakashi Iwai init_digital(codec); 3965352f7f91STakashi Iwai 3966973e4972STakashi Iwai clear_unsol_on_unused_pins(codec); 3967973e4972STakashi Iwai 3968352f7f91STakashi Iwai /* call init functions of standard auto-mute helpers */ 39695d550e15STakashi Iwai snd_hda_gen_hp_automute(codec, NULL); 39705d550e15STakashi Iwai snd_hda_gen_line_automute(codec, NULL); 39715d550e15STakashi Iwai snd_hda_gen_mic_autoswitch(codec, NULL); 3972352f7f91STakashi Iwai 39733bbcd274STakashi Iwai snd_hda_codec_flush_amp_cache(codec); 39743bbcd274STakashi Iwai snd_hda_codec_flush_cmd_cache(codec); 39753bbcd274STakashi Iwai 3976352f7f91STakashi Iwai if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook) 3977352f7f91STakashi Iwai snd_hda_sync_vmaster_hook(&spec->vmaster_mute); 3978352f7f91STakashi Iwai 3979352f7f91STakashi Iwai hda_call_check_power_status(codec, 0x01); 3980352f7f91STakashi Iwai return 0; 3981352f7f91STakashi Iwai } 3982352f7f91STakashi Iwai EXPORT_SYMBOL(snd_hda_gen_init); 3983352f7f91STakashi Iwai 3984352f7f91STakashi Iwai 3985352f7f91STakashi Iwai /* 3986352f7f91STakashi Iwai * the generic codec support 3987352f7f91STakashi Iwai */ 39881da177e4SLinus Torvalds 398983012a7cSTakashi Iwai #ifdef CONFIG_PM 3990cb53c626STakashi Iwai static int generic_check_power_status(struct hda_codec *codec, hda_nid_t nid) 3991cb53c626STakashi Iwai { 3992352f7f91STakashi Iwai struct hda_gen_spec *spec = codec->spec; 3993cb53c626STakashi Iwai return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); 3994cb53c626STakashi Iwai } 3995cb53c626STakashi Iwai #endif 3996cb53c626STakashi Iwai 3997352f7f91STakashi Iwai static void generic_free(struct hda_codec *codec) 3998352f7f91STakashi Iwai { 3999352f7f91STakashi Iwai snd_hda_gen_spec_free(codec->spec); 4000352f7f91STakashi Iwai kfree(codec->spec); 4001352f7f91STakashi Iwai codec->spec = NULL; 4002352f7f91STakashi Iwai } 40031da177e4SLinus Torvalds 4004352f7f91STakashi Iwai static const struct hda_codec_ops generic_patch_ops = { 4005352f7f91STakashi Iwai .build_controls = snd_hda_gen_build_controls, 4006352f7f91STakashi Iwai .build_pcms = snd_hda_gen_build_pcms, 4007352f7f91STakashi Iwai .init = snd_hda_gen_init, 4008352f7f91STakashi Iwai .free = generic_free, 4009352f7f91STakashi Iwai .unsol_event = snd_hda_jack_unsol_event, 401083012a7cSTakashi Iwai #ifdef CONFIG_PM 4011cb53c626STakashi Iwai .check_power_status = generic_check_power_status, 4012cb53c626STakashi Iwai #endif 40131da177e4SLinus Torvalds }; 40141da177e4SLinus Torvalds 40151da177e4SLinus Torvalds int snd_hda_parse_generic_codec(struct hda_codec *codec) 40161da177e4SLinus Torvalds { 4017352f7f91STakashi Iwai struct hda_gen_spec *spec; 40181da177e4SLinus Torvalds int err; 40191da177e4SLinus Torvalds 4020e560d8d8STakashi Iwai spec = kzalloc(sizeof(*spec), GFP_KERNEL); 4021352f7f91STakashi Iwai if (!spec) 40221da177e4SLinus Torvalds return -ENOMEM; 4023352f7f91STakashi Iwai snd_hda_gen_spec_init(spec); 40241da177e4SLinus Torvalds codec->spec = spec; 40251da177e4SLinus Torvalds 40269eb413e5STakashi Iwai err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0); 40279eb413e5STakashi Iwai if (err < 0) 40289eb413e5STakashi Iwai return err; 40299eb413e5STakashi Iwai 40309eb413e5STakashi Iwai err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg); 4031352f7f91STakashi Iwai if (err < 0) 40321da177e4SLinus Torvalds goto error; 40331da177e4SLinus Torvalds 40341da177e4SLinus Torvalds codec->patch_ops = generic_patch_ops; 40351da177e4SLinus Torvalds return 0; 40361da177e4SLinus Torvalds 40371da177e4SLinus Torvalds error: 4038352f7f91STakashi Iwai generic_free(codec); 40391da177e4SLinus Torvalds return err; 40401da177e4SLinus Torvalds } 40411289e9e8STakashi Iwai EXPORT_SYMBOL(snd_hda_parse_generic_codec); 4042