Skip to content

Commit cc051fb

Browse files
DamsDGNtiwai
authored andcommitted
ALSA: hda/realtek: fix LG Gram Style 14 speakers
The LG Gram Style 14 (14Z90RS-G.AD77F, SSID 1854:0490) with Realtek ALC298 shows normal routing and volume changes, but internal speakers stay silent unless a userland HDA-verb workaround is applied. Add a dedicated quirk for the LG Gram Style 14 that programs the codec coefficient sequence used by the known workaround and enables the speaker amps only during playback. Tested-by: Damien Dagorn <damien.dagorn29@gmail.com> Signed-off-by: Damien Dagorn <damien.dagorn29@gmail.com> Link: https://lore.kernel.org/CAN59QMUhd4kHrkRoJA6VzEr2VKezN2yjHnANaQoZn2-Bnwe3bQ@mail.gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent b35f42a commit cc051fb

1 file changed

Lines changed: 170 additions & 0 deletions

File tree

sound/hda/codecs/realtek/alc269.c

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,6 +1854,163 @@ static void alc298_samsung_v2_init_amps(struct hda_codec *codec,
18541854
spec->gen.pcm_playback_hook = alc298_samsung_v2_playback_hook;
18551855
}
18561856

1857+
/* LG Gram Style 14: program vendor coef sequence used by HDA-verb workaround */
1858+
struct alc298_lg_gram_style_seq {
1859+
unsigned short verb;
1860+
unsigned short idx;
1861+
unsigned short val;
1862+
};
1863+
1864+
static void alc298_lg_gram_style_coef_write(struct hda_codec *codec,
1865+
unsigned int verb,
1866+
unsigned int idx,
1867+
unsigned int val)
1868+
{
1869+
snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x23);
1870+
snd_hda_codec_write(codec, 0x20, 0, verb, idx);
1871+
snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, 0x00);
1872+
snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, val);
1873+
snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, 0xb011);
1874+
}
1875+
1876+
static void alc298_lg_gram_style_run_seq(struct hda_codec *codec,
1877+
const struct alc298_lg_gram_style_seq *seq,
1878+
int seq_size)
1879+
{
1880+
int i;
1881+
1882+
for (i = 0; i < seq_size; i++)
1883+
alc298_lg_gram_style_coef_write(codec, seq[i].verb,
1884+
seq[i].idx, seq[i].val);
1885+
}
1886+
1887+
/* Coef sequences derived from the HDA-verb workaround for this model. */
1888+
static const struct alc298_lg_gram_style_seq alc298_lg_gram_style_preinit_seq[] = {
1889+
{ 0x420, 0x00, 0x01 },
1890+
};
1891+
1892+
static const struct alc298_lg_gram_style_seq alc298_lg_gram_style_disable_seq[] = {
1893+
{ 0x423, 0xff, 0x00 },
1894+
{ 0x420, 0x3a, 0x80 },
1895+
};
1896+
1897+
static const struct alc298_lg_gram_style_seq alc298_lg_gram_style_enable_seq[] = {
1898+
{ 0x420, 0x3a, 0x81 },
1899+
{ 0x423, 0xff, 0x01 },
1900+
};
1901+
1902+
static const struct alc298_lg_gram_style_seq alc298_lg_gram_style_init_seq_38[] = {
1903+
{ 0x423, 0xe1, 0x00 }, { 0x420, 0x12, 0x6f }, { 0x420, 0x14, 0x00 },
1904+
{ 0x420, 0x1b, 0x01 }, { 0x420, 0x1d, 0x01 }, { 0x420, 0x1f, 0xfe },
1905+
{ 0x420, 0x21, 0x00 }, { 0x420, 0x22, 0x10 }, { 0x420, 0x3d, 0x05 },
1906+
{ 0x420, 0x3f, 0x03 }, { 0x420, 0x50, 0x2c }, { 0x420, 0x76, 0x0e },
1907+
{ 0x420, 0x7c, 0x4a }, { 0x420, 0x81, 0x03 }, { 0x423, 0x99, 0x03 },
1908+
{ 0x423, 0xa4, 0xb5 }, { 0x423, 0xa5, 0x01 }, { 0x423, 0xba, 0x94 },
1909+
};
1910+
1911+
static const struct alc298_lg_gram_style_seq alc298_lg_gram_style_init_seq_39[] = {
1912+
{ 0x423, 0xe1, 0x00 }, { 0x420, 0x12, 0x6f }, { 0x420, 0x14, 0x00 },
1913+
{ 0x420, 0x1b, 0x02 }, { 0x420, 0x1d, 0x02 }, { 0x420, 0x1f, 0xfd },
1914+
{ 0x420, 0x21, 0x01 }, { 0x420, 0x22, 0x10 }, { 0x420, 0x3d, 0x05 },
1915+
{ 0x420, 0x3f, 0x03 }, { 0x420, 0x50, 0x2c }, { 0x420, 0x76, 0x0e },
1916+
{ 0x420, 0x7c, 0x4a }, { 0x420, 0x81, 0x03 }, { 0x423, 0x99, 0x03 },
1917+
{ 0x423, 0xa4, 0xb5 }, { 0x423, 0xa5, 0x01 }, { 0x423, 0xba, 0x94 },
1918+
};
1919+
1920+
static const struct alc298_lg_gram_style_seq alc298_lg_gram_style_init_seq_3c[] = {
1921+
{ 0x423, 0xe1, 0x00 }, { 0x420, 0x12, 0x6f }, { 0x420, 0x14, 0x00 },
1922+
{ 0x420, 0x1b, 0x01 }, { 0x420, 0x1d, 0x01 }, { 0x420, 0x1f, 0xfe },
1923+
{ 0x420, 0x21, 0x00 }, { 0x420, 0x22, 0x10 }, { 0x420, 0x3d, 0x05 },
1924+
{ 0x420, 0x3f, 0x03 }, { 0x420, 0x50, 0x2c }, { 0x420, 0x76, 0x0e },
1925+
{ 0x420, 0x7c, 0x4a }, { 0x420, 0x81, 0x03 }, { 0x423, 0xba, 0x8d },
1926+
};
1927+
1928+
static const struct alc298_lg_gram_style_seq alc298_lg_gram_style_init_seq_3d[] = {
1929+
{ 0x423, 0xe1, 0x00 }, { 0x420, 0x12, 0x6f }, { 0x420, 0x14, 0x00 },
1930+
{ 0x420, 0x1b, 0x02 }, { 0x420, 0x1d, 0x02 }, { 0x420, 0x1f, 0xfd },
1931+
{ 0x420, 0x21, 0x01 }, { 0x420, 0x22, 0x10 }, { 0x420, 0x3d, 0x05 },
1932+
{ 0x420, 0x3f, 0x03 }, { 0x420, 0x50, 0x2c }, { 0x420, 0x76, 0x0e },
1933+
{ 0x420, 0x7c, 0x4a }, { 0x420, 0x81, 0x03 }, { 0x423, 0xba, 0x8d },
1934+
};
1935+
1936+
struct alc298_lg_gram_style_amp_desc {
1937+
unsigned char nid;
1938+
const struct alc298_lg_gram_style_seq *init_seq;
1939+
int init_seq_size;
1940+
};
1941+
1942+
static const struct alc298_lg_gram_style_amp_desc alc298_lg_gram_style_amps[] = {
1943+
{ 0x38, alc298_lg_gram_style_init_seq_38,
1944+
ARRAY_SIZE(alc298_lg_gram_style_init_seq_38) },
1945+
{ 0x39, alc298_lg_gram_style_init_seq_39,
1946+
ARRAY_SIZE(alc298_lg_gram_style_init_seq_39) },
1947+
{ 0x3c, alc298_lg_gram_style_init_seq_3c,
1948+
ARRAY_SIZE(alc298_lg_gram_style_init_seq_3c) },
1949+
{ 0x3d, alc298_lg_gram_style_init_seq_3d,
1950+
ARRAY_SIZE(alc298_lg_gram_style_init_seq_3d) },
1951+
};
1952+
1953+
static void alc298_lg_gram_style_enable_amps(struct hda_codec *codec)
1954+
{
1955+
struct alc_spec *spec = codec->spec;
1956+
int i;
1957+
1958+
for (i = 0; i < spec->num_speaker_amps; i++) {
1959+
alc_write_coef_idx(codec, 0x22, alc298_lg_gram_style_amps[i].nid);
1960+
alc298_lg_gram_style_run_seq(codec,
1961+
alc298_lg_gram_style_enable_seq,
1962+
ARRAY_SIZE(alc298_lg_gram_style_enable_seq));
1963+
}
1964+
}
1965+
1966+
static void alc298_lg_gram_style_disable_amps(struct hda_codec *codec)
1967+
{
1968+
struct alc_spec *spec = codec->spec;
1969+
int i;
1970+
1971+
for (i = 0; i < spec->num_speaker_amps; i++) {
1972+
alc_write_coef_idx(codec, 0x22, alc298_lg_gram_style_amps[i].nid);
1973+
alc298_lg_gram_style_run_seq(codec,
1974+
alc298_lg_gram_style_disable_seq,
1975+
ARRAY_SIZE(alc298_lg_gram_style_disable_seq));
1976+
}
1977+
}
1978+
1979+
static void alc298_lg_gram_style_playback_hook(struct hda_pcm_stream *hinfo,
1980+
struct hda_codec *codec,
1981+
struct snd_pcm_substream *substream,
1982+
int action)
1983+
{
1984+
if (action == HDA_GEN_PCM_ACT_OPEN)
1985+
alc298_lg_gram_style_enable_amps(codec);
1986+
if (action == HDA_GEN_PCM_ACT_CLOSE)
1987+
alc298_lg_gram_style_disable_amps(codec);
1988+
}
1989+
1990+
static void alc298_lg_gram_style_init_amps(struct hda_codec *codec)
1991+
{
1992+
struct alc_spec *spec = codec->spec;
1993+
int i;
1994+
1995+
spec->num_speaker_amps = ARRAY_SIZE(alc298_lg_gram_style_amps);
1996+
1997+
for (i = 0; i < spec->num_speaker_amps; i++) {
1998+
alc_write_coef_idx(codec, 0x22, alc298_lg_gram_style_amps[i].nid);
1999+
alc298_lg_gram_style_run_seq(codec,
2000+
alc298_lg_gram_style_preinit_seq,
2001+
ARRAY_SIZE(alc298_lg_gram_style_preinit_seq));
2002+
alc298_lg_gram_style_run_seq(codec,
2003+
alc298_lg_gram_style_disable_seq,
2004+
ARRAY_SIZE(alc298_lg_gram_style_disable_seq));
2005+
alc298_lg_gram_style_run_seq(codec,
2006+
alc298_lg_gram_style_amps[i].init_seq,
2007+
alc298_lg_gram_style_amps[i].init_seq_size);
2008+
alc_write_coef_idx(codec, 0x89, 0x0);
2009+
}
2010+
2011+
spec->gen.pcm_playback_hook = alc298_lg_gram_style_playback_hook;
2012+
}
2013+
18572014
static void alc298_fixup_samsung_amp_v2_2_amps(struct hda_codec *codec,
18582015
const struct hda_fixup *fix, int action)
18592016
{
@@ -1868,6 +2025,13 @@ static void alc298_fixup_samsung_amp_v2_4_amps(struct hda_codec *codec,
18682025
alc298_samsung_v2_init_amps(codec, 4);
18692026
}
18702027

2028+
static void alc298_fixup_lg_gram_style_14(struct hda_codec *codec,
2029+
const struct hda_fixup *fix, int action)
2030+
{
2031+
if (action == HDA_FIXUP_ACT_PROBE)
2032+
alc298_lg_gram_style_init_amps(codec);
2033+
}
2034+
18712035
static void gpio2_mic_hotkey_event(struct hda_codec *codec,
18722036
struct hda_jack_callback *event)
18732037
{
@@ -3753,6 +3917,7 @@ enum {
37533917
ALC298_FIXUP_SAMSUNG_AMP,
37543918
ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS,
37553919
ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS,
3920+
ALC298_FIXUP_LG_GRAM_STYLE_14,
37563921
ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET,
37573922
ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET,
37583923
ALC295_FIXUP_ASUS_MIC_NO_PRESENCE,
@@ -5430,6 +5595,10 @@ static const struct hda_fixup alc269_fixups[] = {
54305595
.type = HDA_FIXUP_FUNC,
54315596
.v.func = alc298_fixup_samsung_amp_v2_4_amps
54325597
},
5598+
[ALC298_FIXUP_LG_GRAM_STYLE_14] = {
5599+
.type = HDA_FIXUP_FUNC,
5600+
.v.func = alc298_fixup_lg_gram_style_14
5601+
},
54335602
[ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET] = {
54345603
.type = HDA_FIXUP_VERBS,
54355604
.v.verbs = (const struct hda_verb[]) {
@@ -7368,6 +7537,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
73687537
SND_PCI_QUIRK(0x1854, 0x0488, "LG gram 16 (16Z90R)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
73697538
SND_PCI_QUIRK(0x1854, 0x0489, "LG gram 16 (16Z90R-A)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
73707539
SND_PCI_QUIRK(0x1854, 0x048a, "LG gram 17 (17ZD90R)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
7540+
SND_PCI_QUIRK(0x1854, 0x0490, "LG Gram Style 14 (14Z90RS)", ALC298_FIXUP_LG_GRAM_STYLE_14),
73717541
SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS),
73727542
SND_PCI_QUIRK(0x19e5, 0x320f, "Huawei WRT-WX9 ", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
73737543
SND_PCI_QUIRK(0x19e5, 0x3212, "Huawei KLV-WX9 ", ALC256_FIXUP_ACER_HEADSET_MIC),

0 commit comments

Comments
 (0)