Blob Blame History Raw
From 2e57a3358dda20128593fff9b39b522f1bdd26c6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Sch=C3=A4r?= <jan@jschaer.ch>
Date: Mon, 27 Jun 2022 19:18:55 +0200
Subject: [PATCH] ALSA: usb-audio: Turn off 'manual mode' on Dell dock
Mime-version: 1.0
Content-type: text/plain; charset=UTF-8
Content-transfer-encoding: 8bit
Git-commit: 2e57a3358dda20128593fff9b39b522f1bdd26c6
Patch-mainline: v6.0-rc1
References: git-fixes

This removes the need to power cycle the Dell WD15 dock if it has been
attached to a Windows machine.

The Windows driver puts the ALC4020 USB audio controller into
'manual mode', and then does all the power management and other
configuration itself, by sending HD audio commands directly to the
ALC3263 audio codec via vendor-type USB messages. If manual mode is off,
this is all handled by the firmware, and works well enough.

If manual mode is turned on, the latency of the SET INTERFACE command
goes from several hundred ms to less than 1 ms
(see https://bugzilla.suse.com/show_bug.cgi?id=1089467), but I'm not
sure if the additional code that would be required is worth it.

Funnily enough, the Windows driver tries to turn off manual mode when
the dock is disconnected, which doesn't work for obvious reasons.

Additionally, fix a bug in dell_dock_init_vol, which didn't work because
the Control Selector was missing.
Now, it properly resets the volume to 0dB.

Fixes: 964af639ad69 ("ALSA: usb-audio: Initialize Dell Dock playback volumes")
Signed-off-by: Jan Schär <jan@jschaer.ch>
Link: https://lore.kernel.org/r/20220627171855.42338-2-jan@jschaer.ch
Signed-off-by: Takashi Iwai <tiwai@suse.de>

---
 sound/usb/mixer_quirks.c | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 66b6476994eb..5a45822e60e7 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -1949,9 +1949,11 @@ static int snd_soundblaster_e1_switch_create(struct usb_mixer_interface *mixer)
 #define REALTEK_HDA_VALUE 0x0038
 
 #define REALTEK_HDA_SET		62
+#define REALTEK_MANUAL_MODE	72
 #define REALTEK_HDA_GET_OUT	88
 #define REALTEK_HDA_GET_IN	89
 
+#define REALTEK_AUDIO_FUNCTION_GROUP	0x01
 #define REALTEK_LINE1			0x1a
 #define REALTEK_VENDOR_REGISTERS	0x20
 #define REALTEK_HP_OUT			0x21
@@ -2084,6 +2086,21 @@ static int realtek_add_jack(struct usb_mixer_interface *mixer,
 static int dell_dock_mixer_create(struct usb_mixer_interface *mixer)
 {
 	int err;
+	struct usb_device *dev = mixer->chip->dev;
+
+	/* Power down the audio codec to avoid loud pops in the next step. */
+	realtek_hda_set(mixer->chip,
+			HDA_VERB_CMD(AC_VERB_SET_POWER_STATE,
+				     REALTEK_AUDIO_FUNCTION_GROUP,
+				     AC_PWRST_D3));
+
+	/*
+	 * Turn off 'manual mode' in case it was enabled. This removes the need
+	 * to power cycle the dock after it was attached to a Windows machine.
+	 */
+	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), REALTEK_MANUAL_MODE,
+			USB_RECIP_DEVICE | USB_TYPE_VENDOR | USB_DIR_OUT,
+			0, 0, NULL, 0);
 
 	err = realtek_add_jack(mixer, "Line Out Jack", REALTEK_LINE1);
 	if (err < 0)
@@ -2104,7 +2121,8 @@ static void dell_dock_init_vol(struct snd_usb_audio *chip, int ch, int id)
 
 	snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
 			USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-			ch, snd_usb_ctrl_intf(chip) | (id << 8),
+			(UAC_FU_VOLUME << 8) | ch,
+			snd_usb_ctrl_intf(chip) | (id << 8),
 			&buf, 2);
 }
 
-- 
2.35.3