Commit aeeb85f2 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: hda: Split Realtek HD-audio codec driver



The snd-hda-codec-realtek driver supports many different codec models
and accumulated lots of quirks.  Now let's split it to multiple
modules per probe function, i.e. for ALC260, ALC262, ALC269, etc.

The common code and quirks are provided by the common library module,
snd-hda-codec-realtek-lib now.  One drawback of this action is that
many symbols have to be exported.  But they are limited with
SND_HDA_CODEC_REALTEK namespace, at least.

This patch tries to be idiomatic and doesn't try to rewrite the
existing code.  We can move the codec model-specific code into each
codec driver later.

The HD-audio sub-codec component binding is currently specific to
ALC269, hence the management is moved into alc269.c.
After that, alc_free() became identical with snd_hda_gen_free(), and
it's replaced as a macro just to call snd_hda_gen_free().

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20250709160434.1859-8-tiwai@suse.de
parent 6014e902
Loading
Loading
Loading
Loading
+1 −13
Original line number Diff line number Diff line
@@ -4,19 +4,6 @@ if SND_HDA
config SND_HDA_GENERIC_LEDS
       bool

config SND_HDA_CODEC_REALTEK
	tristate "Build Realtek HD-audio codec support"
	depends on INPUT
	select SND_HDA_GENERIC
	select SND_HDA_GENERIC_LEDS
	select SND_HDA_SCODEC_COMPONENT
	help
	  Say Y or M here to include Realtek HD-audio codec support in
	  snd-hda-intel driver, such as ALC880.

comment "Set to Y if you want auto-loading the codec driver"
	depends on SND_HDA=y && SND_HDA_CODEC_REALTEK=m

config SND_HDA_CODEC_ANALOG
	tristate "Build Analog Devices HD-audio codec support"
	select SND_HDA_GENERIC
@@ -162,6 +149,7 @@ config SND_HDA_INTEL_HDMI_SILENT_STREAM
	  This feature can impact power consumption as resources
	  are kept reserved both at transmitter and receiver.

source "sound/hda/codecs/realtek/Kconfig"
source "sound/hda/codecs/cirrus/Kconfig"
source "sound/hda/codecs/side-codecs/Kconfig"

+3 −2
Original line number Diff line number Diff line
@@ -2,30 +2,31 @@
subdir-ccflags-y += -I$(src)/../common

snd-hda-codec-generic-y :=	generic.o
snd-hda-codec-cmedia-y :=	cmedia.o
snd-hda-codec-analog-y :=	analog.o
snd-hda-codec-ca0110-y :=	ca0110.o
snd-hda-codec-ca0132-y :=	ca0132.o
snd-hda-codec-cmedia-y :=	cmedia.o
snd-hda-codec-conexant-y :=	conexant.o
snd-hda-codec-idt-y :=		sigmatel.o
snd-hda-codec-realtek-y :=	realtek.o
snd-hda-codec-senarytech-y :=	senarytech.o
snd-hda-codec-si3054-y :=	si3054.o
snd-hda-codec-via-y :=		via.o

obj-y += cirrus/
obj-y += hdmi/
obj-y += realtek/
obj-y += side-codecs/

# codec drivers
obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o
obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o
obj-$(CONFIG_SND_HDA_CODEC_ANALOG) += snd-hda-codec-analog.o
obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o
obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o
obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o
obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o
obj-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += snd-hda-codec-idt.o
obj-$(CONFIG_SND_HDA_CODEC_REALTEK) += snd-hda-codec-realtek.o
obj-$(CONFIG_SND_HDA_CODEC_SENARYTECH) += snd-hda-codec-senarytech.o
obj-$(CONFIG_SND_HDA_CODEC_SI3054) += snd-hda-codec-si3054.o
obj-$(CONFIG_SND_HDA_CODEC_VIA) += snd-hda-codec-via.o
+90 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only

menuconfig SND_HDA_CODEC_REALTEK
	bool "Realtek HD-audio codec support"

if SND_HDA_CODEC_REALTEK

config SND_HDA_CODEC_REALTEK_LIB
	tristate
	select SND_HDA_GENERIC
	select SND_HDA_GENERIC_LEDS
	select SND_HDA_SCODEC_COMPONENT

config SND_HDA_CODEC_ALC260
	tristate "Build Realtek ALC260 HD-audio codec support"
	depends on INPUT
	select SND_HDA_CODEC_REALTEK_LIB
	help
	  Say Y or M here to include Realtek ALC260 HD-audio codec support

