diff options
author | Takashi Iwai <tiwai@suse.de> | 2010-07-08 18:42:38 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-07-08 18:42:38 +0200 |
commit | 68cb4b7f9eafb1886b4f46c0d2ea9eb321b76831 (patch) | |
tree | 9e3ed81fdfa63242b1f221200508d5d36b06dabd /sound | |
parent | 30ee960e9d2252992c219815eb284490a9693365 (diff) | |
parent | d47aaa4132a7016e035f2daeb41c722f145d630a (diff) |
Merge branch 'topic/hda' into for-next
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 59 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 5 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 55 |
3 files changed, 103 insertions, 16 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index a3d638c8c1fd..501cbc411a83 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -784,6 +784,9 @@ static int read_pin_defaults(struct hda_codec *codec) pin->nid = nid; pin->cfg = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + pin->ctrl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, + 0); } return 0; } @@ -912,15 +915,38 @@ static void restore_pincfgs(struct hda_codec *codec) void snd_hda_shutup_pins(struct hda_codec *codec) { int i; + /* don't shut up pins when unloading the driver; otherwise it breaks + * the default pin setup at the next load of the driver + */ + if (codec->bus->shutdown) + return; for (i = 0; i < codec->init_pins.used; i++) { struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); /* use read here for syncing after issuing each verb */ snd_hda_codec_read(codec, pin->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0); } + codec->pins_shutup = 1; } EXPORT_SYMBOL_HDA(snd_hda_shutup_pins); +/* Restore the pin controls cleared previously via snd_hda_shutup_pins() */ +static void restore_shutup_pins(struct hda_codec *codec) +{ + int i; + if (!codec->pins_shutup) + return; + if (codec->bus->shutdown) + return; + for (i = 0; i < codec->init_pins.used; i++) { + struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); + snd_hda_codec_write(codec, pin->nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + pin->ctrl); + } + codec->pins_shutup = 0; +} + static void init_hda_cache(struct hda_cache_rec *cache, unsigned int record_size); static void free_hda_cache(struct hda_cache_rec *cache); @@ -1539,6 +1565,17 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); #endif /* SND_HDA_NEEDS_RESUME */ +static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir, + unsigned int ofs) +{ + u32 caps = query_amp_caps(codec, nid, dir); + /* get num steps */ + caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; + if (ofs < caps) + caps -= ofs; + return caps; +} + /** * snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer * @@ -1553,23 +1590,17 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, u8 chs = get_amp_channels(kcontrol); int dir = get_amp_direction(kcontrol); unsigned int ofs = get_amp_offset(kcontrol); - u32 caps; - caps = query_amp_caps(codec, nid, dir); - /* num steps */ - caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; - if (!caps) { + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = chs == 3 ? 2 : 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = get_amp_max_value(codec, nid, dir, ofs); + if (!uinfo->value.integer.max) { printk(KERN_WARNING "hda_codec: " "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid, kcontrol->id.name); return -EINVAL; } - if (ofs < caps) - caps -= ofs; - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = chs == 3 ? 2 : 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = caps; return 0; } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); @@ -1594,8 +1625,13 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid, int ch, int dir, int idx, unsigned int ofs, unsigned int val) { + unsigned int maxval; + if (val > 0) val += ofs; + maxval = get_amp_max_value(codec, nid, dir, ofs); + if (val > maxval) + val = maxval; return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, HDA_AMP_VOLMASK, val); } @@ -2907,6 +2943,7 @@ static void hda_call_codec_resume(struct hda_codec *codec) codec->afg ? codec->afg : codec->mfg, AC_PWRST_D0); restore_pincfgs(codec); /* restore all current pin configs */ + restore_shutup_pins(codec); hda_exec_init_verbs(codec); if (codec->patch_ops.resume) codec->patch_ops.resume(codec); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 49e939e7e5cd..5991d14e1ec0 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -821,6 +821,7 @@ struct hda_codec { unsigned int pin_amp_workaround:1; /* pin out-amp takes index * (e.g. Conexant codecs) */ + unsigned int pins_shutup:1; /* pins are shut up */ unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */ #ifdef CONFIG_SND_HDA_POWER_SAVE unsigned int power_on :1; /* current (global) power-state */ @@ -897,7 +898,9 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec); /* the struct for codec->pin_configs */ struct hda_pincfg { hda_nid_t nid; - unsigned int cfg; + unsigned char ctrl; /* current pin control value */ + unsigned char pad; /* reserved */ + unsigned int cfg; /* default configuration */ }; unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid); diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 54f74191ebca..3b789ee548b4 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -131,6 +131,8 @@ struct conexant_spec { unsigned int dc_enable; unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */ unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ + + unsigned int beep_amp; }; static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, @@ -515,6 +517,15 @@ static struct snd_kcontrol_new cxt_capture_mixers[] = { {} }; +#ifdef CONFIG_SND_HDA_INPUT_BEEP +/* additional beep mixers; the actual parameters are overwritten at build */ +static struct snd_kcontrol_new cxt_beep_mixer[] = { + HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), + HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), + { } /* end */ +}; +#endif + static const char *slave_vols[] = { "Headphone Playback Volume", "Speaker Playback Volume", @@ -580,6 +591,23 @@ static int conexant_build_controls(struct hda_codec *codec) return err; } +#ifdef CONFIG_SND_HDA_INPUT_BEEP + /* create beep controls if needed */ + if (spec->beep_amp) { + struct snd_kcontrol_new *knew; + for (knew = cxt_beep_mixer; knew->name; knew++) { + struct snd_kcontrol *kctl; + kctl = snd_ctl_new1(knew, codec); + if (!kctl) + return -ENOMEM; + kctl->private_value = spec->beep_amp; + err = snd_hda_ctl_add(codec, 0, kctl); + if (err < 0) + return err; + } + } +#endif + return 0; } @@ -590,6 +618,13 @@ static struct hda_codec_ops conexant_patch_ops = { .free = conexant_free, }; +#ifdef CONFIG_SND_HDA_INPUT_BEEP +#define set_beep_amp(spec, nid, idx, dir) \ + ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) +#else +#define set_beep_amp(spec, nid, idx, dir) /* NOP */ +#endif + /* * EAPD control * the private value = nid | (invert << 8) @@ -1130,9 +1165,10 @@ static int patch_cxt5045(struct hda_codec *codec) spec->num_init_verbs = 1; spec->init_verbs[0] = cxt5045_init_verbs; spec->spdif_route = 0; - spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes), - spec->channel_mode = cxt5045_modes, + spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes); + spec->channel_mode = cxt5045_modes; + set_beep_amp(spec, 0x16, 0, 1); codec->patch_ops = conexant_patch_ops; @@ -1211,6 +1247,9 @@ static int patch_cxt5045(struct hda_codec *codec) break; } + if (spec->beep_amp) + snd_hda_attach_beep_device(codec, spec->beep_amp); + return 0; } @@ -1987,6 +2026,8 @@ static int patch_cxt5051(struct hda_codec *codec) spec->cur_adc = 0; spec->cur_adc_idx = 0; + set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); + codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, @@ -2021,6 +2062,9 @@ static int patch_cxt5051(struct hda_codec *codec) break; } + if (spec->beep_amp) + snd_hda_attach_beep_device(codec, spec->beep_amp); + return 0; } @@ -2636,7 +2680,6 @@ static struct snd_kcontrol_new cxt5066_vostro_mixers[] = { .put = cxt5066_mic_boost_mux_enum_put, .private_value = 0x23 | 0x100, }, - HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), {} }; @@ -3034,6 +3077,8 @@ static int patch_cxt5066(struct hda_codec *codec) spec->cur_adc = 0; spec->cur_adc_idx = 0; + set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); + board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, cxt5066_models, cxt5066_cfg_tbl); switch (board_config) { @@ -3082,7 +3127,6 @@ static int patch_cxt5066(struct hda_codec *codec) spec->port_d_mode = 0; spec->dell_vostro = 1; spec->mic_boost = 3; /* default 30dB gain */ - snd_hda_attach_beep_device(codec, 0x13); /* no S/PDIF out */ spec->multiout.dig_out_nid = 0; @@ -3124,6 +3168,9 @@ static int patch_cxt5066(struct hda_codec *codec) break; } + if (spec->beep_amp) + snd_hda_attach_beep_device(codec, spec->beep_amp); + return 0; } |