Merge branch 'devel' of git.alsa-project.org:alsa-kernel into topic/misc
This commit is contained in:
Коммит
47e9134845
|
@ -394,6 +394,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
|
|||
+ HZ/100);
|
||||
/* move new_hw_ptr according jiffies not pos variable */
|
||||
new_hw_ptr = old_hw_ptr;
|
||||
hw_base = delta;
|
||||
/* use loop to avoid checks for delta overflows */
|
||||
/* the delta value is small or zero in most cases */
|
||||
while (delta > 0) {
|
||||
|
@ -403,8 +404,6 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
|
|||
delta--;
|
||||
}
|
||||
/* align hw_base to buffer_size */
|
||||
hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size);
|
||||
delta = 0;
|
||||
hw_ptr_error(substream,
|
||||
"hw_ptr skipping! %s"
|
||||
"(pos=%ld, delta=%ld, period=%ld, "
|
||||
|
@ -412,9 +411,12 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
|
|||
in_interrupt ? "[Q] " : "",
|
||||
(long)pos, (long)hdelta,
|
||||
(long)runtime->period_size, jdelta,
|
||||
((hdelta * HZ) / runtime->rate), delta,
|
||||
((hdelta * HZ) / runtime->rate), hw_base,
|
||||
(unsigned long)old_hw_ptr,
|
||||
(unsigned long)new_hw_ptr);
|
||||
/* reset values to proper state */
|
||||
delta = 0;
|
||||
hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size);
|
||||
}
|
||||
no_jiffies_check:
|
||||
if (delta > runtime->period_size + runtime->period_size / 2) {
|
||||
|
|
|
@ -824,6 +824,9 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
|
|||
struct hda_pincfg *pin;
|
||||
unsigned int oldcfg;
|
||||
|
||||
if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
|
||||
return -EINVAL;
|
||||
|
||||
oldcfg = snd_hda_codec_get_pincfg(codec, nid);
|
||||
pin = look_up_pincfg(codec, list, nid);
|
||||
if (!pin) {
|
||||
|
@ -899,6 +902,25 @@ static void restore_pincfgs(struct hda_codec *codec)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hda_shutup_pins - Shut up all pins
|
||||
* @codec: the HDA codec
|
||||
*
|
||||
* Clear all pin controls to shup up before suspend for avoiding click noise.
|
||||
* The controls aren't cached so that they can be resumed properly.
|
||||
*/
|
||||
void snd_hda_shutup_pins(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);
|
||||
/* use read here for syncing after issuing each verb */
|
||||
snd_hda_codec_read(codec, pin->nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_shutup_pins);
|
||||
|
||||
static void init_hda_cache(struct hda_cache_rec *cache,
|
||||
unsigned int record_size);
|
||||
static void free_hda_cache(struct hda_cache_rec *cache);
|
||||
|
@ -3537,32 +3559,6 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
|
|||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls);
|
||||
|
||||
/**
|
||||
* snd_hda_add_nids - assign nids to controls from the array
|
||||
* @codec: the HDA codec
|
||||
* @kctl: struct snd_kcontrol
|
||||
* @index: index to kctl
|
||||
* @nids: the array of hda_nid_t
|
||||
* @size: count of hda_nid_t items
|
||||
*
|
||||
* This helper function assigns NIDs in the given array to a control element.
|
||||
*
|
||||
* Returns 0 if successful, or a negative error code.
|
||||
*/
|
||||
int snd_hda_add_nids(struct hda_codec *codec, struct snd_kcontrol *kctl,
|
||||
unsigned int index, hda_nid_t *nids, unsigned int size)
|
||||
{
|
||||
int err;
|
||||
|
||||
for ( ; size > 0; size--, nids++) {
|
||||
err = snd_hda_add_nid(codec, kctl, index, *nids);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_add_nids);
|
||||
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
||||
unsigned int power_state);
|
||||
|
|
|
@ -898,6 +898,7 @@ 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 */
|
||||
void snd_hda_shutup_pins(struct hda_codec *codec);
|
||||
|
||||
/*
|
||||
* Mixer
|
||||
|
|
|
@ -293,8 +293,11 @@ static ssize_t type##_store(struct device *dev, \
|
|||
{ \
|
||||
struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
|
||||
struct hda_codec *codec = hwdep->private_data; \
|
||||
char *after; \
|
||||
codec->type = simple_strtoul(buf, &after, 0); \
|
||||
unsigned long val; \
|
||||
int err = strict_strtoul(buf, 0, &val); \
|
||||
if (err < 0) \
|
||||
return err; \
|
||||
codec->type = val; \
|
||||
return count; \
|
||||
}
|
||||
|
||||
|
|
|
@ -356,6 +356,7 @@ struct azx_dev {
|
|||
*/
|
||||
unsigned char stream_tag; /* assigned stream */
|
||||
unsigned char index; /* stream index */
|
||||
int device; /* last device number assigned to */
|
||||
|
||||
unsigned int opened :1;
|
||||
unsigned int running :1;
|
||||
|
@ -1441,10 +1442,13 @@ static int __devinit azx_codec_configure(struct azx *chip)
|
|||
*/
|
||||
|
||||
/* assign a stream for the PCM */
|
||||
static inline struct azx_dev *azx_assign_device(struct azx *chip, int stream)
|
||||
static inline struct azx_dev *
|
||||
azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream)
|
||||
{
|
||||
int dev, i, nums;
|
||||
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
struct azx_dev *res = NULL;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
dev = chip->playback_index_offset;
|
||||
nums = chip->playback_streams;
|
||||
} else {
|
||||
|
@ -1453,10 +1457,15 @@ static inline struct azx_dev *azx_assign_device(struct azx *chip, int stream)
|
|||
}
|
||||
for (i = 0; i < nums; i++, dev++)
|
||||
if (!chip->azx_dev[dev].opened) {
|
||||
chip->azx_dev[dev].opened = 1;
|
||||
return &chip->azx_dev[dev];
|
||||
res = &chip->azx_dev[dev];
|
||||
if (res->device == substream->pcm->device)
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
if (res) {
|
||||
res->opened = 1;
|
||||
res->device = substream->pcm->device;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* release the assigned stream */
|
||||
|
@ -1505,7 +1514,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
|
|||
int err;
|
||||
|
||||
mutex_lock(&chip->open_mutex);
|
||||
azx_dev = azx_assign_device(chip, substream->stream);
|
||||
azx_dev = azx_assign_device(chip, substream);
|
||||
if (azx_dev == NULL) {
|
||||
mutex_unlock(&chip->open_mutex);
|
||||
return -EBUSY;
|
||||
|
@ -2695,32 +2704,10 @@ static struct pci_device_id azx_ids[] = {
|
|||
/* ULI M5461 */
|
||||
{ PCI_DEVICE(0x10b9, 0x5461), .driver_data = AZX_DRIVER_ULI },
|
||||
/* NVIDIA MCP */
|
||||
{ PCI_DEVICE(0x10de, 0x026c), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0371), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x03e4), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x03f0), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x044a), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x044b), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x055c), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x055d), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0590), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0774), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0775), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0776), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0777), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x07fc), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x07fd), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0ac0), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0be2), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0be3), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0be4), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0d94), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0d95), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0d96), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
|
||||
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
|
||||
.class_mask = 0xffffff,
|
||||
.driver_data = AZX_DRIVER_NVIDIA },
|
||||
/* Teradici */
|
||||
{ PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA },
|
||||
/* Creative X-Fi (CA0110-IBG) */
|
||||
|
|
|
@ -343,8 +343,6 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
|
|||
const struct snd_pci_quirk *tbl);
|
||||
int snd_hda_add_new_ctls(struct hda_codec *codec,
|
||||
struct snd_kcontrol_new *knew);
|
||||
int snd_hda_add_nids(struct hda_codec *codec, struct snd_kcontrol *kctl,
|
||||
unsigned int index, hda_nid_t *nids, unsigned int size);
|
||||
|
||||
/*
|
||||
* unsolicited event handler
|
||||
|
|
|
@ -244,8 +244,7 @@ static int ad198x_build_controls(struct hda_codec *codec)
|
|||
if (!kctl)
|
||||
kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
|
||||
for (i = 0; kctl && i < kctl->count; i++) {
|
||||
err = snd_hda_add_nids(codec, kctl, i, spec->capsrc_nids,
|
||||
spec->input_mux->num_items);
|
||||
err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
@ -442,6 +441,11 @@ static int ad198x_build_pcms(struct hda_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void ad198x_shutup(struct hda_codec *codec)
|
||||
{
|
||||
snd_hda_shutup_pins(codec);
|
||||
}
|
||||
|
||||
static void ad198x_free_kctls(struct hda_codec *codec)
|
||||
{
|
||||
struct ad198x_spec *spec = codec->spec;
|
||||
|
@ -455,6 +459,46 @@ static void ad198x_free_kctls(struct hda_codec *codec)
|
|||
snd_array_free(&spec->kctls);
|
||||
}
|
||||
|
||||
static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
|
||||
hda_nid_t hp)
|
||||
{
|
||||
struct ad198x_spec *spec = codec->spec;
|
||||
snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
|
||||
!spec->inv_eapd ? 0x00 : 0x02);
|
||||
snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
|
||||
!spec->inv_eapd ? 0x00 : 0x02);
|
||||
}
|
||||
|
||||
static void ad198x_power_eapd(struct hda_codec *codec)
|
||||
{
|
||||
/* We currently only handle front, HP */
|
||||
switch (codec->vendor_id) {
|
||||
case 0x11d41882:
|
||||
case 0x11d4882a:
|
||||
case 0x11d41884:
|
||||
case 0x11d41984:
|
||||
case 0x11d41883:
|
||||
case 0x11d4184a:
|
||||
case 0x11d4194a:
|
||||
case 0x11d4194b:
|
||||
ad198x_power_eapd_write(codec, 0x12, 0x11);
|
||||
break;
|
||||
case 0x11d41981:
|
||||
case 0x11d41983:
|
||||
ad198x_power_eapd_write(codec, 0x05, 0x06);
|
||||
break;
|
||||
case 0x11d41986:
|
||||
ad198x_power_eapd_write(codec, 0x1b, 0x1a);
|
||||
break;
|
||||
case 0x11d41988:
|
||||
case 0x11d4198b:
|
||||
case 0x11d4989a:
|
||||
case 0x11d4989b:
|
||||
ad198x_power_eapd_write(codec, 0x29, 0x22);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ad198x_free(struct hda_codec *codec)
|
||||
{
|
||||
struct ad198x_spec *spec = codec->spec;
|
||||
|
@ -462,11 +506,29 @@ static void ad198x_free(struct hda_codec *codec)
|
|||
if (!spec)
|
||||
return;
|
||||
|
||||
ad198x_shutup(codec);
|
||||
ad198x_free_kctls(codec);
|
||||
kfree(spec);
|
||||
snd_hda_detach_beep_device(codec);
|
||||
}
|
||||
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
static int ad198x_suspend(struct hda_codec *codec, pm_message_t state)
|
||||
{
|
||||
ad198x_shutup(codec);
|
||||
ad198x_power_eapd(codec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad198x_resume(struct hda_codec *codec)
|
||||
{
|
||||
ad198x_init(codec);
|
||||
snd_hda_codec_resume_amp(codec);
|
||||
snd_hda_codec_resume_cache(codec);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct hda_codec_ops ad198x_patch_ops = {
|
||||
.build_controls = ad198x_build_controls,
|
||||
.build_pcms = ad198x_build_pcms,
|
||||
|
@ -475,6 +537,11 @@ static struct hda_codec_ops ad198x_patch_ops = {
|
|||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
.check_power_status = ad198x_check_power_status,
|
||||
#endif
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
.suspend = ad198x_suspend,
|
||||
.resume = ad198x_resume,
|
||||
#endif
|
||||
.reboot_notify = ad198x_shutup,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -753,6 +753,7 @@ static int build_input(struct hda_codec *codec)
|
|||
spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol);
|
||||
for (i = 0; i < 2; i++) {
|
||||
struct snd_kcontrol *kctl;
|
||||
int n;
|
||||
if (!spec->capture_bind[i])
|
||||
return -ENOMEM;
|
||||
kctl = snd_ctl_new1(&cs_capture_ctls[i], codec);
|
||||
|
@ -762,10 +763,13 @@ static int build_input(struct hda_codec *codec)
|
|||
err = snd_hda_ctl_add(codec, 0, kctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_hda_add_nids(codec, kctl, 0, spec->adc_nid,
|
||||
spec->num_inputs);
|
||||
if (err < 0)
|
||||
return err;
|
||||
for (n = 0; n < AUTO_PIN_LAST; n++) {
|
||||
if (!spec->adc_nid[n])
|
||||
continue;
|
||||
err = snd_hda_add_nid(codec, kctl, 0, spec->adc_nid[i]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (spec->num_inputs > 1 && !spec->mic_detect) {
|
||||
|
|
|
@ -345,8 +345,7 @@ static int cmi9880_build_controls(struct hda_codec *codec)
|
|||
/* assign Capture Source enums to NID */
|
||||
kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
|
||||
for (i = 0; kctl && i < kctl->count; i++) {
|
||||
err = snd_hda_add_nids(codec, kctl, i, spec->adc_nids,
|
||||
spec->input_mux->num_items);
|
||||
err = snd_hda_add_nid(codec, kctl, i, spec->adc_nids[i]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -111,8 +111,22 @@ struct conexant_spec {
|
|||
|
||||
unsigned int dell_automute;
|
||||
unsigned int port_d_mode;
|
||||
unsigned char ext_mic_bias;
|
||||
unsigned int dell_vostro;
|
||||
|
||||
unsigned int ext_mic_present;
|
||||
unsigned int recording;
|
||||
void (*capture_prepare)(struct hda_codec *codec);
|
||||
void (*capture_cleanup)(struct hda_codec *codec);
|
||||
|
||||
/* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors)
|
||||
* through the microphone jack.
|
||||
* When the user enables this through a mixer switch, both internal and
|
||||
* external microphones are disabled. Gain is fixed at 0dB. In this mode,
|
||||
* we also allow the bias to be configured through a separate mixer
|
||||
* control. */
|
||||
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 */
|
||||
};
|
||||
|
||||
static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
|
||||
|
@ -185,6 +199,8 @@ static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
|
|||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
if (spec->capture_prepare)
|
||||
spec->capture_prepare(codec);
|
||||
snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
|
||||
stream_tag, 0, format);
|
||||
return 0;
|
||||
|
@ -196,6 +212,8 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
|||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
|
||||
if (spec->capture_cleanup)
|
||||
spec->capture_cleanup(codec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1723,6 +1741,22 @@ static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new cxt5051_f700_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Master Playback Switch",
|
||||
.info = cxt_eapd_info,
|
||||
.get = cxt_eapd_get,
|
||||
.put = cxt5051_hp_master_sw_put,
|
||||
.private_value = 0x1a,
|
||||
},
|
||||
|
||||
{}
|
||||
};
|
||||
|
||||
static struct hda_verb cxt5051_init_verbs[] = {
|
||||
/* Line in, Mic */
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
|
||||
|
@ -1813,6 +1847,32 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
|
|||
{ } /* end */
|
||||
};
|
||||
|
||||
static struct hda_verb cxt5051_f700_init_verbs[] = {
|
||||
/* Line in, Mic */
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x03},
|
||||
{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0},
|
||||
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0},
|
||||
/* SPK */
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
/* HP, Amp */
|
||||
{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
/* DAC1 */
|
||||
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
/* Record selector: Int mic */
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
|
||||
{0x14, AC_VERB_SET_CONNECT_SEL, 0x1},
|
||||
/* SPDIF route: PCM */
|
||||
{0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
|
||||
/* EAPD */
|
||||
{0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
|
||||
{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
|
||||
{0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
/* initialize jack-sensing, too */
|
||||
static int cxt5051_init(struct hda_codec *codec)
|
||||
{
|
||||
|
@ -1832,6 +1892,7 @@ enum {
|
|||
CXT5051_HP, /* no docking */
|
||||
CXT5051_HP_DV6736, /* HP without mic switch */
|
||||
CXT5051_LENOVO_X200, /* Lenovo X200 laptop */
|
||||
CXT5051_F700, /* HP Compaq Presario F700 */
|
||||
CXT5051_MODELS
|
||||
};
|
||||
|
||||
|
@ -1840,6 +1901,7 @@ static const char *cxt5051_models[CXT5051_MODELS] = {
|
|||
[CXT5051_HP] = "hp",
|
||||
[CXT5051_HP_DV6736] = "hp-dv6736",
|
||||
[CXT5051_LENOVO_X200] = "lenovo-x200",
|
||||
[CXT5051_F700] = "hp 700"
|
||||
};
|
||||
|
||||
static struct snd_pci_quirk cxt5051_cfg_tbl[] = {
|
||||
|
@ -1849,6 +1911,7 @@ static struct snd_pci_quirk cxt5051_cfg_tbl[] = {
|
|||
CXT5051_LAPTOP),
|
||||
SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP),
|
||||
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200),
|
||||
SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700),
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -1899,6 +1962,11 @@ static int patch_cxt5051(struct hda_codec *codec)
|
|||
case CXT5051_LENOVO_X200:
|
||||
spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs;
|
||||
break;
|
||||
case CXT5051_F700:
|
||||
spec->init_verbs[0] = cxt5051_f700_init_verbs;
|
||||
spec->mixers[0] = cxt5051_f700_mixers;
|
||||
spec->no_auto_mic = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1966,53 +2034,97 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol,
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* toggle input of built-in and mic jack appropriately */
|
||||
static void cxt5066_automic(struct hda_codec *codec)
|
||||
static const struct hda_input_mux cxt5066_olpc_dc_bias = {
|
||||
.num_items = 3,
|
||||
.items = {
|
||||
{ "Off", PIN_IN },
|
||||
{ "50%", PIN_VREF50 },
|
||||
{ "80%", PIN_VREF80 },
|
||||
},
|
||||
};
|
||||
|
||||
static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
struct hda_verb ext_mic_present[] = {
|
||||
/* enable external mic, port B */
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias},
|
||||
/* Even though port F is the DC input, the bias is controlled on port B.
|
||||
* we also leave that port as an active input (but unselected) in DC mode
|
||||
* just in case that is necessary to make the bias setting take effect. */
|
||||
return snd_hda_codec_write_cache(codec, 0x1a, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index);
|
||||
}
|
||||
|
||||
/* switch to external mic input */
|
||||
{0x17, AC_VERB_SET_CONNECT_SEL, 0},
|
||||
/* OLPC defers mic widget control until when capture is started because the
|
||||
* microphone LED comes on as soon as these settings are put in place. if we
|
||||
* did this before recording, it would give the false indication that recording
|
||||
* is happening when it is not. */
|
||||
static void cxt5066_olpc_select_mic(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
if (!spec->recording)
|
||||
return;
|
||||
|
||||
/* disable internal mic, port C */
|
||||
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
{}
|
||||
};
|
||||
static struct hda_verb ext_mic_absent[] = {
|
||||
/* enable internal mic, port C */
|
||||
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
if (spec->dc_enable) {
|
||||
/* in DC mode we ignore presence detection and just use the jack
|
||||
* through our special DC port */
|
||||
const struct hda_verb enable_dc_mode[] = {
|
||||
/* disble internal mic, port C */
|
||||
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
|
||||
/* switch to internal mic input */
|
||||
{0x17, AC_VERB_SET_CONNECT_SEL, 1},
|
||||
/* enable DC capture, port F */
|
||||
{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{},
|
||||
};
|
||||
|
||||
/* disable external mic, port B */
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
{}
|
||||
};
|
||||
snd_hda_sequence_write(codec, enable_dc_mode);
|
||||
/* port B input disabled (and bias set) through the following call */
|
||||
cxt5066_set_olpc_dc_bias(codec);
|
||||
return;
|
||||
}
|
||||
|
||||
/* disable DC (port F) */
|
||||
snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
|
||||
|
||||
/* external mic, port B */
|
||||
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0);
|
||||
|
||||
/* internal mic, port C */
|
||||
snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
spec->ext_mic_present ? 0 : PIN_VREF80);
|
||||
}
|
||||
|
||||
/* toggle input of built-in and mic jack appropriately */
|
||||
static void cxt5066_olpc_automic(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
unsigned int present;
|
||||
|
||||
present = snd_hda_jack_detect(codec, 0x1a);
|
||||
if (present) {
|
||||
if (spec->dc_enable) /* don't do presence detection in DC mode */
|
||||
return;
|
||||
|
||||
present = snd_hda_codec_read(codec, 0x1a, 0,
|
||||
AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
|
||||
if (present)
|
||||
snd_printdd("CXT5066: external microphone detected\n");
|
||||
snd_hda_sequence_write(codec, ext_mic_present);
|
||||
} else {
|
||||
else
|
||||
snd_printdd("CXT5066: external microphone absent\n");
|
||||
snd_hda_sequence_write(codec, ext_mic_absent);
|
||||
}
|
||||
|
||||
snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
|
||||
present ? 0 : 1);
|
||||
spec->ext_mic_present = !!present;
|
||||
|
||||
cxt5066_olpc_select_mic(codec);
|
||||
}
|
||||
|
||||
/* toggle input of built-in digital mic and mic jack appropriately */
|
||||
static void cxt5066_vostro_automic(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
unsigned int present;
|
||||
|
||||
struct hda_verb ext_mic_present[] = {
|
||||
/* enable external mic, port B */
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias},
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
|
||||
/* switch to external mic input */
|
||||
{0x17, AC_VERB_SET_CONNECT_SEL, 0},
|
||||
|
@ -2063,15 +2175,18 @@ static void cxt5066_hp_automute(struct hda_codec *codec)
|
|||
}
|
||||
|
||||
/* unsolicited event for jack sensing */
|
||||
static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res)
|
||||
static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
|
||||
switch (res >> 26) {
|
||||
case CONEXANT_HP_EVENT:
|
||||
cxt5066_hp_automute(codec);
|
||||
break;
|
||||
case CONEXANT_MIC_EVENT:
|
||||
cxt5066_automic(codec);
|
||||
/* ignore mic events in DC mode; we're always using the jack */
|
||||
if (!spec->dc_enable)
|
||||
cxt5066_olpc_automic(codec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2101,6 +2216,15 @@ static const struct hda_input_mux cxt5066_analog_mic_boost = {
|
|||
},
|
||||
};
|
||||
|
||||
static int cxt5066_set_mic_boost(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
return snd_hda_codec_write_cache(codec, 0x17, 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT |
|
||||
cxt5066_analog_mic_boost.items[spec->mic_boost].index);
|
||||
}
|
||||
|
||||
static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
|
@ -2111,15 +2235,8 @@ static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
int val;
|
||||
hda_nid_t nid = kcontrol->private_value & 0xff;
|
||||
int inout = (kcontrol->private_value & 0x100) ?
|
||||
AC_AMP_GET_INPUT : AC_AMP_GET_OUTPUT;
|
||||
|
||||
val = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_AMP_GAIN_MUTE, inout);
|
||||
|
||||
ucontrol->value.enumerated.item[0] = val & AC_AMP_GAIN;
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
ucontrol->value.enumerated.item[0] = spec->mic_boost;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2127,26 +2244,132 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
const struct hda_input_mux *imux = &cxt5066_analog_mic_boost;
|
||||
unsigned int idx;
|
||||
hda_nid_t nid = kcontrol->private_value & 0xff;
|
||||
int inout = (kcontrol->private_value & 0x100) ?
|
||||
AC_AMP_SET_INPUT : AC_AMP_SET_OUTPUT;
|
||||
|
||||
if (!imux->num_items)
|
||||
return 0;
|
||||
idx = ucontrol->value.enumerated.item[0];
|
||||
if (idx >= imux->num_items)
|
||||
idx = imux->num_items - 1;
|
||||
|
||||
snd_hda_codec_write_cache(codec, nid, 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | inout |
|
||||
imux->items[idx].index);
|
||||
spec->mic_boost = idx;
|
||||
if (!spec->dc_enable)
|
||||
cxt5066_set_mic_boost(codec);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void cxt5066_enable_dc(struct hda_codec *codec)
|
||||
{
|
||||
const struct hda_verb enable_dc_mode[] = {
|
||||
/* disable gain */
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
|
||||
/* switch to DC input */
|
||||
{0x17, AC_VERB_SET_CONNECT_SEL, 3},
|
||||
{}
|
||||
};
|
||||
|
||||
/* configure as input source */
|
||||
snd_hda_sequence_write(codec, enable_dc_mode);
|
||||
cxt5066_olpc_select_mic(codec); /* also sets configured bias */
|
||||
}
|
||||
|
||||
static void cxt5066_disable_dc(struct hda_codec *codec)
|
||||
{
|
||||
/* reconfigure input source */
|
||||
cxt5066_set_mic_boost(codec);
|
||||
/* automic also selects the right mic if we're recording */
|
||||
cxt5066_olpc_automic(codec);
|
||||
}
|
||||
|
||||
static int cxt5066_olpc_dc_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
ucontrol->value.integer.value[0] = spec->dc_enable;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxt5066_olpc_dc_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
int dc_enable = !!ucontrol->value.integer.value[0];
|
||||
|
||||
if (dc_enable == spec->dc_enable)
|
||||
return 0;
|
||||
|
||||
spec->dc_enable = dc_enable;
|
||||
if (dc_enable)
|
||||
cxt5066_enable_dc(codec);
|
||||
else
|
||||
cxt5066_disable_dc(codec);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cxt5066_olpc_dc_bias_enum_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
return snd_hda_input_mux_info(&cxt5066_olpc_dc_bias, uinfo);
|
||||
}
|
||||
|
||||
static int cxt5066_olpc_dc_bias_enum_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
ucontrol->value.enumerated.item[0] = spec->dc_input_bias;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxt5066_olpc_dc_bias_enum_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
const struct hda_input_mux *imux = &cxt5066_analog_mic_boost;
|
||||
unsigned int idx;
|
||||
|
||||
idx = ucontrol->value.enumerated.item[0];
|
||||
if (idx >= imux->num_items)
|
||||
idx = imux->num_items - 1;
|
||||
|
||||
spec->dc_input_bias = idx;
|
||||
if (spec->dc_enable)
|
||||
cxt5066_set_olpc_dc_bias(codec);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void cxt5066_olpc_capture_prepare(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
/* mark as recording and configure the microphone widget so that the
|
||||
* recording LED comes on. */
|
||||
spec->recording = 1;
|
||||
cxt5066_olpc_select_mic(codec);
|
||||
}
|
||||
|
||||
static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
const struct hda_verb disable_mics[] = {
|
||||
/* disable external mic, port B */
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
|
||||
/* disble internal mic, port C */
|
||||
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
|
||||
/* disable DC capture, port F */
|
||||
{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
{},
|
||||
};
|
||||
|
||||
snd_hda_sequence_write(codec, disable_mics);
|
||||
spec->recording = 0;
|
||||
}
|
||||
|
||||
static struct hda_input_mux cxt5066_capture_source = {
|
||||
.num_items = 4,
|
||||
.items = {
|
||||
|
@ -2199,6 +2422,24 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "DC Mode Enable Switch",
|
||||
.info = snd_ctl_boolean_mono_info,
|
||||
.get = cxt5066_olpc_dc_get,
|
||||
.put = cxt5066_olpc_dc_put,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "DC Input Bias Enum",
|
||||
.info = cxt5066_olpc_dc_bias_enum_info,
|
||||
.get = cxt5066_olpc_dc_bias_enum_get,
|
||||
.put = cxt5066_olpc_dc_bias_enum_put,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new cxt5066_mixers[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
|
@ -2211,11 +2452,10 @@ static struct snd_kcontrol_new cxt5066_mixers[] = {
|
|||
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Ext Mic Boost Capture Enum",
|
||||
.name = "Analog Mic Boost Capture Enum",
|
||||
.info = cxt5066_mic_boost_mux_enum_info,
|
||||
.get = cxt5066_mic_boost_mux_enum_get,
|
||||
.put = cxt5066_mic_boost_mux_enum_put,
|
||||
.private_value = 0x17,
|
||||
},
|
||||
|
||||
HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others),
|
||||
|
@ -2297,10 +2537,10 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = {
|
|||
{0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
|
||||
|
||||
/* Port B: external microphone */
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, CXT5066_OLPC_EXT_MIC_BIAS},
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
|
||||
/* Port C: internal microphone */
|
||||
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
|
||||
/* Port D: unused */
|
||||
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
|
@ -2309,7 +2549,7 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = {
|
|||
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
{0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
|
||||
|
||||
/* Port F: unused */
|
||||
/* Port F: external DC input through microphone port */
|
||||
{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
|
||||
/* Port G: internal speakers */
|
||||
|
@ -2429,8 +2669,22 @@ static int cxt5066_init(struct hda_codec *codec)
|
|||
cxt5066_hp_automute(codec);
|
||||
if (spec->dell_vostro)
|
||||
cxt5066_vostro_automic(codec);
|
||||
else
|
||||
cxt5066_automic(codec);
|
||||
}
|
||||
cxt5066_set_mic_boost(codec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxt5066_olpc_init(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
snd_printdd("CXT5066: init\n");
|
||||
conexant_init(codec);
|
||||
cxt5066_hp_automute(codec);
|
||||
if (!spec->dc_enable) {
|
||||
cxt5066_set_mic_boost(codec);
|
||||
cxt5066_olpc_automic(codec);
|
||||
} else {
|
||||
cxt5066_enable_dc(codec);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -2471,7 +2725,7 @@ static int patch_cxt5066(struct hda_codec *codec)
|
|||
codec->spec = spec;
|
||||
|
||||
codec->patch_ops = conexant_patch_ops;
|
||||
codec->patch_ops.init = cxt5066_init;
|
||||
codec->patch_ops.init = conexant_init;
|
||||
|
||||
spec->dell_automute = 0;
|
||||
spec->multiout.max_channels = 2;
|
||||
|
@ -2484,7 +2738,6 @@ static int patch_cxt5066(struct hda_codec *codec)
|
|||
spec->input_mux = &cxt5066_capture_source;
|
||||
|
||||
spec->port_d_mode = PIN_HP;
|
||||
spec->ext_mic_bias = PIN_VREF80;
|
||||
|
||||
spec->num_init_verbs = 1;
|
||||
spec->init_verbs[0] = cxt5066_init_verbs;
|
||||
|
@ -2511,20 +2764,28 @@ static int patch_cxt5066(struct hda_codec *codec)
|
|||
spec->dell_automute = 1;
|
||||
break;
|
||||
case CXT5066_OLPC_XO_1_5:
|
||||
codec->patch_ops.unsol_event = cxt5066_unsol_event;
|
||||
codec->patch_ops.init = cxt5066_olpc_init;
|
||||
codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event;
|
||||
spec->init_verbs[0] = cxt5066_init_verbs_olpc;
|
||||
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
|
||||
spec->mixers[spec->num_mixers++] = cxt5066_mixer_olpc_dc;
|
||||
spec->mixers[spec->num_mixers++] = cxt5066_mixers;
|
||||
spec->port_d_mode = 0;
|
||||
spec->ext_mic_bias = CXT5066_OLPC_EXT_MIC_BIAS;
|
||||
spec->mic_boost = 3; /* default 30dB gain */
|
||||
|
||||
/* no S/PDIF out */
|
||||
spec->multiout.dig_out_nid = 0;
|
||||
|
||||
/* input source automatically selected */
|
||||
spec->input_mux = NULL;
|
||||
|
||||
/* our capture hooks which allow us to turn on the microphone LED
|
||||
* at the right time */
|
||||
spec->capture_prepare = cxt5066_olpc_capture_prepare;
|
||||
spec->capture_cleanup = cxt5066_olpc_capture_cleanup;
|
||||
break;
|
||||
case CXT5066_DELL_VOSTO:
|
||||
codec->patch_ops.init = cxt5066_init;
|
||||
codec->patch_ops.unsol_event = cxt5066_vostro_event;
|
||||
spec->init_verbs[0] = cxt5066_init_verbs_vostro;
|
||||
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
|
||||
|
@ -2532,6 +2793,7 @@ static int patch_cxt5066(struct hda_codec *codec)
|
|||
spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers;
|
||||
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 */
|
||||
|
|
|
@ -338,7 +338,7 @@ struct alc_spec {
|
|||
void (*init_hook)(struct hda_codec *codec);
|
||||
void (*unsol_event)(struct hda_codec *codec, unsigned int res);
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
void (*power_hook)(struct hda_codec *codec, int power);
|
||||
void (*power_hook)(struct hda_codec *codec);
|
||||
#endif
|
||||
|
||||
/* for pin sensing */
|
||||
|
@ -391,7 +391,7 @@ struct alc_config_preset {
|
|||
void (*init_hook)(struct hda_codec *);
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
struct hda_amp_list *loopbacks;
|
||||
void (*power_hook)(struct hda_codec *codec, int power);
|
||||
void (*power_hook)(struct hda_codec *codec);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -1835,16 +1835,6 @@ static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
|
|||
spec->autocfg.speaker_pins[2] = 0x1b;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
static void alc889_power_eapd(struct hda_codec *codec, int power)
|
||||
{
|
||||
snd_hda_codec_write(codec, 0x14, 0,
|
||||
AC_VERB_SET_EAPD_BTLENABLE, power ? 2 : 0);
|
||||
snd_hda_codec_write(codec, 0x15, 0,
|
||||
AC_VERB_SET_EAPD_BTLENABLE, power ? 2 : 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ALC880 3-stack model
|
||||
*
|
||||
|
@ -2548,8 +2538,10 @@ static int alc_build_controls(struct hda_codec *codec)
|
|||
if (!kctl)
|
||||
kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
|
||||
for (i = 0; kctl && i < kctl->count; i++) {
|
||||
err = snd_hda_add_nids(codec, kctl, i, spec->capsrc_nids,
|
||||
spec->input_mux->num_items);
|
||||
hda_nid_t *nids = spec->capsrc_nids;
|
||||
if (!nids)
|
||||
nids = spec->adc_nids;
|
||||
err = snd_hda_add_nid(codec, kctl, i, nids[i]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
@ -3691,6 +3683,11 @@ static int alc_build_pcms(struct hda_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void alc_shutup(struct hda_codec *codec)
|
||||
{
|
||||
snd_hda_shutup_pins(codec);
|
||||
}
|
||||
|
||||
static void alc_free_kctls(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
|
@ -3711,17 +3708,47 @@ static void alc_free(struct hda_codec *codec)
|
|||
if (!spec)
|
||||
return;
|
||||
|
||||
alc_shutup(codec);
|
||||
alc_free_kctls(codec);
|
||||
kfree(spec);
|
||||
snd_hda_detach_beep_device(codec);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
static void alc_power_eapd(struct hda_codec *codec)
|
||||
{
|
||||
/* We currently only handle front, HP */
|
||||
switch (codec->vendor_id) {
|
||||
case 0x10ec0260:
|
||||
snd_hda_codec_write(codec, 0x0f, 0,
|
||||
AC_VERB_SET_EAPD_BTLENABLE, 0x00);
|
||||
snd_hda_codec_write(codec, 0x10, 0,
|
||||
AC_VERB_SET_EAPD_BTLENABLE, 0x00);
|
||||
break;
|
||||
case 0x10ec0262:
|
||||
case 0x10ec0267:
|
||||
case 0x10ec0268:
|
||||
case 0x10ec0269:
|
||||
case 0x10ec0272:
|
||||
case 0x10ec0660:
|
||||
case 0x10ec0662:
|
||||
case 0x10ec0663:
|
||||
case 0x10ec0862:
|
||||
case 0x10ec0889:
|
||||
snd_hda_codec_write(codec, 0x14, 0,
|
||||
AC_VERB_SET_EAPD_BTLENABLE, 0x00);
|
||||
snd_hda_codec_write(codec, 0x15, 0,
|
||||
AC_VERB_SET_EAPD_BTLENABLE, 0x00);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int alc_suspend(struct hda_codec *codec, pm_message_t state)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
alc_shutup(codec);
|
||||
if (spec && spec->power_hook)
|
||||
spec->power_hook(codec, 0);
|
||||
spec->power_hook(codec);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -3729,16 +3756,9 @@ static int alc_suspend(struct hda_codec *codec, pm_message_t state)
|
|||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
static int alc_resume(struct hda_codec *codec)
|
||||
{
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
struct alc_spec *spec = codec->spec;
|
||||
#endif
|
||||
codec->patch_ops.init(codec);
|
||||
snd_hda_codec_resume_amp(codec);
|
||||
snd_hda_codec_resume_cache(codec);
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
if (spec && spec->power_hook)
|
||||
spec->power_hook(codec, 1);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -3758,6 +3778,7 @@ static struct hda_codec_ops alc_patch_ops = {
|
|||
.suspend = alc_suspend,
|
||||
.check_power_status = alc_check_power_status,
|
||||
#endif
|
||||
.reboot_notify = alc_shutup,
|
||||
};
|
||||
|
||||
|
||||
|
@ -9538,7 +9559,7 @@ static struct alc_config_preset alc882_presets[] = {
|
|||
.setup = alc889_acer_aspire_8930g_setup,
|
||||
.init_hook = alc_automute_amp,
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
.power_hook = alc889_power_eapd,
|
||||
.power_hook = alc_power_eapd,
|
||||
#endif
|
||||
},
|
||||
[ALC888_ACER_ASPIRE_7730G] = {
|
||||
|
@ -14975,8 +14996,12 @@ static int patch_alc861(struct hda_codec *codec)
|
|||
spec->vmaster_nid = 0x03;
|
||||
|
||||
codec->patch_ops = alc_patch_ops;
|
||||
if (board_config == ALC861_AUTO)
|
||||
if (board_config == ALC861_AUTO) {
|
||||
spec->init_hook = alc861_auto_init;
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
spec->power_hook = alc_power_eapd;
|
||||
#endif
|
||||
}
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
if (!spec->loopback.amplist)
|
||||
spec->loopback.amplist = alc861_loopbacks;
|
||||
|
|
|
@ -4159,34 +4159,52 @@ static void stac92xx_power_down(struct hda_codec *codec)
|
|||
static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
|
||||
int enable);
|
||||
|
||||
static inline int get_int_hint(struct hda_codec *codec, const char *key,
|
||||
int *valp)
|
||||
{
|
||||
const char *p;
|
||||
p = snd_hda_get_hint(codec, key);
|
||||
if (p) {
|
||||
unsigned long val;
|
||||
if (!strict_strtoul(p, 0, &val)) {
|
||||
*valp = val;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* override some hints from the hwdep entry */
|
||||
static void stac_store_hints(struct hda_codec *codec)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
const char *p;
|
||||
int val;
|
||||
|
||||
val = snd_hda_get_bool_hint(codec, "hp_detect");
|
||||
if (val >= 0)
|
||||
spec->hp_detect = val;
|
||||
p = snd_hda_get_hint(codec, "gpio_mask");
|
||||
if (p) {
|
||||
spec->gpio_mask = simple_strtoul(p, NULL, 0);
|
||||
if (get_int_hint(codec, "gpio_mask", &spec->gpio_mask)) {
|
||||
spec->eapd_mask = spec->gpio_dir = spec->gpio_data =
|
||||
spec->gpio_mask;
|
||||
}
|
||||
p = snd_hda_get_hint(codec, "gpio_dir");
|
||||
if (p)
|
||||
spec->gpio_dir = simple_strtoul(p, NULL, 0) & spec->gpio_mask;
|
||||
p = snd_hda_get_hint(codec, "gpio_data");
|
||||
if (p)
|
||||
spec->gpio_data = simple_strtoul(p, NULL, 0) & spec->gpio_mask;
|
||||
p = snd_hda_get_hint(codec, "eapd_mask");
|
||||
if (p)
|
||||
spec->eapd_mask = simple_strtoul(p, NULL, 0) & spec->gpio_mask;
|
||||
if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir))
|
||||
spec->gpio_mask &= spec->gpio_mask;
|
||||
if (get_int_hint(codec, "gpio_data", &spec->gpio_data))
|
||||
spec->gpio_dir &= spec->gpio_mask;
|
||||
if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask))
|
||||
spec->eapd_mask &= spec->gpio_mask;
|
||||
if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute))
|
||||
spec->gpio_mute &= spec->gpio_mask;
|
||||
val = snd_hda_get_bool_hint(codec, "eapd_switch");
|
||||
if (val >= 0)
|
||||
spec->eapd_switch = val;
|
||||
get_int_hint(codec, "gpio_led_polarity", &spec->gpio_led_polarity);
|
||||
if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) {
|
||||
spec->gpio_mask |= spec->gpio_led;
|
||||
spec->gpio_dir |= spec->gpio_led;
|
||||
if (spec->gpio_led_polarity)
|
||||
spec->gpio_data |= spec->gpio_led;
|
||||
}
|
||||
}
|
||||
|
||||
static int stac92xx_init(struct hda_codec *codec)
|
||||
|
@ -4371,18 +4389,8 @@ static void stac92xx_free_kctls(struct hda_codec *codec)
|
|||
static void stac92xx_shutup(struct hda_codec *codec)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
int i;
|
||||
hda_nid_t nid;
|
||||
|
||||
/* reset each pin before powering down DAC/ADC to avoid click noise */
|
||||
nid = codec->start_nid;
|
||||
for (i = 0; i < codec->num_nodes; i++, nid++) {
|
||||
unsigned int wcaps = get_wcaps(codec, nid);
|
||||
unsigned int wid_type = get_wcaps_type(wcaps);
|
||||
if (wid_type == AC_WID_PIN)
|
||||
snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
|
||||
}
|
||||
snd_hda_shutup_pins(codec);
|
||||
|
||||
if (spec->eapd_mask)
|
||||
stac_gpio_set(codec, spec->gpio_mask,
|
||||
|
@ -5406,6 +5414,54 @@ static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* HP dv7 bass switch - GPIO5 */
|
||||
#define stac_hp_bass_gpio_info snd_ctl_boolean_mono_info
|
||||
static int stac_hp_bass_gpio_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
ucontrol->value.integer.value[0] = !!(spec->gpio_data & 0x20);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
unsigned int gpio_data;
|
||||
|
||||
gpio_data = (spec->gpio_data & ~0x20) |
|
||||
(ucontrol->value.integer.value[0] ? 0x20 : 0);
|
||||
if (gpio_data == spec->gpio_data)
|
||||
return 0;
|
||||
spec->gpio_data = gpio_data;
|
||||
stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new stac_hp_bass_sw_ctrl = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.info = stac_hp_bass_gpio_info,
|
||||
.get = stac_hp_bass_gpio_get,
|
||||
.put = stac_hp_bass_gpio_put,
|
||||
};
|
||||
|
||||
static int stac_add_hp_bass_switch(struct hda_codec *codec)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
|
||||
if (!stac_control_new(spec, &stac_hp_bass_sw_ctrl,
|
||||
"Bass Speaker Playback Switch", 0))
|
||||
return -ENOMEM;
|
||||
|
||||
spec->gpio_mask |= 0x20;
|
||||
spec->gpio_dir |= 0x20;
|
||||
spec->gpio_data |= 0x20;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int patch_stac92hd71bxx(struct hda_codec *codec)
|
||||
{
|
||||
struct sigmatel_spec *spec;
|
||||
|
@ -5646,6 +5702,15 @@ again:
|
|||
return err;
|
||||
}
|
||||
|
||||
/* enable bass on HP dv7 */
|
||||
if (spec->board_config == STAC_HP_DV5) {
|
||||
unsigned int cap;
|
||||
cap = snd_hda_param_read(codec, 0x1, AC_PAR_GPIO_CAP);
|
||||
cap &= AC_GPIO_IO_COUNT;
|
||||
if (cap >= 6)
|
||||
stac_add_hp_bass_switch(codec);
|
||||
}
|
||||
|
||||
codec->proc_widget_hook = stac92hd7x_proc_hook;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -1907,8 +1907,7 @@ static int via_build_controls(struct hda_codec *codec)
|
|||
/* assign Capture Source enums to NID */
|
||||
kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
|
||||
for (i = 0; kctl && i < kctl->count; i++) {
|
||||
err = snd_hda_add_nids(codec, kctl, i, spec->mux_nids,
|
||||
spec->input_mux->num_items);
|
||||
err = snd_hda_add_nid(codec, kctl, i, spec->mux_nids[i]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче