summaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/Kconfig1
-rw-r--r--sound/pci/hda/hda_codec.c2
-rw-r--r--sound/pci/hda/hda_controller.c2
-rw-r--r--sound/pci/hda/patch_ca0132.c3
-rw-r--r--sound/pci/hda/patch_hdmi.c313
-rw-r--r--sound/pci/hda/patch_realtek.c231
6 files changed, 223 insertions, 329 deletions
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index bd48335d09d7..e1d3082a4fe9 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -184,6 +184,7 @@ comment "Set to Y if you want auto-loading the codec driver"
config SND_HDA_CODEC_CA0132_DSP
bool "Support new DSP code for CA0132 codec"
depends on SND_HDA_CODEC_CA0132
+ default y
select SND_HDA_DSP_LOADER
select FW_LOADER
help
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 53e7732ef752..a34a2c9f4bcf 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -88,7 +88,7 @@ struct hda_conn_list {
struct list_head list;
int len;
hda_nid_t nid;
- hda_nid_t conns[0];
+ hda_nid_t conns[];
};
/* look up the cached results */
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index 2609e391ce54..9765652a73d7 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -373,7 +373,7 @@ static int azx_get_sync_time(ktime_t *device,
u32 wallclk_ctr, wallclk_cycles;
bool direction;
u32 dma_select;
- u32 timeout = 200;
+ u32 timeout;
u32 retry_count = 0;
runtime = substream->runtime;
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index ded8bc07d755..34fe753a46fb 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -1180,6 +1180,7 @@ static const struct snd_pci_quirk ca0132_quirks[] = {
SND_PCI_QUIRK(0x1458, 0xA016, "Recon3Di", QUIRK_R3DI),
SND_PCI_QUIRK(0x1458, 0xA026, "Gigabyte G1.Sniper Z97", QUIRK_R3DI),
SND_PCI_QUIRK(0x1458, 0xA036, "Gigabyte GA-Z170X-Gaming 7", QUIRK_R3DI),
+ SND_PCI_QUIRK(0x3842, 0x1038, "EVGA X99 Classified", QUIRK_R3DI),
SND_PCI_QUIRK(0x1102, 0x0013, "Recon3D", QUIRK_R3D),
SND_PCI_QUIRK(0x1102, 0x0051, "Sound Blaster AE-5", QUIRK_AE5),
{}
@@ -2698,7 +2699,7 @@ struct dsp_image_seg {
u32 magic;
u32 chip_addr;
u32 count;
- u32 data[0];
+ u32 data[];
};
static const u32 g_magic_value = 0x4c46584d;
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 5119a9ae3d8a..bb287a916dae 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -154,7 +154,6 @@ struct hdmi_spec {
struct hda_multi_out multiout;
struct hda_pcm_stream pcm_playback;
- bool use_jack_detect; /* jack detection enabled */
bool use_acomp_notifier; /* use eld_notify callback for hotplug */
bool acomp_registered; /* audio component registered in this driver */
struct drm_audio_component_audio_ops drm_audio_ops;
@@ -753,7 +752,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
* Unsolicited events
*/
-static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
+static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid,
int dev_id)
@@ -764,8 +763,7 @@ static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid,
if (pin_idx < 0)
return;
mutex_lock(&spec->pcm_lock);
- if (hdmi_present_sense(get_pin(spec, pin_idx), 1))
- snd_hda_jack_report_sync(codec);
+ hdmi_present_sense(get_pin(spec, pin_idx), 1);
mutex_unlock(&spec->pcm_lock);
}
@@ -779,21 +777,9 @@ static void jack_callback(struct hda_codec *codec,
check_presence_and_report(codec, jack->nid, jack->dev_id);
}
-static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
+static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res,
+ struct hda_jack_tbl *jack)
{
- int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
- struct hda_jack_tbl *jack;
-
- if (codec->dp_mst) {
- int dev_entry =
- (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT;
-
- jack = snd_hda_jack_tbl_get_from_tag(codec, tag, dev_entry);
- } else {
- jack = snd_hda_jack_tbl_get_from_tag(codec, tag, 0);
- }
- if (!jack)
- return;
jack->jack_dirty = 1;
codec_dbg(codec,
@@ -853,7 +839,7 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
}
if (subtag == 0)
- hdmi_intrinsic_event(codec, res);
+ hdmi_intrinsic_event(codec, res, jack);
else
hdmi_non_intrinsic_event(codec, res);
}
@@ -1480,21 +1466,60 @@ static void hdmi_pcm_reset_pin(struct hdmi_spec *spec,
per_pin->channels = 0;
}
+static struct snd_jack *pin_idx_to_pcm_jack(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin)
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ if (per_pin->pcm_idx >= 0)
+ return spec->pcm_rec[per_pin->pcm_idx].jack;
+ else
+ return NULL;
+}
+
/* update per_pin ELD from the given new ELD;
* setup info frame and notification accordingly
+ * also notify ELD kctl and report jack status changes
*/
-static bool update_eld(struct hda_codec *codec,
+static void update_eld(struct hda_codec *codec,
struct hdmi_spec_per_pin *per_pin,
- struct hdmi_eld *eld)
+ struct hdmi_eld *eld,
+ int repoll)
{
struct hdmi_eld *pin_eld = &per_pin->sink_eld;
struct hdmi_spec *spec = codec->spec;
+ struct snd_jack *pcm_jack;
bool old_eld_valid = pin_eld->eld_valid;
bool eld_changed;
int pcm_idx;
+ if (eld->eld_valid) {
+ if (eld->eld_size <= 0 ||
+ snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer,
+ eld->eld_size) < 0) {
+ eld->eld_valid = false;
+ if (repoll) {
+ schedule_delayed_work(&per_pin->work,
+ msecs_to_jiffies(300));
+ return;
+ }
+ }
+ }
+
+ if (!eld->eld_valid || eld->eld_size <= 0) {
+ eld->eld_valid = false;
+ eld->eld_size = 0;
+ }
+
/* for monitor disconnection, save pcm_idx firstly */
pcm_idx = per_pin->pcm_idx;
+
+ /*
+ * pcm_idx >=0 before update_eld() means it is in monitor
+ * disconnected event. Jack must be fetched before update_eld().
+ */
+ pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
+
if (spec->dyn_pcm_assign) {
if (eld->eld_valid) {
hdmi_attach_hda_pcm(spec, per_pin);
@@ -1509,6 +1534,8 @@ static bool update_eld(struct hda_codec *codec,
*/
if (pcm_idx == -1)
pcm_idx = per_pin->pcm_idx;
+ if (!pcm_jack)
+ pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
if (eld->eld_valid)
snd_hdmi_show_eld(codec, &eld->info);
@@ -1547,42 +1574,17 @@ static bool update_eld(struct hda_codec *codec,
SNDRV_CTL_EVENT_MASK_VALUE |
SNDRV_CTL_EVENT_MASK_INFO,
&get_hdmi_pcm(spec, pcm_idx)->eld_ctl->id);
- return eld_changed;
-}
-static struct snd_jack *pin_idx_to_pcm_jack(struct hda_codec *codec,
- struct hdmi_spec_per_pin *per_pin)
-{
- struct hdmi_spec *spec = codec->spec;
- struct snd_jack *jack = NULL;
- struct hda_jack_tbl *jack_tbl;
-
- /* if !dyn_pcm_assign, get jack from hda_jack_tbl
- * in !dyn_pcm_assign case, spec->pcm_rec[].jack is not
- * NULL even after snd_hda_jack_tbl_clear() is called to
- * free snd_jack. This may cause access invalid memory
- * when calling snd_jack_report
- */
- if (per_pin->pcm_idx >= 0 && spec->dyn_pcm_assign) {
- jack = spec->pcm_rec[per_pin->pcm_idx].jack;
- } else if (!spec->dyn_pcm_assign) {
- /*
- * jack tbl doesn't support DP MST
- * DP MST will use dyn_pcm_assign,
- * so DP MST will never come here
- */
- jack_tbl = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid,
- per_pin->dev_id);
- if (jack_tbl)
- jack = jack_tbl->jack;
- }
- return jack;
+ if (eld_changed && pcm_jack)
+ snd_jack_report(pcm_jack,
+ (eld->monitor_present && eld->eld_valid) ?
+ SND_JACK_AVOUT : 0);
}
+
/* update ELD and jack state via HD-audio verbs */
-static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
+static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
int repoll)
{
- struct hda_jack_tbl *jack;
struct hda_codec *codec = per_pin->codec;
struct hdmi_spec *spec = codec->spec;
struct hdmi_eld *eld = &spec->temp_eld;
@@ -1597,9 +1599,11 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
* the unsolicited response to avoid custom WARs.
*/
int present;
- bool ret;
- bool do_repoll = false;
- struct snd_jack *pcm_jack = NULL;
+ int ret;
+
+ ret = snd_hda_power_up_pm(codec);
+ if (ret < 0 && pm_runtime_suspended(hda_codec_dev(codec)))
+ goto out;
present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id);
@@ -1618,62 +1622,12 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
if (spec->ops.pin_get_eld(codec, pin_nid, dev_id,
eld->eld_buffer, &eld->eld_size) < 0)
eld->eld_valid = false;
- else {
- if (snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer,
- eld->eld_size) < 0)
- eld->eld_valid = false;
- }
- if (!eld->eld_valid && repoll)
- do_repoll = true;
}
- if (do_repoll) {
- schedule_delayed_work(&per_pin->work, msecs_to_jiffies(300));
- } else {
- /*
- * pcm_idx >=0 before update_eld() means it is in monitor
- * disconnected event. Jack must be fetched before
- * update_eld().
- */
- pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
- update_eld(codec, per_pin, eld);
- if (!pcm_jack)
- pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
- }
-
- ret = !repoll || !eld->monitor_present || eld->eld_valid;
-
- jack = snd_hda_jack_tbl_get_mst(codec, pin_nid, per_pin->dev_id);
- if (jack) {
- jack->block_report = !ret;
- jack->pin_sense = (eld->monitor_present && eld->eld_valid) ?
- AC_PINSENSE_PRESENCE : 0;
-
- if (spec->dyn_pcm_assign && pcm_jack && !do_repoll) {
- int state = 0;
-
- if (jack->pin_sense & AC_PINSENSE_PRESENCE)
- state = SND_JACK_AVOUT;
- snd_jack_report(pcm_jack, state);
- }
-
- /*
- * snd_hda_jack_pin_sense() call at the beginning of this
- * function, updates jack->pins_sense and clears
- * jack->jack_dirty, therefore snd_hda_jack_report_sync() will
- * not override the jack->pin_sense.
- *
- * snd_hda_jack_report_sync() is superfluous for dyn_pcm_assign
- * case. The jack->pin_sense update was already performed, and
- * hda_jack->jack is NULL for dyn_pcm_assign.
- *
- * Don't call snd_hda_jack_report_sync() for
- * dyn_pcm_assign.
- */
- ret = ret && !spec->dyn_pcm_assign;
- }
+ update_eld(codec, per_pin, eld, repoll);
mutex_unlock(&per_pin->lock);
- return ret;
+ out:
+ snd_hda_power_down_pm(codec);
}
/* update ELD and jack state via audio component */
@@ -1682,64 +1636,25 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
{
struct hdmi_spec *spec = codec->spec;
struct hdmi_eld *eld = &spec->temp_eld;
- struct snd_jack *jack = NULL;
- bool changed;
- int size;
mutex_lock(&per_pin->lock);
eld->monitor_present = false;
- size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,
+ eld->eld_size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,
per_pin->dev_id, &eld->monitor_present,
eld->eld_buffer, ELD_MAX_SIZE);
- if (size > 0) {
- size = min(size, ELD_MAX_SIZE);
- if (snd_hdmi_parse_eld(codec, &eld->info,
- eld->eld_buffer, size) < 0)
- size = -EINVAL;
- }
-
- if (size > 0) {
- eld->eld_valid = true;
- eld->eld_size = size;
- } else {
- eld->eld_valid = false;
- eld->eld_size = 0;
- }
-
- /* pcm_idx >=0 before update_eld() means it is in monitor
- * disconnected event. Jack must be fetched before update_eld()
- */
- jack = pin_idx_to_pcm_jack(codec, per_pin);
- changed = update_eld(codec, per_pin, eld);
- if (jack == NULL)
- jack = pin_idx_to_pcm_jack(codec, per_pin);
- if (changed && jack)
- snd_jack_report(jack,
- (eld->monitor_present && eld->eld_valid) ?
- SND_JACK_AVOUT : 0);
+ eld->eld_valid = (eld->eld_size > 0);
+ update_eld(codec, per_pin, eld, 0);
mutex_unlock(&per_pin->lock);
}
-static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
+static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
{
struct hda_codec *codec = per_pin->codec;
- int ret;
- /* no temporary power up/down needed for component notifier */
- if (!codec_has_acomp(codec)) {
- ret = snd_hda_power_up_pm(codec);
- if (ret < 0 && pm_runtime_suspended(hda_codec_dev(codec))) {
- snd_hda_power_down_pm(codec);
- return false;
- }
- ret = hdmi_present_sense_via_verbs(per_pin, repoll);
- snd_hda_power_down_pm(codec);
- } else {
+ if (!codec_has_acomp(codec))
+ hdmi_present_sense_via_verbs(per_pin, repoll);
+ else
sync_eld_via_acomp(codec, per_pin);
- ret = false; /* don't call snd_hda_jack_report_sync() */
- }
-
- return ret;
}
static void hdmi_repoll_eld(struct work_struct *work)
@@ -1759,8 +1674,7 @@ static void hdmi_repoll_eld(struct work_struct *work)
per_pin->repoll_count = 0;
mutex_lock(&spec->pcm_lock);
- if (hdmi_present_sense(per_pin, per_pin->repoll_count))
- snd_hda_jack_report_sync(per_pin->codec);
+ hdmi_present_sense(per_pin, per_pin->repoll_count);
mutex_unlock(&spec->pcm_lock);
}
@@ -2206,15 +2120,23 @@ static void free_hdmi_jack_priv(struct snd_jack *jack)
pcm->jack = NULL;
}
-static int add_hdmi_jack_kctl(struct hda_codec *codec,
- struct hdmi_spec *spec,
- int pcm_idx,
- const char *name)
+static int generic_hdmi_build_jack(struct hda_codec *codec, int pcm_idx)
{
+ char hdmi_str[32] = "HDMI/DP";
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_pin *per_pin = get_pin(spec, pcm_idx);
struct snd_jack *jack;
+ int pcmdev = get_pcm_rec(spec, pcm_idx)->device;
int err;
- err = snd_jack_new(codec->card, name, SND_JACK_AVOUT, &jack,
+ if (pcmdev > 0)
+ sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev);
+ if (!spec->dyn_pcm_assign &&
+ !is_jack_detectable(codec, per_pin->pin_nid))
+ strncat(hdmi_str, " Phantom",
+ sizeof(hdmi_str) - strlen(hdmi_str) - 1);
+
+ err = snd_jack_new(codec->card, hdmi_str, SND_JACK_AVOUT, &jack,
true, false);
if (err < 0)
return err;
@@ -2225,48 +2147,6 @@ static int add_hdmi_jack_kctl(struct hda_codec *codec,
return 0;
}
-static int generic_hdmi_build_jack(struct hda_codec *codec, int pcm_idx)
-{
- char hdmi_str[32] = "HDMI/DP";
- struct hdmi_spec *spec = codec->spec;
- struct hdmi_spec_per_pin *per_pin;
- struct hda_jack_tbl *jack;
- int pcmdev = get_pcm_rec(spec, pcm_idx)->device;
- bool phantom_jack;
- int ret;
-
- if (pcmdev > 0)
- sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev);
-
- if (spec->dyn_pcm_assign)
- return add_hdmi_jack_kctl(codec, spec, pcm_idx, hdmi_str);
-
- /* for !dyn_pcm_assign, we still use hda_jack for compatibility */
- /* if !dyn_pcm_assign, it must be non-MST mode.
- * This means pcms and pins are statically mapped.
- * And pcm_idx is pin_idx.
- */
- per_pin = get_pin(spec, pcm_idx);
- phantom_jack = !is_jack_detectable(codec, per_pin->pin_nid);
- if (phantom_jack)
- strncat(hdmi_str, " Phantom",
- sizeof(hdmi_str) - strlen(hdmi_str) - 1);
- ret = snd_hda_jack_add_kctl_mst(codec, per_pin->pin_nid,
- per_pin->dev_id, hdmi_str, phantom_jack,
- 0, NULL);
- if (ret < 0)
- return ret;
- jack = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid,
- per_pin->dev_id);
- if (jack == NULL)
- return 0;
- /* assign jack->jack to pcm_rec[].jack to
- * align with dyn_pcm_assign mode
- */
- spec->pcm_rec[pcm_idx].jack = jack->jack;
- return 0;
-}
-
static int generic_hdmi_build_controls(struct hda_codec *codec)
{
struct hdmi_spec *spec = codec->spec;
@@ -2355,7 +2235,6 @@ static int generic_hdmi_init(struct hda_codec *codec)
int pin_idx;
mutex_lock(&spec->bind_lock);
- spec->use_jack_detect = !codec->jackpoll_interval;
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
hda_nid_t pin_nid = per_pin->pin_nid;
@@ -2365,12 +2244,8 @@ static int generic_hdmi_init(struct hda_codec *codec)
hdmi_init_pin(codec, pin_nid);
if (codec_has_acomp(codec))
continue;
- if (spec->use_jack_detect)
- snd_hda_jack_detect_enable(codec, pin_nid, dev_id);
- else
- snd_hda_jack_detect_enable_callback_mst(codec, pin_nid,
- dev_id,
- jack_callback);
+ snd_hda_jack_detect_enable_callback_mst(codec, pin_nid, dev_id,
+ jack_callback);
}
mutex_unlock(&spec->bind_lock);
return 0;
@@ -2532,12 +2407,6 @@ static void reprogram_jack_detect(struct hda_codec *codec, hda_nid_t nid,
unsigned int val = use_acomp ? 0 : (AC_USRSP_EN | tbl->tag);
snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_UNSOLICITED_ENABLE, val);
- } else {
- /* if no jack entry was defined beforehand, create a new one
- * at need (i.e. only when notifier is cleared)
- */
- if (!use_acomp)
- snd_hda_jack_detect_enable(codec, nid, dev_id);
}
}
@@ -2553,13 +2422,11 @@ static void generic_acomp_notifier_set(struct drm_audio_component *acomp,
spec->use_acomp_notifier = use_acomp;
spec->codec->relaxed_resume = use_acomp;
/* reprogram each jack detection logic depending on the notifier */
- if (spec->use_jack_detect) {
- for (i = 0; i < spec->num_pins; i++)
- reprogram_jack_detect(spec->codec,
- get_pin(spec, i)->pin_nid,
- get_pin(spec, i)->dev_id,
- use_acomp);
- }
+ for (i = 0; i < spec->num_pins; i++)
+ reprogram_jack_detect(spec->codec,
+ get_pin(spec, i)->pin_nid,
+ get_pin(spec, i)->dev_id,
+ use_acomp);
mutex_unlock(&spec->bind_lock);
}
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 63e1a56f705b..f66a48154a57 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -107,6 +107,7 @@ struct alc_spec {
unsigned int done_hp_init:1;
unsigned int no_shutup_pins:1;
unsigned int ultra_low_power:1;
+ unsigned int has_hs_key:1;
/* for PLL fix */
hda_nid_t pll_nid;
@@ -367,7 +368,9 @@ static void alc_fill_eapd_coef(struct hda_codec *codec)
case 0x10ec0215:
case 0x10ec0233:
case 0x10ec0235:
+ case 0x10ec0236:
case 0x10ec0255:
+ case 0x10ec0256:
case 0x10ec0257:
case 0x10ec0282:
case 0x10ec0283:
@@ -379,11 +382,6 @@ static void alc_fill_eapd_coef(struct hda_codec *codec)
case 0x10ec0300:
alc_update_coef_idx(codec, 0x10, 1<<9, 0);
break;
- case 0x10ec0236:
- case 0x10ec0256:
- alc_write_coef_idx(codec, 0x36, 0x5757);
- alc_update_coef_idx(codec, 0x10, 1<<9, 0);
- break;
case 0x10ec0275:
alc_update_coef_idx(codec, 0xe, 0, 1<<0);
break;
@@ -2982,6 +2980,107 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
return alc_parse_auto_config(codec, alc269_ignore, ssids);
}
+static const struct hda_jack_keymap alc_headset_btn_keymap[] = {
+ { SND_JACK_BTN_0, KEY_PLAYPAUSE },
+ { SND_JACK_BTN_1, KEY_VOICECOMMAND },
+ { SND_JACK_BTN_2, KEY_VOLUMEUP },
+ { SND_JACK_BTN_3, KEY_VOLUMEDOWN },
+ {}
+};
+
+static void alc_headset_btn_callback(struct hda_codec *codec,
+ struct hda_jack_callback *jack)
+{
+ int report = 0;
+
+ if (jack->unsol_res & (7 << 13))
+ report |= SND_JACK_BTN_0;
+
+ if (jack->unsol_res & (1 << 16 | 3 << 8))
+ report |= SND_JACK_BTN_1;
+
+ /* Volume up key */
+ if (jack->unsol_res & (7 << 23))
+ report |= SND_JACK_BTN_2;
+
+ /* Volume down key */
+ if (jack->unsol_res & (7 << 10))
+ report |= SND_JACK_BTN_3;
+
+ jack->jack->button_state = report;
+}
+
+static void alc_disable_headset_jack_key(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (!spec->has_hs_key)
+ return;
+
+ switch (codec->core.vendor_id) {
+ case 0x10ec0215:
+ case 0x10ec0225:
+ case 0x10ec0285:
+ case 0x10ec0295:
+ case 0x10ec0289:
+ case 0x10ec0299:
+ alc_write_coef_idx(codec, 0x48, 0x0);
+ alc_update_coef_idx(codec, 0x49, 0x0045, 0x0);
+ alc_update_coef_idx(codec, 0x44, 0x0045 << 8, 0x0);
+ break;
+ case 0x10ec0236:
+ case 0x10ec0256:
+ alc_write_coef_idx(codec, 0x48, 0x0);
+ alc_update_coef_idx(codec, 0x49, 0x0045, 0x0);
+ break;
+ }
+}
+
+static void alc_enable_headset_jack_key(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (!spec->has_hs_key)
+ return;
+
+ switch (codec->core.vendor_id) {
+ case 0x10ec0215:
+ case 0x10ec0225:
+ case 0x10ec0285:
+ case 0x10ec0295:
+ case 0x10ec0289:
+ case 0x10ec0299:
+ alc_write_coef_idx(codec, 0x48, 0xd011);
+ alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
+ alc_update_coef_idx(codec, 0x44, 0x007f << 8, 0x0045 << 8);
+ break;
+ case 0x10ec0236:
+ case 0x10ec0256:
+ alc_write_coef_idx(codec, 0x48, 0xd011);
+ alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
+ break;
+ }
+}
+
+static void alc_fixup_headset_jack(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ spec->has_hs_key = 1;
+ snd_hda_jack_detect_enable_callback(codec, 0x55,
+ alc_headset_btn_callback);
+ snd_hda_jack_add_kctl(codec, 0x55, "Headset Jack", false,
+ SND_JACK_HEADSET, alc_headset_btn_keymap);
+ break;
+ case HDA_FIXUP_ACT_INIT:
+ alc_enable_headset_jack_key(codec);
+ break;
+ }
+}
+
static void alc269vb_toggle_power_output(struct hda_codec *codec, int power_up)
{
alc_update_coef_idx(codec, 0x04, 1 << 11, power_up ? (1 << 11) : 0);
@@ -3269,7 +3368,13 @@ static void alc256_init(struct hda_codec *codec)
alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */
alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 1 << 15); /* Clear bit */
alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 0 << 15);
- alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/
+ /*
+ * Expose headphone mic (or possibly Line In on some machines) instead
+ * of PC Beep on 1Ah, and disable 1Ah loopback for all outputs. See
+ * Documentation/sound/hd-audio/realtek-pc-beep.rst for details of
+ * this register.
+ */
+ alc_write_coef_idx(codec, 0x36, 0x5757);
}
static void alc256_shutup(struct hda_codec *codec)
@@ -3372,6 +3477,8 @@ static void alc225_shutup(struct hda_codec *codec)
if (!hp_pin)
hp_pin = 0x21;
+
+ alc_disable_headset_jack_key(codec);
/* 3k pull low control for Headset jack. */
alc_update_coef_idx(codec, 0x4a, 0, 3 << 10);
@@ -3411,6 +3518,9 @@ static void alc225_shutup(struct hda_codec *codec)
alc_update_coef_idx(codec, 0x4a, 3<<4, 2<<4);
msleep(30);
}
+
+ alc_update_coef_idx(codec, 0x4a, 3 << 10, 0);
+ alc_enable_headset_jack_key(codec);
}
static void alc_default_init(struct hda_codec *codec)
@@ -4008,6 +4118,12 @@ static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
alc_fixup_hp_gpio_led(codec, action, 0x08, 0x10);
}
+static void alc285_fixup_hp_gpio_led(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ alc_fixup_hp_gpio_led(codec, action, 0x04, 0x00);
+}
+
static void alc286_fixup_hp_gpio_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -5375,17 +5491,6 @@ static void alc271_hp_gate_mic_jack(struct hda_codec *codec,
}
}
-static void alc256_fixup_dell_xps_13_headphone_noise2(struct hda_codec *codec,
- const struct hda_fixup *fix,
- int action)
-{
- if (action != HDA_FIXUP_ACT_PRE_PROBE)
- return;
-
- snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 0, HDA_AMP_VOLMASK, 1);
- snd_hda_override_wcaps(codec, 0x1a, get_wcaps(codec, 0x1a) & ~AC_WCAP_IN_AMP);
-}
-
static void alc269_fixup_limit_int_mic_boost(struct hda_codec *codec,
const struct hda_fixup *fix,
int action)
@@ -5662,69 +5767,6 @@ static void alc285_fixup_invalidate_dacs(struct hda_codec *codec,
snd_hda_override_wcaps(codec, 0x03, 0);
}
-static const struct hda_jack_keymap alc_headset_btn_keymap[] = {
- { SND_JACK_BTN_0, KEY_PLAYPAUSE },
- { SND_JACK_BTN_1, KEY_VOICECOMMAND },
- { SND_JACK_BTN_2, KEY_VOLUMEUP },
- { SND_JACK_BTN_3, KEY_VOLUMEDOWN },
- {}
-};
-
-static void alc_headset_btn_callback(struct hda_codec *codec,
- struct hda_jack_callback *jack)
-{
- int report = 0;
-
- if (jack->unsol_res & (7 << 13))
- report |= SND_JACK_BTN_0;
-
- if (jack->unsol_res & (1 << 16 | 3 << 8))
- report |= SND_JACK_BTN_1;
-
- /* Volume up key */
- if (jack->unsol_res & (7 << 23))
- report |= SND_JACK_BTN_2;
-
- /* Volume down key */
- if (jack->unsol_res & (7 << 10))
- report |= SND_JACK_BTN_3;
-
- jack->jack->button_state = report;
-}
-
-static void alc_fixup_headset_jack(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
-
- switch (action) {
- case HDA_FIXUP_ACT_PRE_PROBE:
- snd_hda_jack_detect_enable_callback(codec, 0x55,
- alc_headset_btn_callback);
- snd_hda_jack_add_kctl(codec, 0x55, "Headset Jack", false,
- SND_JACK_HEADSET, alc_headset_btn_keymap);
- break;
- case HDA_FIXUP_ACT_INIT:
- switch (codec->core.vendor_id) {
- case 0x10ec0215:
- case 0x10ec0225:
- case 0x10ec0285:
- case 0x10ec0295:
- case 0x10ec0289:
- case 0x10ec0299:
- alc_write_coef_idx(codec, 0x48, 0xd011);
- alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
- alc_update_coef_idx(codec, 0x44, 0x007f << 8, 0x0045 << 8);
- break;
- case 0x10ec0236:
- case 0x10ec0256:
- alc_write_coef_idx(codec, 0x48, 0xd011);
- alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
- break;
- }
- break;
- }
-}
-
static void alc295_fixup_chromebook(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -5863,8 +5905,6 @@ enum {
ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE,
ALC275_FIXUP_DELL_XPS,
- ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE,
- ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE2,
ALC293_FIXUP_LENOVO_SPK_NOISE,
ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY,
ALC255_FIXUP_DELL_SPK_NOISE,
@@ -5923,6 +5963,7 @@ enum {
ALC294_FIXUP_ASUS_DUAL_SPK,
ALC285_FIXUP_THINKPAD_HEADSET_JACK,
ALC294_FIXUP_ASUS_HPE,
+ ALC285_FIXUP_HP_GPIO_LED,
};
static const struct hda_fixup alc269_fixups[] = {
@@ -6604,23 +6645,6 @@ static const struct hda_fixup alc269_fixups[] = {
{}
}
},
- [ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- /* Disable pass-through path for FRONT 14h */
- {0x20, AC_VERB_SET_COEF_INDEX, 0x36},
- {0x20, AC_VERB_SET_PROC_COEF, 0x1737},
- {}
- },
- .chained = true,
- .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
- },
- [ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE2] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc256_fixup_dell_xps_13_headphone_noise2,
- .chained = true,
- .chain_id = ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE
- },
[ALC293_FIXUP_LENOVO_SPK_NOISE] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_disable_aamix,
@@ -7061,6 +7085,10 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC
},
+ [ALC285_FIXUP_HP_GPIO_LED] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_hp_gpio_led,
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -7114,17 +7142,14 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x06de, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
- SND_PCI_QUIRK(0x1028, 0x0704, "Dell XPS 13 9350", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE2),
SND_PCI_QUIRK(0x1028, 0x0706, "Dell Inspiron 7559", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER),
SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE),
SND_PCI_QUIRK(0x1028, 0x0738, "Dell Precision 5820", ALC269_FIXUP_NO_SHUTUP),
- SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE2),
SND_PCI_QUIRK(0x1028, 0x075c, "Dell XPS 27 7760", ALC298_FIXUP_SPK_VOLUME),
SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME),
SND_PCI_QUIRK(0x1028, 0x07b0, "Dell Precision 7520", ALC295_FIXUP_DISABLE_DAC3),
SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER),
SND_PCI_QUIRK(0x1028, 0x080c, "Dell WYSE", ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE),
- SND_PCI_QUIRK(0x1028, 0x082a, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE2),
SND_PCI_QUIRK(0x1028, 0x084b, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB),
SND_PCI_QUIRK(0x1028, 0x084e, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB),
SND_PCI_QUIRK(0x1028, 0x0871, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC),
@@ -7208,6 +7233,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x83b9, "HP Spectre x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
SND_PCI_QUIRK(0x103c, 0x8497, "HP Envy x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3),
+ SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -7477,7 +7503,6 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC298_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc298-dell1"},
{.id = ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE, .name = "alc298-dell-aio"},
{.id = ALC275_FIXUP_DELL_XPS, .name = "alc275-dell-xps"},
- {.id = ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE, .name = "alc256-dell-xps13"},
{.id = ALC293_FIXUP_LENOVO_SPK_NOISE, .name = "lenovo-spk-noise"},
{.id = ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY, .name = "lenovo-hotkey"},
{.id = ALC255_FIXUP_DELL_SPK_NOISE, .name = "dell-spk-noise"},