diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index 99f7fbbe3e67..99958be7b454 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -365,10 +365,23 @@ modelname:: to this file. init_verbs:: The extra verbs to execute at initialization. You can add a verb by - writing to this file. Pass tree numbers, nid, verb and parameter. + writing to this file. Pass three numbers: nid, verb and parameter. hints:: Shows hint strings for codec parsers for any use. Right now it's not used. +init_pin_configs:: + Shows the initial pin default config values set by BIOS. +driver_pin_configs:: + Shows the pin default values set by the codec parser explicitly. + This doesn't show all pin values but only the changed values by + the parser. That is, if the parser doesn't change the pin default + config values by itself, this will contain nothing. +user_pin_configs:: + Shows the pin default config values to override the BIOS setup. + Writing this (with two numbers, NID and value) appends the new + value. The given will be used instead of the initial BIOS value at + the next reconfiguration time. Note that this config will override + even the driver pin configs, too. reconfig:: Triggers the codec re-configuration. When any value is written to this file, the driver re-initialize and parses the codec tree @@ -378,6 +391,14 @@ clear:: Resets the codec, removes the mixer elements and PCM stuff of the specified codec, and clear all init verbs and hints. +For example, when you want to change the pin default configuration +value of the pin widget 0x14 to 0x9993013f, and let the driver +re-configure based on that state, run like below: +------------------------------------------------------------------------ + # echo 0x14 0x9993013f > /sys/class/sound/hwC0D0/user_pin_configs + # echo 1 > /sys/class/sound/hwC0D0/reconfig +------------------------------------------------------------------------ + Power-Saving ~~~~~~~~~~~~ diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 98884bc8f35f..a13480fa8e74 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -682,11 +682,140 @@ static int read_widget_caps(struct hda_codec *codec, hda_nid_t fg_node) return 0; } +/* read all pin default configurations and save codec->init_pins */ +static int read_pin_defaults(struct hda_codec *codec) +{ + int i; + hda_nid_t nid = codec->start_nid; + + for (i = 0; i < codec->num_nodes; i++, nid++) { + struct hda_pincfg *pin; + unsigned int wcaps = get_wcaps(codec, nid); + unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >> + AC_WCAP_TYPE_SHIFT; + if (wid_type != AC_WID_PIN) + continue; + pin = snd_array_new(&codec->init_pins); + if (!pin) + return -ENOMEM; + pin->nid = nid; + pin->cfg = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONFIG_DEFAULT, 0); + } + return 0; +} + +/* look up the given pin config list and return the item matching with NID */ +static struct hda_pincfg *look_up_pincfg(struct hda_codec *codec, + struct snd_array *array, + hda_nid_t nid) +{ + int i; + for (i = 0; i < array->used; i++) { + struct hda_pincfg *pin = snd_array_elem(array, i); + if (pin->nid == nid) + return pin; + } + return NULL; +} + +/* write a config value for the given NID */ +static void set_pincfg(struct hda_codec *codec, hda_nid_t nid, + unsigned int cfg) +{ + int i; + for (i = 0; i < 4; i++) { + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i, + cfg & 0xff); + cfg >>= 8; + } +} + +/* set the current pin config value for the given NID. + * the value is cached, and read via snd_hda_codec_get_pincfg() + */ +int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, + hda_nid_t nid, unsigned int cfg) +{ + struct hda_pincfg *pin; + unsigned int oldcfg; + + oldcfg = snd_hda_codec_get_pincfg(codec, nid); + pin = look_up_pincfg(codec, list, nid); + if (!pin) { + pin = snd_array_new(list); + if (!pin) + return -ENOMEM; + pin->nid = nid; + } + pin->cfg = cfg; + + /* change only when needed; e.g. if the pincfg is already present + * in user_pins[], don't write it + */ + cfg = snd_hda_codec_get_pincfg(codec, nid); + if (oldcfg != cfg) + set_pincfg(codec, nid, cfg); + return 0; +} + +int snd_hda_codec_set_pincfg(struct hda_codec *codec, + hda_nid_t nid, unsigned int cfg) +{ + return snd_hda_add_pincfg(codec, &codec->driver_pins, nid, cfg); +} +EXPORT_SYMBOL_HDA(snd_hda_codec_set_pincfg); + +/* get the current pin config value of the given pin NID */ +unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid) +{ + struct hda_pincfg *pin; + +#ifdef CONFIG_SND_HDA_HWDEP + pin = look_up_pincfg(codec, &codec->user_pins, nid); + if (pin) + return pin->cfg; +#endif + pin = look_up_pincfg(codec, &codec->driver_pins, nid); + if (pin) + return pin->cfg; + pin = look_up_pincfg(codec, &codec->init_pins, nid); + if (pin) + return pin->cfg; + return 0; +} +EXPORT_SYMBOL_HDA(snd_hda_codec_get_pincfg); + +/* restore all current pin configs */ +static void restore_pincfgs(struct hda_codec *codec) +{ + int i; + for (i = 0; i < codec->init_pins.used; i++) { + struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); + set_pincfg(codec, pin->nid, + snd_hda_codec_get_pincfg(codec, pin->nid)); + } +} static void init_hda_cache(struct hda_cache_rec *cache, unsigned int record_size); static void free_hda_cache(struct hda_cache_rec *cache); +/* restore the initial pin cfgs and release all pincfg lists */ +static void restore_init_pincfgs(struct hda_codec *codec) +{ + /* first free driver_pins and user_pins, then call restore_pincfg + * so that only the values in init_pins are restored + */ + snd_array_free(&codec->driver_pins); +#ifdef CONFIG_SND_HDA_HWDEP + snd_array_free(&codec->user_pins); +#endif + restore_pincfgs(codec); + snd_array_free(&codec->init_pins); +} + /* * codec destructor */ @@ -694,6 +823,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) { if (!codec) return; + restore_init_pincfgs(codec); #ifdef CONFIG_SND_HDA_POWER_SAVE cancel_delayed_work(&codec->power_work); flush_workqueue(codec->bus->workq); @@ -751,6 +881,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); + snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); + snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); if (codec->bus->modelname) { codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); if (!codec->modelname) { @@ -787,15 +919,18 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr setup_fg_nodes(codec); if (!codec->afg && !codec->mfg) { snd_printdd("hda_codec: no AFG or MFG node found\n"); - snd_hda_codec_free(codec); - return -ENODEV; + err = -ENODEV; + goto error; } - if (read_widget_caps(codec, codec->afg ? codec->afg : codec->mfg) < 0) { + err = read_widget_caps(codec, codec->afg ? codec->afg : codec->mfg); + if (err < 0) { snd_printk(KERN_ERR "hda_codec: cannot malloc\n"); - snd_hda_codec_free(codec); - return -ENOMEM; + goto error; } + err = read_pin_defaults(codec); + if (err < 0) + goto error; if (!codec->subsystem_id) { hda_nid_t nid = codec->afg ? codec->afg : codec->mfg; @@ -808,10 +943,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr if (do_init) { err = snd_hda_codec_configure(codec); - if (err < 0) { - snd_hda_codec_free(codec); - return err; - } + if (err < 0) + goto error; } snd_hda_codec_proc_new(codec); @@ -824,6 +957,10 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr if (codecp) *codecp = codec; return 0; + + error: + snd_hda_codec_free(codec); + return err; } EXPORT_SYMBOL_HDA(snd_hda_codec_new); @@ -1334,6 +1471,9 @@ void snd_hda_codec_reset(struct hda_codec *codec) free_hda_cache(&codec->cmd_cache); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); + /* free only driver_pins so that init_pins + user_pins are restored */ + snd_array_free(&codec->driver_pins); + restore_pincfgs(codec); codec->num_pcms = 0; codec->pcm_info = NULL; codec->preset = NULL; @@ -2175,6 +2315,7 @@ static void hda_call_codec_resume(struct hda_codec *codec) hda_set_power_state(codec, codec->afg ? codec->afg : codec->mfg, AC_PWRST_D0); + restore_pincfgs(codec); /* restore all current pin configs */ hda_exec_init_verbs(codec); if (codec->patch_ops.resume) codec->patch_ops.resume(codec); @@ -3355,8 +3496,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, if (ignore_nids && is_in_nid_list(nid, ignore_nids)) continue; - def_conf = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); + def_conf = snd_hda_codec_get_pincfg(codec, nid); if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) continue; loc = get_defcfg_location(def_conf); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 09a332ada0c6..2ea628478a91 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -778,11 +778,14 @@ struct hda_codec { unsigned short spdif_ctls; /* SPDIF control bits */ unsigned int spdif_in_enable; /* SPDIF input enable? */ hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ + struct snd_array init_pins; /* initial (BIOS) pin configurations */ + struct snd_array driver_pins; /* pin configs set by codec parser */ #ifdef CONFIG_SND_HDA_HWDEP struct snd_hwdep *hwdep; /* assigned hwdep device */ struct snd_array init_verbs; /* additional init verbs */ struct snd_array hints; /* additional hints */ + struct snd_array user_pins; /* default pin configs to override */ #endif /* misc flags */ @@ -855,6 +858,18 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec); #define snd_hda_sequence_write_cache snd_hda_sequence_write #endif +/* the struct for codec->pin_configs */ +struct hda_pincfg { + hda_nid_t nid; + unsigned int cfg; +}; + +unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid); +int snd_hda_codec_set_pincfg(struct hda_codec *codec, hda_nid_t nid, + unsigned int cfg); +int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, + hda_nid_t nid, unsigned int cfg); /* for hwdep */ + /* * Mixer */ diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 65745e96dc70..2c81a683e8f8 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -146,7 +146,7 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid if (node->type == AC_WID_PIN) { node->pin_caps = snd_hda_param_read(codec, node->nid, AC_PAR_PIN_CAP); node->pin_ctl = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - node->def_cfg = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + node->def_cfg = snd_hda_codec_get_pincfg(codec, node->nid); } if (node->wid_caps & AC_WCAP_OUT_AMP) { diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 4ae51dcb81af..c660383ef381 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -109,6 +109,7 @@ static void clear_hwdep_elements(struct hda_codec *codec) for (i = 0; i < codec->hints.used; i++, head++) kfree(*head); snd_array_free(&codec->hints); + snd_array_free(&codec->user_pins); } static void hwdep_free(struct snd_hwdep *hwdep) @@ -141,6 +142,7 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec) snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32); snd_array_init(&codec->hints, sizeof(char *), 32); + snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16); return 0; } @@ -316,6 +318,67 @@ static ssize_t hints_store(struct device *dev, return count; } +static ssize_t pin_configs_show(struct hda_codec *codec, + struct snd_array *list, + char *buf) +{ + int i, len = 0; + for (i = 0; i < list->used; i++) { + struct hda_pincfg *pin = snd_array_elem(list, i); + len += sprintf(buf + len, "0x%02x 0x%08x\n", + pin->nid, pin->cfg); + } + return len; +} + +static ssize_t init_pin_configs_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); + struct hda_codec *codec = hwdep->private_data; + return pin_configs_show(codec, &codec->init_pins, buf); +} + +static ssize_t user_pin_configs_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); + struct hda_codec *codec = hwdep->private_data; + return pin_configs_show(codec, &codec->user_pins, buf); +} + +static ssize_t driver_pin_configs_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); + struct hda_codec *codec = hwdep->private_data; + return pin_configs_show(codec, &codec->driver_pins, buf); +} + +#define MAX_PIN_CONFIGS 32 + +static ssize_t user_pin_configs_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); + struct hda_codec *codec = hwdep->private_data; + int nid, cfg; + int err; + + if (sscanf(buf, "%i %i", &nid, &cfg) != 2) + return -EINVAL; + if (!nid) + return -EINVAL; + err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg); + if (err < 0) + return err; + return count; +} + #define CODEC_ATTR_RW(type) \ __ATTR(type, 0644, type##_show, type##_store) #define CODEC_ATTR_RO(type) \ @@ -333,6 +396,9 @@ static struct device_attribute codec_attrs[] = { CODEC_ATTR_RW(modelname), CODEC_ATTR_WO(init_verbs), CODEC_ATTR_WO(hints), + CODEC_ATTR_RO(init_pin_configs), + CODEC_ATTR_RW(user_pin_configs), + CODEC_ATTR_RO(driver_pin_configs), CODEC_ATTR_WO(reconfig), CODEC_ATTR_WO(clear), }; diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index b16802841468..0253cb93aa7f 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -1047,8 +1047,7 @@ static struct hda_amp_list ad1986a_loopbacks[] = { static int is_jack_available(struct hda_codec *codec, hda_nid_t nid) { - unsigned int conf = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); + unsigned int conf = snd_hda_codec_get_pincfg(codec, nid); return get_defcfg_connect(conf) != AC_JACK_PORT_NONE; } diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index f3ebe837f2d5..c921264bbd71 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -680,13 +680,13 @@ static int patch_cmi9880(struct hda_codec *codec) struct auto_pin_cfg cfg; /* collect pin default configuration */ - port_e = snd_hda_codec_read(codec, 0x0f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); - port_f = snd_hda_codec_read(codec, 0x10, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + port_e = snd_hda_codec_get_pincfg(codec, 0x0f); + port_f = snd_hda_codec_get_pincfg(codec, 0x10); spec->front_panel = 1; if (get_defcfg_connect(port_e) == AC_JACK_PORT_NONE || get_defcfg_connect(port_f) == AC_JACK_PORT_NONE) { - port_g = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); - port_h = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + port_g = snd_hda_codec_get_pincfg(codec, 0x1f); + port_h = snd_hda_codec_get_pincfg(codec, 0x20); spec->channel_modes = cmi9880_channel_modes; /* no front panel */ if (get_defcfg_connect(port_g) == AC_JACK_PORT_NONE || @@ -703,8 +703,8 @@ static int patch_cmi9880(struct hda_codec *codec) spec->multiout.max_channels = cmi9880_channel_modes[0].channels; } else { spec->input_mux = &cmi9880_basic_mux; - port_spdifi = snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); - port_spdifo = snd_hda_codec_read(codec, 0x12, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + port_spdifi = snd_hda_codec_get_pincfg(codec, 0x13); + port_spdifo = snd_hda_codec_get_pincfg(codec, 0x12); if (get_defcfg_connect(port_spdifo) != AC_JACK_PORT_NONE) spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; if (get_defcfg_connect(port_spdifi) != AC_JACK_PORT_NONE) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5c9bb066a764..50ae8f33af5f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -330,13 +330,6 @@ struct alc_spec { /* for PLL fix */ hda_nid_t pll_nid; unsigned int pll_coef_idx, pll_coef_bit; - -#ifdef SND_HDA_NEEDS_RESUME -#define ALC_MAX_PINS 16 - unsigned int num_pins; - hda_nid_t pin_nids[ALC_MAX_PINS]; - unsigned int pin_cfgs[ALC_MAX_PINS]; -#endif }; /* @@ -1010,8 +1003,7 @@ static void alc_subsystem_id(struct hda_codec *codec, nid = 0x1d; if (codec->vendor_id == 0x10ec0260) nid = 0x17; - ass = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); + ass = snd_hda_codec_get_pincfg(codec, nid); if (!(ass & 1) && !(ass & 0x100000)) return; if ((ass >> 30) != 1) /* no physical connection */ @@ -1185,16 +1177,8 @@ static void alc_fix_pincfg(struct hda_codec *codec, return; cfg = pinfix[quirk->value]; - for (; cfg->nid; cfg++) { - int i; - u32 val = cfg->val; - for (i = 0; i < 4; i++) { - snd_hda_codec_write(codec, cfg->nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i, - val & 0xff); - val >>= 8; - } - } + for (; cfg->nid; cfg++) + snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); } /* @@ -3216,61 +3200,13 @@ static void alc_free(struct hda_codec *codec) } #ifdef SND_HDA_NEEDS_RESUME -static void store_pin_configs(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid, end_nid; - - end_nid = codec->start_nid + codec->num_nodes; - for (nid = codec->start_nid; nid < end_nid; nid++) { - unsigned int wid_caps = get_wcaps(codec, nid); - unsigned int wid_type = - (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - if (wid_type != AC_WID_PIN) - continue; - if (spec->num_pins >= ARRAY_SIZE(spec->pin_nids)) - break; - spec->pin_nids[spec->num_pins] = nid; - spec->pin_cfgs[spec->num_pins] = - snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); - spec->num_pins++; - } -} - -static void resume_pin_configs(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->num_pins; i++) { - hda_nid_t pin_nid = spec->pin_nids[i]; - unsigned int pin_config = spec->pin_cfgs[i]; - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, - pin_config & 0x000000ff); - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, - (pin_config & 0x0000ff00) >> 8); - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, - (pin_config & 0x00ff0000) >> 16); - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, - pin_config >> 24); - } -} - static int alc_resume(struct hda_codec *codec) { - resume_pin_configs(codec); codec->patch_ops.init(codec); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); return 0; } -#else -#define store_pin_configs(codec) #endif /* @@ -4330,7 +4266,6 @@ static int alc880_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux[0]; - store_pin_configs(codec); return 1; } @@ -5809,7 +5744,6 @@ static int alc260_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux[0]; - store_pin_configs(codec); return 1; } @@ -10821,7 +10755,6 @@ static int alc262_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - store_pin_configs(codec); return 1; } @@ -11994,7 +11927,6 @@ static int alc268_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - store_pin_configs(codec); return 1; } @@ -12907,7 +12839,6 @@ static int alc269_parse_auto_config(struct hda_codec *codec) if (!spec->cap_mixer && !spec->no_analog) set_capture_mixer(spec); - store_pin_configs(codec); return 1; } @@ -13958,7 +13889,6 @@ static int alc861_parse_auto_config(struct hda_codec *codec) spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); set_capture_mixer(spec); - store_pin_configs(codec); return 1; } @@ -15060,7 +14990,6 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - store_pin_configs(codec); return 1; } @@ -16870,7 +16799,6 @@ static int alc662_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - store_pin_configs(codec); return 1; } diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d00a211a813b..da48d8c0b295 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -229,7 +229,6 @@ struct sigmatel_spec { /* pin widgets */ hda_nid_t *pin_nids; unsigned int num_pins; - unsigned int *pin_configs; /* codec specific stuff */ struct hda_verb *init; @@ -2272,101 +2271,19 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = { {} /* terminator */ }; -static int stac92xx_save_bios_config_regs(struct hda_codec *codec) -{ - int i; - struct sigmatel_spec *spec = codec->spec; - - kfree(spec->pin_configs); - spec->pin_configs = kcalloc(spec->num_pins, sizeof(*spec->pin_configs), - GFP_KERNEL); - if (!spec->pin_configs) - return -ENOMEM; - - for (i = 0; i < spec->num_pins; i++) { - hda_nid_t nid = spec->pin_nids[i]; - unsigned int pin_cfg; - - if (!nid) - continue; - pin_cfg = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0x00); - snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n", - nid, pin_cfg); - spec->pin_configs[i] = pin_cfg; - } - - return 0; -} - -static void stac92xx_set_config_reg(struct hda_codec *codec, - hda_nid_t pin_nid, unsigned int pin_config) -{ - int i; - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, - pin_config & 0x000000ff); - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, - (pin_config & 0x0000ff00) >> 8); - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, - (pin_config & 0x00ff0000) >> 16); - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, - pin_config >> 24); - i = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, - 0x00); - snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n", - pin_nid, i); -} - -static void stac92xx_set_config_regs(struct hda_codec *codec) +static void stac92xx_set_config_regs(struct hda_codec *codec, + unsigned int *pincfgs) { int i; struct sigmatel_spec *spec = codec->spec; - if (!spec->pin_configs) - return; + if (!pincfgs) + return; for (i = 0; i < spec->num_pins; i++) - if (spec->pin_nids[i] && spec->pin_configs[i]) - stac92xx_set_config_reg(codec, spec->pin_nids[i], - spec->pin_configs[i]); -} - -static int stac_save_pin_cfgs(struct hda_codec *codec, unsigned int *pins) -{ - struct sigmatel_spec *spec = codec->spec; - - if (!pins) - return stac92xx_save_bios_config_regs(codec); - - kfree(spec->pin_configs); - spec->pin_configs = kmemdup(pins, - spec->num_pins * sizeof(*pins), - GFP_KERNEL); - if (!spec->pin_configs) - return -ENOMEM; - - stac92xx_set_config_regs(codec); - return 0; -} - -static void stac_change_pin_config(struct hda_codec *codec, hda_nid_t nid, - unsigned int cfg) -{ - struct sigmatel_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->num_pins; i++) { - if (spec->pin_nids[i] == nid) { - spec->pin_configs[i] = cfg; - stac92xx_set_config_reg(codec, nid, cfg); - break; - } - } + if (spec->pin_nids[i] && pincfgs[i]) + snd_hda_codec_set_pincfg(codec, spec->pin_nids[i], + pincfgs[i]); } /* @@ -2853,8 +2770,7 @@ static hda_nid_t check_mic_out_switch(struct hda_codec *codec) mic_pin = AUTO_PIN_MIC; for (;;) { hda_nid_t nid = cfg->input_pins[mic_pin]; - def_conf = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); + def_conf = snd_hda_codec_get_pincfg(codec, nid); /* some laptops have an internal analog microphone * which can't be used as a output */ if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) { @@ -3426,11 +3342,7 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, unsigned int wcaps; unsigned int def_conf; - def_conf = snd_hda_codec_read(codec, - spec->dmic_nids[i], - 0, - AC_VERB_GET_CONFIG_DEFAULT, - 0); + def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]); if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) continue; @@ -3779,9 +3691,7 @@ static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec, for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) { hda_nid_t pin = spec->autocfg.line_out_pins[i]; unsigned int defcfg; - defcfg = snd_hda_codec_read(codec, pin, 0, - AC_VERB_GET_CONFIG_DEFAULT, - 0x00); + defcfg = snd_hda_codec_get_pincfg(codec, pin); if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) { unsigned int wcaps = get_wcaps(codec, pin); wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP); @@ -3885,8 +3795,7 @@ static int stac92xx_add_jack(struct hda_codec *codec, #ifdef CONFIG_SND_JACK struct sigmatel_spec *spec = codec->spec; struct sigmatel_jack *jack; - int def_conf = snd_hda_codec_read(codec, nid, - 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + int def_conf = snd_hda_codec_get_pincfg(codec, nid); int connectivity = get_defcfg_connect(def_conf); char name[32]; @@ -4066,8 +3975,7 @@ static int stac92xx_init(struct hda_codec *codec) pinctl); } } - conf = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); + conf = snd_hda_codec_get_pincfg(codec, nid); if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) { enable_pin_detect(codec, nid, STAC_INSERT_EVENT); @@ -4108,8 +4016,7 @@ static int stac92xx_init(struct hda_codec *codec) stac_toggle_power_map(codec, nid, 1); continue; } - def_conf = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); + def_conf = snd_hda_codec_get_pincfg(codec, nid); def_conf = get_defcfg_connect(def_conf); /* skip any ports that don't have jacks since presence * detection is useless */ @@ -4163,7 +4070,6 @@ static void stac92xx_free(struct hda_codec *codec) if (! spec) return; - kfree(spec->pin_configs); stac92xx_free_jacks(codec); snd_array_free(&spec->events); @@ -4474,7 +4380,6 @@ static int stac92xx_resume(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - stac92xx_set_config_regs(codec); stac92xx_init(codec); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); @@ -4523,16 +4428,11 @@ static int patch_stac9200(struct hda_codec *codec) spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS, stac9200_models, stac9200_cfg_tbl); - if (spec->board_config < 0) { + if (spec->board_config < 0) snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n"); - err = stac92xx_save_bios_config_regs(codec); - } else - err = stac_save_pin_cfgs(codec, + else + stac92xx_set_config_regs(codec, stac9200_brd_tbl[spec->board_config]); - if (err < 0) { - stac92xx_free(codec); - return err; - } spec->multiout.max_channels = 2; spec->multiout.num_dacs = 1; @@ -4600,17 +4500,12 @@ static int patch_stac925x(struct hda_codec *codec) stac925x_models, stac925x_cfg_tbl); again: - if (spec->board_config < 0) { + if (spec->board_config < 0) snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x," "using BIOS defaults\n"); - err = stac92xx_save_bios_config_regs(codec); - } else - err = stac_save_pin_cfgs(codec, + else + stac92xx_set_config_regs(codec, stac925x_brd_tbl[spec->board_config]); - if (err < 0) { - stac92xx_free(codec); - return err; - } spec->multiout.max_channels = 2; spec->multiout.num_dacs = 1; @@ -4688,17 +4583,12 @@ static int patch_stac92hd73xx(struct hda_codec *codec) stac92hd73xx_models, stac92hd73xx_cfg_tbl); again: - if (spec->board_config < 0) { + if (spec->board_config < 0) snd_printdd(KERN_INFO "hda_codec: Unknown model for" " STAC92HD73XX, using BIOS defaults\n"); - err = stac92xx_save_bios_config_regs(codec); - } else - err = stac_save_pin_cfgs(codec, + else + stac92xx_set_config_regs(codec, stac92hd73xx_brd_tbl[spec->board_config]); - if (err < 0) { - stac92xx_free(codec); - return err; - } num_dacs = snd_hda_get_connections(codec, 0x0a, conn, STAC92HD73_DAC_COUNT + 2) - 1; @@ -4758,18 +4648,18 @@ again: spec->init = dell_m6_core_init; switch (spec->board_config) { case STAC_DELL_M6_AMIC: /* Analog Mics */ - stac92xx_set_config_reg(codec, 0x0b, 0x90A70170); + snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170); spec->num_dmics = 0; spec->private_dimux.num_items = 1; break; case STAC_DELL_M6_DMIC: /* Digital Mics */ - stac92xx_set_config_reg(codec, 0x13, 0x90A60160); + snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160); spec->num_dmics = 1; spec->private_dimux.num_items = 2; break; case STAC_DELL_M6_BOTH: /* Both */ - stac92xx_set_config_reg(codec, 0x0b, 0x90A70170); - stac92xx_set_config_reg(codec, 0x13, 0x90A60160); + snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170); + snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160); spec->num_dmics = 1; spec->private_dimux.num_items = 2; break; @@ -4865,17 +4755,12 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) stac92hd83xxx_models, stac92hd83xxx_cfg_tbl); again: - if (spec->board_config < 0) { + if (spec->board_config < 0) snd_printdd(KERN_INFO "hda_codec: Unknown model for" " STAC92HD83XXX, using BIOS defaults\n"); - err = stac92xx_save_bios_config_regs(codec); - } else - err = stac_save_pin_cfgs(codec, + else + stac92xx_set_config_regs(codec, stac92hd83xxx_brd_tbl[spec->board_config]); - if (err < 0) { - stac92xx_free(codec); - return err; - } switch (codec->vendor_id) { case 0x111d7604: @@ -4945,6 +4830,16 @@ static struct hda_input_mux stac92hd71bxx_dmux_amixer = { } }; +/* get the pin connection (fixed, none, etc) */ +static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx) +{ + struct sigmatel_spec *spec = codec->spec; + unsigned int cfg; + + cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]); + return get_defcfg_connect(cfg); +} + static int stac92hd71bxx_connected_ports(struct hda_codec *codec, hda_nid_t *nids, int num_nids) { @@ -4958,7 +4853,7 @@ static int stac92hd71bxx_connected_ports(struct hda_codec *codec, break; if (idx >= spec->num_pins) break; - def_conf = get_defcfg_connect(spec->pin_configs[idx]); + def_conf = stac_get_defcfg_connect(codec, idx); if (def_conf == AC_JACK_PORT_NONE) break; } @@ -4978,13 +4873,13 @@ static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec, return 0; /* dig1pin case */ - if (get_defcfg_connect(spec->pin_configs[idx+1]) != AC_JACK_PORT_NONE) + if (stac_get_defcfg_connect(codec, idx + 1) != AC_JACK_PORT_NONE) return 2; /* dig0pin + dig2pin case */ - if (get_defcfg_connect(spec->pin_configs[idx+2]) != AC_JACK_PORT_NONE) + if (stac_get_defcfg_connect(codec, idx + 2) != AC_JACK_PORT_NONE) return 2; - if (get_defcfg_connect(spec->pin_configs[idx]) != AC_JACK_PORT_NONE) + if (stac_get_defcfg_connect(codec, idx) != AC_JACK_PORT_NONE) return 1; else return 0; @@ -5023,17 +4918,12 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) stac92hd71bxx_models, stac92hd71bxx_cfg_tbl); again: - if (spec->board_config < 0) { + if (spec->board_config < 0) snd_printdd(KERN_INFO "hda_codec: Unknown model for" " STAC92HD71BXX, using BIOS defaults\n"); - err = stac92xx_save_bios_config_regs(codec); - } else - err = stac_save_pin_cfgs(codec, + else + stac92xx_set_config_regs(codec, stac92hd71bxx_brd_tbl[spec->board_config]); - if (err < 0) { - stac92xx_free(codec); - return err; - } if (spec->board_config > STAC_92HD71BXX_REF) { /* GPIO0 = EAPD */ @@ -5097,8 +4987,8 @@ again: /* disable VSW */ spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF]; unmute_init++; - stac_change_pin_config(codec, 0x0f, 0x40f000f0); - stac_change_pin_config(codec, 0x19, 0x40f000f3); + snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0); + snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3); stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS - 1] = 0; spec->num_dmics = stac92hd71bxx_connected_ports(codec, stac92hd71bxx_dmic_nids, @@ -5147,7 +5037,7 @@ again: switch (spec->board_config) { case STAC_HP_M4: /* enable internal microphone */ - stac_change_pin_config(codec, 0x0e, 0x01813040); + snd_hda_codec_set_pincfg(codec, 0x0e, 0x01813040); stac92xx_auto_set_pinctl(codec, 0x0e, AC_PINCTL_IN_EN | AC_PINCTL_VREF_80); /* fallthru */ @@ -5163,7 +5053,7 @@ again: spec->num_dmuxes = 0; break; case STAC_HP_DV5: - stac_change_pin_config(codec, 0x0d, 0x90170010); + snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010); stac92xx_auto_set_pinctl(codec, 0x0d, AC_PINCTL_OUT_EN); break; }; @@ -5247,17 +5137,12 @@ static int patch_stac922x(struct hda_codec *codec) } again: - if (spec->board_config < 0) { + if (spec->board_config < 0) snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, " "using BIOS defaults\n"); - err = stac92xx_save_bios_config_regs(codec); - } else - err = stac_save_pin_cfgs(codec, + else + stac92xx_set_config_regs(codec, stac922x_brd_tbl[spec->board_config]); - if (err < 0) { - stac92xx_free(codec); - return err; - } spec->adc_nids = stac922x_adc_nids; spec->mux_nids = stac922x_mux_nids; @@ -5315,17 +5200,12 @@ static int patch_stac927x(struct hda_codec *codec) stac927x_models, stac927x_cfg_tbl); again: - if (spec->board_config < 0) { + if (spec->board_config < 0) snd_printdd(KERN_INFO "hda_codec: Unknown model for" "STAC927x, using BIOS defaults\n"); - err = stac92xx_save_bios_config_regs(codec); - } else - err = stac_save_pin_cfgs(codec, + else + stac92xx_set_config_regs(codec, stac927x_brd_tbl[spec->board_config]); - if (err < 0) { - stac92xx_free(codec); - return err; - } spec->digbeep_nid = 0x23; spec->adc_nids = stac927x_adc_nids; @@ -5354,15 +5234,15 @@ static int patch_stac927x(struct hda_codec *codec) case 0x10280209: case 0x1028022e: /* correct the device field to SPDIF out */ - stac_change_pin_config(codec, 0x21, 0x01442070); + snd_hda_codec_set_pincfg(codec, 0x21, 0x01442070); break; }; /* configure the analog microphone on some laptops */ - stac_change_pin_config(codec, 0x0c, 0x90a79130); + snd_hda_codec_set_pincfg(codec, 0x0c, 0x90a79130); /* correct the front output jack as a hp out */ - stac_change_pin_config(codec, 0x0f, 0x0227011f); + snd_hda_codec_set_pincfg(codec, 0x0f, 0x0227011f); /* correct the front input jack as a mic */ - stac_change_pin_config(codec, 0x0e, 0x02a79130); + snd_hda_codec_set_pincfg(codec, 0x0e, 0x02a79130); /* fallthru */ case STAC_DELL_3ST: /* GPIO2 High = Enable EAPD */ @@ -5447,16 +5327,11 @@ static int patch_stac9205(struct hda_codec *codec) stac9205_models, stac9205_cfg_tbl); again: - if (spec->board_config < 0) { + if (spec->board_config < 0) snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n"); - err = stac92xx_save_bios_config_regs(codec); - } else - err = stac_save_pin_cfgs(codec, + else + stac92xx_set_config_regs(codec, stac9205_brd_tbl[spec->board_config]); - if (err < 0) { - stac92xx_free(codec); - return err; - } spec->digbeep_nid = 0x23; spec->adc_nids = stac9205_adc_nids; @@ -5484,8 +5359,8 @@ static int patch_stac9205(struct hda_codec *codec) switch (spec->board_config){ case STAC_9205_DELL_M43: /* Enable SPDIF in/out */ - stac_change_pin_config(codec, 0x1f, 0x01441030); - stac_change_pin_config(codec, 0x20, 0x1c410030); + snd_hda_codec_set_pincfg(codec, 0x1f, 0x01441030); + snd_hda_codec_set_pincfg(codec, 0x20, 0x1c410030); /* Enable unsol response for GPIO4/Dock HP connection */ err = stac_add_event(spec, codec->afg, STAC_VREF_EVENT, 0x01); diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 639b2ff510a6..b25a5cc637d6 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -1308,16 +1308,13 @@ static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid) unsigned int def_conf; unsigned char seqassoc; - def_conf = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); + def_conf = snd_hda_codec_get_pincfg(codec, nid); seqassoc = (unsigned char) get_defcfg_association(def_conf); seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf); if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) { if (seqassoc == 0xff) { def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30)); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, - def_conf >> 24); + snd_hda_codec_set_pincfg(codec, nid, def_conf); } }