All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Jordan <david2@system76.com>
To: Takashi Iwai <tiwai@suse.de>
Cc: alsa-devel@alsa-project.org, Clemens Ladisch <clemens@ladisch.de>
Subject: Re: Fixup set PCM/headphones volume from Master
Date: Thu, 10 Nov 2016 10:21:31 -0800	[thread overview]
Message-ID: <1478802091.454740.783828673.10EC9220@webmail.messagingengine.com> (raw)
In-Reply-To: <s5hinry9gnm.wl-tiwai@suse.de>

[-- Attachment #1: Type: text/plain, Size: 1210 bytes --]

I've attached the patch I've been working with.

-- 
  David Jordan
  david2@system76.com

On Tue, Nov 8, 2016, at 06:42 AM, Takashi Iwai wrote:
> On Mon, 07 Nov 2016 22:36:21 +0100,
> David Jordan wrote:
> > 
> > It's HDA, Realtek ALC898.  The headphones jack (analog 3.5mm output)
> > (0x1b) is connected to a separate ESS DAC, which takes sound input from
> > the PCM SPDIF output.  
> 
> Note that the "Master" volume is a vmaster control, and usually it
> covers all DAC volume controls.
> 
> It'd be better if you provide a patch you're fighting with, together
> with alsa-info.sh output.  Then other people can track the issue
> either with the real h/w or hda-emu.
> 
> 
> Takashi
> 
> 
> > 
> > -- 
> >   David Jordan
> >   david2@system76.com
> > 
> > On Mon, Nov 7, 2016, at 01:19 PM, Clemens Ladisch wrote:
> > > David Jordan wrote:
> > > > I'm working on a kernel-level fixup for a set of hardware
> > > 
> > > What hardware?  If HDA, which codec, and how is it connected?
> > > 
> > > 
> > > Regards,
> > > Clemens
> > _______________________________________________
> > Alsa-devel mailing list
> > Alsa-devel@alsa-project.org
> > http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
> > 

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: alsa-hda-alc898-pcm-hp-dac-vol-test.patch --]
[-- Type: text/x-patch; name="alsa-hda-alc898-pcm-hp-dac-vol-test.patch", Size: 11432 bytes --]

diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4b6d861..4419a7e 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -32,6 +32,7 @@
 #include <linux/input.h>
 #include <sound/core.h>
 #include <sound/jack.h>