config SND_HDA_CODEC_ALC262
	tristate "Build Realtek ALC262 HD-audio codec support"
	depends on INPUT
	select SND_HDA_CODEC_REALTEK_LIB
	help
	  Say Y or M here to include Realtek ALC262 HD-audio codec support

config SND_HDA_CODEC_ALC268
	tristate "Build Realtek ALC268 HD-audio codec support"
	depends on INPUT
	select SND_HDA_CODEC_REALTEK_LIB
	help
	  Say Y or M here to include Realtek ALC268 and compatible HD-audio
	  codec support

config SND_HDA_CODEC_ALC269
	tristate "Build Realtek ALC269 HD-audio codecs support"
	depends on INPUT
	select SND_HDA_CODEC_REALTEK_LIB
	help
	  Say Y or M here to include Realtek ALC269 and compatible HD-audio
	  codec support

config SND_HDA_CODEC_ALC662
	tristate "Build Realtek ALC662 HD-audio codecs support"
	depends on INPUT
	select SND_HDA_CODEC_REALTEK_LIB
	help
	  Say Y or M here to include Realtek ALC662 and compatible HD-audio
	  codec support

config SND_HDA_CODEC_ALC680
	tristate "Build Realtek ALC680 HD-audio codecs support"
	depends on INPUT
	select SND_HDA_CODEC_REALTEK_LIB
	help
	  Say Y or M here to include Realtek ALC680 HD-audio codec support

config SND_HDA_CODEC_ALC861
	tristate "Build Realtek ALC861 HD-audio codecs support"
	depends on INPUT
	select SND_HDA_CODEC_REALTEK_LIB
	help
	  Say Y or M here to include Realtek ALC861 HD-audio codec support

config SND_HDA_CODEC_ALC861VD
	tristate "Build Realtek ALC861-VD HD-audio codecs support"
	depends on INPUT
	select SND_HDA_CODEC_REALTEK_LIB
	help
	  Say Y or M here to include Realtek ALC861-VD HD-audio codec support

config SND_HDA_CODEC_ALC880
	tristate "Build Realtek ALC880 HD-audio codecs support"
	depends on INPUT
	select SND_HDA_CODEC_REALTEK_LIB
	help
	  Say Y or M here to include Realtek ALC880 HD-audio codec support

config SND_HDA_CODEC_ALC882
	tristate "Build Realtek ALC882 HD-audio codecs support"
	depends on INPUT
	select SND_HDA_CODEC_REALTEK_LIB
	help
	  Say Y or M here to include Realtek ALC882 and compatible HD-audio
	  codec support

endif

+26 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0
subdir-ccflags-y += -I$(src)/../../common

snd-hda-codec-realtek-lib-y :=	realtek.o
snd-hda-codec-alc260-y :=	alc260.o
snd-hda-codec-alc262-y :=	alc262.o
snd-hda-codec-alc268-y :=	alc268.o
snd-hda-codec-alc269-y :=	alc269.o
snd-hda-codec-alc662-y :=	alc662.o
snd-hda-codec-alc680-y :=	alc680.o
snd-hda-codec-alc861-y :=	alc861.o
snd-hda-codec-alc861vd-y :=	alc861vd.o
snd-hda-codec-alc880-y :=	alc880.o
snd-hda-codec-alc882-y :=	alc882.o

obj-$(CONFIG_SND_HDA_CODEC_REALTEK_LIB) += snd-hda-codec-realtek-lib.o
obj-$(CONFIG_SND_HDA_CODEC_ALC260) += snd-hda-codec-alc260.o
obj-$(CONFIG_SND_HDA_CODEC_ALC262) += snd-hda-codec-alc262.o
obj-$(CONFIG_SND_HDA_CODEC_ALC268) += snd-hda-codec-alc268.o
obj-$(CONFIG_SND_HDA_CODEC_ALC269) += snd-hda-codec-alc269.o
obj-$(CONFIG_SND_HDA_CODEC_ALC662) += snd-hda-codec-alc662.o
obj-$(CONFIG_SND_HDA_CODEC_ALC680) += snd-hda-codec-alc680.o
obj-$(CONFIG_SND_HDA_CODEC_ALC861) += snd-hda-codec-alc861.o
obj-$(CONFIG_SND_HDA_CODEC_ALC861VD) += snd-hda-codec-alc861vd.o
obj-$(CONFIG_SND_HDA_CODEC_ALC880) += snd-hda-codec-alc880.o
obj-$(CONFIG_SND_HDA_CODEC_ALC882) += snd-hda-codec-alc882.o
+276 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-or-later
//
// Realtek ALC260 codec
//

#include <linux/init.h>
#include <linux/module.h>
#include "realtek.h"

