Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Damien Dagorn and committed by
Takashi Iwai
cc051fbd b35f42a9

+170
+170
sound/hda/codecs/realtek/alc269.c
··· 1854 1854 spec->gen.pcm_playback_hook = alc298_samsung_v2_playback_hook; 1855 1855 } 1856 1856 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 + 1857 2014 static void alc298_fixup_samsung_amp_v2_2_amps(struct hda_codec *codec, 1858 2015 const struct hda_fixup *fix, int action) 1859 2016 { ··· 2023 1866 { 2024 1867 if (action == HDA_FIXUP_ACT_PROBE) 2025 1868 alc298_samsung_v2_init_amps(codec, 4); 1869 + } 1870 + 1871 + static void alc298_fixup_lg_gram_style_14(struct hda_codec *codec, 1872 + const struct hda_fixup *fix, int action) 1873 + { 1874 + if (action == HDA_FIXUP_ACT_PROBE) 1875 + alc298_lg_gram_style_init_amps(codec); 2026 1876 } 2027 1877 2028 1878 static void gpio2_mic_hotkey_event(struct hda_codec *codec, ··· 3917 3753 ALC298_FIXUP_SAMSUNG_AMP, 3918 3754 ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS, 3919 3755 ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS, 3756 + ALC298_FIXUP_LG_GRAM_STYLE_14, 3920 3757 ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, 3921 3758 ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, 3922 3759 ALC295_FIXUP_ASUS_MIC_NO_PRESENCE, ··· 5594 5429 [ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS] = { 5595 5430 .type = HDA_FIXUP_FUNC, 5596 5431 .v.func = alc298_fixup_samsung_amp_v2_4_amps 5432 + }, 5433 + [ALC298_FIXUP_LG_GRAM_STYLE_14] = { 5434 + .type = HDA_FIXUP_FUNC, 5435 + .v.func = alc298_fixup_lg_gram_style_14 5597 5436 }, 5598 5437 [ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET] = { 5599 5438 .type = HDA_FIXUP_VERBS, ··· 7537 7368 SND_PCI_QUIRK(0x1854, 0x0488, "LG gram 16 (16Z90R)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS), 7538 7369 SND_PCI_QUIRK(0x1854, 0x0489, "LG gram 16 (16Z90R-A)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS), 7539 7370 SND_PCI_QUIRK(0x1854, 0x048a, "LG gram 17 (17ZD90R)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS), 7371 + SND_PCI_QUIRK(0x1854, 0x0490, "LG Gram Style 14 (14Z90RS)", ALC298_FIXUP_LG_GRAM_STYLE_14), 7540 7372 SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS), 7541 7373 SND_PCI_QUIRK(0x19e5, 0x320f, "Huawei WRT-WX9 ", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), 7542 7374 SND_PCI_QUIRK(0x19e5, 0x3212, "Huawei KLV-WX9 ", ALC256_FIXUP_ACER_HEADSET_MIC),