+#include <sound/tlv.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
@@ -128,6 +129,14 @@ struct alc_spec {
 	unsigned int coef0;
 	struct input_dev *kb_dev;
 	u8 alc_mute_keycode_map[1];
+	
+	/* for clevo headphones fix */
+	unsigned int hp_volume;
+	unsigned int num_inits;
+	struct snd_kcontrol *master_kctl;
+	struct snd_kcontrol *pcm_kctl;
+	struct snd_kcontrol embedded_pcm_kctl;
+/*	struct snd_kcontrol *master_kctl;*/
 };
 
 /*
@@ -1797,6 +1806,7 @@ enum {
 	ALC882_FIXUP_NO_PRIMARY_HP,
 	ALC887_FIXUP_ASUS_BASS,
 	ALC887_FIXUP_BASS_CHMAP,
+	ALC898_FIXUP_CLEVO_SPDIF,
 };
 
 static void alc889_fixup_coef(struct hda_codec *codec,
@@ -1956,6 +1966,205 @@ static void alc882_fixup_no_primary_hp(struct hda_codec *codec,
 	}
 }
 
+
+
+
+
+/* Set PCM volume from Master.  HP volume is based on PCM volume exclusively.
+ * TODO: Trigger this function on Master Volume Change.
+ * TODO: Ensure appropriate scaling of PCM levels relative to Master.
+ */
+ 
+#define CLEVO_PCM_MAX_VOLUME 31
+
+static int snd_clevo_pcm_volume_info(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_info *uinfo)
+{
+    
+	printk("SYS76: snd_clevo_pcm_volume_info\n");
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = CLEVO_PCM_MAX_VOLUME;
+    return 0;
+}
+
+static int snd_clevo_pcm_volume_get(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+    
+	printk("SYS76: snd_clevo_pcm_volume_get\n");
+	struct hda_codec *chip = snd_kcontrol_chip(kcontrol);
+	unsigned int idx = kcontrol->id.subdevice;
+	
+	
+	struct alc_spec *spec = chip->spec;
+	
+	printk("SYS76: pcm_volume get...addrs\n");
+	printk("addr spec %lu \n", spec);
+	printk("addr codec %lu \n", chip);
+	printk("spec->hp_volume %u\n", spec->hp_volume);
+    
+    if (spec != 0) {
+        printk("meep!\n");
+	    ucontrol->value.integer.value[0] = CLEVO_PCM_MAX_VOLUME - spec->hp_volume;//chip->playback_volume[idx][0];
+	    ucontrol->value.integer.value[1] = CLEVO_PCM_MAX_VOLUME - spec->hp_volume;//chip->playback_volume[idx][1];
+	}
+	else {
+	    printk("leep!\n");
+	    ucontrol->value.integer.value[0] = CLEVO_PCM_MAX_VOLUME - 1;//chip->playback_volume[idx][0];
+	    ucontrol->value.integer.value[1] = CLEVO_PCM_MAX_VOLUME - 1;//chip->playback_volume[idx][1];
+	}
+    return 0;
+}
+
+//Okay, so this is creating the pcm_volume_ctl, but how is hard?
+static int snd_clevo_pcm_volume_put(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *chip = snd_kcontrol_chip(kcontrol);
+	unsigned int idx;
+	unsigned char val;
+	int i, change = 0;
+	
+	printk("SYS76: snd_clevo_pcm_volume_put\n");
+	
+	struct alc_spec *spec = chip->spec;
+	struct snd_card *card = chip->card;
+	
+	printk(kcontrol->id.name);
+	
+	
+	/*	*/
+/*	struct snd_ctl_elem_id pcm_id;*/
+/*	struct snd_kcontrol *pcm_control;*/
+/*	memset(&pcm_id, 0, sizeof(pcm_id));*/
+/*	pcm_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;*/
+/*	pcm_id.device = 0;*/
+/*	pcm_id.index = 0;*/
+/*	strcpy(pcm_id.name, "PCM Playback Volume");*/
+/*    Crashes Here:*/
+/*	pcm_control = snd_ctl_find_id(chip->card, &pcm_id);*/
+/*	*/
+	
+	printk("SYS76: PUT snd before find mixer ctl\n");
+	
+/*	Get the PCM Control to set it.  For some reason this fails.*/
+	struct snd_kcontrol * pcm_kctl = snd_hda_find_mixer_ctl(chip, "PCM Playback Volume");
+	struct snd_ctl_elem_value *pcm_uctl;
+	
+	printk("SYS76: PUT snd_hda_find_mixer_ctl\n");
+	
+	if (!pcm_kctl)
+	    printk("SYS76: PUT no kctl\n");
+		return;
+	pcm_uctl = kzalloc(sizeof(*pcm_uctl), GFP_KERNEL);
+	if (!pcm_uctl)
+		return;
+		
+/*	Set the PCM ucontrol from Master ucontrol*/
+	val = ucontrol->value.integer.value[0];
+	val &= HDA_AMP_VOLMASK;
+	
+	pcm_uctl->value.integer.value[0] = val;
+	pcm_uctl->value.integer.value[1] = val;
+	pcm_kctl->put(pcm_kctl, pcm_uctl);
+	
+	kfree(pcm_uctl);
+	
+	return change;
+}
+
+
+static void alc898_clevo_automute_hook(struct hda_codec *codec,
+				    struct hda_jack_callback *jack)
+{
+	int val;
+	snd_hda_codec_write(codec, codec->core.afg, 0,
+			    AC_VERB_SET_GPIO_MASK, 2);
+	snd_hda_codec_write(codec, codec->core.afg, 0,
+			    AC_VERB_SET_GPIO_DIRECTION, 0);
+    
+	struct alc_spec *spec = codec->spec;
+	
+	if (snd_hda_jack_detect(codec, 0x1b) && (snd_hda_codec_read(codec, codec->core.afg, 0,
+				       AC_VERB_GET_GPIO_DATA, 0) >= 0)) {
+		val = snd_hda_codec_get_pin_target(codec, 0x1b);
+		val |= AC_PINCTL_VREF_80;
+		snd_hda_set_pin_ctl(codec, 0x1b, val);
+		snd_hda_gen_hp_automute(codec, jack);
+	} else {
+	    printk("S76: automute case B\n");
+		val = snd_hda_codec_get_pin_target(codec, 0x1b);
+		val = val & 0xfff8;
+		snd_hda_set_pin_ctl(codec, 0x1b, val);
+		snd_hda_gen_hp_automute(codec, jack);
+		
+		/* Don't mute the digital output, needed for ESS DAC operation */
+		/* TODO: This might belong in alc898_fixup_clevo instead. */
+		/* struct snd_kcontrol *kctl;
+		kctl = snd_hda_find_mixer_ctl(codec, "IEC958 Playback Switch");
+		if (!kctl)
+			return;
+		kctl->put = NULL; */
+
+	}
+}				    
+static void alc898_fixup_clevo(struct hda_codec *codec,
+				       const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	
+	printk("SYS76: version 0020\n");
+	printk("SYS76: num_mixers = %u\n", spec->num_mixers);
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		spec->gen.detect_hp = 1;
+		spec->gen.automute_speaker = 1;
+		spec->gen.autocfg.hp_pins[0] = 0x1b; /* copy it for automute */	
+		snd_hda_jack_detect_enable_callback(codec, 0x1b,
+						    alc898_clevo_automute_hook);
+		spec->gen.hp_automute_hook = alc898_clevo_automute_hook;
+	}
+	
+	
+	struct snd_ctl_elem_id mid;
+	memset(&mid, 0, sizeof(mid));
+	strcpy(mid.name, "PCM Playback Volume");
+	mid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	struct snd_kcontrol * pcm_kcontrol;
+	pcm_kcontrol = snd_ctl_find_id(codec->card, &mid);
+	if (!pcm_kcontrol) {
+	    printk("SYS76: No PCM_kcontrol\n");
+	    printk("SYS76: oh well\n");
+	    return; //returning so we don't do the master stuff until pcm exists...maybe fix kernel panic this way
+	}
+	else {
+	    spec->pcm_kctl = pcm_kcontrol;
+	    spec->embedded_pcm_kctl = *pcm_kcontrol;
+	    printk("MY PCM NUMID IS: %x", pcm_kcontrol->id.numid);
+	}
+	
+	struct snd_ctl_elem_id sid;
+	memset(&sid, 0, sizeof(sid));
+	strcpy(sid.name, "Master Playback Volume");
+	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	struct snd_kcontrol * newsid;
+	//huh, find_id and find_numid are different...look into this
+	newsid = snd_ctl_find_id(codec->card, &sid);
+	if (!newsid) {
+	    printk("SYS76: No PCM Playback Volume ctl\n");
+	    //Now try *replacing* the headphone control instead of adding another
+	    //the snd_ctl_activate function is interesting maybe?
+	    //snd_ctl_replace(codec->card, snd_ctl_new1(&snd_clevo_pcm_volume_control, codec), 0);
+	}
+	else {
+	    printk("SYS76: PCM Playback Volume ctl id is %d\n", newsid->id.numid);
+	    newsid->put = snd_clevo_pcm_volume_put;
+	    printk("SYS76: My ID hahaha!\n");
+	}
+}
+
+
 static void alc_fixup_bass_chmap(struct hda_codec *codec,
 				 const struct hda_fixup *fix, int action);
 
