summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2010-07-08 18:42:38 +0200
committerTakashi Iwai <tiwai@suse.de>2010-07-08 18:42:38 +0200
commit68cb4b7f9eafb1886b4f46c0d2ea9eb321b76831 (patch)
tree9e3ed81fdfa63242b1f221200508d5d36b06dabd /sound
parent30ee960e9d2252992c219815eb284490a9693365 (diff)
parentd47aaa4132a7016e035f2daeb41c722f145d630a (diff)
Merge branch 'topic/hda' into for-next
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/hda_codec.c59
-rw-r--r--sound/pci/hda/hda_codec.h5
-rw-r--r--sound/pci/hda/patch_conexant.c55
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;
}