static int alc260_parse_auto_config(struct hda_codec *codec)
{
	static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
	static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 };
	return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
}

/*
 * Pin config fixes
 */
enum {
	ALC260_FIXUP_HP_DC5750,
	ALC260_FIXUP_HP_PIN_0F,
	ALC260_FIXUP_COEF,
	ALC260_FIXUP_GPIO1,
	ALC260_FIXUP_GPIO1_TOGGLE,
	ALC260_FIXUP_REPLACER,
	ALC260_FIXUP_HP_B1900,
	ALC260_FIXUP_KN1,
	ALC260_FIXUP_FSC_S7020,
	ALC260_FIXUP_FSC_S7020_JWSE,
	ALC260_FIXUP_VAIO_PINS,
};

static void alc260_gpio1_automute(struct hda_codec *codec)
{
	struct alc_spec *spec = codec->spec;

	alc_update_gpio_data(codec, 0x01, spec->gen.hp_jack_present);
}

static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
				      const struct hda_fixup *fix, int action)
{
	struct alc_spec *spec = codec->spec;
	if (action == HDA_FIXUP_ACT_PROBE) {
		/* although the machine has only one output pin, we need to
		 * toggle GPIO1 according to the jack state
		 */
		spec->gen.automute_hook = alc260_gpio1_automute;
		spec->gen.detect_hp = 1;
		spec->gen.automute_speaker = 1;
		spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
		snd_hda_jack_detect_enable_callback(codec, 0x0f,
						    snd_hda_gen_hp_automute);
		alc_setup_gpio(codec, 0x01);
	}
}

static void alc260_fixup_kn1(struct hda_codec *codec,
			     const struct hda_fixup *fix, int action)
{
	struct alc_spec *spec = codec->spec;
	static const struct hda_pintbl pincfgs[] = {
		{ 0x0f, 0x02214000 }, /* HP/speaker */
		{ 0x12, 0x90a60160 }, /* int mic */
		{ 0x13, 0x02a19000 }, /* ext mic */
		{ 0x18, 0x01446000 }, /* SPDIF out */
		/* disable bogus I/O pins */
		{ 0x10, 0x411111f0 },
		{ 0x11, 0x411111f0 },
		{ 0x14, 0x411111f0 },
		{ 0x15, 0x411111f0 },
		{ 0x16, 0x411111f0 },
		{ 0x17, 0x411111f0 },
		{ 0x19, 0x411111f0 },
		{ }
	};

	switch (action) {
	case HDA_FIXUP_ACT_PRE_PROBE:
		snd_hda_apply_pincfgs(codec, pincfgs);
		spec->init_amp = ALC_INIT_NONE;
		break;
	}
}

static void alc260_fixup_fsc_s7020(struct hda_codec *codec,
				   const struct hda_fixup *fix, int action)
{
	struct alc_spec *spec = codec->spec;
	if (action == HDA_FIXUP_ACT_PRE_PROBE)
		spec->init_amp = ALC_INIT_NONE;
}

static void alc260_fixup_fsc_s7020_jwse(struct hda_codec *codec,
				   const struct hda_fixup *fix, int action)
{
	struct alc_spec *spec = codec->spec;
	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
		spec->gen.add_jack_modes = 1;
		spec->gen.hp_mic = 1;
	}
}