@@ -2195,6 +2404,10 @@ static const struct hda_fixup alc882_fixups[] = {
 		.type = HDA_FIXUP_FUNC,
 		.v.func = alc_fixup_bass_chmap,
 	},
+	[ALC898_FIXUP_CLEVO_SPDIF] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc898_fixup_clevo,
+	},
 };
 
 static const struct snd_pci_quirk alc882_fixup_tbl[] = {
@@ -2264,6 +2477,41 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
 	SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
 	SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
 	SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
+	SND_PCI_QUIRK(0x1558, 0x0872, "Clevo P870DM2/P870DM3", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x0873, "Clevo P870DM2-G/P870DM3-G", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x0874, "Clevo P870DM2-G/P870DM3-G", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x0875, "Clevo P870KM/P870KM1", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x0876, "Clevo P870KM-G/P870KM1_G", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x65a1, "Clevo P65xHS_HP-D0", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x65a2, "Clevo P65xHS_HP-D", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x65a3, "Clevo P65xHS_HP-G0", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x65a4, "Clevo P65xHS_HP-G", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x67a1, "Clevo P67xHS_HP-D0", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x67a2, "Clevo P67xHS_HP-D", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x67a3, "Clevo P67xHS_HP-G0", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x67a4, "Clevo P67xHS_HP-G", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x6a01, "Clevo P65xRS_RP-D0", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x6a02, "Clevo P65xRS_RP-D", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x6a03, "Clevo P65xRS_RP-G0", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x6a04, "Clevo P65xRS_RP-G", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x6a05, "Clevo P65xRS_RP-V", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x6a06, "Clevo P65xRS_RP-Direct", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x6b01, "Clevo P67xRS_RP-D0", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x6b02, "Clevo P67xRS_RP-D", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x6b03, "Clevo P67xRS_RP-G0", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x6b04, "Clevo P67xRS_RP-G", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x6b05, "Clevo P67xRS_RP-V", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x6b06, "Clevo P67xRS_RP-Direct", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x7504, "Clevo P750DM2", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x7505, "Clevo P750DM2G", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x7506, "Clevo P750KM", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x7507, "Clevo P750KMG", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x7705, "Clevo P775DM2", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x7706, "Clevo P775DM2G", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x7707, "Clevo P775KM", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x7708, "Clevo P775KMG", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x7705, "System76 serw10", ALC898_FIXUP_CLEVO_SPDIF),
+	SND_PCI_QUIRK(0x1558, 0x6b01, "System76 oryp2-ess", ALC898_FIXUP_CLEVO_SPDIF),
 	SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
 	SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
 	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530),
@@ -2277,6 +2525,7 @@ static const struct hda_model_fixup alc882_fixup_models[] = {
 	{.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"},
 	{.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"},
 	{.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"},
+	{.id = ALC898_FIXUP_CLEVO_SPDIF, .name = "system76"},
 	{}
 };

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



  parent reply	other threads:[~2016-11-10 18:21 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-11-07 16:59 Fixup set PCM/headphones volume from Master David Jordan
2016-11-07 21:19 ` Clemens Ladisch
2016-11-07 21:36   ` David Jordan
2016-11-08 14:42     ` Takashi Iwai
2016-11-08 19:17       ` David Jordan
2016-11-10 18:21       ` David Jordan [this message]
2016-11-10 19:16         ` David Jordan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1478802091.454740.783828673.10EC9220@webmail.messagingengine.com \
    --to=david2@system76.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=clemens@ladisch.de \
    --cc=tiwai@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.