static const struct hda_fixup alc260_fixups[] = {
	[ALC260_FIXUP_HP_DC5750] = {
		.type = HDA_FIXUP_PINS,
		.v.pins = (const struct hda_pintbl[]) {
			{ 0x11, 0x90130110 }, /* speaker */
			{ }
		}
	},
	[ALC260_FIXUP_HP_PIN_0F] = {
		.type = HDA_FIXUP_PINS,
		.v.pins = (const struct hda_pintbl[]) {
			{ 0x0f, 0x01214000 }, /* HP */
			{ }
		}
	},
	[ALC260_FIXUP_COEF] = {
		.type = HDA_FIXUP_VERBS,
		.v.verbs = (const struct hda_verb[]) {
			{ 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
			{ 0x1a, AC_VERB_SET_PROC_COEF,  0x3040 },
			{ }
		},
	},
	[ALC260_FIXUP_GPIO1] = {
		.type = HDA_FIXUP_FUNC,
		.v.func = alc_fixup_gpio1,
	},
	[ALC260_FIXUP_GPIO1_TOGGLE] = {
		.type = HDA_FIXUP_FUNC,
		.v.func = alc260_fixup_gpio1_toggle,
		.chained = true,
		.chain_id = ALC260_FIXUP_HP_PIN_0F,
	},
	[ALC260_FIXUP_REPLACER] = {
		.type = HDA_FIXUP_VERBS,
		.v.verbs = (const struct hda_verb[]) {
			{ 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
			{ 0x1a, AC_VERB_SET_PROC_COEF,  0x3050 },
			{ }
		},
		.chained = true,
		.chain_id = ALC260_FIXUP_GPIO1_TOGGLE,
	},
	[ALC260_FIXUP_HP_B1900] = {
		.type = HDA_FIXUP_FUNC,
		.v.func = alc260_fixup_gpio1_toggle,
		.chained = true,
		.chain_id = ALC260_FIXUP_COEF,
	},
	[ALC260_FIXUP_KN1] = {
		.type = HDA_FIXUP_FUNC,
		.v.func = alc260_fixup_kn1,
	},
	[ALC260_FIXUP_FSC_S7020] = {
		.type = HDA_FIXUP_FUNC,
		.v.func = alc260_fixup_fsc_s7020,
	},
	[ALC260_FIXUP_FSC_S7020_JWSE] = {
		.type = HDA_FIXUP_FUNC,
		.v.func = alc260_fixup_fsc_s7020_jwse,
		.chained = true,
		.chain_id = ALC260_FIXUP_FSC_S7020,
	},
	[ALC260_FIXUP_VAIO_PINS] = {
		.type = HDA_FIXUP_PINS,
		.v.pins = (const struct hda_pintbl[]) {
			/* Pin configs are missing completely on some VAIOs */
			{ 0x0f, 0x01211020 },
			{ 0x10, 0x0001003f },
			{ 0x11, 0x411111f0 },
			{ 0x12, 0x01a15930 },
			{ 0x13, 0x411111f0 },
			{ 0x14, 0x411111f0 },
			{ 0x15, 0x411111f0 },
			{ 0x16, 0x411111f0 },
			{ 0x17, 0x411111f0 },
			{ 0x18, 0x411111f0 },
			{ 0x19, 0x411111f0 },
			{ }
		}
	},
};

static const struct hda_quirk alc260_fixup_tbl[] = {
	SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1),
	SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF),
	SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1),
	SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750),
	SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900),
	SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_FIXUP_VAIO_PINS),
	SND_PCI_QUIRK(0x104d, 0x81e2, "Sony VAIO TX", ALC260_FIXUP_HP_PIN_0F),
	SND_PCI_QUIRK(0x10cf, 0x1326, "FSC LifeBook S7020", ALC260_FIXUP_FSC_S7020),
	SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1),
	SND_PCI_QUIRK(0x152d, 0x0729, "Quanta KN1", ALC260_FIXUP_KN1),
	SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_FIXUP_REPLACER),
	SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_FIXUP_COEF),
	{}
};

static const struct hda_model_fixup alc260_fixup_models[] = {
	{.id = ALC260_FIXUP_GPIO1, .name = "gpio1"},
	{.id = ALC260_FIXUP_COEF, .name = "coef"},
	{.id = ALC260_FIXUP_FSC_S7020, .name = "fujitsu"},
	{.id = ALC260_FIXUP_FSC_S7020_JWSE, .name = "fujitsu-jwse"},
	{}
};

/*
 */
static int patch_alc260(struct hda_codec *codec)
{
	struct alc_spec *spec;
	int err;

	err = alc_alloc_spec(codec, 0x07);
	if (err < 0)
		return err;

	spec = codec->spec;
	/* as quite a few machines require HP amp for speaker outputs,
	 * it's easier to enable it unconditionally; even if it's unneeded,
	 * it's almost harmless.
	 */
	spec->gen.prefer_hp_amp = 1;
	spec->gen.beep_nid = 0x01;

	spec->shutup = alc_eapd_shutup;

	alc_pre_init(codec);

	snd_hda_pick_fixup(codec, alc260_fixup_models, alc260_fixup_tbl,
			   alc260_fixups);
	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);

	/* automatic parse from the BIOS config */
	err = alc260_parse_auto_config(codec);
	if (err < 0)
		goto error;

	if (!spec->gen.no_analog) {
		err = set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
		if (err < 0)
			goto error;
	}

	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);

	return 0;

 error:
	alc_free(codec);
	return err;
}

/*
 * driver entries
 */
static const struct hda_device_id snd_hda_id_alc260[] = {
	HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260),
	{} /* terminator */
};
MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc260);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Realtek ALC260 HD-audio codec");
MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");

static struct hda_codec_driver alc260_driver = {
	.id = snd_hda_id_alc260,
};

module_hda_codec_driver(alc260_driver);
Loading