From c4b79a2fbfb28308e958e4ffdd988f3cf678fe2a Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 7 May 2025 10:01:38 +0200 Subject: [PATCH 001/385] ASoC: qcom: sm8250: set card driver name from match data Sound machine drivers for Qualcomm SoCs can be reused across multiple SoCs. But user space ALSA UCM files depend on the card driver name which should be set per board/SoC. Allow such customization by using driver match data as sound card driver name. The QRB4210 RB2 gets its name set to "sm4250" as requested by Srinivas Kandagatla, and since no (known) UCM has been written yet this should not break anything. Also while we're already touching these lines, sort the compatibles alphabetically. Reviewed-by: Dmitry Baryshkov Reviewed-by: Neil Armstrong Signed-off-by: Luca Weiss Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20250507-fp5-dp-sound-v4-2-4098e918a29e@fairphone.com Signed-off-by: Mark Brown --- sound/soc/qcom/sm8250.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index b70b2a5031df..f0d83a843765 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -16,7 +16,6 @@ #include "usb_offload_utils.h" #include "sdw.h" -#define DRIVER_NAME "sm8250" #define MI2S_BCLK_RATE 1536000 struct sm8250_snd_data { @@ -200,15 +199,15 @@ static int sm8250_platform_probe(struct platform_device *pdev) if (ret) return ret; - card->driver_name = DRIVER_NAME; + card->driver_name = of_device_get_match_data(dev); sm8250_add_be_ops(card); return devm_snd_soc_register_card(dev, card); } static const struct of_device_id snd_sm8250_dt_match[] = { - {.compatible = "qcom,sm8250-sndcard"}, - {.compatible = "qcom,qrb4210-rb2-sndcard"}, - {.compatible = "qcom,qrb5165-rb5-sndcard"}, + { .compatible = "qcom,qrb4210-rb2-sndcard", .data = "sm4250" }, + { .compatible = "qcom,qrb5165-rb5-sndcard", .data = "sm8250" }, + { .compatible = "qcom,sm8250-sndcard", .data = "sm8250" }, {} }; From ed82808c6a0f333e51fee4e97cbe8e0189b7f354 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 7 May 2025 10:01:39 +0200 Subject: [PATCH 002/385] ASoC: qcom: sm8250: add DisplayPort Jack support Add support for DisplayPort Jack events, so that user space can configure the audio routing correctly. Reviewed-by: Dmitry Baryshkov Signed-off-by: Luca Weiss Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20250507-fp5-dp-sound-v4-3-4098e918a29e@fairphone.com Signed-off-by: Mark Brown --- sound/soc/qcom/sm8250.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index f0d83a843765..2317fe285ee7 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -25,6 +25,7 @@ struct sm8250_snd_data { struct snd_soc_jack jack; struct snd_soc_jack usb_offload_jack; bool usb_offload_jack_setup; + struct snd_soc_jack dp_jack; bool jack_setup; }; @@ -32,14 +33,16 @@ static int sm8250_snd_init(struct snd_soc_pcm_runtime *rtd) { struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); - int ret; - if (cpu_dai->id == USB_RX) - ret = qcom_snd_usb_offload_jack_setup(rtd, &data->usb_offload_jack, - &data->usb_offload_jack_setup); - else - ret = qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); - return ret; + switch (cpu_dai->id) { + case DISPLAY_PORT_RX: + return qcom_snd_dp_jack_setup(rtd, &data->dp_jack, 0); + case USB_RX: + return qcom_snd_usb_offload_jack_setup(rtd, &data->usb_offload_jack, + &data->usb_offload_jack_setup); + default: + return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); + } } static void sm8250_snd_exit(struct snd_soc_pcm_runtime *rtd) From e6e8897995a9e6028563ce36c27877e5478c8571 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 7 May 2025 10:01:40 +0200 Subject: [PATCH 003/385] ASoC: qcom: sm8250: Add Fairphone 5 soundcard compatible Add a compatible for the QCM6490-based Fairphone 5 which can use this machine driver. As a note, QCM6490 RB3 board is using audioreach architecture while Fairphone 5 uses pre-audioreach. Reviewed-by: Dmitry Baryshkov Reviewed-by: Neil Armstrong Signed-off-by: Luca Weiss Link: https://patch.msgid.link/20250507-fp5-dp-sound-v4-4-4098e918a29e@fairphone.com Signed-off-by: Mark Brown --- sound/soc/qcom/sm8250.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index 2317fe285ee7..69c514fad0b1 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -208,6 +208,7 @@ static int sm8250_platform_probe(struct platform_device *pdev) } static const struct of_device_id snd_sm8250_dt_match[] = { + { .compatible = "fairphone,fp5-sndcard", .data = "qcm6490" }, { .compatible = "qcom,qrb4210-rb2-sndcard", .data = "sm4250" }, { .compatible = "qcom,qrb5165-rb5-sndcard", .data = "sm8250" }, { .compatible = "qcom,sm8250-sndcard", .data = "sm8250" }, From 0045b902ad27f2676c2a5b6444494a8287b80072 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 28 May 2025 21:59:55 +0200 Subject: [PATCH 004/385] ASoC: codecs: Constify regmap configuration static variables Static arrays/structs for regmap configuration like 'struct reg_default', 'struct reg_sequence' and others are not modified so can be changed to const for more safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Charles Keepax Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20250528-asoc-const-unused-v1-1-19a5d07b9d5c@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l36.c | 2 +- sound/soc/codecs/da7218.c | 2 +- sound/soc/codecs/da7219.c | 4 ++-- sound/soc/codecs/es8375.c | 2 +- sound/soc/codecs/max98363.c | 2 +- sound/soc/codecs/max98373-i2c.c | 2 +- sound/soc/codecs/max98373-sdw.c | 2 +- sound/soc/codecs/max98388.c | 2 +- sound/soc/codecs/max98390.c | 2 +- sound/soc/codecs/max98396.c | 4 ++-- sound/soc/codecs/max98504.c | 2 +- sound/soc/codecs/max98520.c | 2 +- sound/soc/codecs/max98927.c | 2 +- sound/soc/codecs/rt722-sdca-sdw.c | 2 +- sound/soc/codecs/wcd938x.c | 2 +- sound/soc/codecs/wsa881x.c | 4 ++-- sound/soc/codecs/wsa883x.c | 2 +- sound/soc/codecs/wsa884x.c | 2 +- 18 files changed, 21 insertions(+), 21 deletions(-) diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c index b49c6905e872..b60697ff7a50 100644 --- a/sound/soc/codecs/cs35l36.c +++ b/sound/soc/codecs/cs35l36.c @@ -129,7 +129,7 @@ static const struct cs35l36_pll_config cs35l36_pll_sysclk[] = { {27000000, 0x3F, 0x0A}, }; -static struct reg_default cs35l36_reg[] = { +static const struct reg_default cs35l36_reg[] = { {CS35L36_TESTKEY_CTRL, 0x00000000}, {CS35L36_USERKEY_CTL, 0x00000000}, {CS35L36_OTP_CTRL1, 0x00002460}, diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index 5f2f67e3bd29..a7539e1a1893 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c @@ -3033,7 +3033,7 @@ static const struct snd_soc_component_driver soc_component_dev_da7218 = { * Regmap configs */ -static struct reg_default da7218_reg_defaults[] = { +static const struct reg_default da7218_reg_defaults[] = { { DA7218_SYSTEM_ACTIVE, 0x00 }, { DA7218_CIF_CTRL, 0x00 }, { DA7218_SPARE1, 0x00 }, diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 3958e88a2445..221577574525 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -2312,7 +2312,7 @@ static void da7219_handle_pdata(struct snd_soc_component *component) * Regmap configs */ -static struct reg_default da7219_reg_defaults[] = { +static const struct reg_default da7219_reg_defaults[] = { { DA7219_MIC_1_SELECT, 0x00 }, { DA7219_CIF_TIMEOUT_CTRL, 0x01 }, { DA7219_SR_24_48, 0x00 }, @@ -2443,7 +2443,7 @@ static const struct regmap_config da7219_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static struct reg_sequence da7219_rev_aa_patch[] = { +static const struct reg_sequence da7219_rev_aa_patch[] = { { DA7219_REFERENCES, 0x08 }, }; diff --git a/sound/soc/codecs/es8375.c b/sound/soc/codecs/es8375.c index 009259632107..36b0ebdce514 100644 --- a/sound/soc/codecs/es8375.c +++ b/sound/soc/codecs/es8375.c @@ -620,7 +620,7 @@ static bool es8375_writeable_register(struct device *dev, unsigned int reg) } } -static struct regmap_config es8375_regmap_config = { +static const struct regmap_config es8375_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = ES8375_REG_MAX, diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c index 950105e5bffd..fd6830a7579d 100644 --- a/sound/soc/codecs/max98363.c +++ b/sound/soc/codecs/max98363.c @@ -14,7 +14,7 @@ #include "max98363.h" -static struct reg_default max98363_reg[] = { +static const struct reg_default max98363_reg[] = { {MAX98363_R2021_ERR_MON_CTRL, 0x0}, {MAX98363_R2022_SPK_MON_THRESH, 0x0}, {MAX98363_R2023_SPK_MON_DURATION, 0x0}, diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c index 56c4ba1f3782..f58b8c8625a7 100644 --- a/sound/soc/codecs/max98373-i2c.c +++ b/sound/soc/codecs/max98373-i2c.c @@ -23,7 +23,7 @@ static const u32 max98373_i2c_cache_reg[] = { MAX98373_R20B6_BDE_CUR_STATE_READBACK, }; -static struct reg_default max98373_reg[] = { +static const struct reg_default max98373_reg[] = { {MAX98373_R2000_SW_RESET, 0x00}, {MAX98373_R2001_INT_RAW1, 0x00}, {MAX98373_R2002_INT_RAW2, 0x00}, diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index 6088278e6503..43b52bda6ad5 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -26,7 +26,7 @@ static const u32 max98373_sdw_cache_reg[] = { MAX98373_R20B6_BDE_CUR_STATE_READBACK, }; -static struct reg_default max98373_reg[] = { +static const struct reg_default max98373_reg[] = { {MAX98373_R0040_SCP_INIT_STAT_1, 0x00}, {MAX98373_R0041_SCP_INIT_MASK_1, 0x00}, {MAX98373_R0042_SCP_INIT_STAT_2, 0x00}, diff --git a/sound/soc/codecs/max98388.c b/sound/soc/codecs/max98388.c index 99986090b4a6..076f15a9867e 100644 --- a/sound/soc/codecs/max98388.c +++ b/sound/soc/codecs/max98388.c @@ -18,7 +18,7 @@ #include #include "max98388.h" -static struct reg_default max98388_reg[] = { +static const struct reg_default max98388_reg[] = { {MAX98388_R2000_SW_RESET, 0x00}, {MAX98388_R2001_INT_RAW1, 0x00}, {MAX98388_R2002_INT_RAW2, 0x00}, diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c index 76296176f948..a8a282ff9fc5 100644 --- a/sound/soc/codecs/max98390.c +++ b/sound/soc/codecs/max98390.c @@ -23,7 +23,7 @@ #include "max98390.h" -static struct reg_default max98390_reg_defaults[] = { +static const struct reg_default max98390_reg_defaults[] = { {MAX98390_INT_EN1, 0xf0}, {MAX98390_INT_EN2, 0x00}, {MAX98390_INT_EN3, 0x00}, diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c index c1888cd83dbc..4b4e1fc98a6d 100644 --- a/sound/soc/codecs/max98396.c +++ b/sound/soc/codecs/max98396.c @@ -16,7 +16,7 @@ static const char * const max98396_core_supplies[MAX98396_NUM_CORE_SUPPLIES] = { "dvddio", }; -static struct reg_default max98396_reg[] = { +static const struct reg_default max98396_reg[] = { {MAX98396_R2000_SW_RESET, 0x00}, {MAX98396_R2001_INT_RAW1, 0x00}, {MAX98396_R2002_INT_RAW2, 0x00}, @@ -174,7 +174,7 @@ static struct reg_default max98396_reg[] = { {MAX98396_R21FF_REVISION_ID, 0x00}, }; -static struct reg_default max98397_reg[] = { +static const struct reg_default max98397_reg[] = { {MAX98396_R2000_SW_RESET, 0x00}, {MAX98396_R2001_INT_RAW1, 0x00}, {MAX98396_R2002_INT_RAW2, 0x00}, diff --git a/sound/soc/codecs/max98504.c b/sound/soc/codecs/max98504.c index 6b6a7ece4cec..c94142768c81 100644 --- a/sound/soc/codecs/max98504.c +++ b/sound/soc/codecs/max98504.c @@ -35,7 +35,7 @@ struct max98504_priv { unsigned int brownout_release_rate; }; -static struct reg_default max98504_reg_defaults[] = { +static const struct reg_default max98504_reg_defaults[] = { { 0x01, 0}, { 0x02, 0}, { 0x03, 0}, diff --git a/sound/soc/codecs/max98520.c b/sound/soc/codecs/max98520.c index adf5a898c6df..2bf8976c1828 100644 --- a/sound/soc/codecs/max98520.c +++ b/sound/soc/codecs/max98520.c @@ -16,7 +16,7 @@ #include #include "max98520.h" -static struct reg_default max98520_reg[] = { +static const struct reg_default max98520_reg[] = { {MAX98520_R2000_SW_RESET, 0x00}, {MAX98520_R2001_STATUS_1, 0x00}, {MAX98520_R2002_STATUS_2, 0x00}, diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index 55cc18451a2d..0e9b8970997c 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -19,7 +19,7 @@ #include #include "max98927.h" -static struct reg_default max98927_reg[] = { +static const struct reg_default max98927_reg[] = { {MAX98927_R0001_INT_RAW1, 0x00}, {MAX98927_R0002_INT_RAW2, 0x00}, {MAX98927_R0003_INT_RAW3, 0x00}, diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c index 609ca0d6c83a..70700bdb80a1 100644 --- a/sound/soc/codecs/rt722-sdca-sdw.c +++ b/sound/soc/codecs/rt722-sdca-sdw.c @@ -147,7 +147,7 @@ static int rt722_sdca_mbq_size(struct device *dev, unsigned int reg) } } -static struct regmap_sdw_mbq_cfg rt722_mbq_config = { +static const struct regmap_sdw_mbq_cfg rt722_mbq_config = { .mbq_size = rt722_sdca_mbq_size, }; diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index d9b61eab029a..342d1f7d5dee 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -275,7 +275,7 @@ static const struct regmap_irq wcd938x_irqs[WCD938X_NUM_IRQS] = { REGMAP_IRQ_REG(WCD938X_IRQ_HPHR_SURGE_DET_INT, 2, 0x08), }; -static struct regmap_irq_chip wcd938x_regmap_irq_chip = { +static const struct regmap_irq_chip wcd938x_regmap_irq_chip = { .name = "wcd938x", .irqs = wcd938x_irqs, .num_irqs = ARRAY_SIZE(wcd938x_irqs), diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index 6627d2da3722..d479521a6d50 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -202,7 +202,7 @@ SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, \ snd_soc_get_volsw, wsa881x_put_pa_gain, tlv_array) -static struct reg_default wsa881x_defaults[] = { +static const struct reg_default wsa881x_defaults[] = { { WSA881X_CHIP_ID0, 0x00 }, { WSA881X_CHIP_ID1, 0x00 }, { WSA881X_CHIP_ID2, 0x00 }, @@ -346,7 +346,7 @@ static const struct reg_sequence wsa881x_vi_txfe_en_2_0[] = { }; /* Default register reset values for WSA881x rev 2.0 */ -static struct reg_sequence wsa881x_rev_2_0[] = { +static const struct reg_sequence wsa881x_rev_2_0[] = { { WSA881X_RESET_CTL, 0x00, 0x00 }, { WSA881X_TADC_VALUE_CTL, 0x01, 0x00 }, { WSA881X_INTR_MASK, 0x1B, 0x00 }, diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index f04d99c66f33..13c9d4a6f015 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -572,7 +572,7 @@ static const struct sdw_port_config wsa883x_pconfig[WSA883X_MAX_SWR_PORTS] = { }, }; -static struct reg_default wsa883x_defaults[] = { +static const struct reg_default wsa883x_defaults[] = { { WSA883X_REF_CTRL, 0xD5 }, { WSA883X_TEST_CTL_0, 0x06 }, { WSA883X_BIAS_0, 0xD2 }, diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c index fd6ebc25fe89..07d8a2645404 100644 --- a/sound/soc/codecs/wsa884x.c +++ b/sound/soc/codecs/wsa884x.c @@ -899,7 +899,7 @@ static const struct sdw_port_config wsa884x_pconfig[WSA884X_MAX_SWR_PORTS] = { }, }; -static struct reg_default wsa884x_defaults[] = { +static const struct reg_default wsa884x_defaults[] = { { WSA884X_BG_CTRL, 0xa5 }, { WSA884X_ADC_CTRL, 0x00 }, { WSA884X_BOP1_PROG, 0x22 }, From 239dab898b739f49b1bda8d65163fe4f5c773468 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 28 May 2025 21:59:56 +0200 Subject: [PATCH 005/385] ASoC: fsl: Constify reg_default array Static 'struct reg_default' array is not modified so can be changed to const for more safety. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250528-asoc-const-unused-v1-2-19a5d07b9d5c@linaro.org Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 2 +- sound/soc/fsl/fsl_sai.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 677529916dc0..637260f306ec 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -930,7 +930,7 @@ static bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg) } } -static struct reg_default fsl_asrc_reg[] = { +static const struct reg_default fsl_asrc_reg[] = { { REG_ASRCTR, 0x0000 }, { REG_ASRIER, 0x0000 }, { REG_ASRCNCR, 0x0000 }, { REG_ASRCFG, 0x0000 }, { REG_ASRCSR, 0x0000 }, { REG_ASRCDR1, 0x0000 }, diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index af1a168d35e3..c84e3bb1290f 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -1059,7 +1059,7 @@ static const struct snd_soc_component_driver fsl_component = { .legacy_dai_naming = 1, }; -static struct reg_default fsl_sai_reg_defaults_ofs0[] = { +static const struct reg_default fsl_sai_reg_defaults_ofs0[] = { {FSL_SAI_TCR1(0), 0}, {FSL_SAI_TCR2(0), 0}, {FSL_SAI_TCR3(0), 0}, @@ -1082,7 +1082,7 @@ static struct reg_default fsl_sai_reg_defaults_ofs0[] = { {FSL_SAI_RMR, 0}, }; -static struct reg_default fsl_sai_reg_defaults_ofs8[] = { +static const struct reg_default fsl_sai_reg_defaults_ofs8[] = { {FSL_SAI_TCR1(8), 0}, {FSL_SAI_TCR2(8), 0}, {FSL_SAI_TCR3(8), 0}, From 620d9687004ce877b340041b8213da166f329367 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 28 May 2025 21:59:57 +0200 Subject: [PATCH 006/385] ASoC: codecs: wcd9335: Drop unused sido_input_src field Member wcd9335_codec.sido_input_src is not read anywhere after assignment, so it can be safely dropped. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20250528-asoc-const-unused-v1-3-19a5d07b9d5c@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 5e19e813748d..1c050b8c19de 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -312,7 +312,6 @@ struct wcd9335_codec { u32 num_rx_port; u32 num_tx_port; - int sido_input_src; enum wcd9335_sido_voltage sido_voltage; struct wcd_slim_codec_dai_data dai[NUM_CODEC_DAIS]; @@ -4725,8 +4724,6 @@ static const struct snd_soc_dapm_widget wcd9335_dapm_widgets[] = { static void wcd9335_enable_sido_buck(struct snd_soc_component *component) { - struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); - snd_soc_component_update_bits(component, WCD9335_ANA_RCO, WCD9335_ANA_RCO_BG_EN_MASK, WCD9335_ANA_RCO_BG_ENABLE); @@ -4740,7 +4737,6 @@ static void wcd9335_enable_sido_buck(struct snd_soc_component *component) WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_EXT); /* 100us sleep needed after VREF settings */ usleep_range(100, 110); - wcd->sido_input_src = SIDO_SOURCE_RCO_BG; } static int wcd9335_enable_efuse_sensing(struct snd_soc_component *comp) @@ -4871,7 +4867,6 @@ static int wcd9335_probe(struct wcd9335_codec *wcd) memcpy(wcd->rx_chs, wcd9335_rx_chs, sizeof(wcd9335_rx_chs)); memcpy(wcd->tx_chs, wcd9335_tx_chs, sizeof(wcd9335_tx_chs)); - wcd->sido_input_src = SIDO_SOURCE_INTERNAL; wcd->sido_voltage = SIDO_VOLTAGE_NOMINAL_MV; return devm_snd_soc_register_component(dev, &wcd9335_component_drv, From 9afc53569d800f5e3caf9401d49ad2d89f340a54 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 28 May 2025 21:59:58 +0200 Subject: [PATCH 007/385] ASoC: codecs: wcd934x: Drop unused num_rx_port/num_tx_port fields Members wcd934x_codec.num_rx_port and num_tx_port are not read anywhere after assignment, so they can be safely dropped. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20250528-asoc-const-unused-v1-4-19a5d07b9d5c@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd934x.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index fa69817c97ea..1bb7e1dc7e6b 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -537,8 +537,6 @@ struct wcd934x_codec { int rate; u32 version; u32 hph_mode; - int num_rx_port; - int num_tx_port; u32 tx_port_value[WCD934X_TX_MAX]; u32 rx_port_value[WCD934X_RX_MAX]; int sido_input_src; @@ -1928,13 +1926,11 @@ static int wcd934x_set_channel_map(struct snd_soc_dai *dai, return -EINVAL; } - wcd->num_rx_port = rx_num; for (i = 0; i < rx_num; i++) { wcd->rx_chs[i].ch_num = rx_slot[i]; INIT_LIST_HEAD(&wcd->rx_chs[i].list); } - wcd->num_tx_port = tx_num; for (i = 0; i < tx_num; i++) { wcd->tx_chs[i].ch_num = tx_slot[i]; INIT_LIST_HEAD(&wcd->tx_chs[i].list); From 87a2270fd1f560dbfc1b26391ff3b37f56d2a1a3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 28 May 2025 21:59:59 +0200 Subject: [PATCH 008/385] ASoC: codecs: wcd937x: Drop unused 'struct wcd937x_priv' fields 'wcd_regmap_irq_chip' and 'jack' in 'struct wcd937x_priv' are not used at all. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20250528-asoc-const-unused-v1-5-19a5d07b9d5c@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd937x.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index b9df58b86ce9..126a29e0b3ff 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -88,10 +88,8 @@ struct wcd937x_priv { struct wcd_mbhc_intr intr_ids; struct wcd_clsh_ctrl *clsh_info; struct irq_domain *virq; - struct regmap_irq_chip *wcd_regmap_irq_chip; struct regmap_irq_chip_data *irq_chip; struct regulator_bulk_data supplies[WCD937X_MAX_BULK_SUPPLY]; - struct snd_soc_jack *jack; unsigned long status_mask; s32 micb_ref[WCD937X_MAX_MICBIAS]; s32 pullup_ref[WCD937X_MAX_MICBIAS]; From fd32bd4467c13254cb52188034fce242f0f6340d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 28 May 2025 22:00:00 +0200 Subject: [PATCH 009/385] ASoC: codecs: wcd938x: Drop unused 'struct wcd938x_priv' fields 'wcd_regmap_irq_chip' and 'jack' in 'struct wcd938x_priv' are not used at all. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20250528-asoc-const-unused-v1-6-19a5d07b9d5c@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd938x.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index 342d1f7d5dee..43347c14070c 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -159,10 +159,8 @@ struct wcd938x_priv { struct wcd_mbhc_intr intr_ids; struct wcd_clsh_ctrl *clsh_info; struct irq_domain *virq; - struct regmap_irq_chip *wcd_regmap_irq_chip; struct regmap_irq_chip_data *irq_chip; struct regulator_bulk_data supplies[WCD938X_MAX_SUPPLY]; - struct snd_soc_jack *jack; unsigned long status_mask; s32 micb_ref[WCD938X_MAX_MICBIAS]; s32 pullup_ref[WCD938X_MAX_MICBIAS]; From ff228b6b9ed8f5d7ef418b6cbece772c6617d789 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 28 May 2025 22:00:01 +0200 Subject: [PATCH 010/385] ASoC: codecs: wcd938x: Drop unused variant field Member wcd938x_priv.variant is assigned in probe() function and used immediately thereafter, thus it can be just a local variable for less variables stored in 'struct wcd938x_priv' device-wide state. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20250528-asoc-const-unused-v1-7-19a5d07b9d5c@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd938x.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index 43347c14070c..5a751056a98a 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -168,7 +168,6 @@ struct wcd938x_priv { u32 tx_mode[TX_ADC_MAX]; int flyback_cur_det_disable; int ear_rx_path; - int variant; struct gpio_desc *reset_gpio; struct gpio_desc *us_euro_gpio; struct mux_control *us_euro_mux; @@ -3044,6 +3043,7 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component) struct sdw_slave *tx_sdw_dev = wcd938x->tx_sdw_dev; struct device *dev = component->dev; unsigned long time_left; + unsigned int variant; int ret, i; time_left = wait_for_completion_timeout(&tx_sdw_dev->initialization_complete, @@ -3059,9 +3059,9 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component) if (ret < 0) return ret; - wcd938x->variant = snd_soc_component_read_field(component, - WCD938X_DIGITAL_EFUSE_REG_0, - WCD938X_ID_MASK); + variant = snd_soc_component_read_field(component, + WCD938X_DIGITAL_EFUSE_REG_0, + WCD938X_ID_MASK); wcd938x->clsh_info = wcd_clsh_ctrl_alloc(component, WCD938X); if (IS_ERR(wcd938x->clsh_info)) { @@ -3115,14 +3115,14 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component) disable_irq_nosync(wcd938x->hphl_pdm_wd_int); disable_irq_nosync(wcd938x->aux_pdm_wd_int); - switch (wcd938x->variant) { + switch (variant) { case WCD9380: ret = snd_soc_add_component_controls(component, wcd9380_snd_controls, ARRAY_SIZE(wcd9380_snd_controls)); if (ret < 0) { dev_err(component->dev, "%s: Failed to add snd ctrls for variant: %d\n", - __func__, wcd938x->variant); + __func__, variant); goto err_free_aux_pdm_wd_int; } break; @@ -3132,7 +3132,7 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component) if (ret < 0) { dev_err(component->dev, "%s: Failed to add snd ctrls for variant: %d\n", - __func__, wcd938x->variant); + __func__, variant); goto err_free_aux_pdm_wd_int; } break; From ece5d881004f041c2e1493436409dbcbea3ad5f8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 28 May 2025 22:00:02 +0200 Subject: [PATCH 011/385] ASoC: codecs: wcd939x: Drop unused 'struct wcd939x_priv' fields 'wcd_regmap_irq_chip' and 'jack' in 'struct wcd939x_priv' are not used at all. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20250528-asoc-const-unused-v1-8-19a5d07b9d5c@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd939x.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index 067d23c7ecf9..bfd4d2c8bdc9 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -190,10 +190,8 @@ struct wcd939x_priv { struct wcd_mbhc_intr intr_ids; struct wcd_clsh_ctrl *clsh_info; struct irq_domain *virq; - struct regmap_irq_chip *wcd_regmap_irq_chip; struct regmap_irq_chip_data *irq_chip; struct regulator_bulk_data supplies[WCD939X_MAX_SUPPLY]; - struct snd_soc_jack *jack; unsigned long status_mask; s32 micb_ref[WCD939X_MAX_MICBIAS]; s32 pullup_ref[WCD939X_MAX_MICBIAS]; From 077caf1d1763e069239101b4a72351fb38d37f13 Mon Sep 17 00:00:00 2001 From: Ai Chao Date: Tue, 3 Jun 2025 13:51:07 +0800 Subject: [PATCH 012/385] ASoC: renesas: Use helper function for_each_child_of_node_scoped() The for_each_child_of_node_scoped() helper provides a scope-based clean-up functionality to put the device_node automatically, and as such, there is no need to call of_node_put() directly. Acked-by: Kuninori Morimoto Signed-off-by: Ai Chao Link: https://patch.msgid.link/20250603055109.3154061-3-aichao@kylinos.cn Signed-off-by: Mark Brown --- sound/soc/renesas/rcar/core.c | 35 +++++++++++------------------------ sound/soc/renesas/rcar/ctu.c | 8 ++------ sound/soc/renesas/rcar/dma.c | 4 +--- sound/soc/renesas/rcar/dvc.c | 8 ++------ sound/soc/renesas/rcar/mix.c | 8 ++------ sound/soc/renesas/rcar/src.c | 10 ++-------- sound/soc/renesas/rcar/ssi.c | 18 +++++------------- sound/soc/renesas/rcar/ssiu.c | 7 ++----- 8 files changed, 27 insertions(+), 71 deletions(-) diff --git a/sound/soc/renesas/rcar/core.c b/sound/soc/renesas/rcar/core.c index a72f36d3ca2c..37d954495ea5 100644 --- a/sound/soc/renesas/rcar/core.c +++ b/sound/soc/renesas/rcar/core.c @@ -1075,7 +1075,6 @@ static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, { struct device *dev = rsnd_priv_to_dev(priv); struct device_node *ssiu_np = rsnd_ssiu_of_node(priv); - struct device_node *np; int is_play = rsnd_io_is_play(io); int i; @@ -1094,7 +1093,7 @@ static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, if (!node) break; - for_each_child_of_node(ssiu_np, np) { + for_each_child_of_node_scoped(ssiu_np, np) { if (np == node) { rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT); dev_dbg(dev, "%s is part of TDM Split\n", io->name); @@ -1154,21 +1153,18 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name, { struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *np; int i; if (!node) return; i = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { struct rsnd_mod *mod; i = rsnd_node_fixed_index(dev, np, name, i); - if (i < 0) { - of_node_put(np); + if (i < 0) break; - } mod = mod_get(priv, i); @@ -1217,16 +1213,13 @@ int rsnd_node_fixed_index(struct device *dev, struct device_node *node, char *na int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name) { struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *np; int i; i = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { i = rsnd_node_fixed_index(dev, np, name, i); - if (i < 0) { - of_node_put(np); + if (i < 0) return 0; - } i++; } @@ -1250,7 +1243,7 @@ static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph) { struct device *dev = rsnd_priv_to_dev(priv); struct device_node *np = dev->of_node; - struct device_node *ports, *node; + struct device_node *node; int nr = 0; int i = 0; @@ -1270,7 +1263,7 @@ static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph) of_node_put(node); - for_each_child_of_node(np, node) { + for_each_child_of_node_scoped(np, node) { if (!of_node_name_eq(node, RSND_NODE_DAI)) continue; @@ -1279,7 +1272,6 @@ static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph) i++; if (i >= RSND_MAX_COMPONENT) { dev_info(dev, "reach to max component\n"); - of_node_put(node); break; } } @@ -1290,7 +1282,7 @@ audio_graph: /* * Audio-Graph-Card */ - for_each_child_of_node(np, ports) { + for_each_child_of_node_scoped(np, ports) { node = rsnd_pick_endpoint_node_for_ports(ports, np); if (!node) continue; @@ -1299,7 +1291,6 @@ audio_graph: i++; if (i >= RSND_MAX_COMPONENT) { dev_info(dev, "reach to max component\n"); - of_node_put(ports); break; } } @@ -1505,10 +1496,9 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) dai_i = 0; if (is_graph) { struct device_node *dai_np_port; - struct device_node *ports; struct device_node *dai_np; - for_each_child_of_node(np, ports) { + for_each_child_of_node_scoped(np, ports) { dai_np_port = rsnd_pick_endpoint_node_for_ports(ports, np); if (!dai_np_port) continue; @@ -1525,14 +1515,11 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) } } } else { - struct device_node *node; - struct device_node *dai_np; - - for_each_child_of_node(np, node) { + for_each_child_of_node_scoped(np, node) { if (!of_node_name_eq(node, RSND_NODE_DAI)) continue; - for_each_child_of_node(node, dai_np) { + for_each_child_of_node_scoped(node, dai_np) { __rsnd_dai_probe(priv, dai_np, np, dai_i, dai_i); if (!rsnd_is_gen1(priv) && !rsnd_is_gen2(priv)) { rdai = rsnd_rdai_get(priv, dai_i); diff --git a/sound/soc/renesas/rcar/ctu.c b/sound/soc/renesas/rcar/ctu.c index a26ec7b780cd..bd4c61f9fb3c 100644 --- a/sound/soc/renesas/rcar/ctu.c +++ b/sound/soc/renesas/rcar/ctu.c @@ -316,7 +316,6 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) int rsnd_ctu_probe(struct rsnd_priv *priv) { struct device_node *node; - struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_ctu *ctu; struct clk *clk; @@ -344,7 +343,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv) i = 0; ret = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { ctu = rsnd_ctu_get(priv, i); /* @@ -357,16 +356,13 @@ int rsnd_ctu_probe(struct rsnd_priv *priv) clk = devm_clk_get(dev, name); if (IS_ERR(clk)) { ret = PTR_ERR(clk); - of_node_put(np); goto rsnd_ctu_probe_done; } ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops, clk, RSND_MOD_CTU, i); - if (ret) { - of_node_put(np); + if (ret) goto rsnd_ctu_probe_done; - } i++; } diff --git a/sound/soc/renesas/rcar/dma.c b/sound/soc/renesas/rcar/dma.c index 2342bbb6fe92..2035ce06fe4c 100644 --- a/sound/soc/renesas/rcar/dma.c +++ b/sound/soc/renesas/rcar/dma.c @@ -194,14 +194,12 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *nam struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct device *dev = rsnd_priv_to_dev(priv); struct dma_chan *chan = NULL; - struct device_node *np; int i = 0; - for_each_child_of_node(of_node, np) { + for_each_child_of_node_scoped(of_node, np) { i = rsnd_node_fixed_index(dev, np, name, i); if (i < 0) { chan = NULL; - of_node_put(np); break; } diff --git a/sound/soc/renesas/rcar/dvc.c b/sound/soc/renesas/rcar/dvc.c index da91dd301aab..988cbddbc611 100644 --- a/sound/soc/renesas/rcar/dvc.c +++ b/sound/soc/renesas/rcar/dvc.c @@ -324,7 +324,6 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) int rsnd_dvc_probe(struct rsnd_priv *priv) { struct device_node *node; - struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_dvc *dvc; struct clk *clk; @@ -352,7 +351,7 @@ int rsnd_dvc_probe(struct rsnd_priv *priv) i = 0; ret = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { dvc = rsnd_dvc_get(priv, i); snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d", @@ -361,16 +360,13 @@ int rsnd_dvc_probe(struct rsnd_priv *priv) clk = devm_clk_get(dev, name); if (IS_ERR(clk)) { ret = PTR_ERR(clk); - of_node_put(np); goto rsnd_dvc_probe_done; } ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops, clk, RSND_MOD_DVC, i); - if (ret) { - of_node_put(np); + if (ret) goto rsnd_dvc_probe_done; - } i++; } diff --git a/sound/soc/renesas/rcar/mix.c b/sound/soc/renesas/rcar/mix.c index 024d91cc8748..aea74e703305 100644 --- a/sound/soc/renesas/rcar/mix.c +++ b/sound/soc/renesas/rcar/mix.c @@ -288,7 +288,6 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) int rsnd_mix_probe(struct rsnd_priv *priv) { struct device_node *node; - struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mix *mix; struct clk *clk; @@ -316,7 +315,7 @@ int rsnd_mix_probe(struct rsnd_priv *priv) i = 0; ret = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { mix = rsnd_mix_get(priv, i); snprintf(name, MIX_NAME_SIZE, "%s.%d", @@ -325,16 +324,13 @@ int rsnd_mix_probe(struct rsnd_priv *priv) clk = devm_clk_get(dev, name); if (IS_ERR(clk)) { ret = PTR_ERR(clk); - of_node_put(np); goto rsnd_mix_probe_done; } ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops, clk, RSND_MOD_MIX, i); - if (ret) { - of_node_put(np); + if (ret) goto rsnd_mix_probe_done; - } i++; } diff --git a/sound/soc/renesas/rcar/src.c b/sound/soc/renesas/rcar/src.c index 7d73b183bda6..f47bf38c2f94 100644 --- a/sound/soc/renesas/rcar/src.c +++ b/sound/soc/renesas/rcar/src.c @@ -715,7 +715,6 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) int rsnd_src_probe(struct rsnd_priv *priv) { struct device_node *node; - struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_src *src; struct clk *clk; @@ -742,14 +741,13 @@ int rsnd_src_probe(struct rsnd_priv *priv) priv->src = src; i = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { if (!of_device_is_available(np)) goto skip; i = rsnd_node_fixed_index(dev, np, SRC_NAME, i); if (i < 0) { ret = -EINVAL; - of_node_put(np); goto rsnd_src_probe_done; } @@ -761,23 +759,19 @@ int rsnd_src_probe(struct rsnd_priv *priv) src->irq = irq_of_parse_and_map(np, 0); if (!src->irq) { ret = -EINVAL; - of_node_put(np); goto rsnd_src_probe_done; } clk = devm_clk_get(dev, name); if (IS_ERR(clk)) { ret = PTR_ERR(clk); - of_node_put(np); goto rsnd_src_probe_done; } ret = rsnd_mod_init(priv, rsnd_mod_get(src), &rsnd_src_ops, clk, RSND_MOD_SRC, i); - if (ret) { - of_node_put(np); + if (ret) goto rsnd_src_probe_done; - } skip: i++; diff --git a/sound/soc/renesas/rcar/ssi.c b/sound/soc/renesas/rcar/ssi.c index 0c6424a1fcac..d52056caa3ec 100644 --- a/sound/soc/renesas/rcar/ssi.c +++ b/sound/soc/renesas/rcar/ssi.c @@ -1115,7 +1115,6 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct device *dev = rsnd_priv_to_dev(priv); struct device_node *node; - struct device_node *np; int i; node = rsnd_ssi_of_node(priv); @@ -1123,14 +1122,12 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, return; i = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { struct rsnd_mod *mod; i = rsnd_node_fixed_index(dev, np, SSI_NAME, i); - if (i < 0) { - of_node_put(np); + if (i < 0) break; - } mod = rsnd_ssi_mod_get(priv, i); @@ -1163,7 +1160,6 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) int rsnd_ssi_probe(struct rsnd_priv *priv) { struct device_node *node; - struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mod_ops *ops; struct clk *clk; @@ -1191,14 +1187,13 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) priv->ssi_nr = nr; i = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { if (!of_device_is_available(np)) goto skip; i = rsnd_node_fixed_index(dev, np, SSI_NAME, i); if (i < 0) { ret = -EINVAL; - of_node_put(np); goto rsnd_ssi_probe_done; } @@ -1210,7 +1205,6 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) clk = devm_clk_get(dev, name); if (IS_ERR(clk)) { ret = PTR_ERR(clk); - of_node_put(np); goto rsnd_ssi_probe_done; } @@ -1223,7 +1217,6 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) ssi->irq = irq_of_parse_and_map(np, 0); if (!ssi->irq) { ret = -EINVAL; - of_node_put(np); goto rsnd_ssi_probe_done; } @@ -1234,10 +1227,9 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk, RSND_MOD_SSI, i); - if (ret) { - of_node_put(np); + if (ret) goto rsnd_ssi_probe_done; - } + skip: i++; } diff --git a/sound/soc/renesas/rcar/ssiu.c b/sound/soc/renesas/rcar/ssiu.c index 665e8b2db579..faf351126d57 100644 --- a/sound/soc/renesas/rcar/ssiu.c +++ b/sound/soc/renesas/rcar/ssiu.c @@ -478,17 +478,14 @@ void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai, /* use rcar_sound,ssiu if exist */ if (node) { - struct device_node *np; int i = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { struct rsnd_mod *mod; i = rsnd_node_fixed_index(dev, np, SSIU_NAME, i); - if (i < 0) { - of_node_put(np); + if (i < 0) break; - } mod = rsnd_ssiu_mod_get(priv, i); From 618abc785e0cbe9993f7217c9f8ecb1cd2478e4f Mon Sep 17 00:00:00 2001 From: Ai Chao Date: Tue, 3 Jun 2025 13:51:08 +0800 Subject: [PATCH 013/385] ASoC: meson: Use helper function for_each_child_of_node_scoped() The for_each_child_of_node_scoped() helper provides a scope-based clean-up functionality to put the device_node automatically, and as such, there is no need to call of_node_put() directly. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202505210557.EpJig9BQ-lkp@intel.com/ Signed-off-by: Ai Chao Link: https://patch.msgid.link/20250603055109.3154061-4-aichao@kylinos.cn Signed-off-by: Mark Brown --- sound/soc/meson/axg-card.c | 3 +-- sound/soc/meson/meson-card-utils.c | 16 +++++----------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index a2dfccb7990f..b4dca80e15e4 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -222,7 +222,6 @@ static int axg_card_parse_codecs_masks(struct snd_soc_card *card, struct axg_dai_link_tdm_data *be) { struct axg_dai_link_tdm_mask *codec_mask; - struct device_node *np; codec_mask = devm_kcalloc(card->dev, link->num_codecs, sizeof(*codec_mask), GFP_KERNEL); @@ -231,7 +230,7 @@ static int axg_card_parse_codecs_masks(struct snd_soc_card *card, be->codec_masks = codec_mask; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", &codec_mask->rx); snd_soc_of_get_slot_mask(np, "dai-tdm-slot-tx-mask", diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c index 68531183fb60..cdb759b466ad 100644 --- a/sound/soc/meson/meson-card-utils.c +++ b/sound/soc/meson/meson-card-utils.c @@ -137,7 +137,6 @@ int meson_card_set_be_link(struct snd_soc_card *card, struct device_node *node) { struct snd_soc_dai_link_component *codec; - struct device_node *np; int ret, num_codecs; num_codecs = of_get_child_count(node); @@ -154,19 +153,17 @@ int meson_card_set_be_link(struct snd_soc_card *card, link->codecs = codec; link->num_codecs = num_codecs; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { ret = meson_card_parse_dai(card, np, codec); - if (ret) { - of_node_put(np); + if (ret) return ret; - } codec++; } ret = meson_card_set_link_name(card, link, node, "be"); if (ret) - dev_err(card->dev, "error setting %pOFn link name\n", np); + dev_err(card->dev, "error setting %pOFn link name\n", node); return ret; } @@ -198,7 +195,6 @@ static int meson_card_add_links(struct snd_soc_card *card) { struct meson_card *priv = snd_soc_card_get_drvdata(card); struct device_node *node = card->dev->of_node; - struct device_node *np; int num, i, ret; num = of_get_child_count(node); @@ -212,12 +208,10 @@ static int meson_card_add_links(struct snd_soc_card *card) return ret; i = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { ret = priv->match_data->add_link(card, np, &i); - if (ret) { - of_node_put(np); + if (ret) return ret; - } i++; } From 111a2c8ab462d77d1519b71b46f13ae1b46920b4 Mon Sep 17 00:00:00 2001 From: Ai Chao Date: Tue, 3 Jun 2025 13:51:09 +0800 Subject: [PATCH 014/385] ASoC: imx-card: Use helper function for_each_child_of_node_scoped() The for_each_child_of_node_scoped() helper provides a scope-based clean-up functionality to put the device_node automatically, and as such, there is no need to call of_node_put() directly. Signed-off-by: Ai Chao Link: https://patch.msgid.link/20250603055109.3154061-5-aichao@kylinos.cn Signed-off-by: Mark Brown --- sound/soc/fsl/imx-card.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c index 9e668ae68039..ea5dbb54b584 100644 --- a/sound/soc/fsl/imx-card.c +++ b/sound/soc/fsl/imx-card.c @@ -513,7 +513,6 @@ static int imx_card_parse_of(struct imx_card_data *data) struct device_node *platform = NULL; struct device_node *codec = NULL; struct device_node *cpu = NULL; - struct device_node *np; struct device *dev = card->dev; struct snd_soc_dai_link *link; struct dai_link_data *link_data; @@ -552,11 +551,10 @@ static int imx_card_parse_of(struct imx_card_data *data) link = card->dai_link; link_data = data->link_data; - for_each_child_of_node(dev->of_node, np) { + for_each_child_of_node_scoped(dev->of_node, np) { dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL); if (!dlc) { - ret = -ENOMEM; - goto err_put_np; + return -ENOMEM; } link->cpus = &dlc[0]; @@ -567,8 +565,8 @@ static int imx_card_parse_of(struct imx_card_data *data) ret = of_property_read_string(np, "link-name", &link->name); if (ret) { - dev_err(card->dev, "error getting codec dai_link name\n"); - goto err_put_np; + return dev_err_probe(card->dev, ret, + "error getting codec dai_link name\n"); } cpu = of_get_child_by_name(np, "cpu"); @@ -725,8 +723,7 @@ err: of_node_put(cpu); of_node_put(codec); of_node_put(platform); -err_put_np: - of_node_put(np); + return ret; } From 8167f4f42572818fa8153be2b03e4c2120846603 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 4 Jun 2025 02:06:48 +0000 Subject: [PATCH 015/385] ASoC: qcom: use drvdata instead of component to keep id Qcom lpass is using component->id to keep DAI ID (A). (S) static int lpass_platform_pcmops_open( sruct snd_soc_component *component, struct snd_pcm_substream *substream) { ^^^^^^^^^(B0) ... (B1) struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream); (B2) struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); ... (B3) unsigned int dai_id = cpu_dai->driver->id; (A) component->id = dai_id; ... } This driver can get dai_id from substream (B0 - B3). In this driver, below functions get dai_id from component->id (A). (X) lpass_platform_pcmops_suspend() (Y) lpass_platform_pcmops_resume() (Z) lpass_platform_copy() Here, (Z) can get it from substream (B0 - B3), don't need to use component->id (A). On suspend/resume (X)(Y), dai_id can only be obtained from component->id (A), because there is no substream (B0) in function parameter. But, component->id (A) itself should not be used for such purpose. It is intilialized at snd_soc_component_initialize(), and parsed its ID (= component->id) from device name (a). int snd_soc_component_initialize(...) { ... if (!component->name) { (a) component->name = fmt_single_name(dev, &component->id); ... ^^^^^^^^^^^^^ } ... } Unfortunately, current code is broken to start with. There are many regmaps that the driver cares about, however its only managing one (either dp or i2s) in component suspend/resume path. I2S regmap is mandatory however other regmaps are setup based on flags like "hdmi_port_enable" and "codec_dma_enable". Correct thing for suspend/resume path to handle is by checking these flags, instead of using component->id. Signed-off-by: Srinivas Kandagatla Suggested-by: Kuninori Morimoto Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87a56ouuob.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-platform.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 9946f12254b3..b456e096f138 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -202,7 +202,6 @@ static int lpass_platform_pcmops_open(struct snd_soc_component *component, struct regmap *map; unsigned int dai_id = cpu_dai->driver->id; - component->id = dai_id; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -1190,13 +1189,14 @@ static int lpass_platform_pcmops_suspend(struct snd_soc_component *component) { struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); struct regmap *map; - unsigned int dai_id = component->id; - if (dai_id == LPASS_DP_RX) + if (drvdata->hdmi_port_enable) { map = drvdata->hdmiif_map; - else - map = drvdata->lpaif_map; + regcache_cache_only(map, true); + regcache_mark_dirty(map); + } + map = drvdata->lpaif_map; regcache_cache_only(map, true); regcache_mark_dirty(map); @@ -1207,14 +1207,19 @@ static int lpass_platform_pcmops_resume(struct snd_soc_component *component) { struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); struct regmap *map; - unsigned int dai_id = component->id; + int ret; - if (dai_id == LPASS_DP_RX) + if (drvdata->hdmi_port_enable) { map = drvdata->hdmiif_map; - else - map = drvdata->lpaif_map; + regcache_cache_only(map, false); + ret = regcache_sync(map); + if (ret) + return ret; + } + map = drvdata->lpaif_map; regcache_cache_only(map, false); + return regcache_sync(map); } @@ -1224,7 +1229,9 @@ static int lpass_platform_copy(struct snd_soc_component *component, unsigned long bytes) { struct snd_pcm_runtime *rt = substream->runtime; - unsigned int dai_id = component->id; + struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); + unsigned int dai_id = cpu_dai->driver->id; int ret = 0; void __iomem *dma_buf = (void __iomem *) (rt->dma_area + pos + From 6ada7351af0c4e295739adfa2c4b780c037b3d27 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Jun 2025 02:06:57 +0000 Subject: [PATCH 016/385] ASoC: soc-core: save ID if param was set in fmt_single_name() fmt_single_name() requests "ind *id" and not allow NULL for it. But sometimes we don't need it. Allow NULL. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/878qm8uunz.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 67bebc339148..ecea2dddbe9a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2604,6 +2604,7 @@ static char *fmt_single_name(struct device *dev, int *id) const char *devname = dev_name(dev); char *found, *name; unsigned int id1, id2; + int __id; if (devname == NULL) return NULL; @@ -2616,10 +2617,10 @@ static char *fmt_single_name(struct device *dev, int *id) found = strstr(name, dev->driver->name); if (found) { /* get ID */ - if (sscanf(&found[strlen(dev->driver->name)], ".%d", id) == 1) { + if (sscanf(&found[strlen(dev->driver->name)], ".%d", &__id) == 1) { /* discard ID from name if ID == -1 */ - if (*id == -1) + if (__id == -1) found[strlen(dev->driver->name)] = '\0'; } @@ -2627,16 +2628,19 @@ static char *fmt_single_name(struct device *dev, int *id) } else if (sscanf(name, "%x-%x", &id1, &id2) == 2) { /* create unique ID number from I2C addr and bus */ - *id = ((id1 & 0xffff) << 16) + id2; + __id = ((id1 & 0xffff) << 16) + id2; devm_kfree(dev, name); /* sanitize component name for DAI link creation */ name = devm_kasprintf(dev, GFP_KERNEL, "%s.%s", dev->driver->name, devname); } else { - *id = 0; + __id = 0; } + if (id) + *id = __id; + return name; } From 267be32b0a7b70cc777f8a46f0904c92c0521d89 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Jun 2025 02:07:22 +0000 Subject: [PATCH 017/385] ASoC: remove component->id No one is using component->id. One idea is we can re-use it as serial number for component. But we have no usage, so far. Let's just remove it for now. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/877c1suuna.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 1 - sound/soc/soc-core.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 61534ac0edd1..2caa807c6249 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -206,7 +206,6 @@ struct snd_soc_component_driver { struct snd_soc_component { const char *name; - int id; const char *name_prefix; struct device *dev; struct snd_soc_card *card; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ecea2dddbe9a..cfafdabcdc88 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2835,7 +2835,7 @@ int snd_soc_component_initialize(struct snd_soc_component *component, mutex_init(&component->io_mutex); if (!component->name) { - component->name = fmt_single_name(dev, &component->id); + component->name = fmt_single_name(dev, NULL); if (!component->name) { dev_err(dev, "ASoC: Failed to allocate name\n"); return -ENOMEM; From 10cf8f6be63f2acfd3d366d917f1af6625cd9124 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 26 May 2025 12:49:50 +0200 Subject: [PATCH 018/385] ASoC: codecs: wcd937x: Simplify with devm_regulator_bulk_get_enable() Drop separate regulator get and enable in probe() path with devm_regulator_bulk_get_enable(), which simplifies cleanup paths and device remove(). Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250526-b4-asoc-wcd9395-vdd-px-v1-1-64d3cb60313b@linaro.org Reviewed-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/codecs/wcd937x.c | 31 +++++++++---------------------- sound/soc/codecs/wcd937x.h | 1 - 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index b9df58b86ce9..92765a8693fb 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -90,7 +90,6 @@ struct wcd937x_priv { struct irq_domain *virq; struct regmap_irq_chip *wcd_regmap_irq_chip; struct regmap_irq_chip_data *irq_chip; - struct regulator_bulk_data supplies[WCD937X_MAX_BULK_SUPPLY]; struct snd_soc_jack *jack; unsigned long status_mask; s32 micb_ref[WCD937X_MAX_MICBIAS]; @@ -113,6 +112,10 @@ struct wcd937x_priv { atomic_t ana_clk_count; }; +static const char * const wcd937x_supplies[] = { + "vdd-rxtx", "vdd-px", "vdd-mic-bias", "vdd-buck", +}; + static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800); static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); @@ -2934,18 +2937,10 @@ static int wcd937x_probe(struct platform_device *pdev) cfg = &wcd937x->mbhc_cfg; cfg->swap_gnd_mic = wcd937x_swap_gnd_mic; - wcd937x->supplies[0].supply = "vdd-rxtx"; - wcd937x->supplies[1].supply = "vdd-px"; - wcd937x->supplies[2].supply = "vdd-mic-bias"; - wcd937x->supplies[3].supply = "vdd-buck"; - - ret = devm_regulator_bulk_get(dev, WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(wcd937x_supplies), + wcd937x_supplies); if (ret) - return dev_err_probe(dev, ret, "Failed to get supplies\n"); - - ret = regulator_bulk_enable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); - if (ret) - return dev_err_probe(dev, ret, "Failed to enable supplies\n"); + return dev_err_probe(dev, ret, "Failed to get and enable supplies\n"); wcd937x_dt_parse_micbias_info(dev, wcd937x); @@ -2962,13 +2957,13 @@ static int wcd937x_probe(struct platform_device *pdev) ret = wcd937x_add_slave_components(wcd937x, dev, &match); if (ret) - goto err_disable_regulators; + return ret; wcd937x_reset(wcd937x); ret = component_master_add_with_match(dev, &wcd937x_comp_ops, match); if (ret) - goto err_disable_regulators; + return ret; pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); @@ -2978,25 +2973,17 @@ static int wcd937x_probe(struct platform_device *pdev) pm_runtime_idle(dev); return 0; - -err_disable_regulators: - regulator_bulk_disable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); - - return ret; } static void wcd937x_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct wcd937x_priv *wcd937x = dev_get_drvdata(dev); component_master_del(&pdev->dev, &wcd937x_comp_ops); pm_runtime_disable(dev); pm_runtime_set_suspended(dev); pm_runtime_dont_use_autosuspend(dev); - - regulator_bulk_disable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); } #if defined(CONFIG_OF) diff --git a/sound/soc/codecs/wcd937x.h b/sound/soc/codecs/wcd937x.h index 4ef57c496c37..3ab21bb5846e 100644 --- a/sound/soc/codecs/wcd937x.h +++ b/sound/soc/codecs/wcd937x.h @@ -487,7 +487,6 @@ #define WCD937X_MAX_REGISTER (WCD937X_DIGITAL_EFUSE_REG_31) #define WCD937X_MAX_MICBIAS 3 -#define WCD937X_MAX_BULK_SUPPLY 4 #define WCD937X_MAX_SWR_CH_IDS 15 #define WCD937X_SWRM_CH_MASK(ch_idx) BIT(ch_idx - 1) From a7ee107c2dc382d28794d7b254d0b4de2a75dff2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 26 May 2025 12:49:51 +0200 Subject: [PATCH 019/385] ASoC: codecs: wcd938x: Simplify with devm_regulator_bulk_get_enable() Drop separate regulator get and enable in probe() path with devm_regulator_bulk_get_enable(), which simplifies cleanup paths and device remove(). Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250526-b4-asoc-wcd9395-vdd-px-v1-2-64d3cb60313b@linaro.org Reviewed-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/codecs/wcd938x.c | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index d9b61eab029a..9bee50d37619 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -26,7 +26,6 @@ #include "wcd938x.h" #define WCD938X_MAX_MICBIAS (4) -#define WCD938X_MAX_SUPPLY (4) #define WCD938X_MBHC_MAX_BUTTONS (8) #define TX_ADC_MAX (4) @@ -161,7 +160,6 @@ struct wcd938x_priv { struct irq_domain *virq; struct regmap_irq_chip *wcd_regmap_irq_chip; struct regmap_irq_chip_data *irq_chip; - struct regulator_bulk_data supplies[WCD938X_MAX_SUPPLY]; struct snd_soc_jack *jack; unsigned long status_mask; s32 micb_ref[WCD938X_MAX_MICBIAS]; @@ -188,6 +186,10 @@ struct wcd938x_priv { bool mux_setup_done; }; +static const char * const wcd938x_supplies[] = { + "vdd-rxtx", "vdd-io", "vdd-buck", "vdd-mic-bias", +}; + static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800); static const DECLARE_TLV_DB_SCALE(line_gain, -3000, 150, 0); static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(analog_gain, 0, 3000); @@ -3292,20 +3294,10 @@ static int wcd938x_populate_dt_data(struct wcd938x_priv *wcd938x, struct device cfg->swap_gnd_mic = wcd938x_swap_gnd_mic; - wcd938x->supplies[0].supply = "vdd-rxtx"; - wcd938x->supplies[1].supply = "vdd-io"; - wcd938x->supplies[2].supply = "vdd-buck"; - wcd938x->supplies[3].supply = "vdd-mic-bias"; - - ret = regulator_bulk_get(dev, WCD938X_MAX_SUPPLY, wcd938x->supplies); + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(wcd938x_supplies), + wcd938x_supplies); if (ret) - return dev_err_probe(dev, ret, "Failed to get supplies\n"); - - ret = regulator_bulk_enable(WCD938X_MAX_SUPPLY, wcd938x->supplies); - if (ret) { - regulator_bulk_free(WCD938X_MAX_SUPPLY, wcd938x->supplies); - return dev_err_probe(dev, ret, "Failed to enable supplies\n"); - } + return dev_err_probe(dev, ret, "Failed to get and enable supplies\n"); wcd938x_dt_parse_micbias_info(dev, wcd938x); @@ -3569,13 +3561,13 @@ static int wcd938x_probe(struct platform_device *pdev) ret = wcd938x_add_slave_components(wcd938x, dev, &match); if (ret) - goto err_disable_regulators; + return ret; wcd938x_reset(wcd938x); ret = component_master_add_with_match(dev, &wcd938x_comp_ops, match); if (ret) - goto err_disable_regulators; + return ret; pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); @@ -3585,12 +3577,6 @@ static int wcd938x_probe(struct platform_device *pdev) pm_runtime_idle(dev); return 0; - -err_disable_regulators: - regulator_bulk_disable(WCD938X_MAX_SUPPLY, wcd938x->supplies); - regulator_bulk_free(WCD938X_MAX_SUPPLY, wcd938x->supplies); - - return ret; } static void wcd938x_remove(struct platform_device *pdev) @@ -3606,9 +3592,6 @@ static void wcd938x_remove(struct platform_device *pdev) if (wcd938x->us_euro_mux && wcd938x->mux_setup_done) mux_control_deselect(wcd938x->us_euro_mux); - - regulator_bulk_disable(WCD938X_MAX_SUPPLY, wcd938x->supplies); - regulator_bulk_free(WCD938X_MAX_SUPPLY, wcd938x->supplies); } #if defined(CONFIG_OF) From cc50d176d0d8b38df2ae119310970f793cb5e756 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 26 May 2025 12:49:52 +0200 Subject: [PATCH 020/385] ASoC: codecs: wcd939x: Simplify with devm_regulator_bulk_get_enable() Drop separate regulator get and enable in probe() path with devm_regulator_bulk_get_enable(), which simplifies cleanup paths and device remove(). Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250526-b4-asoc-wcd9395-vdd-px-v1-3-64d3cb60313b@linaro.org Reviewed-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/codecs/wcd939x.c | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index 067d23c7ecf9..95cd88a37acb 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -32,7 +32,6 @@ #include "wcd939x.h" #define WCD939X_MAX_MICBIAS (4) -#define WCD939X_MAX_SUPPLY (4) #define WCD939X_MBHC_MAX_BUTTONS (8) #define TX_ADC_MAX (4) #define WCD_MBHC_HS_V_MAX 1600 @@ -192,7 +191,6 @@ struct wcd939x_priv { struct irq_domain *virq; struct regmap_irq_chip *wcd_regmap_irq_chip; struct regmap_irq_chip_data *irq_chip; - struct regulator_bulk_data supplies[WCD939X_MAX_SUPPLY]; struct snd_soc_jack *jack; unsigned long status_mask; s32 micb_ref[WCD939X_MAX_MICBIAS]; @@ -213,6 +211,10 @@ struct wcd939x_priv { bool ldoh; }; +static const char * const wcd939x_supplies[] = { + "vdd-rxtx", "vdd-io", "vdd-buck", "vdd-mic-bias", +}; + static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800); static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); @@ -3244,20 +3246,10 @@ static int wcd939x_populate_dt_data(struct wcd939x_priv *wcd939x, struct device return dev_err_probe(dev, ret, "Failed to get reset gpio\n"); } - wcd939x->supplies[0].supply = "vdd-rxtx"; - wcd939x->supplies[1].supply = "vdd-io"; - wcd939x->supplies[2].supply = "vdd-buck"; - wcd939x->supplies[3].supply = "vdd-mic-bias"; - - ret = regulator_bulk_get(dev, WCD939X_MAX_SUPPLY, wcd939x->supplies); + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(wcd939x_supplies), + wcd939x_supplies); if (ret) - return dev_err_probe(dev, ret, "Failed to get supplies\n"); - - ret = regulator_bulk_enable(WCD939X_MAX_SUPPLY, wcd939x->supplies); - if (ret) { - regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies); - return dev_err_probe(dev, ret, "Failed to enable supplies\n"); - } + return dev_err_probe(dev, ret, "Failed to get and enable supplies\n"); wcd939x_dt_parse_micbias_info(dev, wcd939x); @@ -3629,17 +3621,17 @@ static int wcd939x_probe(struct platform_device *pdev) ret = wcd939x_add_typec(wcd939x, dev); if (ret) - goto err_disable_regulators; + return ret; ret = wcd939x_add_slave_components(wcd939x, dev, &match); if (ret) - goto err_disable_regulators; + return ret; wcd939x_reset(wcd939x); ret = component_master_add_with_match(dev, &wcd939x_comp_ops, match); if (ret) - goto err_disable_regulators; + return ret; pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); @@ -3649,27 +3641,17 @@ static int wcd939x_probe(struct platform_device *pdev) pm_runtime_idle(dev); return 0; - -err_disable_regulators: - regulator_bulk_disable(WCD939X_MAX_SUPPLY, wcd939x->supplies); - regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies); - - return ret; } static void wcd939x_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct wcd939x_priv *wcd939x = dev_get_drvdata(dev); component_master_del(dev, &wcd939x_comp_ops); pm_runtime_disable(dev); pm_runtime_set_suspended(dev); pm_runtime_dont_use_autosuspend(dev); - - regulator_bulk_disable(WCD939X_MAX_SUPPLY, wcd939x->supplies); - regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies); } #if defined(CONFIG_OF) From 1a134881a8f861bfc996d77d3eee9017a95eb5d7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 26 May 2025 12:49:53 +0200 Subject: [PATCH 021/385] ASoC: codecs: wcd939x: Simplify return from devm_gpiod_get() error No need to store devm_gpiod_get() error code in temporary variable. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250526-b4-asoc-wcd9395-vdd-px-v1-4-64d3cb60313b@linaro.org Reviewed-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/codecs/wcd939x.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index 95cd88a37acb..9592462f2d6e 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -3241,10 +3241,9 @@ static int wcd939x_populate_dt_data(struct wcd939x_priv *wcd939x, struct device int ret; wcd939x->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(wcd939x->reset_gpio)) { - ret = PTR_ERR(wcd939x->reset_gpio); - return dev_err_probe(dev, ret, "Failed to get reset gpio\n"); - } + if (IS_ERR(wcd939x->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(wcd939x->reset_gpio), + "Failed to get reset gpio\n"); ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(wcd939x_supplies), wcd939x_supplies); From 7d648206bae8e7fd3d67481751a76dcb0a299eb8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 26 May 2025 12:49:54 +0200 Subject: [PATCH 022/385] ASoC: dt-bindings: qcom,wcd939x: Document missing VDD_PX supply Document VDD_PX supply on WCD9390 and WCD9395 audio codecs, which was missed in original posting. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250526-b4-asoc-wcd9395-vdd-px-v1-5-64d3cb60313b@linaro.org Acked-by: "Rob Herring (Arm)" Reviewed-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,wcd939x.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd939x.yaml b/Documentation/devicetree/bindings/sound/qcom,wcd939x.yaml index c69291f4d575..85283f94465d 100644 --- a/Documentation/devicetree/bindings/sound/qcom,wcd939x.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,wcd939x.yaml @@ -45,6 +45,9 @@ properties: purpose of handling altmode muxing and orientation switching to detect and enable Audio Accessory Mode. + vdd-px-supply: + description: A reference to the 1.2V PX supply + required: - compatible From b9ecde0bcf6a99a3ff08496d4ba90a385ebbfd68 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 26 May 2025 12:49:55 +0200 Subject: [PATCH 023/385] ASoC: codecs: wcd939x: Add VDD_PX supply Device has also VDD_PX supply, which should be acquired by the driver. Regulator framework will provide a dummy supply, thus the change is compatible with older DTS. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250526-b4-asoc-wcd9395-vdd-px-v1-6-64d3cb60313b@linaro.org Reviewed-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/codecs/wcd939x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index 9592462f2d6e..690832037b5d 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -212,7 +212,7 @@ struct wcd939x_priv { }; static const char * const wcd939x_supplies[] = { - "vdd-rxtx", "vdd-io", "vdd-buck", "vdd-mic-bias", + "vdd-rxtx", "vdd-io", "vdd-buck", "vdd-mic-bias", "vdd-px", }; static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800); From c2bde4666d229d155de5f9b0aa0676804b32fa7a Mon Sep 17 00:00:00 2001 From: Bram Vlerick Date: Wed, 28 May 2025 14:10:08 +0200 Subject: [PATCH 024/385] ASoC: tas571x: add support for tas5753 Add support for tas5753, device is similar to tas5733 but with added headphone / line driver. Signed-off-by: Bram Vlerick Link: https://patch.msgid.link/20250528-asoc-tas5753-support-v1-1-a50c3f6734ee@openpixelsystems.org Reviewed-by: Krzysztof Kozlowski Acked-by: Peter Korsgaard Signed-off-by: Mark Brown --- sound/soc/codecs/tas571x.c | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c index 6bf37c77f0a7..41d73f470f8b 100644 --- a/sound/soc/codecs/tas571x.c +++ b/sound/soc/codecs/tas571x.c @@ -839,6 +839,56 @@ static const struct tas571x_chip tas5733_chip = { .vol_reg_size = 2, }; +static const struct reg_default tas5753_reg_defaults[] = { + {TAS571X_CLK_CTRL_REG, 0x6c}, + {TAS571X_DEV_ID_REG, 0x41}, + {TAS571X_ERR_STATUS_REG, 0x00}, + {TAS571X_SYS_CTRL_1_REG, 0xa0}, + {TAS571X_SDI_REG, 0x05}, + {TAS571X_SYS_CTRL_2_REG, 0x40}, + {TAS571X_SOFT_MUTE_REG, 0x00}, + {TAS571X_MVOL_REG, 0x03ff}, + {TAS571X_CH1_VOL_REG, 0x00c0}, + {TAS571X_CH2_VOL_REG, 0x00c0}, + {TAS571X_CH3_VOL_REG, 0x00c0}, + {TAS571X_VOL_CFG_REG, 0xf0}, + {TAS571X_MODULATION_LIMIT_REG, 0x01}, + {TAS571X_IC_DELAY_CH1_REG, 0xac}, + {TAS571X_IC_DELAY_CH2_REG, 0x54}, + {TAS571X_IC_DELAY_CH3_REG, 0xac}, + {TAS571X_IC_DELAY_CH4_REG, 0x54}, + {TAS571X_OSC_TRIM_REG, 0x82}, + {TAS571X_BKND_ERR_REG, 0x57}, + {TAS571X_INPUT_MUX_REG, 0x00017772}, + {TAS571X_PWM_MUX_REG, 0x01021345}, + {TAS5717_CH1_RIGHT_CH_MIX_REG, 0x00}, + {TAS5717_CH1_LEFT_CH_MIX_REG, 0x800000}, + {TAS5717_CH2_LEFT_CH_MIX_REG, 0x00}, + {TAS5717_CH2_RIGHT_CH_MIX_REG, 0x800000}, +}; + +static const struct regmap_config tas5753_regmap_config = { + .reg_bits = 8, + .val_bits = 32, + .max_register = 0xff, + .reg_read = tas571x_reg_read, + .reg_write = tas571x_reg_write, + .reg_defaults = tas5753_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tas5753_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .wr_table = &tas571x_write_regs, + .volatile_table = &tas571x_volatile_regs, +}; + +static const struct tas571x_chip tas5753_chip = { + .supply_names = tas5721_supply_names, + .num_supply_names = ARRAY_SIZE(tas5721_supply_names), + .controls = tas5733_controls, + .num_controls = ARRAY_SIZE(tas5733_controls), + .regmap_config = &tas5753_regmap_config, + .vol_reg_size = 2, +}; + static const struct tas571x_chip tas5721_chip = { .supply_names = tas5721_supply_names, .num_supply_names = ARRAY_SIZE(tas5721_supply_names), @@ -1007,6 +1057,7 @@ static const struct of_device_id tas571x_of_match[] __maybe_unused = { { .compatible = "ti,tas5719", .data = &tas5717_chip, }, { .compatible = "ti,tas5721", .data = &tas5721_chip, }, { .compatible = "ti,tas5733", .data = &tas5733_chip, }, + { .compatible = "ti,tas5753", .data = &tas5753_chip, }, { } }; MODULE_DEVICE_TABLE(of, tas571x_of_match); @@ -1018,6 +1069,7 @@ static const struct i2c_device_id tas571x_i2c_id[] = { { "tas5719", (kernel_ulong_t) &tas5717_chip }, { "tas5721", (kernel_ulong_t) &tas5721_chip }, { "tas5733", (kernel_ulong_t) &tas5733_chip }, + { "tas5753", (kernel_ulong_t) &tas5753_chip }, { } }; MODULE_DEVICE_TABLE(i2c, tas571x_i2c_id); From f6f914893d478b7ba08e5c375de1ced16deb5e92 Mon Sep 17 00:00:00 2001 From: Bram Vlerick Date: Wed, 28 May 2025 14:10:09 +0200 Subject: [PATCH 025/385] ASoC: dt-bindings: tas57xx: add tas5753 compatibility Add tas5753 to ti,tas57xx devicetree bindings. Signed-off-by: Bram Vlerick Link: https://patch.msgid.link/20250528-asoc-tas5753-support-v1-2-a50c3f6734ee@openpixelsystems.org Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/ti,tas57xx.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/ti,tas57xx.yaml b/Documentation/devicetree/bindings/sound/ti,tas57xx.yaml index 74f7d02b424b..0b013a34e2c1 100644 --- a/Documentation/devicetree/bindings/sound/ti,tas57xx.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tas57xx.yaml @@ -18,6 +18,7 @@ properties: - ti,tas5719 - ti,tas5721 - ti,tas5733 + - ti,tas5753 reg: maxItems: 1 @@ -98,6 +99,7 @@ allOf: contains: enum: - ti,tas5721 + - ti,tas5753 then: properties: HPVDD-supply: false From 5dc302d00807b8916992dd25a7a22b78d07dcd03 Mon Sep 17 00:00:00 2001 From: Pei Xiao Date: Fri, 6 Jun 2025 17:18:21 +0800 Subject: [PATCH 026/385] ASOC: rockchip: fix capture stream handling in rockchip_sai_xfer_stop Correcting the capture stream handling which was incorrectly setting playback=true for capture streams. The original code mistakenly set playback=true for capture streams, causing incorrect behavior. Fixes: cc78d1eaabad ("ASoC: rockchip: add Serial Audio Interface (SAI) driver") Signed-off-by: Pei Xiao Tested-by: Nicolas Frattaroli Acked-by: Nicolas Frattaroli Link: https://patch.msgid.link/c374aae92c177aaf42c0f1371eccdbc7e9615786.1749201126.git.xiaopei01@kylinos.cn Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_sai.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c index 602f1ddfad00..916af63f1c2c 100644 --- a/sound/soc/rockchip/rockchip_sai.c +++ b/sound/soc/rockchip/rockchip_sai.c @@ -378,19 +378,9 @@ static void rockchip_sai_xfer_start(struct rk_sai_dev *sai, int stream) static void rockchip_sai_xfer_stop(struct rk_sai_dev *sai, int stream) { unsigned int msk = 0, val = 0, clr = 0; - bool playback; - bool capture; - - if (stream < 0) { - playback = true; - capture = true; - } else if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - playback = true; - capture = false; - } else { - playback = true; - capture = false; - } + bool capture = stream == SNDRV_PCM_STREAM_CAPTURE || stream < 0; + bool playback = stream == SNDRV_PCM_STREAM_PLAYBACK || stream < 0; + /* could be <= 0 but we don't want to depend on enum values */ if (playback) { msk |= SAI_XFER_TXS_MASK; From 03b778d1994827ea5cc971dbdfbb457bbb7bfa5d Mon Sep 17 00:00:00 2001 From: Pei Xiao Date: Fri, 6 Jun 2025 17:18:22 +0800 Subject: [PATCH 027/385] ASOC: rockchip: Use helper function devm_clk_get_enabled() Since commit 7ef9651e9792 ("clk: Provide new devm_clk helpers for prepared and enabled clocks"), devm_clk_get() and clk_prepare_enable() can now be replaced by devm_clk_get_enabled() when driver enables the clocks for the whole lifetime of the device. Moreover, it is no longer necessary to unprepare and disable the clocks explicitly. Signed-off-by: Pei Xiao Acked-by: Nicolas Frattaroli Tested-by: Nicolas Frattaroli Link: https://patch.msgid.link/84bc40641d05596f1edf4f01d1e6aea16bdbeeb5.1749201126.git.xiaopei01@kylinos.cn Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_sai.c | 35 +++++++++---------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c index 916af63f1c2c..0b9f54102d69 100644 --- a/sound/soc/rockchip/rockchip_sai.c +++ b/sound/soc/rockchip/rockchip_sai.c @@ -1427,43 +1427,32 @@ static int rockchip_sai_probe(struct platform_device *pdev) if (irq > 0) { ret = devm_request_irq(&pdev->dev, irq, rockchip_sai_isr, IRQF_SHARED, node->name, sai); - if (ret) { + if (ret) return dev_err_probe(&pdev->dev, ret, "Failed to request irq %d\n", irq); - } } else { dev_dbg(&pdev->dev, "Asked for an IRQ but got %d\n", irq); } sai->mclk = devm_clk_get(&pdev->dev, "mclk"); - if (IS_ERR(sai->mclk)) { + if (IS_ERR(sai->mclk)) return dev_err_probe(&pdev->dev, PTR_ERR(sai->mclk), "Failed to get mclk\n"); - } - sai->hclk = devm_clk_get(&pdev->dev, "hclk"); - if (IS_ERR(sai->hclk)) { + sai->hclk = devm_clk_get_enabled(&pdev->dev, "hclk"); + if (IS_ERR(sai->hclk)) return dev_err_probe(&pdev->dev, PTR_ERR(sai->hclk), "Failed to get hclk\n"); - } - - ret = clk_prepare_enable(sai->hclk); - if (ret) - return dev_err_probe(&pdev->dev, ret, "Failed to enable hclk\n"); regmap_read(sai->regmap, SAI_VERSION, &sai->version); ret = rockchip_sai_init_dai(sai, res, &dai); - if (ret) { - dev_err(&pdev->dev, "Failed to initialize DAI: %d\n", ret); - goto err_disable_hclk; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to initialize DAI\n"); ret = rockchip_sai_parse_paths(sai, node); - if (ret) { - dev_err(&pdev->dev, "Failed to parse paths: %d\n", ret); - goto err_disable_hclk; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to parse paths\n"); /* * From here on, all register accesses need to be wrapped in @@ -1474,10 +1463,8 @@ static int rockchip_sai_probe(struct platform_device *pdev) devm_pm_runtime_enable(&pdev->dev); pm_runtime_get_noresume(&pdev->dev); ret = rockchip_sai_runtime_resume(&pdev->dev); - if (ret) { - dev_err(&pdev->dev, "Failed to resume device: %pe\n", ERR_PTR(ret)); - goto err_disable_hclk; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to resume device\n"); ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); if (ret) { @@ -1504,8 +1491,6 @@ err_runtime_suspend: /* If we're !CONFIG_PM, we get -ENOSYS and disable manually */ if (pm_runtime_put(&pdev->dev)) rockchip_sai_runtime_suspend(&pdev->dev); -err_disable_hclk: - clk_disable_unprepare(sai->hclk); return ret; } From cecec195b2930fc45d71e29f66a66f0c83e41468 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 30 May 2025 16:21:18 +0200 Subject: [PATCH 028/385] ASoC: codecs: rt5640: Drop dummy register names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Registers 0xfa and 0xfb represent "General Control 1" and "General Control 2" respectively. Reviewed-by: Amadeusz Sławiński Signed-off-by: Cezary Rojewski Link: https://patch.msgid.link/20250530142120.2944095-2-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 38 +++++++++++++++++++------------------- sound/soc/codecs/rt5640.h | 6 +++--- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 21a18012b4c0..265b30856faf 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -193,7 +193,7 @@ static bool rt5640_volatile_register(struct device *dev, unsigned int reg) case RT5640_PRIV_DATA: case RT5640_PGM_REG_ARR1: case RT5640_PGM_REG_ARR3: - case RT5640_DUMMY2: + case RT5640_GCTL2: case RT5640_VENDOR_ID: case RT5640_VENDOR_ID1: case RT5640_VENDOR_ID2: @@ -325,8 +325,8 @@ static bool rt5640_readable_register(struct device *dev, unsigned int reg) case RT5640_HP_CALIB2: case RT5640_SV_ZCD1: case RT5640_SV_ZCD2: - case RT5640_DUMMY1: - case RT5640_DUMMY2: + case RT5640_GCTL1: + case RT5640_GCTL2: case RT5640_DUMMY3: case RT5640_VENDOR_ID: case RT5640_VENDOR_ID1: @@ -423,7 +423,7 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = { SOC_DOUBLE_TLV("ADC Capture Volume", RT5640_ADC_DIG_VOL, RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 127, 0, adc_vol_tlv), - SOC_DOUBLE("Mono ADC Capture Switch", RT5640_DUMMY1, + SOC_DOUBLE("Mono ADC Capture Switch", RT5640_GCTL1, RT5640_M_MONO_ADC_L_SFT, RT5640_M_MONO_ADC_R_SFT, 1, 1), SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5640_ADC_DATA, RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, @@ -1969,7 +1969,7 @@ static int rt5640_set_bias_level(struct snd_soc_component *component, snd_soc_component_update_bits(component, RT5640_PWR_ANLG1, RT5640_PWR_FV1 | RT5640_PWR_FV2, RT5640_PWR_FV1 | RT5640_PWR_FV2); - snd_soc_component_update_bits(component, RT5640_DUMMY1, + snd_soc_component_update_bits(component, RT5640_GCTL1, 0x1, 0x1); snd_soc_component_update_bits(component, RT5640_MICBIAS, 0x0030, 0x0030); @@ -1979,7 +1979,7 @@ static int rt5640_set_bias_level(struct snd_soc_component *component, case SND_SOC_BIAS_OFF: snd_soc_component_write(component, RT5640_DEPOP_M1, 0x0004); snd_soc_component_write(component, RT5640_DEPOP_M2, 0x1100); - snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x1, 0); + snd_soc_component_update_bits(component, RT5640_GCTL1, 0x1, 0); snd_soc_component_write(component, RT5640_PWR_DIG1, 0x0000); snd_soc_component_write(component, RT5640_PWR_DIG2, 0x0000); snd_soc_component_write(component, RT5640_PWR_VOL, 0x0000); @@ -2328,12 +2328,12 @@ static void rt5640_jack_work(struct work_struct *work) jack_type |= SND_JACK_MICROPHONE; /* headphone jack */ - val = snd_soc_component_read(component, RT5640_DUMMY2); + val = snd_soc_component_read(component, RT5640_GCTL2); hda_hp_plugged = !(val & (0x1 << 11)); dev_dbg(component->dev, "headphone jack status %d\n", hda_hp_plugged); - snd_soc_component_update_bits(component, RT5640_DUMMY2, + snd_soc_component_update_bits(component, RT5640_GCTL2, (0x1 << 10), !hda_hp_plugged << 10); if (hda_hp_plugged) @@ -2504,7 +2504,7 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component, snd_soc_component_update_bits(component, RT5640_GPIO_CTRL3, RT5640_GP1_PF_MASK, RT5640_GP1_PF_OUT); - snd_soc_component_write(component, RT5640_DUMMY1, 0x3f41); + snd_soc_component_write(component, RT5640_GCTL1, 0x3f41); rt5640_set_ovcd_params(component); @@ -2519,7 +2519,7 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component, snd_soc_component_write(component, RT5640_IRQ_CTRL1, RT5640_IRQ_JD_NOR); else if (rt5640->jd_src == RT5640_JD_SRC_JD2_IN4N) - snd_soc_component_update_bits(component, RT5640_DUMMY2, + snd_soc_component_update_bits(component, RT5640_GCTL2, RT5640_IRQ_JD2_MASK | RT5640_JD2_MASK, RT5640_IRQ_JD2_NOR | RT5640_JD2_EN); } else { @@ -2527,7 +2527,7 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component, snd_soc_component_write(component, RT5640_IRQ_CTRL1, RT5640_IRQ_JD_NOR | RT5640_JD_P_INV); else if (rt5640->jd_src == RT5640_JD_SRC_JD2_IN4N) - snd_soc_component_update_bits(component, RT5640_DUMMY2, + snd_soc_component_update_bits(component, RT5640_GCTL2, RT5640_IRQ_JD2_MASK | RT5640_JD2_P_MASK | RT5640_JD2_MASK, RT5640_IRQ_JD2_NOR | RT5640_JD2_P_INV | @@ -2596,7 +2596,7 @@ static void rt5640_enable_hda_jack_detect( snd_soc_component_write(component, RT5640_IRQ_CTRL1, RT5640_IRQ_JD_NOR); /* Select JD2 for Headphone */ - snd_soc_component_update_bits(component, RT5640_DUMMY2, 0x1100, 0x1100); + snd_soc_component_update_bits(component, RT5640_GCTL2, 0x1100, 0x1100); /* Selecting GPIO01 as an interrupt */ snd_soc_component_update_bits(component, RT5640_GPIO_CTRL1, @@ -2606,7 +2606,7 @@ static void rt5640_enable_hda_jack_detect( snd_soc_component_update_bits(component, RT5640_GPIO_CTRL3, RT5640_GP1_PF_MASK, RT5640_GP1_PF_OUT); - snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x400, 0x0); + snd_soc_component_update_bits(component, RT5640_GCTL1, 0x400, 0x0); snd_soc_component_update_bits(component, RT5640_PWR_ANLG1, RT5640_PWR_VREF2 | RT5640_PWR_MB | RT5640_PWR_BG, @@ -2668,7 +2668,7 @@ static int rt5640_probe(struct snd_soc_component *component) snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF); - snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x0301, 0x0301); + snd_soc_component_update_bits(component, RT5640_GCTL1, 0x0301, 0x0301); snd_soc_component_update_bits(component, RT5640_MICBIAS, 0x0030, 0x0030); snd_soc_component_update_bits(component, RT5640_DSP_PATH2, 0xfc00, 0x0c00); @@ -2719,7 +2719,7 @@ static int rt5640_probe(struct snd_soc_component *component) RT5640_IN_DF2, RT5640_IN_DF2); if (device_property_read_bool(component->dev, "realtek,lout-differential")) - snd_soc_component_update_bits(component, RT5640_DUMMY1, + snd_soc_component_update_bits(component, RT5640_GCTL1, RT5640_EN_LOUT_DF, RT5640_EN_LOUT_DF); if (device_property_read_u32(component->dev, "realtek,dmic1-data-pin", @@ -2829,12 +2829,12 @@ static int rt5640_resume(struct snd_soc_component *component) if (rt5640->jack) { if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) { snd_soc_component_update_bits(component, - RT5640_DUMMY2, 0x1100, 0x1100); + RT5640_GCTL2, 0x1100, 0x1100); } else { if (rt5640->jd_inverted) { if (rt5640->jd_src == RT5640_JD_SRC_JD2_IN4N) snd_soc_component_update_bits( - component, RT5640_DUMMY2, + component, RT5640_GCTL2, RT5640_IRQ_JD2_MASK | RT5640_JD2_MASK, RT5640_IRQ_JD2_NOR | @@ -2843,7 +2843,7 @@ static int rt5640_resume(struct snd_soc_component *component) } else { if (rt5640->jd_src == RT5640_JD_SRC_JD2_IN4N) snd_soc_component_update_bits( - component, RT5640_DUMMY2, + component, RT5640_GCTL2, RT5640_IRQ_JD2_MASK | RT5640_JD2_P_MASK | RT5640_JD2_MASK, @@ -3026,7 +3026,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c) if (ret != 0) dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); - regmap_update_bits(rt5640->regmap, RT5640_DUMMY1, + regmap_update_bits(rt5640->regmap, RT5640_GCTL1, RT5640_MCLK_DET, RT5640_MCLK_DET); rt5640->hp_mute = true; diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 94b9a502f7f9..8a12cee76bdc 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -139,8 +139,8 @@ #define RT5640_SV_ZCD1 0xd9 #define RT5640_SV_ZCD2 0xda /* Dummy Register */ -#define RT5640_DUMMY1 0xfa -#define RT5640_DUMMY2 0xfb +#define RT5640_GCTL1 0xfa +#define RT5640_GCTL2 0xfb #define RT5640_DUMMY3 0xfc @@ -1986,7 +1986,7 @@ #define RT5640_M_MONO_ADC_R_SFT 12 #define RT5640_MCLK_DET (0x1 << 11) -/* General Control 1 (0xfb) */ +/* General Control 2 (0xfb) */ #define RT5640_IRQ_JD2_MASK (0x1 << 12) #define RT5640_IRQ_JD2_SFT 12 #define RT5640_IRQ_JD2_BP (0x0 << 12) From 19f971057b2d7b99c80530ec1052b45de236a8da Mon Sep 17 00:00:00 2001 From: Xinxin Wan Date: Fri, 30 May 2025 16:21:19 +0200 Subject: [PATCH 029/385] ASoC: codecs: rt5640: Retry DEVICE_ID verification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To be more resilient to codec-detection failures when the hardware powers on slowly, add retry mechanism to the device verification check. Similar pattern is found throughout a number of Realtek codecs. Our tests show that 60ms delay is sufficient to address readiness issues on rt5640 chip. Reviewed-by: Amadeusz Sławiński Reviewed-by: Cezary Rojewski Signed-off-by: Xinxin Wan Signed-off-by: Cezary Rojewski Link: https://patch.msgid.link/20250530142120.2944095-3-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 265b30856faf..f50e771db24b 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -3013,6 +3013,11 @@ static int rt5640_i2c_probe(struct i2c_client *i2c) } regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val); + if (val != RT5640_DEVICE_ID) { + usleep_range(60000, 100000); + regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val); + } + if (val != RT5640_DEVICE_ID) { dev_err(&i2c->dev, "Device with ID register %#x is not rt5640/39\n", val); From c95e925daa434ee1a40a86aec6476ce588e4bd77 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 30 May 2025 16:21:20 +0200 Subject: [PATCH 030/385] ASoC: Intel: avs: Add rt5640 machine board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To support connection between Intel AudioDSP and Realek 5640 codec implement avs_rt5640 machine board driver. The codec chip is located on I2C bus and the streaming occurs over I2S interface. A number of such devices can be connected simultaneously to the platform. Majority of the board's behavior is inherited from existing representatives such as avs_rt274. Reviewed-by: Amadeusz Sławiński Signed-off-by: Cezary Rojewski Link: https://patch.msgid.link/20250530142120.2944095-4-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/board_selection.c | 27 +++ sound/soc/intel/avs/boards/Kconfig | 12 ++ sound/soc/intel/avs/boards/Makefile | 2 + sound/soc/intel/avs/boards/rt5640.c | 270 ++++++++++++++++++++++++++ 4 files changed, 311 insertions(+) create mode 100644 sound/soc/intel/avs/boards/rt5640.c diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index 673ccf162023..fb49167f5fc4 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -308,6 +308,33 @@ static struct snd_soc_acpi_mach avs_tgl_i2s_machines[] = { }, .tplg_filename = "rt1308-tplg.bin", }, + { + .id = "10EC5640", + .uid = "1", + .drv_name = "avs_rt5640", + .mach_params = { + .i2s_link_mask = AVS_SSP(0), + }, + .tplg_filename = "rt5640-tplg.bin", + }, + { + .id = "10EC5640", + .uid = "3", + .drv_name = "avs_rt5640", + .mach_params = { + .i2s_link_mask = AVS_SSP(1), + }, + .tplg_filename = "rt5640-tplg.bin", + }, + { + .id = "10EC5640", + .uid = "2", + .drv_name = "avs_rt5640", + .mach_params = { + .i2s_link_mask = AVS_SSP(2), + }, + .tplg_filename = "rt5640-tplg.bin", + }, { .id = "ESSX8336", .drv_name = "avs_es8336", diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig index 8b654181004e..82f50207bb2f 100644 --- a/sound/soc/intel/avs/boards/Kconfig +++ b/sound/soc/intel/avs/boards/Kconfig @@ -153,6 +153,18 @@ config SND_SOC_INTEL_AVS_MACH_RT5514 Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +config SND_SOC_INTEL_AVS_MACH_RT5640 + tristate "rt5640 in I2S mode" + depends on I2C + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_RT5640 + help + This adds support for ASoC machine board connecting AVS with RT5640, + components representing Intel AudioDSP and Realtek 5640 codec respectively. + The codec chip is present on I2C bus and the streaming occurs over I2S + interface. + Say Y or m if you have such a device. + config SND_SOC_INTEL_AVS_MACH_RT5663 tristate "rt5663 in I2S mode" depends on I2C diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile index a95256b94dc8..46ef1babda34 100644 --- a/sound/soc/intel/avs/boards/Makefile +++ b/sound/soc/intel/avs/boards/Makefile @@ -15,6 +15,7 @@ snd-soc-avs-rt274-y := rt274.o snd-soc-avs-rt286-y := rt286.o snd-soc-avs-rt298-y := rt298.o snd-soc-avs-rt5514-y := rt5514.o +snd-soc-avs-rt5640-y := rt5640.o snd-soc-avs-rt5663-y := rt5663.o snd-soc-avs-rt5682-y := rt5682.o snd-soc-avs-ssm4567-y := ssm4567.o @@ -34,6 +35,7 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5514) += snd-soc-avs-rt5514.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5640) += snd-soc-avs-rt5640.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5663) += snd-soc-avs-rt5663.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5682) += snd-soc-avs-rt5682.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_SSM4567) += snd-soc-avs-ssm4567.o diff --git a/sound/soc/intel/avs/boards/rt5640.c b/sound/soc/intel/avs/boards/rt5640.c new file mode 100644 index 000000000000..706b84ffe1ef --- /dev/null +++ b/sound/soc/intel/avs/boards/rt5640.c @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2022-2025 Intel Corporation +// +// Authors: Cezary Rojewski +// Amadeusz Slawinski +// + +#include +#include +#include +#include +#include +#include +#include "../../../codecs/rt5640.h" +#include "../utils.h" + +#define AVS_RT5640_MCLK_HZ 19200000 +#define RT5640_CODEC_DAI "rt5640-aif1" + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_soc_dapm_route card_routes[] = { + { "Headphone Jack", NULL, "HPOR" }, + { "Headphone Jack", NULL, "HPOL" }, + { "IN2P", NULL, "Mic Jack" }, + { "IN2P", NULL, "MICBIAS1" }, + { "Speaker", NULL, "SPOLP" }, + { "Speaker", NULL, "SPOLN" }, + { "Speaker", NULL, "SPORP" }, + { "Speaker", NULL, "SPORN" }, +}; + +static const struct snd_soc_jack_pin card_headset_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int avs_rt5640_codec_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0); + struct snd_soc_card *card = runtime->card; + struct snd_soc_jack_pin *pins; + struct snd_soc_jack *jack; + int num_pins, ret; + + jack = snd_soc_card_get_drvdata(card); + num_pins = ARRAY_SIZE(card_headset_pins); + + pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + if (!pins) + return -ENOMEM; + + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET, jack, pins, + num_pins); + if (ret) + return ret; + + snd_soc_component_set_jack(codec_dai->component, jack, NULL); + card->dapm.idle_bias_off = true; + + return 0; +} + +static void avs_rt5640_codec_exit(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0); + + snd_soc_component_set_jack(codec_dai->component, NULL, NULL); +} + +static int avs_rt5640_be_fixup(struct snd_soc_pcm_runtime *runtime, + struct snd_pcm_hw_params *params) +{ + struct snd_mask *fmask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* Format 24/32 is MSB-aligned for HDAudio and LSB-aligned for I2S. */ + if (params_format(params) == SNDRV_PCM_FORMAT_S32_LE) + snd_mask_set_format(fmask, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +static int avs_rt5640_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *runtime = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0); + int ret; + + ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_MCLK, AVS_RT5640_MCLK_HZ, + params_rate(params) * 512); + if (ret < 0) { + dev_err(runtime->dev, "Set codec PLL failed: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, params_rate(params) * 512, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(runtime->dev, "Set codec SCLK failed: %d\n", ret); + return ret; + } + + ret = rt5640_sel_asrc_clk_src(codec_dai->component, + RT5640_DA_STEREO_FILTER | RT5640_AD_STEREO_FILTER | + RT5640_DA_MONO_L_FILTER | RT5640_DA_MONO_R_FILTER | + RT5640_AD_MONO_L_FILTER | RT5640_AD_MONO_R_FILTER, + RT5640_CLK_SEL_ASRC); + if (ret) + dev_err(runtime->dev, "Set codec ASRC failed: %d\n", ret); + + return ret; +} + +static const struct snd_soc_ops avs_rt5640_ops = { + .hw_params = avs_rt5640_hw_params, +}; + +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_acpi_mach *mach, + struct snd_soc_dai_link **dai_link) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + u32 uid = 0; + int ret; + + if (mach->uid) { + ret = kstrtou32(mach->uid, 0, &uid); + if (ret) + return ret; + uid--; /* 0-based indexing. */ + } + + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + dl->name = devm_kasprintf(dev, GFP_KERNEL, + AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); + dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); + dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); + if (!dl->name || !dl->cpus || !dl->codecs) + return -ENOMEM; + + dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot)); + dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10EC5640:0%d", uid); + dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT5640_CODEC_DAI); + if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) + return -ENOMEM; + + platform->name = dev_name(dev); + dl->num_cpus = 1; + dl->num_codecs = 1; + dl->platforms = platform; + dl->num_platforms = 1; + dl->id = 0; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; + dl->init = avs_rt5640_codec_init; + dl->exit = avs_rt5640_codec_exit; + dl->be_hw_params_fixup = avs_rt5640_be_fixup; + dl->ops = &avs_rt5640_ops; + dl->nonatomic = 1; + dl->no_pcm = 1; + + *dai_link = dl; + + return 0; +} + +static int avs_card_suspend_pre(struct snd_soc_card *card) +{ + struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT5640_CODEC_DAI); + + return snd_soc_component_set_jack(codec_dai->component, NULL, NULL); +} + +static int avs_card_resume_post(struct snd_soc_card *card) +{ + struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT5640_CODEC_DAI); + struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card); + + return snd_soc_component_set_jack(codec_dai->component, jack, NULL); +} + +static int avs_rt5640_probe(struct platform_device *pdev) +{ + struct snd_soc_dai_link *dai_link; + struct device *dev = &pdev->dev; + struct snd_soc_acpi_mach *mach; + struct snd_soc_card *card; + struct snd_soc_jack *jack; + int ssp_port, tdm_slot, ret; + + mach = dev_get_platdata(dev); + + ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); + if (ret) + return ret; + + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, mach, &dai_link); + if (ret) { + dev_err(dev, "Failed to create dai link: %d", ret); + return ret; + } + + jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL); + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!jack || !card) + return -ENOMEM; + + if (mach->uid) { + card->name = devm_kasprintf(dev, GFP_KERNEL, "AVS I2S ALC5640.%s", mach->uid); + if (!card->name) + return -ENOMEM; + } else { + card->name = "AVS I2S ALC5640"; + } + card->driver_name = "avs_rt5640"; + card->long_name = card->name; + card->dev = dev; + card->owner = THIS_MODULE; + card->suspend_pre = avs_card_suspend_pre; + card->resume_post = avs_card_resume_post; + card->dai_link = dai_link; + card->num_links = 1; + card->dapm_widgets = card_widgets; + card->num_dapm_widgets = ARRAY_SIZE(card_widgets); + card->dapm_routes = card_routes; + card->num_dapm_routes = ARRAY_SIZE(card_routes); + card->fully_routed = true; + snd_soc_card_set_drvdata(card, jack); + + return devm_snd_soc_register_deferrable_card(dev, card); +} + +static const struct platform_device_id avs_rt5640_driver_ids[] = { + { + .name = "avs_rt5640", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_rt5640_driver_ids); + +static struct platform_driver avs_rt5640_driver = { + .probe = avs_rt5640_probe, + .driver = { + .name = "avs_rt5640", + .pm = &snd_soc_pm_ops, + }, + .id_table = avs_rt5640_driver_ids, +}; + +module_platform_driver(avs_rt5640_driver); + +MODULE_DESCRIPTION("Intel rt5640 machine driver"); +MODULE_LICENSE("GPL"); From bb4a0f497bc19558ba7fe9feac814286fc7ebe85 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 23 May 2025 14:18:12 +0200 Subject: [PATCH 031/385] ASoC: codecs: lpass: Drop unused AIF_INVALID first DAI identifier All four Qualcomm SoC macro codecs define DAI IDs in an enum starting with AIF_INVALID=0, which is nowhere used in the code thus actual DAI IDs start from 1. Drivers do not have their own of_xlate_dai_name(), thus snd_soc_get_dlc() expects the DTS to start numbering DAIs from 0, which creates confusing debugging scenario, e.g. DTS should use <&lpass_wsamacro 2> for WSA_MACRO_AIF_VI with dai->id=3. This also wastes some space, because drivers allocate few arrays for all DAIs and basically the [0] is never used. Drop the confusing first AIF_INVALID DAI identifier so the enum with DAI IDs will start from 0. This has little functional impact and does not affect the ABI, except saving a few bytes of memory per driver. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250523121811.380045-2-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 1 - sound/soc/codecs/lpass-tx-macro.c | 1 - sound/soc/codecs/lpass-va-macro.c | 1 - sound/soc/codecs/lpass-wsa-macro.c | 1 - 4 files changed, 4 deletions(-) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 45a6b83808b2..238dbdb46c18 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -619,7 +619,6 @@ static struct interp_sample_rate sr_val_tbl[] = { }; enum { - RX_MACRO_AIF_INVALID = 0, RX_MACRO_AIF1_PB, RX_MACRO_AIF2_PB, RX_MACRO_AIF3_PB, diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index 27bae58f4072..40d79bee4584 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -208,7 +208,6 @@ #define MCLK_FREQ 19200000 enum { - TX_MACRO_AIF_INVALID = 0, TX_MACRO_AIF1_CAP, TX_MACRO_AIF2_CAP, TX_MACRO_AIF3_CAP, diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index 74ada6e77526..a49551f3fb29 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -165,7 +165,6 @@ static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400); enum { - VA_MACRO_AIF_INVALID = 0, VA_MACRO_AIF1_CAP, VA_MACRO_AIF2_CAP, VA_MACRO_AIF3_CAP, diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index c1fb71cfb5d0..da6adb3de21d 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -369,7 +369,6 @@ static struct interp_sample_rate int_mix_sample_rate_val[] = { }; enum { - WSA_MACRO_AIF_INVALID = 0, WSA_MACRO_AIF1_PB, WSA_MACRO_AIF_MIX1_PB, WSA_MACRO_AIF_VI, From 039de8f598dd7f060c8fde2498a7163315466f6d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 5 Jun 2025 01:43:37 +0000 Subject: [PATCH 032/385] ASoC: hdac_hdmi: remove hdac_hdmi_jack[_port]_init() No one is using hdac_hdmi_jack[_port]_init(). Remove it and its related functions. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87o6v3j73q.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 297 ----------------------------------- sound/soc/codecs/hdac_hdmi.h | 10 -- 2 files changed, 307 deletions(-) delete mode 100644 sound/soc/codecs/hdac_hdmi.h diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 1139a2754ca3..e05f0bf91fa5 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -25,7 +25,6 @@ #include #include #include "../../hda/local.h" -#include "hdac_hdmi.h" #define NAME_SIZE 32 @@ -1431,122 +1430,6 @@ static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdev) } -static int hdac_hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component); - struct hdac_hdmi_pcm *pcm; - struct hdac_hdmi_port *port; - struct hdac_hdmi_eld *eld; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; - uinfo->count = 0; - - pcm = get_hdmi_pcm_from_id(hdmi, kcontrol->id.device); - if (!pcm) { - dev_dbg(component->dev, "%s: no pcm, device %d\n", __func__, - kcontrol->id.device); - return 0; - } - - if (list_empty(&pcm->port_list)) { - dev_dbg(component->dev, "%s: empty port list, device %d\n", - __func__, kcontrol->id.device); - return 0; - } - - mutex_lock(&hdmi->pin_mutex); - - list_for_each_entry(port, &pcm->port_list, head) { - eld = &port->eld; - - if (eld->eld_valid) { - uinfo->count = eld->eld_size; - break; - } - } - - mutex_unlock(&hdmi->pin_mutex); - - return 0; -} - -static int hdac_hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component); - struct hdac_hdmi_pcm *pcm; - struct hdac_hdmi_port *port; - struct hdac_hdmi_eld *eld; - - memset(ucontrol->value.bytes.data, 0, sizeof(ucontrol->value.bytes.data)); - - pcm = get_hdmi_pcm_from_id(hdmi, kcontrol->id.device); - if (!pcm) { - dev_dbg(component->dev, "%s: no pcm, device %d\n", __func__, - kcontrol->id.device); - return 0; - } - - if (list_empty(&pcm->port_list)) { - dev_dbg(component->dev, "%s: empty port list, device %d\n", - __func__, kcontrol->id.device); - return 0; - } - - mutex_lock(&hdmi->pin_mutex); - - list_for_each_entry(port, &pcm->port_list, head) { - eld = &port->eld; - - if (!eld->eld_valid) - continue; - - if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data) || - eld->eld_size > ELD_MAX_SIZE) { - mutex_unlock(&hdmi->pin_mutex); - - dev_err(component->dev, "%s: buffer too small, device %d eld_size %d\n", - __func__, kcontrol->id.device, eld->eld_size); - snd_BUG(); - return -EINVAL; - } - - memcpy(ucontrol->value.bytes.data, eld->eld_buffer, - eld->eld_size); - break; - } - - mutex_unlock(&hdmi->pin_mutex); - - return 0; -} - -static int hdac_hdmi_create_eld_ctl(struct snd_soc_component *component, struct hdac_hdmi_pcm *pcm) -{ - struct snd_kcontrol *kctl; - struct snd_kcontrol_new hdmi_eld_ctl = { - .access = SNDRV_CTL_ELEM_ACCESS_READ | - SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = "ELD", - .info = hdac_hdmi_eld_ctl_info, - .get = hdac_hdmi_eld_ctl_get, - .device = pcm->pcm_id, - }; - - /* add ELD ctl with the device number corresponding to the PCM stream */ - kctl = snd_ctl_new1(&hdmi_eld_ctl, component); - if (!kctl) - return -ENOMEM; - - pcm->eld_ctl = kctl; - - return snd_ctl_add(component->card->snd_card, kctl); -} - static const struct snd_soc_dai_ops hdmi_dai_ops = { .startup = hdac_hdmi_pcm_open, .shutdown = hdac_hdmi_pcm_close, @@ -1754,186 +1637,6 @@ static struct drm_audio_component_audio_ops aops = { .pin_eld_notify = hdac_hdmi_eld_notify_cb, }; -static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card, - int device) -{ - struct snd_soc_pcm_runtime *rtd; - - for_each_card_rtds(card, rtd) { - if (rtd->pcm && (rtd->pcm->device == device)) - return rtd->pcm; - } - - return NULL; -} - -/* create jack pin kcontrols */ -static int create_fill_jack_kcontrols(struct snd_soc_card *card, - struct hdac_device *hdev) -{ - struct hdac_hdmi_pin *pin; - struct snd_kcontrol_new *kc; - char *name; - int i = 0, j; - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); - struct snd_soc_component *component = hdmi->component; - - kc = devm_kcalloc(component->dev, hdmi->num_ports, - sizeof(*kc), GFP_KERNEL); - - if (!kc) - return -ENOMEM; - - list_for_each_entry(pin, &hdmi->pin_list, head) { - for (j = 0; j < pin->num_ports; j++) { - name = devm_kasprintf(component->dev, GFP_KERNEL, - "hif%d-%d Jack", - pin->nid, pin->ports[j].id); - if (!name) - return -ENOMEM; - - kc[i].name = devm_kasprintf(component->dev, GFP_KERNEL, - "%s Switch", name); - if (!kc[i].name) - return -ENOMEM; - - kc[i].private_value = (unsigned long)name; - kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc[i].access = 0; - kc[i].info = snd_soc_dapm_info_pin_switch; - kc[i].put = snd_soc_dapm_put_pin_switch; - kc[i].get = snd_soc_dapm_get_pin_switch; - i++; - } - } - - return snd_soc_add_card_controls(card, kc, i); -} - -int hdac_hdmi_jack_port_init(struct snd_soc_component *component, - struct snd_soc_dapm_context *dapm) -{ - struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component); - struct hdac_device *hdev = hdmi->hdev; - struct hdac_hdmi_pin *pin; - struct snd_soc_dapm_widget *widgets; - struct snd_soc_dapm_route *route; - char w_name[NAME_SIZE]; - int i = 0, j, ret; - - widgets = devm_kcalloc(dapm->dev, hdmi->num_ports, - sizeof(*widgets), GFP_KERNEL); - - if (!widgets) - return -ENOMEM; - - route = devm_kcalloc(dapm->dev, hdmi->num_ports, - sizeof(*route), GFP_KERNEL); - if (!route) - return -ENOMEM; - - /* create Jack DAPM widget */ - list_for_each_entry(pin, &hdmi->pin_list, head) { - for (j = 0; j < pin->num_ports; j++) { - snprintf(w_name, sizeof(w_name), "hif%d-%d Jack", - pin->nid, pin->ports[j].id); - - ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], - snd_soc_dapm_spk, NULL, - w_name, NULL, NULL, 0, NULL, 0); - if (ret < 0) - return ret; - - pin->ports[j].jack_pin = widgets[i].name; - pin->ports[j].dapm = dapm; - - /* add to route from Jack widget to output */ - hdac_hdmi_fill_route(&route[i], pin->ports[j].jack_pin, - NULL, pin->ports[j].output_pin, NULL); - - i++; - } - } - - /* Add Route from Jack widget to the output widget */ - ret = snd_soc_dapm_new_controls(dapm, widgets, hdmi->num_ports); - if (ret < 0) - return ret; - - ret = snd_soc_dapm_add_routes(dapm, route, hdmi->num_ports); - if (ret < 0) - return ret; - - ret = snd_soc_dapm_new_widgets(dapm->card); - if (ret < 0) - return ret; - - /* Add Jack Pin switch Kcontrol */ - ret = create_fill_jack_kcontrols(dapm->card, hdev); - - if (ret < 0) - return ret; - - /* default set the Jack Pin switch to OFF */ - list_for_each_entry(pin, &hdmi->pin_list, head) { - for (j = 0; j < pin->num_ports; j++) - snd_soc_dapm_disable_pin(pin->ports[j].dapm, - pin->ports[j].jack_pin); - } - - return 0; -} -EXPORT_SYMBOL_GPL(hdac_hdmi_jack_port_init); - -int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, - struct snd_soc_jack *jack) -{ - struct snd_soc_component *component = dai->component; - struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component); - struct hdac_device *hdev = hdmi->hdev; - struct hdac_hdmi_pcm *pcm; - struct snd_pcm *snd_pcm; - int err; - - /* - * this is a new PCM device, create new pcm and - * add to the pcm list - */ - pcm = devm_kzalloc(&hdev->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - pcm->pcm_id = device; - pcm->cvt = hdmi->dai_map[dai->id].cvt; - pcm->jack_event = 0; - pcm->jack = jack; - mutex_init(&pcm->lock); - INIT_LIST_HEAD(&pcm->port_list); - snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); - if (snd_pcm) { - err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap); - if (err < 0) { - dev_err(&hdev->dev, - "chmap control add failed with err: %d for pcm: %d\n", - err, device); - return err; - } - } - - /* add control for ELD Bytes */ - err = hdac_hdmi_create_eld_ctl(component, pcm); - if (err < 0) { - dev_err(&hdev->dev, - "eld control add failed with err: %d for pcm: %d\n", - err, device); - return err; - } - - list_add_tail(&pcm->head, &hdmi->pcm_list); - - return 0; -} -EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init); - static void hdac_hdmi_present_sense_all_pins(struct hdac_device *hdev, struct hdac_hdmi_priv *hdmi, bool detect_pin_caps) { diff --git a/sound/soc/codecs/hdac_hdmi.h b/sound/soc/codecs/hdac_hdmi.h deleted file mode 100644 index 493fa3b4ef75..000000000000 --- a/sound/soc/codecs/hdac_hdmi.h +++ /dev/null @@ -1,10 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __HDAC_HDMI_H__ -#define __HDAC_HDMI_H__ - -int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, - struct snd_soc_jack *jack); - -int hdac_hdmi_jack_port_init(struct snd_soc_component *component, - struct snd_soc_dapm_context *dapm); -#endif /* __HDAC_HDMI_H__ */ From f4c77d5af0a9cd0ee22617baa8b49d0e151fbda7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 6 Jun 2025 01:59:15 +0000 Subject: [PATCH 033/385] ASoC: soc-dai: tidyup return value of snd_soc_xlate_tdm_slot_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 7f1186a8d738661 ("ASoC: soc-dai: check return value at snd_soc_dai_set_tdm_slot()") checks return value of xlate_tdm_slot_mask() (A1)(A2). /* * ... (Y) * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask, * @rx_mask and @slot_width will be ignored. * ... */ int snd_soc_dai_set_tdm_slot(...) { ... if (...) (A1) ret = dai->driver->ops->xlate_tdm_slot_mask(...); else (A2) ret = snd_soc_xlate_tdm_slot_mask(...); if (ret) goto err; ... } snd_soc_xlate_tdm_slot_mask() (A2) will return -EINVAL if slots was 0 (X), but snd_soc_dai_set_tdm_slot() allow to use it (Y). (A) static int snd_soc_xlate_tdm_slot_mask(...) { ... if (!slots) (X) return -EINVAL; ... } Call xlate_tdm_slot_mask() only if slots was non zero. Reported-by: Giedrius Trainavičius Closes: https://lore.kernel.org/r/CAMONXLtSL7iKyvH6w=CzPTxQdBECf++hn8RKL6Y4=M_ou2YHow@mail.gmail.com Fixes: 7f1186a8d738661 ("ASoC: soc-dai: check return value at snd_soc_dai_set_tdm_slot()") Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/8734cdfx59.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-dai.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index a210089747d0..32f46a38682b 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -259,13 +259,15 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, &rx_mask, }; - if (dai->driver->ops && - dai->driver->ops->xlate_tdm_slot_mask) - ret = dai->driver->ops->xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); - else - ret = snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); - if (ret) - goto err; + if (slots) { + if (dai->driver->ops && + dai->driver->ops->xlate_tdm_slot_mask) + ret = dai->driver->ops->xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); + else + ret = snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); + if (ret) + goto err; + } for_each_pcm_streams(stream) snd_soc_dai_tdm_mask_set(dai, stream, *tdm_mask[stream]); From db1a7a6f28b84c5ccd84a800cd4827b5599c95b9 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Wed, 28 May 2025 12:57:54 -0400 Subject: [PATCH 034/385] ASoC: dt-bindings: covert mxs-audio-sgtl5000.txt to yaml format Convert mxs-audio-sgtl5000.txt to yaml format. Additional changes: - Add compatible string: bluegiga,apx4devkit-sgtl5000 denx,m28evk-sgtl5000 fsl,imx28-mbmx28lc-sgtl500 - Remove audio-routing from required list. Signed-off-by: Frank Li Reviewed-by: "Rob Herring (Arm)" Link: https://patch.msgid.link/20250528165755.692264-1-Frank.Li@nxp.com Signed-off-by: Mark Brown --- .../sound/fsl,mxs-audio-sgtl5000.yaml | 81 +++++++++++++++++++ .../bindings/sound/mxs-audio-sgtl5000.txt | 42 ---------- 2 files changed, 81 insertions(+), 42 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/fsl,mxs-audio-sgtl5000.yaml delete mode 100644 Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt diff --git a/Documentation/devicetree/bindings/sound/fsl,mxs-audio-sgtl5000.yaml b/Documentation/devicetree/bindings/sound/fsl,mxs-audio-sgtl5000.yaml new file mode 100644 index 000000000000..d12774b42a11 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,mxs-audio-sgtl5000.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/fsl,mxs-audio-sgtl5000.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale MXS audio complex with SGTL5000 codec + +maintainers: + - Frank Li + +properties: + compatible: + items: + - enum: + - bluegiga,apx4devkit-sgtl5000 + - denx,m28evk-sgtl5000 + - fsl,imx28-evk-sgtl5000 + - fsl,imx28-mbmx28lc-sgtl5000 + - fsl,imx28-tx28-sgtl5000 + - const: fsl,mxs-audio-sgtl5000 + + model: + $ref: /schemas/types.yaml#/definitions/string + description: The user-visible name of this sound complex + + saif-controllers: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: The phandle list of the MXS SAIF controller + + audio-codec: + $ref: /schemas/types.yaml#/definitions/phandle + description: The phandle of the SGTL5000 audio codec + + audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. Valid names could be power supplies, SGTL5000 + pins, and the jacks on the board: + + Power supplies: + * Mic Bias + + SGTL5000 pins: + * MIC_IN + * LINE_IN + * HP_OUT + * LINE_OUT + + Board connectors: + * Mic Jack + * Line In Jack + * Headphone Jack + * Line Out Jack + * Ext Spk + +required: + - compatible + - saif-controllers + - audio-codec + +allOf: + - $ref: dai-common.yaml# + +unevaluatedProperties: false + +examples: + - | + sound { + compatible = "fsl,imx28-evk-sgtl5000", "fsl,mxs-audio-sgtl5000"; + model = "imx28-evk-sgtl5000"; + saif-controllers = <&saif0 &saif1>; + audio-codec = <&sgtl5000>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; + }; diff --git a/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt deleted file mode 100644 index 4eb980bd0287..000000000000 --- a/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt +++ /dev/null @@ -1,42 +0,0 @@ -* Freescale MXS audio complex with SGTL5000 codec - -Required properties: -- compatible : "fsl,mxs-audio-sgtl5000" -- model : The user-visible name of this sound complex -- saif-controllers : The phandle list of the MXS SAIF controller -- audio-codec : The phandle of the SGTL5000 audio codec -- audio-routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the - connection's sink, the second being the connection's - source. Valid names could be power supplies, SGTL5000 - pins, and the jacks on the board: - - Power supplies: - * Mic Bias - - SGTL5000 pins: - * MIC_IN - * LINE_IN - * HP_OUT - * LINE_OUT - - Board connectors: - * Mic Jack - * Line In Jack - * Headphone Jack - * Line Out Jack - * Ext Spk - -Example: - -sound { - compatible = "fsl,imx28-evk-sgtl5000", - "fsl,mxs-audio-sgtl5000"; - model = "imx28-evk-sgtl5000"; - saif-controllers = <&saif0 &saif1>; - audio-codec = <&sgtl5000>; - audio-routing = - "MIC_IN", "Mic Jack", - "Mic Jack", "Mic Bias", - "Headphone Jack", "HP_OUT"; -}; From ac209bde018fd320b79976657a44c23113181af6 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Fri, 23 May 2025 21:11:11 +0800 Subject: [PATCH 035/385] ASoC: tas2781: Drop the unnecessary symbol imply The unnecessary symbols for imply are SND_SOC_TAS2781_COMLIB, SND_SOC_TAS2781_COMLIB_I2C, and SND_SOC_TAS2781_FMWLIB. They all used for library compiling. All the symbols in the imply are used for codec driver compiling. Signed-off-by: Shenghao Ding Link: https://patch.msgid.link/20250523131111.1884-1-shenghao-ding@ti.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 126f897312d4..496a3e4b276f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -263,9 +263,6 @@ config SND_SOC_ALL_CODECS imply SND_SOC_TAS2764 imply SND_SOC_TAS2770 imply SND_SOC_TAS2780 - imply SND_SOC_TAS2781_COMLIB - imply SND_SOC_TAS2781_COMLIB_I2C - imply SND_SOC_TAS2781_FMWLIB imply SND_SOC_TAS2781_I2C imply SND_SOC_TAS5086 imply SND_SOC_TAS571X From bca638aa737d13749a871d1a0d2ed276501ffc54 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Mon, 26 May 2025 17:07:40 +0300 Subject: [PATCH 036/385] ALSA: usb-audio: Fix code alignment in mixer_quirks Format code to fix all alignment issues reported by checkpatch.pl: CHECK: Alignment should match open parenthesis Signed-off-by: Cristian Ciocaltea Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250526-dualsense-alsa-jack-v1-1-1a821463b632@collabora.com --- sound/usb/mixer_quirks.c | 250 ++++++++++++++++++++------------------- 1 file changed, 127 insertions(+), 123 deletions(-) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index aad205df93b2..c05861450465 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -55,13 +55,13 @@ struct std_mono_table { * version, we keep it mono for simplicity. */ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer, - unsigned int unitid, - unsigned int control, - unsigned int cmask, - int val_type, - unsigned int idx_off, - const char *name, - snd_kcontrol_tlv_rw_t *tlv_callback) + unsigned int unitid, + unsigned int control, + unsigned int cmask, + int val_type, + unsigned int idx_off, + const char *name, + snd_kcontrol_tlv_rw_t *tlv_callback) { struct usb_mixer_elem_info *cval; struct snd_kcontrol *kctl; @@ -108,15 +108,16 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer, } static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer, - unsigned int unitid, - unsigned int control, - unsigned int cmask, - int val_type, - const char *name, - snd_kcontrol_tlv_rw_t *tlv_callback) + unsigned int unitid, + unsigned int control, + unsigned int cmask, + int val_type, + const char *name, + snd_kcontrol_tlv_rw_t *tlv_callback) { return snd_create_std_mono_ctl_offset(mixer, unitid, control, cmask, - val_type, 0 /* Offset */, name, tlv_callback); + val_type, 0 /* Offset */, + name, tlv_callback); } /* @@ -129,7 +130,8 @@ static int snd_create_std_mono_table(struct usb_mixer_interface *mixer, while (t->name != NULL) { err = snd_create_std_mono_ctl(mixer, t->unitid, t->control, - t->cmask, t->val_type, t->name, t->tlv_callback); + t->cmask, t->val_type, t->name, + t->tlv_callback); if (err < 0) return err; t++; @@ -214,7 +216,7 @@ static void snd_usb_soundblaster_remote_complete(struct urb *urb) } static long snd_usb_sbrc_hwdep_read(struct snd_hwdep *hw, char __user *buf, - long count, loff_t *offset) + long count, loff_t *offset) { struct usb_mixer_interface *mixer = hw->private_data; int err; @@ -234,7 +236,7 @@ static long snd_usb_sbrc_hwdep_read(struct snd_hwdep *hw, char __user *buf, } static __poll_t snd_usb_sbrc_hwdep_poll(struct snd_hwdep *hw, struct file *file, - poll_table *wait) + poll_table *wait) { struct usb_mixer_interface *mixer = hw->private_data; @@ -310,20 +312,20 @@ static int snd_audigy2nx_led_update(struct usb_mixer_interface *mixer, if (chip->usb_id == USB_ID(0x041e, 0x3042)) err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), 0x24, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, - !value, 0, NULL, 0); + usb_sndctrlpipe(chip->dev, 0), 0x24, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + !value, 0, NULL, 0); /* USB X-Fi S51 Pro */ if (chip->usb_id == USB_ID(0x041e, 0x30df)) err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), 0x24, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, - !value, 0, NULL, 0); + usb_sndctrlpipe(chip->dev, 0), 0x24, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + !value, 0, NULL, 0); else err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), 0x24, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, - value, index + 2, NULL, 0); + usb_sndctrlpipe(chip->dev, 0), 0x24, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + value, index + 2, NULL, 0); snd_usb_unlock_shutdown(chip); return err; } @@ -481,9 +483,9 @@ static int snd_emu0204_ch_switch_update(struct usb_mixer_interface *mixer, buf[0] = 0x01; buf[1] = value ? 0x02 : 0x01; err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - 0x0400, 0x0e00, buf, 2); + usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, + 0x0400, 0x0e00, buf, 2); snd_usb_unlock_shutdown(chip); return err; } @@ -1021,7 +1023,7 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, /* M-Audio FastTrack Ultra quirks */ /* FTU Effect switch (also used by C400/C600) */ static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) + struct snd_ctl_elem_info *uinfo) { static const char *const texts[8] = { "Room 1", "Room 2", "Room 3", "Hall 1", @@ -1055,7 +1057,7 @@ static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer, } static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { ucontrol->value.enumerated.item[0] = kctl->private_value >> 24; return 0; @@ -1086,7 +1088,7 @@ static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list) } static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl); unsigned int pval = list->kctl->private_value; @@ -1104,7 +1106,7 @@ static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, } static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer, - int validx, int bUnitID) + int validx, int bUnitID) { static struct snd_kcontrol_new template = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -1143,22 +1145,22 @@ static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) for (in = 0; in < 8; in++) { cmask = BIT(in); snprintf(name, sizeof(name), - "AIn%d - Out%d Capture Volume", - in + 1, out + 1); + "AIn%d - Out%d Capture Volume", + in + 1, out + 1); err = snd_create_std_mono_ctl(mixer, id, control, - cmask, val_type, name, - &snd_usb_mixer_vol_tlv); + cmask, val_type, name, + &snd_usb_mixer_vol_tlv); if (err < 0) return err; } for (in = 8; in < 16; in++) { cmask = BIT(in); snprintf(name, sizeof(name), - "DIn%d - Out%d Playback Volume", - in - 7, out + 1); + "DIn%d - Out%d Playback Volume", + in - 7, out + 1); err = snd_create_std_mono_ctl(mixer, id, control, - cmask, val_type, name, - &snd_usb_mixer_vol_tlv); + cmask, val_type, name, + &snd_usb_mixer_vol_tlv); if (err < 0) return err; } @@ -1219,10 +1221,10 @@ static int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer) for (ch = 0; ch < 4; ++ch) { cmask = BIT(ch); snprintf(name, sizeof(name), - "Effect Return %d Volume", ch + 1); + "Effect Return %d Volume", ch + 1); err = snd_create_std_mono_ctl(mixer, id, control, - cmask, val_type, name, - snd_usb_mixer_vol_tlv); + cmask, val_type, name, + snd_usb_mixer_vol_tlv); if (err < 0) return err; } @@ -1243,20 +1245,20 @@ static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer) for (ch = 0; ch < 8; ++ch) { cmask = BIT(ch); snprintf(name, sizeof(name), - "Effect Send AIn%d Volume", ch + 1); + "Effect Send AIn%d Volume", ch + 1); err = snd_create_std_mono_ctl(mixer, id, control, cmask, - val_type, name, - snd_usb_mixer_vol_tlv); + val_type, name, + snd_usb_mixer_vol_tlv); if (err < 0) return err; } for (ch = 8; ch < 16; ++ch) { cmask = BIT(ch); snprintf(name, sizeof(name), - "Effect Send DIn%d Volume", ch - 7); + "Effect Send DIn%d Volume", ch - 7); err = snd_create_std_mono_ctl(mixer, id, control, cmask, - val_type, name, - snd_usb_mixer_vol_tlv); + val_type, name, + snd_usb_mixer_vol_tlv); if (err < 0) return err; } @@ -1346,19 +1348,19 @@ static int snd_c400_create_vol_ctls(struct usb_mixer_interface *mixer) for (out = 0; out < num_outs; out++) { if (chan < num_outs) { snprintf(name, sizeof(name), - "PCM%d-Out%d Playback Volume", - chan + 1, out + 1); + "PCM%d-Out%d Playback Volume", + chan + 1, out + 1); } else { snprintf(name, sizeof(name), - "In%d-Out%d Playback Volume", - chan - num_outs + 1, out + 1); + "In%d-Out%d Playback Volume", + chan - num_outs + 1, out + 1); } cmask = (out == 0) ? 0 : BIT(out - 1); offset = chan * num_outs; err = snd_create_std_mono_ctl_offset(mixer, id, control, - cmask, val_type, offset, name, - &snd_usb_mixer_vol_tlv); + cmask, val_type, offset, name, + &snd_usb_mixer_vol_tlv); if (err < 0) return err; } @@ -1377,7 +1379,7 @@ static int snd_c400_create_effect_volume_ctl(struct usb_mixer_interface *mixer) const unsigned int cmask = 0; return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, - name, snd_usb_mixer_vol_tlv); + name, snd_usb_mixer_vol_tlv); } /* This control needs a volume quirk, see mixer.c */ @@ -1390,7 +1392,7 @@ static int snd_c400_create_effect_duration_ctl(struct usb_mixer_interface *mixer const unsigned int cmask = 0; return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, - name, snd_usb_mixer_vol_tlv); + name, snd_usb_mixer_vol_tlv); } /* This control needs a volume quirk, see mixer.c */ @@ -1403,7 +1405,7 @@ static int snd_c400_create_effect_feedback_ctl(struct usb_mixer_interface *mixer const unsigned int cmask = 0; return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, - name, NULL); + name, NULL); } static int snd_c400_create_effect_vol_ctls(struct usb_mixer_interface *mixer) @@ -1432,18 +1434,18 @@ static int snd_c400_create_effect_vol_ctls(struct usb_mixer_interface *mixer) for (chan = 0; chan < num_outs + num_ins; chan++) { if (chan < num_outs) { snprintf(name, sizeof(name), - "Effect Send DOut%d", - chan + 1); + "Effect Send DOut%d", + chan + 1); } else { snprintf(name, sizeof(name), - "Effect Send AIn%d", - chan - num_outs + 1); + "Effect Send AIn%d", + chan - num_outs + 1); } cmask = (chan == 0) ? 0 : BIT(chan - 1); err = snd_create_std_mono_ctl(mixer, id, control, - cmask, val_type, name, - &snd_usb_mixer_vol_tlv); + cmask, val_type, name, + &snd_usb_mixer_vol_tlv); if (err < 0) return err; } @@ -1478,14 +1480,14 @@ static int snd_c400_create_effect_ret_vol_ctls(struct usb_mixer_interface *mixer for (chan = 0; chan < num_outs; chan++) { snprintf(name, sizeof(name), - "Effect Return %d", - chan + 1); + "Effect Return %d", + chan + 1); cmask = (chan == 0) ? 0 : BIT(chan + (chan % 2) * num_outs - 1); err = snd_create_std_mono_ctl_offset(mixer, id, control, - cmask, val_type, offset, name, - &snd_usb_mixer_vol_tlv); + cmask, val_type, offset, name, + &snd_usb_mixer_vol_tlv); if (err < 0) return err; } @@ -1626,7 +1628,7 @@ static const struct std_mono_table ebox44_table[] = { * */ static int snd_microii_spdif_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) + struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; uinfo->count = 1; @@ -1634,7 +1636,7 @@ static int snd_microii_spdif_info(struct snd_kcontrol *kcontrol, } static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); struct snd_usb_audio *chip = list->mixer->chip; @@ -1667,13 +1669,13 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, ep = get_endpoint(alts, 0)->bEndpointAddress; err = snd_usb_ctl_msg(chip->dev, - usb_rcvctrlpipe(chip->dev, 0), - UAC_GET_CUR, - USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, - UAC_EP_CS_ATTR_SAMPLE_RATE << 8, - ep, - data, - sizeof(data)); + usb_rcvctrlpipe(chip->dev, 0), + UAC_GET_CUR, + USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, + UAC_EP_CS_ATTR_SAMPLE_RATE << 8, + ep, + data, + sizeof(data)); if (err < 0) goto end; @@ -1700,26 +1702,26 @@ static int snd_microii_spdif_default_update(struct usb_mixer_elem_list *list) reg = ((pval >> 4) & 0xf0) | (pval & 0x0f); err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), - UAC_SET_CUR, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, - reg, - 2, - NULL, - 0); + usb_sndctrlpipe(chip->dev, 0), + UAC_SET_CUR, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + reg, + 2, + NULL, + 0); if (err < 0) goto end; reg = (pval & IEC958_AES0_NONAUDIO) ? 0xa0 : 0x20; reg |= (pval >> 12) & 0x0f; err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), - UAC_SET_CUR, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, - reg, - 3, - NULL, - 0); + usb_sndctrlpipe(chip->dev, 0), + UAC_SET_CUR, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + reg, + 3, + NULL, + 0); if (err < 0) goto end; @@ -1729,7 +1731,7 @@ static int snd_microii_spdif_default_update(struct usb_mixer_elem_list *list) } static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); unsigned int pval, pval_old; @@ -1756,7 +1758,7 @@ static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol, } static int snd_microii_spdif_mask_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { ucontrol->value.iec958.status[0] = 0x0f; ucontrol->value.iec958.status[1] = 0xff; @@ -1767,7 +1769,7 @@ static int snd_microii_spdif_mask_get(struct snd_kcontrol *kcontrol, } static int snd_microii_spdif_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = !(kcontrol->private_value & 0x02); @@ -1785,20 +1787,20 @@ static int snd_microii_spdif_switch_update(struct usb_mixer_elem_list *list) return err; err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), - UAC_SET_CUR, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, - reg, - 9, - NULL, - 0); + usb_sndctrlpipe(chip->dev, 0), + UAC_SET_CUR, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + reg, + 9, + NULL, + 0); snd_usb_unlock_shutdown(chip); return err; } static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); u8 reg; @@ -1883,9 +1885,9 @@ static int snd_soundblaster_e1_switch_update(struct usb_mixer_interface *mixer, if (err < 0) return err; err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), HID_REQ_SET_REPORT, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, - 0x0202, 3, buff, 2); + usb_sndctrlpipe(chip->dev, 0), HID_REQ_SET_REPORT, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, + 0x0202, 3, buff, 2); snd_usb_unlock_shutdown(chip); return err; } @@ -3235,7 +3237,7 @@ static int snd_rme_digiface_enum_put(struct snd_kcontrol *kcontrol, } static int snd_rme_digiface_current_sync_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { int ret = snd_rme_digiface_enum_get(kcontrol, ucontrol); @@ -3918,7 +3920,7 @@ static const struct snd_djm_device snd_djm_devices[] = { static int snd_djm_controls_info(struct snd_kcontrol *kctl, - struct snd_ctl_elem_info *info) + struct snd_ctl_elem_info *info) { unsigned long private_value = kctl->private_value; u8 device_idx = (private_value & SND_DJM_DEVICE_MASK) >> SND_DJM_DEVICE_SHIFT; @@ -3937,8 +3939,8 @@ static int snd_djm_controls_info(struct snd_kcontrol *kctl, info->value.enumerated.item = noptions - 1; name = snd_djm_get_label(device_idx, - ctl->options[info->value.enumerated.item], - ctl->wIndex); + ctl->options[info->value.enumerated.item], + ctl->wIndex); if (!name) return -EINVAL; @@ -3950,7 +3952,7 @@ static int snd_djm_controls_info(struct snd_kcontrol *kctl, } static int snd_djm_controls_update(struct usb_mixer_interface *mixer, - u8 device_idx, u8 group, u16 value) + u8 device_idx, u8 group, u16 value) { int err; const struct snd_djm_device *device = &snd_djm_devices[device_idx]; @@ -3962,13 +3964,13 @@ static int snd_djm_controls_update(struct usb_mixer_interface *mixer, if (err) return err; - err = snd_usb_ctl_msg( - mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0), - USB_REQ_SET_FEATURE, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - device->controls[group].options[value], - device->controls[group].wIndex, - NULL, 0); + err = snd_usb_ctl_msg(mixer->chip->dev, + usb_sndctrlpipe(mixer->chip->dev, 0), + USB_REQ_SET_FEATURE, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + device->controls[group].options[value], + device->controls[group].wIndex, + NULL, 0); snd_usb_unlock_shutdown(mixer->chip); return err; @@ -4009,7 +4011,7 @@ static int snd_djm_controls_resume(struct usb_mixer_elem_list *list) } static int snd_djm_controls_create(struct usb_mixer_interface *mixer, - const u8 device_idx) + const u8 device_idx) { int err, i; u16 value; @@ -4028,10 +4030,10 @@ static int snd_djm_controls_create(struct usb_mixer_interface *mixer, for (i = 0; i < device->ncontrols; i++) { value = device->controls[i].default_value; knew.name = device->controls[i].name; - knew.private_value = ( + knew.private_value = ((unsigned long)device_idx << SND_DJM_DEVICE_SHIFT) | (i << SND_DJM_GROUP_SHIFT) | - value); + value; err = snd_djm_controls_update(mixer, device_idx, i, value); if (err) return err; @@ -4098,13 +4100,15 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) break; case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */ - err = snd_nativeinstruments_create_mixer(mixer, + err = snd_nativeinstruments_create_mixer(/* checkpatch hack */ + mixer, snd_nativeinstruments_ta6_mixers, ARRAY_SIZE(snd_nativeinstruments_ta6_mixers)); break; case USB_ID(0x17cc, 0x1021): /* Traktor Audio 10 */ - err = snd_nativeinstruments_create_mixer(mixer, + err = snd_nativeinstruments_create_mixer(/* checkpatch hack */ + mixer, snd_nativeinstruments_ta10_mixers, ARRAY_SIZE(snd_nativeinstruments_ta10_mixers)); break; From df6b4dcf2e2c3b4e34c3213a575c92d0c9415d0d Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Mon, 26 May 2025 17:07:41 +0300 Subject: [PATCH 037/385] ALSA: usb-audio: Fix whitespace & blank line issues in mixer_quirks Address all whitespace & blank line(s) related issues reported by checkpatch.pl: ERROR: trailing whitespace ERROR: space required after that ',' (ctx:VxV) WARNING: Missing a blank line after declarations CHECK: Please use a blank line after function/struct/union/enum declarations CHECK: Please don't use multiple blank lines Signed-off-by: Cristian Ciocaltea Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250526-dualsense-alsa-jack-v1-2-1a821463b632@collabora.com --- sound/usb/mixer_quirks.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index c05861450465..ec14b5ee61c2 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -287,7 +287,7 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) mixer->rc_setup_packet->wLength = cpu_to_le16(len); usb_fill_control_urb(mixer->rc_urb, mixer->chip->dev, usb_rcvctrlpipe(mixer->chip->dev, 0), - (u8*)mixer->rc_setup_packet, mixer->rc_buffer, len, + (u8 *)mixer->rc_setup_packet, mixer->rc_buffer, len, snd_usb_soundblaster_remote_complete, mixer); return 0; } @@ -389,7 +389,7 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) mixer->chip->usb_id == USB_ID(0x041e, 0x3042) || mixer->chip->usb_id == USB_ID(0x041e, 0x30df) || mixer->chip->usb_id == USB_ID(0x041e, 0x3048))) - break; + break; knew = snd_audigy2nx_control; knew.name = snd_audigy2nx_led_names[i]; @@ -858,6 +858,7 @@ static const struct snd_kcontrol_new snd_mbox1_src_switch = { static int snd_mbox1_controls_create(struct usb_mixer_interface *mixer) { int err; + err = add_single_ctl_with_resume(mixer, 0, snd_mbox1_clk_switch_resume, &snd_mbox1_clk_switch, NULL); @@ -871,7 +872,7 @@ static int snd_mbox1_controls_create(struct usb_mixer_interface *mixer) /* Native Instruments device quirks */ -#define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex)) +#define _MAKE_NI_CONTROL(bRequest, wIndex) ((bRequest) << 16 | (wIndex)) static int snd_ni_control_init_val(struct usb_mixer_interface *mixer, struct snd_kcontrol *kctl) @@ -2183,6 +2184,7 @@ static const u32 snd_rme_rate_table[] = { 256000, 352800, 384000, 400000, 512000, 705600, 768000, 800000 }; + /* maximum number of items for AES and S/PDIF rates for above table */ #define SND_RME_RATE_IDX_AES_SPDIF_NUM 12 @@ -3271,7 +3273,6 @@ static int snd_rme_digiface_sync_state_get(struct snd_kcontrol *kcontrol, return 0; } - static int snd_rme_digiface_format_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -3283,7 +3284,6 @@ static int snd_rme_digiface_format_info(struct snd_kcontrol *kcontrol, ARRAY_SIZE(format), format); } - static int snd_rme_digiface_sync_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -3566,7 +3566,6 @@ static int snd_rme_digiface_controls_create(struct usb_mixer_interface *mixer) #define SND_DJM_A9_IDX 0x6 #define SND_DJM_V10_IDX 0x7 - #define SND_DJM_CTL(_name, suffix, _default_value, _windex) { \ .name = _name, \ .options = snd_djm_opts_##suffix, \ @@ -3578,7 +3577,6 @@ static int snd_rme_digiface_controls_create(struct usb_mixer_interface *mixer) .controls = snd_djm_ctls_##suffix, \ .ncontrols = ARRAY_SIZE(snd_djm_ctls_##suffix) } - struct snd_djm_device { const char *name; const struct snd_djm_ctl *controls; @@ -3724,7 +3722,6 @@ static const struct snd_djm_ctl snd_djm_ctls_250mk2[] = { SND_DJM_CTL("Output 3 Playback Switch", 250mk2_pb3, 2, SND_DJM_WINDEX_PB) }; - // DJM-450 static const u16 snd_djm_opts_450_cap1[] = { 0x0103, 0x0100, 0x0106, 0x0107, 0x0108, 0x0109, 0x010d, 0x010a }; @@ -3749,7 +3746,6 @@ static const struct snd_djm_ctl snd_djm_ctls_450[] = { SND_DJM_CTL("Output 3 Playback Switch", 450_pb3, 2, SND_DJM_WINDEX_PB) }; - // DJM-750 static const u16 snd_djm_opts_750_cap1[] = { 0x0101, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a, 0x010f }; @@ -3768,7 +3764,6 @@ static const struct snd_djm_ctl snd_djm_ctls_750[] = { SND_DJM_CTL("Input 4 Capture Switch", 750_cap4, 0, SND_DJM_WINDEX_CAP) }; - // DJM-850 static const u16 snd_djm_opts_850_cap1[] = { 0x0100, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a, 0x010f }; @@ -3787,7 +3782,6 @@ static const struct snd_djm_ctl snd_djm_ctls_850[] = { SND_DJM_CTL("Input 4 Capture Switch", 850_cap4, 1, SND_DJM_WINDEX_CAP) }; - // DJM-900NXS2 static const u16 snd_djm_opts_900nxs2_cap1[] = { 0x0100, 0x0102, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a }; @@ -3825,7 +3819,6 @@ static const u16 snd_djm_opts_750mk2_pb1[] = { 0x0100, 0x0101, 0x0104 }; static const u16 snd_djm_opts_750mk2_pb2[] = { 0x0200, 0x0201, 0x0204 }; static const u16 snd_djm_opts_750mk2_pb3[] = { 0x0300, 0x0301, 0x0304 }; - static const struct snd_djm_ctl snd_djm_ctls_750mk2[] = { SND_DJM_CTL("Master Input Level Capture Switch", cap_level, 0, SND_DJM_WINDEX_CAPLVL), SND_DJM_CTL("Input 1 Capture Switch", 750mk2_cap1, 2, SND_DJM_WINDEX_CAP), @@ -3838,7 +3831,6 @@ static const struct snd_djm_ctl snd_djm_ctls_750mk2[] = { SND_DJM_CTL("Output 3 Playback Switch", 750mk2_pb3, 2, SND_DJM_WINDEX_PB) }; - // DJM-A9 static const u16 snd_djm_opts_a9_cap_level[] = { 0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500 }; @@ -3867,29 +3859,35 @@ static const struct snd_djm_ctl snd_djm_ctls_a9[] = { static const u16 snd_djm_opts_v10_cap_level[] = { 0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500 }; + static const u16 snd_djm_opts_v10_cap1[] = { 0x0103, 0x0100, 0x0102, 0x0106, 0x0110, 0x0107, 0x0108, 0x0109, 0x010a, 0x0121, 0x0122 }; + static const u16 snd_djm_opts_v10_cap2[] = { 0x0200, 0x0202, 0x0206, 0x0210, 0x0207, 0x0208, 0x0209, 0x020a, 0x0221, 0x0222 }; + static const u16 snd_djm_opts_v10_cap3[] = { 0x0303, 0x0300, 0x0302, 0x0306, 0x0310, 0x0307, 0x0308, 0x0309, 0x030a, 0x0321, 0x0322 }; + static const u16 snd_djm_opts_v10_cap4[] = { 0x0403, 0x0400, 0x0402, 0x0406, 0x0410, 0x0407, 0x0408, 0x0409, 0x040a, 0x0421, 0x0422 }; + static const u16 snd_djm_opts_v10_cap5[] = { 0x0500, 0x0502, 0x0506, 0x0510, 0x0507, 0x0508, 0x0509, 0x050a, 0x0521, 0x0522 }; + static const u16 snd_djm_opts_v10_cap6[] = { 0x0603, 0x0600, 0x0602, 0x0606, 0x0610, 0x0607, @@ -3918,7 +3916,6 @@ static const struct snd_djm_device snd_djm_devices[] = { [SND_DJM_V10_IDX] = SND_DJM_DEVICE(v10), }; - static int snd_djm_controls_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *info) { @@ -4356,4 +4353,3 @@ void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, (cval->control == UAC_FU_MUTE || cval->control == UAC_FU_VOLUME)) snd_fix_plt_name(mixer->chip, &kctl->id); } - From fd3ab72e42e9871a9902b945a2bf8bb87b49c718 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Mon, 26 May 2025 17:07:42 +0300 Subject: [PATCH 038/385] ALSA: usb-audio: Avoid precedence issues in mixer_quirks macros Fix all macro related issues identified by checkpatch.pl: CHECK: Macro argument 'x' may be better as '(x)' to avoid precedence issues Signed-off-by: Cristian Ciocaltea Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250526-dualsense-alsa-jack-v1-3-1a821463b632@collabora.com --- sound/usb/mixer_quirks.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index ec14b5ee61c2..19abd709c4d7 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -2156,15 +2156,15 @@ static int dell_dock_mixer_init(struct usb_mixer_interface *mixer) #define SND_RME_CLK_FREQMUL_SHIFT 18 #define SND_RME_CLK_FREQMUL_MASK 0x7 #define SND_RME_CLK_SYSTEM(x) \ - ((x >> SND_RME_CLK_SYSTEM_SHIFT) & SND_RME_CLK_SYSTEM_MASK) + (((x) >> SND_RME_CLK_SYSTEM_SHIFT) & SND_RME_CLK_SYSTEM_MASK) #define SND_RME_CLK_AES(x) \ - ((x >> SND_RME_CLK_AES_SHIFT) & SND_RME_CLK_AES_SPDIF_MASK) + (((x) >> SND_RME_CLK_AES_SHIFT) & SND_RME_CLK_AES_SPDIF_MASK) #define SND_RME_CLK_SPDIF(x) \ - ((x >> SND_RME_CLK_SPDIF_SHIFT) & SND_RME_CLK_AES_SPDIF_MASK) + (((x) >> SND_RME_CLK_SPDIF_SHIFT) & SND_RME_CLK_AES_SPDIF_MASK) #define SND_RME_CLK_SYNC(x) \ - ((x >> SND_RME_CLK_SYNC_SHIFT) & SND_RME_CLK_SYNC_MASK) + (((x) >> SND_RME_CLK_SYNC_SHIFT) & SND_RME_CLK_SYNC_MASK) #define SND_RME_CLK_FREQMUL(x) \ - ((x >> SND_RME_CLK_FREQMUL_SHIFT) & SND_RME_CLK_FREQMUL_MASK) + (((x) >> SND_RME_CLK_FREQMUL_SHIFT) & SND_RME_CLK_FREQMUL_MASK) #define SND_RME_CLK_AES_LOCK 0x1 #define SND_RME_CLK_AES_SYNC 0x4 #define SND_RME_CLK_SPDIF_LOCK 0x2 @@ -2173,9 +2173,9 @@ static int dell_dock_mixer_init(struct usb_mixer_interface *mixer) #define SND_RME_SPDIF_FORMAT_SHIFT 5 #define SND_RME_BINARY_MASK 0x1 #define SND_RME_SPDIF_IF(x) \ - ((x >> SND_RME_SPDIF_IF_SHIFT) & SND_RME_BINARY_MASK) + (((x) >> SND_RME_SPDIF_IF_SHIFT) & SND_RME_BINARY_MASK) #define SND_RME_SPDIF_FORMAT(x) \ - ((x >> SND_RME_SPDIF_FORMAT_SHIFT) & SND_RME_BINARY_MASK) + (((x) >> SND_RME_SPDIF_FORMAT_SHIFT) & SND_RME_BINARY_MASK) static const u32 snd_rme_rate_table[] = { 32000, 44100, 48000, 50000, From 231225d8a20f8668b4fd6601d54a2fac0e0ab7a5 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Mon, 26 May 2025 17:07:43 +0300 Subject: [PATCH 039/385] ALSA: usb-audio: Fix block comments in mixer_quirks Address a couple of comment formatting issues indicated by checkpatch.pl: WARNING: Block comments use a trailing */ on a separate line Signed-off-by: Cristian Ciocaltea Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250526-dualsense-alsa-jack-v1-4-1a821463b632@collabora.com --- sound/usb/mixer_quirks.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 19abd709c4d7..5ef8fc714cc3 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -78,7 +78,8 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer, cval->idx_off = idx_off; /* get_min_max() is called only for integer volumes later, - * so provide a short-cut for booleans */ + * so provide a short-cut for booleans + */ cval->min = 0; cval->max = 1; cval->res = 0; @@ -4255,7 +4256,8 @@ static void snd_dragonfly_quirk_db_scale(struct usb_mixer_interface *mixer, struct snd_kcontrol *kctl) { /* Approximation using 10 ranges based on output measurement on hw v1.2. - * This seems close to the cubic mapping e.g. alsamixer uses. */ + * This seems close to the cubic mapping e.g. alsamixer uses. + */ static const DECLARE_TLV_DB_RANGE(scale, 0, 1, TLV_DB_MINMAX_ITEM(-5300, -4970), 2, 5, TLV_DB_MINMAX_ITEM(-4710, -4160), From c0495cef8b43ad61efbd4019e3573742e0e63c67 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Mon, 26 May 2025 17:07:44 +0300 Subject: [PATCH 040/385] ALSA: usb-audio: Drop unnecessary parentheses in mixer_quirks Fix multiple 'CHECK: Unnecessary parentheses around ...' reports from checkpatch.pl. Signed-off-by: Cristian Ciocaltea Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250526-dualsense-alsa-jack-v1-5-1a821463b632@collabora.com --- sound/usb/mixer_quirks.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 5ef8fc714cc3..071a76554d09 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -380,10 +380,10 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) struct snd_kcontrol_new knew; /* USB X-Fi S51 doesn't have a CMSS LED */ - if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0) + if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042) && i == 0) continue; /* USB X-Fi S51 Pro doesn't have one either */ - if ((mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) && i == 0) + if (mixer->chip->usb_id == USB_ID(0x041e, 0x30df) && i == 0) continue; if (i > 1 && /* Live24ext has 2 LEDs only */ (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || @@ -3955,7 +3955,7 @@ static int snd_djm_controls_update(struct usb_mixer_interface *mixer, int err; const struct snd_djm_device *device = &snd_djm_devices[device_idx]; - if ((group >= device->ncontrols) || value >= device->controls[group].noptions) + if (group >= device->ncontrols || value >= device->controls[group].noptions) return -EINVAL; err = snd_usb_lock_shutdown(mixer->chip); From 03ddd3bdb94df3edb1f2408b57cfb00b3d92a208 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Mon, 26 May 2025 17:07:45 +0300 Subject: [PATCH 041/385] ALSA: usb-audio: Avoid multiple assignments in mixer_quirks Handle report from checkpatch.pl: CHECK: multiple assignments should be avoided Signed-off-by: Cristian Ciocaltea Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250526-dualsense-alsa-jack-v1-6-1a821463b632@collabora.com --- sound/usb/mixer_quirks.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 071a76554d09..17c9cbbfce22 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -1739,7 +1739,8 @@ static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol, unsigned int pval, pval_old; int err; - pval = pval_old = kcontrol->private_value; + pval = kcontrol->private_value; + pval_old = pval; pval &= 0xfffff0f0; pval |= (ucontrol->value.iec958.status[1] & 0x0f) << 8; pval |= (ucontrol->value.iec958.status[0] & 0x0f); From f2d6d660e8fd5f4467e80743f82119201e67fa9c Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Mon, 26 May 2025 17:07:46 +0300 Subject: [PATCH 042/385] ALSA: usb-audio: Simplify NULL comparison in mixer_quirks Handle report from checkpatch.pl: CHECK: Comparison to NULL could be written "t->name" Signed-off-by: Cristian Ciocaltea Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250526-dualsense-alsa-jack-v1-7-1a821463b632@collabora.com --- sound/usb/mixer_quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 17c9cbbfce22..783789cbcfe2 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -129,7 +129,7 @@ static int snd_create_std_mono_table(struct usb_mixer_interface *mixer, { int err; - while (t->name != NULL) { + while (t->name) { err = snd_create_std_mono_ctl(mixer, t->unitid, t->control, t->cmask, t->val_type, t->name, t->tlv_callback); From 9cea7425595697802e8d55a322a251999554b8b1 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Mon, 26 May 2025 17:07:47 +0300 Subject: [PATCH 043/385] ALSA: usb-audio: Remove unneeded wmb() in mixer_quirks Adding a memory barrier before wake_up() in snd_usb_soundblaster_remote_complete() is supposed to ensure the write to mixer->rc_code is visible in wait_event_interruptible() from snd_usb_sbrc_hwdep_read(). However, this is not really necessary, since wake_up() is just a wrapper over __wake_up() which already executes a full memory barrier before accessing the state of the task to be waken up. Drop the redundant call to wmb() and implicitly fix the checkpatch complaint: WARNING: memory barrier without comment Signed-off-by: Cristian Ciocaltea Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250526-dualsense-alsa-jack-v1-8-1a821463b632@collabora.com --- sound/usb/mixer_quirks.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 783789cbcfe2..ffda3b8d42cc 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -212,7 +212,6 @@ static void snd_usb_soundblaster_remote_complete(struct urb *urb) if (code == rc->mute_code) snd_usb_mixer_notify_id(mixer, rc->mute_mixer_id); mixer->rc_code = code; - wmb(); wake_up(&mixer->rc_waitq); } From 79d561c4ec0497669f19a9550cfb74812f60938b Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Mon, 26 May 2025 17:07:48 +0300 Subject: [PATCH 044/385] ALSA: usb-audio: Add mixer quirk for Sony DualSense PS5 The Sony DualSense wireless controller (PS5) features an internal mono speaker, but it also provides a 3.5mm jack socket for headphone output and headset microphone input. Since this is a UAC1 device, it doesn't advertise any jack detection capability. However, the controller is able to report HP & MIC insert events via HID, i.e. through a dedicated input device managed by the hid-playstation driver. Add a quirk to create the jack controls for headphone and headset mic, respectively, and setup an input handler for each of them in order to intercept the related hotplug events. Signed-off-by: Cristian Ciocaltea Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250526-dualsense-alsa-jack-v1-9-1a821463b632@collabora.com --- sound/usb/mixer_quirks.c | 263 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index ffda3b8d42cc..0769ecd91144 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -531,6 +532,263 @@ static int snd_emu0204_controls_create(struct usb_mixer_interface *mixer) &snd_emu0204_control, NULL); } +/* + * Sony DualSense controller (PS5) jack detection + * + * Since this is an UAC 1 device, it doesn't support jack detection. + * However, the controller hid-playstation driver reports HP & MIC + * insert events through a dedicated input device. + */ + +#define SND_DUALSENSE_JACK_OUT_TERM_ID 3 +#define SND_DUALSENSE_JACK_IN_TERM_ID 4 + +struct dualsense_mixer_elem_info { + struct usb_mixer_elem_info info; + struct input_handler ih; + struct input_device_id id_table[2]; + bool connected; +}; + +static void snd_dualsense_ih_event(struct input_handle *handle, + unsigned int type, unsigned int code, + int value) +{ + struct dualsense_mixer_elem_info *mei; + struct usb_mixer_elem_list *me; + + if (type != EV_SW) + return; + + mei = container_of(handle->handler, struct dualsense_mixer_elem_info, ih); + me = &mei->info.head; + + if ((me->id == SND_DUALSENSE_JACK_OUT_TERM_ID && code == SW_HEADPHONE_INSERT) || + (me->id == SND_DUALSENSE_JACK_IN_TERM_ID && code == SW_MICROPHONE_INSERT)) { + mei->connected = !!value; + snd_ctl_notify(me->mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &me->kctl->id); + } +} + +static bool snd_dualsense_ih_match(struct input_handler *handler, + struct input_dev *dev) +{ + struct dualsense_mixer_elem_info *mei; + struct usb_device *snd_dev; + char *input_dev_path, *usb_dev_path; + size_t usb_dev_path_len; + bool match = false; + + mei = container_of(handler, struct dualsense_mixer_elem_info, ih); + snd_dev = mei->info.head.mixer->chip->dev; + + input_dev_path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); + if (!input_dev_path) { + dev_warn(&snd_dev->dev, "Failed to get input dev path\n"); + return false; + } + + usb_dev_path = kobject_get_path(&snd_dev->dev.kobj, GFP_KERNEL); + if (!usb_dev_path) { + dev_warn(&snd_dev->dev, "Failed to get USB dev path\n"); + goto free_paths; + } + + /* + * Ensure the VID:PID matched input device supposedly owned by the + * hid-playstation driver belongs to the actual hardware handled by + * the current USB audio device, which implies input_dev_path being + * a subpath of usb_dev_path. + * + * This verification is necessary when there is more than one identical + * controller attached to the host system. + */ + usb_dev_path_len = strlen(usb_dev_path); + if (usb_dev_path_len >= strlen(input_dev_path)) + goto free_paths; + + usb_dev_path[usb_dev_path_len] = '/'; + match = !memcmp(input_dev_path, usb_dev_path, usb_dev_path_len + 1); + +free_paths: + kfree(input_dev_path); + kfree(usb_dev_path); + + return match; +} + +static int snd_dualsense_ih_connect(struct input_handler *handler, + struct input_dev *dev, + const struct input_device_id *id) +{ + struct input_handle *handle; + int err; + + handle = kzalloc(sizeof(*handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = handler->name; + + err = input_register_handle(handle); + if (err) + goto err_free; + + err = input_open_device(handle); + if (err) + goto err_unregister; + + return 0; + +err_unregister: + input_unregister_handle(handle); +err_free: + kfree(handle); + return err; +} + +static void snd_dualsense_ih_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static void snd_dualsense_ih_start(struct input_handle *handle) +{ + struct dualsense_mixer_elem_info *mei; + struct usb_mixer_elem_list *me; + int status = -1; + + mei = container_of(handle->handler, struct dualsense_mixer_elem_info, ih); + me = &mei->info.head; + + if (me->id == SND_DUALSENSE_JACK_OUT_TERM_ID && + test_bit(SW_HEADPHONE_INSERT, handle->dev->swbit)) + status = test_bit(SW_HEADPHONE_INSERT, handle->dev->sw); + else if (me->id == SND_DUALSENSE_JACK_IN_TERM_ID && + test_bit(SW_MICROPHONE_INSERT, handle->dev->swbit)) + status = test_bit(SW_MICROPHONE_INSERT, handle->dev->sw); + + if (status >= 0) { + mei->connected = !!status; + snd_ctl_notify(me->mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &me->kctl->id); + } +} + +static int snd_dualsense_jack_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct dualsense_mixer_elem_info *mei = snd_kcontrol_chip(kctl); + + ucontrol->value.integer.value[0] = mei->connected; + + return 0; +} + +static const struct snd_kcontrol_new snd_dualsense_jack_control = { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .info = snd_ctl_boolean_mono_info, + .get = snd_dualsense_jack_get, +}; + +static int snd_dualsense_resume_jack(struct usb_mixer_elem_list *list) +{ + snd_ctl_notify(list->mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &list->kctl->id); + return 0; +} + +static void snd_dualsense_mixer_elem_free(struct snd_kcontrol *kctl) +{ + struct dualsense_mixer_elem_info *mei = snd_kcontrol_chip(kctl); + + if (mei->ih.event) + input_unregister_handler(&mei->ih); + + snd_usb_mixer_elem_free(kctl); +} + +static int snd_dualsense_jack_create(struct usb_mixer_interface *mixer, + const char *name, bool is_output) +{ + struct dualsense_mixer_elem_info *mei; + struct input_device_id *idev_id; + struct snd_kcontrol *kctl; + int err; + + mei = kzalloc(sizeof(*mei), GFP_KERNEL); + if (!mei) + return -ENOMEM; + + snd_usb_mixer_elem_init_std(&mei->info.head, mixer, + is_output ? SND_DUALSENSE_JACK_OUT_TERM_ID : + SND_DUALSENSE_JACK_IN_TERM_ID); + + mei->info.head.resume = snd_dualsense_resume_jack; + mei->info.val_type = USB_MIXER_BOOLEAN; + mei->info.channels = 1; + mei->info.min = 0; + mei->info.max = 1; + + kctl = snd_ctl_new1(&snd_dualsense_jack_control, mei); + if (!kctl) { + kfree(mei); + return -ENOMEM; + } + + strscpy(kctl->id.name, name, sizeof(kctl->id.name)); + kctl->private_free = snd_dualsense_mixer_elem_free; + + err = snd_usb_mixer_add_control(&mei->info.head, kctl); + if (err) + return err; + + idev_id = &mei->id_table[0]; + idev_id->flags = INPUT_DEVICE_ID_MATCH_VENDOR | INPUT_DEVICE_ID_MATCH_PRODUCT | + INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT; + idev_id->vendor = USB_ID_VENDOR(mixer->chip->usb_id); + idev_id->product = USB_ID_PRODUCT(mixer->chip->usb_id); + idev_id->evbit[BIT_WORD(EV_SW)] = BIT_MASK(EV_SW); + if (is_output) + idev_id->swbit[BIT_WORD(SW_HEADPHONE_INSERT)] = BIT_MASK(SW_HEADPHONE_INSERT); + else + idev_id->swbit[BIT_WORD(SW_MICROPHONE_INSERT)] = BIT_MASK(SW_MICROPHONE_INSERT); + + mei->ih.event = snd_dualsense_ih_event; + mei->ih.match = snd_dualsense_ih_match; + mei->ih.connect = snd_dualsense_ih_connect, + mei->ih.disconnect = snd_dualsense_ih_disconnect, + mei->ih.start = snd_dualsense_ih_start, + mei->ih.name = name; + mei->ih.id_table = mei->id_table; + + err = input_register_handler(&mei->ih); + if (err) { + dev_warn(&mixer->chip->dev->dev, + "Could not register input handler: %d\n", err); + mei->ih.event = NULL; + } + + return 0; +} + +static int snd_dualsense_controls_create(struct usb_mixer_interface *mixer) +{ + int err; + + err = snd_dualsense_jack_create(mixer, "Headphone Jack", true); + if (err < 0) + return err; + + return snd_dualsense_jack_create(mixer, "Headset Mic Jack", false); +} + /* ASUS Xonar U1 / U3 controls */ static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol, @@ -4073,6 +4331,11 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) err = snd_emu0204_controls_create(mixer); break; + case USB_ID(0x054c, 0x0ce6): /* Sony DualSense controller (PS5) */ + case USB_ID(0x054c, 0x0df2): /* Sony DualSense Edge controller (PS5) */ + err = snd_dualsense_controls_create(mixer); + break; + case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C400 */ err = snd_c400_create_mixer(mixer); From 9955ea2e3698411fc798b2056facdf3f6e56aa61 Mon Sep 17 00:00:00 2001 From: Baojun Xu Date: Mon, 2 Jun 2025 09:58:09 +0800 Subject: [PATCH 045/385] ALSA: hda/tas2781: Add missed brace and hardware id re-order This patch is do code clean and prepare for next patch, which is relative with hardware id. Signed-off-by: Baojun Xu Link: https://patch.msgid.link/20250602015809.20344-1-baojun.xu@ti.com Signed-off-by: Takashi Iwai --- sound/pci/hda/tas2781_hda_i2c.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index d91eed9f7804..eb2295b490d9 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -591,8 +591,9 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt) device_name = "INT8866"; hda_priv->save_calibration = tas2563_save_calibration; tas_hda->priv->global_addr = TAS2563_GLOBAL_ADDR; - } else + } else { return -ENODEV; + } tas_hda->priv->irq = clt->irq; ret = tas2781_read_acpi(tas_hda->priv, device_name); @@ -722,8 +723,8 @@ static const struct i2c_device_id tas2781_hda_i2c_id[] = { }; static const struct acpi_device_id tas2781_acpi_hda_match[] = { - {"TIAS2781", 0 }, {"INT8866", 0 }, + {"TIAS2781", 0 }, {} }; MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match); From ed57a3d5a3118b9681de607692608fe573c5959d Mon Sep 17 00:00:00 2001 From: Lucy Thrun Date: Tue, 3 Jun 2025 14:53:04 +0200 Subject: [PATCH 046/385] ALSA: hda/ca0132: Enable hardware band EQ for Sound Blaster Core3D This patch enables the Hardware DSP-based 10-band hardware equalizer on Sound Blaster Core3D (CA0132) based cards for example the soundblaster z and soundblaster x-ae5, allowing fine-grained audio tuning via hardware registers. Tested on Sound Blaster X-AE5. No regressions observed. Signed-off-by: Lucy Thrun Link: https://patch.msgid.link/20250603125304.507-1-lucy.thrun@digital-rabbithole.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index d40197fb5fbd..cfe422a79703 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -28,7 +28,7 @@ #include "ca0132_regs.h" /* Enable this to see controls for tuning purpose. */ -/*#define ENABLE_TUNING_CONTROLS*/ +#define ENABLE_TUNING_CONTROLS #ifdef ENABLE_TUNING_CONTROLS #include From 92f59aeb13252265c20e7aef1379a8080c57e0a2 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 6 Jun 2025 11:44:02 +0200 Subject: [PATCH 047/385] ALSA: pcm: Rewrite recalculate_boundary() to avoid costly loop At the time being recalculate_boundary() is implemented with a loop which shows up as costly in a perf profile, as depicted by the annotate below: 0.00 : c057e934: 3d 40 7f ff lis r10,32767 0.03 : c057e938: 61 4a ff ff ori r10,r10,65535 0.21 : c057e93c: 7d 49 50 50 subf r10,r9,r10 5.39 : c057e940: 7d 3c 4b 78 mr r28,r9 2.11 : c057e944: 55 29 08 3c slwi r9,r9,1 3.04 : c057e948: 7c 09 50 40 cmplw r9,r10 2.47 : c057e94c: 40 81 ff f4 ble c057e940 Total: 13.2% on that simple loop. But what the loop does is to multiply the boundary by 2 until it is over the wanted border. This can be avoided by using fls() to get the boundary value order and shift it by the appropriate number of bits at once. This change provides the following profile: 0.04 : c057f6e8: 3d 20 7f ff lis r9,32767 0.02 : c057f6ec: 61 29 ff ff ori r9,r9,65535 0.34 : c057f6f0: 7d 5a 48 50 subf r10,r26,r9 0.23 : c057f6f4: 7c 1a 50 40 cmplw r26,r10 0.02 : c057f6f8: 41 81 00 20 bgt c057f718 0.26 : c057f6fc: 7f 47 00 34 cntlzw r7,r26 0.09 : c057f700: 7d 48 00 34 cntlzw r8,r10 0.22 : c057f704: 7d 08 38 50 subf r8,r8,r7 0.04 : c057f708: 7f 5a 40 30 slw r26,r26,r8 0.35 : c057f70c: 7c 0a d0 40 cmplw r10,r26 0.13 : c057f710: 40 80 05 f8 bge c057fd08 0.00 : c057f714: 57 5a f8 7e srwi r26,r26,1 Total: 1.7% with that loopless alternative. Signed-off-by: Christophe Leroy Link: https://patch.msgid.link/4836e2cde653eebaf2709ebe30eec736bb8c67fd.1749202237.git.christophe.leroy@csgroup.eu Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 853ac5bb33ff..ecb71bf1859d 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "pcm_local.h" @@ -3130,13 +3131,23 @@ struct snd_pcm_sync_ptr32 { static snd_pcm_uframes_t recalculate_boundary(struct snd_pcm_runtime *runtime) { snd_pcm_uframes_t boundary; + snd_pcm_uframes_t border; + int order; if (! runtime->buffer_size) return 0; - boundary = runtime->buffer_size; - while (boundary * 2 <= 0x7fffffffUL - runtime->buffer_size) - boundary *= 2; - return boundary; + + border = 0x7fffffffUL - runtime->buffer_size; + if (runtime->buffer_size > border) + return runtime->buffer_size; + + order = __fls(border) - __fls(runtime->buffer_size); + boundary = runtime->buffer_size << order; + + if (boundary <= border) + return boundary; + else + return boundary / 2; } static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream, From 5c694e3a83d089df6b00747cf4627735ea14014e Mon Sep 17 00:00:00 2001 From: ChiYuan Huang Date: Mon, 9 Jun 2025 15:47:27 +0800 Subject: [PATCH 048/385] ASoC: dt-bindings: rt9123: Append RTQ9124 description Document the ASoC Richtek RTQ9124 in existed RT9123 file. Signed-off-by: ChiYuan Huang Link: https://patch.msgid.link/9921d64ce4d63c24499f92ef33a4ce7cb018c60b.1749454717.git.cy_huang@richtek.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/richtek,rt9123.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/richtek,rt9123.yaml b/Documentation/devicetree/bindings/sound/richtek,rt9123.yaml index 5acb05cdfefd..819ca06203b1 100644 --- a/Documentation/devicetree/bindings/sound/richtek,rt9123.yaml +++ b/Documentation/devicetree/bindings/sound/richtek,rt9123.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/sound/richtek,rt9123.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Richtek RT9123 Audio Amplifier +title: Richtek RT9123/RTQ9124 Audio Amplifier maintainers: - ChiYuan Huang @@ -15,6 +15,12 @@ description: support various formats, including I2S, left-justified, right-justified, and TDM formats. + RTQ9124 is an ultra-low output noise, digital input, mono-channel Class-D + power amplifier that supports a 2.1MHz switching frequency. It integrates + both DC and AC load diagnostics, as well as real-time load monitoring to + assess speaker condition. The device operates from 4.5V to 18V and delivers + up to 30W output power. + allOf: - $ref: dai-common.yaml# @@ -22,6 +28,7 @@ properties: compatible: enum: - richtek,rt9123 + - richtek,rtq9124 reg: maxItems: 1 From 1f5cdb6ab45e1c06ae0953609acbb52f8946b3e8 Mon Sep 17 00:00:00 2001 From: ChiYuan Huang Date: Mon, 9 Jun 2025 15:47:28 +0800 Subject: [PATCH 049/385] ASoC: codecs: Add support for Richtek RTQ9124 Add codecs driver for Richtek RTQ9124. Signed-off-by: ChiYuan Huang Link: https://patch.msgid.link/aca49d1912bfd1b90e82146df6393760a731810c.1749454717.git.cy_huang@richtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 9 + sound/soc/codecs/Makefile | 4 +- sound/soc/codecs/rtq9124.c | 543 +++++++++++++++++++++++++++++++++++++ 3 files changed, 555 insertions(+), 1 deletion(-) create mode 100644 sound/soc/codecs/rtq9124.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 126f897312d4..d0c01f49a8ba 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -238,6 +238,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT1320_SDW imply SND_SOC_RT9120 imply SND_SOC_RT9123 + imply SND_SOC_RTQ9124 imply SND_SOC_RTQ9128 imply SND_SOC_SDW_MOCKUP imply SND_SOC_SGTL5000 @@ -1858,6 +1859,14 @@ config SND_SOC_RT9123P Enable support for the HW control mode of Richtek RT9123P 3.2W mono Class-D audio amplifier. +config SND_SOC_RTQ9124 + tristate "Richtek RTQ9124 Mono Class-D Amplifier" + depends on I2C + select REGMAP + help + Enable support for Richtek RTQ9124 1x30W digital input automotive + audio amplifier with current sense and real-time load diagnostics. + config SND_SOC_RTQ9128 tristate "Richtek RTQ9128 45W Digital Input Amplifier" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 6d7aa109ede7..a68c3d192a1b 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -275,6 +275,7 @@ snd-soc-rt722-sdca-y := rt722-sdca.o rt722-sdca-sdw.o snd-soc-rt9120-y := rt9120.o snd-soc-rt9123-y := rt9123.o snd-soc-rt9123p-y := rt9123p.o +snd-soc-rtq9124-y := rtq9124.o snd-soc-rtq9128-y := rtq9128.o snd-soc-sdw-mockup-y := sdw-mockup.o snd-soc-sgtl5000-y := sgtl5000.o @@ -695,6 +696,7 @@ obj-$(CONFIG_SND_SOC_RT722_SDCA_SDW) += snd-soc-rt722-sdca.o obj-$(CONFIG_SND_SOC_RT9120) += snd-soc-rt9120.o obj-$(CONFIG_SND_SOC_RT9123) += snd-soc-rt9123.o obj-$(CONFIG_SND_SOC_RT9123P) += snd-soc-rt9123p.o +obj-$(CONFIG_SND_SOC_RTQ9124) += snd-soc-rtq9124.o obj-$(CONFIG_SND_SOC_RTQ9128) += snd-soc-rtq9128.o obj-$(CONFIG_SND_SOC_SDW_MOCKUP) += snd-soc-sdw-mockup.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o @@ -853,4 +855,4 @@ obj-$(CONFIG_SND_SOC_LPASS_RX_MACRO) += snd-soc-lpass-rx-macro.o obj-$(CONFIG_SND_SOC_LPASS_TX_MACRO) += snd-soc-lpass-tx-macro.o # Mux -obj-$(CONFIG_SND_SOC_SIMPLE_MUX) += snd-soc-simple-mux.o \ No newline at end of file +obj-$(CONFIG_SND_SOC_SIMPLE_MUX) += snd-soc-simple-mux.o diff --git a/sound/soc/codecs/rtq9124.c b/sound/soc/codecs/rtq9124.c new file mode 100644 index 000000000000..186904b31434 --- /dev/null +++ b/sound/soc/codecs/rtq9124.c @@ -0,0 +1,543 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rtq9124.c -- RTQ9124 ALSA SoC Codec driver +// +// Author: ChiYuan Huang + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RTQ9124_REG_SDI_SEL 0x00 +#define RTQ9124_REG_SDO_SEL 0x01 +#define RTQ9124_REG_I2S_OPT 0x02 +#define RTQ9124_REG_AMP_OPT 0x03 +#define RTQ9124_REG_STATE_CTRL 0x04 +#define RTQ9124_REG_PWM_PHASE 0x05 +#define RTQ9124_REG_SIL_CTRL 0x06 +#define RTQ9124_REG_PWM_SS_OPT 0x07 +#define RTQ9124_REG_ERR_INT_0 0x10 +#define RTQ9124_REG_ERR_MASK6 0x26 +#define RTQ9124_REG_TDM_TX_CH0 0x32 +#define RTQ9124_REG_TDM_RX_CH0 0x34 +#define RTQ9124_REG_VOL_OPT 0x38 +#define RTQ9124_REG_DCR_TH 0x4B +#define RTQ9124_REG_ERR_TH 0x4C +#define RTQ9124_REG_PROT_EN 0x5B +#define RTQ9124_REG_PRJ_CODE 0xF9 + +#define RTQ9124_MASK_CS_DATA_INV BIT(9) +#define RTQ9124_MASK_VDDIO_SDO_SEL BIT(8) +#define RTQ9124_MASK_AUD_BITS GENMASK(5, 4) +#define RTQ9124_MASK_AUD_FMT GENMASK(3, 0) +#define RTQ9124_MASK_CH_STATE GENMASK(1, 0) +#define RTQ9124_MASK_SF_RESET BIT(15) + +#define RTQ9124_FIXED_VENID 0x9124 + +struct rtq9124_priv { + struct gpio_desc *enable; + unsigned int dai_fmt; + int tdm_slots; + int tdm_slot_width; +}; + +static int rtq9124_enable_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + unsigned int i, chan_state; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* Change state to normal */ + chan_state = 0; + break; + case SND_SOC_DAPM_POST_PMD: + /* Change state to HiZ */ + chan_state = 1; + break; + default: + return -EINVAL; + } + + /* Before amp turn on, clear old events first */ + for (i = 0; !chan_state && i < 8; i++) + snd_soc_component_write(comp, RTQ9124_REG_ERR_INT_0 + i, 0xffff); + + snd_soc_component_write_field(comp, RTQ9124_REG_STATE_CTRL, RTQ9124_MASK_CH_STATE, + chan_state); + + return 0; +} + +static const struct snd_soc_dapm_widget rtq9124_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("SPK"), + SND_SOC_DAPM_OUT_DRV_E("Amp Drv", SND_SOC_NOPM, 0, 0, NULL, 0, rtq9124_enable_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route rtq9124_dapm_routes[] = { + { "Amp Drv", NULL, "HiFi Playback" }, + { "SPK", NULL, "Amp Drv" }, +}; + +static const DECLARE_TLV_DB_SCALE(dig_tlv, -10375, 25, 0); +static const DECLARE_TLV_DB_RANGE(ana_tlv, + 0, 3, TLV_DB_SCALE_ITEM(-600, 600, 0), + 4, 6, TLV_DB_SCALE_ITEM(1400, 200, 0)); +static const char * const i2sch_text[] = { "(L+R)/2", "LCH", "RCH", "(L+R)/2" }; +static const struct soc_enum rtq9124_i2sch_select_enum = + SOC_ENUM_SINGLE(RTQ9124_REG_SDI_SEL, 0, ARRAY_SIZE(i2sch_text), i2sch_text); +static const char * const sdo_vsel_text[] = { "1.8V", "3.3V" }; +static const struct soc_enum rtq9124_sdo_vselect_enum = + SOC_ENUM_SINGLE(RTQ9124_REG_SDO_SEL, 8, ARRAY_SIZE(sdo_vsel_text), sdo_vsel_text); +static const char * const pwmfreq_text[] = { "8*fs", "10*fs", "40*fs", "44*fs", "48*fs" }; +static const struct soc_enum rtq9124_pwm_freq_enum = + SOC_ENUM_SINGLE(RTQ9124_REG_AMP_OPT, 4, ARRAY_SIZE(pwmfreq_text), pwmfreq_text); +static const char * const out_angle_text[] = { "0", "45", "90", "135", "180", "225", "270", "315" }; +static const struct soc_enum rtq9124_out_angle_enum = + SOC_ENUM_SINGLE(RTQ9124_REG_PWM_PHASE, 0, ARRAY_SIZE(out_angle_text), out_angle_text); +static const char * const sdo_select_text[] = { + "None", "I2S DataI", "Interface", "DSP", "DF", "ISense", "ACLoad Cos", "ACLoad Sin", + "DCR", +}; +static const struct soc_enum rtq9124_sdo_select_enum = + SOC_ENUM_DOUBLE(RTQ9124_REG_SDO_SEL, 4, 0, ARRAY_SIZE(sdo_select_text), sdo_select_text); +static const char * const ulqm_dcvt_text[] = { "Disable", "DC", "VT", "DC+VT" }; +static const struct soc_enum rtq9124_ulqm_dcvt_select_enum = + SOC_ENUM_SINGLE(RTQ9124_REG_STATE_CTRL, 10, ARRAY_SIZE(ulqm_dcvt_text), ulqm_dcvt_text); + +static const struct snd_kcontrol_new rtq9124_controls[] = { + SOC_SINGLE_TLV("Master Volume", RTQ9124_REG_VOL_OPT, 2, 511, 1, dig_tlv), + SOC_SINGLE_TLV("Speaker Volume", RTQ9124_REG_AMP_OPT, 0, 6, 0, ana_tlv), + SOC_ENUM("I2S CH Select", rtq9124_i2sch_select_enum), + SOC_ENUM("SDO VDDIO Select", rtq9124_sdo_vselect_enum), + SOC_ENUM("PWM Frequency Select", rtq9124_pwm_freq_enum), + SOC_ENUM("PWM Output Phase Select", rtq9124_out_angle_enum), + SOC_ENUM("SDO Select", rtq9124_sdo_select_enum), + SOC_ENUM("ULQM DCVT Select", rtq9124_ulqm_dcvt_select_enum), + SOC_SINGLE("Silence Detect Enable Switch", RTQ9124_REG_SIL_CTRL, 7, 1, 0), + SOC_SINGLE("Spread Spectrum Enable Switch", RTQ9124_REG_PWM_SS_OPT, 7, 1, 0), +}; + +static int rtq9124_comp_probe(struct snd_soc_component *comp) +{ + /* CS Data INV */ + snd_soc_component_write_field(comp, RTQ9124_REG_SDO_SEL, RTQ9124_MASK_CS_DATA_INV, 1); + + /* RTLD */ + snd_soc_component_write(comp, RTQ9124_REG_DCR_TH, 0x5e30); + snd_soc_component_write(comp, RTQ9124_REG_ERR_TH, 0x3ff); + snd_soc_component_write(comp, RTQ9124_REG_PROT_EN, 0x3fc); + snd_soc_component_write(comp, RTQ9124_REG_ERR_MASK6, 0); + + return 0; +} + +static const struct snd_soc_component_driver rtq9124_comp_driver = { + .probe = rtq9124_comp_probe, + .controls = rtq9124_controls, + .num_controls = ARRAY_SIZE(rtq9124_controls), + .dapm_widgets = rtq9124_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rtq9124_dapm_widgets), + .dapm_routes = rtq9124_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rtq9124_dapm_routes), + .use_pmdown_time = 1, + .endianness = 1, +}; + +static int rtq9124_dai_set_format(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct rtq9124_priv *rtq9124 = snd_soc_dai_get_drvdata(dai); + + rtq9124->dai_fmt = fmt; + return 0; +} + +static int rtq9124_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct rtq9124_priv *rtq9124 = snd_soc_dai_get_drvdata(dai); + struct snd_soc_component *comp = dai->component; + struct device *dev = dai->dev; + unsigned int byte_loc, i; + + dev_dbg(dev, "(slots, slot_width) = (%d, %d), (txmask, rxmask) = 0x%x, 0x%x\n", slots, + slot_width, tx_mask, rx_mask); + + if (slots <= 0 || slots > 16 || slot_width <= 0 || slots % 2 || slot_width % 8) { + dev_err(dev, "Invalid slot parameter (%d, %d)\n", slots, slot_width); + return -EINVAL; + } + + if (tx_mask && (hweight_long(tx_mask) > 2 || fls(tx_mask) > slots)) { + dev_err(dev, "Invalid tx_mask 0x%08x, slots = %d\n", tx_mask, slots); + return -EINVAL; + } + + if (!rx_mask || hweight_long(rx_mask) > 1 || fls(rx_mask) > slots) { + dev_err(dev, "Invalid rx_mask 0x%08x, slots = %d\n", rx_mask, slots); + return -EINVAL; + } + + /* Configure tx channel data location */ + for (i = 0; tx_mask; i++, tx_mask ^= BIT(ffs(tx_mask) - 1)) { + byte_loc = (ffs(tx_mask) - 1) * slot_width / 8; + snd_soc_component_write(comp, RTQ9124_REG_TDM_TX_CH0 + i, byte_loc); + } + + /* Configure rx channel data location */ + byte_loc = (ffs(rx_mask) - 1) * slot_width / 8; + snd_soc_component_write(comp, RTQ9124_REG_TDM_RX_CH0, byte_loc); + + rtq9124->tdm_slots = slots; + rtq9124->tdm_slot_width = slot_width; + + return 0; +} + +static int rtq9124_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *param, struct snd_soc_dai *dai) +{ + struct rtq9124_priv *rtq9124 = snd_soc_dai_get_drvdata(dai); + struct snd_soc_component *comp = dai->component; + unsigned int fmtval, width, slot_width, bitrate; + struct device *dev = dai->dev; + unsigned int audfmt, audbit; + + fmtval = FIELD_GET(SND_SOC_DAIFMT_FORMAT_MASK, rtq9124->dai_fmt); + if (rtq9124->tdm_slots && fmtval != SND_SOC_DAIFMT_DSP_A && + fmtval != SND_SOC_DAIFMT_DSP_B) { + dev_err(dev, "TDM only can support DSP_A or DSP_B format\n"); + return -EINVAL; + } + + switch (fmtval) { + case SND_SOC_DAIFMT_I2S: + audfmt = 0; + break; + case SND_SOC_DAIFMT_LEFT_J: + audfmt = 1; + break; + case SND_SOC_DAIFMT_RIGHT_J: + audfmt = 2; + break; + case SND_SOC_DAIFMT_DSP_B: + audfmt = rtq9124->tdm_slots ? 7 : 3; + break; + case SND_SOC_DAIFMT_DSP_A: + audfmt = rtq9124->tdm_slots ? 15 : 11; + break; + default: + dev_err(dev, "Unsupported format %d\n", fmtval); + return -EINVAL; + } + + switch (width = params_width(param)) { + case 16: + audbit = 0; + break; + case 20: + audbit = 1; + break; + case 24: + case 32: + audbit = 3; + break; + default: + dev_err(dev, "Unsupported width %d\n", width); + return -EINVAL; + } + + if (rtq9124->tdm_slots) { + slot_width = params_physical_width(param); + if (slot_width > rtq9124->tdm_slot_width) { + dev_err(dev, "Slot width is larger than TDM slot width\n"); + return -EINVAL; + } + + bitrate = rtq9124->tdm_slots * rtq9124->tdm_slot_width * params_rate(param); + if (bitrate > 24576000) { + dev_err(dev, "Bitrate exceed the internal PLL 24.576MHz (%d)\n", bitrate); + return -EINVAL; + } + } + + snd_soc_component_write_field(comp, RTQ9124_REG_I2S_OPT, RTQ9124_MASK_AUD_FMT, audfmt); + snd_soc_component_write_field(comp, RTQ9124_REG_I2S_OPT, RTQ9124_MASK_AUD_BITS, audbit); + + return 0; +} + +static const struct snd_soc_dai_ops rtq9124_dai_ops = { + .set_fmt = rtq9124_dai_set_format, + .set_tdm_slot = rtq9124_dai_set_tdm_slot, + .hw_params = rtq9124_dai_hw_params, +}; + +static struct snd_soc_dai_driver rtq9124_dai_driver = { + .name = "HiFi", + .playback = { + .stream_name = "HiFi Playback", + .formats = SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_24000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &rtq9124_dai_ops, + .symmetric_rate = 1, + .symmetric_sample_bits = 1, +}; + +static bool rtq9124_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x00 ... 0x17: + case 0x20 ... 0x27: + case 0x30 ... 0x3D: + case 0x40 ... 0x68: + case 0x80 ... 0xBC: + case 0xC0 ... 0xDE: + case 0xE0 ... 0xE7: + case 0xF0 ... 0xFD: + return true; + default: + return false; + } +} + +static bool rtq9124_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x00 ... 0x09: + case 0x0C ... 0x0E: + case 0x10 ... 0x17: + case 0x20 ... 0x27: + case 0x30: + case 0x32 ... 0x3D: + case 0x40 ... 0x4E: + case 0x50 ... 0x68: + case 0x80 ... 0xBC: + case 0xC0 ... 0xDE: + case 0xE0 ... 0xE7: + case 0xF0 ... 0xFD: + return true; + default: + return false; + } +} + +static bool rtq9124_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x0A ... 0x0B: + case 0x0F ... 0x17: + case 0x31: + case 0x4F: + case 0x51: + case 0x53 ... 0x57: + case 0x80 ... 0xBC: + case 0xC0 ... 0xDE: + case 0xE0 ... 0xE7: + case 0xF0 ... 0xFD: + return true; + default: + return false; + } +} + +static inline u8 rtq9124_get_reg_len(unsigned int reg) +{ + return (reg >= 0x40 && reg <= 0x47) ? 4 : 2; +} + +static int rtq9124_regmap_read(void *context, const void *reg_buf, size_t reg_size, void *val_buf, + size_t val_size) +{ + struct i2c_client *i2c = context; + u8 reg = *(u8 *)reg_buf; + u8 size = rtq9124_get_reg_len(reg); + u32 *val = val_buf; + int ret; + + ret = i2c_smbus_read_i2c_block_data(i2c, reg, size, val_buf); + if (ret < 0) + return ret; + else if (ret != size) + return -EIO; + + *val = size == 4 ? be32_to_cpup(val_buf) : be16_to_cpup(val_buf); + + return 0; +} + +static int rtq9124_regmap_write(void *context, const void *data, size_t count) +{ + struct i2c_client *i2c = context; + u8 reg = *(u8 *)data, *vbuf; + u8 size = rtq9124_get_reg_len(reg); + __be16 val16 = cpu_to_be16p(data + 1); + __be32 val32 = cpu_to_be32p(data + 1); + + vbuf = size == 4 ? (u8 *)&val32 : (u8 *)&val16; + return i2c_smbus_write_i2c_block_data(i2c, reg, size, vbuf); +} + +static const struct regmap_config rtq9124_regmap_config = { + .name = "rtq9124", + .reg_bits = 8, + .val_bits = 32, + .read = rtq9124_regmap_read, + .write = rtq9124_regmap_write, + .readable_reg = rtq9124_readable_reg, + .writeable_reg = rtq9124_writeable_reg, + .volatile_reg = rtq9124_volatile_reg, + .cache_type = REGCACHE_MAPLE, + .num_reg_defaults_raw = 0xFD + 1, + .use_single_read = 1, + .use_single_write = 1, +}; + +static const struct reg_sequence rtq9124_init_regs[] = { + { 0xfb, 0x0065 }, + { 0x93, 0x2000 }, + { 0xfb, 0x0000 }, +}; + +static int rtq9124_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct rtq9124_priv *rtq9124; + struct regmap *regmap; + int ret; + + rtq9124 = devm_kzalloc(dev, sizeof(*rtq9124), GFP_KERNEL); + if (!rtq9124) + return -ENOMEM; + + rtq9124->enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); + if (IS_ERR(rtq9124->enable)) + return PTR_ERR(rtq9124->enable); + else if (rtq9124->enable) + usleep_range(6000, 7000); + else + dev_dbg(dev, "No 'enable' GPIO specified, treat it as default on\n"); + + /* Check vendor id information */ + ret = i2c_smbus_read_word_swapped(i2c, RTQ9124_REG_PRJ_CODE); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to read project code\n"); + else if (ret != RTQ9124_FIXED_VENID) + return dev_err_probe(dev, -ENODEV, "Incorrect project-code 0x%04x\n", ret); + + /* Trigger RG reset before regmap init */ + ret = i2c_smbus_write_word_swapped(i2c, RTQ9124_REG_STATE_CTRL, RTQ9124_MASK_SF_RESET); + if (ret) + return dev_err_probe(dev, ret, "Failed to trigger RG reset\n"); + + /* Need to wait 10ms for the reset to complete */ + usleep_range(10000, 11000); + + regmap = devm_regmap_init(dev, NULL, i2c, &rtq9124_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "Failed to init regmap\n"); + + ret = regmap_register_patch(regmap, rtq9124_init_regs, ARRAY_SIZE(rtq9124_init_regs)); + if (ret) + return dev_err_probe(dev, ret, "Failed to register regmap patch\n"); + + i2c_set_clientdata(i2c, rtq9124); + + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_active(dev); + ret = devm_pm_runtime_enable(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable pm runtime\n"); + + return devm_snd_soc_register_component(dev, &rtq9124_comp_driver, &rtq9124_dai_driver, 1); +} + +#ifdef CONFIG_PM +static int rtq9124_runtime_suspend(struct device *dev) +{ + struct rtq9124_priv *rtq9124 = dev_get_drvdata(dev); + struct regmap *regmap = dev_get_regmap(dev, NULL); + + if (rtq9124->enable) { + regcache_cache_only(regmap, true); + regcache_mark_dirty(regmap); + gpiod_set_value(rtq9124->enable, 0); + } + + return 0; +} + +static int rtq9124_runtime_resume(struct device *dev) +{ + struct rtq9124_priv *rtq9124 = dev_get_drvdata(dev); + struct regmap *regmap = dev_get_regmap(dev, NULL); + int ret; + + if (rtq9124->enable) { + gpiod_set_value(rtq9124->enable, 1); + usleep_range(6000, 7000); + + regcache_cache_only(regmap, false); + ret = regcache_sync(regmap); + if (ret) + return ret; + } + + return 0; +} +#endif + +static const struct dev_pm_ops rtq9124_dev_pm_ops = { + SET_RUNTIME_PM_OPS(rtq9124_runtime_suspend, rtq9124_runtime_resume, NULL) +}; + +#ifdef CONFIG_OF +static const struct of_device_id rtq9124_device_id[] = { + { .compatible = "richtek,rtq9124" }, + {} +}; +MODULE_DEVICE_TABLE(of, rtq9124_device_id); +#endif + +static struct i2c_driver rtq9124_driver = { + .driver = { + .name = "rtq9124", + .of_match_table = of_match_ptr(rtq9124_device_id), + .pm = pm_ptr(&rtq9124_dev_pm_ops), + }, + .probe = rtq9124_probe, +}; +module_i2c_driver(rtq9124_driver); + +MODULE_AUTHOR("ChiYuan Huang "); +MODULE_DESCRIPTION("ASoC RTQ9124 Driver"); +MODULE_LICENSE("GPL"); From 0779c0ad2a7cc0ae1865860c9bc8732613cc56b1 Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Mon, 9 Jun 2025 17:42:32 +0530 Subject: [PATCH 050/385] ASoC: amd: acp: Fix pointer assignments for snd_soc_acpi_mach structures This patch modifies the assignment of machine structure pointers in the acp_pci_probe function. Previously, the machine pointers were assigned using the address-of operator (&), which caused incompatibility issues in type assignments. Additionally, the declarations of the machine arrays in amd.h have been updated to reflect that they are indeed arrays (`[]`). The code is further cleaned up by declaring the codec structures in amd-acpi-mach.c as static, reflecting their intended usage. error: symbol 'amp_rt1019' was not declared. Should it be static? error: symbol 'amp_max' was not declared. Should it be static? error: symbol 'snd_soc_acpi_amd_acp_machines' was not declared. Should it be static? error: symbol 'snd_soc_acpi_amd_rmb_acp_machines' was not declared. Should it be static? error: symbol 'snd_soc_acpi_amd_acp63_acp_machines' was not declared. Should it be static? error: symbol 'snd_soc_acpi_amd_acp70_acp_machines' was not declared. Should it be static? Fixes: 9c2c0ef64009 ("ASoC: amd: acp: Fix snd_soc_acpi_mach id's duplicate symbol error") Link: https://github.com/thesofproject/linux/issues/5438 Signed-off-by: Venkata Prasad Potturu Link: https://patch.msgid.link/20250609121251.639080-1-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-pci.c | 8 ++++---- sound/soc/amd/acp/amd-acpi-mach.c | 4 ++-- sound/soc/amd/acp/amd.h | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index 0b2aa33cc426..2591b1a1c5e0 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -137,26 +137,26 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id chip->name = "acp_asoc_renoir"; chip->rsrc = &rn_rsrc; chip->acp_hw_ops_init = acp31_hw_ops_init; - chip->machines = &snd_soc_acpi_amd_acp_machines; + chip->machines = snd_soc_acpi_amd_acp_machines; break; case 0x6f: chip->name = "acp_asoc_rembrandt"; chip->rsrc = &rmb_rsrc; chip->acp_hw_ops_init = acp6x_hw_ops_init; - chip->machines = &snd_soc_acpi_amd_rmb_acp_machines; + chip->machines = snd_soc_acpi_amd_rmb_acp_machines; break; case 0x63: chip->name = "acp_asoc_acp63"; chip->rsrc = &acp63_rsrc; chip->acp_hw_ops_init = acp63_hw_ops_init; - chip->machines = &snd_soc_acpi_amd_acp63_acp_machines; + chip->machines = snd_soc_acpi_amd_acp63_acp_machines; break; case 0x70: case 0x71: chip->name = "acp_asoc_acp70"; chip->rsrc = &acp70_rsrc; chip->acp_hw_ops_init = acp70_hw_ops_init; - chip->machines = &snd_soc_acpi_amd_acp70_acp_machines; + chip->machines = snd_soc_acpi_amd_acp70_acp_machines; break; default: dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision); diff --git a/sound/soc/amd/acp/amd-acpi-mach.c b/sound/soc/amd/acp/amd-acpi-mach.c index d95047d2ee94..27da2a862f1c 100644 --- a/sound/soc/amd/acp/amd-acpi-mach.c +++ b/sound/soc/amd/acp/amd-acpi-mach.c @@ -8,12 +8,12 @@ #include -struct snd_soc_acpi_codecs amp_rt1019 = { +static struct snd_soc_acpi_codecs amp_rt1019 = { .num_codecs = 1, .codecs = {"10EC1019"} }; -struct snd_soc_acpi_codecs amp_max = { +static struct snd_soc_acpi_codecs amp_max = { .num_codecs = 1, .codecs = {"MX98360A"} }; diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index 863e74fcee43..cb8d97122f95 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -243,10 +243,10 @@ extern struct acp_resource rmb_rsrc; extern struct acp_resource acp63_rsrc; extern struct acp_resource acp70_rsrc; -extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines; -extern struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_acp_machines; -extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_acp_machines; -extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_acp_machines; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_acp_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_acp_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_acp_machines[]; extern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops; extern const struct snd_soc_dai_ops acp_dmic_dai_ops; From 6ba68e5aa9d5d15c8877a655db279fcfc0b38b04 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 16 May 2025 15:32:25 +0200 Subject: [PATCH 051/385] ASoC: renesas: msiof: Convert to Convert the MSIOF I2S driver to reuse the MSIOF register and register bit definitions in the header file shared by the MSIOF SPI driver. Signed-off-by: Geert Uytterhoeven Tested-by: Kuninori Morimoto Link: https://patch.msgid.link/754ed54057e54effd06143e71d6cd305c3334eca.1747401908.git.geert+renesas@glider.be Signed-off-by: Mark Brown --- sound/soc/renesas/rcar/msiof.c | 94 ++++++++++------------------------ 1 file changed, 28 insertions(+), 66 deletions(-) diff --git a/sound/soc/renesas/rcar/msiof.c b/sound/soc/renesas/rcar/msiof.c index 75c9e91bada1..36d31ab8ac6a 100644 --- a/sound/soc/renesas/rcar/msiof.c +++ b/sound/soc/renesas/rcar/msiof.c @@ -30,56 +30,15 @@ #include #include #include +#include #include #include -/* register */ -#define SITMDR1 0x00 -#define SITMDR2 0x04 -#define SITMDR3 0x08 -#define SIRMDR1 0x10 -#define SIRMDR2 0x14 -#define SIRMDR3 0x18 -#define SICTR 0x28 -#define SISTR 0x40 -#define SIIER 0x44 -#define SITFDR 0x50 -#define SIRFDR 0x60 - -/* SITMDR1/ SIRMDR1 */ -#define PCON (1 << 30) /* Transfer Signal Connection */ -#define SYNCMD_LR (3 << 28) /* L/R mode */ -#define SYNCAC (1 << 25) /* Sync Polarity (Active-low) */ -#define DTDL_1 (1 << 20) /* 1-clock-cycle delay */ -#define TXSTP (1 << 0) /* Transmission/Reception Stop on FIFO */ - -/* SITMDR2 and SIRMDR2 */ -#define BITLEN1(x) (((x) - 1) << 24) /* Data Size (8-32 bits) */ -#define GRP (1 << 30) /* Group count */ - -/* SICTR */ -#define TEDG (1 << 27) /* Transmit Timing (1 = falling edge) */ -#define REDG (1 << 26) /* Receive Timing (1 = rising edge) */ -#define TXE (1 << 9) /* Transmit Enable */ -#define RXE (1 << 8) /* Receive Enable */ - /* SISTR */ -#define TFSERR (1 << 21) /* Transmit Frame Synchronization Error */ -#define TFOVF (1 << 20) /* Transmit FIFO Overflow */ -#define TFUDF (1 << 19) /* Transmit FIFO Underflow */ -#define RFSERR (1 << 5) /* Receive Frame Synchronization Error */ -#define RFUDF (1 << 4) /* Receive FIFO Underflow */ -#define RFOVF (1 << 3) /* Receive FIFO Overflow */ -#define SISTR_ERR_TX (TFSERR | TFOVF | TFUDF) -#define SISTR_ERR_RX (RFSERR | RFOVF | RFUDF) +#define SISTR_ERR_TX (SISTR_TFSERR | SISTR_TFOVF | SISTR_TFUDF) +#define SISTR_ERR_RX (SISTR_RFSERR | SISTR_RFOVF | SISTR_RFUDF) #define SISTR_ERR (SISTR_ERR_TX | SISTR_ERR_RX) -/* SIIER */ -#define TDMAE (1 << 31) /* Transmit Data DMA Transfer Req. Enable */ -#define TDREQE (1 << 28) /* Transmit Data Transfer Request Enable */ -#define RDMAE (1 << 15) /* Receive Data DMA Transfer Req. Enable */ -#define RDREQE (1 << 12) /* Receive Data Transfer Request Enable */ - /* * The data on memory in 24bit case is located at side * [ xxxxxx] @@ -174,42 +133,45 @@ static int msiof_hw_start(struct snd_soc_component *component, /* SITMDRx */ if (is_play) { - val = PCON | SYNCMD_LR | SYNCAC | TXSTP; + val = SITMDR1_PCON | + FIELD_PREP(SIMDR1_SYNCMD, SIMDR1_SYNCMD_LR) | + SIMDR1_SYNCAC | SIMDR1_XXSTP; if (msiof_flag_has(priv, MSIOF_FLAGS_NEED_DELAY)) - val |= DTDL_1; + val |= FIELD_PREP(SIMDR1_DTDL, 1); msiof_write(priv, SITMDR1, val); - val = BITLEN1(width); - msiof_write(priv, SITMDR2, val | GRP); + val = FIELD_PREP(SIMDR2_BITLEN1, width - 1); + msiof_write(priv, SITMDR2, val | FIELD_PREP(SIMDR2_GRP, 1)); msiof_write(priv, SITMDR3, val); } /* SIRMDRx */ else { - val = SYNCMD_LR | SYNCAC; + val = FIELD_PREP(SIMDR1_SYNCMD, SIMDR1_SYNCMD_LR) | + SIMDR1_SYNCAC; if (msiof_flag_has(priv, MSIOF_FLAGS_NEED_DELAY)) - val |= DTDL_1; + val |= FIELD_PREP(SIMDR1_DTDL, 1); msiof_write(priv, SIRMDR1, val); - val = BITLEN1(width); - msiof_write(priv, SIRMDR2, val | GRP); + val = FIELD_PREP(SIMDR2_BITLEN1, width - 1); + msiof_write(priv, SIRMDR2, val | FIELD_PREP(SIMDR2_GRP, 1)); msiof_write(priv, SIRMDR3, val); } /* SIIER */ if (is_play) - val = TDREQE | TDMAE | SISTR_ERR_TX; + val = SIIER_TDREQE | SIIER_TDMAE | SISTR_ERR_TX; else - val = RDREQE | RDMAE | SISTR_ERR_RX; + val = SIIER_RDREQE | SIIER_RDMAE | SISTR_ERR_RX; msiof_update(priv, SIIER, val, val); /* SICTR */ if (is_play) - val = TXE | TEDG; + val = SICTR_TXE | SICTR_TEDG; else - val = RXE | REDG; + val = SICTR_RXE | SICTR_REDG; msiof_update_and_wait(priv, SICTR, val, val, val); msiof_status_clear(priv); @@ -230,9 +192,9 @@ static int msiof_hw_stop(struct snd_soc_component *component, /* SIIER */ if (is_play) - val = TDREQE | TDMAE | SISTR_ERR_TX; + val = SIIER_TDREQE | SIIER_TDMAE | SISTR_ERR_TX; else - val = RDREQE | RDMAE | SISTR_ERR_RX; + val = SIIER_RDREQE | SIIER_RDMAE | SISTR_ERR_RX; msiof_update(priv, SIIER, val, 0); /* Stop DMAC */ @@ -240,9 +202,9 @@ static int msiof_hw_stop(struct snd_soc_component *component, /* SICTR */ if (is_play) - val = TXE; + val = SICTR_TXE; else - val = RXE; + val = SICTR_RXE; msiof_update_and_wait(priv, SICTR, val, 0, 0); /* indicate error status if exist */ @@ -478,22 +440,22 @@ static irqreturn_t msiof_interrupt(int irq, void *data) substream = priv->substream[SNDRV_PCM_STREAM_PLAYBACK]; if (substream && (sistr & SISTR_ERR_TX)) { // snd_pcm_stop_xrun(substream); - if (sistr & TFSERR) + if (sistr & SISTR_TFSERR) priv->err_syc[SNDRV_PCM_STREAM_PLAYBACK]++; - if (sistr & TFOVF) + if (sistr & SISTR_TFOVF) priv->err_ovf[SNDRV_PCM_STREAM_PLAYBACK]++; - if (sistr & TFUDF) + if (sistr & SISTR_TFUDF) priv->err_udf[SNDRV_PCM_STREAM_PLAYBACK]++; } substream = priv->substream[SNDRV_PCM_STREAM_CAPTURE]; if (substream && (sistr & SISTR_ERR_RX)) { // snd_pcm_stop_xrun(substream); - if (sistr & RFSERR) + if (sistr & SISTR_RFSERR) priv->err_syc[SNDRV_PCM_STREAM_CAPTURE]++; - if (sistr & RFOVF) + if (sistr & SISTR_RFOVF) priv->err_ovf[SNDRV_PCM_STREAM_CAPTURE]++; - if (sistr & RFUDF) + if (sistr & SISTR_RFUDF) priv->err_udf[SNDRV_PCM_STREAM_CAPTURE]++; } From 7e10d7242ea8a5947878880b912ffa5806520705 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 10 Jun 2025 11:30:53 +0200 Subject: [PATCH 052/385] ASoC: ops: dynamically allocate struct snd_ctl_elem_value This structure is really too larget to be allocated on the stack: sound/soc/soc-ops.c:435:5: error: stack frame size (1296) exceeds limit (1280) in 'snd_soc_limit_volume' [-Werror,-Wframe-larger-than] Change the function to dynamically allocate it instead. There is probably a better way to do it since only two integer fields inside of that structure are actually used, but this is the simplest rework for the moment. Fixes: 783db6851c18 ("ASoC: ops: Enforce platform maximum on initial value") Signed-off-by: Arnd Bergmann Link: https://patch.msgid.link/20250610093057.2643233-1-arnd@kernel.org Signed-off-by: Mark Brown --- sound/soc/soc-ops.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index 8d4dd11c9aef..a629e0eacb20 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -399,28 +399,32 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx); static int snd_soc_clip_to_platform_max(struct snd_kcontrol *kctl) { struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; - struct snd_ctl_elem_value uctl; + struct snd_ctl_elem_value *uctl; int ret; if (!mc->platform_max) return 0; - ret = kctl->get(kctl, &uctl); - if (ret < 0) - return ret; + uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); + if (!uctl) + return -ENOMEM; - if (uctl.value.integer.value[0] > mc->platform_max) - uctl.value.integer.value[0] = mc->platform_max; + ret = kctl->get(kctl, uctl); + if (ret < 0) + goto out; + + if (uctl->value.integer.value[0] > mc->platform_max) + uctl->value.integer.value[0] = mc->platform_max; if (snd_soc_volsw_is_stereo(mc) && - uctl.value.integer.value[1] > mc->platform_max) - uctl.value.integer.value[1] = mc->platform_max; + uctl->value.integer.value[1] > mc->platform_max) + uctl->value.integer.value[1] = mc->platform_max; - ret = kctl->put(kctl, &uctl); - if (ret < 0) - return ret; + ret = kctl->put(kctl, uctl); - return 0; +out: + kfree(uctl); + return ret; } /** From d6e2c062e5f154d1c54022b8defb91c21648562d Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 10 Jun 2025 14:18:33 +0200 Subject: [PATCH 053/385] ALSA: mips/sgio2audio: Replace deprecated strcpy() with strscpy() strcpy() is deprecated; use strscpy() instead. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20250610121835.2908-2-thorsten.blum@linux.dev Signed-off-by: Takashi Iwai --- sound/mips/sgio2audio.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index 4e2ff954ff59..1af177f25c68 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -685,7 +686,7 @@ static int snd_sgio2audio_new_pcm(struct snd_sgio2audio *chip) return err; pcm->private_data = chip; - strcpy(pcm->name, "SGI O2 DAC1"); + strscpy(pcm->name, "SGI O2 DAC1"); /* set operators */ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, @@ -700,7 +701,7 @@ static int snd_sgio2audio_new_pcm(struct snd_sgio2audio *chip) return err; pcm->private_data = chip; - strcpy(pcm->name, "SGI O2 DAC2"); + strscpy(pcm->name, "SGI O2 DAC2"); /* set operators */ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, @@ -892,8 +893,8 @@ static int snd_sgio2audio_probe(struct platform_device *pdev) return err; } - strcpy(card->driver, "SGI O2 Audio"); - strcpy(card->shortname, "SGI O2 Audio"); + strscpy(card->driver, "SGI O2 Audio"); + strscpy(card->shortname, "SGI O2 Audio"); sprintf(card->longname, "%s irq %i-%i", card->shortname, MACEISA_AUDIO1_DMAT_IRQ, From 165bb5b154de4c39c3aa9962f0dd69836d030c19 Mon Sep 17 00:00:00 2001 From: Lucy Thrun Date: Tue, 10 Jun 2025 19:50:11 +0200 Subject: [PATCH 054/385] ALSA: hda/ca0132: Fix using plain integer as NULL pointer in add_tuning_control The 'add_tuning_control' function initializes two pointers using the integer 0 instead of the NULL pointer, triggering sparse warnings. Replaced both instaces of '0' with 'NULL' to resolve the type mismatch and suppress the sparse warnings. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202506100842.d8lwwdwU-lkp@intel.com/ Signed-off-by: Lucy Thrun Link: https://patch.msgid.link/20250610175012.918-2-lucy.thrun@digital-rabbithole.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index cfe422a79703..491d45d652dd 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4385,8 +4385,8 @@ static int add_tuning_control(struct hda_codec *codec, knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ; - knew.tlv.c = 0; - knew.tlv.p = 0; + knew.tlv.c = NULL; + knew.tlv.p = NULL; switch (pnid) { case VOICE_FOCUS: knew.info = voice_focus_ctl_info; From a409c60111e6bb98fcabab2aeaa069daa9434ca0 Mon Sep 17 00:00:00 2001 From: Lucy Thrun Date: Tue, 10 Jun 2025 19:50:12 +0200 Subject: [PATCH 055/385] ALSA: hda/ca0132: Fix buffer overflow in add_tuning_control The 'sprintf' call in 'add_tuning_control' may exceed the 44-byte buffer if either string argument is too long. This triggers a compiler warning. Replaced 'sprintf' with 'snprintf' to limit string lengths to prevent overflow. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202506100642.95jpuMY1-lkp@intel.com/ Signed-off-by: Lucy Thrun Link: https://patch.msgid.link/20250610175012.918-3-lucy.thrun@digital-rabbithole.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 491d45d652dd..1904964591db 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4410,7 +4410,7 @@ static int add_tuning_control(struct hda_codec *codec, } knew.private_value = HDA_COMPOSE_AMP_VAL(nid, 1, 0, type); - sprintf(namestr, "%s %s Volume", name, dirstr[dir]); + snprintf(namestr, sizeof(namestr), "%s %s Volume", name, dirstr[dir]); return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); } From 9ca30a1b007d5fefb5752428f852a2d8d7219c1c Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Thu, 12 Jun 2025 14:02:28 +0800 Subject: [PATCH 056/385] ALSA: usb-audio: Convert comma to semicolon Replace comma between expressions with semicolons. Using a ',' in place of a ';' can have unintended side effects. Although that is not the case here, it is seems best to use ';' unless ',' is intended. Found by inspection. No functional change intended. Compile tested only. Fixes: 79d561c4ec04 ("ALSA: usb-audio: Add mixer quirk for Sony DualSense PS5") Signed-off-by: Chen Ni Reviewed-by: Cristian Ciocaltea Link: https://patch.msgid.link/20250612060228.1518028-1-nichen@iscas.ac.cn Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 0769ecd91144..a0ffe8b559dc 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -762,9 +762,9 @@ static int snd_dualsense_jack_create(struct usb_mixer_interface *mixer, mei->ih.event = snd_dualsense_ih_event; mei->ih.match = snd_dualsense_ih_match; - mei->ih.connect = snd_dualsense_ih_connect, - mei->ih.disconnect = snd_dualsense_ih_disconnect, - mei->ih.start = snd_dualsense_ih_start, + mei->ih.connect = snd_dualsense_ih_connect; + mei->ih.disconnect = snd_dualsense_ih_disconnect; + mei->ih.start = snd_dualsense_ih_start; mei->ih.name = name; mei->ih.id_table = mei->id_table; From 30f85eddbdebba7665f9b7b772821e588547ca9e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 Jun 2025 08:48:01 +0200 Subject: [PATCH 057/385] ALSA: hda/ca0132: Use const char * for strings Some static strings have been stored in fixed char arrays although they could be gracefully "const char *" instead. Also, a few other definitions use the raw "char *" without const. Converting those to "const char *" will save some memory and give more safety, in addition to a side-effect to address the bogus compiler warning with snprintf(). Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202506121025.G9uunMlx-lkp@intel.com/ Link: https://patch.msgid.link/20250612064802.1170-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 1904964591db..686ce0947131 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -174,7 +174,7 @@ static const unsigned int effect_slider_defaults[] = {67, 65, 50, 74, 50}; #define DSP_SPEAKER_OUT_LATENCY 7 struct ct_effect { - char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + const char *name; hda_nid_t nid; int mid; /*effect module ID*/ int reqs[EFFECT_VALS_MAX_COUNT]; /*effect module request*/ @@ -305,7 +305,7 @@ enum { }; struct ct_tuning_ctl { - char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + const char *name; hda_nid_t parent_nid; hda_nid_t nid; int mid; /*effect module ID*/ @@ -418,14 +418,14 @@ static const struct ct_tuning_ctl ca0132_tuning_ctls[] = { #define VOICEFX_MAX_PARAM_COUNT 9 struct ct_voicefx { - char *name; + const char *name; hda_nid_t nid; int mid; int reqs[VOICEFX_MAX_PARAM_COUNT]; /*effect module request*/ }; struct ct_voicefx_preset { - char *name; /*preset name*/ + const char *name; /*preset name*/ unsigned int vals[VOICEFX_MAX_PARAM_COUNT]; }; @@ -514,14 +514,14 @@ static const struct ct_voicefx_preset ca0132_voicefx_presets[] = { #define EQ_PRESET_MAX_PARAM_COUNT 11 struct ct_eq { - char *name; + const char *name; hda_nid_t nid; int mid; int reqs[EQ_PRESET_MAX_PARAM_COUNT]; /*effect module request*/ }; struct ct_eq_preset { - char *name; /*preset name*/ + const char *name; /*preset name*/ unsigned int vals[EQ_PRESET_MAX_PARAM_COUNT]; }; @@ -679,7 +679,7 @@ enum { }; struct ca0132_alt_speaker_channel_cfg { - char *name; + const char *name; unsigned int val; }; @@ -755,7 +755,7 @@ static const struct ae_ca0113_output_set ae7_ca0113_output_presets = { /* ae5 ca0113 command sequences to set headphone gain levels. */ #define AE5_HEADPHONE_GAIN_PRESET_MAX_COMMANDS 4 struct ae5_headphone_gain_set { - char *name; + const char *name; unsigned int vals[AE5_HEADPHONE_GAIN_PRESET_MAX_COMMANDS]; }; @@ -772,7 +772,7 @@ static const struct ae5_headphone_gain_set ae5_headphone_gain_presets[] = { }; struct ae5_filter_set { - char *name; + const char *name; unsigned int val; }; @@ -5787,7 +5787,7 @@ static int ca0132_alt_effect_slider_put(struct snd_kcontrol *kcontrol, static int ca0132_alt_mic_boost_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - char *sfx = "dB"; + const char *sfx = "dB"; char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; @@ -5839,7 +5839,7 @@ static int ca0132_alt_mic_boost_put(struct snd_kcontrol *kcontrol, static int ae5_headphone_gain_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - char *sfx = " Ohms)"; + const char *sfx = " Ohms)"; char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; From 8a5a5cecb79058b608e5562d8998123a3adb313c Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Thu, 12 Jun 2025 12:42:52 +0800 Subject: [PATCH 058/385] ASoC: tas2781: Move the "include linux/debugfs.h" into tas2781.h Move the include linux/debugfs.h into tas2781.h for code clean. Signed-off-by: Shenghao Ding Link: https://patch.msgid.link/20250612044252.1025-1-shenghao-ding@ti.com Signed-off-by: Mark Brown --- include/sound/tas2781.h | 4 ++++ sound/soc/codecs/tas2781-i2c.c | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h index 40cd3bd079b5..3875e92f1ec5 100644 --- a/include/sound/tas2781.h +++ b/include/sound/tas2781.h @@ -17,6 +17,10 @@ #ifndef __TAS2781_H__ #define __TAS2781_H__ +#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C +#include +#endif + #include "tas2781-dsp.h" /* version number */ diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index c40d8f754d89..9f4d965a1335 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -14,9 +14,6 @@ // #include -#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C -#include -#endif #include #include #include From bb90e0c91d375ec5db8a4f8cd2555900aea0725f Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 12 Jun 2025 15:48:52 +0800 Subject: [PATCH 059/385] ASoC: dt-bindings: Convert MT8173 AFE binding to dt-schema Convert the MT8173 AFE (audio frontend) binding from text to dt-schema in YAML. "clocks" is added to the list of required properties to match "clock-names". And the example was slightly fixed up in style. Otherwise everything is as before. A contributer and maintainer for a recently added MediaTek audio binding was chosen instead of the original submitter. Cc: Trevor Wu Reviewed-by: Krzysztof Kozlowski Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Chen-Yu Tsai Link: https://patch.msgid.link/20250612074901.4023253-2-wenst@chromium.org Signed-off-by: Mark Brown --- .../sound/mediatek,mt8173-afe-pcm.yaml | 87 +++++++++++++++++++ .../devicetree/bindings/sound/mtk-afe-pcm.txt | 45 ---------- 2 files changed, 87 insertions(+), 45 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8173-afe-pcm.yaml delete mode 100644 Documentation/devicetree/bindings/sound/mtk-afe-pcm.txt diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8173-afe-pcm.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8173-afe-pcm.yaml new file mode 100644 index 000000000000..a95215ba6361 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8173-afe-pcm.yaml @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/mediatek,mt8173-afe-pcm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek AFE PCM controller for MT8173 + +maintainers: + - Trevor Wu + +properties: + compatible: + const: mediatek,mt8173-afe-pcm + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: audio infra sys clock + - description: audio top mux + - description: audio intbus mux + - description: apll1 clock + - description: apll2 clock + - description: i2s0 mclk mux + - description: i2s1 mclk mux + - description: i2s2 mclk mux + - description: i2s3 mclk mux + - description: i2s3 bclk mux + + clock-names: + items: + - const: infra_sys_audio_clk + - const: top_pdn_audio + - const: top_pdn_aud_intbus + - const: bck0 + - const: bck1 + - const: i2s0_m + - const: i2s1_m + - const: i2s2_m + - const: i2s3_m + - const: i2s3_b + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include + #include + #include + + mt8173-afe-pcm@11220000 { + compatible = "mediatek,mt8173-afe-pcm"; + reg = <0x11220000 0x1000>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_AUDIO>, + <&topckgen CLK_TOP_AUDIO_SEL>, + <&topckgen CLK_TOP_AUD_INTBUS_SEL>, + <&topckgen CLK_TOP_APLL1_DIV0>, + <&topckgen CLK_TOP_APLL2_DIV0>, + <&topckgen CLK_TOP_I2S0_M_SEL>, + <&topckgen CLK_TOP_I2S1_M_SEL>, + <&topckgen CLK_TOP_I2S2_M_SEL>, + <&topckgen CLK_TOP_I2S3_M_SEL>, + <&topckgen CLK_TOP_I2S3_B_SEL>; + clock-names = "infra_sys_audio_clk", + "top_pdn_audio", + "top_pdn_aud_intbus", + "bck0", + "bck1", + "i2s0_m", + "i2s1_m", + "i2s2_m", + "i2s3_m", + "i2s3_b"; + }; diff --git a/Documentation/devicetree/bindings/sound/mtk-afe-pcm.txt b/Documentation/devicetree/bindings/sound/mtk-afe-pcm.txt deleted file mode 100644 index e302c7f43b95..000000000000 --- a/Documentation/devicetree/bindings/sound/mtk-afe-pcm.txt +++ /dev/null @@ -1,45 +0,0 @@ -Mediatek AFE PCM controller - -Required properties: -- compatible = "mediatek,mt8173-afe-pcm"; -- reg: register location and size -- interrupts: Should contain AFE interrupt -- clock-names: should have these clock names: - "infra_sys_audio_clk", - "top_pdn_audio", - "top_pdn_aud_intbus", - "bck0", - "bck1", - "i2s0_m", - "i2s1_m", - "i2s2_m", - "i2s3_m", - "i2s3_b"; - -Example: - - afe: mt8173-afe-pcm@11220000 { - compatible = "mediatek,mt8173-afe-pcm"; - reg = <0 0x11220000 0 0x1000>; - interrupts = ; - clocks = <&infracfg INFRA_AUDIO>, - <&topckgen TOP_AUDIO_SEL>, - <&topckgen TOP_AUD_INTBUS_SEL>, - <&topckgen TOP_APLL1_DIV0>, - <&topckgen TOP_APLL2_DIV0>, - <&topckgen TOP_I2S0_M_CK_SEL>, - <&topckgen TOP_I2S1_M_CK_SEL>, - <&topckgen TOP_I2S2_M_CK_SEL>, - <&topckgen TOP_I2S3_M_CK_SEL>, - <&topckgen TOP_I2S3_B_CK_SEL>; - clock-names = "infra_sys_audio_clk", - "top_pdn_audio", - "top_pdn_aud_intbus", - "bck0", - "bck1", - "i2s0_m", - "i2s1_m", - "i2s2_m", - "i2s3_m", - "i2s3_b"; - }; From 2fd902152c15a8cacab91e4a660413d189411561 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 12 Jun 2025 15:48:53 +0800 Subject: [PATCH 060/385] ASoC: dt-bindings: mt8173-afe-pcm: Add power domain The audio subsystem sits under a controllable power domain. Add it to the binding. Acked-by: "Rob Herring (Arm)" Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Chen-Yu Tsai Link: https://patch.msgid.link/20250612074901.4023253-3-wenst@chromium.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/mediatek,mt8173-afe-pcm.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8173-afe-pcm.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8173-afe-pcm.yaml index a95215ba6361..666408d32f5c 100644 --- a/Documentation/devicetree/bindings/sound/mediatek,mt8173-afe-pcm.yaml +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8173-afe-pcm.yaml @@ -45,12 +45,16 @@ properties: - const: i2s3_m - const: i2s3_b + power-domains: + maxItems: 1 + required: - compatible - reg - interrupts - clocks - clock-names + - power-domains additionalProperties: false @@ -59,11 +63,13 @@ examples: #include #include #include + #include mt8173-afe-pcm@11220000 { compatible = "mediatek,mt8173-afe-pcm"; reg = <0x11220000 0x1000>; interrupts = ; + power-domains = <&spm MT8173_POWER_DOMAIN_AUDIO>; clocks = <&infracfg CLK_INFRA_AUDIO>, <&topckgen CLK_TOP_AUDIO_SEL>, <&topckgen CLK_TOP_AUD_INTBUS_SEL>, From 473ee884263f2127ea4e46a74ba15d07446ceabb Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 12 Jun 2025 15:48:54 +0800 Subject: [PATCH 061/385] ASoC: dt-bindings: mt8173-afe-pcm: Allow specifying reserved memory region It is desirable to reserve memory for the audio frontend. Allow the "memory-region" property, to be used to point to a reserved memory region. Acked-by: "Rob Herring (Arm)" Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Chen-Yu Tsai Link: https://patch.msgid.link/20250612074901.4023253-4-wenst@chromium.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/mediatek,mt8173-afe-pcm.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8173-afe-pcm.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8173-afe-pcm.yaml index 666408d32f5c..d8993b5d457a 100644 --- a/Documentation/devicetree/bindings/sound/mediatek,mt8173-afe-pcm.yaml +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8173-afe-pcm.yaml @@ -48,6 +48,10 @@ properties: power-domains: maxItems: 1 + memory-region: + description: memory region for audio DMA buffers + maxItems: 1 + required: - compatible - reg @@ -90,4 +94,5 @@ examples: "i2s2_m", "i2s3_m", "i2s3_b"; + memory-region = <&afe_dma_mem>; }; From 81c73294a4eb2df31e974db2fc4397f5e0ecae09 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 12 Jun 2025 15:48:55 +0800 Subject: [PATCH 062/385] ASoC: dt-bindings: mt8186-afe-pcm: Allow specifying reserved memory region It is desirable to reserve memory for the audio frontend. Allow the "memory-region" property, to be used to point to a reserved memory region. Acked-by: "Rob Herring (Arm)" Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Chen-Yu Tsai Link: https://patch.msgid.link/20250612074901.4023253-5-wenst@chromium.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/mt8186-afe-pcm.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/mt8186-afe-pcm.yaml b/Documentation/devicetree/bindings/sound/mt8186-afe-pcm.yaml index 7fe85b08f9df..f5af2cf18158 100644 --- a/Documentation/devicetree/bindings/sound/mt8186-afe-pcm.yaml +++ b/Documentation/devicetree/bindings/sound/mt8186-afe-pcm.yaml @@ -25,6 +25,10 @@ properties: reset-names: const: audiosys + memory-region: + description: memory region for audio DMA buffers + maxItems: 1 + mediatek,apmixedsys: $ref: /schemas/types.yaml#/definitions/phandle description: The phandle of the mediatek apmixedsys controller @@ -170,6 +174,7 @@ examples: "top_apll12_div_tdm", "top_mux_audio_h", "top_clk26m_clk"; + memory-region = <&afe_dma_mem>; }; ... From cd12d3a5ed10e3e3b323f2b2c652de1c8e17a750 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 12 Jun 2025 15:48:56 +0800 Subject: [PATCH 063/385] ASoC: dt-bindings: mt8192-afe-pcm: Allow specifying reserved memory region It is desirable to reserve memory for the audio frontend. Allow the "memory-region" property, to be used to point to a reserved memory region. Acked-by: "Rob Herring (Arm)" Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Chen-Yu Tsai Link: https://patch.msgid.link/20250612074901.4023253-6-wenst@chromium.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/mt8192-afe-pcm.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/mt8192-afe-pcm.yaml b/Documentation/devicetree/bindings/sound/mt8192-afe-pcm.yaml index 064ef172bef4..8ddf49b0040d 100644 --- a/Documentation/devicetree/bindings/sound/mt8192-afe-pcm.yaml +++ b/Documentation/devicetree/bindings/sound/mt8192-afe-pcm.yaml @@ -23,6 +23,10 @@ properties: reset-names: const: audiosys + memory-region: + description: memory region for audio DMA buffers + maxItems: 1 + mediatek,apmixedsys: $ref: /schemas/types.yaml#/definitions/phandle description: The phandle of the mediatek apmixedsys controller @@ -95,6 +99,7 @@ examples: "aud_dac_predis_clk", "aud_infra_clk", "aud_infra_26m_clk"; + memory-region = <&afe_dma_mem>; }; ... From ec4a10ca4a68ec97f12f4d17d7abb74db34987db Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 12 Jun 2025 15:48:57 +0800 Subject: [PATCH 064/385] ASoC: mediatek: use reserved memory or enable buffer pre-allocation In commit 32c9c06adb5b ("ASoC: mediatek: disable buffer pre-allocation") buffer pre-allocation was disabled to accommodate newer platforms that have a limited reserved memory region for the audio frontend. Turns out disabling pre-allocation across the board impacts platforms that don't have this reserved memory region. Buffer allocation failures have been observed on MT8173 and MT8183 based Chromebooks under low memory conditions, which results in no audio playback for the user. Since some MediaTek platforms already have dedicated reserved memory pools for the audio frontend, the plan is to enable this for all of them. This requires device tree changes. As a fallback, reinstate the original policy of pre-allocating audio buffers at probe time of the reserved memory pool cannot be found or used. This patch covers the MT8173, MT8183, MT8186 and MT8192 platforms for now, the reason being that existing MediaTek platform drivers that supported reserved memory were all platforms that mainly supported ChromeOS, and is also the set of devices that I can verify. Fixes: 32c9c06adb5b ("ASoC: mediatek: disable buffer pre-allocation") Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Chen-Yu Tsai Link: https://patch.msgid.link/20250612074901.4023253-7-wenst@chromium.org Signed-off-by: Mark Brown --- sound/soc/mediatek/common/mtk-afe-platform-driver.c | 4 +++- sound/soc/mediatek/common/mtk-base-afe.h | 1 + sound/soc/mediatek/mt8173/mt8173-afe-pcm.c | 7 +++++++ sound/soc/mediatek/mt8183/mt8183-afe-pcm.c | 7 +++++++ sound/soc/mediatek/mt8186/mt8186-afe-pcm.c | 7 +++++++ sound/soc/mediatek/mt8192/mt8192-afe-pcm.c | 7 +++++++ 6 files changed, 32 insertions(+), 1 deletion(-) diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c index 6b6330583941..70fd05d5ff48 100644 --- a/sound/soc/mediatek/common/mtk-afe-platform-driver.c +++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c @@ -120,7 +120,9 @@ int mtk_afe_pcm_new(struct snd_soc_component *component, struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); size = afe->mtk_afe_hardware->buffer_bytes_max; - snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, afe->dev, 0, size); + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, afe->dev, + afe->preallocate_buffers ? size : 0, + size); return 0; } diff --git a/sound/soc/mediatek/common/mtk-base-afe.h b/sound/soc/mediatek/common/mtk-base-afe.h index f51578b6c50a..a406f2e3e7a8 100644 --- a/sound/soc/mediatek/common/mtk-base-afe.h +++ b/sound/soc/mediatek/common/mtk-base-afe.h @@ -117,6 +117,7 @@ struct mtk_base_afe { struct mtk_base_afe_irq *irqs; int irqs_size; int memif_32bit_supported; + bool preallocate_buffers; struct list_head sub_dais; struct snd_soc_dai_driver *dai_drivers; diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c index 04ed0cfec174..f93d6348fdf8 100644 --- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c +++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -1070,6 +1071,12 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) afe->dev = &pdev->dev; + ret = of_reserved_mem_device_init(&pdev->dev); + if (ret) { + dev_info(&pdev->dev, "no reserved memory found, pre-allocating buffers instead\n"); + afe->preallocate_buffers = true; + } + irq_id = platform_get_irq(pdev, 0); if (irq_id <= 0) return irq_id < 0 ? irq_id : -ENXIO; diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c index e8884354995c..9b6b45c646e6 100644 --- a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c +++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -777,6 +778,12 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev) afe->dev = &pdev->dev; dev = afe->dev; + ret = of_reserved_mem_device_init(dev); + if (ret) { + dev_info(dev, "no reserved memory found, pre-allocating buffers instead\n"); + afe->preallocate_buffers = true; + } + /* initial audio related clock */ ret = mt8183_init_clock(afe); if (ret) { diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c index db7c93401bee..c73b4664e53e 100644 --- a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c +++ b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -2835,6 +2836,12 @@ static int mt8186_afe_pcm_dev_probe(struct platform_device *pdev) afe_priv = afe->platform_priv; afe->dev = &pdev->dev; + ret = of_reserved_mem_device_init(dev); + if (ret) { + dev_info(dev, "no reserved memory found, pre-allocating buffers instead\n"); + afe->preallocate_buffers = true; + } + afe->base_addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(afe->base_addr)) return PTR_ERR(afe->base_addr); diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c index fd6af74d7995..3d32fe46118e 100644 --- a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c +++ b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -2179,6 +2180,12 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev) afe->dev = dev; + ret = of_reserved_mem_device_init(dev); + if (ret) { + dev_info(dev, "no reserved memory found, pre-allocating buffers instead\n"); + afe->preallocate_buffers = true; + } + /* init audio related clock */ ret = mt8192_init_clock(afe); if (ret) { From 9e7bc5cb8d089d9799e17a9ac99c5da9b13b02e3 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 12 Jun 2025 15:48:58 +0800 Subject: [PATCH 065/385] ASoC: mediatek: mt8183-afe-pcm: Support >32 bit DMA addresses The AFE DMA hardware supports up to 34 bits for DMA addresses. This is missing from the driver and prevents reserved memory regions from working properly when the allocated region is above the 4GB line. Fill in the related register offsets for each DAI, and also set the DMA mask. Also fill in the LSB end register offsets for completeness. Fixes: a94aec035a12 ("ASoC: mediatek: mt8183: add platform driver") Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Chen-Yu Tsai Link: https://patch.msgid.link/20250612074901.4023253-8-wenst@chromium.org Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-afe-pcm.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c index 9b6b45c646e6..7383184097a4 100644 --- a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c +++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c @@ -6,6 +6,7 @@ // Author: KaiChieh Chuang #include +#include #include #include #include @@ -432,6 +433,9 @@ static const struct snd_soc_component_driver mt8183_afe_pcm_dai_component = { .reg_ofs_base = AFE_##_id##_BASE, \ .reg_ofs_cur = AFE_##_id##_CUR, \ .reg_ofs_end = AFE_##_id##_END, \ + .reg_ofs_base_msb = AFE_##_id##_BASE_MSB, \ + .reg_ofs_cur_msb = AFE_##_id##_CUR_MSB, \ + .reg_ofs_end_msb = AFE_##_id##_END_MSB, \ .fs_reg = (_fs_reg), \ .fs_shift = _id##_MODE_SFT, \ .fs_maskbit = _id##_MODE_MASK, \ @@ -463,11 +467,17 @@ static const struct snd_soc_component_driver mt8183_afe_pcm_dai_component = { #define AFE_VUL12_BASE AFE_VUL_D2_BASE #define AFE_VUL12_CUR AFE_VUL_D2_CUR #define AFE_VUL12_END AFE_VUL_D2_END +#define AFE_VUL12_BASE_MSB AFE_VUL_D2_BASE_MSB +#define AFE_VUL12_CUR_MSB AFE_VUL_D2_CUR_MSB +#define AFE_VUL12_END_MSB AFE_VUL_D2_END_MSB #define AWB2_HD_ALIGN_SFT AWB2_ALIGN_SFT #define VUL12_DATA_SFT VUL12_MONO_SFT #define AFE_HDMI_BASE AFE_HDMI_OUT_BASE #define AFE_HDMI_CUR AFE_HDMI_OUT_CUR #define AFE_HDMI_END AFE_HDMI_OUT_END +#define AFE_HDMI_BASE_MSB AFE_HDMI_OUT_BASE_MSB +#define AFE_HDMI_CUR_MSB AFE_HDMI_OUT_CUR_MSB +#define AFE_HDMI_END_MSB AFE_HDMI_OUT_END_MSB static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = { MT8183_MEMIF(DL1, AFE_DAC_CON1, AFE_DAC_CON1), @@ -764,6 +774,10 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev) struct reset_control *rstc; int i, irq_id, ret; + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34)); + if (ret) + return ret; + afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); if (!afe) return -ENOMEM; From b2c090c9f6aa9d19f4c966233d7fcb872255f83b Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 12 Jun 2025 15:48:59 +0800 Subject: [PATCH 066/385] ASoC: mediatek: mt8173-afe-pcm: use local `dev` pointer in driver callbacks The probe and remove functions in the mt8183-afe-pcm driver repeatedly uses `&pdev->dev` for |struct device *|, but then assigns this value to `afe->dev` and uses that in other places in the same function. Store `&pdev->dev` in a local pointer and use that exclusively to avoid the numerous dereferences and to make the code more consistent. Lines are reflowed where it makes sense. Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Chen-Yu Tsai Link: https://patch.msgid.link/20250612074901.4023253-9-wenst@chromium.org Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173/mt8173-afe-pcm.c | 63 +++++++++++----------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c index f93d6348fdf8..c0fa623e0b17 100644 --- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c +++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c @@ -1054,26 +1054,26 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) struct mtk_base_afe *afe; struct mt8173_afe_private *afe_priv; struct snd_soc_component *comp_pcm, *comp_hdmi; + struct device *dev = &pdev->dev; - ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33)); + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(33)); if (ret) return ret; - afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); + afe = devm_kzalloc(dev, sizeof(*afe), GFP_KERNEL); if (!afe) return -ENOMEM; - afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv), - GFP_KERNEL); + afe->platform_priv = devm_kzalloc(dev, sizeof(*afe_priv), GFP_KERNEL); afe_priv = afe->platform_priv; if (!afe_priv) return -ENOMEM; - afe->dev = &pdev->dev; + afe->dev = dev; - ret = of_reserved_mem_device_init(&pdev->dev); + ret = of_reserved_mem_device_init(dev); if (ret) { - dev_info(&pdev->dev, "no reserved memory found, pre-allocating buffers instead\n"); + dev_info(dev, "no reserved memory found, pre-allocating buffers instead\n"); afe->preallocate_buffers = true; } @@ -1085,27 +1085,27 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) if (IS_ERR(afe->base_addr)) return PTR_ERR(afe->base_addr); - afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr, - &mt8173_afe_regmap_config); + afe->regmap = devm_regmap_init_mmio(dev, afe->base_addr, + &mt8173_afe_regmap_config); if (IS_ERR(afe->regmap)) return PTR_ERR(afe->regmap); /* initial audio related clock */ ret = mt8173_afe_init_audio_clk(afe); if (ret) { - dev_err(afe->dev, "mt8173_afe_init_audio_clk fail\n"); + dev_err(dev, "mt8173_afe_init_audio_clk fail\n"); return ret; } /* memif % irq initialize*/ afe->memif_size = MT8173_AFE_MEMIF_NUM; - afe->memif = devm_kcalloc(afe->dev, afe->memif_size, + afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif), GFP_KERNEL); if (!afe->memif) return -ENOMEM; afe->irqs_size = MT8173_AFE_IRQ_NUM; - afe->irqs = devm_kcalloc(afe->dev, afe->irqs_size, + afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs), GFP_KERNEL); if (!afe->irqs) return -ENOMEM; @@ -1124,9 +1124,9 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) platform_set_drvdata(pdev, afe); - pm_runtime_enable(&pdev->dev); - if (!pm_runtime_enabled(&pdev->dev)) { - ret = mt8173_afe_runtime_resume(&pdev->dev); + pm_runtime_enable(dev); + if (!pm_runtime_enabled(dev)) { + ret = mt8173_afe_runtime_resume(dev); if (ret) goto err_pm_disable; } @@ -1136,13 +1136,12 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) afe->runtime_resume = mt8173_afe_runtime_resume; afe->runtime_suspend = mt8173_afe_runtime_suspend; - ret = devm_snd_soc_register_component(&pdev->dev, - &mtk_afe_pcm_platform, - NULL, 0); + ret = devm_snd_soc_register_component(dev, &mtk_afe_pcm_platform, + NULL, 0); if (ret) goto err_pm_disable; - comp_pcm = devm_kzalloc(&pdev->dev, sizeof(*comp_pcm), GFP_KERNEL); + comp_pcm = devm_kzalloc(dev, sizeof(*comp_pcm), GFP_KERNEL); if (!comp_pcm) { ret = -ENOMEM; goto err_pm_disable; @@ -1150,7 +1149,7 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) ret = snd_soc_component_initialize(comp_pcm, &mt8173_afe_pcm_dai_component, - &pdev->dev); + dev); if (ret) goto err_pm_disable; @@ -1164,7 +1163,7 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) if (ret) goto err_pm_disable; - comp_hdmi = devm_kzalloc(&pdev->dev, sizeof(*comp_hdmi), GFP_KERNEL); + comp_hdmi = devm_kzalloc(dev, sizeof(*comp_hdmi), GFP_KERNEL); if (!comp_hdmi) { ret = -ENOMEM; goto err_cleanup_components; @@ -1172,7 +1171,7 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) ret = snd_soc_component_initialize(comp_hdmi, &mt8173_afe_hdmi_dai_component, - &pdev->dev); + dev); if (ret) goto err_cleanup_components; @@ -1186,30 +1185,32 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) if (ret) goto err_cleanup_components; - ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler, + ret = devm_request_irq(dev, irq_id, mt8173_afe_irq_handler, 0, "Afe_ISR_Handle", (void *)afe); if (ret) { - dev_err(afe->dev, "could not request_irq\n"); + dev_err(dev, "could not request_irq\n"); goto err_cleanup_components; } - dev_info(&pdev->dev, "MT8173 AFE driver initialized.\n"); + dev_info(dev, "MT8173 AFE driver initialized.\n"); return 0; err_cleanup_components: - snd_soc_unregister_component(&pdev->dev); + snd_soc_unregister_component(dev); err_pm_disable: - pm_runtime_disable(&pdev->dev); + pm_runtime_disable(dev); return ret; } static void mt8173_afe_pcm_dev_remove(struct platform_device *pdev) { - snd_soc_unregister_component(&pdev->dev); + struct device *dev = &pdev->dev; - pm_runtime_disable(&pdev->dev); - if (!pm_runtime_status_suspended(&pdev->dev)) - mt8173_afe_runtime_suspend(&pdev->dev); + snd_soc_unregister_component(dev); + + pm_runtime_disable(dev); + if (!pm_runtime_status_suspended(dev)) + mt8173_afe_runtime_suspend(dev); } static const struct of_device_id mt8173_afe_pcm_dt_match[] = { From bb8d8ba4715cb8f997d63d90ba935f6073595df5 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 12 Jun 2025 15:49:00 +0800 Subject: [PATCH 067/385] ASoC: mediatek: mt8183-afe-pcm: use local `dev` pointer in driver callbacks The probe and remove functions in the mt8183-afe-pcm driver repeatedly uses `&pdev->dev` for |struct device *|, but then assigns this value to `afe->dev` and uses that in other places in the same function. Store `&pdev->dev` in a local pointer and use that exclusively to avoid the numerous dereferences and to make the code more consistent. Lines are reflowed where it makes sense. Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Chen-Yu Tsai Link: https://patch.msgid.link/20250612074901.4023253-10-wenst@chromium.org Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-afe-pcm.c | 37 ++++++++++------------ 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c index 7383184097a4..a7fef772760a 100644 --- a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c +++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c @@ -770,27 +770,25 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev) { struct mtk_base_afe *afe; struct mt8183_afe_private *afe_priv; - struct device *dev; + struct device *dev = &pdev->dev; struct reset_control *rstc; int i, irq_id, ret; - ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34)); + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34)); if (ret) return ret; - afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); + afe = devm_kzalloc(dev, sizeof(*afe), GFP_KERNEL); if (!afe) return -ENOMEM; platform_set_drvdata(pdev, afe); - afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv), - GFP_KERNEL); + afe->platform_priv = devm_kzalloc(dev, sizeof(*afe_priv), GFP_KERNEL); if (!afe->platform_priv) return -ENOMEM; afe_priv = afe->platform_priv; - afe->dev = &pdev->dev; - dev = afe->dev; + afe->dev = dev; ret = of_reserved_mem_device_init(dev); if (ret) { @@ -835,7 +833,7 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev) /* enable clock for regcache get default value from hw */ afe_priv->pm_runtime_bypass_reg_ctl = true; - pm_runtime_get_sync(&pdev->dev); + pm_runtime_get_sync(dev); ret = regmap_reinit_cache(afe->regmap, &mt8183_afe_regmap_config); if (ret) { @@ -843,7 +841,7 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev) goto err_pm_disable; } - pm_runtime_put_sync(&pdev->dev); + pm_runtime_put_sync(dev); afe_priv->pm_runtime_bypass_reg_ctl = false; regcache_cache_only(afe->regmap, true); @@ -901,7 +899,7 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) { ret = dai_register_cbs[i](afe); if (ret) { - dev_warn(afe->dev, "dai register i %d fail, ret %d\n", + dev_warn(dev, "dai register i %d fail, ret %d\n", i, ret); goto err_pm_disable; } @@ -910,8 +908,7 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev) /* init dai_driver and component_driver */ ret = mtk_afe_combine_sub_dai(afe); if (ret) { - dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n", - ret); + dev_warn(dev, "mtk_afe_combine_sub_dai fail, ret %d\n", ret); goto err_pm_disable; } @@ -923,16 +920,14 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev) afe->runtime_suspend = mt8183_afe_runtime_suspend; /* register component */ - ret = devm_snd_soc_register_component(&pdev->dev, - &mtk_afe_pcm_platform, + ret = devm_snd_soc_register_component(dev, &mtk_afe_pcm_platform, NULL, 0); if (ret) { dev_warn(dev, "err_platform\n"); goto err_pm_disable; } - ret = devm_snd_soc_register_component(afe->dev, - &mt8183_afe_pcm_dai_component, + ret = devm_snd_soc_register_component(dev, &mt8183_afe_pcm_dai_component, afe->dai_drivers, afe->num_dai_drivers); if (ret) { @@ -943,15 +938,17 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev) return ret; err_pm_disable: - pm_runtime_disable(&pdev->dev); + pm_runtime_disable(dev); return ret; } static void mt8183_afe_pcm_dev_remove(struct platform_device *pdev) { - pm_runtime_disable(&pdev->dev); - if (!pm_runtime_status_suspended(&pdev->dev)) - mt8183_afe_runtime_suspend(&pdev->dev); + struct device *dev = &pdev->dev; + + pm_runtime_disable(dev); + if (!pm_runtime_status_suspended(dev)) + mt8183_afe_runtime_suspend(dev); } static const struct of_device_id mt8183_afe_pcm_dt_match[] = { From dfce24f0032439113848939816ef78b6e83f4086 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Thu, 12 Jun 2025 17:00:22 +0100 Subject: [PATCH 068/385] ALSA: hda: cs35l41: Add support for center channel in CS35L41 HDA Currently only left and right channels are supported for each amp. Support is needed for a center channel, using both left and right channel audio. Signed-off-by: Stefan Binding Link: https://patch.msgid.link/20250612160029.848104-2-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- include/sound/cs35l41.h | 12 +++++ sound/pci/hda/cs35l41_hda.c | 103 +++++++++++++++++++++++------------- sound/pci/hda/cs35l41_hda.h | 1 + 3 files changed, 78 insertions(+), 38 deletions(-) diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h index 43c6a9ef8d9f..7542cabfa726 100644 --- a/include/sound/cs35l41.h +++ b/include/sound/cs35l41.h @@ -609,6 +609,18 @@ #define CS35L41_DSP_NG_DELAY_MASK 0x0F00 #define CS35L41_DSP_NG_DELAY_SHIFT 8 +#define CS35L41_ASP_RX1_EN_MASK 0x00010000 +#define CS35L41_ASP_RX1_EN_SHIFT 16 +#define CS35L41_ASP_RX2_EN_MASK 0x00020000 +#define CS35L41_ASP_RX2_EN_SHIFT 17 +#define CS35L41_ASP_TX1_EN_MASK 0x00000001 +#define CS35L41_ASP_TX1_EN_SHIFT 0 +#define CS35L41_ASP_TX2_EN_MASK 0x00000002 +#define CS35L41_ASP_TX2_EN_SHIFT 1 +#define CS35L41_ASP_TX3_EN_MASK 0x00000004 +#define CS35L41_ASP_TX3_EN_SHIFT 2 +#define CS35L41_ASP_TX4_EN_MASK 0x00000008 +#define CS35L41_ASP_TX4_EN_SHIFT 3 #define CS35L41_ASP_FMT_MASK 0x0700 #define CS35L41_ASP_FMT_SHIFT 8 #define CS35L41_ASP_DOUT_HIZ_MASK 0x03 diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index d5bc81099d0d..c2cf3813872a 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -93,47 +93,36 @@ module_param(firmware_autostart, bool, 0444); MODULE_PARM_DESC(firmware_autostart, "Allow automatic firmware download on boot" "(0=Disable, 1=Enable) (default=1); "); +static const char channel_name[3] = { 'L', 'R', 'C' }; + static const struct reg_sequence cs35l41_hda_config[] = { { CS35L41_PLL_CLK_CTRL, 0x00000430 }, // 3072000Hz, BCLK Input, PLL_REFCLK_EN = 1 { CS35L41_DSP_CLK_CTRL, 0x00000003 }, // DSP CLK EN { CS35L41_GLOBAL_CLK_CTRL, 0x00000003 }, // GLOBAL_FS = 48 kHz - { CS35L41_SP_ENABLES, 0x00010000 }, // ASP_RX1_EN = 1 { CS35L41_SP_RATE_CTRL, 0x00000021 }, // ASP_BCLK_FREQ = 3.072 MHz { CS35L41_SP_FORMAT, 0x20200200 }, // 32 bits RX/TX slots, I2S, clk consumer - { CS35L41_SP_HIZ_CTRL, 0x00000002 }, // Hi-Z unused { CS35L41_SP_TX_WL, 0x00000018 }, // 24 cycles/slot { CS35L41_SP_RX_WL, 0x00000018 }, // 24 cycles/slot - { CS35L41_DAC_PCM1_SRC, 0x00000008 }, // DACPCM1_SRC = ASPRX1 { CS35L41_ASP_TX1_SRC, 0x00000018 }, // ASPTX1 SRC = VMON { CS35L41_ASP_TX2_SRC, 0x00000019 }, // ASPTX2 SRC = IMON - { CS35L41_ASP_TX3_SRC, 0x00000032 }, // ASPTX3 SRC = ERRVOL - { CS35L41_ASP_TX4_SRC, 0x00000033 }, // ASPTX4 SRC = CLASSH_TGT - { CS35L41_DSP1_RX1_SRC, 0x00000008 }, // DSP1RX1 SRC = ASPRX1 - { CS35L41_DSP1_RX2_SRC, 0x00000009 }, // DSP1RX2 SRC = ASPRX2 { CS35L41_DSP1_RX3_SRC, 0x00000018 }, // DSP1RX3 SRC = VMON { CS35L41_DSP1_RX4_SRC, 0x00000019 }, // DSP1RX4 SRC = IMON +}; + +static const struct reg_sequence cs35l41_hda_config_no_dsp[] = { + { CS35L41_SP_HIZ_CTRL, 0x00000002 }, // Hi-Z unused + { CS35L41_DAC_PCM1_SRC, 0x00000008 }, // DACPCM1_SRC = ASPRX1 + { CS35L41_ASP_TX3_SRC, 0x00000000 }, // ASPTX3 SRC = ZERO FILL + { CS35L41_ASP_TX4_SRC, 0x00000000 }, // ASPTX4 SRC = ZERO FILL { CS35L41_DSP1_RX5_SRC, 0x00000020 }, // DSP1RX5 SRC = ERRVOL + { CS35L41_DSP1_RX6_SRC, 0x00000021 }, // DSP1RX6 SRC = CLASSH_TGT }; static const struct reg_sequence cs35l41_hda_config_dsp[] = { - { CS35L41_PLL_CLK_CTRL, 0x00000430 }, // 3072000Hz, BCLK Input, PLL_REFCLK_EN = 1 - { CS35L41_DSP_CLK_CTRL, 0x00000003 }, // DSP CLK EN - { CS35L41_GLOBAL_CLK_CTRL, 0x00000003 }, // GLOBAL_FS = 48 kHz - { CS35L41_SP_ENABLES, 0x00010001 }, // ASP_RX1_EN = 1, ASP_TX1_EN = 1 - { CS35L41_SP_RATE_CTRL, 0x00000021 }, // ASP_BCLK_FREQ = 3.072 MHz - { CS35L41_SP_FORMAT, 0x20200200 }, // 32 bits RX/TX slots, I2S, clk consumer { CS35L41_SP_HIZ_CTRL, 0x00000003 }, // Hi-Z unused/disabled - { CS35L41_SP_TX_WL, 0x00000018 }, // 24 cycles/slot - { CS35L41_SP_RX_WL, 0x00000018 }, // 24 cycles/slot { CS35L41_DAC_PCM1_SRC, 0x00000032 }, // DACPCM1_SRC = DSP1TX1 - { CS35L41_ASP_TX1_SRC, 0x00000018 }, // ASPTX1 SRC = VMON - { CS35L41_ASP_TX2_SRC, 0x00000019 }, // ASPTX2 SRC = IMON { CS35L41_ASP_TX3_SRC, 0x00000028 }, // ASPTX3 SRC = VPMON { CS35L41_ASP_TX4_SRC, 0x00000029 }, // ASPTX4 SRC = VBSTMON - { CS35L41_DSP1_RX1_SRC, 0x00000008 }, // DSP1RX1 SRC = ASPRX1 - { CS35L41_DSP1_RX2_SRC, 0x00000008 }, // DSP1RX2 SRC = ASPRX1 - { CS35L41_DSP1_RX3_SRC, 0x00000018 }, // DSP1RX3 SRC = VMON - { CS35L41_DSP1_RX4_SRC, 0x00000019 }, // DSP1RX4 SRC = IMON { CS35L41_DSP1_RX6_SRC, 0x00000029 }, // DSP1RX6 SRC = VBSTMON }; @@ -657,6 +646,41 @@ static void cs35l41_irq_release(struct cs35l41_hda *cs35l41) cs35l41->irq_errors = 0; } +static void cs35l41_update_mixer(struct cs35l41_hda *cs35l41) +{ + struct regmap *reg = cs35l41->regmap; + unsigned int asp_en = 0; + unsigned int dsp1rx2_src = 0; + + regmap_multi_reg_write(reg, cs35l41_hda_config, ARRAY_SIZE(cs35l41_hda_config)); + + if (cs35l41->cs_dsp.running) { + asp_en |= CS35L41_ASP_TX1_EN_MASK; // ASP_TX1_EN = 1 + regmap_multi_reg_write(reg, cs35l41_hda_config_dsp, + ARRAY_SIZE(cs35l41_hda_config_dsp)); + if (cs35l41->hw_cfg.bst_type == CS35L41_INT_BOOST) + regmap_write(reg, CS35L41_DSP1_RX5_SRC, CS35L41_INPUT_SRC_VPMON); + else + regmap_write(reg, CS35L41_DSP1_RX5_SRC, CS35L41_INPUT_SRC_VBSTMON); + } else { + regmap_multi_reg_write(reg, cs35l41_hda_config_no_dsp, + ARRAY_SIZE(cs35l41_hda_config_no_dsp)); + } + + if (cs35l41->hw_cfg.spk_pos == CS35L41_CENTER) { + asp_en |= CS35L41_ASP_RX2_EN_MASK; // ASP_RX2_EN = 1 + dsp1rx2_src = 0x00000009; // DSP1RX2 SRC = ASPRX2 + } else { + dsp1rx2_src = 0x00000008; // DSP1RX2 SRC = ASPRX1 + } + + asp_en |= CS35L41_ASP_RX1_EN_MASK; // ASP_RX1_EN = 1 + + regmap_write(reg, CS35L41_SP_ENABLES, asp_en); + regmap_write(reg, CS35L41_DSP1_RX1_SRC, 0x00000008); // DSP1RX1 SRC = ASPRX1 + regmap_write(reg, CS35L41_DSP1_RX2_SRC, dsp1rx2_src); +} + static void cs35l41_hda_play_start(struct device *dev) { struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); @@ -671,19 +695,13 @@ static void cs35l41_hda_play_start(struct device *dev) cs35l41->playback_started = true; + cs35l41_update_mixer(cs35l41); + if (cs35l41->cs_dsp.running) { - regmap_multi_reg_write(reg, cs35l41_hda_config_dsp, - ARRAY_SIZE(cs35l41_hda_config_dsp)); - if (cs35l41->hw_cfg.bst_type == CS35L41_INT_BOOST) - regmap_write(reg, CS35L41_DSP1_RX5_SRC, CS35L41_INPUT_SRC_VPMON); - else - regmap_write(reg, CS35L41_DSP1_RX5_SRC, CS35L41_INPUT_SRC_VBSTMON); regmap_update_bits(reg, CS35L41_PWR_CTRL2, CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK, 1 << CS35L41_VMON_EN_SHIFT | 1 << CS35L41_IMON_EN_SHIFT); cs35l41_set_cspl_mbox_cmd(cs35l41->dev, reg, CSPL_MBOX_CMD_RESUME); - } else { - regmap_multi_reg_write(reg, cs35l41_hda_config, ARRAY_SIZE(cs35l41_hda_config)); } regmap_update_bits(reg, CS35L41_PWR_CTRL2, CS35L41_AMP_EN_MASK, 1 << CS35L41_AMP_EN_SHIFT); if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) @@ -841,22 +859,31 @@ static void cs35l41_hda_post_playback_hook(struct device *dev, int action) } } -static int cs35l41_hda_channel_map(struct device *dev, unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot) +static int cs35l41_hda_channel_map(struct cs35l41_hda *cs35l41) { - struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); - static const char * const channel_name[] = { "L", "R" }; + unsigned int tx_num = 0; + unsigned int *tx_slot = NULL; + unsigned int rx_num; + unsigned int *rx_slot; + unsigned int mono = 0; if (!cs35l41->amp_name) { - if (*rx_slot >= ARRAY_SIZE(channel_name)) + if (cs35l41->hw_cfg.spk_pos >= ARRAY_SIZE(channel_name)) return -EINVAL; - cs35l41->amp_name = devm_kasprintf(cs35l41->dev, GFP_KERNEL, "%s%d", - channel_name[*rx_slot], cs35l41->channel_index); + cs35l41->amp_name = devm_kasprintf(cs35l41->dev, GFP_KERNEL, "%c%d", + channel_name[cs35l41->hw_cfg.spk_pos], + cs35l41->channel_index); if (!cs35l41->amp_name) return -ENOMEM; } + rx_num = 1; + if (cs35l41->hw_cfg.spk_pos == CS35L41_CENTER) + rx_slot = &mono; + else + rx_slot = &cs35l41->hw_cfg.spk_pos; + return cs35l41_set_channels(cs35l41->dev, cs35l41->regmap, tx_num, tx_slot, rx_num, rx_slot); } @@ -1495,7 +1522,7 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas "CS35L41 Bound - SSID: %s, BST: %d, VSPK: %d, CH: %c, FW EN: %d, SPKID: %d\n", cs35l41->acpi_subsystem_id, cs35l41->hw_cfg.bst_type, cs35l41->hw_cfg.gpio1.func == CS35l41_VSPK_SWITCH, - cs35l41->hw_cfg.spk_pos ? 'R' : 'L', + channel_name[cs35l41->hw_cfg.spk_pos], cs35l41->cs_dsp.running, cs35l41->speaker_id); return ret; @@ -1709,7 +1736,7 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41) if (using_irq) cs35l41_configure_interrupt(cs35l41, irq_pol); - return cs35l41_hda_channel_map(cs35l41->dev, 0, NULL, 1, &hw_cfg->spk_pos); + return cs35l41_hda_channel_map(cs35l41); } int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int fixed_gpio_id) diff --git a/sound/pci/hda/cs35l41_hda.h b/sound/pci/hda/cs35l41_hda.h index c730b3351589..7d003c598e93 100644 --- a/sound/pci/hda/cs35l41_hda.h +++ b/sound/pci/hda/cs35l41_hda.h @@ -42,6 +42,7 @@ struct cs35l41_amp_efi_data { enum cs35l41_hda_spk_pos { CS35L41_LEFT, CS35L41_RIGHT, + CS35L41_CENTER, }; enum cs35l41_hda_gpio_function { From 84fc8896f0d9d1c075e0e08a416faedbd73907fa Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Thu, 12 Jun 2025 17:00:23 +0100 Subject: [PATCH 069/385] ALSA: hda/realtek: Add support for ASUS NUC using CS35L41 HDA Add support for ASUS NUC14LNS. This NUC uses a single CS35L41 Amp in using Internal Boost with SPI. To support the Single Amp, a new quirk is required. Signed-off-by: Stefan Binding Link: https://patch.msgid.link/20250612160029.848104-3-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index cd0d7ba7320e..7db62477b785 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7296,6 +7296,11 @@ static void cs35l41_fixup_spi_two(struct hda_codec *codec, const struct hda_fixu comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 2); } +static void cs35l41_fixup_spi_one(struct hda_codec *codec, const struct hda_fixup *fix, int action) +{ + comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 1); +} + static void cs35l41_fixup_spi_four(struct hda_codec *codec, const struct hda_fixup *fix, int action) { comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 4); @@ -7986,6 +7991,7 @@ enum { ALC287_FIXUP_CS35L41_I2C_2, ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED, ALC287_FIXUP_CS35L41_I2C_4, + ALC245_FIXUP_CS35L41_SPI_1, ALC245_FIXUP_CS35L41_SPI_2, ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED, ALC245_FIXUP_CS35L41_SPI_4, @@ -10112,6 +10118,10 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = cs35l41_fixup_spi_two, }, + [ALC245_FIXUP_CS35L41_SPI_1] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs35l41_fixup_spi_one, + }, [ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED] = { .type = HDA_FIXUP_FUNC, .v.func = cs35l41_fixup_spi_two, @@ -11049,6 +11059,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x8516, "ASUS X101CH", ALC269_FIXUP_ASUS_X101), + SND_PCI_QUIRK(0x1043, 0x88f4, "ASUS NUC14LNS", ALC245_FIXUP_CS35L41_SPI_1), SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2), SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), From d0630a0b80c08530857146e3bf183a7d6b743847 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 Jun 2025 10:15:30 +0200 Subject: [PATCH 070/385] ALSA: usb-audio: Fix build with CONFIG_INPUT=n The recent addition of DualSense mixer quirk relies on the input device handle, and the build can fail if CONFIG_INPUT isn't set. Put (rather ugly) workarounds to wrap with IS_REACHABLE() for avoiding the build error. Fixes: 79d561c4ec04 ("ALSA: usb-audio: Add mixer quirk for Sony DualSense PS5") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202506130733.gnPKw2l3-lkp@intel.com/ Reviewed-by: Cristian Ciocaltea Link: https://patch.msgid.link/20250613081543.7404-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index a0ffe8b559dc..7cc27ae5512f 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -532,6 +532,7 @@ static int snd_emu0204_controls_create(struct usb_mixer_interface *mixer) &snd_emu0204_control, NULL); } +#if IS_REACHABLE(CONFIG_INPUT) /* * Sony DualSense controller (PS5) jack detection * @@ -788,6 +789,7 @@ static int snd_dualsense_controls_create(struct usb_mixer_interface *mixer) return snd_dualsense_jack_create(mixer, "Headset Mic Jack", false); } +#endif /* IS_REACHABLE(CONFIG_INPUT) */ /* ASUS Xonar U1 / U3 controls */ @@ -4331,10 +4333,12 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) err = snd_emu0204_controls_create(mixer); break; +#if IS_REACHABLE(CONFIG_INPUT) case USB_ID(0x054c, 0x0ce6): /* Sony DualSense controller (PS5) */ case USB_ID(0x054c, 0x0df2): /* Sony DualSense Edge controller (PS5) */ err = snd_dualsense_controls_create(mixer); break; +#endif /* IS_REACHABLE(CONFIG_INPUT) */ case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C400 */ From dae29b678bb74aa2995c1d2b0fa6b1b91f5d8986 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 13 Jun 2025 06:00:20 +0000 Subject: [PATCH 071/385] ASoC: soc-ops-test: dynamically allocate struct snd_ctl_elem_value This structure is really too larget to be allocated on the stack: linux/sound/soc/soc-ops-test.c:520:1: error: the frame size of\ 1304 bytes is larger than 1280 bytes [-Werror=frame-larger-than=] Change the function to dynamically allocate it instead. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87sek489l8.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-ops-test.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/sound/soc/soc-ops-test.c b/sound/soc/soc-ops-test.c index dc1e482bba6a..1bafa5626d48 100644 --- a/sound/soc/soc-ops-test.c +++ b/sound/soc/soc-ops-test.c @@ -481,22 +481,27 @@ static void soc_ops_test_access(struct kunit *test) .private_data = &priv->component, .private_value = (unsigned long)¶m->mc, }; - struct snd_ctl_elem_value result; unsigned int val; int ret; + /* it is too large struct. use kzalloc() */ + struct snd_ctl_elem_value *result; + + result = kzalloc(sizeof(*result), GFP_KERNEL); + if (!result) + return; ret = regmap_write(priv->component.regmap, 0x0, param->init); KUNIT_ASSERT_FALSE(test, ret); ret = regmap_write(priv->component.regmap, 0x1, param->init); KUNIT_ASSERT_FALSE(test, ret); - result.value.integer.value[0] = param->lctl; - result.value.integer.value[1] = param->rctl; + result->value.integer.value[0] = param->lctl; + result->value.integer.value[1] = param->rctl; - ret = param->put(&kctl, &result); + ret = param->put(&kctl, result); KUNIT_ASSERT_EQ(test, ret, param->ret); if (ret < 0) - return; + goto end; ret = regmap_read(priv->component.regmap, 0x0, &val); KUNIT_ASSERT_FALSE(test, ret); @@ -506,17 +511,19 @@ static void soc_ops_test_access(struct kunit *test) KUNIT_ASSERT_FALSE(test, ret); KUNIT_EXPECT_EQ(test, val, (param->init & ~param->rmask) | param->rreg); - result.value.integer.value[0] = 0; - result.value.integer.value[1] = 0; + result->value.integer.value[0] = 0; + result->value.integer.value[1] = 0; - ret = param->get(&kctl, &result); + ret = param->get(&kctl, result); KUNIT_ASSERT_GE(test, ret, 0); - KUNIT_EXPECT_EQ(test, result.value.integer.value[0], param->lctl); + KUNIT_EXPECT_EQ(test, result->value.integer.value[0], param->lctl); if (param->layout != SOC_OPS_TEST_SINGLE) - KUNIT_EXPECT_EQ(test, result.value.integer.value[1], param->rctl); + KUNIT_EXPECT_EQ(test, result->value.integer.value[1], param->rctl); else - KUNIT_EXPECT_EQ(test, result.value.integer.value[1], 0); + KUNIT_EXPECT_EQ(test, result->value.integer.value[1], 0); +end: + kfree(result); } KUNIT_ARRAY_PARAM(all_info_tests, all_info_test_params, info_test_desc); From 5eb8a0d7733d4cd32a776acf1d1aa1c7c01c8a14 Mon Sep 17 00:00:00 2001 From: Terry Cheong Date: Fri, 13 Jun 2025 16:51:27 +0800 Subject: [PATCH 072/385] ASoC: hdmi-codec: use SND_JACK_AVOUT as jack status Use SND_JACK_AVOUT as the mask to align with hdac_hdmi driver so that we can determine HDMI/DP devices from event type. Most drivers that uses hdmi-codec driver will not be affected since they are creating jacks with SND_JACK_LINEOUT mask. They will still report SND_JACK_LINEOUT when the jack status is updated with snd_soc_jack_report. Signed-off-by: Terry Cheong Link: https://patch.msgid.link/20250613-hdmi-v1-1-665ba7ecd5e7@chromium.org Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 31121f9c18c9..e1933f733af1 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -943,7 +943,7 @@ static void hdmi_codec_jack_report(struct hdmi_codec_priv *hcp, { if (jack_status != hcp->jack_status) { if (hcp->jack) - snd_soc_jack_report(hcp->jack, jack_status, SND_JACK_LINEOUT); + snd_soc_jack_report(hcp->jack, jack_status, SND_JACK_AVOUT); hcp->jack_status = jack_status; } } @@ -964,7 +964,7 @@ static void plugged_cb(struct device *dev, bool plugged) else snd_show_eld(dev, &hcp->eld_parsed); } - hdmi_codec_jack_report(hcp, SND_JACK_LINEOUT); + hdmi_codec_jack_report(hcp, SND_JACK_AVOUT); } else { hdmi_codec_jack_report(hcp, 0); memset(hcp->eld, 0, sizeof(hcp->eld)); @@ -984,7 +984,7 @@ static int hdmi_codec_set_jack(struct snd_soc_component *component, * Report the initial jack status which may have been provided * by the parent hdmi driver while the hpd hook was registered. */ - snd_soc_jack_report(jack, hcp->jack_status, SND_JACK_LINEOUT); + snd_soc_jack_report(jack, hcp->jack_status, SND_JACK_AVOUT); return 0; } From 2acd83beb4d3fdff1e74f56d2f16f7e70f1faa6d Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Sat, 14 Jun 2025 08:43:14 +0200 Subject: [PATCH 073/385] ALSA: pcm: refactor copy from/to user in SNDRV_PCM_IOCTL_SYNC_PTR In an effort of optimising SNDRV_PCM_IOCTL_SYNC_PTR ioctl which is a hot path, lets first refactor the copy from and to user with macros. This is done with macros and not static inline fonctions because types differs between the different versions of snd_pcm_sync_ptr() like functions. First step is to refactor only snd_pcm_ioctl_sync_ptr_compat() and snd_pcm_ioctl_sync_ptr_x32() as it would be a performance regression for snd_pcm_sync_ptr() and snd_pcm_ioctl_sync_ptr_buggy() for now. They may be refactored after next patch. Signed-off-by: Christophe Leroy Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/f8b77932bb9ce96148ae5c3953e7ee44fa2359f8.1749883041.git.christophe.leroy@csgroup.eu --- sound/core/pcm_compat.c | 14 ++------------ sound/core/pcm_native.c | 42 +++++++++++++++++++++++++++++------------ 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index a42ec7f5a1da..17540020ac2f 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -418,9 +418,7 @@ static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream, if (snd_BUG_ON(!runtime)) return -EINVAL; - if (get_user(sflags, &src->flags) || - get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || - get_user(scontrol.avail_min, &src->c.control.avail_min)) + if (snd_pcm_sync_ptr_get_user(sflags, scontrol, src)) return -EFAULT; if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) { err = snd_pcm_hwsync(substream); @@ -450,15 +448,7 @@ static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream, } if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); - if (put_user(sstatus.state, &src->s.status.state) || - put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) || - put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp_sec) || - put_user(sstatus.tstamp.tv_nsec, &src->s.status.tstamp_nsec) || - put_user(sstatus.suspended_state, &src->s.status.suspended_state) || - put_user(sstatus.audio_tstamp.tv_sec, &src->s.status.audio_tstamp_sec) || - put_user(sstatus.audio_tstamp.tv_nsec, &src->s.status.audio_tstamp_nsec) || - put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || - put_user(scontrol.avail_min, &src->c.control.avail_min)) + if (snd_pcm_sync_ptr_put_user(sstatus, scontrol, src)) return -EFAULT; return 0; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index ecb71bf1859d..1f8f6d95b18c 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3052,6 +3052,34 @@ static inline int snd_pcm_hwsync(struct snd_pcm_substream *substream) return snd_pcm_delay(substream, NULL); } +#define snd_pcm_sync_ptr_get_user(__f, __c, __ptr) ({ \ + int __err = 0; \ + typeof(*(__ptr)) __user *__src = (__ptr); \ + \ + if (get_user(__f, &src->flags) || \ + get_user(__c.appl_ptr, &__src->c.control.appl_ptr) || \ + get_user(__c.avail_min, &__src->c.control.avail_min)) \ + __err = -EFAULT; \ + __err; \ +}) + +#define snd_pcm_sync_ptr_put_user(__s, __c, __ptr) ({ \ + int __err = 0; \ + typeof(*(__ptr)) __user *__src = (__ptr); \ + \ + if (put_user(__s.state, &__src->s.status.state) || \ + put_user(__s.hw_ptr, &__src->s.status.hw_ptr) || \ + put_user(__s.tstamp.tv_sec, &__src->s.status.tstamp_sec) || \ + put_user(__s.tstamp.tv_nsec, &__src->s.status.tstamp_nsec) || \ + put_user(__s.suspended_state, &__src->s.status.suspended_state) || \ + put_user(__s.audio_tstamp.tv_sec, &__src->s.status.audio_tstamp_sec) || \ + put_user(__s.audio_tstamp.tv_nsec, &__src->s.status.audio_tstamp_nsec) || \ + put_user(__c.appl_ptr, &__src->c.control.appl_ptr) || \ + put_user(__c.avail_min, &__src->c.control.avail_min)) \ + __err = -EFAULT; \ + __err; \ +}) + static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, struct snd_pcm_sync_ptr __user *_sync_ptr) { @@ -3165,9 +3193,7 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream, if (snd_BUG_ON(!runtime)) return -EINVAL; - if (get_user(sflags, &src->flags) || - get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || - get_user(scontrol.avail_min, &src->c.control.avail_min)) + if (snd_pcm_sync_ptr_get_user(sflags, scontrol, src)) return -EFAULT; if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) { err = snd_pcm_hwsync(substream); @@ -3200,15 +3226,7 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream, } if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); - if (put_user(sstatus.state, &src->s.status.state) || - put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) || - put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp_sec) || - put_user(sstatus.tstamp.tv_nsec, &src->s.status.tstamp_nsec) || - put_user(sstatus.suspended_state, &src->s.status.suspended_state) || - put_user(sstatus.audio_tstamp.tv_sec, &src->s.status.audio_tstamp_sec) || - put_user(sstatus.audio_tstamp.tv_nsec, &src->s.status.audio_tstamp_nsec) || - put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || - put_user(scontrol.avail_min, &src->c.control.avail_min)) + if (snd_pcm_sync_ptr_put_user(sstatus, scontrol, src)) return -EFAULT; return 0; From a9b49bf8ad5905ebd999da345dcff3b9fad43877 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Sat, 14 Jun 2025 08:43:15 +0200 Subject: [PATCH 074/385] ALSA: pcm: Convert SNDRV_PCM_IOCTL_SYNC_PTR to user_access_begin/user_access_end() With user access protection (Called SMAP on x86 or KUAP on powerpc) each and every call to get_user() or put_user() performs heavy operations to unlock and lock kernel access to userspace. SNDRV_PCM_IOCTL_SYNC_PTR is a hot path which is called really often and needs to run as fast as possible. To improve performance, perform user accesses by blocks using user_access_begin/user_access_end() and unsafe_get_user()/ unsafe_put_user(). Before the patch the 9 calls to put_user() at the end of snd_pcm_ioctl_sync_ptr_compat() imply the following set of instructions about 9 times (access_ok - enable user - write - disable user): 0.00 : c057f858: 3d 20 7f ff lis r9,32767 0.29 : c057f85c: 39 5e 00 14 addi r10,r30,20 0.77 : c057f860: 61 29 ff fc ori r9,r9,65532 0.32 : c057f864: 7c 0a 48 40 cmplw r10,r9 0.36 : c057f868: 41 a1 fb 58 bgt c057f3c0 0.30 : c057f86c: 3d 20 dc 00 lis r9,-9216 1.95 : c057f870: 7d 3a c3 a6 mtspr 794,r9 0.33 : c057f874: 92 8a 00 00 stw r20,0(r10) 0.27 : c057f878: 3d 20 de 00 lis r9,-8704 0.28 : c057f87c: 7d 3a c3 a6 mtspr 794,r9 ... A perf profile shows that in total the 9 put_user() represent 36% of the time spent in snd_pcm_ioctl() and about 80 instructions. With this patch everything is done in 13 instructions and represent only 15% of the time spent in snd_pcm_ioctl(): 0.57 : c057f5dc: 3d 20 dc 00 lis r9,-9216 0.98 : c057f5e0: 7d 3a c3 a6 mtspr 794,r9 0.16 : c057f5e4: 92 7f 00 04 stw r19,4(r31) 0.63 : c057f5e8: 93 df 00 0c stw r30,12(r31) 0.16 : c057f5ec: 93 9f 00 10 stw r28,16(r31) 4.95 : c057f5f0: 92 9f 00 14 stw r20,20(r31) 0.19 : c057f5f4: 92 5f 00 18 stw r18,24(r31) 0.49 : c057f5f8: 92 bf 00 1c stw r21,28(r31) 0.27 : c057f5fc: 93 7f 00 20 stw r27,32(r31) 5.88 : c057f600: 93 36 00 00 stw r25,0(r22) 0.11 : c057f604: 93 17 00 00 stw r24,0(r23) 0.00 : c057f608: 3d 20 de 00 lis r9,-8704 0.79 : c057f60c: 7d 3a c3 a6 mtspr 794,r9 Note that here the access_ok() in user_write_access_begin() is skipped because the exact same verification has already been performed at the beginning of the fonction with the call to user_read_access_begin(). Signed-off-by: Christophe Leroy Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/eccd047f2dfeb550129a1d60035e2233c4401d0c.1749883041.git.christophe.leroy@csgroup.eu --- sound/core/pcm_native.c | 44 ++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 1f8f6d95b18c..5eb59fdb3cb2 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3053,30 +3053,42 @@ static inline int snd_pcm_hwsync(struct snd_pcm_substream *substream) } #define snd_pcm_sync_ptr_get_user(__f, __c, __ptr) ({ \ - int __err = 0; \ + __label__ failed, failed_begin; \ + int __err = -EFAULT; \ typeof(*(__ptr)) __user *__src = (__ptr); \ \ - if (get_user(__f, &src->flags) || \ - get_user(__c.appl_ptr, &__src->c.control.appl_ptr) || \ - get_user(__c.avail_min, &__src->c.control.avail_min)) \ - __err = -EFAULT; \ + if (!user_read_access_begin(__src, sizeof(*__src))) \ + goto failed_begin; \ + unsafe_get_user(__f, &__src->flags, failed); \ + unsafe_get_user(__c.appl_ptr, &__src->c.control.appl_ptr, failed); \ + unsafe_get_user(__c.avail_min, &__src->c.control.avail_min, failed); \ + __err = 0; \ +failed: \ + user_read_access_end(); \ +failed_begin: \ __err; \ }) #define snd_pcm_sync_ptr_put_user(__s, __c, __ptr) ({ \ - int __err = 0; \ + __label__ failed, failed_begin; \ + int __err = -EFAULT; \ typeof(*(__ptr)) __user *__src = (__ptr); \ \ - if (put_user(__s.state, &__src->s.status.state) || \ - put_user(__s.hw_ptr, &__src->s.status.hw_ptr) || \ - put_user(__s.tstamp.tv_sec, &__src->s.status.tstamp_sec) || \ - put_user(__s.tstamp.tv_nsec, &__src->s.status.tstamp_nsec) || \ - put_user(__s.suspended_state, &__src->s.status.suspended_state) || \ - put_user(__s.audio_tstamp.tv_sec, &__src->s.status.audio_tstamp_sec) || \ - put_user(__s.audio_tstamp.tv_nsec, &__src->s.status.audio_tstamp_nsec) || \ - put_user(__c.appl_ptr, &__src->c.control.appl_ptr) || \ - put_user(__c.avail_min, &__src->c.control.avail_min)) \ - __err = -EFAULT; \ + if (!user_write_access_begin(__src, sizeof(*__src))) \ + goto failed_begin; \ + unsafe_put_user(__s.state, &__src->s.status.state, failed); \ + unsafe_put_user(__s.hw_ptr, &__src->s.status.hw_ptr, failed); \ + unsafe_put_user(__s.tstamp.tv_sec, &__src->s.status.tstamp_sec, failed);\ + unsafe_put_user(__s.tstamp.tv_nsec, &__src->s.status.tstamp_nsec, failed); \ + unsafe_put_user(__s.suspended_state, &__src->s.status.suspended_state, failed); \ + unsafe_put_user(__s.audio_tstamp.tv_sec, &__src->s.status.audio_tstamp_sec, failed); \ + unsafe_put_user(__s.audio_tstamp.tv_nsec, &__src->s.status.audio_tstamp_nsec, failed); \ + unsafe_put_user(__c.appl_ptr, &__src->c.control.appl_ptr, failed); \ + unsafe_put_user(__c.avail_min, &__src->c.control.avail_min, failed); \ + __err = 0; \ +failed: \ + user_write_access_end(); \ +failed_begin: \ __err; \ }) From c72fad73ba497c237fcc0d771d87a2f8447599bb Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Sat, 14 Jun 2025 08:43:16 +0200 Subject: [PATCH 075/385] ALSA: pcm: Replace [audio_]tstamp_[n]sec by struct __snd_timespec in struct snd_pcm_mmap_status32 To match struct __snd_pcm_mmap_status and enable reuse of snd_pcm_sync_ptr_get_user() and snd_pcm_sync_ptr_put_user() by snd_pcm_sync_ptr() replace tstamp_sec and tstamp_nsec fields by a struct __snd_timespec in struct snd_pcm_mmap_status32. Do the same with audio_tstamp_sec and audio_tstamp_nsec. This is possible because struct snd_pcm_mmap_status32 is packed and __SND_STRUCT_TIME64 is always defined for kernel which means struct __snd_timespec is always defined as: struct __snd_timespec { __s32 tv_sec; __s32 tv_nsec; }; Signed-off-by: Christophe Leroy Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/df8ea1a9aff61c3e358759b1f495bdb9fb8a3e6a.1749883041.git.christophe.leroy@csgroup.eu --- sound/core/pcm_compat.c | 6 ++---- sound/core/pcm_native.c | 14 ++++++-------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 17540020ac2f..54eb9bd8eb21 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -377,12 +377,10 @@ struct snd_pcm_mmap_status_x32 { s32 pad1; u32 hw_ptr; u32 pad2; /* alignment */ - s64 tstamp_sec; - s64 tstamp_nsec; + struct __snd_timespec64 tstamp; snd_pcm_state_t suspended_state; s32 pad3; - s64 audio_tstamp_sec; - s64 audio_tstamp_nsec; + struct __snd_timespec64 audio_tstamp; } __packed; struct snd_pcm_mmap_control_x32 { diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 5eb59fdb3cb2..b7339c9ebb1f 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3078,11 +3078,11 @@ failed_begin: \ goto failed_begin; \ unsafe_put_user(__s.state, &__src->s.status.state, failed); \ unsafe_put_user(__s.hw_ptr, &__src->s.status.hw_ptr, failed); \ - unsafe_put_user(__s.tstamp.tv_sec, &__src->s.status.tstamp_sec, failed);\ - unsafe_put_user(__s.tstamp.tv_nsec, &__src->s.status.tstamp_nsec, failed); \ + unsafe_put_user(__s.tstamp.tv_sec, &__src->s.status.tstamp.tv_sec, failed); \ + unsafe_put_user(__s.tstamp.tv_nsec, &__src->s.status.tstamp.tv_nsec, failed); \ unsafe_put_user(__s.suspended_state, &__src->s.status.suspended_state, failed); \ - unsafe_put_user(__s.audio_tstamp.tv_sec, &__src->s.status.audio_tstamp_sec, failed); \ - unsafe_put_user(__s.audio_tstamp.tv_nsec, &__src->s.status.audio_tstamp_nsec, failed); \ + unsafe_put_user(__s.audio_tstamp.tv_sec, &__src->s.status.audio_tstamp.tv_sec, failed); \ + unsafe_put_user(__s.audio_tstamp.tv_nsec, &__src->s.status.audio_tstamp.tv_nsec, failed);\ unsafe_put_user(__c.appl_ptr, &__src->c.control.appl_ptr, failed); \ unsafe_put_user(__c.avail_min, &__src->c.control.avail_min, failed); \ __err = 0; \ @@ -3143,11 +3143,9 @@ struct snd_pcm_mmap_status32 { snd_pcm_state_t state; s32 pad1; u32 hw_ptr; - s32 tstamp_sec; - s32 tstamp_nsec; + struct __snd_timespec tstamp; snd_pcm_state_t suspended_state; - s32 audio_tstamp_sec; - s32 audio_tstamp_nsec; + struct __snd_timespec audio_tstamp; } __packed; struct snd_pcm_mmap_control32 { From 8629eea901b8a672dd096ca783ece8322701ca5a Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Sat, 14 Jun 2025 08:43:17 +0200 Subject: [PATCH 076/385] ALSA: pcm: Convert snd_pcm_sync_ptr() to user_access_begin/user_access_end() Now that snd_pcm_sync_ptr_get_user() and snd_pcm_sync_ptr_put_user() are converted to user_access_begin/user_access_end(), snd_pcm_sync_ptr_get_user() is more efficient than a raw get_user() followed by a copy_from_user(). And because copy_{to/from}_user() are generic functions focussed on transfer of big data blocks to/from user, snd_pcm_sync_ptr_put_user() is also more efficient for small amont of data. So use snd_pcm_sync_ptr_get_user() and snd_pcm_sync_ptr_put_user() in snd_pcm_sync_ptr() too. snd_pcm_ioctl_sync_ptr_buggy() is left as it is because the conversion wouldn't be straigh-forward due to the workaround it provides. Signed-off-by: Christophe Leroy Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/6ce6bc4da498ea7ea2be5f279b374370b1613b13.1749883041.git.christophe.leroy@csgroup.eu --- sound/core/pcm_native.c | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index b7339c9ebb1f..1eab940fa2e5 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3096,45 +3096,43 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, struct snd_pcm_sync_ptr __user *_sync_ptr) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_pcm_sync_ptr sync_ptr; volatile struct snd_pcm_mmap_status *status; volatile struct snd_pcm_mmap_control *control; + u32 sflags; + struct snd_pcm_mmap_control scontrol; + struct snd_pcm_mmap_status sstatus; int err; - memset(&sync_ptr, 0, sizeof(sync_ptr)); - if (get_user(sync_ptr.flags, (unsigned __user *)&(_sync_ptr->flags))) + if (snd_pcm_sync_ptr_get_user(sflags, scontrol, _sync_ptr)) return -EFAULT; - if (copy_from_user(&sync_ptr.c.control, &(_sync_ptr->c.control), sizeof(struct snd_pcm_mmap_control))) - return -EFAULT; status = runtime->status; control = runtime->control; - if (sync_ptr.flags & SNDRV_PCM_SYNC_PTR_HWSYNC) { + if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) { err = snd_pcm_hwsync(substream); if (err < 0) return err; } scoped_guard(pcm_stream_lock_irq, substream) { - if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) { - err = pcm_lib_apply_appl_ptr(substream, - sync_ptr.c.control.appl_ptr); + if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) { + err = pcm_lib_apply_appl_ptr(substream, scontrol.appl_ptr); if (err < 0) return err; } else { - sync_ptr.c.control.appl_ptr = control->appl_ptr; + scontrol.appl_ptr = control->appl_ptr; } - if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) - control->avail_min = sync_ptr.c.control.avail_min; + if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) + control->avail_min = scontrol.avail_min; else - sync_ptr.c.control.avail_min = control->avail_min; - sync_ptr.s.status.state = status->state; - sync_ptr.s.status.hw_ptr = status->hw_ptr; - sync_ptr.s.status.tstamp = status->tstamp; - sync_ptr.s.status.suspended_state = status->suspended_state; - sync_ptr.s.status.audio_tstamp = status->audio_tstamp; + scontrol.avail_min = control->avail_min; + sstatus.state = status->state; + sstatus.hw_ptr = status->hw_ptr; + sstatus.tstamp = status->tstamp; + sstatus.suspended_state = status->suspended_state; + sstatus.audio_tstamp = status->audio_tstamp; } - if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) + if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); - if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr))) + if (snd_pcm_sync_ptr_put_user(sstatus, scontrol, _sync_ptr)) return -EFAULT; return 0; } From b2904df0a347f206900681f566bb53fc42bd8ba7 Mon Sep 17 00:00:00 2001 From: Baojun Xu Date: Mon, 16 Jun 2025 11:56:07 +0800 Subject: [PATCH 077/385] ALSA: hda/tas2781: Add compatible for hardware id TIAS2781 and TXNW2781 TIAS2781 is unofficial hardware id in ACPI for tas2781 in HDA, has been used for several projects. TXNW is the official hardware id for TI, will be used in new projects, including device on SPI bus, which was enumerated by drivers/acpi/scan.c, and probed by smi_probe() in drivers/platform/x86/serial-multi-instantiate.c. This patch will support both TIAS2781 and TXNW2781 in ACPI with tas2781 under HDA. As our I2C driver will handle all of slaver devices, so we probe first device only: "TXNW2781:00-tas2781-hda.0" Signed-off-by: Baojun Xu Link: https://patch.msgid.link/20250616035607.2569-1-baojun.xu@ti.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 21 +++++++++++++++++---- sound/pci/hda/tas2781_hda_i2c.c | 6 ++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 7db62477b785..84a68c7d65b7 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7328,7 +7328,7 @@ static void alc285_fixup_asus_ga403u(struct hda_codec *cdc, const struct hda_fix alc_fixup_inv_dmic(cdc, fix, action); } -static void tas2781_fixup_i2c(struct hda_codec *cdc, +static void tas2781_fixup_tias_i2c(struct hda_codec *cdc, const struct hda_fixup *fix, int action) { comp_generic_fixup(cdc, action, "i2c", "TIAS2781", "-%s:00", 1); @@ -7339,6 +7339,12 @@ static void tas2781_fixup_spi(struct hda_codec *cdc, const struct hda_fixup *fix comp_generic_fixup(cdc, action, "spi", "TXNW2781", "-%s:00-tas2781-hda.%d", 2); } +static void tas2781_fixup_txnw_i2c(struct hda_codec *cdc, + const struct hda_fixup *fix, int action) +{ + comp_generic_fixup(cdc, action, "i2c", "TXNW2781", "-%s:00-tas2781-hda.%d", 1); +} + static void yoga7_14arb7_fixup_i2c(struct hda_codec *cdc, const struct hda_fixup *fix, int action) { @@ -8007,6 +8013,7 @@ enum { ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI, ALC287_FIXUP_TAS2781_I2C, ALC245_FIXUP_TAS2781_SPI_2, + ALC287_FIXUP_TXNW2781_I2C, ALC287_FIXUP_YOGA7_14ARB7_I2C, ALC245_FIXUP_HP_MUTE_LED_COEFBIT, ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT, @@ -10261,7 +10268,7 @@ static const struct hda_fixup alc269_fixups[] = { }, [ALC287_FIXUP_TAS2781_I2C] = { .type = HDA_FIXUP_FUNC, - .v.func = tas2781_fixup_i2c, + .v.func = tas2781_fixup_tias_i2c, .chained = true, .chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK, }, @@ -10271,6 +10278,12 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC285_FIXUP_HP_GPIO_LED, }, + [ALC287_FIXUP_TXNW2781_I2C] = { + .type = HDA_FIXUP_FUNC, + .v.func = tas2781_fixup_txnw_i2c, + .chained = true, + .chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK, + }, [ALC287_FIXUP_YOGA7_14ARB7_I2C] = { .type = HDA_FIXUP_FUNC, .v.func = yoga7_14arb7_fixup_i2c, @@ -11329,8 +11342,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), SND_PCI_QUIRK(0x17aa, 0x390d, "Lenovo Yoga Pro 7 14ASP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), SND_PCI_QUIRK(0x17aa, 0x3913, "Lenovo 145", ALC236_FIXUP_LENOVO_INV_DMIC), - SND_PCI_QUIRK(0x17aa, 0x391f, "Yoga S990-16 pro Quad YC Quad", ALC287_FIXUP_TAS2781_I2C), - SND_PCI_QUIRK(0x17aa, 0x3920, "Yoga S990-16 pro Quad VECO Quad", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x391f, "Yoga S990-16 pro Quad YC Quad", ALC287_FIXUP_TXNW2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x3920, "Yoga S990-16 pro Quad VECO Quad", ALC287_FIXUP_TXNW2781_I2C), SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index eb2295b490d9..b9cdbca951e4 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -587,6 +587,11 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt) device_name = "TIAS2781"; hda_priv->save_calibration = tas2781_save_calibration; tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR; + } else if (strstarts(dev_name(&clt->dev), + "TXNW2781:00-tas2781-hda.0")) { + device_name = "TXNW2781"; + hda_priv->save_calibration = tas2781_save_calibration; + tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR; } else if (strstr(dev_name(&clt->dev), "INT8866")) { device_name = "INT8866"; hda_priv->save_calibration = tas2563_save_calibration; @@ -725,6 +730,7 @@ static const struct i2c_device_id tas2781_hda_i2c_id[] = { static const struct acpi_device_id tas2781_acpi_hda_match[] = { {"INT8866", 0 }, {"TIAS2781", 0 }, + {"TXNW2781", 0 }, {} }; MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match); From e7af416aebb36e6681b9c6950d0f6352aee7c084 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 16 Jun 2025 11:30:52 +0100 Subject: [PATCH 078/385] firmware: cs_dsp: Remove unused struct list_head from cs_dsp_coeff_ctl Remove two unused pointers from struct cs_dsp_coeff_ctl by taking the struct list_head out of struct cs_dsp_alg_region. On a x86_64 build this saves 16 bytes per control. Each cs_dsp_coeff_ctl instance needs to keep information about the algorithm region it refers to. This is done by embedding an instance of struct cs_dsp_alg_region. But cs_dsp_alg_region was also used to store entries in a list of algorithm regions, and so had a struct list_head object for that purpose. This list_head object is not used with the embedded object in struct cs_dsp_alg_region so was just wasted bytes. A new struct cs_dsp_alg_region_list_item has been defined for creating the list of algorithm regions. It contains a struct cs_dsp_alg_region and a struct list_head. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20250616103052.66537-1-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 45 ++++++++++++++------------ include/linux/firmware/cirrus/cs_dsp.h | 2 -- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 560724ce21aa..f51047d8ea64 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -311,6 +311,11 @@ static const struct cs_dsp_ops cs_dsp_adsp2_ops[]; static const struct cs_dsp_ops cs_dsp_halo_ops; static const struct cs_dsp_ops cs_dsp_halo_ao_ops; +struct cs_dsp_alg_region_list_item { + struct list_head list; + struct cs_dsp_alg_region alg_region; +}; + struct cs_dsp_buf { struct list_head list; void *buf; @@ -1752,13 +1757,13 @@ static void *cs_dsp_read_algs(struct cs_dsp *dsp, size_t n_algs, struct cs_dsp_alg_region *cs_dsp_find_alg_region(struct cs_dsp *dsp, int type, unsigned int id) { - struct cs_dsp_alg_region *alg_region; + struct cs_dsp_alg_region_list_item *item; lockdep_assert_held(&dsp->pwr_lock); - list_for_each_entry(alg_region, &dsp->alg_regions, list) { - if (id == alg_region->alg && type == alg_region->type) - return alg_region; + list_for_each_entry(item, &dsp->alg_regions, list) { + if (id == item->alg_region.alg && type == item->alg_region.type) + return &item->alg_region; } return NULL; @@ -1769,35 +1774,35 @@ static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp, int type, __be32 id, __be32 ver, __be32 base) { - struct cs_dsp_alg_region *alg_region; + struct cs_dsp_alg_region_list_item *item; - alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL); - if (!alg_region) + item = kzalloc(sizeof(*item), GFP_KERNEL); + if (!item) return ERR_PTR(-ENOMEM); - alg_region->type = type; - alg_region->alg = be32_to_cpu(id); - alg_region->ver = be32_to_cpu(ver); - alg_region->base = be32_to_cpu(base); + item->alg_region.type = type; + item->alg_region.alg = be32_to_cpu(id); + item->alg_region.ver = be32_to_cpu(ver); + item->alg_region.base = be32_to_cpu(base); - list_add_tail(&alg_region->list, &dsp->alg_regions); + list_add_tail(&item->list, &dsp->alg_regions); if (dsp->wmfw_ver > 0) - cs_dsp_ctl_fixup_base(dsp, alg_region); + cs_dsp_ctl_fixup_base(dsp, &item->alg_region); - return alg_region; + return &item->alg_region; } static void cs_dsp_free_alg_regions(struct cs_dsp *dsp) { - struct cs_dsp_alg_region *alg_region; + struct cs_dsp_alg_region_list_item *item; while (!list_empty(&dsp->alg_regions)) { - alg_region = list_first_entry(&dsp->alg_regions, - struct cs_dsp_alg_region, - list); - list_del(&alg_region->list); - kfree(alg_region); + item = list_first_entry(&dsp->alg_regions, + struct cs_dsp_alg_region_list_item, + list); + list_del(&item->list); + kfree(item); } } diff --git a/include/linux/firmware/cirrus/cs_dsp.h b/include/linux/firmware/cirrus/cs_dsp.h index 7cae703b3137..a66eb7624730 100644 --- a/include/linux/firmware/cirrus/cs_dsp.h +++ b/include/linux/firmware/cirrus/cs_dsp.h @@ -64,14 +64,12 @@ struct cs_dsp_region { /** * struct cs_dsp_alg_region - Describes a logical algorithm region in DSP address space - * @list: List node for internal use * @alg: Algorithm id * @ver: Expected algorithm version * @type: Memory region type * @base: Address of region */ struct cs_dsp_alg_region { - struct list_head list; unsigned int alg; unsigned int ver; int type; From 47972c1c3315672352f25c68f91dd88543541947 Mon Sep 17 00:00:00 2001 From: Sachin Mokashi Date: Fri, 13 Jun 2025 12:35:30 -0400 Subject: [PATCH 079/385] ASoC: Intel: Replace deprecated strcpy() with strscpy() strcpy() is deprecated, use strscpy() instead. As strcpy() performs no bounds checking on the destination buffer. This could result in buffer overflow. The safe replacement is strscpy(). Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Sachin Mokashi Link: https://patch.msgid.link/20250613163530.1165690-1-sachin.mokashi@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5672.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index aaef212cf44e..54c1894ee96a 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -458,7 +459,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) if (!drv) return -ENOMEM; - strcpy(drv->codec_name, RT5672_I2C_DEFAULT); + strscpy(drv->codec_name, RT5672_I2C_DEFAULT, sizeof(drv->codec_name)); /* find index of codec dai */ for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { From d9f38d9824bfb1b046d2e720349d2f45959ab184 Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Tue, 17 Jun 2025 11:21:03 +0800 Subject: [PATCH 080/385] ASoC: tegra: AHUB: Remove unneeded semicolon Remove unnecessary semicolons reported by Coccinelle/coccicheck and the semantic patch at scripts/coccinelle/misc/semicolon.cocci. Signed-off-by: Chen Ni Link: https://patch.msgid.link/20250617032103.1725040-1-nichen@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/tegra/tegra210_ahub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c index 2376cc76e684..21aeaeba0b10 100644 --- a/sound/soc/tegra/tegra210_ahub.c +++ b/sound/soc/tegra/tegra210_ahub.c @@ -2066,7 +2066,7 @@ static bool tegra264_ahub_wr_reg(struct device *dev, unsigned int reg) return true; default: break; - }; + } } return false; From 7f4c540e0859e2025675d2c5c5c6ab88eaf817e2 Mon Sep 17 00:00:00 2001 From: wangdicheng Date: Mon, 16 Jun 2025 15:43:31 +0800 Subject: [PATCH 081/385] ALSA: hda/conexant: Renaming the codec with device ID 0x1f86 and 0x1f87 Due to changes in the manufacturer's plan, all 0x14f11f86 will be named CX11880, and 0x14f11f87 will be named SN6140 Signed-off-by: wangdicheng Link: https://patch.msgid.link/20250616074331.581309-1-wangdich9700@163.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 34874039ad45..e584a7b2877d 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -42,7 +42,7 @@ struct conexant_spec { unsigned int gpio_led; unsigned int gpio_mute_led_mask; unsigned int gpio_mic_led_mask; - bool is_cx8070_sn6140; + bool is_cx11880_sn6140; }; @@ -195,7 +195,7 @@ static int cx_auto_init(struct hda_codec *codec) cxt_init_gpio_led(codec); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); - if (spec->is_cx8070_sn6140) + if (spec->is_cx11880_sn6140) cx_fixup_headset_recog(codec); return 0; @@ -247,7 +247,7 @@ static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_ { unsigned int mic_present; - /* In cx8070 and sn6140, the node 16 can only be configured to headphone or disabled, + /* In cx11880 and sn6140, the node 16 can only be configured to headphone or disabled, * the node 19 can only be configured to microphone or disabled. * Check hp&mic tag to process headset plugin & plugout. */ @@ -1192,11 +1192,11 @@ static int patch_conexant_auto(struct hda_codec *codec) codec->spec = spec; codec->patch_ops = cx_auto_patch_ops; - /* init cx8070/sn6140 flag and reset headset_present_flag */ + /* init cx11880/sn6140 flag and reset headset_present_flag */ switch (codec->core.vendor_id) { case 0x14f11f86: case 0x14f11f87: - spec->is_cx8070_sn6140 = true; + spec->is_cx11880_sn6140 = true; snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref); break; } @@ -1284,7 +1284,7 @@ static int patch_conexant_auto(struct hda_codec *codec) */ static const struct hda_device_id snd_hda_id_conexant[] = { - HDA_CODEC_ENTRY(0x14f11f86, "CX8070", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f11f86, "CX11880", patch_conexant_auto), HDA_CODEC_ENTRY(0x14f11f87, "SN6140", patch_conexant_auto), HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto), HDA_CODEC_ENTRY(0x14f120d0, "CX11970", patch_conexant_auto), From 7f8924e8785b68c998bc1906e049bf5595865e60 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Tue, 17 Jun 2025 10:46:19 -0400 Subject: [PATCH 082/385] ASoC: dt-bindings: cirrus,cs42xx8: add 'port' property The cs42xx8 codecs may be used with audio graph card and thus may require an additional property: 'port'. Add it. Signed-off-by: Laurentiu Mihalcea Reviewed-by: Charles Keepax Link: https://patch.msgid.link/20250617144619.1130857-1-laurentiumihalcea111@gmail.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml index 725b47e82062..cd47905eb20a 100644 --- a/Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml +++ b/Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml @@ -41,6 +41,10 @@ properties: description: This pin is connected to the chip's RESET pin. maxItems: 1 + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + required: - compatible - reg From cbf4e0fac347b78f1bcd29350b78184665ad487d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 19 Jun 2025 11:42:19 +0300 Subject: [PATCH 083/385] ASoC: topology: Do not call snd_soc_remove_pcm_runtime() for ignored links If a link has been ignored then it is not even added. The snd_soc_get_pcm_runtime() will return NULL as the runtime will does not exist. We can just skip this step to avoid performing a lookup to do nothing. Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Liam Girdwood Reviewed-by: Kai Vehmanen Link: https://patch.msgid.link/20250619084222.559-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 7b0b8531bb32..44b60324eaa2 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -429,8 +429,11 @@ static void soc_tplg_remove_link(struct snd_soc_component *comp, dobj->unload(comp, dobj); list_del(&dobj->list); - snd_soc_remove_pcm_runtime(comp->card, - snd_soc_get_pcm_runtime(comp->card, link)); + + /* Ignored links do not need to be removed, they are not added */ + if (!link->ignore) + snd_soc_remove_pcm_runtime(comp->card, + snd_soc_get_pcm_runtime(comp->card, link)); } /* unload dai link */ From 2d91cb261cac6d885954b8f5da28b5c176c18131 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 19 Jun 2025 11:42:20 +0300 Subject: [PATCH 084/385] ASoC: core: Check for rtd == NULL in snd_soc_remove_pcm_runtime() snd_soc_remove_pcm_runtime() might be called with rtd == NULL which will leads to null pointer dereference. This was reproduced with topology loading and marking a link as ignore due to missing hardware component on the system. On module removal the soc_tplg_remove_link() would call snd_soc_remove_pcm_runtime() with rtd == NULL since the link was ignored, no runtime was created. Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Liam Girdwood Reviewed-by: Kai Vehmanen Link: https://patch.msgid.link/20250619084222.559-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index cfafdabcdc88..1ffabac1fb6b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1139,6 +1139,9 @@ sanity_check: void snd_soc_remove_pcm_runtime(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd) { + if (!rtd) + return; + lockdep_assert_held(&client_mutex); /* From 86591907527effbfd99c038ffc06ca30bb4f6b64 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 19 Jun 2025 11:42:21 +0300 Subject: [PATCH 085/385] ASoC: Intel: skl_hda_dsp_generic: Implement add_dai_link to filter HDMI PCMs If the system does not have iDisp codec then mark the HDMI PCM link as ignore. This ensures that HDMI PCMs will not be created when there is no iDisp codec available. When iDisp codec is not present and the HDMI PCMs were created they were not operational, all operations would fail on them. With this patch it is possible to load the topology with HDMI links, but gives the ability to ignore them and thus prevent the creation of the nonworking PCM devices. Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Liam Girdwood Reviewed-by: Kai Vehmanen Link: https://patch.msgid.link/20250619084222.559-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_hda_dsp_generic.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 0554c7e2cb34..519218385fdf 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -85,6 +85,18 @@ skl_hda_get_board_quirk(struct snd_soc_acpi_mach_params *mach_params) return board_quirk; } +static int skl_hda_add_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *link) +{ + struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); + + /* Ignore the HDMI PCM link if iDisp is not present */ + if (strstr(link->stream_name, "HDMI") && !ctx->hdmi.idisp_codec) + link->ignore = true; + + return 0; +} + static int skl_hda_audio_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; @@ -101,6 +113,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev) card->owner = THIS_MODULE; card->fully_routed = true; card->late_probe = skl_hda_card_late_probe; + card->add_dai_link = skl_hda_add_dai_link; dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk); From bb48117b79ebc39485f7306d09dc602981fe540f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 19 Jun 2025 11:42:22 +0300 Subject: [PATCH 086/385] ASoC: Intel: sof_sdw: Implement add_dai_link to filter HDMI PCMs If the system does not have iDisp codec then mark the HDMI PCM link as ignore. This ensures that HDMI PCMs will not be created when there is no iDisp codec available. When iDisp codec is not present and the HDMI PCMs were created they were not operational, all operations would fail on them. With this patch it is possible to load the topology with HDMI links, but gives the ability to ignore them and thus prevent the creation of the nonworking PCM devices. Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Liam Girdwood Reviewed-by: Kai Vehmanen Link: https://patch.msgid.link/20250619084222.559-5-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 81a914bd7ec2..05d13bacf88a 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1295,6 +1295,19 @@ static int sof_sdw_card_late_probe(struct snd_soc_card *card) return ret; } +static int sof_sdw_add_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *link) +{ + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; + + /* Ignore the HDMI PCM link if iDisp is not present */ + if (strstr(link->stream_name, "HDMI") && !intel_ctx->hdmi.idisp_codec) + link->ignore = true; + + return 0; +} + static int mc_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); @@ -1321,6 +1334,7 @@ static int mc_probe(struct platform_device *pdev) card->name = "soundwire"; card->owner = THIS_MODULE; card->late_probe = sof_sdw_card_late_probe; + card->add_dai_link = sof_sdw_add_dai_link; snd_soc_card_set_drvdata(card, ctx); From cec49fa47bccadb288fd984ef2a5c45e8a2e2099 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 19 Jun 2025 13:56:22 +0300 Subject: [PATCH 087/385] ASoC: SOF: ipc4-priv: Add kernel doc for fw_context_save of sof_ipc4_fw_data The kernel documentation is missing entry for the fw_context_save. Signed-off-by: Peter Ujfalusi Reviewed-by: Guennadi Liakhovetski Reviewed-by: Liam Girdwood Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Link: https://patch.msgid.link/20250619105623.4546-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-priv.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h index 58b032820683..76dc54a2f07d 100644 --- a/sound/soc/sof/ipc4-priv.h +++ b/sound/soc/sof/ipc4-priv.h @@ -72,6 +72,7 @@ struct sof_ipc4_fw_library { * @max_num_pipelines: max number of pipelines * @max_libs_count: Maximum number of libraries support by the FW including the * base firmware + * @fw_context_save: Firmware supports full context save and restore * * @load_library: Callback function for platform dependent library loading * @pipeline_state_mutex: Mutex to protect pipeline triggers, ref counts, states and deletion From ace9b3daf2b4778358573d3698e34cb1c0fa7e14 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 19 Jun 2025 13:56:23 +0300 Subject: [PATCH 088/385] ASoC: SOF: ipc4/Intel: Add support for library restore firmware functionality The firmware will be able to only save and restore the context related to library management. This means that even without a full context save, the libraries do not need to be re-loaded to the firmware after second or consecutive boots. This is reported via the FW_READY notification, where BIT(15) indicates: 0 - the library restore is not done 1 - library restore is done This bit is only valid if full context save is not enabled, full context save is by definition saves and restores the library related book-keeping as well. Add a new flag to tell the platform code if the libraries have been restored, no need to reload them after boot. Signed-off-by: Peter Ujfalusi Reviewed-by: Guennadi Liakhovetski Reviewed-by: Liam Girdwood Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Link: https://patch.msgid.link/20250619105623.4546-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/ipc4/header.h | 2 ++ sound/soc/sof/intel/hda-loader.c | 7 +++++-- sound/soc/sof/ipc4-loader.c | 6 ++++++ sound/soc/sof/ipc4-priv.h | 2 ++ sound/soc/sof/ipc4.c | 14 ++++++++++++-- 5 files changed, 27 insertions(+), 4 deletions(-) diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h index f71d04736d17..e85c7afd85a4 100644 --- a/include/sound/sof/ipc4/header.h +++ b/include/sound/sof/ipc4/header.h @@ -498,6 +498,8 @@ struct sof_ipc4_intel_mic_privacy_cap { #define SOF_IPC4_LOG_CORE_GET(x) (((x) & SOF_IPC4_LOG_CORE_MASK) >> \ SOF_IPC4_LOG_CORE_SHIFT) +#define SOF_IPC4_FW_READY_LIB_RESTORED BIT(15) + /* Value of notification type field - must fit into 8 bits */ enum sof_ipc4_notification_type { /* Phrase detected (notification from WoV module) */ diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 49085ca7b46b..2cc11d8b0f70 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -579,8 +579,11 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, struct sof_ipc4_msg msg = {}; int ret, ret1; - /* if IMR booting is enabled and fw context is saved for D3 state, skip the loading */ - if (reload && hda->booted_from_imr && ipc4_data->fw_context_save) + /* + * if IMR booting is enabled and libraries have been restored during fw + * boot, skip the loading + */ + if (reload && hda->booted_from_imr && ipc4_data->libraries_restored) return 0; /* the fw_lib has been verified during loading, we can trust the validity here */ diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c index d2f534d65edf..ee61394e73d7 100644 --- a/sound/soc/sof/ipc4-loader.c +++ b/sound/soc/sof/ipc4-loader.c @@ -494,6 +494,12 @@ int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev) break; case SOF_IPC4_FW_CONTEXT_SAVE: ipc4_data->fw_context_save = *tuple->value; + /* + * Set the default libraries_restored value - if full + * context save is supported then it means that + * libraries are restored + */ + ipc4_data->libraries_restored = ipc4_data->fw_context_save; break; default: break; diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h index 76dc54a2f07d..45e9b78432f7 100644 --- a/sound/soc/sof/ipc4-priv.h +++ b/sound/soc/sof/ipc4-priv.h @@ -73,6 +73,7 @@ struct sof_ipc4_fw_library { * @max_libs_count: Maximum number of libraries support by the FW including the * base firmware * @fw_context_save: Firmware supports full context save and restore + * @libraries_restored: The libraries have been retained during firmware boot * * @load_library: Callback function for platform dependent library loading * @pipeline_state_mutex: Mutex to protect pipeline triggers, ref counts, states and deletion @@ -88,6 +89,7 @@ struct sof_ipc4_fw_data { int max_num_pipelines; u32 max_libs_count; bool fw_context_save; + bool libraries_restored; int (*load_library)(struct snd_sof_dev *sdev, struct sof_ipc4_fw_library *fw_lib, bool reload); diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index 37e837b22ac8..0ba0e8e615ae 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -576,9 +576,19 @@ EXPORT_SYMBOL(sof_ipc4_find_debug_slot_offset_by_type); static int ipc4_fw_ready(struct snd_sof_dev *sdev, struct sof_ipc4_msg *ipc4_msg) { - /* no need to re-check version/ABI for subsequent boots */ - if (!sdev->first_boot) + if (!sdev->first_boot) { + struct sof_ipc4_fw_data *ipc4_data = sdev->private; + + /* + * After the initial boot only check if the libraries have been + * restored when full context save is not enabled + */ + if (!ipc4_data->fw_context_save) + ipc4_data->libraries_restored = !!(ipc4_msg->primary & + SOF_IPC4_FW_READY_LIB_RESTORED); + return 0; + } sof_ipc4_create_exception_debugfs_node(sdev); From ecd41e0e2581d60f5268ad662065d17e0f049539 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 19 Jun 2025 15:11:19 +0300 Subject: [PATCH 089/385] ASoC: SOF: ipc4: Add sof_ipc4_pipeline_state_str() for debugging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add sof_ipc4_pipeline_state_str() to translate enum sof_ipc4_pipeline_state into human readable form. Signed-off-by: Jyri Sarha Reviewed-by: Péter Ujfalusi Reviewed-by: Guennadi Liakhovetski Reviewed-by: Liam Girdwood Reviewed-by: Ranjani Sridharan Signed-off-by: Peter Ujfalusi Link: https://patch.msgid.link/20250619121121.25241-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-priv.h | 3 +++ sound/soc/sof/ipc4.c | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h index 58b032820683..a256528e030f 100644 --- a/sound/soc/sof/ipc4-priv.h +++ b/sound/soc/sof/ipc4-priv.h @@ -123,4 +123,7 @@ size_t sof_ipc4_find_debug_slot_offset_by_type(struct snd_sof_dev *sdev, void sof_ipc4_mic_privacy_state_change(struct snd_sof_dev *sdev, bool state); +enum sof_ipc4_pipeline_state; +const char *sof_ipc4_pipeline_state_str(enum sof_ipc4_pipeline_state state); + #endif diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index 37e837b22ac8..0b91bd443025 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -237,6 +237,26 @@ static void sof_ipc4_log_header(struct device *dev, u8 *text, struct sof_ipc4_ms msg->extension, str); } } + +const char *sof_ipc4_pipeline_state_str(enum sof_ipc4_pipeline_state state) +{ + switch (state) { + case SOF_IPC4_PIPE_INVALID_STATE: + return " (INVALID_STATE)"; + case SOF_IPC4_PIPE_UNINITIALIZED: + return " (UNINITIALIZED)"; + case SOF_IPC4_PIPE_RESET: + return " (RESET)"; + case SOF_IPC4_PIPE_PAUSED: + return " (PAUSED)"; + case SOF_IPC4_PIPE_RUNNING: + return " (RUNNING)"; + case SOF_IPC4_PIPE_EOS: + return " (EOS)"; + default: + return " ()"; + } +} #else /* CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC */ static void sof_ipc4_log_header(struct device *dev, u8 *text, struct sof_ipc4_msg *msg, bool data_size_valid) @@ -254,6 +274,11 @@ static void sof_ipc4_log_header(struct device *dev, u8 *text, struct sof_ipc4_ms else dev_dbg(dev, "%s: %#x|%#x\n", text, msg->primary, msg->extension); } + +const char *sof_ipc4_pipeline_state_str(enum sof_ipc4_pipeline_state state) +{ + return ""; +} #endif static void sof_ipc4_dump_payload(struct snd_sof_dev *sdev, From 0e57fa20678d2d2dc0f047f052bb509c8f3ebc3b Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 19 Jun 2025 15:11:20 +0300 Subject: [PATCH 090/385] ASoC: SOF: ipc4-pcm: Pipe instances to dev_dbg in multi_pipeline_state() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a dev_dbg to sof_ipc4_set_multi_pipeline_state(). The debug print lists the pipeline instance numbers that are included in the SOF_IPC4_GLB_SET_PIPELINE_STATE message. Without this log its very hard to tell what pipelines are affected. This print is very helpful when analyzing SOF logs automatically. Signed-off-by: Jyri Sarha Reviewed-by: Péter Ujfalusi Reviewed-by: Guennadi Liakhovetski Reviewed-by: Liam Girdwood Reviewed-by: Ranjani Sridharan Signed-off-by: Peter Ujfalusi Link: https://patch.msgid.link/20250619121121.25241-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-pcm.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 8eee3e1aadf9..be4518d8970b 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -56,17 +56,41 @@ sof_ipc4_sps_to_time_info(struct snd_sof_pcm_stream *sps) return stream_priv->time_info; } +static +char *sof_ipc4_set_multi_pipeline_state_debug(struct snd_sof_dev *sdev, char *buf, size_t size, + struct ipc4_pipeline_set_state_data *trigger_list) +{ + int i, offset = 0; + + for (i = 0; i < trigger_list->count; i++) { + offset += snprintf(buf + offset, size - offset, " %d", + trigger_list->pipeline_instance_ids[i]); + + if (offset >= size - 1) { + buf[size - 1] = '\0'; + break; + } + } + return buf; +} + static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state, struct ipc4_pipeline_set_state_data *trigger_list) { struct sof_ipc4_msg msg = {{ 0 }}; u32 primary, ipc_size; + char debug_buf[32]; /* trigger a single pipeline */ if (trigger_list->count == 1) return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_instance_ids[0], state); + dev_dbg(sdev->dev, "Set pipelines %s to state %d%s", + sof_ipc4_set_multi_pipeline_state_debug(sdev, debug_buf, sizeof(debug_buf), + trigger_list), + state, sof_ipc4_pipeline_state_str(state)); + primary = state; primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE); primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); From 2756b7f08ff6ca7c68c8c7dd61c8dc6895c9de34 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 19 Jun 2025 15:11:21 +0300 Subject: [PATCH 091/385] ASoC: SOF: ipc4-pcm: Harmonize sof_ipc4_set_pipeline_state() dbg print MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Harmonize sof_ipc4_set_pipeline_state() dbg print with the new print in sof_ipc4_set_multi_pipeline_state(). Signed-off-by: Jyri Sarha Reviewed-by: Péter Ujfalusi Reviewed-by: Guennadi Liakhovetski Reviewed-by: Liam Girdwood Reviewed-by: Ranjani Sridharan Signed-off-by: Peter Ujfalusi Link: https://patch.msgid.link/20250619121121.25241-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-pcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index be4518d8970b..cf809959eaea 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -113,7 +113,8 @@ int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 s struct sof_ipc4_msg msg = {{ 0 }}; u32 primary; - dev_dbg(sdev->dev, "ipc4 set pipeline instance %d state %d", instance_id, state); + dev_dbg(sdev->dev, "Set pipeline %d to state %d%s", instance_id, state, + sof_ipc4_pipeline_state_str(state)); primary = state; primary |= SOF_IPC4_GLB_PIPE_STATE_ID(instance_id); From 8a07944a77e962b625c582696497964c393a3489 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 19 Jun 2025 13:26:57 +0300 Subject: [PATCH 092/385] ASoC: SOF: ipc4-pcm: Look for best matching hw_config for SSP Instead of just looking for a hw_config with matching rate only it sounds better to try to find the best matching configuration. If we have multiple hw_configurations with the same rate, but each with different format for example then we have been picking the first config with the matching rate, which can be a problem and it wil depend on how the configs are ordered. Instead we should be trying to find the best match out of the configs 1. rate + format + channels are matching 2. rate + format are matching 3. rate matching Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://patch.msgid.link/20250619102657.12109-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-pcm.c | 61 ++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 8eee3e1aadf9..a5b365ab1945 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -557,12 +557,15 @@ static int sof_ipc4_pcm_hw_free(struct snd_soc_component *component, return sof_ipc4_trigger_pipelines(component, substream, SOF_IPC4_PIPE_RESET, 0); } -static void ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char *link_name, - struct snd_pcm_hw_params *params) +static int ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, + const char *link_name, + struct snd_pcm_hw_params *params) { struct snd_sof_dai_link *slink; struct snd_sof_dai *dai; bool dai_link_found = false; + int current_config = -1; + bool partial_match; int i; list_for_each_entry(slink, &sdev->dai_link_list, list) { @@ -573,19 +576,50 @@ static void ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const } if (!dai_link_found) - return; + return 0; + /* + * Find the first best matching hardware config: + * rate + format + channels are matching + * rate + channel are matching + * + * The copier cannot do rate and/or channel conversion. + */ for (i = 0; i < slink->num_hw_configs; i++) { struct snd_soc_tplg_hw_config *hw_config = &slink->hw_configs[i]; - if (params_rate(params) == le32_to_cpu(hw_config->fsync_rate)) { - /* set current config for all DAI's with matching name */ - list_for_each_entry(dai, &sdev->dai_list, list) - if (!strcmp(slink->link->name, dai->name)) - dai->current_config = le32_to_cpu(hw_config->id); + if (params_rate(params) == le32_to_cpu(hw_config->fsync_rate) && + params_width(params) == le32_to_cpu(hw_config->tdm_slot_width) && + params_channels(params) == le32_to_cpu(hw_config->tdm_slots)) { + current_config = le32_to_cpu(hw_config->id); + partial_match = false; + /* best match found */ break; + } else if (current_config < 0 && + params_rate(params) == le32_to_cpu(hw_config->fsync_rate) && + params_channels(params) == le32_to_cpu(hw_config->tdm_slots)) { + current_config = le32_to_cpu(hw_config->id); + partial_match = true; + /* keep looking for better match */ } } + + if (current_config < 0) { + dev_err(sdev->dev, + "%s: No suitable hw_config found for %s (num_hw_configs: %d)\n", + __func__, slink->link->name, slink->num_hw_configs); + return -EINVAL; + } + + dev_dbg(sdev->dev, + "hw_config for %s: %d (num_hw_configs: %d) with %s match\n", + slink->link->name, current_config, slink->num_hw_configs, + partial_match ? "partial" : "full"); + list_for_each_entry(dai, &sdev->dai_list, list) + if (!strcmp(slink->link->name, dai->name)) + dai->current_config = current_config; + + return 0; } /* @@ -728,13 +762,10 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, break; } - switch (ipc4_copier->dai_type) { - case SOF_DAI_INTEL_SSP: - ipc4_ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params); - break; - default: - break; - } + if (ipc4_copier->dai_type == SOF_DAI_INTEL_SSP) + return ipc4_ssp_dai_config_pcm_params_match(sdev, + (char *)rtd->dai_link->name, + params); return 0; } From 2710204bf1005ee5ca94d07fe740111a9677b919 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 19 Jun 2025 13:46:08 +0300 Subject: [PATCH 093/385] ASoC: SOF: pcm: Remove local create_page_table() wrapper function The create_page_table() can be dropped and replaced with a direct call to snd_sof_create_page_table(). Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://patch.msgid.link/20250619104608.25947-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index d584a72e6f52..acf1995e04e8 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -20,24 +20,6 @@ #include "sof-utils.h" #include "ops.h" -/* Create DMA buffer page table for DSP */ -static int create_page_table(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - unsigned char *dma_area, size_t size) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_sof_pcm *spcm; - struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream); - int stream = substream->stream; - - spcm = snd_sof_find_spcm_dai(component, rtd); - if (!spcm) - return -EINVAL; - - return snd_sof_create_page_table(component->dev, dmab, - spcm->stream[stream].page_table.area, size); -} - /* * sof pcm period elapse work */ @@ -168,9 +150,11 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, /* create compressed page table for audio firmware */ if (runtime->buffer_changed) { - ret = create_page_table(component, substream, runtime->dma_area, - runtime->dma_bytes); + struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream); + ret = snd_sof_create_page_table(component->dev, dmab, + spcm->stream[substream->stream].page_table.area, + runtime->dma_bytes); if (ret < 0) return ret; } From 6b3cb7f4341cbf62d41ccf6ea906dbe66be8aa3d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 19 Jun 2025 13:26:40 +0300 Subject: [PATCH 094/385] ASoC: SOF: topology: Parse the dapm_widget_tokens in case of DSPless mode Parsing the dapm_widget_tokens is also needed for DSPless mode as it is setting the snd_soc_dapm_widget.no_wname_in_kcontrol_name flag for the kcontrol creation from DAPM widgets. Without that flag set, the following warnings might appear because of long control names: ALSA: Control name 'eqiir.2.1 Post Mixer Analog Playback IIR Eq bytes' truncated to 'eqiir.2.1 Post Mixer Analog Playback IIR Eq' ALSA: Control name 'eqfir.2.1 Post Mixer Analog Playback FIR Eq bytes' truncated to 'eqfir.2.1 Post Mixer Analog Playback FIR Eq' ALSA: Control name 'drc.2.1 Post Mixer Analog Playback DRC bytes' truncated to 'drc.2.1 Post Mixer Analog Playback DRC byte' ALSA: Control name 'drc.2.1 Post Mixer Analog Playback DRC switch' truncated to 'drc.2.1 Post Mixer Analog Playback DRC swit' ALSA: Control name 'gain.15.1 Pre Mixer Deepbuffer HDA Analog Volume' truncated to 'gain.15.1 Pre Mixer Deepbuffer HDA Analog V' Signed-off-by: Peter Ujfalusi Reviewed-by: Liam Girdwood Reviewed-by: Ranjani Sridharan Link: https://patch.msgid.link/20250619102640.12068-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index d612d693efc3..b6d5c8024f8c 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2378,14 +2378,25 @@ static int sof_dspless_widget_ready(struct snd_soc_component *scomp, int index, struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tw) { + struct snd_soc_tplg_private *priv = &tw->priv; + int ret; + + /* for snd_soc_dapm_widget.no_wname_in_kcontrol_name */ + ret = sof_parse_tokens(scomp, w, dapm_widget_tokens, + ARRAY_SIZE(dapm_widget_tokens), + priv->array, le32_to_cpu(priv->size)); + if (ret < 0) { + dev_err(scomp->dev, "failed to parse dapm widget tokens for %s\n", + w->name); + return ret; + } + if (WIDGET_IS_DAI(w->id)) { static const struct sof_topology_token dai_tokens[] = { {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, 0}}; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_tplg_private *priv = &tw->priv; struct snd_sof_widget *swidget; struct snd_sof_dai *sdai; - int ret; swidget = kzalloc(sizeof(*swidget), GFP_KERNEL); if (!swidget) From 3d77763c9a6d94ebc258183583891fdf23599a18 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 19 Jun 2025 13:45:51 +0300 Subject: [PATCH 095/385] ASoC: SOF: pcm: Reverse check for prepared stream in sof_pcm_hw_params() Reduce the number of checks needed with the simple and most common audio sequence when the stream is started then stopped. If the stream has not been prepared there is no need to check if we have pcm_ops and pcm_ops->hw_free() callback as it does not matter. Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://patch.msgid.link/20250619104551.25912-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index acf1995e04e8..090ea3a76892 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -126,7 +126,7 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, * Handle repeated calls to hw_params() without free_pcm() in * between. At least ALSA OSS emulation depends on this. */ - if (pcm_ops && pcm_ops->hw_free && spcm->prepared[substream->stream]) { + if (spcm->prepared[substream->stream] && pcm_ops && pcm_ops->hw_free) { ret = pcm_ops->hw_free(component, substream); if (ret < 0) return ret; From f9c7c093797fc00c7ce3042387994cf9d6c6d4ce Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Thu, 19 Jun 2025 13:47:35 +0300 Subject: [PATCH 096/385] ASoC: SOF: ipc4-topology: Add load of ASRC component MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds to IPC4 topology parsing the support for the asynchronous sample rate converter (ASRC) SOF component. It is applied for the DAPM widget type SND_SOC_TPLG_DAPM_ASRC. The parsed SOF tokens for ASRC are SOF_TKN_ASRC_RATE_OUT and SOF_TKN_ASRC_OPERATION_MODE. Signed-off-by: Seppo Ingalsuo Reviewed-by: Liam Girdwood Reviewed-by: Péter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Signed-off-by: Peter Ujfalusi Link: https://patch.msgid.link/20250619104735.26161-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 88 +++++++++++++++++++++++++++++++++++ sound/soc/sof/ipc4-topology.h | 24 ++++++++++ 2 files changed, 112 insertions(+) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 540ba140e155..089f2c9fe693 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -145,6 +145,14 @@ static const struct sof_topology_token src_tokens[] = { offsetof(struct sof_ipc4_src_data, sink_rate)}, }; +/* ASRC */ +static const struct sof_topology_token asrc_tokens[] = { + {SOF_TKN_ASRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_asrc_data, out_freq)}, + {SOF_TKN_ASRC_OPERATION_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_asrc_data, asrc_mode)}, +}; + static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { [SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)}, [SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)}, @@ -166,6 +174,7 @@ static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)}, [SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)}, [SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)}, + [SOF_ASRC_TOKENS] = {"ASRC tokens", asrc_tokens, ARRAY_SIZE(asrc_tokens)}, }; struct snd_sof_widget *sof_ipc4_find_swidget_by_ids(struct snd_sof_dev *sdev, @@ -1045,6 +1054,50 @@ err: return ret; } +static int sof_ipc4_widget_setup_comp_asrc(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_pipeline *spipe = swidget->spipe; + struct sof_ipc4_asrc *asrc; + int ret; + + dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); + + asrc = kzalloc(sizeof(*asrc), GFP_KERNEL); + if (!asrc) + return -ENOMEM; + + swidget->private = asrc; + + ret = sof_ipc4_get_audio_fmt(scomp, swidget, &asrc->available_fmt, + &asrc->data.base_config); + if (ret) + goto err; + + ret = sof_update_ipc_object(scomp, &asrc->data, SOF_ASRC_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(*asrc), 1); + if (ret) { + dev_err(scomp->dev, "Parsing ASRC tokens failed\n"); + goto err; + } + + spipe->core_mask |= BIT(swidget->core); + + dev_dbg(scomp->dev, "ASRC sink rate %d, mode 0x%08x\n", + asrc->data.out_freq, asrc->data.asrc_mode); + + ret = sof_ipc4_widget_setup_msg(swidget, &asrc->msg); + if (ret) + goto err; + + return 0; +err: + sof_ipc4_free_audio_fmt(&asrc->available_fmt); + kfree(asrc); + swidget->private = NULL; + return ret; +} + static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget) { struct sof_ipc4_src *src = swidget->private; @@ -1057,6 +1110,18 @@ static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget) swidget->private = NULL; } +static void sof_ipc4_widget_free_comp_asrc(struct snd_sof_widget *swidget) +{ + struct sof_ipc4_asrc *asrc = swidget->private; + + if (!asrc) + return; + + sof_ipc4_free_audio_fmt(&asrc->available_fmt); + kfree(swidget->private); + swidget->private = NULL; +} + static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget) { struct sof_ipc4_mixer *mixer = swidget->private; @@ -2817,6 +2882,16 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget msg = &src->msg; break; } + case snd_soc_dapm_asrc: + { + struct sof_ipc4_asrc *asrc = swidget->private; + + ipc_size = sizeof(asrc->data); + ipc_data = &asrc->data; + + msg = &asrc->msg; + break; + } case snd_soc_dapm_effect: { struct sof_ipc4_process *process = swidget->private; @@ -3503,6 +3578,15 @@ static enum sof_tokens src_token_list[] = { SOF_COMP_EXT_TOKENS, }; +static enum sof_tokens asrc_token_list[] = { + SOF_COMP_TOKENS, + SOF_ASRC_TOKENS, + SOF_AUDIO_FMT_NUM_TOKENS, + SOF_IN_AUDIO_FORMAT_TOKENS, + SOF_OUT_AUDIO_FORMAT_TOKENS, + SOF_COMP_EXT_TOKENS, +}; + static enum sof_tokens process_token_list[] = { SOF_COMP_TOKENS, SOF_AUDIO_FMT_NUM_TOKENS, @@ -3548,6 +3632,10 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TY src_token_list, ARRAY_SIZE(src_token_list), NULL, sof_ipc4_prepare_src_module, NULL}, + [snd_soc_dapm_asrc] = {sof_ipc4_widget_setup_comp_asrc, sof_ipc4_widget_free_comp_asrc, + asrc_token_list, ARRAY_SIZE(asrc_token_list), + NULL, sof_ipc4_prepare_src_module, /* Common prepare with SRC */ + NULL}, [snd_soc_dapm_effect] = {sof_ipc4_widget_setup_comp_process, sof_ipc4_widget_free_comp_process, process_token_list, ARRAY_SIZE(process_token_list), diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index f4dc499c0ffe..9e98cac19532 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -435,6 +435,30 @@ struct sof_ipc4_src { struct sof_ipc4_msg msg; }; +/* + * struct sof_ipc4_asrc_data - IPC data for ASRC + * @base_config: IPC base config data + * @out_freq: Output rate for sink module, passed as such from topology to FW. + * @asrc_mode: Control for ASRC features with bit-fields, passed as such from topolgy to FW. + */ +struct sof_ipc4_asrc_data { + struct sof_ipc4_base_module_cfg base_config; + uint32_t out_freq; + uint32_t asrc_mode; +} __packed __aligned(4); + +/** + * struct sof_ipc4_asrc - ASRC config data + * @data: IPC base config data + * @available_fmt: Available audio format + * @msg: IPC4 message struct containing header and data info + */ +struct sof_ipc4_asrc { + struct sof_ipc4_asrc_data data; + struct sof_ipc4_available_audio_format available_fmt; + struct sof_ipc4_msg msg; +}; + /** * struct sof_ipc4_base_module_cfg_ext - base module config extension containing the pin format * information for the module. Both @num_input_pin_fmts and @num_output_pin_fmts cannot be 0 for a From ce4b269c26ac3216da44ef7699ee61791e6fcbc7 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 19 Jun 2025 13:25:48 +0300 Subject: [PATCH 097/385] ASoC: SOF: Intel: hda: Do not probe Soundwire in nocodec mode Soundwire is not needed for nocodec mode, skip probing it. Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Guennadi Liakhovetski Reviewed-by: Ranjani Sridharan Reviewed-by: Liam Girdwood Link: https://patch.msgid.link/20250619102548.11928-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index bdfe388da198..5347c433ac8e 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -629,6 +629,11 @@ static int hda_init_caps(struct snd_sof_dev *sdev) if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH))) goto skip_soundwire; + /* Skip SoundWire in nocodec mode */ + if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && + sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) + goto skip_soundwire; + /* scan SoundWire capabilities exposed by DSDT */ ret = hda_sdw_acpi_scan(sdev); if (ret < 0) { From a1d203d390e04798ccc1c3c06019cd4411885d6d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 19 Jun 2025 13:28:48 +0300 Subject: [PATCH 098/385] ASoC: SOF: ipc4-pcm: Enable delay reporting for ChainDMA streams All streams (currently) which is configured to use ChainDMA can only work on Link/host DMA pairs where the link side position can be access via host registers (like HDA on CAVS 2.5 platforms). Since the firmware does not provide time_info for ChainDMA, unlike for HDA stream, the kernel should calculate the start and end offsets that is needed for the delay calculation. With this small change we can report accurate delays when the stream is configured to use ChainDMA. Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Liam Girdwood Reviewed-by: Ranjani Sridharan Link: https://patch.msgid.link/20250619102848.12389-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-pcm.c | 49 ++++++++++++++++++++++++++++++++--- sound/soc/sof/ipc4-topology.c | 6 ++--- sound/soc/sof/ipc4-topology.h | 1 + 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index a5b365ab1945..6e19d89e2963 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -409,9 +409,33 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, * If use_chain_dma attribute is set we proceed to chained DMA * trigger function that handles the rest for the substream. */ - if (pipeline->use_chain_dma) - return sof_ipc4_chain_dma_trigger(sdev, spcm, substream->stream, - pipeline_list, state, cmd); + if (pipeline->use_chain_dma) { + struct sof_ipc4_timestamp_info *time_info; + + time_info = sof_ipc4_sps_to_time_info(&spcm->stream[substream->stream]); + + ret = sof_ipc4_chain_dma_trigger(sdev, spcm, substream->stream, + pipeline_list, state, cmd); + if (ret || !time_info) + return ret; + + if (state == SOF_IPC4_PIPE_PAUSED) { + /* + * Record the DAI position for delay reporting + * To handle multiple pause/resume/xrun we need to add + * the positions to simulate how the firmware behaves + */ + u64 pos = snd_sof_pcm_get_dai_frame_counter(sdev, component, + substream); + + time_info->stream_end_offset += pos; + } else if (state == SOF_IPC4_PIPE_RESET) { + /* Reset the end offset as the stream is stopped */ + time_info->stream_end_offset = 0; + } + + return 0; + } /* allocate memory for the pipeline data */ trigger_list = kzalloc(struct_size(trigger_list, pipeline_instance_ids, @@ -959,8 +983,24 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev, if (!host_copier || !dai_copier) return -EINVAL; - if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_INVALID_NODE_ID) + if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_INVALID_NODE_ID) { return -EINVAL; + } else if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_CHAIN_DMA_NODE_ID) { + /* + * While the firmware does not supports time_info reporting for + * streams using ChainDMA, it is granted that ChainDMA can only + * be used on Host+Link pairs where the link position is + * accessible from the host side. + * + * Enable delay calculation in case of ChainDMA via host + * accessible registers. + * + * The ChainDMA uses 2x 1ms ping-pong buffer, dai side starts + * when 1ms data is available + */ + time_info->stream_start_offset = substream->runtime->rate / MSEC_PER_SEC; + goto out; + } node_index = SOF_IPC4_NODE_INDEX(host_copier->data.gtw_cfg.node_id); offset = offsetof(struct sof_ipc4_fw_registers, pipeline_regs) + node_index * sizeof(ppl_reg); @@ -978,6 +1018,7 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev, time_info->stream_end_offset = ppl_reg.stream_end_offset; do_div(time_info->stream_end_offset, dai_sample_size); +out: /* * Calculate the wrap boundary need to be used for delay calculation * The host counter is in bytes, it will wrap earlier than the frames diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 089f2c9fe693..591ee30551ba 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1938,10 +1938,10 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, pipeline->msg.extension |= SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE(fifo_size); /* - * Chain DMA does not support stream timestamping, set node_id to invalid - * to skip the code in sof_ipc4_get_stream_start_offset(). + * Chain DMA does not support stream timestamping, but it + * can use the host side registers for delay calculation. */ - copier_data->gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID; + copier_data->gtw_cfg.node_id = SOF_IPC4_CHAIN_DMA_NODE_ID; return 0; } diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index 9e98cac19532..14ba58d2be03 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -58,6 +58,7 @@ #define SOF_IPC4_DMA_DEVICE_MAX_COUNT 16 +#define SOF_IPC4_CHAIN_DMA_NODE_ID 0x7fffffff #define SOF_IPC4_INVALID_NODE_ID 0xffffffff /* FW requires minimum 2ms DMA buffer size */ From bb0d147c9cf4a11cdc34321e276eb914648b0326 Mon Sep 17 00:00:00 2001 From: wangdicheng Date: Thu, 19 Jun 2025 15:17:45 +0800 Subject: [PATCH 099/385] ALSA: hda/realtek: Fixup ft alc257 rename alc3328 Audio ALC3328 recognized as ALC257, updated PCI ID 0x10EC12F0 to rename it to 3328. Signed-off-by: wangdicheng Link: https://patch.msgid.link/20250619071745.149299-1-wangdich9700@163.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 84a68c7d65b7..cfcc204264aa 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1088,6 +1088,7 @@ static const struct alc_codec_rename_pci_table rename_pci_tbl[] = { { 0x10ec0668, 0x103c, 0, "ALC3662" }, { 0x10ec0283, 0x17aa, 0, "ALC3239" }, { 0x10ec0292, 0x17aa, 0, "ALC3232" }, + { 0x10ec0257, 0x12f0, 0, "ALC3328" }, { } /* terminator */ }; From bec7ac4700305020bfb2dd4d0bfc9e60dc908c5c Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Thu, 19 Jun 2025 19:40:48 +0200 Subject: [PATCH 100/385] ALSA: emu10k1: Replace deprecated strcpy() with strscpy() strcpy() is deprecated; use strscpy() instead. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20250619174057.175676-2-thorsten.blum@linux.dev Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1.c | 3 ++- sound/pci/emu10k1/emu10k1x.c | 13 +++++++------ sound/pci/emu10k1/emufx.c | 23 ++++++++++++----------- sound/pci/emu10k1/emumixer.c | 9 +++++---- 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index dadeda7758ce..548e7d049901 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -154,7 +155,7 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, } else { struct snd_emu10k1_synth_arg *arg; arg = SNDRV_SEQ_DEVICE_ARGPTR(wave); - strcpy(wave->name, "Emu-10k1 Synth"); + strscpy(wave->name, "Emu-10k1 Synth"); arg->hwptr = emu; arg->index = 1; arg->seq_ports = seq_ports[dev]; diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 30ac37b5a214..8c18ad987223 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -840,15 +841,15 @@ static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device) pcm->info_flags = 0; switch(device) { case 0: - strcpy(pcm->name, "EMU10K1X Front"); + strscpy(pcm->name, "EMU10K1X Front"); map = snd_pcm_std_chmaps; break; case 1: - strcpy(pcm->name, "EMU10K1X Rear"); + strscpy(pcm->name, "EMU10K1X Rear"); map = surround_map; break; case 2: - strcpy(pcm->name, "EMU10K1X Center/LFE"); + strscpy(pcm->name, "EMU10K1X Center/LFE"); map = clfe_map; break; } @@ -1461,7 +1462,7 @@ static int emu10k1x_midi_init(struct emu10k1x *emu, spin_lock_init(&midi->open_lock); spin_lock_init(&midi->input_lock); spin_lock_init(&midi->output_lock); - strcpy(rmidi->name, name); + strscpy(rmidi->name, name); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_emu10k1x_midi_output); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_emu10k1x_midi_input); rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | @@ -1540,8 +1541,8 @@ static int __snd_emu10k1x_probe(struct pci_dev *pci, snd_emu10k1x_proc_init(chip); - strcpy(card->driver, "EMU10K1X"); - strcpy(card->shortname, "Dell Sound Blaster Live!"); + strscpy(card->driver, "EMU10K1X"); + strscpy(card->shortname, "Dell Sound Blaster Live!"); sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->port, chip->irq); diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 03efc317e05f..7db0660e6b61 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -1175,7 +1176,7 @@ snd_emu10k1_init_mono_control2(struct snd_emu10k1_fx8010_control_gpr *ctl, const char *name, int gpr, int defval, int defval_hr) { ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; - strcpy(ctl->id.name, name); + strscpy(ctl->id.name, name); ctl->vcount = ctl->count = 1; if (high_res_gpr_volume) { ctl->min = -1; @@ -1199,7 +1200,7 @@ snd_emu10k1_init_stereo_control2(struct snd_emu10k1_fx8010_control_gpr *ctl, const char *name, int gpr, int defval, int defval_hr) { ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; - strcpy(ctl->id.name, name); + strscpy(ctl->id.name, name); ctl->vcount = ctl->count = 2; if (high_res_gpr_volume) { ctl->min = -1; @@ -1224,7 +1225,7 @@ snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl, const char *name, int gpr, int defval) { ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; - strcpy(ctl->id.name, name); + strscpy(ctl->id.name, name); ctl->vcount = ctl->count = 1; ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; ctl->min = 0; @@ -1237,7 +1238,7 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl const char *name, int gpr, int defval) { ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; - strcpy(ctl->id.name, name); + strscpy(ctl->id.name, name); ctl->vcount = ctl->count = 2; ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; ctl->gpr[1] = gpr + 1; ctl->value[1] = defval; @@ -1325,7 +1326,7 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) /* clear TRAM data & address lines */ memset(icode->tram_valid, 0xff, 256 / 8); - strcpy(icode->name, "Audigy DSP code for ALSA"); + strscpy(icode->name, "Audigy DSP code for ALSA"); ptr = 0; nctl = 0; gpr_map[bit_shifter16] = 0x00008000; @@ -1563,7 +1564,7 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) */ ctl = &controls[nctl + 0]; ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; - strcpy(ctl->id.name, "Tone Control - Bass"); + strscpy(ctl->id.name, "Tone Control - Bass"); ctl->vcount = 2; ctl->count = 10; ctl->min = 0; @@ -1572,7 +1573,7 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) ctl->translation = EMU10K1_GPR_TRANSLATION_BASS; ctl = &controls[nctl + 1]; ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; - strcpy(ctl->id.name, "Tone Control - Treble"); + strscpy(ctl->id.name, "Tone Control - Treble"); ctl->vcount = 2; ctl->count = 10; ctl->min = 0; @@ -1849,7 +1850,7 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) /* clear TRAM data & address lines */ memset(icode->tram_valid, 0xff, 160 / 8); - strcpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela"); + strscpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela"); ptr = 0; i = 0; /* we have 12 inputs */ playback = SND_EMU10K1_INPUTS; @@ -2160,7 +2161,7 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) */ ctl = &controls[i + 0]; ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; - strcpy(ctl->id.name, "Tone Control - Bass"); + strscpy(ctl->id.name, "Tone Control - Bass"); ctl->vcount = 2; ctl->count = 10; ctl->min = 0; @@ -2170,7 +2171,7 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) ctl->translation = EMU10K1_GPR_TRANSLATION_BASS; ctl = &controls[i + 1]; ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; - strcpy(ctl->id.name, "Tone Control - Treble"); + strscpy(ctl->id.name, "Tone Control - Treble"); ctl->vcount = 2; ctl->count = 10; ctl->min = 0; @@ -2623,7 +2624,7 @@ int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device) err = snd_hwdep_new(emu->card, "FX8010", device, &hw); if (err < 0) return err; - strcpy(hw->name, "EMU10K1 (FX8010)"); + strscpy(hw->name, "EMU10K1 (FX8010)"); hw->iface = SNDRV_HWDEP_IFACE_EMU10K1; hw->ops.open = snd_emu10k1_fx8010_open; hw->ops.ioctl = snd_emu10k1_fx8010_ioctl; diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 05b98d9b547b..d665d5d1ad7c 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -1983,7 +1984,7 @@ static int remove_ctl(struct snd_card *card, const char *name) { struct snd_ctl_elem_id id; memset(&id, 0, sizeof(id)); - strcpy(id.name, name); + strscpy(id.name, name); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; return snd_ctl_remove_id(card, &id); } @@ -2188,11 +2189,11 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, } else { no_ac97: if (emu->card_capabilities->ecard) - strcpy(emu->card->mixername, "EMU APS"); + strscpy(emu->card->mixername, "EMU APS"); else if (emu->audigy) - strcpy(emu->card->mixername, "SB Audigy"); + strscpy(emu->card->mixername, "SB Audigy"); else - strcpy(emu->card->mixername, "Emu10k1"); + strscpy(emu->card->mixername, "Emu10k1"); } if (emu->audigy) From 962297a7cd9e2302c2a10291ff551ebe7f19213d Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Thu, 19 Jun 2025 00:38:43 +0200 Subject: [PATCH 101/385] ALSA: aloop: Replace deprecated strcpy() with strscpy() strcpy() is deprecated; use strscpy() instead. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20250618223844.1458-2-thorsten.blum@linux.dev Signed-off-by: Takashi Iwai --- sound/drivers/aloop.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 6c318a5903ab..a8902dc45dc1 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -1368,7 +1369,7 @@ static int loopback_pcm_new(struct loopback *loopback, pcm->private_data = loopback; pcm->info_flags = 0; - strcpy(pcm->name, "Loopback PCM"); + strscpy(pcm->name, "Loopback PCM"); loopback->pcm[device] = pcm; return 0; @@ -1631,7 +1632,7 @@ static int loopback_mixer_new(struct loopback *loopback, int notify) struct loopback_setup *setup; int err, dev, substr, substr_count, idx; - strcpy(card->mixername, "Loopback Mixer"); + strscpy(card->mixername, "Loopback Mixer"); for (dev = 0; dev < 2; dev++) { pcm = loopback->pcm[dev]; substr_count = @@ -1824,8 +1825,8 @@ static int loopback_probe(struct platform_device *devptr) loopback_cable_proc_new(loopback, 0); loopback_cable_proc_new(loopback, 1); loopback_timer_source_proc_new(loopback); - strcpy(card->driver, "Loopback"); - strcpy(card->shortname, "Loopback"); + strscpy(card->driver, "Loopback"); + strscpy(card->shortname, "Loopback"); sprintf(card->longname, "Loopback %i", dev + 1); err = snd_card_register(card); if (err < 0) From 13ef21dffe7691a32c83a83d697d119c045536eb Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Mon, 16 Jun 2025 19:48:20 +0800 Subject: [PATCH 102/385] ASoC: SDCA: add support for HIDE entity properties and HID descriptor/report Add support for parsing the HIDE entity descriptor and HID descriptor/report Signed-off-by: Shuming Fan Reviewed-by: Charles Keepax Link: https://patch.msgid.link/20250616114820.855401-1-shumingf@realtek.com Signed-off-by: Mark Brown --- include/sound/sdca_function.h | 29 ++++++++++++ sound/soc/sdca/sdca_functions.c | 83 +++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h index eaedb54a8322..856b0f40ce5e 100644 --- a/include/sound/sdca_function.h +++ b/include/sound/sdca_function.h @@ -11,6 +11,7 @@ #include #include +#include struct device; struct sdca_entity; @@ -1040,6 +1041,32 @@ struct sdca_entity_ge { int num_modes; }; +/** + * struct sdca_entity_hide - information specific to HIDE Entities + * @hid: HID device structure + * @hidtx_ids: HIDTx Report ID + * @num_hidtx_ids: number of HIDTx Report ID + * @hidrx_ids: HIDRx Report ID + * @num_hidrx_ids: number of HIDRx Report ID + * @hide_reside_function_num: indicating which Audio Function Numbers within this Device + * @max_delay: the maximum time in microseconds allowed for the Device to change the ownership from Device to Host + * @af_number_list: which Audio Function Numbers within this Device are sending/receiving the messages in this HIDE + * @hid_desc: HID descriptor for the HIDE Entity + * @hid_report_desc: HID Report Descriptor for the HIDE Entity + */ +struct sdca_entity_hide { + struct hid_device *hid; + unsigned int *hidtx_ids; + int num_hidtx_ids; + unsigned int *hidrx_ids; + int num_hidrx_ids; + unsigned int hide_reside_function_num; + unsigned int max_delay; + unsigned int af_number_list[SDCA_MAX_FUNCTION_COUNT]; + struct hid_descriptor hid_desc; + unsigned char *hid_report_desc; +}; + /** * struct sdca_entity - information for one SDCA Entity * @label: String such as "OT 12". @@ -1055,6 +1082,7 @@ struct sdca_entity_ge { * @cs: Clock Source specific Entity properties. * @pde: Power Domain Entity specific Entity properties. * @ge: Group Entity specific Entity properties. + * @hide: HIDE Entity specific Entity properties. */ struct sdca_entity { const char *label; @@ -1071,6 +1099,7 @@ struct sdca_entity { struct sdca_entity_cs cs; struct sdca_entity_pde pde; struct sdca_entity_ge ge; + struct sdca_entity_hide hide; }; }; diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index 64ac26443890..4a89067dcf76 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -1220,6 +1220,86 @@ bad_list: return -EINVAL; } +static int +find_sdca_entity_hide(struct device *dev, struct fwnode_handle *function_node, + struct fwnode_handle *entity_node, struct sdca_entity *entity) +{ + struct sdca_entity_hide *hide = &entity->hide; + unsigned int delay, *af_list = hide->af_number_list; + int nval, ret; + unsigned char *report_desc = NULL; + + ret = fwnode_property_read_u32(entity_node, + "mipi-sdca-RxUMP-ownership-transition-maxdelay", &delay); + if (!ret) + hide->max_delay = delay; + + nval = fwnode_property_count_u32(entity_node, "mipi-sdca-HIDTx-supported-report-ids"); + if (nval > 0) { + hide->num_hidtx_ids = nval; + hide->hidtx_ids = devm_kcalloc(dev, hide->num_hidtx_ids, + sizeof(*hide->hidtx_ids), GFP_KERNEL); + if (!hide->hidtx_ids) + return -ENOMEM; + + ret = fwnode_property_read_u32_array(entity_node, + "mipi-sdca-HIDTx-supported-report-ids", + hide->hidtx_ids, + hide->num_hidtx_ids); + if (ret < 0) + return ret; + } + + nval = fwnode_property_count_u32(entity_node, "mipi-sdca-HIDRx-supported-report-ids"); + if (nval > 0) { + hide->num_hidrx_ids = nval; + hide->hidrx_ids = devm_kcalloc(dev, hide->num_hidrx_ids, + sizeof(*hide->hidrx_ids), GFP_KERNEL); + if (!hide->hidrx_ids) + return -ENOMEM; + + ret = fwnode_property_read_u32_array(entity_node, + "mipi-sdca-HIDRx-supported-report-ids", + hide->hidrx_ids, + hide->num_hidrx_ids); + if (ret < 0) + return ret; + } + + nval = fwnode_property_count_u32(entity_node, "mipi-sdca-hide-related-audio-function-list"); + if (nval <= 0) { + dev_err(dev, "%pfwP: audio function numbers list missing: %d\n", + entity_node, nval); + return -EINVAL; + } else if (nval > SDCA_MAX_FUNCTION_COUNT) { + dev_err(dev, "%pfwP: maximum number of audio function exceeded\n", entity_node); + return -EINVAL; + } + + hide->hide_reside_function_num = nval; + fwnode_property_read_u32_array(entity_node, + "mipi-sdca-hide-related-audio-function-list", af_list, nval); + + nval = fwnode_property_count_u8(function_node, "mipi-sdca-hid-descriptor"); + if (nval) + fwnode_property_read_u8_array(function_node, "mipi-sdca-hid-descriptor", + (u8 *)&hide->hid_desc, nval); + + if (hide->hid_desc.bNumDescriptors) { + nval = fwnode_property_count_u8(function_node, "mipi-sdca-report-descriptor"); + if (nval) { + report_desc = devm_kzalloc(dev, nval, GFP_KERNEL); + if (!report_desc) + return -ENOMEM; + hide->hid_report_desc = report_desc; + fwnode_property_read_u8_array(function_node, "mipi-sdca-report-descriptor", + report_desc, nval); + } + } + + return 0; +} + static int find_sdca_entity(struct device *dev, struct fwnode_handle *function_node, struct fwnode_handle *entity_node, @@ -1261,6 +1341,9 @@ static int find_sdca_entity(struct device *dev, case SDCA_ENTITY_TYPE_GE: ret = find_sdca_entity_ge(dev, entity_node, entity); break; + case SDCA_ENTITY_TYPE_HIDE: + ret = find_sdca_entity_hide(dev, function_node, entity_node, entity); + break; default: break; } From 3421d46440ebe0865bec71dbd2330b4e17a425ab Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 16 Jun 2025 19:49:07 +0800 Subject: [PATCH 103/385] HID: core: Add bus define for SoundWire bus SDCA (SoundWire Device Class for Audio) uses HID to convey input events from peripheral devices. Add a bus define for the SoundWire bus to prepare support for this. Signed-off-by: Charles Keepax Signed-off-by: Shuming Fan Acked-by: Jiri Kosina Link: https://patch.msgid.link/20250616114907.855452-1-shumingf@realtek.com Signed-off-by: Mark Brown --- drivers/hid/hid-core.c | 3 +++ include/uapi/linux/input.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index b348d0464314..b419e31005b8 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2294,6 +2294,9 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) case BUS_I2C: bus = "I2C"; break; + case BUS_SDW: + bus = "SOUNDWIRE"; + break; case BUS_VIRTUAL: bus = "VIRTUAL"; break; diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h index 2557eb7b0561..127119c287cf 100644 --- a/include/uapi/linux/input.h +++ b/include/uapi/linux/input.h @@ -275,6 +275,7 @@ struct input_mask { #define BUS_CEC 0x1E #define BUS_INTEL_ISHTP 0x1F #define BUS_AMD_SFH 0x20 +#define BUS_SDW 0x21 /* * MT_TOOL types From 87aafc8580acf87fcaf1a7e30ed858d8c8d37d81 Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Sat, 21 Jun 2025 11:52:24 -0700 Subject: [PATCH 104/385] ALSA: intel8x0: Fix incorrect codec index usage in mixer for ICH4 code mistakenly used a hardcoded index (codec[1]) instead of iterating, over the codec array using the loop variable i. Use codec[i] instead of codec[1] to match the loop iteration. Signed-off-by: Alok Tiwari Link: https://patch.msgid.link/20250621185233.4081094-1-alok.a.tiwari@oracle.com Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 51e7f1f1a48e..b521cec20333 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2249,7 +2249,7 @@ static int snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, tmp |= chip->ac97_sdin[0] << ICH_DI1L_SHIFT; for (i = 1; i < 4; i++) { if (pcm->r[0].codec[i]) { - tmp |= chip->ac97_sdin[pcm->r[0].codec[1]->num] << ICH_DI2L_SHIFT; + tmp |= chip->ac97_sdin[pcm->r[0].codec[i]->num] << ICH_DI2L_SHIFT; break; } } From 2f6ff1e615cd4f8a86c9d0e4e778db9ae44d5481 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 16 Jun 2025 13:54:08 +0200 Subject: [PATCH 105/385] ASoC: codecs: wcd937x: Use simple defines for chipid register value The value used to identify chip variant is not an enumeration, but raw value used to compare registers with. The 'enum' is not used in the code at all, so simplify and make it a raw hex value define, so intention will be explicit. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250616-asoc-wcd93xx-enum-v1-1-a20a1b538509@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd937x.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index a5cf6015122c..3b0a8cc314e0 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -24,10 +24,8 @@ #include "wcd-mbhc-v2.h" #include "wcd937x.h" -enum { - CHIPID_WCD9370 = 0, - CHIPID_WCD9375 = 5, -}; +#define CHIPID_WCD9370 0x0 +#define CHIPID_WCD9375 0x5 /* Z value defined in milliohm */ #define WCD937X_ZDET_VAL_32 (32000) From 100877df34b00257c9ed6d279b06b3ed1da5e2c1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 16 Jun 2025 13:54:09 +0200 Subject: [PATCH 106/385] ASoC: codecs: wcd938x: Use simple defines for chipid register value The value used to identify chip variant is not an enumeration, but raw value used to compare registers with. The 'enum' is not used in the code at all, so simplify and make it a raw hex value define, so intention will be explicit. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250616-asoc-wcd93xx-enum-v1-2-a20a1b538509@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd938x.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index 6401ac32d1b6..711f373ece24 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -25,6 +25,9 @@ #include "wcd-mbhc-v2.h" #include "wcd938x.h" +#define CHIPID_WCD9380 0x0 +#define CHIPID_WCD9385 0x5 + #define WCD938X_MAX_MICBIAS (4) #define WCD938X_MBHC_MAX_BUTTONS (8) #define TX_ADC_MAX (4) @@ -72,11 +75,6 @@ SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, snd_soc_get_volsw, \ wcd938x_ear_pa_put_gain, tlv_array) -enum { - WCD9380 = 0, - WCD9385 = 5, -}; - enum { /* INTR_CTRL_INT_MASK_0 */ WCD938X_IRQ_MBHC_BUTTON_PRESS_DET = 0, @@ -3119,7 +3117,7 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component) disable_irq_nosync(wcd938x->aux_pdm_wd_int); switch (variant) { - case WCD9380: + case CHIPID_WCD9380: ret = snd_soc_add_component_controls(component, wcd9380_snd_controls, ARRAY_SIZE(wcd9380_snd_controls)); if (ret < 0) { @@ -3129,7 +3127,7 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component) goto err_free_aux_pdm_wd_int; } break; - case WCD9385: + case CHIPID_WCD9385: ret = snd_soc_add_component_controls(component, wcd9385_snd_controls, ARRAY_SIZE(wcd9385_snd_controls)); if (ret < 0) { From 5d3ccd356e2ce510bdbd4b0c389f2fe3deb41a45 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 16 Jun 2025 13:54:10 +0200 Subject: [PATCH 107/385] ASoC: codecs: wcd939x: Use simple defines for chipid register value The value used to identify chip variant is not an enumeration, but raw value used to compare registers with. The 'enum' is not used in the code at all, so simplify and make it a raw hex value define, so intention will be explicit. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250616-asoc-wcd93xx-enum-v1-3-a20a1b538509@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd939x.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index 45645abe3085..7ec751a6cd26 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -36,6 +36,9 @@ #define TX_ADC_MAX (4) #define WCD_MBHC_HS_V_MAX 1600 +#define CHIPID_WCD9390 0x0 +#define CHIPID_WCD9395 0x5 + enum { WCD939X_VERSION_1_0 = 0, WCD939X_VERSION_1_1, @@ -85,11 +88,6 @@ enum { /* Z value compared in milliOhm */ #define WCD939X_ANA_MBHC_ZDET_CONST (1018 * 1024) -enum { - WCD9390 = 0, - WCD9395 = 5, -}; - enum { /* INTR_CTRL_INT_MASK_0 */ WCD939X_IRQ_MBHC_BUTTON_PRESS_DET = 0, @@ -1483,7 +1481,7 @@ static int wcd939x_rx_hph_mode_put(struct snd_kcontrol *kcontrol, if (mode_val == wcd939x->hph_mode) return 0; - if (wcd939x->variant == WCD9390) { + if (wcd939x->variant == CHIPID_WCD9390) { switch (mode_val) { case CLS_H_NORMAL: case CLS_H_LP: @@ -3065,7 +3063,7 @@ static int wcd939x_soc_codec_probe(struct snd_soc_component *component) disable_irq_nosync(wcd939x->ear_pdm_wd_int); switch (wcd939x->variant) { - case WCD9390: + case CHIPID_WCD9390: ret = snd_soc_add_component_controls(component, wcd9390_snd_controls, ARRAY_SIZE(wcd9390_snd_controls)); if (ret < 0) { @@ -3075,7 +3073,7 @@ static int wcd939x_soc_codec_probe(struct snd_soc_component *component) goto err_free_ear_pdm_wd_int; } break; - case WCD9395: + case CHIPID_WCD9395: ret = snd_soc_add_component_controls(component, wcd9395_snd_controls, ARRAY_SIZE(wcd9395_snd_controls)); if (ret < 0) { From a48352921f0b15b1f7eff83f5b5613d6ae2350d3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 16 Jun 2025 13:54:11 +0200 Subject: [PATCH 108/385] ASoC: codecs: wcd939x: Add defines for major/minor version decoding Replace hard-coded register values with defines for checking major and minor versions of device. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250616-asoc-wcd93xx-enum-v1-4-a20a1b538509@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd939x.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index 7ec751a6cd26..64f082e474c1 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -39,6 +39,11 @@ #define CHIPID_WCD9390 0x0 #define CHIPID_WCD9395 0x5 +/* Version major: 1.x */ +#define CHIPID_WCD939X_VER_MAJOR_1 0x0 +/* Version minor: x.1 */ +#define CHIPID_WCD939X_VER_MINOR_1 0x3 + enum { WCD939X_VERSION_1_0 = 0, WCD939X_VERSION_1_1, @@ -3449,8 +3454,8 @@ static int wcd939x_bind(struct device *dev) regmap_read(wcd939x->regmap, WCD939X_DIGITAL_CHIP_ID1, &id1); regmap_read(wcd939x->regmap, WCD939X_EAR_STATUS_REG_1, &status1); - if (id1 == 0) - version = ((status1 & 0x3) ? WCD939X_VERSION_1_1 : WCD939X_VERSION_1_0); + if (id1 == CHIPID_WCD939X_VER_MAJOR_1) + version = ((status1 & CHIPID_WCD939X_VER_MINOR_1) ? WCD939X_VERSION_1_1 : WCD939X_VERSION_1_0); else version = WCD939X_VERSION_2_0; From ac558015dfd803626622bd0ba9645d58a3ed16b1 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Mon, 16 Jun 2025 19:49:29 +0800 Subject: [PATCH 109/385] ASoC: SDCA: add a HID device for HIDE entity This patch supports to add a HID device for SDCA HIDE entity. The codec driver could call 'hid_input_report' to report events. Signed-off-by: Shuming Fan Reviewed-by: Charles Keepax Link: https://patch.msgid.link/20250616114929.855496-1-shumingf@realtek.com Signed-off-by: Mark Brown --- include/sound/sdca_hid.h | 25 +++++++ sound/soc/sdca/Kconfig | 4 + sound/soc/sdca/Makefile | 3 + sound/soc/sdca/sdca_functions.c | 9 +++ sound/soc/sdca/sdca_hid.c | 127 ++++++++++++++++++++++++++++++++ 5 files changed, 168 insertions(+) create mode 100644 include/sound/sdca_hid.h create mode 100644 sound/soc/sdca/sdca_hid.c diff --git a/include/sound/sdca_hid.h b/include/sound/sdca_hid.h new file mode 100644 index 000000000000..8ab3e498884e --- /dev/null +++ b/include/sound/sdca_hid.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * The MIPI SDCA specification is available for public downloads at + * https://www.mipi.org/mipi-sdca-v1-0-download + * + */ + +#ifndef __SDCA_HID_H__ +#define __SDCA_HID_H__ + +#include +#include + +#if IS_ENABLED(CONFIG_SND_SOC_SDCA_HID) +int sdca_add_hid_device(struct device *dev, struct sdca_entity *entity); + +#else +static inline int sdca_add_hid_device(struct device *dev, struct sdca_entity *entity) +{ + return 0; +} + +#endif + +#endif /* __SDCA_HID_H__ */ diff --git a/sound/soc/sdca/Kconfig b/sound/soc/sdca/Kconfig index ee20b9914aa1..ec28855fe3b0 100644 --- a/sound/soc/sdca/Kconfig +++ b/sound/soc/sdca/Kconfig @@ -9,3 +9,7 @@ config SND_SOC_SDCA config SND_SOC_SDCA_OPTIONAL def_tristate SND_SOC_SDCA || !SND_SOC_SDCA + +config SND_SOC_SDCA_HID + tristate "SDCA HID support" + depends on SND_SOC_SDCA && HID diff --git a/sound/soc/sdca/Makefile b/sound/soc/sdca/Makefile index 53344f108ca6..9af46e7edfd2 100644 --- a/sound/soc/sdca/Makefile +++ b/sound/soc/sdca/Makefile @@ -2,4 +2,7 @@ snd-soc-sdca-y := sdca_functions.o sdca_device.o sdca_regmap.o sdca_asoc.o +snd-soc-sdca-hid-y := sdca_hid.o + +obj-$(CONFIG_SND_SOC_SDCA_HID) += snd-soc-sdca-hid.o obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca.o diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index 4a89067dcf76..093c681e9387 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -19,6 +19,7 @@ #include #include #include +#include /* * Should be long enough to encompass all the MIPI DisCo properties. @@ -1294,6 +1295,13 @@ find_sdca_entity_hide(struct device *dev, struct fwnode_handle *function_node, hide->hid_report_desc = report_desc; fwnode_property_read_u8_array(function_node, "mipi-sdca-report-descriptor", report_desc, nval); + + /* add HID device */ + ret = sdca_add_hid_device(dev, entity); + if (ret) { + dev_err(dev, "%pfwP: failed to add HID device: %d\n", entity_node, ret); + return ret; + } } } @@ -1933,3 +1941,4 @@ EXPORT_SYMBOL_NS(sdca_parse_function, "SND_SOC_SDCA"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SDCA library"); +MODULE_IMPORT_NS("SND_SOC_SDCA_HID"); diff --git a/sound/soc/sdca/sdca_hid.c b/sound/soc/sdca/sdca_hid.c new file mode 100644 index 000000000000..b227ad94d08f --- /dev/null +++ b/sound/soc/sdca/sdca_hid.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) + +/* + * The MIPI SDCA specification is available for public downloads at + * https://www.mipi.org/mipi-sdca-v1-0-download + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int sdwhid_parse(struct hid_device *hid) +{ + struct sdca_entity *entity = hid->driver_data; + unsigned int rsize; + int ret; + + rsize = entity->hide.hid_desc.rpt_desc.wDescriptorLength; + + if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { + dev_err(&hid->dev, "invalid size of report descriptor (%u)\n", rsize); + return -EINVAL; + } + + ret = hid_parse_report(hid, entity->hide.hid_report_desc, rsize); + + if (!ret) + return 0; + + dev_err(&hid->dev, "parsing report descriptor failed\n"); + return ret; +} + +static int sdwhid_start(struct hid_device *hid) +{ + return 0; +} + +static void sdwhid_stop(struct hid_device *hid) +{ +} + +static int sdwhid_raw_request(struct hid_device *hid, unsigned char reportnum, + __u8 *buf, size_t len, unsigned char rtype, int reqtype) +{ + switch (reqtype) { + case HID_REQ_GET_REPORT: + /* not implemented yet */ + return 0; + case HID_REQ_SET_REPORT: + /* not implemented yet */ + return 0; + default: + return -EIO; + } +} + +static int sdwhid_open(struct hid_device *hid) +{ + return 0; +} + +static void sdwhid_close(struct hid_device *hid) +{ +} + +static const struct hid_ll_driver sdw_hid_driver = { + .parse = sdwhid_parse, + .start = sdwhid_start, + .stop = sdwhid_stop, + .open = sdwhid_open, + .close = sdwhid_close, + .raw_request = sdwhid_raw_request, +}; + +int sdca_add_hid_device(struct device *dev, struct sdca_entity *entity) +{ + struct sdw_bus *bus; + struct hid_device *hid; + struct sdw_slave *slave = dev_to_sdw_dev(dev); + int ret; + + bus = slave->bus; + + hid = hid_allocate_device(); + if (IS_ERR(hid)) + return PTR_ERR(hid); + + hid->ll_driver = &sdw_hid_driver; + + hid->dev.parent = dev; + hid->bus = BUS_SDW; + hid->version = le16_to_cpu(entity->hide.hid_desc.bcdHID); + + snprintf(hid->name, sizeof(hid->name), + "HID sdw:%01x:%01x:%04x:%04x:%02x", + bus->controller_id, bus->link_id, slave->id.mfg_id, + slave->id.part_id, slave->id.class_id); + + snprintf(hid->phys, sizeof(hid->phys), "%s", dev->bus->name); + + hid->driver_data = entity; + + ret = hid_add_device(hid); + if (ret && ret != -ENODEV) { + dev_err(dev, "can't add hid device: %d\n", ret); + hid_destroy_device(hid); + return ret; + } + + entity->hide.hid = hid; + + return 0; +} +EXPORT_SYMBOL_NS(sdca_add_hid_device, "SND_SOC_SDCA_HID"); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("SDCA HID library"); From c4ca928a6db1593802cd945f075a7e21dd0430c1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 13 Jun 2025 17:41:04 +0100 Subject: [PATCH 110/385] ASoC: hdac_hdmi: Rate limit logging on connection and disconnection We currently log parse failures for ELD data and some disconnection events as errors without rate limiting. These log messages can be triggered very frequently in some situations, especially ELD parsing when there is nothing connected to a HDMI port which will generate: hdmi-audio-codec hdmi-audio-codec.1.auto: HDMI: Unknown ELD version 0 While there's doubtless work that could be done on reducing the number of connection notification callbacks it's possible these may be legitimately generated by poor quality physical connections so let's use rate limiting to mitigate the log spam for the parse errors and lower the severity for disconnect logging to debug level. Signed-off-by: Mark Brown Link: https://patch.msgid.link/20250613-asoc-hdmi-eld-logging-v1-1-76d64154d969@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index e05f0bf91fa5..3aae0a2eb047 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1231,7 +1231,8 @@ static int hdac_hdmi_parse_eld(struct hdac_device *hdev, >> DRM_ELD_VER_SHIFT; if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) { - dev_err(&hdev->dev, "HDMI: Unknown ELD version %d\n", ver); + dev_err_ratelimited(&hdev->dev, + "HDMI: Unknown ELD version %d\n", ver); return -EINVAL; } @@ -1239,7 +1240,8 @@ static int hdac_hdmi_parse_eld(struct hdac_device *hdev, DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT; if (mnl > ELD_MAX_MNL) { - dev_err(&hdev->dev, "HDMI: MNL Invalid %d\n", mnl); + dev_err_ratelimited(&hdev->dev, + "HDMI: MNL Invalid %d\n", mnl); return -EINVAL; } @@ -1298,8 +1300,8 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, if (!port->eld.monitor_present || !port->eld.eld_valid) { - dev_err(&hdev->dev, "%s: disconnect for pin:port %d:%d\n", - __func__, pin->nid, port->id); + dev_dbg(&hdev->dev, "%s: disconnect for pin:port %d:%d\n", + __func__, pin->nid, port->id); /* * PCMs are not registered during device probe, so don't From 8b04b766714e93ca5a8021ff3408c9ef89d9eb85 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Fri, 20 Jun 2025 17:38:42 +0530 Subject: [PATCH 111/385] ASoC: amd: acp: add soundwire machine for ACP7.0 and ACP7.1 sof stack Add SoundWire machine with RT722 multi functional codec support for ACP7.0 and ACP7.1 platforms at sdw link0 for sof stack. Signed-off-by: Vijendar Mukunda Link: https://patch.msgid.link/20250620120942.1168827-2-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/Kconfig | 1 + sound/soc/amd/acp/amd-acp70-acpi-match.c | 12 ++++++++++++ sound/soc/amd/mach-config.h | 1 + 3 files changed, 14 insertions(+) diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index b9432052c638..c2a60bc80ee6 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -148,6 +148,7 @@ config SND_SOC_AMD_SOF_SDW_MACH select SND_SOC_RT1316_SDW select SND_SOC_RT715_SDW select SND_SOC_RT715_SDCA_SDW + select SND_SOC_RT722_SDCA_SDW help This option enables SOF sound card support for SoundWire enabled AMD platforms along with ACP PDM controller. diff --git a/sound/soc/amd/acp/amd-acp70-acpi-match.c b/sound/soc/amd/acp/amd-acp70-acpi-match.c index e87ccfeee5bd..dcecac792e6d 100644 --- a/sound/soc/amd/acp/amd-acp70-acpi-match.c +++ b/sound/soc/amd/acp/amd-acp70-acpi-match.c @@ -155,6 +155,18 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sdw_machines[] = { }; EXPORT_SYMBOL(snd_soc_acpi_amd_acp70_sdw_machines); +struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_sdw_machines[] = { + { + .link_mask = BIT(0), + .links = acp70_rt722_only, + .drv_name = "amd_sof_sdw", + .sof_tplg_filename = "sof-acp_7_0-rt722-l0.tplg", + .fw_filename = "sof-acp_7_0.ri", + }, + {}, +}; +EXPORT_SYMBOL(snd_soc_acpi_amd_acp70_sof_sdw_machines); + MODULE_DESCRIPTION("AMD ACP7.0 & ACP7.1 tables and support for ACPI enumeration"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h index fdf016a64bbf..5b6362103ca0 100644 --- a/sound/soc/amd/mach-config.h +++ b/sound/soc/amd/mach-config.h @@ -27,6 +27,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sdw_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_sdw_machines[]; struct config_entry { u32 flags; From 59566923d955b69bfb1e1163f07dff437dde8c9c Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Fri, 20 Jun 2025 17:38:43 +0530 Subject: [PATCH 112/385] ASoC: SOF: amd: add alternate machines for ACP7.0 and ACP7.1 platforms Add SoundWire machines as alternate machines for ACP7.0 and ACP7.1 platforms. Signed-off-by: Vijendar Mukunda Link: https://patch.msgid.link/20250620120942.1168827-3-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/pci-acp70.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/amd/pci-acp70.c b/sound/soc/sof/amd/pci-acp70.c index c4db21668252..51d36d43c42b 100644 --- a/sound/soc/sof/amd/pci-acp70.c +++ b/sound/soc/sof/amd/pci-acp70.c @@ -48,6 +48,7 @@ static const struct sof_amd_acp_desc acp70_chip_info = { static const struct sof_dev_desc acp70_desc = { .machines = snd_soc_acpi_amd_acp70_sof_machines, + .alt_machines = snd_soc_acpi_amd_acp70_sof_sdw_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, From d5363522042bca867f45174b4d5a8b5a39eae989 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 23 Jun 2025 13:38:54 +0200 Subject: [PATCH 113/385] ALSA: mixer_oss: Remove deprecated strcpy() function calls Remove the deprecated strcpy() function calls and assign the strings directly to a 'char *' instead. Use 'if/else if' instead of two separate if statements. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20250623113855.37031-2-thorsten.blum@linux.dev Signed-off-by: Takashi Iwai --- sound/core/oss/mixer_oss.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 05fc8911479c..e839a4bb93f8 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -991,7 +991,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct slot *pslot; struct snd_kcontrol *kctl; struct snd_mixer_oss_slot *rslot; - char str[64]; + const char *str; /* check if already assigned */ if (mixer->slots[ptr->oss_id].get_volume && ! replace_old) @@ -1014,11 +1014,11 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, if (kctl->info(kctl, uinfo)) return 0; - strcpy(str, ptr->name); + str = ptr->name; if (!strcmp(str, "Master")) - strcpy(str, "Mix"); - if (!strcmp(str, "Master Mono")) - strcpy(str, "Mix Mono"); + str = "Mix"; + else if (!strcmp(str, "Master Mono")) + str = "Mix Mono"; slot.capture_item = 0; if (!strcmp(uinfo->value.enumerated.name, str)) { slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE; From 1adcbdf54f76e1004bdf71df4eb1888c26e7ad06 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Jun 2025 15:14:30 +0200 Subject: [PATCH 114/385] ALSA: hda: Disable jack polling at shutdown Although the jack polling is canceled at shutdown in snd_hda_codec_shutdown(), it might be still re-triggered when the work is being processed at cancel_delayed_work_sync() call. This may result in the unexpected hardware access that should have been already disabled. For assuring to stop the jack polling, clear codec->jackpoll_interval at shutdown. Reported-by: Joakim Zhang Closes: https://lore.kernel.org/20250619020844.2974160-4-joakim.zhang@cixtech.com Tested-by: Joakim Zhang Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250623131437.10670-2-tiwai@suse.de --- sound/pci/hda/hda_codec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index c018beeecd3d..4eba3970cd1a 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3020,6 +3020,7 @@ void snd_hda_codec_shutdown(struct hda_codec *codec) if (!codec->core.registered) return; + codec->jackpoll_interval = 0; /* don't poll any longer */ cancel_delayed_work_sync(&codec->jackpoll_work); list_for_each_entry(cpcm, &codec->pcm_list_head, list) snd_pcm_suspend_all(cpcm->pcm); From 507cd1216a6d70da6b230c806862c065632c713f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Jun 2025 15:14:31 +0200 Subject: [PATCH 115/385] ALSA: hda: Disable codec runtime PM when jack polling is enabled When the jack polling is triggered quite frequently, it makes little sense to perform the runtime PM at each time; since we do almost full configuration at each runtime resume for HD-audio, the merit by power saving would be lost. Hence, it'd be more reasonable to disable the runtime PM when the jack polling is enabled. This patch introduces the runtime PM idle callback and disables the runtime PM when the jack polling is enabled. This also serves as the preliminary change for the further jack poll cleanup. The exception is the case where codec->bus->jackpoll_in_suspend flag is set by the driver (currently set by HD-audio Tegra driver). This flag indicates that the polling is infrequent, hence there is still benefit to perform the runtime PM. The idle callback checks this flag and allows the runtime PM when set. Link: https://lore.kernel.org/20250619020844.2974160-1-joakim.zhang@cixtech.com Tested-by: Joakim Zhang Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250623131437.10670-3-tiwai@suse.de --- sound/pci/hda/hda_codec.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 4eba3970cd1a..ea361390b829 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2943,6 +2943,15 @@ static int hda_codec_runtime_resume(struct device *dev) return 0; } +static int hda_codec_runtime_idle(struct device *dev) +{ + struct hda_codec *codec = dev_to_hda_codec(dev); + + if (codec->jackpoll_interval && !codec->bus->jackpoll_in_suspend) + return -EBUSY; + return 0; +} + static int hda_codec_pm_prepare(struct device *dev) { struct hda_codec *codec = dev_to_hda_codec(dev); @@ -3008,7 +3017,8 @@ const struct dev_pm_ops hda_codec_driver_pm = { .thaw = pm_sleep_ptr(hda_codec_pm_thaw), .poweroff = pm_sleep_ptr(hda_codec_pm_suspend), .restore = pm_sleep_ptr(hda_codec_pm_restore), - RUNTIME_PM_OPS(hda_codec_runtime_suspend, hda_codec_runtime_resume, NULL) + RUNTIME_PM_OPS(hda_codec_runtime_suspend, hda_codec_runtime_resume, + hda_codec_runtime_idle) }; /* suspend the codec at shutdown; called from driver's shutdown callback */ From 5f7e54b23e4d253eff3b10b12d6fa92d28d7dddc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Jun 2025 15:14:32 +0200 Subject: [PATCH 116/385] ALSA: hda: Handle the jack polling always via a work We used to call directly hda_jackpoll_work() from a couple of places for updating the jack and notify to user-space, but this makes rather the code flow fragile. Namely, because of those direct calls, hda_jackpoll_work() uses snd_hda_power_up_pm() and *_down_pm() calls instead of the standard snd_hda_power_up() and *_down() calls. The latter pair assures the runtime PM resume sync, so it can avoid the race against the PM callbacks gracefully, while the former pair may continue if called concurrently, hence it may race (by design). In this patch, we change the call pattern of hda_jackpoll_work(); now all callers are replaced with the standard snd_hda_jack_report_sync() and the additional schedule_delayed_work(). Since hda_jackpoll_work() is called only from the associated work, it's always outside the PM code path, and we can safely use snd_hda_power_up() and *_down() there instead. This allows us to remove the racy check of power-state in hda_jackpoll_work(), as well as the tricky cancel_delayed_work() and rescheduling at hda_codec_runtime_suspend(). Reported-by: Joakim Zhang Closes: https://lore.kernel.org/20250619020844.2974160-1-joakim.zhang@cixtech.com Tested-by: Joakim Zhang Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250623131437.10670-4-tiwai@suse.de --- sound/pci/hda/hda_codec.c | 43 ++++++++++++++------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index ea361390b829..5508381a1833 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -639,24 +639,16 @@ static void hda_jackpoll_work(struct work_struct *work) struct hda_codec *codec = container_of(work, struct hda_codec, jackpoll_work.work); - /* for non-polling trigger: we need nothing if already powered on */ - if (!codec->jackpoll_interval && snd_hdac_is_power_on(&codec->core)) - return; - - /* the power-up/down sequence triggers the runtime resume */ - snd_hda_power_up_pm(codec); - /* update jacks manually if polling is required, too */ - if (codec->jackpoll_interval) { - snd_hda_jack_set_dirty_all(codec); - snd_hda_jack_poll_all(codec); - } - snd_hda_power_down_pm(codec); - if (!codec->jackpoll_interval) return; - schedule_delayed_work(&codec->jackpoll_work, - codec->jackpoll_interval); + /* the power-up/down sequence triggers the runtime resume */ + snd_hda_power_up(codec); + /* update jacks manually if polling is required, too */ + snd_hda_jack_set_dirty_all(codec); + snd_hda_jack_poll_all(codec); + schedule_delayed_work(&codec->jackpoll_work, codec->jackpoll_interval); + snd_hda_power_down(codec); } /* release all pincfg lists */ @@ -2895,12 +2887,12 @@ static void hda_call_codec_resume(struct hda_codec *codec) snd_hda_regmap_sync(codec); } - if (codec->jackpoll_interval) - hda_jackpoll_work(&codec->jackpoll_work.work); - else - snd_hda_jack_report_sync(codec); + snd_hda_jack_report_sync(codec); codec->core.dev.power.power_state = PMSG_ON; snd_hdac_leave_pm(&codec->core); + if (codec->jackpoll_interval) + schedule_delayed_work(&codec->jackpoll_work, + codec->jackpoll_interval); } static int hda_codec_runtime_suspend(struct device *dev) @@ -2912,8 +2904,6 @@ static int hda_codec_runtime_suspend(struct device *dev) if (!codec->card) return 0; - cancel_delayed_work_sync(&codec->jackpoll_work); - state = hda_call_codec_suspend(codec); if (codec->link_down_at_suspend || (codec_has_clkstop(codec) && codec_has_epss(codec) && @@ -2921,10 +2911,6 @@ static int hda_codec_runtime_suspend(struct device *dev) snd_hdac_codec_link_down(&codec->core); snd_hda_codec_display_power(codec, false); - if (codec->bus->jackpoll_in_suspend && - (dev->power.power_state.event != PM_EVENT_SUSPEND)) - schedule_delayed_work(&codec->jackpoll_work, - codec->jackpoll_interval); return 0; } @@ -3097,10 +3083,11 @@ int snd_hda_codec_build_controls(struct hda_codec *codec) if (err < 0) return err; + snd_hda_jack_report_sync(codec); /* call at the last init point */ if (codec->jackpoll_interval) - hda_jackpoll_work(&codec->jackpoll_work.work); - else - snd_hda_jack_report_sync(codec); /* call at the last init point */ + schedule_delayed_work(&codec->jackpoll_work, + codec->jackpoll_interval); + sync_power_up_states(codec); return 0; } From 17cc308b183308bf5ada36e164284fff7eb064ba Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 20 Jun 2025 10:14:03 +0800 Subject: [PATCH 117/385] ASoC: wm8524: enable constraints when sysclk is configured. In some cases, the sysclk won't be configured on init, and sysclk can be changed in hw_params() according to different sample rate, for example, for 44kHz sample rate, the sysclk is 11.2896MHz, for 48kHz sample rate, the sysclk is 12.288MHz. In order to support the above case, only enable constraints when sysclk is configured, and check the rate in hw_params. So overall there are three cases that need to be considered: - call set_sysclk() on init, then constraints will be initialized. - don't call set_sysclk() on init, but call it after startup(), then constraints will be configured, the constraints can be cleared with call set_sysclk() again in shutdown(). - don't call set_sysclk() in the whole flow, then there are no any constraints. The clocks depend on cpu dai. Enlarge the WM8524_NUM_RATES to 12, as the supported rate range is 8kHz to 192kHz. Signed-off-by: Shengjiu Wang Reviewed-by: Charles Keepax Link: https://patch.msgid.link/20250620021403.624303-1-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8524.c | 57 +++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/wm8524.c b/sound/soc/codecs/wm8524.c index 403e513f3fa8..6b1a7450b0ac 100644 --- a/sound/soc/codecs/wm8524.c +++ b/sound/soc/codecs/wm8524.c @@ -21,7 +21,7 @@ #include #include -#define WM8524_NUM_RATES 7 +#define WM8524_NUM_RATES 12 /* codec private data */ struct wm8524_priv { @@ -46,7 +46,7 @@ static const struct snd_soc_dapm_route wm8524_dapm_routes[] = { static const struct { int value; int ratio; -} lrclk_ratios[WM8524_NUM_RATES] = { +} lrclk_ratios[] = { { 1, 128 }, { 2, 192 }, { 3, 256 }, @@ -63,17 +63,12 @@ static int wm8524_startup(struct snd_pcm_substream *substream, struct wm8524_priv *wm8524 = snd_soc_component_get_drvdata(component); /* The set of sample rates that can be supported depends on the - * MCLK supplied to the CODEC - enforce this. + * MCLK supplied to the CODEC. */ - if (!wm8524->sysclk) { - dev_err(component->dev, - "No MCLK configured, call set_sysclk() on init\n"); - return -EINVAL; - } - - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &wm8524->rate_constraint); + if (wm8524->sysclk) + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &wm8524->rate_constraint); gpiod_set_value_cansleep(wm8524->mute, 1); @@ -97,9 +92,11 @@ static int wm8524_set_dai_sysclk(struct snd_soc_dai *codec_dai, unsigned int val; int i, j = 0; - wm8524->sysclk = freq; - wm8524->rate_constraint.count = 0; + wm8524->sysclk = freq; + if (!wm8524->sysclk) + return 0; + for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { val = freq / lrclk_ratios[i].ratio; /* Check that it's a standard rate since core can't @@ -108,9 +105,13 @@ static int wm8524_set_dai_sysclk(struct snd_soc_dai *codec_dai, */ switch (val) { case 8000: + case 11025: + case 16000: + case 22050: case 32000: case 44100: case 48000: + case 64000: case 88200: case 96000: case 176400: @@ -157,6 +158,33 @@ static int wm8524_mute_stream(struct snd_soc_dai *dai, int mute, int stream) return 0; } +static int wm8524_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct wm8524_priv *wm8524 = snd_soc_component_get_drvdata(component); + int i; + + /* If sysclk is not configured, no need to check the rate */ + if (!wm8524->sysclk) + return 0; + + /* Find a supported LRCLK rate */ + for (i = 0; i < wm8524->rate_constraint.count; i++) { + if (wm8524->rate_constraint.list[i] == params_rate(params)) + break; + } + + if (i == wm8524->rate_constraint.count) { + dev_err(component->dev, "LRCLK %d unsupported with MCLK %d\n", + params_rate(params), wm8524->sysclk); + return -EINVAL; + } + + return 0; +} + #define WM8524_RATES SNDRV_PCM_RATE_8000_192000 #define WM8524_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ @@ -169,6 +197,7 @@ static const struct snd_soc_dai_ops wm8524_dai_ops = { .set_sysclk = wm8524_set_dai_sysclk, .set_fmt = wm8524_set_fmt, .mute_stream = wm8524_mute_stream, + .hw_params = wm8524_hw_params, }; static struct snd_soc_dai_driver wm8524_dai = { From 6469fb5c8b2dc88c3840eced9ccdd3ddc97213b2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:41:46 +0000 Subject: [PATCH 118/385] ASoC: ti: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/874iwl20th.wl-kuninori.morimoto.gx@renesas.com Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/ti/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/ti/Kconfig b/sound/soc/ti/Kconfig index e22e41af3226..3323cf96e309 100644 --- a/sound/soc/ti/Kconfig +++ b/sound/soc/ti/Kconfig @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -menu "Audio support for Texas Instruments SoCs" +menu "Texas Instruments" depends on DMA_OMAP || TI_EDMA || TI_K3_UDMA || COMPILE_TEST config SND_SOC_TI_EDMA_PCM From 652dd81c7a66843db0afbe0866537492c965a3cc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:41:54 +0000 Subject: [PATCH 119/385] ASoC: adi: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/8734c520t9.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/adi/Kconfig | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/soc/adi/Kconfig b/sound/soc/adi/Kconfig index 0236dc5b4e9f..d47dffbf40d0 100644 --- a/sound/soc/adi/Kconfig +++ b/sound/soc/adi/Kconfig @@ -1,12 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only -config SND_SOC_ADI - tristate "Audio support for Analog Devices reference designs" - help - Audio support for various reference designs by Analog Devices. +menu "Analog Devices" config SND_SOC_ADI_AXI_I2S tristate "AXI-I2S support" - depends on SND_SOC_ADI select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO help @@ -14,8 +10,9 @@ config SND_SOC_ADI_AXI_I2S config SND_SOC_ADI_AXI_SPDIF tristate "AXI-SPDIF support" - depends on SND_SOC_ADI select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO help ASoC driver for the Analog Devices AXI-SPDIF softcore peripheral. + +endmenu From 6895deb5f25f92a9a8f7cf52977b0e8ef18baebb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:42:00 +0000 Subject: [PATCH 120/385] ASoC: amd: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Reviewed-by: Vijendar Mukunda Link: https://patch.msgid.link/871prp20t3.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/amd/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index c7daae392d74..fd35a03aadcb 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "AMD" + config SND_SOC_AMD_ACP tristate "AMD Audio Coprocessor support" help @@ -185,3 +187,4 @@ config SND_SOC_AMD_PS_MACH If unsure select "N". endif +endmenu From da65de541568cb9beb0feaa302a91d6af2f0258a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:42:08 +0000 Subject: [PATCH 121/385] ASoC: bcm: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87zfedzqfj.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/bcm/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig index 4218057b0874..de4e8a0daf1c 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "Broadcom" + config SND_BCM2835_SOC_I2S tristate "SoC Audio support for the Broadcom BCM2835 I2S module" depends on ARCH_BCM2835 || COMPILE_TEST @@ -26,3 +28,5 @@ config SND_BCM63XX_I2S_WHISTLER DSL/PON chips (bcm63158, bcm63178) If you don't know what to do here, say N + +endmenu From bb0b8820527eb32b5f9cc1405e855a33eca2d83b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:42:13 +0000 Subject: [PATCH 122/385] ASoC: dwc: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87y0txzqfe.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/dwc/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/dwc/Kconfig b/sound/soc/dwc/Kconfig index 71a58f7ac13a..6bb31b64210a 100644 --- a/sound/soc/dwc/Kconfig +++ b/sound/soc/dwc/Kconfig @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "DesignWare" + config SND_DESIGNWARE_I2S tristate "Synopsys I2S Device Driver" depends on HAVE_CLK @@ -18,3 +20,4 @@ config SND_DESIGNWARE_PCM This functionality is specially suited for I2S devices that don't have DMA support. +endmenu From 71951375b0ea03671a1752991cbeab0b9bc3f365 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:42:18 +0000 Subject: [PATCH 123/385] ASoC: fsl: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87wm9hzqf9.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index c4cf3cff58de..c4a00b22bc2a 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -menu "SoC Audio for Freescale CPUs" +menu "Freescale" comment "Common SoC Audio options for Freescale CPUs:" From b13f7eef9ff82e0163c6af8ac262fc2607161390 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:42:23 +0000 Subject: [PATCH 124/385] ASoC: img: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87v7p1zqf4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- arch/mips/configs/generic/board-marduk.config | 1 - sound/soc/img/Kconfig | 13 +++---------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/arch/mips/configs/generic/board-marduk.config b/arch/mips/configs/generic/board-marduk.config index 05ca34cd5a73..65433c5c4fde 100644 --- a/arch/mips/configs/generic/board-marduk.config +++ b/arch/mips/configs/generic/board-marduk.config @@ -50,4 +50,3 @@ CONFIG_CRYPTO_DEV_IMGTEC_HASH=y CONFIG_IMGPDC_WDT=y CONFIG_IR_IMG=y CONFIG_CC10001_ADC=y -CONFIG_SND_SOC_IMG=y diff --git a/sound/soc/img/Kconfig b/sound/soc/img/Kconfig index 568efa606ca4..9a4cba6fdb50 100644 --- a/sound/soc/img/Kconfig +++ b/sound/soc/img/Kconfig @@ -1,12 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only -config SND_SOC_IMG - bool "Audio support for Imagination Technologies designs" - help - Audio support for Imagination Technologies audio hardware +menu "Imagination Technologies" config SND_SOC_IMG_I2S_IN tristate "Imagination I2S Input Device Driver" - depends on SND_SOC_IMG select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for I2S in driver for @@ -14,7 +10,6 @@ config SND_SOC_IMG_I2S_IN config SND_SOC_IMG_I2S_OUT tristate "Imagination I2S Output Device Driver" - depends on SND_SOC_IMG select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for I2S out driver for @@ -22,7 +17,6 @@ config SND_SOC_IMG_I2S_OUT config SND_SOC_IMG_PARALLEL_OUT tristate "Imagination Parallel Output Device Driver" - depends on SND_SOC_IMG select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for parallel out driver for @@ -30,7 +24,6 @@ config SND_SOC_IMG_PARALLEL_OUT config SND_SOC_IMG_SPDIF_IN tristate "Imagination SPDIF Input Device Driver" - depends on SND_SOC_IMG select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for SPDIF input driver for @@ -38,7 +31,6 @@ config SND_SOC_IMG_SPDIF_IN config SND_SOC_IMG_SPDIF_OUT tristate "Imagination SPDIF Output Device Driver" - depends on SND_SOC_IMG select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for SPDIF out driver for @@ -47,7 +39,8 @@ config SND_SOC_IMG_SPDIF_OUT config SND_SOC_IMG_PISTACHIO_INTERNAL_DAC tristate "Support for Pistachio SoC Internal DAC Driver" - depends on SND_SOC_IMG help Say Y or M if you want to add support for Pistachio internal DAC driver for Imagination Technologies Pistachio internal DAC device. + +endmenu From 01f7d179a7348c252c5f26e1521bc1df81fadcd2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:42:28 +0000 Subject: [PATCH 125/385] ASoC: mxs: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87tt4lzqez.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/mxs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/mxs/Kconfig b/sound/soc/mxs/Kconfig index 402ef1ee7a32..2fb1ca711f71 100644 --- a/sound/soc/mxs/Kconfig +++ b/sound/soc/mxs/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only menuconfig SND_MXS_SOC - tristate "SoC Audio for Freescale MXS CPUs" + tristate "Freescale MXS" depends on ARCH_MXS || COMPILE_TEST depends on COMMON_CLK select SND_SOC_GENERIC_DMAENGINE_PCM From bcd02da3721967c006c90b1b58536d34765283a5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:42:33 +0000 Subject: [PATCH 126/385] ASoC: pxa: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87sek5zqeu.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/pxa/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index e05d6ce4c8fa..e026f9912a6d 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "PXA" + config SND_PXA2XX_SOC tristate "SoC Audio for the Intel PXA2xx chip" depends on ARCH_PXA || COMPILE_TEST @@ -52,3 +54,5 @@ config SND_PXA910_SOC help Say Y if you want to add support for SoC audio on the Marvell PXA910 reference platform. + +endmenu From afd1bff53b48d1431fefe57887017207c3df6bf5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:42:38 +0000 Subject: [PATCH 127/385] ASoC: sti: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87qzzpzqep.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sti/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sti/Kconfig b/sound/soc/sti/Kconfig index f881da4b6aea..8e12356a4490 100644 --- a/sound/soc/sti/Kconfig +++ b/sound/soc/sti/Kconfig @@ -3,7 +3,7 @@ # STM SoC audio configuration # menuconfig SND_SOC_STI - tristate "SoC Audio support for STI System-On-Chip" + tristate "STI" depends on SND_SOC depends on ARCH_STI || COMPILE_TEST select SND_SOC_GENERIC_DMAENGINE_PCM From 53696514d72fab66025afca531a1668bee635abf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:42:43 +0000 Subject: [PATCH 128/385] ASoC: stm: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87plf9zqek.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/stm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index da1f7a16605b..2753d6c2a826 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -menu "STMicroelectronics STM32 SOC audio support" +menu "STMicroelectronics STM32" config SND_SOC_STM32_SAI tristate "STM32 SAI interface (Serial Audio Interface) support" From 3b2a8a3c5769e2e02bf6f2cd7444847056087984 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:42:49 +0000 Subject: [PATCH 129/385] ASoC: sof: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87o6utzqef.wl-kuninori.morimoto.gx@renesas.com Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/Kconfig | 4 +++- sound/soc/sof/Kconfig | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 1b983c7006f1..ce74818bd715 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -127,7 +127,6 @@ source "sound/soc/renesas/Kconfig" source "sound/soc/rockchip/Kconfig" source "sound/soc/samsung/Kconfig" source "sound/soc/sdca/Kconfig" -source "sound/soc/sof/Kconfig" source "sound/soc/spear/Kconfig" source "sound/soc/sprd/Kconfig" source "sound/soc/starfive/Kconfig" @@ -141,6 +140,9 @@ source "sound/soc/ux500/Kconfig" source "sound/soc/xilinx/Kconfig" source "sound/soc/xtensa/Kconfig" +# SOF +source "sound/soc/sof/Kconfig" + # Supported codecs source "sound/soc/codecs/Kconfig" diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 32ffd345e07f..a487ab0b51c7 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only menuconfig SND_SOC_SOF_TOPLEVEL - bool "Sound Open Firmware Support" + bool "Sound Open Firmware (SOF) platforms" help This adds support for Sound Open Firmware (SOF). SOF is free and generic open source audio DSP firmware for multiple devices. From 335c898312f3b2366123c10b7bca56ca8cea1781 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:42:53 +0000 Subject: [PATCH 130/385] ASoC: au1x: Standardize ASoC menu use "ASoC support for xxxx" menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87msadzqea.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/au1x/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/au1x/Kconfig b/sound/soc/au1x/Kconfig index 8a78809e8754..a7630897bc0b 100644 --- a/sound/soc/au1x/Kconfig +++ b/sound/soc/au1x/Kconfig @@ -2,6 +2,8 @@ ## ## Au1200/Au1550/Au1300 PSC + DBDMA ## +menu "Au1x" + config SND_SOC_AU1XPSC tristate "SoC Audio for Au12xx/Au13xx/Au1550" depends on MIPS_ALCHEMY @@ -63,3 +65,5 @@ config SND_SOC_DB1200 Select this option to enable audio (AC97 and I2S) on the Alchemy/AMD/RMI/NetLogic Db1200, Db1550 and Db1300 evaluation boards. If you need Db1300 touchscreen support, you definitely want to say Y. + +endmenu From 36e6420440db119943b28b84523b8e0e77cae08b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:42:58 +0000 Subject: [PATCH 131/385] ASoC: sdca: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87ldpxzqe5.wl-kuninori.morimoto.gx@renesas.com Reviewed-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/sdca/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sdca/Kconfig b/sound/soc/sdca/Kconfig index ee20b9914aa1..71d2a52b2b50 100644 --- a/sound/soc/sdca/Kconfig +++ b/sound/soc/sdca/Kconfig @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "SoundWire (SDCA)" config SND_SOC_SDCA tristate @@ -9,3 +10,5 @@ config SND_SOC_SDCA config SND_SOC_SDCA_OPTIONAL def_tristate SND_SOC_SDCA || !SND_SOC_SDCA + +endmenu From 1d9ac30a8df639169ab97576cb5b1d48bb403e8b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:43:02 +0000 Subject: [PATCH 132/385] ASoC: sprd: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87jz5hzqe1.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sprd/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sprd/Kconfig b/sound/soc/sprd/Kconfig index 5e0ac8278572..8ddfe55aa21f 100644 --- a/sound/soc/sprd/Kconfig +++ b/sound/soc/sprd/Kconfig @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "Spreadtrum" + config SND_SOC_SPRD tristate "SoC Audio for the Spreadtrum SoC chips" depends on ARCH_SPRD || COMPILE_TEST @@ -14,3 +16,5 @@ config SND_SOC_SPRD_MCDT Say y here to enable multi-channel data transfer support. It is used for sound stream transmission between audio subsystem and other AP/CP subsystem. + +endmenu From 8ada023e996ca7131d9a42b2dd915e1966870d4a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:43:07 +0000 Subject: [PATCH 133/385] ASoC: qcom: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87ikl1zqdx.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/qcom/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index e86b4a03dd61..dfbdab9eb3a3 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only menuconfig SND_SOC_QCOM - tristate "ASoC support for QCOM platforms" + tristate "Qualcomm" depends on ARCH_QCOM || COMPILE_TEST help Say Y or M if you want to add support to use audio devices From 58e490935f20e38a4de156f705e89f7f13838aad Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:43:11 +0000 Subject: [PATCH 134/385] ASoC: meson: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87h60lzqds.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/meson/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig index 6458d5dc4902..d9a730994a2a 100644 --- a/sound/soc/meson/Kconfig +++ b/sound/soc/meson/Kconfig @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -menu "ASoC support for Amlogic platforms" +menu "Amlogic" depends on ARCH_MESON || (COMPILE_TEST && COMMON_CLK) config SND_MESON_AIU From 68a8fd461a564f8b5957944f4b056f44de5dfabc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:43:16 +0000 Subject: [PATCH 135/385] ASoC: apple: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87frg5zqdo.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/apple/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/apple/Kconfig b/sound/soc/apple/Kconfig index e9c777cdb6e3..d8dc2f1ccc83 100644 --- a/sound/soc/apple/Kconfig +++ b/sound/soc/apple/Kconfig @@ -1,3 +1,5 @@ +menu "Apple" + config SND_SOC_APPLE_MCA tristate "Apple Silicon MCA driver" depends on ARCH_APPLE || COMPILE_TEST @@ -5,3 +7,5 @@ config SND_SOC_APPLE_MCA help This option enables an ASoC platform driver for MCA peripherals found on Apple Silicon SoCs. + +endmenu From 4f30f84feb7757f09aeecba120a05e1145b8f264 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:43:21 +0000 Subject: [PATCH 136/385] ASoC: atmel: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87ecvpzqdi.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/atmel/Kconfig | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 5d59e00be823..4f51612f3dd2 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -1,13 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -config SND_ATMEL_SOC - tristate "SoC Audio for the Atmel System-on-Chip" +menu "Atmel" depends on HAS_IOMEM - help - Say Y or M if you want to add support for codecs attached to - the ATMEL SSC interface. You will also need - to select the audio interfaces to support below. - -if SND_ATMEL_SOC config SND_ATMEL_SOC_PDC bool @@ -176,4 +169,4 @@ config SND_MCHP_SOC_PDMC 2 data lines. The signal path includes an audio grade programmable decimation filter and outputs 24-bit audio words. -endif +endmenu From c153c508e5b41405db3ac9ce32169af6961aa878 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:43:26 +0000 Subject: [PATCH 137/385] ASoC: intel: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87cyb9zqde.wl-kuninori.morimoto.gx@renesas.com Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 2db494b0e3cf..412555e626b8 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "Intel" + config SND_SOC_INTEL_SST_TOPLEVEL bool "Intel ASoC SST drivers" default y @@ -115,3 +117,5 @@ source "sound/soc/intel/avs/boards/Kconfig" # ASoC codec drivers source "sound/soc/intel/boards/Kconfig" + +endmenu From 7798775a033e7d19270e20bcd105c29e373b8bad Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:43:30 +0000 Subject: [PATCH 138/385] ASoC: spear: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87bjqtzqd9.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/spear/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/spear/Kconfig b/sound/soc/spear/Kconfig index 1b053de1ae7c..84a52fd4c3ea 100644 --- a/sound/soc/spear/Kconfig +++ b/sound/soc/spear/Kconfig @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "ST SPEAr" + config SND_SPEAR_SOC tristate select SND_SOC_GENERIC_DMAENGINE_PCM @@ -8,3 +10,5 @@ config SND_SPEAR_SPDIF_OUT config SND_SPEAR_SPDIF_IN tristate + +endmenu From c0262c187a0b8473169156f4cf3aad0f41b08d00 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:43:35 +0000 Subject: [PATCH 139/385] ASoC: sunxi: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Acked-by: Chen-Yu Tsai Link: https://patch.msgid.link/87a56dzqd4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sunxi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index 1f18f016acbb..205f422d9ded 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -menu "Allwinner SoC Audio support" +menu "Allwinner" depends on ARCH_SUNXI || COMPILE_TEST config SND_SUN4I_CODEC From 41b94a6f2debeb0483d8cda0558df860c0a26969 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:43:40 +0000 Subject: [PATCH 140/385] ASoC: tegra: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Reviewed-by: Jon Hunter Link: https://patch.msgid.link/878qlxzqd0.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/tegra/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 2463c22e9cf6..71203a9197ed 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "Tegra" + config SND_SOC_TEGRA tristate "SoC Audio for the Tegra System-on-Chip" depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST @@ -293,3 +295,5 @@ config SND_SOC_TEGRA_SGTL5000 Colibri T30. endif + +endmenu From 5b8b93e695bb8b5aa0d6432f397e8126faf56f5f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:43:45 +0000 Subject: [PATCH 141/385] ASoC: ux500: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/877c1hzqcv.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/ux500/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/ux500/Kconfig b/sound/soc/ux500/Kconfig index 34b2438b52d3..113058060350 100644 --- a/sound/soc/ux500/Kconfig +++ b/sound/soc/ux500/Kconfig @@ -3,7 +3,7 @@ # Ux500 SoC audio configuration # menuconfig SND_SOC_UX500 - tristate "SoC Audio support for Ux500 platform" + tristate "Ux500" depends on SND_SOC depends on MFD_DB8500_PRCMU help From 8a40e95a1328b8045094b1037c457358c56700cb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:43:51 +0000 Subject: [PATCH 142/385] ASoC: cirrus: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Reviewed-by: Alexander Sverdlin Link: https://patch.msgid.link/875xh1zqcp.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/cirrus/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig index 97def4e53fbc..31475e64e7dd 100644 --- a/sound/soc/cirrus/Kconfig +++ b/sound/soc/cirrus/Kconfig @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "Cirrus Logic" + config SND_EP93XX_SOC tristate "SoC Audio support for the Cirrus Logic EP93xx series" depends on ARCH_EP93XX || COMPILE_TEST @@ -31,3 +33,4 @@ config SND_EP93XX_SOC_I2S_WATCHDOG endif # if SND_EP93XX_SOC_I2S +endmenu From c6ddacab374702ed187359f103a95ad187d16d94 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:43:55 +0000 Subject: [PATCH 143/385] ASoC: google: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/874iwlzqck.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/google/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/google/Kconfig b/sound/soc/google/Kconfig index 7603782fb060..6005653170a8 100644 --- a/sound/soc/google/Kconfig +++ b/sound/soc/google/Kconfig @@ -1,6 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "Google" config SND_SOC_CHV3_I2S tristate "Google Chameleon v3 I2S device" help Enable support for the Google Chameleon v3 I2S device. + +endmenu From 099ae845c6b23ea2865a3912be3f51408f62f334 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:44:00 +0000 Subject: [PATCH 144/385] ASoC: jz4740: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/8734c5zqcg.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/jz4740/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/jz4740/Kconfig b/sound/soc/jz4740/Kconfig index dd3b4507fbe6..f3ff3fb49239 100644 --- a/sound/soc/jz4740/Kconfig +++ b/sound/soc/jz4740/Kconfig @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "JZ4740" + config SND_JZ4740_SOC_I2S tristate "SoC Audio (I2S protocol) for Ingenic JZ4740 SoC" depends on MIPS || COMPILE_TEST @@ -8,3 +10,5 @@ config SND_JZ4740_SOC_I2S help Say Y if you want to use I2S protocol and I2S codec on Ingenic JZ4740 based boards. + +endmenu From 69fa5909b3dc8b7968192d110e0d7ec8ef8dfd45 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:44:05 +0000 Subject: [PATCH 145/385] ASoC: xilinx: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/871prpzqca.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/xilinx/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/xilinx/Kconfig b/sound/soc/xilinx/Kconfig index 5bd2730aab76..670e0f301097 100644 --- a/sound/soc/xilinx/Kconfig +++ b/sound/soc/xilinx/Kconfig @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "Xilinx" + config SND_SOC_XILINX_I2S tristate "Audio support for the Xilinx I2S" help @@ -21,3 +23,5 @@ config SND_SOC_XILINX_SPDIF Select this option to enable Xilinx SPDIF Audio. This provides playback and capture of SPDIF audio in AES format. + +endmenu From 41d88bb7546e445806febf45c971b854ba4bc3d7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:44:10 +0000 Subject: [PATCH 146/385] ASoC: xtensa: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87zfedybrp.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/xtensa/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/xtensa/Kconfig b/sound/soc/xtensa/Kconfig index 74b778f186ce..87457272c773 100644 --- a/sound/soc/xtensa/Kconfig +++ b/sound/soc/xtensa/Kconfig @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "Xtensa" + config SND_SOC_XTFPGA_I2S tristate "XTFPGA I2S master" select REGMAP_MMIO @@ -6,3 +8,5 @@ config SND_SOC_XTFPGA_I2S Say Y or M if you want to add support for codecs attached to the I2S interface on XTFPGA daughter board. You will also need to select the drivers for the rest of XTFPGA audio subsystem. + +endmenu From a549459a05c0a46aaf6fdf0d21a42ff09cbac91a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:44:15 +0000 Subject: [PATCH 147/385] ASoC: renesas: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87y0txybrk.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/renesas/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/renesas/Kconfig b/sound/soc/renesas/Kconfig index dabf02a955ca..11c2027c88a7 100644 --- a/sound/soc/renesas/Kconfig +++ b/sound/soc/renesas/Kconfig @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -menu "SoC Audio support for Renesas SoCs" +menu "Renesas" depends on SUPERH || ARCH_RENESAS || COMPILE_TEST config SND_SOC_PCM_SH7760 From acc84d15e45393fbbe87758c5fed25d01c83ef92 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:44:20 +0000 Subject: [PATCH 148/385] ASoC: generic: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87wm9hybrf.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/Kconfig | 4 +--- sound/soc/generic/Kconfig | 4 ++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index ce74818bd715..bf362bfca456 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -111,6 +111,7 @@ source "sound/soc/bcm/Kconfig" source "sound/soc/cirrus/Kconfig" source "sound/soc/dwc/Kconfig" source "sound/soc/fsl/Kconfig" +source "sound/soc/generic/Kconfig" source "sound/soc/google/Kconfig" source "sound/soc/hisilicon/Kconfig" source "sound/soc/jz4740/Kconfig" @@ -148,8 +149,5 @@ source "sound/soc/codecs/Kconfig" source "sound/soc/sdw_utils/Kconfig" -# generic frame-work -source "sound/soc/generic/Kconfig" - endif # SND_SOC diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig index b6df4e26bc4a..64b0817e2955 100644 --- a/sound/soc/generic/Kconfig +++ b/sound/soc/generic/Kconfig @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "Generic drivers" + config SND_SIMPLE_CARD_UTILS tristate @@ -37,3 +39,5 @@ config SND_TEST_COMPONENT depends on OF help This option enables test component sound driver support. + +endmenu From 0fa7adb638f6c4e8e458056adbcfc028a8085cf8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:44:25 +0000 Subject: [PATCH 149/385] ASoC: samsung: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87v7p1ybrb.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/samsung/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 60b4b7b75215..ec7204f57fd4 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only menuconfig SND_SOC_SAMSUNG - tristate "ASoC support for Samsung" + tristate "Samsung" depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST depends on COMMON_CLK select SND_SOC_GENERIC_DMAENGINE_PCM From 9fad9eb0371b11af1cea3e32cb423913cd10582a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:44:29 +0000 Subject: [PATCH 150/385] ASoC: kirkwood: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87tt4lybr6.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/kirkwood/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig index 5d8a86b26fa2..924072e402c8 100644 --- a/sound/soc/kirkwood/Kconfig +++ b/sound/soc/kirkwood/Kconfig @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "Kirkwood" + config SND_KIRKWOOD_SOC tristate "SoC Audio for the Marvell Kirkwood and Dove chips" depends on ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST @@ -16,3 +18,4 @@ config SND_KIRKWOOD_SOC_ARMADA370_DB Say Y if you want to add support for SoC audio on the Armada 370 Development Board. +endmenu From 9c0169922db5cec50a9f470df098dd835477c388 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:44:35 +0000 Subject: [PATCH 151/385] ASoC: loongson: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87sek5ybr0.wl-kuninori.morimoto.gx@renesas.com Reviewed-by: Binbin Zhou Signed-off-by: Mark Brown --- sound/soc/loongson/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/loongson/Kconfig b/sound/soc/loongson/Kconfig index 1a3c28816e7a..2e06670e4d7e 100644 --- a/sound/soc/loongson/Kconfig +++ b/sound/soc/loongson/Kconfig @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -menu "SoC Audio for Loongson CPUs" +menu "Loongson" config SND_SOC_LOONGSON_CARD tristate "Loongson Sound Card Driver" From 05016f7e481e3d8d9ea539c05a0e8aba2c4f22ee Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:44:41 +0000 Subject: [PATCH 152/385] ASoC: mediatek: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Reviewed-by: Matthias Brugger Link: https://patch.msgid.link/87qzzpybqu.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 90e367586493..10ca8bccabdd 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "Mediatek" + config SND_SOC_MEDIATEK tristate select REGMAP_MMIO @@ -319,3 +321,5 @@ config SND_SOC_MT8365_MT6357 boards with the MT6357 PMIC codec. Select Y if you have such device. If unsure select "N". + +endmenu From cae3cc435db56f2896be1d114952b4da0ac2eda8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:44:46 +0000 Subject: [PATCH 153/385] ASoC: rockchip: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87plf9ybqp.wl-kuninori.morimoto.gx@renesas.com Reviewed-by: Heiko Stuebner Signed-off-by: Mark Brown --- sound/soc/rockchip/Kconfig | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig index a08544827b2a..bd210fafe9fe 100644 --- a/sound/soc/rockchip/Kconfig +++ b/sound/soc/rockchip/Kconfig @@ -1,15 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only -config SND_SOC_ROCKCHIP - tristate "ASoC support for Rockchip" +menu "Rockchip" depends on COMPILE_TEST || ARCH_ROCKCHIP - help - Say Y or M if you want to add support for codecs attached to - the Rockchip SoCs' Audio interfaces. You will also need to - select the audio interfaces to support below. + depends on HAVE_CLK config SND_SOC_ROCKCHIP_I2S tristate "Rockchip I2S Device Driver" - depends on HAVE_CLK && SND_SOC_ROCKCHIP select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for I2S driver for @@ -18,7 +13,6 @@ config SND_SOC_ROCKCHIP_I2S config SND_SOC_ROCKCHIP_I2S_TDM tristate "Rockchip I2S/TDM Device Driver" - depends on HAVE_CLK && SND_SOC_ROCKCHIP select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for the I2S/TDM driver for @@ -29,7 +23,6 @@ config SND_SOC_ROCKCHIP_I2S_TDM config SND_SOC_ROCKCHIP_PDM tristate "Rockchip PDM Controller Driver" - depends on HAVE_CLK && SND_SOC_ROCKCHIP select SND_SOC_GENERIC_DMAENGINE_PCM select RATIONAL help @@ -39,7 +32,6 @@ config SND_SOC_ROCKCHIP_PDM config SND_SOC_ROCKCHIP_SAI tristate "Rockchip SAI Controller Driver" - depends on HAVE_CLK && SND_SOC_ROCKCHIP select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for the Rockchip Serial Audio @@ -49,7 +41,6 @@ config SND_SOC_ROCKCHIP_SAI config SND_SOC_ROCKCHIP_SPDIF tristate "Rockchip SPDIF Device Driver" - depends on HAVE_CLK && SND_SOC_ROCKCHIP select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for SPDIF driver for @@ -57,7 +48,7 @@ config SND_SOC_ROCKCHIP_SPDIF config SND_SOC_ROCKCHIP_MAX98090 tristate "ASoC support for Rockchip boards using a MAX98090 codec" - depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && HAVE_CLK + depends on I2C && GPIOLIB select SND_SOC_ROCKCHIP_I2S select SND_SOC_MAX98090 select SND_SOC_TS3A227E @@ -68,7 +59,7 @@ config SND_SOC_ROCKCHIP_MAX98090 config SND_SOC_ROCKCHIP_RT5645 tristate "ASoC support for Rockchip boards using a RT5645/RT5650 codec" - depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && HAVE_CLK + depends on I2C && GPIOLIB select SND_SOC_ROCKCHIP_I2S select SND_SOC_RT5645 help @@ -77,7 +68,7 @@ config SND_SOC_ROCKCHIP_RT5645 config SND_SOC_RK3288_HDMI_ANALOG tristate "ASoC support multiple codecs for Rockchip RK3288 boards" - depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && HAVE_CLK + depends on I2C && GPIOLIB select SND_SOC_ROCKCHIP_I2S select SND_SOC_HDMI_CODEC select SND_SOC_ES8328_I2C @@ -89,7 +80,7 @@ config SND_SOC_RK3288_HDMI_ANALOG config SND_SOC_RK3399_GRU_SOUND tristate "ASoC support multiple codecs for Rockchip RK3399 GRU boards" - depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && HAVE_CLK && SPI + depends on I2C && GPIOLIB && SPI select SND_SOC_ROCKCHIP_I2S select SND_SOC_MAX98357A select SND_SOC_RT5514 @@ -100,3 +91,5 @@ config SND_SOC_RK3399_GRU_SOUND help Say Y or M here if you want to add support multiple codecs for SoC audio on Rockchip RK3399 GRU boards. + +endmenu From acc317e5254a739eedf60b53aaf31f69f55e3dc8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:44:51 +0000 Subject: [PATCH 154/385] ASoC: starfive: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87o6utybqk.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/starfive/Kconfig | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/soc/starfive/Kconfig b/sound/soc/starfive/Kconfig index 279ac5c1d309..1e11aa74594d 100644 --- a/sound/soc/starfive/Kconfig +++ b/sound/soc/starfive/Kconfig @@ -1,15 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only -config SND_SOC_STARFIVE - tristate "Audio support for StarFive SoC" +menu "StarFive" depends on COMPILE_TEST || ARCH_STARFIVE - help - Say Y or M if you want to add support for codecs attached to - the Starfive SoCs' Audio interfaces. You will also need to - select the audio interfaces to support below. + depends on HAVE_CLK config SND_SOC_JH7110_PWMDAC tristate "JH7110 PWM-DAC device driver" - depends on HAVE_CLK && SND_SOC_STARFIVE select SND_SOC_GENERIC_DMAENGINE_PCM select SND_SOC_SPDIF help @@ -18,7 +13,8 @@ config SND_SOC_JH7110_PWMDAC config SND_SOC_JH7110_TDM tristate "JH7110 TDM device driver" - depends on HAVE_CLK && SND_SOC_STARFIVE select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for StarFive TDM driver. + +endmenu From ac131c4148bcfa682104628d2174e8e38e03fd25 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:44:57 +0000 Subject: [PATCH 155/385] ASoC: uniphier: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Reviewed-by: Masami Hiramatsu (Google) Link: https://patch.msgid.link/87msadybqf.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/uniphier/Kconfig | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/sound/soc/uniphier/Kconfig b/sound/soc/uniphier/Kconfig index ddfa6424c656..7c978639e0aa 100644 --- a/sound/soc/uniphier/Kconfig +++ b/sound/soc/uniphier/Kconfig @@ -1,18 +1,11 @@ # SPDX-License-Identifier: GPL-2.0 -config SND_SOC_UNIPHIER - tristate "ASoC support for UniPhier" +menu "UniPhier" depends on (ARCH_UNIPHIER || COMPILE_TEST) - help - Say Y or M if you want to add support for the Socionext - UniPhier SoC audio interfaces. You will also need to select the - audio interfaces to support below. - If unsure select "N". config SND_SOC_UNIPHIER_AIO tristate "UniPhier AIO DAI Driver" select REGMAP_MMIO select SND_SOC_COMPRESS - depends on SND_SOC_UNIPHIER help This adds ASoC driver support for Socionext UniPhier 'AIO' Audio Input/Output subsystem. @@ -21,7 +14,6 @@ config SND_SOC_UNIPHIER_AIO config SND_SOC_UNIPHIER_LD11 tristate "UniPhier LD11/LD20 Device Driver" - depends on SND_SOC_UNIPHIER select SND_SOC_UNIPHIER_AIO help This adds ASoC driver for Socionext UniPhier LD11/LD20 @@ -31,7 +23,6 @@ config SND_SOC_UNIPHIER_LD11 config SND_SOC_UNIPHIER_PXS2 tristate "UniPhier PXs2 Device Driver" - depends on SND_SOC_UNIPHIER select SND_SOC_UNIPHIER_AIO help This adds ASoC driver for Socionext UniPhier PXs2 @@ -41,10 +32,11 @@ config SND_SOC_UNIPHIER_PXS2 config SND_SOC_UNIPHIER_EVEA_CODEC tristate "UniPhier SoC internal audio codec" - depends on SND_SOC_UNIPHIER select REGMAP_MMIO help This adds Codec driver for Socionext UniPhier LD11/20 SoC internal DAC. This driver supports Line In / Out and HeadPhone. Select Y if you use such device. If unsure select "N". + +endmenu From 68fbc70ece40139380380dce74059afa592846b3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Jun 2025 01:45:03 +0000 Subject: [PATCH 156/385] ASoC: hisilicon: Standardize ASoC menu Current Kconfig menu at [ALSA for SoC audio support] has no rules. So, some venders are using menu style, some venders are listed each drivers on top page, etc. It is difficult to find target vender and/or drivers because it is very random. Let's standardize ASoC menu Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87ldpxybq9.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/hisilicon/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/hisilicon/Kconfig b/sound/soc/hisilicon/Kconfig index df8fbd8bb4b0..d95da932f352 100644 --- a/sound/soc/hisilicon/Kconfig +++ b/sound/soc/hisilicon/Kconfig @@ -1,6 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "Hisilicon" + config SND_I2S_HI6210_I2S tristate "Hisilicon I2S controller" select SND_SOC_GENERIC_DMAENGINE_PCM help Hisilicon I2S + +endmenu From f792733e08d5f5d44ef76d22bcca7ca45a82d0de Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 25 Jun 2025 22:04:28 +0800 Subject: [PATCH 157/385] ASoC: sdw_utils: add component_name string to dai_info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the sdw machine driver uses different way to get the component name from the DAI name for different codecs in the rtd_init callback. It means that we need to rely on the rtd_init callback to get the component name. Add an optional component string to the asoc_sdw_dai_info struct allows the machine driver to get the component name directly. The commit adds the component names for the AMP dais for the preparation to set card->components string for combined speaker configs. Signed-off-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Shuming Fan Link: https://patch.msgid.link/20250625140430.311865-2-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- include/sound/soc_sdw_utils.h | 1 + sound/soc/sdw_utils/soc_sdw_utils.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h index b63021f5afaf..6049a5d0cfcd 100644 --- a/include/sound/soc_sdw_utils.h +++ b/include/sound/soc_sdw_utils.h @@ -46,6 +46,7 @@ struct asoc_sdw_codec_info; struct asoc_sdw_dai_info { const bool direction[2]; /* playback & capture support */ const char *dai_name; + const char *component_name; const int dai_type; const int dailink[2]; /* dailink id for each direction */ const struct snd_kcontrol_new *controls; diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index d75e7292240b..2e8820137c69 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -135,6 +135,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { { .direction = {true, false}, .dai_name = "rt712-sdca-aif2", + .component_name = "rt712", .dai_type = SOC_SDW_DAI_TYPE_AMP, .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, .init = asoc_sdw_rt_amp_init, @@ -275,6 +276,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { { .direction = {true, false}, .dai_name = "rt1320-aif1", + .component_name = "rt1320", .dai_type = SOC_SDW_DAI_TYPE_AMP, .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, .init = asoc_sdw_rt_amp_init, @@ -409,6 +411,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { { .direction = {true, false}, .dai_name = "rt722-sdca-aif2", + .component_name = "rt722", .dai_type = SOC_SDW_DAI_TYPE_AMP, /* No feedback capability is provided by rt722-sdca codec driver*/ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, @@ -438,6 +441,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { { .direction = {true, true}, .dai_name = "max98373-aif1", + .component_name = "mx8373", .dai_type = SOC_SDW_DAI_TYPE_AMP, .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, .init = asoc_sdw_maxim_init, @@ -456,6 +460,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { { .direction = {true, false}, .dai_name = "max98363-aif1", + .component_name = "mx8363", .dai_type = SOC_SDW_DAI_TYPE_AMP, .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, .init = asoc_sdw_maxim_init, @@ -491,6 +496,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { { .direction = {true, false}, .dai_name = "cs35l56-sdw1", + .component_name = "cs35l56", .dai_type = SOC_SDW_DAI_TYPE_AMP, .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, .init = asoc_sdw_cs_amp_init, @@ -516,6 +522,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { { .direction = {true, false}, .dai_name = "cs35l56-sdw1", + .component_name = "cs35l56", .dai_type = SOC_SDW_DAI_TYPE_AMP, .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, .init = asoc_sdw_cs_amp_init, From 0f60ecffbfe35e12eb56c99640ba2360244b5bb3 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 25 Jun 2025 22:04:29 +0800 Subject: [PATCH 158/385] ASoC: sdw_utils: generate combined spk components string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The suggestion from UCM for 2 speaker components is using 1 "spk" tag with 2 component names. Like "spk:rt722+rt1320". The commit removes the creation of the "spk" components in each rtd_init callback and creat the string in asoc_sdw_rtd_init(). Signed-off-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Shuming Fan Link: https://patch.msgid.link/20250625140430.311865-3-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sdw_utils/soc_sdw_cs_amp.c | 10 --------- sound/soc/sdw_utils/soc_sdw_maxim.c | 9 -------- sound/soc/sdw_utils/soc_sdw_rt_amp.c | 6 ------ sound/soc/sdw_utils/soc_sdw_rt_mf_sdca.c | 7 ------- sound/soc/sdw_utils/soc_sdw_utils.c | 26 ++++++++++++++++++++++++ 5 files changed, 26 insertions(+), 32 deletions(-) diff --git a/sound/soc/sdw_utils/soc_sdw_cs_amp.c b/sound/soc/sdw_utils/soc_sdw_cs_amp.c index 35b550bcd4de..520ea36c63ee 100644 --- a/sound/soc/sdw_utils/soc_sdw_cs_amp.c +++ b/sound/soc/sdw_utils/soc_sdw_cs_amp.c @@ -14,7 +14,6 @@ #include #include -#define CODEC_NAME_SIZE 8 #define CS_AMP_CHANNELS_PER_AMP 4 #define CS35L56_SPK_VOLUME_0DB 400 /* 0dB Max */ @@ -38,21 +37,12 @@ EXPORT_SYMBOL_NS(asoc_sdw_cs35l56_volume_limit, "SND_SOC_SDW_UTILS"); int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { - const char *dai_name = rtd->dai_link->codecs->dai_name; struct snd_soc_card *card = rtd->card; - char codec_name[CODEC_NAME_SIZE]; char widget_name[16]; struct snd_soc_dapm_route route = { "Speaker", NULL, widget_name }; struct snd_soc_dai *codec_dai; int i, ret; - snprintf(codec_name, CODEC_NAME_SIZE, "%s", dai_name); - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s spk:%s", - card->components, codec_name); - if (!card->components) - return -ENOMEM; - for_each_rtd_codec_dais(rtd, i, codec_dai) { if (!strstr(codec_dai->name, "cs35l56")) continue; diff --git a/sound/soc/sdw_utils/soc_sdw_maxim.c b/sound/soc/sdw_utils/soc_sdw_maxim.c index 5df8d9cae60c..8f9d1ed0725b 100644 --- a/sound/soc/sdw_utils/soc_sdw_maxim.c +++ b/sound/soc/sdw_utils/soc_sdw_maxim.c @@ -28,15 +28,6 @@ int asoc_sdw_maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_ struct snd_soc_card *card = rtd->card; int ret; - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s spk:mx%04x", - card->components, maxim_part_id); - if (!card->components) - return -ENOMEM; - - dev_dbg(card->dev, "soundwire maxim card components assigned : %s\n", - card->components); - ret = snd_soc_dapm_add_routes(&card->dapm, max_98373_dapm_routes, 2); if (ret) dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret); diff --git a/sound/soc/sdw_utils/soc_sdw_rt_amp.c b/sound/soc/sdw_utils/soc_sdw_rt_amp.c index 83c2368170cb..76ee24b8eee4 100644 --- a/sound/soc/sdw_utils/soc_sdw_rt_amp.c +++ b/sound/soc/sdw_utils/soc_sdw_rt_amp.c @@ -195,12 +195,6 @@ int asoc_sdw_rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc rt_amp_map = get_codec_name_and_route(dai, codec_name); - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s spk:%s", - card->components, codec_name); - if (!card->components) - return -ENOMEM; - for_each_rtd_codec_dais(rtd, i, codec_dai) { if (strstr(codec_dai->component->name_prefix, "-1")) ret = snd_soc_dapm_add_routes(&card->dapm, rt_amp_map, 2); diff --git a/sound/soc/sdw_utils/soc_sdw_rt_mf_sdca.c b/sound/soc/sdw_utils/soc_sdw_rt_mf_sdca.c index 0161b14297d5..224b58de9084 100644 --- a/sound/soc/sdw_utils/soc_sdw_rt_mf_sdca.c +++ b/sound/soc/sdw_utils/soc_sdw_rt_mf_sdca.c @@ -73,13 +73,6 @@ int asoc_sdw_rt_mf_sdca_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd return -EINVAL; } - /* Update card components */ - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s spk:%s", - card->components, codec_name); - if (!card->components) - return -ENOMEM; - /* Add routes */ ret = snd_soc_dapm_add_routes(&card->dapm, route_map->route_map, route_map->route_size); if (ret) diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index 2e8820137c69..a744ca019378 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -740,6 +740,7 @@ int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_card *card = rtd->card; struct asoc_sdw_codec_info *codec_info; struct snd_soc_dai *dai; + const char *spk_components=""; int dai_index; int ret; int i; @@ -792,7 +793,32 @@ skip_add_controls_widgets: if (ret) return ret; } + + /* Generate the spk component string for card->components string */ + if (codec_info->dais[dai_index].dai_type == SOC_SDW_DAI_TYPE_AMP && + codec_info->dais[dai_index].component_name) { + if (strlen (spk_components) == 0) + spk_components = + devm_kasprintf(card->dev, GFP_KERNEL, "%s", + codec_info->dais[dai_index].component_name); + else + /* Append component name to spk_components */ + spk_components = + devm_kasprintf(card->dev, GFP_KERNEL, + "%s+%s", spk_components, + codec_info->dais[dai_index].component_name); + } + codec_info->dais[dai_index].rtd_init_done = true; + + } + + if (strlen (spk_components) > 0) { + /* Update card components for speaker components */ + card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s spk:%s", + card->components, spk_components); + if (!card->components) + return -ENOMEM; } return 0; From 29ddce17e909779633f856ad1c2f111fbf71c0df Mon Sep 17 00:00:00 2001 From: Weidong Wang Date: Fri, 27 Jun 2025 19:03:06 +0800 Subject: [PATCH 159/385] ASoC: codecs: Add calibration function to aw88399 chip Add calibration functionality to the aw88399 chip. When the chip is in calibration condition, calibration can be achieved by configuring the chip's internal DSP and save the calibration values in cali_re. Signed-off-by: Weidong Wang Link: https://patch.msgid.link/20250627110306.23488-1-wangweidong.a@awinic.com Signed-off-by: Mark Brown --- sound/soc/codecs/aw88395/aw88395_device.h | 21 ++ sound/soc/codecs/aw88399.c | 440 +++++++++++++++++++++- sound/soc/codecs/aw88399.h | 34 ++ 3 files changed, 493 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/aw88395/aw88395_device.h b/sound/soc/codecs/aw88395/aw88395_device.h index 0f750f654f3e..6f8b30b475da 100644 --- a/sound/soc/codecs/aw88395/aw88395_device.h +++ b/sound/soc/codecs/aw88395/aw88395_device.h @@ -102,6 +102,11 @@ struct aw_profctrl_desc { unsigned int cur_mode; }; +enum { + CALI_RESULT_NORMAL, + CALI_RESULT_ERROR, +}; + struct aw_volume_desc { unsigned int init_volume; unsigned int mute_volume; @@ -124,9 +129,25 @@ struct aw_cali_delay_desc { unsigned int delay; }; +#define AW_CALI_CFG_NUM (4) +struct cali_cfg { + uint32_t data[AW_CALI_CFG_NUM]; +}; + +struct aw_cali_backup_desc { + unsigned int dsp_ng_cfg; + unsigned int dsp_lp_cfg; +}; + struct aw_cali_desc { u32 cali_re; u32 ra; + bool cali_switch; + bool cali_running; + uint16_t cali_result; + uint16_t store_vol; + struct cali_cfg cali_cfg; + struct aw_cali_backup_desc backup_info; }; struct aw_container { diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c index 4b90133e5ab4..bad3ad6b8c0e 100644 --- a/sound/soc/codecs/aw88399.c +++ b/sound/soc/codecs/aw88399.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "aw88399.h" #include "aw88395/aw88395_device.h" @@ -45,6 +46,67 @@ static int aw_dev_dsp_write_16bit(struct aw_device *aw_dev, return 0; } +static int aw_dev_dsp_write_32bit(struct aw_device *aw_dev, + unsigned short dsp_addr, unsigned int dsp_data) +{ + unsigned int temp_data; + int ret; + + ret = regmap_write(aw_dev->regmap, AW88399_DSPMADD_REG, dsp_addr); + if (ret) { + dev_err(aw_dev->dev, "%s write addr error, ret=%d", __func__, ret); + return ret; + } + + temp_data = dsp_data & AW88395_DSP_16_DATA_MASK; + ret = regmap_write(aw_dev->regmap, AW88399_DSPMDAT_REG, temp_data); + if (ret) { + dev_err(aw_dev->dev, "%s write datal error, ret=%d", __func__, ret); + return ret; + } + + temp_data = dsp_data >> 16; + ret = regmap_write(aw_dev->regmap, AW88399_DSPMDAT_REG, temp_data); + if (ret) + dev_err(aw_dev->dev, "%s write datah error, ret=%d", __func__, ret); + + return ret; +} + +static int aw_dev_dsp_write(struct aw_device *aw_dev, + unsigned short dsp_addr, unsigned int dsp_data, unsigned char data_type) +{ + unsigned int reg_value; + int ret; + + mutex_lock(&aw_dev->dsp_lock); + switch (data_type) { + case AW88395_DSP_16_DATA: + ret = aw_dev_dsp_write_16bit(aw_dev, dsp_addr, dsp_data); + if (ret) + dev_err(aw_dev->dev, "write dsp_addr[0x%x] 16-bit dsp_data[0x%x] failed", + dsp_addr, dsp_data); + break; + case AW88395_DSP_32_DATA: + ret = aw_dev_dsp_write_32bit(aw_dev, dsp_addr, dsp_data); + if (ret) + dev_err(aw_dev->dev, "write dsp_addr[0x%x] 32-bit dsp_data[0x%x] failed", + dsp_addr, dsp_data); + break; + default: + dev_err(aw_dev->dev, "data type[%d] unsupported", data_type); + ret = -EINVAL; + break; + } + + /* clear dsp chip select state */ + if (regmap_read(aw_dev->regmap, 0x00, ®_value)) + dev_err(aw_dev->dev, "%s fail to clear chip state. Err=%d\n", __func__, ret); + mutex_unlock(&aw_dev->dsp_lock); + + return ret; +} + static int aw_dev_dsp_read_16bit(struct aw_device *aw_dev, unsigned short dsp_addr, unsigned int *dsp_data) { @@ -452,14 +514,14 @@ static int aw_dev_set_vcalb(struct aw88399 *aw88399) case AW88399_DEV_VDSEL_VSENSE: ret = aw88399_dev_get_vcalk(aw88399, &vcalk); vcal_k = vcalk * AW88399_VCABLK_FACTOR + AW88399_CABL_BASE_VALUE; - vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_FACTOR / AW88399_ISCAL_FACTOR / + vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_FACTOR / AW88399_ISCAL_FACTOR * ical_k / vcal_k * aw88399->vcalb_init_val; break; case AW88399_DEV_VDSEL_DAC: ret = aw88399_dev_get_internal_vcalk(aw88399, &vcalk); vcal_k = vcalk * AW88399_VCABLK_DAC_FACTOR + AW88399_CABL_BASE_VALUE; vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_DAC_FACTOR / - AW88399_ISCAL_DAC_FACTOR / ical_k / + AW88399_ISCAL_DAC_FACTOR * ical_k / vcal_k * aw88399->vcalb_init_val; break; default: @@ -1356,6 +1418,329 @@ static struct snd_soc_dai_driver aw88399_dai[] = { }, }; +static void aw_cali_svc_run_mute(struct aw_device *aw_dev, uint16_t cali_result) +{ + if (cali_result == CALI_RESULT_ERROR) + aw88399_dev_mute(aw_dev, true); + else if (cali_result == CALI_RESULT_NORMAL) + aw88399_dev_mute(aw_dev, false); +} + +static int aw_cali_svc_get_cali_cfg(struct aw_device *aw_dev) +{ + struct cali_cfg *cali_cfg = &aw_dev->cali_desc.cali_cfg; + int ret; + + ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_MBMEC_ACTAMPTH, + &cali_cfg->data[0], AW88399_DSP_32_DATA); + if (ret) + return ret; + + ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_MBMEC_NOISEAMPTH, + &cali_cfg->data[1], AW88399_DSP_32_DATA); + if (ret) + return ret; + + ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_ADPZ_USTEPN, + &cali_cfg->data[2], AW88399_DSP_16_DATA); + if (ret) + return ret; + + ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_RE_ALPHA, + &cali_cfg->data[3], AW88399_DSP_16_DATA); + + return ret; +} + +static int aw_cali_svc_set_cali_cfg(struct aw_device *aw_dev, + struct cali_cfg cali_cfg) +{ + int ret; + + ret = aw_dev_dsp_write(aw_dev, AW88399_DSP_REG_CFG_MBMEC_ACTAMPTH, + cali_cfg.data[0], AW88399_DSP_32_DATA); + if (ret) + return ret; + + ret = aw_dev_dsp_write(aw_dev, AW88399_DSP_REG_CFG_MBMEC_NOISEAMPTH, + cali_cfg.data[1], AW88399_DSP_32_DATA); + if (ret) + return ret; + + ret = aw_dev_dsp_write(aw_dev, AW88399_DSP_REG_CFG_ADPZ_USTEPN, + cali_cfg.data[2], AW88399_DSP_16_DATA); + if (ret) + return ret; + + ret = aw_dev_dsp_write(aw_dev, AW88399_DSP_REG_CFG_RE_ALPHA, + cali_cfg.data[3], AW88399_DSP_16_DATA); + + return ret; +} + +static int aw_cali_svc_cali_en(struct aw_device *aw_dev, bool cali_en) +{ + struct cali_cfg set_cfg; + int ret; + + aw_dev_dsp_enable(aw_dev, false); + if (cali_en) { + regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, + ~AW883XX_DSP_NG_EN_MASK, AW883XX_DSP_NG_EN_DISABLE_VALUE); + aw_dev_dsp_write(aw_dev, AW88399_DSP_LOW_POWER_SWITCH_CFG_ADDR, + AW88399_DSP_LOW_POWER_SWITCH_DISABLE, AW88399_DSP_16_DATA); + + ret = aw_cali_svc_get_cali_cfg(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "get cali cfg failed\n"); + aw_dev_dsp_enable(aw_dev, true); + return ret; + } + set_cfg.data[0] = 0; + set_cfg.data[1] = 0; + set_cfg.data[2] = -1; + set_cfg.data[3] = 1; + + ret = aw_cali_svc_set_cali_cfg(aw_dev, set_cfg); + if (ret) { + dev_err(aw_dev->dev, "set cali cfg failed\n"); + aw_cali_svc_set_cali_cfg(aw_dev, aw_dev->cali_desc.cali_cfg); + aw_dev_dsp_enable(aw_dev, true); + return ret; + } + } else { + aw_cali_svc_set_cali_cfg(aw_dev, aw_dev->cali_desc.cali_cfg); + } + + aw_dev_dsp_enable(aw_dev, true); + + return 0; +} + +static int aw_cali_svc_cali_run_dsp_vol(struct aw_device *aw_dev, bool enable) +{ + unsigned int reg_val; + int ret; + + if (enable) { + ret = regmap_read(aw_dev->regmap, AW88399_DSPCFG_REG, ®_val); + if (ret) { + dev_err(aw_dev->dev, "read reg 0x%x failed\n", AW88399_DSPCFG_REG); + return ret; + } + + aw_dev->cali_desc.store_vol = reg_val & (~AW88399_DSP_VOL_MASK); + ret = regmap_update_bits(aw_dev->regmap, AW88399_DSPCFG_REG, + ~AW88399_DSP_VOL_MASK, AW88399_DSP_VOL_MUTE); + } else { + ret = regmap_update_bits(aw_dev->regmap, AW88399_DSPCFG_REG, + ~AW88399_DSP_VOL_MASK, aw_dev->cali_desc.store_vol); + } + + return ret; +} + +static void aw_cali_svc_backup_info(struct aw_device *aw_dev) +{ + struct aw_cali_backup_desc *backup_desc = &aw_dev->cali_desc.backup_info; + unsigned int reg_val, dsp_val; + + regmap_read(aw_dev->regmap, AW88399_DBGCTRL_REG, ®_val); + backup_desc->dsp_ng_cfg = reg_val & (~AW883XX_DSP_NG_EN_MASK); + + aw_dev_dsp_read(aw_dev, AW88399_DSP_LOW_POWER_SWITCH_CFG_ADDR, + &dsp_val, AW88399_DSP_16_DATA); + + backup_desc->dsp_lp_cfg = dsp_val; +} + +static void aw_cali_svc_recover_info(struct aw_device *aw_dev) +{ + struct aw_cali_backup_desc *backup_desc = &aw_dev->cali_desc.backup_info; + + regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, + ~AW883XX_DSP_NG_EN_MASK, backup_desc->dsp_ng_cfg); + + aw_dev_dsp_write(aw_dev, AW88399_DSP_LOW_POWER_SWITCH_CFG_ADDR, + backup_desc->dsp_lp_cfg, AW88399_DSP_16_DATA); +} + +static int aw_cali_svc_cali_re_mode_enable(struct aw_device *aw_dev, bool is_enable) +{ + int ret; + + if (is_enable) { + ret = aw_dev_check_syspll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "pll check failed cannot start\n"); + return ret; + } + + ret = aw_dev_get_dsp_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "dsp status error\n"); + return ret; + } + + aw_cali_svc_backup_info(aw_dev); + ret = aw_cali_svc_cali_en(aw_dev, true); + if (ret) { + dev_err(aw_dev->dev, "aw_cali_svc_cali_en failed\n"); + return ret; + } + + ret = aw_cali_svc_cali_run_dsp_vol(aw_dev, true); + if (ret) { + aw_cali_svc_cali_en(aw_dev, false); + return ret; + } + + } else { + aw_cali_svc_cali_run_dsp_vol(aw_dev, false); + aw_cali_svc_recover_info(aw_dev); + aw_cali_svc_cali_en(aw_dev, false); + } + + return 0; +} + +static int aw_cali_svc_get_dev_re(struct aw_device *aw_dev, uint32_t *re) +{ + uint32_t dsp_re, show_re; + int ret; + + ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CALRE, &dsp_re, AW88399_DSP_16_DATA); + if (ret) + return ret; + + show_re = AW88399_DSP_RE_TO_SHOW_RE(dsp_re, AW88399_DSP_REG_CALRE_SHIFT); + + *re = (uint32_t)(show_re - aw_dev->cali_desc.ra); + + return 0; +} + +static void aw_cali_svc_del_max_min_ave_algo(uint32_t *data, int data_size, uint32_t *dsp_re) +{ + int sum = 0, i; + + for (i = 1; i < data_size - 1; i++) + sum += data[i]; + + *dsp_re = sum / (data_size - AW_CALI_DATA_SUM_RM); +} + +static int aw_cali_svc_get_iv_st(struct aw_device *aw_dev) +{ + unsigned int reg_data; + int ret, i; + + for (i = 0; i < AW_GET_IV_CNT_MAX; i++) { + ret = regmap_read(aw_dev->regmap, AW88399_ASR1_REG, ®_data); + if (ret) { + dev_err(aw_dev->dev, "read 0x%x failed\n", AW88399_ASR1_REG); + return ret; + } + + reg_data &= (~AW88399_REABS_MASK); + if (!reg_data) + return 0; + msleep(30); + } + + dev_err(aw_dev->dev, "IV data abnormal, please check\n"); + + return -EINVAL; +} + +static int compare_ints(const void *a, const void *b) +{ + return *(int *)a - *(int *)b; +} + +static int aw_cali_svc_get_smooth_cali_re(struct aw_device *aw_dev) +{ + uint32_t re_temp[AW_CALI_READ_CNT_MAX]; + uint32_t dsp_re; + int ret, i; + + for (i = 0; i < AW_CALI_READ_CNT_MAX; i++) { + ret = aw_cali_svc_get_dev_re(aw_dev, &re_temp[i]); + if (ret) + goto cali_re_fail; + msleep(30); + } + + sort(re_temp, AW_CALI_READ_CNT_MAX, sizeof(uint32_t), compare_ints, NULL); + + aw_cali_svc_del_max_min_ave_algo(re_temp, AW_CALI_READ_CNT_MAX, &dsp_re); + + ret = aw_cali_svc_get_iv_st(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "get iv data failed"); + goto cali_re_fail; + } + + if (dsp_re < AW88399_CALI_RE_MIN || dsp_re > AW88399_CALI_RE_MAX) { + dev_err(aw_dev->dev, "out range re value: [%d]mohm\n", dsp_re); + aw_dev->cali_desc.cali_re = dsp_re; + aw_dev->cali_desc.cali_result = CALI_RESULT_ERROR; + aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result); + + return 0; + } + + aw_dev->cali_desc.cali_result = CALI_RESULT_NORMAL; + + aw_dev->cali_desc.cali_re = dsp_re; + dev_dbg(aw_dev->dev, "re[%d]mohm\n", aw_dev->cali_desc.cali_re); + + aw_dev_dsp_enable(aw_dev, false); + aw_dev_update_cali_re(&aw_dev->cali_desc); + aw_dev_dsp_enable(aw_dev, true); + + return 0; + +cali_re_fail: + aw_dev->cali_desc.cali_result = CALI_RESULT_ERROR; + aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result); + return -EINVAL; +} + +static int aw_cali_svc_dev_cali_re(struct aw88399 *aw88399) +{ + struct aw_device *aw_dev = aw88399->aw_pa; + struct aw_cali_desc *cali_desc = &aw_dev->cali_desc; + int ret; + + if (cali_desc->cali_running) { + dev_err(aw_dev->dev, "calibration in progress\n"); + return -EINVAL; + } + + cali_desc->cali_running = true; + aw_cali_svc_run_mute(aw_dev, CALI_RESULT_NORMAL); + + ret = aw_cali_svc_cali_re_mode_enable(aw_dev, true); + if (ret) { + dev_err(aw_dev->dev, "start cali re failed\n"); + goto re_mode_err; + } + + msleep(1000); + + ret = aw_cali_svc_get_smooth_cali_re(aw_dev); + if (ret) + dev_err(aw_dev->dev, "get cali re failed\n"); + + aw_cali_svc_cali_re_mode_enable(aw_dev, false); + +re_mode_err: + cali_desc->cali_running = false; + + return ret; +} + static int aw88399_get_fade_in_time(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1616,6 +2001,53 @@ static int aw88399_re_set(struct snd_kcontrol *kcontrol, return 0; } +static int aw88399_calib_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec); + struct aw_device *aw_dev = aw88399->aw_pa; + + ucontrol->value.integer.value[0] = aw_dev->cali_desc.cali_switch; + + return 0; +} + +static int aw88399_calib_switch_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec); + struct aw_device *aw_dev = aw88399->aw_pa; + + if (aw_dev->cali_desc.cali_switch == ucontrol->value.integer.value[0]) + return 0; + + aw_dev->cali_desc.cali_switch = ucontrol->value.integer.value[0]; + + return 1; +} + +static int aw88399_calib_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + /* do nothing */ + return 0; +} + +static int aw88399_calib_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec); + struct aw_device *aw_dev = aw88399->aw_pa; + + if (aw_dev->status && aw_dev->cali_desc.cali_switch) + aw_cali_svc_dev_cali_re(aw88399); + + return 0; +} + static int aw88399_dev_init(struct aw88399 *aw88399, struct aw_container *aw_cfg) { struct aw_device *aw_dev = aw88399->aw_pa; @@ -1708,6 +2140,10 @@ static const struct snd_kcontrol_new aw88399_controls[] = { aw88399_get_fade_out_time, aw88399_set_fade_out_time), SOC_SINGLE_EXT("Calib", 0, 0, AW88399_CALI_RE_MAX, 0, aw88399_re_get, aw88399_re_set), + SOC_SINGLE_BOOL_EXT("Calib Switch", 0, + aw88399_calib_switch_get, aw88399_calib_switch_set), + SOC_SINGLE_EXT("Trigger Calib", SND_SOC_NOPM, 0, 1, 0, + aw88399_calib_get, aw88399_calib_set), AW88399_PROFILE_EXT("AW88399 Profile Set", aw88399_profile_info, aw88399_profile_get, aw88399_profile_set), }; diff --git a/sound/soc/codecs/aw88399.h b/sound/soc/codecs/aw88399.h index 5e9cdf725d3d..cacc03b1eefa 100644 --- a/sound/soc/codecs/aw88399.h +++ b/sound/soc/codecs/aw88399.h @@ -451,6 +451,24 @@ #define AW88399_WDT_CNT_MASK \ (~(((1< Date: Mon, 30 Jun 2025 12:54:18 +0200 Subject: [PATCH 160/385] ALSA: timer: Replace deprecated strcpy() with strscpy() strcpy() is deprecated; use strscpy() instead. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20250630105420.1448-2-thorsten.blum@linux.dev Signed-off-by: Takashi Iwai --- sound/core/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/timer.c b/sound/core/timer.c index 8072183c33d3..3ce12264eed8 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1195,7 +1195,7 @@ static int snd_timer_register_system(void) err = snd_timer_global_new("system", SNDRV_TIMER_GLOBAL_SYSTEM, &timer); if (err < 0) return err; - strcpy(timer->name, "system timer"); + strscpy(timer->name, "system timer"); timer->hw = snd_timer_system; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (priv == NULL) { From 24ffcf7f27cf75389ca550a18f9e45a8dad27bd2 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 30 Jun 2025 12:57:22 +0200 Subject: [PATCH 161/385] ALSA: hrtimer: Replace deprecated strcpy() with strscpy() strcpy() is deprecated; use strscpy() instead. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20250630105723.1703-2-thorsten.blum@linux.dev Signed-off-by: Takashi Iwai --- sound/core/hrtimer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c index e9c60dce59fb..c364bd126ac8 100644 --- a/sound/core/hrtimer.c +++ b/sound/core/hrtimer.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -138,7 +139,7 @@ static int __init snd_hrtimer_init(void) return err; timer->module = THIS_MODULE; - strcpy(timer->name, "HR timer"); + strscpy(timer->name, "HR timer"); timer->hw = hrtimer_hw; timer->hw.resolution = resolution; timer->hw.ticks = NANO_SEC / resolution; From 66b338d006d75ab52b16bf05a7f4f451043199bf Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 30 Jun 2025 13:09:44 +0200 Subject: [PATCH 162/385] ALSA: dummy: Replace deprecated strcpy() with strscpy() strcpy() is deprecated; use strscpy() instead. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20250630110945.2225-2-thorsten.blum@linux.dev Signed-off-by: Takashi Iwai --- sound/drivers/dummy.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 783fe3a22bc9..6dac0b2523c1 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -684,7 +685,7 @@ static int snd_card_dummy_pcm(struct snd_dummy *dummy, int device, snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, ops); pcm->private_data = dummy; pcm->info_flags = 0; - strcpy(pcm->name, "Dummy PCM"); + strscpy(pcm->name, "Dummy PCM"); if (!fake_buffer) { snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, @@ -875,7 +876,7 @@ static int snd_card_dummy_new_mixer(struct snd_dummy *dummy) int err; spin_lock_init(&dummy->mixer_lock); - strcpy(card->mixername, "Dummy Mixer"); + strscpy(card->mixername, "Dummy Mixer"); dummy->iobox = 1; for (idx = 0; idx < ARRAY_SIZE(snd_dummy_controls); idx++) { @@ -1083,8 +1084,8 @@ static int snd_dummy_probe(struct platform_device *devptr) err = snd_card_dummy_new_mixer(dummy); if (err < 0) return err; - strcpy(card->driver, "Dummy"); - strcpy(card->shortname, "Dummy"); + strscpy(card->driver, "Dummy"); + strscpy(card->shortname, "Dummy"); sprintf(card->longname, "Dummy %i", dev + 1); dummy_proc_init(dummy); From 0383a710d28dd5dc43d26ccf9fc74e1ba41868fd Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 24 Jun 2025 13:28:38 +0100 Subject: [PATCH 163/385] MAINTAINERS: Add SDCA maintainers entry Add a maintainers entry for the new SDCA support code. Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250624122844.2761627-2-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- MAINTAINERS | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index a92290fffa16..b9782f84bb36 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22298,6 +22298,17 @@ M: Jim Cromie S: Maintained F: drivers/clocksource/scx200_hrt.c +SDCA LIBRARY AND CLASS DRIVER +M: Charles Keepax +M: Maciej Strozek +R: Bard Liao +R: Pierre-Louis Bossart +L: linux-sound@vger.kernel.org +L: patches@opensource.cirrus.com +S: Maintained +F: include/sound/sdca* +F: sound/soc/sdca/* + SDRICOH_CS MMC/SD HOST CONTROLLER INTERFACE DRIVER M: Sascha Sommer L: sdricohcs-devel@lists.sourceforge.net (subscribers-only) From 2ed526bf04a6d81592b314f81e7719a14048f732 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 24 Jun 2025 13:28:39 +0100 Subject: [PATCH 164/385] ASoC: SDCA: Add missing default in switch in entity_pde_event() The current code should be safe as the PDE widget only registers for the two events handled in the switch statement. However, it is causing a smatch warning and also is a little fragile to future code changes, add a default case to avoid the warning and make the code more robust. Fixes: 2c8b3a8e6aa8 ("ASoC: SDCA: Create DAPM widgets and routes from DisCo") Reported-by: Dan Carpenter Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250624122844.2761627-3-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/sdca/sdca_asoc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c index 7bc8f6069f3d..e96e696cb107 100644 --- a/sound/soc/sdca/sdca_asoc.c +++ b/sound/soc/sdca/sdca_asoc.c @@ -397,6 +397,8 @@ static int entity_pde_event(struct snd_soc_dapm_widget *widget, from = widget->off_val; to = widget->on_val; break; + default: + return 0; } for (i = 0; i < entity->pde.num_max_delay; i++) { From b4515fd87cc9a260ae89fb81ca2aa928d496ac86 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 24 Jun 2025 13:28:40 +0100 Subject: [PATCH 165/385] ASoC: SDCA: Fixup some kernel doc errors Correct some typos and omissions in the kernel doc for the ASoC SDCA code. Fixes: 2c8b3a8e6aa8 ("ASoC: SDCA: Create DAPM widgets and routes from DisCo") Reported-by: Bard Liao Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250624122844.2761627-4-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/sdca/sdca_asoc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c index e96e696cb107..83911dab73ae 100644 --- a/sound/soc/sdca/sdca_asoc.c +++ b/sound/soc/sdca/sdca_asoc.c @@ -93,6 +93,7 @@ static bool readonly_control(struct sdca_control *control) /** * sdca_asoc_count_component - count the various component parts + * @dev: Pointer to the device against which allocations will be done. * @function: Pointer to the Function information. * @num_widgets: Output integer pointer, will be filled with the * required number of DAPM widgets for the Function. @@ -997,7 +998,7 @@ static int populate_pin_switch(struct device *dev, * sdca_asoc_populate_controls - fill in an array of ALSA controls for a Function * @dev: Pointer to the device against which allocations will be done. * @function: Pointer to the Function information. - * @route: Array of ALSA controls to be populated. + * @kctl: Array of ALSA controls to be populated. * * This function populates an array of ALSA controls from the DisCo * information for a particular SDCA Function. Typically, @@ -1244,7 +1245,11 @@ EXPORT_SYMBOL_NS(sdca_asoc_populate_dais, "SND_SOC_SDCA"); * sdca_asoc_populate_component - fill in a component driver for a Function * @dev: Pointer to the device against which allocations will be done. * @function: Pointer to the Function information. - * @copmonent_drv: Pointer to the component driver to be populated. + * @component_drv: Pointer to the component driver to be populated. + * @dai_drv: Pointer to the DAI driver array to be allocated and populated. + * @num_dai_drv: Pointer to integer that will be populated with the number of + * DAI drivers. + * @ops: DAI ops pointer that will be used for each DAI driver. * * This function populates a snd_soc_component_driver structure based * on the DisCo information for a particular SDCA Function. It does From 37d2aa62138daa8ecb6442ae4753704e9c92346f Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 24 Jun 2025 13:28:41 +0100 Subject: [PATCH 166/385] ASoC: SDCA: Minor selected/detected mode control fixups Make the names a slightly better match for the specification and add some constants for the values rather than hard coding. Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250624122844.2761627-5-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/sdca_function.h | 9 +++++++++ sound/soc/sdca/sdca_asoc.c | 8 ++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h index 856b0f40ce5e..4b278513597e 100644 --- a/include/sound/sdca_function.h +++ b/include/sound/sdca_function.h @@ -319,6 +319,15 @@ enum sdca_selected_mode_range { SDCA_SELECTED_MODE_NCOLS = 2, }; +/** + * enum sdca_detected_mode_values - Predefined GE Detected Mode values + */ +enum sdca_detected_mode_values { + SDCA_DETECTED_MODE_JACK_UNPLUGGED = 0, + SDCA_DETECTED_MODE_JACK_UNKNOWN = 1, + SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS = 2, +}; + /** * enum sdca_spe_controls - SDCA Controls for Security & Privacy Unit * diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c index 83911dab73ae..dd7b19083c85 100644 --- a/sound/soc/sdca/sdca_asoc.c +++ b/sound/soc/sdca/sdca_asoc.c @@ -246,12 +246,12 @@ static int entity_early_parse_ge(struct device *dev, if (!values) return -ENOMEM; - texts[0] = "No Jack"; + texts[0] = "Jack Unplugged"; texts[1] = "Jack Unknown"; texts[2] = "Detection in Progress"; - values[0] = 0; - values[1] = 1; - values[2] = 2; + values[0] = SDCA_DETECTED_MODE_JACK_UNPLUGGED; + values[1] = SDCA_DETECTED_MODE_JACK_UNKNOWN; + values[2] = SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS; for (i = 0; i < range->rows; i++) { enum sdca_terminal_type type; From 775f5729b47d8737f4f98e0141f61b3358245398 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 24 Jun 2025 13:28:42 +0100 Subject: [PATCH 167/385] ASoC: SDCA: Add flag for unused IRQs Zero is a valid SDCA IRQ interrupt position so add a special value to indicate that the IRQ is not used. Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250624122844.2761627-6-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/sdca_function.h | 2 ++ sound/soc/sdca/sdca_functions.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h index 4b278513597e..b4a97ff08729 100644 --- a/include/sound/sdca_function.h +++ b/include/sound/sdca_function.h @@ -17,6 +17,8 @@ struct device; struct sdca_entity; struct sdca_function_desc; +#define SDCA_NO_INTERRUPT -1 + /* * The addressing space for SDCA relies on 7 bits for Entities, so a * maximum of 128 Entities per function can be represented. diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index 093c681e9387..c34f3bf62983 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -912,6 +912,8 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti &tmp); if (!ret) control->interrupt_position = tmp; + else + control->interrupt_position = SDCA_NO_INTERRUPT; control->label = find_sdca_control_label(dev, entity, control); if (!control->label) From b126394d9ec6f9d8322cf392ba23d4a5f96faf5a Mon Sep 17 00:00:00 2001 From: Maciej Strozek Date: Tue, 24 Jun 2025 13:28:43 +0100 Subject: [PATCH 168/385] ASoC: SDCA: Generic interrupt support Add a library supporting usage of SDCA interrupts, using regmap irq framework. The library adds functions for parsing ACPI for interrupt-related information, configuring irq chip and requesting individual irqs. Calling code (SDCA function code) is expected to also substitute the library's base irq handler for its own, appropriate callback. Signed-off-by: Maciej Strozek Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250624122844.2761627-7-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/sdca_interrupts.h | 75 ++++++++ sound/soc/sdca/Kconfig | 7 + sound/soc/sdca/Makefile | 5 +- sound/soc/sdca/sdca_interrupts.c | 284 +++++++++++++++++++++++++++++++ 4 files changed, 369 insertions(+), 2 deletions(-) create mode 100644 include/sound/sdca_interrupts.h create mode 100644 sound/soc/sdca/sdca_interrupts.c diff --git a/include/sound/sdca_interrupts.h b/include/sound/sdca_interrupts.h new file mode 100644 index 000000000000..4cda8b75bae0 --- /dev/null +++ b/include/sound/sdca_interrupts.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * The MIPI SDCA specification is available for public downloads at + * https://www.mipi.org/mipi-sdca-v1-0-download + * + * Copyright (C) 2025 Cirrus Logic, Inc. and + * Cirrus Logic International Semiconductor Ltd. + */ + +#ifndef __SDCA_INTERRUPTS_H__ +#define __SDCA_INTERRUPTS_H__ + +#include +#include +#include + +struct device; +struct snd_soc_component; +struct sdca_function_data; + +#define SDCA_MAX_INTERRUPTS 31 /* the last bit is reserved for future extensions */ + +/** + * struct sdca_interrupt - contains information about a single SDCA interrupt + * @name: The name of the interrupt. + * @component: Pointer to the ASoC component owns the interrupt. + * @function: Pointer to the Function that the interrupt is associated with. + * @entity: Pointer to the Entity that the interrupt is associated with. + * @control: Pointer to the Control that the interrupt is associated with. + * @externally_requested: Internal flag used to check if a client driver has + * already requested the interrupt, for custom handling, allowing the core to + * skip handling this interrupt. + */ +struct sdca_interrupt { + const char *name; + + struct snd_soc_component *component; + struct sdca_function_data *function; + struct sdca_entity *entity; + struct sdca_control *control; + + bool externally_requested; +}; + +/** + * struct sdca_interrupt_info - contains top-level SDCA interrupt information + * @irq_chip: regmap irq chip structure. + * @irq_data: regmap irq chip data structure. + * @irqs: Array of data for each individual IRQ. + * @irq_lock: Protects access to the list of sdca_interrupt structures. + */ +struct sdca_interrupt_info { + struct regmap_irq_chip irq_chip; + struct regmap_irq_chip_data *irq_data; + + struct sdca_interrupt irqs[SDCA_MAX_INTERRUPTS]; + + struct mutex irq_lock; /* Protect irqs list across functions */ +}; + +int sdca_irq_request(struct device *dev, struct sdca_interrupt_info *interrupt_info, + int sdca_irq, const char *name, irq_handler_t handler, + void *data); +int sdca_irq_data_populate(struct snd_soc_component *component, + struct sdca_function_data *function, + struct sdca_entity *entity, + struct sdca_control *control, + struct sdca_interrupt *interrupt); +int sdca_irq_populate(struct sdca_function_data *function, + struct snd_soc_component *component, + struct sdca_interrupt_info *info); +struct sdca_interrupt_info *sdca_irq_allocate(struct device *dev, + struct regmap *regmap, int irq); + +#endif diff --git a/sound/soc/sdca/Kconfig b/sound/soc/sdca/Kconfig index ec28855fe3b0..a633d5a0fea5 100644 --- a/sound/soc/sdca/Kconfig +++ b/sound/soc/sdca/Kconfig @@ -13,3 +13,10 @@ config SND_SOC_SDCA_OPTIONAL config SND_SOC_SDCA_HID tristate "SDCA HID support" depends on SND_SOC_SDCA && HID + +config SND_SOC_SDCA_IRQ + tristate + select REGMAP + select REGMAP_IRQ + help + This option enables support for SDCA IRQs. diff --git a/sound/soc/sdca/Makefile b/sound/soc/sdca/Makefile index 9af46e7edfd2..2a3938d11ca9 100644 --- a/sound/soc/sdca/Makefile +++ b/sound/soc/sdca/Makefile @@ -1,8 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-only snd-soc-sdca-y := sdca_functions.o sdca_device.o sdca_regmap.o sdca_asoc.o - snd-soc-sdca-hid-y := sdca_hid.o +snd-soc-sdca-irq-y := sdca_interrupts.o -obj-$(CONFIG_SND_SOC_SDCA_HID) += snd-soc-sdca-hid.o obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca.o +obj-$(CONFIG_SND_SOC_SDCA_HID) += snd-soc-sdca-hid.o +obj-$(CONFIG_SND_SOC_SDCA_IRQ) += snd-soc-sdca-irq.o diff --git a/sound/soc/sdca/sdca_interrupts.c b/sound/soc/sdca/sdca_interrupts.c new file mode 100644 index 000000000000..7272d11cb6d4 --- /dev/null +++ b/sound/soc/sdca/sdca_interrupts.c @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2025 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +/* + * The MIPI SDCA specification is available for public downloads at + * https://www.mipi.org/mipi-sdca-v1-0-download + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IRQ_SDCA(number) REGMAP_IRQ_REG(number, ((number) / BITS_PER_BYTE), \ + SDW_SCP_SDCA_INTMASK_SDCA_##number) + +static const struct regmap_irq regmap_irqs[SDCA_MAX_INTERRUPTS] = { + IRQ_SDCA(0), + IRQ_SDCA(1), + IRQ_SDCA(2), + IRQ_SDCA(3), + IRQ_SDCA(4), + IRQ_SDCA(5), + IRQ_SDCA(6), + IRQ_SDCA(7), + IRQ_SDCA(8), + IRQ_SDCA(9), + IRQ_SDCA(10), + IRQ_SDCA(11), + IRQ_SDCA(12), + IRQ_SDCA(13), + IRQ_SDCA(14), + IRQ_SDCA(15), + IRQ_SDCA(16), + IRQ_SDCA(17), + IRQ_SDCA(18), + IRQ_SDCA(19), + IRQ_SDCA(20), + IRQ_SDCA(21), + IRQ_SDCA(22), + IRQ_SDCA(23), + IRQ_SDCA(24), + IRQ_SDCA(25), + IRQ_SDCA(26), + IRQ_SDCA(27), + IRQ_SDCA(28), + IRQ_SDCA(29), + IRQ_SDCA(30), +}; + +static const struct regmap_irq_chip sdca_irq_chip = { + .name = "sdca_irq", + + .status_base = SDW_SCP_SDCA_INT1, + .unmask_base = SDW_SCP_SDCA_INTMASK1, + .ack_base = SDW_SCP_SDCA_INT1, + .num_regs = 4, + + .irqs = regmap_irqs, + .num_irqs = SDCA_MAX_INTERRUPTS, + + .runtime_pm = true, +}; + +static irqreturn_t base_handler(int irq, void *data) +{ + struct sdca_interrupt *interrupt = data; + struct device *dev = interrupt->component->dev; + + dev_info(dev, "%s irq without full handling\n", interrupt->name); + + return IRQ_HANDLED; +} + +static int sdca_irq_request_locked(struct device *dev, + struct sdca_interrupt_info *info, + int sdca_irq, const char *name, + irq_handler_t handler, void *data) +{ + int irq; + int ret; + + irq = regmap_irq_get_virq(info->irq_data, sdca_irq); + if (irq < 0) + return irq; + + ret = devm_request_threaded_irq(dev, irq, NULL, handler, + IRQF_ONESHOT, name, data); + if (ret) + return ret; + + dev_dbg(dev, "requested irq %d for %s\n", irq, name); + + return 0; +} + +/** + * sdca_request_irq - request an individual SDCA interrupt + * @dev: Pointer to the struct device against which things should be allocated. + * @interrupt_info: Pointer to the interrupt information structure. + * @sdca_irq: SDCA interrupt position. + * @name: Name to be given to the IRQ. + * @handler: A callback thread function to be called for the IRQ. + * @data: Private data pointer that will be passed to the handler. + * + * Typically this is handled internally by sdca_irq_populate, however if + * a device requires custom IRQ handling this can be called manually before + * calling sdca_irq_populate, which will then skip that IRQ whilst processing. + * + * Return: Zero on success, and a negative error code on failure. + */ +int sdca_irq_request(struct device *dev, struct sdca_interrupt_info *info, + int sdca_irq, const char *name, irq_handler_t handler, + void *data) +{ + int ret; + + if (sdca_irq < 0 || sdca_irq > SDCA_MAX_INTERRUPTS) { + dev_err(dev, "bad irq request: %d\n", sdca_irq); + return -EINVAL; + } + + guard(mutex)(&info->irq_lock); + + ret = sdca_irq_request_locked(dev, info, sdca_irq, name, handler, data); + if (ret) { + dev_err(dev, "failed to request irq %s: %d\n", name, ret); + return ret; + } + + info->irqs[sdca_irq].externally_requested = true; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(sdca_irq_request, "SND_SOC_SDCA_IRQ"); + +/** + * sdca_irq_data_populate - Populate common interrupt data + * @component: Pointer to the ASoC component for the Function. + * @function: Pointer to the SDCA Function. + * @entity: Pointer to the SDCA Entity. + * @control: Pointer to the SDCA Control. + * @interrupt: Pointer to the SDCA interrupt for this IRQ. + * + * Return: Zero on success, and a negative error code on failure. + */ +int sdca_irq_data_populate(struct snd_soc_component *component, + struct sdca_function_data *function, + struct sdca_entity *entity, + struct sdca_control *control, + struct sdca_interrupt *interrupt) +{ + struct device *dev = component->dev; + const char *name; + + name = devm_kasprintf(dev, GFP_KERNEL, "%s %s %s", function->desc->name, + entity->label, control->label); + if (!name) + return -ENOMEM; + + interrupt->name = name; + interrupt->component = component; + interrupt->function = function; + interrupt->entity = entity; + interrupt->control = control; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(sdca_irq_data_populate, "SND_SOC_SDCA_IRQ"); + +/** + * sdca_irq_populate - Request all the individual IRQs for an SDCA Function + * @function: Pointer to the SDCA Function. + * @component: Pointer to the ASoC component for the Function. + * @info: Pointer to the SDCA interrupt info for this device. + * + * Typically this would be called from the driver for a single SDCA Function. + * + * Return: Zero on success, and a negative error code on failure. + */ +int sdca_irq_populate(struct sdca_function_data *function, + struct snd_soc_component *component, + struct sdca_interrupt_info *info) +{ + struct device *dev = component->dev; + int i, j; + + guard(mutex)(&info->irq_lock); + + for (i = 0; i < function->num_entities; i++) { + struct sdca_entity *entity = &function->entities[i]; + + for (j = 0; j < entity->num_controls; j++) { + struct sdca_control *control = &entity->controls[j]; + int irq = control->interrupt_position; + struct sdca_interrupt *interrupt; + const char *name; + int ret; + + if (irq == SDCA_NO_INTERRUPT) { + continue; + } else if (irq < 0 || irq >= SDCA_MAX_INTERRUPTS) { + dev_err(dev, "bad irq position: %d\n", irq); + return -EINVAL; + } + + interrupt = &info->irqs[irq]; + + if (interrupt->externally_requested) { + dev_dbg(dev, + "skipping irq %d, externally requested\n", + irq); + continue; + } + + ret = sdca_irq_data_populate(component, function, entity, + control, interrupt); + if (ret) + return ret; + + ret = sdca_irq_request_locked(dev, info, irq, interrupt->name, + base_handler, interrupt); + if (ret) { + dev_err(dev, "failed to request irq %s: %d\n", + name, ret); + return ret; + } + } + } + + return 0; +} +EXPORT_SYMBOL_NS_GPL(sdca_irq_populate, "SND_SOC_SDCA_IRQ"); + +/** + * sdca_irq_allocate - allocate an SDCA interrupt structure for a device + * @dev: Device pointer against which things should be allocated. + * @regmap: regmap to be used for accessing the SDCA IRQ registers. + * @irq: The interrupt number. + * + * Typically this would be called from the top level driver for the whole + * SDCA device, as only a single instance is required across all Functions + * on the device. + * + * Return: A pointer to the allocated sdca_interrupt_info struct, or an + * error code. + */ +struct sdca_interrupt_info *sdca_irq_allocate(struct device *dev, + struct regmap *regmap, int irq) +{ + struct sdca_interrupt_info *info; + int ret; + + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) + return ERR_PTR(-ENOMEM); + + info->irq_chip = sdca_irq_chip; + + devm_mutex_init(dev, &info->irq_lock); + + ret = devm_regmap_add_irq_chip(dev, regmap, irq, IRQF_ONESHOT, 0, + &info->irq_chip, &info->irq_data); + if (ret) { + dev_err(dev, "failed to register irq chip: %d\n", ret); + return ERR_PTR(ret); + } + + dev_dbg(dev, "registered on irq %d\n", irq); + + return info; +} +EXPORT_SYMBOL_NS_GPL(sdca_irq_allocate, "SND_SOC_SDCA_IRQ"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SDCA IRQ library"); From b9ab3b61824190b1c6b2c59e7ba4de591f24eb92 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 24 Jun 2025 13:28:44 +0100 Subject: [PATCH 169/385] ASoC: SDCA: Add some initial IRQ handlers Add basic IRQ handlers for the function status and jack detection interrupts. Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250624122844.2761627-8-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/sdca_interrupts.h | 3 + sound/soc/sdca/sdca_interrupts.c | 157 ++++++++++++++++++++++++++++++- 2 files changed, 159 insertions(+), 1 deletion(-) diff --git a/include/sound/sdca_interrupts.h b/include/sound/sdca_interrupts.h index 4cda8b75bae0..bbbc3ab27eba 100644 --- a/include/sound/sdca_interrupts.h +++ b/include/sound/sdca_interrupts.h @@ -27,6 +27,7 @@ struct sdca_function_data; * @function: Pointer to the Function that the interrupt is associated with. * @entity: Pointer to the Entity that the interrupt is associated with. * @control: Pointer to the Control that the interrupt is associated with. + * @priv: Pointer to private data for use by the handler. * @externally_requested: Internal flag used to check if a client driver has * already requested the interrupt, for custom handling, allowing the core to * skip handling this interrupt. @@ -39,6 +40,8 @@ struct sdca_interrupt { struct sdca_entity *entity; struct sdca_control *control; + void *priv; + bool externally_requested; }; diff --git a/sound/soc/sdca/sdca_interrupts.c b/sound/soc/sdca/sdca_interrupts.c index 7272d11cb6d4..edb045c7ebb0 100644 --- a/sound/soc/sdca/sdca_interrupts.c +++ b/sound/soc/sdca/sdca_interrupts.c @@ -7,6 +7,7 @@ * https://www.mipi.org/mipi-sdca-v1-0-download */ +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #define IRQ_SDCA(number) REGMAP_IRQ_REG(number, ((number) / BITS_PER_BYTE), \ SDW_SCP_SDCA_INTMASK_SDCA_##number) @@ -80,6 +82,143 @@ static irqreturn_t base_handler(int irq, void *data) return IRQ_HANDLED; } +static irqreturn_t function_status_handler(int irq, void *data) +{ + struct sdca_interrupt *interrupt = data; + struct device *dev = interrupt->component->dev; + unsigned int reg, val; + unsigned long status; + unsigned int mask; + int ret; + + reg = SDW_SDCA_CTL(interrupt->function->desc->adr, interrupt->entity->id, + interrupt->control->sel, 0); + + ret = regmap_read(interrupt->component->regmap, reg, &val); + if (ret < 0) { + dev_err(dev, "failed to read function status: %d\n", ret); + return IRQ_NONE; + } + + dev_dbg(dev, "function status: %#x\n", val); + + status = val; + for_each_set_bit(mask, &status, BITS_PER_BYTE) { + mask = 1 << mask; + + switch (mask) { + case SDCA_CTL_ENTITY_0_FUNCTION_NEEDS_INITIALIZATION: + //FIXME: Add init writes + break; + case SDCA_CTL_ENTITY_0_FUNCTION_FAULT: + dev_err(dev, "function fault\n"); + break; + case SDCA_CTL_ENTITY_0_UMP_SEQUENCE_FAULT: + dev_err(dev, "ump sequence fault\n"); + break; + case SDCA_CTL_ENTITY_0_FUNCTION_BUSY: + dev_info(dev, "unexpected function busy\n"); + break; + case SDCA_CTL_ENTITY_0_DEVICE_NEWLY_ATTACHED: + case SDCA_CTL_ENTITY_0_INTS_DISABLED_ABNORMALLY: + case SDCA_CTL_ENTITY_0_STREAMING_STOPPED_ABNORMALLY: + case SDCA_CTL_ENTITY_0_FUNCTION_HAS_BEEN_RESET: + break; + } + } + + ret = regmap_write(interrupt->component->regmap, reg, val); + if (ret < 0) { + dev_err(dev, "failed to clear function status: %d\n", ret); + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + +static irqreturn_t detected_mode_handler(int irq, void *data) +{ + struct sdca_interrupt *interrupt = data; + struct snd_soc_component *component = interrupt->component; + struct device *dev = component->dev; + struct snd_soc_card *card = component->card; + struct rw_semaphore *rwsem = &card->snd_card->controls_rwsem; + struct snd_kcontrol *kctl = interrupt->priv; + struct snd_ctl_elem_value ucontrol; + struct soc_enum *soc_enum; + unsigned int reg, val; + int ret; + + if (!kctl) { + const char *name __free(kfree) = kasprintf(GFP_KERNEL, "%s %s", + interrupt->entity->label, + SDCA_CTL_SELECTED_MODE_NAME); + + if (!name) + return -ENOMEM; + + kctl = snd_soc_component_get_kcontrol(component, name); + if (!kctl) { + dev_dbg(dev, "control not found: %s\n", name); + return IRQ_NONE; + } + + interrupt->priv = kctl; + } + + soc_enum = (struct soc_enum *)kctl->private_value; + + reg = SDW_SDCA_CTL(interrupt->function->desc->adr, interrupt->entity->id, + interrupt->control->sel, 0); + + ret = regmap_read(component->regmap, reg, &val); + if (ret < 0) { + dev_err(dev, "failed to read detected mode: %d\n", ret); + return IRQ_NONE; + } + + switch (val) { + case SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS: + case SDCA_DETECTED_MODE_JACK_UNKNOWN: + reg = SDW_SDCA_CTL(interrupt->function->desc->adr, + interrupt->entity->id, + SDCA_CTL_GE_SELECTED_MODE, 0); + + /* + * Selected mode is not normally marked as volatile register + * (RW), but here force a read from the hardware. If the + * detected mode is unknown we need to see what the device + * selected as a "safe" option. + */ + regcache_drop_region(component->regmap, reg, reg); + + ret = regmap_read(component->regmap, reg, &val); + if (ret) { + dev_err(dev, "failed to re-check selected mode: %d\n", ret); + return IRQ_NONE; + } + break; + default: + break; + } + + dev_dbg(dev, "%s: %#x\n", interrupt->name, val); + + ucontrol.value.enumerated.item[0] = snd_soc_enum_val_to_item(soc_enum, val); + + down_write(rwsem); + ret = kctl->put(kctl, &ucontrol); + up_write(rwsem); + if (ret < 0) { + dev_err(dev, "failed to update selected mode: %d\n", ret); + return IRQ_NONE; + } + + snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); + + return IRQ_HANDLED; +} + static int sdca_irq_request_locked(struct device *dev, struct sdca_interrupt_info *info, int sdca_irq, const char *name, @@ -202,6 +341,7 @@ int sdca_irq_populate(struct sdca_function_data *function, struct sdca_control *control = &entity->controls[j]; int irq = control->interrupt_position; struct sdca_interrupt *interrupt; + irq_handler_t handler; const char *name; int ret; @@ -226,8 +366,23 @@ int sdca_irq_populate(struct sdca_function_data *function, if (ret) return ret; + handler = base_handler; + + switch (entity->type) { + case SDCA_ENTITY_TYPE_ENTITY_0: + if (control->sel == SDCA_CTL_ENTITY_0_FUNCTION_STATUS) + handler = function_status_handler; + break; + case SDCA_ENTITY_TYPE_GE: + if (control->sel == SDCA_CTL_GE_DETECTED_MODE) + handler = detected_mode_handler; + break; + default: + break; + } + ret = sdca_irq_request_locked(dev, info, irq, interrupt->name, - base_handler, interrupt); + handler, interrupt); if (ret) { dev_err(dev, "failed to request irq %s: %d\n", name, ret); From a3b0e80428c8e2aa50d7e3c75721dd7f5c76c4d9 Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Wed, 2 Jul 2025 15:14:10 +0530 Subject: [PATCH 170/385] ASoC: amd: acp: Add legacy driver support acp7.2 based platforms Add pci revision id 0x72 in pci and platform driver to support acp7.2 based platforms. Signed-off-by: Venkata Prasad Potturu Link: https://patch.msgid.link/20250702094425.155185-2-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-legacy-common.c | 2 ++ sound/soc/amd/acp/acp-pci.c | 1 + sound/soc/amd/acp/acp-platform.c | 2 ++ sound/soc/amd/acp/acp70.c | 1 + sound/soc/amd/acp/acp_common.h | 1 + 5 files changed, 7 insertions(+) diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c index ba8db0851daa..3078f459e005 100644 --- a/sound/soc/amd/acp/acp-legacy-common.c +++ b/sound/soc/amd/acp/acp-legacy-common.c @@ -372,6 +372,7 @@ static int acp_power_on(struct acp_chip_info *chip) break; case ACP70_PCI_ID: case ACP71_PCI_ID: + case ACP72_PCI_ID: acp_pgfsm_stat_reg = ACP70_PGFSM_STATUS; acp_pgfsm_ctrl_reg = ACP70_PGFSM_CONTROL; break; @@ -573,6 +574,7 @@ void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip) break; case ACP70_PCI_ID: case ACP71_PCI_ID: + case ACP72_PCI_ID: pdm_addr = ACP70_PDM_ADDR; check_acp70_config(chip); break; diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index 2591b1a1c5e0..f83708755ed1 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -153,6 +153,7 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id break; case 0x70: case 0x71: + case 0x72: chip->name = "acp_asoc_acp70"; chip->rsrc = &acp70_rsrc; chip->acp_hw_ops_init = acp70_hw_ops_init; diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c index b3eddf76aaa4..b25ac5612808 100644 --- a/sound/soc/amd/acp/acp-platform.c +++ b/sound/soc/amd/acp/acp-platform.c @@ -140,6 +140,7 @@ void config_acp_dma(struct acp_chip_info *chip, struct acp_stream *stream, int s switch (chip->acp_rev) { case ACP70_PCI_ID: case ACP71_PCI_ID: + case ACP72_PCI_ID: switch (stream->dai_id) { case I2S_SP_INSTANCE: if (stream->dir == SNDRV_PCM_STREAM_PLAYBACK) @@ -205,6 +206,7 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs case ACP63_PCI_ID: case ACP70_PCI_ID: case ACP71_PCI_ID: + case ACP72_PCI_ID: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) runtime->hw = acp6x_pcm_hardware_playback; else diff --git a/sound/soc/amd/acp/acp70.c b/sound/soc/amd/acp/acp70.c index b95e3949e70b..bca311c88139 100644 --- a/sound/soc/amd/acp/acp70.c +++ b/sound/soc/amd/acp/acp70.c @@ -136,6 +136,7 @@ static int acp_acp70_audio_probe(struct platform_device *pdev) switch (chip->acp_rev) { case ACP70_PCI_ID: case ACP71_PCI_ID: + case ACP72_PCI_ID: break; default: dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev); diff --git a/sound/soc/amd/acp/acp_common.h b/sound/soc/amd/acp/acp_common.h index f1ae88013f62..984685602e3d 100644 --- a/sound/soc/amd/acp/acp_common.h +++ b/sound/soc/amd/acp/acp_common.h @@ -15,5 +15,6 @@ #define ACP63_PCI_ID 0x63 #define ACP70_PCI_ID 0x70 #define ACP71_PCI_ID 0x71 +#define ACP72_PCI_ID 0x72 #endif From 3549725e0f7823d085403fc4219fd3df347a1ae4 Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Wed, 2 Jul 2025 15:14:11 +0530 Subject: [PATCH 171/385] ASoC: amd: acp: Enable I2S support for acp7.2 based platforms Enable I2S dai driver support for acp7.2 based platforms. Signed-off-by: Venkata Prasad Potturu Link: https://patch.msgid.link/20250702094425.155185-3-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-i2s.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 70fa54d568ef..617690362ad7 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -58,6 +58,7 @@ static inline void acp_set_i2s_clk(struct acp_chip_info *chip, int dai_id) case ACP63_PCI_ID: case ACP70_PCI_ID: case ACP71_PCI_ID: + case ACP72_PCI_ID: val |= FIELD_PREP(ACP63_LRCLK_DIV_FIELD, chip->lrclk_div); val |= FIELD_PREP(ACP63_BCLK_DIV_FIELD, chip->bclk_div); break; @@ -134,6 +135,7 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas case ACP63_PCI_ID: case ACP70_PCI_ID: case ACP71_PCI_ID: + case ACP72_PCI_ID: switch (slots) { case 1 ... 31: no_of_slots = slots; @@ -168,6 +170,7 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas case ACP63_PCI_ID: case ACP70_PCI_ID: case ACP71_PCI_ID: + case ACP72_PCI_ID: if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK) chip->tdm_tx_fmt[stream->dai_id - 1] = FRM_LEN | (slots << 13) | (slot_len << 18); From 0c0ef1d90967717b91cded41b00dbae05d8e521c Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Wed, 2 Jul 2025 15:14:12 +0530 Subject: [PATCH 172/385] ASoC: amd: acp: Enable acp7.2 platform based DMIC support in machine driver Enable acp7.2 platform based DMIC support in machine driver. Signed-off-by: Venkata Prasad Potturu Link: https://patch.msgid.link/20250702094425.155185-4-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-mach-common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index a0dab85088ec..c4bc8e849284 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -1772,6 +1772,7 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) break; case ACP70_PCI_ID: case ACP71_PCI_ID: + case ACP72_PCI_ID: links[i].platforms = platform_acp70_component; links[i].num_platforms = ARRAY_SIZE(platform_acp70_component); break; From 3b8dc31715e31ab930d36ef7b98ffc714344e411 Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Tue, 1 Jul 2025 15:59:14 +0530 Subject: [PATCH 173/385] ASoC: dt-bindings: qcom,sm8250: Add QCS8275 sound card Add bindings for QCS8275 sound card, which looks fully compatible with existing SM8250. Signed-off-by: Prasad Kumpatla Link: https://patch.msgid.link/20250701102915.4016108-2-quic_pkumpatl@quicinc.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,sm8250.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index 590eb177f57a..6b4a8dbdaf61 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -32,6 +32,7 @@ properties: - qcom,apq8096-sndcard - qcom,qcm6490-idp-sndcard - qcom,qcs6490-rb3gen2-sndcard + - qcom,qcs8275-sndcard - qcom,qcs9075-sndcard - qcom,qcs9100-sndcard - qcom,qrb4210-rb2-sndcard From 34d340d48e595f8dfd4e72fe4100d2579dbe4a1a Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Tue, 1 Jul 2025 15:59:15 +0530 Subject: [PATCH 174/385] ASoC: qcom: sc8280xp: Add support for QCS8275 Add compatible for sound card on Qualcomm QCS8275 boards. Signed-off-by: Prasad Kumpatla Link: https://patch.msgid.link/20250701102915.4016108-3-quic_pkumpatl@quicinc.com Signed-off-by: Mark Brown --- sound/soc/qcom/sc8280xp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index 99fd34728e38..73f9f82c4e25 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -186,6 +186,7 @@ static int sc8280xp_platform_probe(struct platform_device *pdev) static const struct of_device_id snd_sc8280xp_dt_match[] = { {.compatible = "qcom,qcm6490-idp-sndcard", "qcm6490"}, {.compatible = "qcom,qcs6490-rb3gen2-sndcard", "qcs6490"}, + {.compatible = "qcom,qcs8275-sndcard", "qcs8275"}, {.compatible = "qcom,qcs9075-sndcard", "qcs9075"}, {.compatible = "qcom,qcs9100-sndcard", "qcs9100"}, {.compatible = "qcom,sc8280xp-sndcard", "sc8280xp"}, From 30cd59961981ae235c59aca61715f6732f65d8cc Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 1 Jul 2025 14:05:25 +0200 Subject: [PATCH 175/385] ALSA: pcmtest: Replace deprecated strcpy() with strscpy() strcpy() is deprecated; use strscpy() instead. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20250701120525.185831-2-thorsten.blum@linux.dev Signed-off-by: Takashi Iwai --- sound/drivers/pcmtest.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/drivers/pcmtest.c b/sound/drivers/pcmtest.c index 39f1e1fe4c44..19b3f306c564 100644 --- a/sound/drivers/pcmtest.c +++ b/sound/drivers/pcmtest.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -555,7 +556,7 @@ static int snd_pcmtst_new_pcm(struct pcmtst *pcmtst) if (err < 0) return err; pcm->private_data = pcmtst; - strcpy(pcm->name, "PCMTest"); + strscpy(pcm->name, "PCMTest"); pcmtst->pcm = pcm; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_pcmtst_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_pcmtst_capture_ops); @@ -613,9 +614,9 @@ static int pcmtst_probe(struct platform_device *pdev) if (err < 0) return err; - strcpy(card->driver, "PCM-TEST Driver"); - strcpy(card->shortname, "PCM-Test"); - strcpy(card->longname, "PCM-Test virtual driver"); + strscpy(card->driver, "PCM-TEST Driver"); + strscpy(card->shortname, "PCM-Test"); + strscpy(card->longname, "PCM-Test virtual driver"); err = snd_card_register(card); if (err < 0) From 9931d2899eec3737f4e4fa9fc900be7329816e94 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 20 Jun 2025 13:52:28 +0800 Subject: [PATCH 176/385] ASoC: fsl_mqs: Distinguish different modules by system manager indices On i.MX94, the MQS2 also needs to be configured by SCMI interface, add sm_index variable in struct fsl_mqs_soc_data to distinguish the MQS1 and MQS2 on this platform. Add the system manager indices for i.MX94 in the header file. Signed-off-by: Shengjiu Wang Reviewed-by: Peng Fan Link: https://patch.msgid.link/20250620055229.965942-2-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- include/linux/firmware/imx/sm.h | 8 ++++++++ sound/soc/fsl/fsl_mqs.c | 11 ++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/include/linux/firmware/imx/sm.h b/include/linux/firmware/imx/sm.h index a8a17eeb7d90..a6220c500f7c 100644 --- a/include/linux/firmware/imx/sm.h +++ b/include/linux/firmware/imx/sm.h @@ -18,6 +18,14 @@ #define SCMI_IMX_CTRL_SAI4_MCLK 4 /* WAKE SAI4 MCLK */ #define SCMI_IMX_CTRL_SAI5_MCLK 5 /* WAKE SAI5 MCLK */ +#define SCMI_IMX94_CTRL_PDM_CLK_SEL 0U /*!< AON PDM clock sel */ +#define SCMI_IMX94_CTRL_MQS1_SETTINGS 1U /*!< AON MQS settings */ +#define SCMI_IMX94_CTRL_MQS2_SETTINGS 2U /*!< WAKE MQS settings */ +#define SCMI_IMX94_CTRL_SAI1_MCLK 3U /*!< AON SAI1 MCLK */ +#define SCMI_IMX94_CTRL_SAI2_MCLK 4U /*!< WAKE SAI2 MCLK */ +#define SCMI_IMX94_CTRL_SAI3_MCLK 5U /*!< WAKE SAI3 MCLK */ +#define SCMI_IMX94_CTRL_SAI4_MCLK 6U /*!< WAKE SAI4 MCLK */ + int scmi_imx_misc_ctrl_get(u32 id, u32 *num, u32 *val); int scmi_imx_misc_ctrl_set(u32 id, u32 val); diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index e34e5ea98de5..11f2f3792dce 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -39,6 +39,7 @@ enum reg_type { * struct fsl_mqs_soc_data - soc specific data * * @type: control register space type + * @sm_index: index from definition in system manager * @ctrl_off: control register offset * @en_mask: enable bit mask * @en_shift: enable bit shift @@ -51,6 +52,7 @@ enum reg_type { */ struct fsl_mqs_soc_data { enum reg_type type; + int sm_index; int ctrl_off; int en_mask; int en_shift; @@ -82,7 +84,7 @@ static int fsl_mqs_sm_read(void *context, unsigned int reg, unsigned int *val) if (IS_ENABLED(CONFIG_IMX_SCMI_MISC_DRV) && mqs_priv->soc->ctrl_off == reg) - return scmi_imx_misc_ctrl_get(SCMI_IMX_CTRL_MQS1_SETTINGS, &num, val); + return scmi_imx_misc_ctrl_get(mqs_priv->soc->sm_index, &num, val); return -EINVAL; }; @@ -93,7 +95,7 @@ static int fsl_mqs_sm_write(void *context, unsigned int reg, unsigned int val) if (IS_ENABLED(CONFIG_IMX_SCMI_MISC_DRV) && mqs_priv->soc->ctrl_off == reg) - return scmi_imx_misc_ctrl_set(SCMI_IMX_CTRL_MQS1_SETTINGS, val); + return scmi_imx_misc_ctrl_set(mqs_priv->soc->sm_index, val); return -EINVAL; }; @@ -386,6 +388,7 @@ static const struct fsl_mqs_soc_data fsl_mqs_imx93_data = { static const struct fsl_mqs_soc_data fsl_mqs_imx95_aon_data = { .type = TYPE_REG_SM, + .sm_index = SCMI_IMX_CTRL_MQS1_SETTINGS, .ctrl_off = 0x88, .en_mask = BIT(1), .en_shift = 1, @@ -412,6 +415,7 @@ static const struct fsl_mqs_soc_data fsl_mqs_imx95_netc_data = { static const struct fsl_mqs_soc_data fsl_mqs_imx943_aon_data = { .type = TYPE_REG_SM, + .sm_index = SCMI_IMX94_CTRL_MQS1_SETTINGS, .ctrl_off = 0x88, .en_mask = BIT(1), .en_shift = 1, @@ -424,7 +428,8 @@ static const struct fsl_mqs_soc_data fsl_mqs_imx943_aon_data = { }; static const struct fsl_mqs_soc_data fsl_mqs_imx943_wakeup_data = { - .type = TYPE_REG_GPR, + .type = TYPE_REG_SM, + .sm_index = SCMI_IMX94_CTRL_MQS2_SETTINGS, .ctrl_off = 0x10, .en_mask = BIT(1), .en_shift = 1, From baee26a9d6cd3d3c6c3c03c56270aa647a67e4bd Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 20 Jun 2025 13:52:29 +0800 Subject: [PATCH 177/385] ASoC: fsl_mqs: rename system manager indices for i.MX95 The system manager indices names are different for each platform, rename the indices for i.MX95 to differentiate with other platform. Signed-off-by: Shengjiu Wang Reviewed-by: Peng Fan Link: https://patch.msgid.link/20250620055229.965942-3-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- include/linux/firmware/imx/sm.h | 12 ++++++------ sound/soc/fsl/fsl_mqs.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/linux/firmware/imx/sm.h b/include/linux/firmware/imx/sm.h index a6220c500f7c..d4212bc42b2c 100644 --- a/include/linux/firmware/imx/sm.h +++ b/include/linux/firmware/imx/sm.h @@ -11,12 +11,12 @@ #include #include -#define SCMI_IMX_CTRL_PDM_CLK_SEL 0 /* AON PDM clock sel */ -#define SCMI_IMX_CTRL_MQS1_SETTINGS 1 /* AON MQS settings */ -#define SCMI_IMX_CTRL_SAI1_MCLK 2 /* AON SAI1 MCLK */ -#define SCMI_IMX_CTRL_SAI3_MCLK 3 /* WAKE SAI3 MCLK */ -#define SCMI_IMX_CTRL_SAI4_MCLK 4 /* WAKE SAI4 MCLK */ -#define SCMI_IMX_CTRL_SAI5_MCLK 5 /* WAKE SAI5 MCLK */ +#define SCMI_IMX95_CTRL_PDM_CLK_SEL 0 /* AON PDM clock sel */ +#define SCMI_IMX95_CTRL_MQS1_SETTINGS 1 /* AON MQS settings */ +#define SCMI_IMX95_CTRL_SAI1_MCLK 2 /* AON SAI1 MCLK */ +#define SCMI_IMX95_CTRL_SAI3_MCLK 3 /* WAKE SAI3 MCLK */ +#define SCMI_IMX95_CTRL_SAI4_MCLK 4 /* WAKE SAI4 MCLK */ +#define SCMI_IMX95_CTRL_SAI5_MCLK 5 /* WAKE SAI5 MCLK */ #define SCMI_IMX94_CTRL_PDM_CLK_SEL 0U /*!< AON PDM clock sel */ #define SCMI_IMX94_CTRL_MQS1_SETTINGS 1U /*!< AON MQS settings */ diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index 11f2f3792dce..901f840df904 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -388,7 +388,7 @@ static const struct fsl_mqs_soc_data fsl_mqs_imx93_data = { static const struct fsl_mqs_soc_data fsl_mqs_imx95_aon_data = { .type = TYPE_REG_SM, - .sm_index = SCMI_IMX_CTRL_MQS1_SETTINGS, + .sm_index = SCMI_IMX95_CTRL_MQS1_SETTINGS, .ctrl_off = 0x88, .en_mask = BIT(1), .en_shift = 1, From 72a600a27ff53aaf94c81d5ddb9795139b56881e Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Thu, 3 Jul 2025 15:42:52 +0200 Subject: [PATCH 178/385] ALSA: mtpav: Replace deprecated strcpy() with strscpy() strcpy() is deprecated; use strscpy() instead. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20250703134255.3948-2-thorsten.blum@linux.dev Signed-off-by: Takashi Iwai --- sound/drivers/mtpav.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index 851f34e2cdd0..91828f496738 100644 --- a/sound/drivers/mtpav.c +++ b/sound/drivers/mtpav.c @@ -46,6 +46,7 @@ #include #include #include +#include /* * globals @@ -605,11 +606,11 @@ static void snd_mtpav_set_name(struct mtpav *chip, else if (substream->number >= 8 && substream->number < chip->num_ports * 2) sprintf(substream->name, "MTP remote %d", (substream->number % chip->num_ports) + 1); else if (substream->number == chip->num_ports * 2) - strcpy(substream->name, "MTP computer"); + strscpy(substream->name, "MTP computer"); else if (substream->number == chip->num_ports * 2 + 1) - strcpy(substream->name, "MTP ADAT"); + strscpy(substream->name, "MTP ADAT"); else - strcpy(substream->name, "MTP broadcast"); + strscpy(substream->name, "MTP broadcast"); } static int snd_mtpav_get_RAWMIDI(struct mtpav *mcard) @@ -697,8 +698,8 @@ static int snd_mtpav_probe(struct platform_device *dev) if (err < 0) return err; - strcpy(card->driver, "MTPAV"); - strcpy(card->shortname, "MTPAV on parallel port"); + strscpy(card->driver, "MTPAV"); + strscpy(card->shortname, "MTPAV on parallel port"); snprintf(card->longname, sizeof(card->longname), "MTPAV on parallel port at 0x%lx", port); From a48d994ca321caaa82cb657eceae7722416a0c07 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Fri, 4 Jul 2025 00:52:36 +0200 Subject: [PATCH 179/385] ALSA: hda: Remove old commented out sanity check The sanity check has been commented out for more than 12 years since commit d5657ec9f4ad ("ALSA: hda - Disable the sanity check in snd_hda_add_pincfg()") - remove it. Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20250703225238.308359-2-thorsten.blum@linux.dev Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 5508381a1833..cb72e9655c8a 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -479,15 +479,6 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, { struct hda_pincfg *pin; - /* the check below may be invalid when pins are added by a fixup - * dynamically (e.g. via snd_hda_codec_update_widgets()), so disabled - * for now - */ - /* - if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) - return -EINVAL; - */ - pin = look_up_pincfg(codec, list, nid); if (!pin) { pin = snd_array_new(list); From 0d3d3d01947b842d3c8934394f5210143a54db4a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 4 Jul 2025 09:11:06 +0200 Subject: [PATCH 180/385] ALSA: hda: Add device entry for QEMU QEMU HD-audio device (1af4:0021) is handled by the generic HD-audio codec driver, hence it's better to have an explicit device ID listing, so that we can avoid the superfluous vendor driver matching. Link: https://patch.msgid.link/20250704071107.14626-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_generic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index b34d84fedcc8..2a28c8b6ba55 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -6144,6 +6144,7 @@ error: } static const struct hda_device_id snd_hda_id_generic[] = { + HDA_CODEC_ENTRY(0x1af40021, "Generic", snd_hda_parse_generic_codec), /* QEMU */ HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC, "Generic", snd_hda_parse_generic_codec), {} /* terminator */ }; From bc163baef57002c08b3afe64cdd2f55f55a765eb Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 3 Jul 2025 13:35:21 -0500 Subject: [PATCH 181/385] ASoC: Use of_reserved_mem_region_to_resource() for "memory-region" Use the newly added of_reserved_mem_region_to_resource() function to handle "memory-region" properties. Signed-off-by: Rob Herring (Arm) Reviewed-by: Tzung-Bi Shih Reviewed-by: Cheng-Yi Chiang Link: https://patch.msgid.link/20250703183523.2075276-1-robh@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/cros_ec_codec.c | 28 +++++++++----------- sound/soc/sof/imx/imx-common.c | 36 +++++--------------------- sound/soc/sof/mediatek/mt8186/mt8186.c | 11 +------- sound/soc/sof/mediatek/mt8195/mt8195.c | 11 +------- 4 files changed, 21 insertions(+), 65 deletions(-) diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index 571222ec520c..937c8cec682a 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -961,7 +962,6 @@ static int cros_ec_codec_platform_probe(struct platform_device *pdev) struct ec_response_ec_codec_get_capabilities r; int ret; #ifdef CONFIG_OF - struct device_node *node; struct resource res; u64 ec_shm_size; const __be32 *regaddr_p; @@ -981,22 +981,18 @@ static int cros_ec_codec_platform_probe(struct platform_device *pdev) priv->ec_shm_addr, priv->ec_shm_len); } - node = of_parse_phandle(dev->of_node, "memory-region", 0); - if (node) { - ret = of_address_to_resource(node, 0, &res); - if (!ret) { - priv->ap_shm_phys_addr = res.start; - priv->ap_shm_len = resource_size(&res); - priv->ap_shm_addr = - (uint64_t)(uintptr_t)devm_ioremap_wc( - dev, priv->ap_shm_phys_addr, - priv->ap_shm_len); - priv->ap_shm_last_alloc = priv->ap_shm_phys_addr; + ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res); + if (!ret) { + priv->ap_shm_phys_addr = res.start; + priv->ap_shm_len = resource_size(&res); + priv->ap_shm_addr = + (uint64_t)(uintptr_t)devm_ioremap_wc( + dev, priv->ap_shm_phys_addr, + priv->ap_shm_len); + priv->ap_shm_last_alloc = priv->ap_shm_phys_addr; - dev_dbg(dev, "ap_shm_phys_addr=%#llx len=%#x\n", - priv->ap_shm_phys_addr, priv->ap_shm_len); - } - of_node_put(node); + dev_dbg(dev, "ap_shm_phys_addr=%#llx len=%#x\n", + priv->ap_shm_phys_addr, priv->ap_shm_len); } #endif diff --git a/sound/soc/sof/imx/imx-common.c b/sound/soc/sof/imx/imx-common.c index 62bf707aa909..f00b381cec3b 100644 --- a/sound/soc/sof/imx/imx-common.c +++ b/sound/soc/sof/imx/imx-common.c @@ -282,11 +282,8 @@ static int imx_region_name_to_blk_type(const char *region_name) static int imx_parse_ioremap_memory(struct snd_sof_dev *sdev) { const struct imx_chip_info *chip_info; - struct reserved_mem *reserved; struct platform_device *pdev; - struct device_node *res_np; - phys_addr_t base, size; - struct resource *res; + struct resource *res, _res; int i, blk_type, ret; pdev = to_platform_device(sdev->dev); @@ -307,37 +304,18 @@ static int imx_parse_ioremap_memory(struct snd_sof_dev *sdev) "failed to fetch %s resource\n", chip_info->memory[i].name); - base = res->start; - size = resource_size(res); } else { - ret = of_property_match_string(pdev->dev.of_node, - "memory-region-names", - chip_info->memory[i].name); + ret = of_reserved_mem_region_to_resource_byname(pdev->dev.of_node, + chip_info->memory[i].name, + &_res); if (ret < 0) return dev_err_probe(sdev->dev, ret, - "no valid index for %s\n", + "no valid entry for %s\n", chip_info->memory[i].name); - - res_np = of_parse_phandle(pdev->dev.of_node, - "memory-region", - ret); - if (!res_np) - return dev_err_probe(sdev->dev, -ENODEV, - "failed to parse phandle %s\n", - chip_info->memory[i].name); - - reserved = of_reserved_mem_lookup(res_np); - of_node_put(res_np); - if (!reserved) - return dev_err_probe(sdev->dev, -ENODEV, - "failed to get %s reserved\n", - chip_info->memory[i].name); - - base = reserved->base; - size = reserved->size; + res = &_res; } - sdev->bar[blk_type] = devm_ioremap(sdev->dev, base, size); + sdev->bar[blk_type] = devm_ioremap_resource(sdev->dev, res); if (!sdev->bar[blk_type]) return dev_err_probe(sdev->dev, -ENOMEM, diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index 7ff080452cbe..c1bea967737d 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -46,7 +45,6 @@ static int platform_parse_resource(struct platform_device *pdev, void *data) { struct resource *mmio; struct resource res; - struct device_node *mem_region; struct device *dev = &pdev->dev; struct mtk_adsp_chip_info *adsp = data; int ret; @@ -57,14 +55,7 @@ static int platform_parse_resource(struct platform_device *pdev, void *data) return ret; } - mem_region = of_parse_phandle(dev->of_node, "memory-region", 1); - if (!mem_region) { - dev_err(dev, "no memory-region sysmem phandle\n"); - return -ENODEV; - } - - ret = of_address_to_resource(mem_region, 0, &res); - of_node_put(mem_region); + ret = of_reserved_mem_region_to_resource(dev->of_node, 1, &res); if (ret) { dev_err(dev, "of_address_to_resource sysmem failed\n"); return ret; diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 3b3582d74510..4d6e9300a9c0 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -46,7 +45,6 @@ static int platform_parse_resource(struct platform_device *pdev, void *data) { struct resource *mmio; struct resource res; - struct device_node *mem_region; struct device *dev = &pdev->dev; struct mtk_adsp_chip_info *adsp = data; int ret; @@ -57,14 +55,7 @@ static int platform_parse_resource(struct platform_device *pdev, void *data) return ret; } - mem_region = of_parse_phandle(dev->of_node, "memory-region", 1); - if (!mem_region) { - dev_err(dev, "no memory-region sysmem phandle\n"); - return -ENODEV; - } - - ret = of_address_to_resource(mem_region, 0, &res); - of_node_put(mem_region); + ret = of_reserved_mem_region_to_resource(dev->of_node, 1, &res); if (ret) { dev_err(dev, "of_address_to_resource sysmem failed\n"); return ret; From 571defe0dff3f1e4180bd0db79283d3d5bf74a71 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 4 Jul 2025 21:09:06 +0800 Subject: [PATCH 182/385] ASoC: codec: rockchip_sai: Remove including of_gpio.h of_gpio.h is deprecated. And there is no user in this driver using API in of_gpio.h, so remove it. Signed-off-by: Peng Fan Acked-by: Nicolas Frattaroli Link: https://patch.msgid.link/20250704130906.1207134-1-peng.fan@nxp.com Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_sai.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c index 0b9f54102d69..6695349ee561 100644 --- a/sound/soc/rockchip/rockchip_sai.c +++ b/sound/soc/rockchip/rockchip_sai.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include From 9069141d1d9c585a20e43037c2f9c00d9d3fc9eb Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 4 Jul 2025 10:54:55 +0300 Subject: [PATCH 183/385] ASoC: atmel: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Signed-off-by: Sakari Ailus Link: https://patch.msgid.link/20250704075455.3222541-1-sakari.ailus@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/atmel/mchp-spdifrx.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/atmel/mchp-spdifrx.c b/sound/soc/atmel/mchp-spdifrx.c index fb820609c043..521bee4998f8 100644 --- a/sound/soc/atmel/mchp-spdifrx.c +++ b/sound/soc/atmel/mchp-spdifrx.c @@ -577,7 +577,6 @@ static int mchp_spdifrx_cs_get(struct mchp_spdifrx_dev *dev, sizeof(ch_stat->data)); pm_runtime_put: - pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); unlock: mutex_unlock(&dev->mlock); @@ -660,7 +659,6 @@ static int mchp_spdifrx_subcode_ch_get(struct mchp_spdifrx_dev *dev, sizeof(user_data->data)); pm_runtime_put: - pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); unlock: mutex_unlock(&dev->mlock); @@ -726,7 +724,6 @@ static int mchp_spdifrx_ulock_get(struct snd_kcontrol *kcontrol, uvalue->value.integer.value[0] = ctrl->ulock; - pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); unlock: mutex_unlock(&dev->mlock); @@ -762,7 +759,6 @@ static int mchp_spdifrx_badf_get(struct snd_kcontrol *kcontrol, ctrl->badf = 0; } - pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); unlock: mutex_unlock(&dev->mlock); @@ -811,7 +807,6 @@ static int mchp_spdifrx_signal_get(struct snd_kcontrol *kcontrol, regmap_read(dev->regmap, SPDIFRX_RSR, &val); } - pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); unlock: @@ -875,7 +870,6 @@ static int mchp_spdifrx_rate_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] = rate / (32 * SPDIFRX_RSR_IFS(val)); pm_runtime_put: - pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); unlock: mutex_unlock(&dev->mlock); From bbe5e3c433a34e7f7bc762c390abb38205f821c5 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 4 Jul 2025 10:54:56 +0300 Subject: [PATCH 184/385] ASoC: codecs: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Signed-off-by: Sakari Ailus Link: https://patch.msgid.link/20250704075456.3222642-1-sakari.ailus@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/arizona-jack.c | 2 -- sound/soc/codecs/cs35l41.c | 2 -- sound/soc/codecs/cs35l45.c | 1 - sound/soc/codecs/cs35l56-sdw.c | 1 - sound/soc/codecs/cs35l56.c | 1 - sound/soc/codecs/cs42l42.c | 1 - sound/soc/codecs/cs42l43-jack.c | 5 ----- sound/soc/codecs/cs42l43.c | 2 -- sound/soc/codecs/cs48l32.c | 1 - sound/soc/codecs/hda.c | 3 --- sound/soc/codecs/max98363.c | 1 - sound/soc/codecs/max98373-sdw.c | 1 - sound/soc/codecs/rt1017-sdca-sdw.c | 1 - sound/soc/codecs/rt1308-sdw.c | 1 - sound/soc/codecs/rt1316-sdw.c | 1 - sound/soc/codecs/rt1318-sdw.c | 1 - sound/soc/codecs/rt1320-sdw.c | 1 - sound/soc/codecs/rt5682-sdw.c | 1 - sound/soc/codecs/rt700.c | 2 -- sound/soc/codecs/rt711-sdca.c | 2 -- sound/soc/codecs/rt711.c | 2 -- sound/soc/codecs/rt712-sdca-dmic.c | 1 - sound/soc/codecs/rt712-sdca.c | 2 -- sound/soc/codecs/rt715-sdca.c | 1 - sound/soc/codecs/rt715.c | 1 - sound/soc/codecs/rt721-sdca.c | 2 -- sound/soc/codecs/rt722-sdca.c | 2 -- sound/soc/codecs/rt9123.c | 3 --- sound/soc/codecs/tas2552.c | 1 - sound/soc/codecs/wcd-mbhc-v2.c | 2 -- sound/soc/codecs/wsa881x.c | 1 - sound/soc/codecs/wsa883x.c | 1 - sound/soc/codecs/wsa884x.c | 1 - 33 files changed, 51 deletions(-) diff --git a/sound/soc/codecs/arizona-jack.c b/sound/soc/codecs/arizona-jack.c index 9c15ddba6008..22f9c431a0e5 100644 --- a/sound/soc/codecs/arizona-jack.c +++ b/sound/soc/codecs/arizona-jack.c @@ -319,7 +319,6 @@ static void arizona_stop_mic(struct arizona_priv *info) if (change) { regulator_disable(info->micvdd); - pm_runtime_mark_last_busy(arizona->dev); pm_runtime_put_autosuspend(arizona->dev); } } @@ -1127,7 +1126,6 @@ out: mutex_unlock(&info->lock); - pm_runtime_mark_last_busy(arizona->dev); pm_runtime_put_autosuspend(arizona->dev); return IRQ_HANDLED; diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index ff4134bee858..224d65987a8d 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -483,7 +483,6 @@ static irqreturn_t cs35l41_irq(int irq, void *data) } done: - pm_runtime_mark_last_busy(cs35l41->dev); pm_runtime_put_autosuspend(cs35l41->dev); return ret; @@ -1328,7 +1327,6 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg * pm_runtime_set_autosuspend_delay(cs35l41->dev, 3000); pm_runtime_use_autosuspend(cs35l41->dev); - pm_runtime_mark_last_busy(cs35l41->dev); pm_runtime_set_active(cs35l41->dev); pm_runtime_get_noresume(cs35l41->dev); pm_runtime_enable(cs35l41->dev); diff --git a/sound/soc/codecs/cs35l45.c b/sound/soc/codecs/cs35l45.c index 432a19f4de2b..d4dcdf37bb70 100644 --- a/sound/soc/codecs/cs35l45.c +++ b/sound/soc/codecs/cs35l45.c @@ -1427,7 +1427,6 @@ int cs35l45_probe(struct cs35l45_private *cs35l45) pm_runtime_set_autosuspend_delay(cs35l45->dev, 3000); pm_runtime_use_autosuspend(cs35l45->dev); - pm_runtime_mark_last_busy(cs35l45->dev); pm_runtime_set_active(cs35l45->dev); pm_runtime_get_noresume(cs35l45->dev); pm_runtime_enable(cs35l45->dev); diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c index 13f602f51bf3..2c722a0ea852 100644 --- a/sound/soc/codecs/cs35l56-sdw.c +++ b/sound/soc/codecs/cs35l56-sdw.c @@ -282,7 +282,6 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral) } out: - pm_runtime_mark_last_busy(cs35l56->base.dev); pm_runtime_put_autosuspend(cs35l56->base.dev); } diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index c78e4746e428..c6658dcc6dd1 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -849,7 +849,6 @@ static void cs35l56_dsp_work(struct work_struct *work) cs35l56_log_tuning(&cs35l56->base, &cs35l56->dsp.cs_dsp); err: - pm_runtime_mark_last_busy(cs35l56->base.dev); pm_runtime_put_autosuspend(cs35l56->base.dev); } diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 56668c392063..78bb093fa0cc 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -1775,7 +1775,6 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data) } mutex_unlock(&cs42l42->irq_lock); - pm_runtime_mark_last_busy(cs42l42->dev); pm_runtime_put_autosuspend(cs42l42->dev); return IRQ_HANDLED; diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c index 6165ac16c3a9..f5c5150c25e5 100644 --- a/sound/soc/codecs/cs42l43-jack.c +++ b/sound/soc/codecs/cs42l43-jack.c @@ -242,7 +242,6 @@ done: error: mutex_unlock(&priv->jack_lock); - pm_runtime_mark_last_busy(priv->dev); pm_runtime_put_autosuspend(priv->dev); return ret; @@ -423,7 +422,6 @@ void cs42l43_button_press_work(struct work_struct *work) error: mutex_unlock(&priv->jack_lock); - pm_runtime_mark_last_busy(priv->dev); pm_runtime_put_autosuspend(priv->dev); } @@ -462,7 +460,6 @@ void cs42l43_button_release_work(struct work_struct *work) mutex_unlock(&priv->jack_lock); - pm_runtime_mark_last_busy(priv->dev); pm_runtime_put_autosuspend(priv->dev); } @@ -504,7 +501,6 @@ void cs42l43_bias_sense_timeout(struct work_struct *work) mutex_unlock(&priv->jack_lock); - pm_runtime_mark_last_busy(priv->dev); pm_runtime_put_autosuspend(priv->dev); } @@ -776,7 +772,6 @@ error: priv->suspend_jack_debounce = false; - pm_runtime_mark_last_busy(priv->dev); pm_runtime_put_autosuspend(priv->dev); } diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c index ea84ac64c775..d84ad8d43438 100644 --- a/sound/soc/codecs/cs42l43.c +++ b/sound/soc/codecs/cs42l43.c @@ -1088,7 +1088,6 @@ static int cs42l43_shutter_get(struct cs42l43_codec *priv, unsigned int shift) ret ? "open" : "closed"); error: - pm_runtime_mark_last_busy(priv->dev); pm_runtime_put_autosuspend(priv->dev); return ret; @@ -2370,7 +2369,6 @@ static int cs42l43_codec_probe(struct platform_device *pdev) goto err_clk; } - pm_runtime_mark_last_busy(priv->dev); pm_runtime_put_autosuspend(priv->dev); return 0; diff --git a/sound/soc/codecs/cs48l32.c b/sound/soc/codecs/cs48l32.c index 90a795230d27..6503f04cf8bb 100644 --- a/sound/soc/codecs/cs48l32.c +++ b/sound/soc/codecs/cs48l32.c @@ -1385,7 +1385,6 @@ static irqreturn_t cs48l32_irq(int irq, void *data) result = IRQ_HANDLED; out: - pm_runtime_mark_last_busy(cs48l32_codec->core.dev); pm_runtime_put_autosuspend(cs48l32_codec->core.dev); return result; diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c index dc7794c9ac44..7e4df1481486 100644 --- a/sound/soc/codecs/hda.c +++ b/sound/soc/codecs/hda.c @@ -162,7 +162,6 @@ int hda_codec_probe_complete(struct hda_codec *codec) snd_hda_codec_register(codec); /* Complement pm_runtime_get_sync(bus) in probe */ - pm_runtime_mark_last_busy(bus->dev); pm_runtime_put_autosuspend(bus->dev); return ret; @@ -262,7 +261,6 @@ device_new_err: snd_hdac_ext_bus_link_put(bus, hlink); - pm_runtime_mark_last_busy(bus->dev); pm_runtime_put_autosuspend(bus->dev); return ret; } @@ -300,7 +298,6 @@ static void hda_codec_remove(struct snd_soc_component *component) * not be called due to early error, leaving bus uc unbalanced */ if (!was_registered) { - pm_runtime_mark_last_busy(bus->dev); pm_runtime_put_autosuspend(bus->dev); } diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c index 950105e5bffd..575331e4bc46 100644 --- a/sound/soc/codecs/max98363.c +++ b/sound/soc/codecs/max98363.c @@ -188,7 +188,6 @@ static int max98363_io_init(struct sdw_slave *slave) max98363->hw_init = true; out: - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index 6088278e6503..143c0384ba0f 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -458,7 +458,6 @@ static int max98373_io_init(struct sdw_slave *slave) max98373->first_hw_init = true; max98373->hw_init = true; - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c index 88fc23a4999f..a9c000876be8 100644 --- a/sound/soc/codecs/rt1017-sdca-sdw.c +++ b/sound/soc/codecs/rt1017-sdca-sdw.c @@ -362,7 +362,6 @@ static int rt1017_sdca_io_init(struct device *dev, struct sdw_slave *slave) /* Mark Slave initialization complete */ rt1017->hw_init = true; - pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); dev_dbg(&slave->dev, "hw_init complete\n"); diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index ea708068f0e8..b6c224832a43 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -291,7 +291,6 @@ _preset_ready_: /* Mark Slave initialization complete */ rt1308->hw_init = true; - pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index 960b6c4f5a66..01a977398864 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -302,7 +302,6 @@ static int rt1316_io_init(struct device *dev, struct sdw_slave *slave) /* Mark Slave initialization complete */ rt1316->hw_init = true; - pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c index 4eb636e0c9ed..70db5450d6d2 100644 --- a/sound/soc/codecs/rt1318-sdw.c +++ b/sound/soc/codecs/rt1318-sdw.c @@ -434,7 +434,6 @@ static int rt1318_io_init(struct device *dev, struct sdw_slave *slave) rt1318->first_hw_init = true; rt1318->hw_init = true; - pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c index 015cc710e6dc..b13d7a99bf63 100644 --- a/sound/soc/codecs/rt1320-sdw.c +++ b/sound/soc/codecs/rt1320-sdw.c @@ -763,7 +763,6 @@ static int rt1320_io_init(struct device *dev, struct sdw_slave *slave) rt1320->first_hw_init = true; rt1320->hw_init = true; - pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index aa229894129b..055bea0a4a3b 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -474,7 +474,6 @@ reinit: rt5682->first_hw_init = true; err_nodev: - pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); dev_dbg(&slave->dev, "%s hw_init complete: %d\n", __func__, ret); diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index 434b926f96c8..8f6d569c8f25 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -338,7 +338,6 @@ static int rt700_set_jack_detect(struct snd_soc_component *component, rt700_jack_init(rt700); - pm_runtime_mark_last_busy(component->dev); pm_runtime_put_autosuspend(component->dev); return 0; @@ -1230,7 +1229,6 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave) /* Mark Slave initialization complete */ rt700->hw_init = true; - pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index dd6ccf17afd4..16c351779243 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -545,7 +545,6 @@ static int rt711_sdca_set_jack_detect(struct snd_soc_component *component, rt711_sdca_jack_init(rt711); - pm_runtime_mark_last_busy(component->dev); pm_runtime_put_autosuspend(component->dev); return 0; @@ -1662,7 +1661,6 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave) /* Mark Slave initialization complete */ rt711->hw_init = true; - pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index 5446f9506a16..af3a49aee618 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -480,7 +480,6 @@ static int rt711_set_jack_detect(struct snd_soc_component *component, rt711_jack_init(rt711); - pm_runtime_mark_last_busy(component->dev); pm_runtime_put_autosuspend(component->dev); return 0; @@ -1331,7 +1330,6 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave) /* Mark Slave initialization complete */ rt711->hw_init = true; - pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c index 4d044dfa3136..42f8f7b8bed0 100644 --- a/sound/soc/codecs/rt712-sdca-dmic.c +++ b/sound/soc/codecs/rt712-sdca-dmic.c @@ -236,7 +236,6 @@ static int rt712_sdca_dmic_io_init(struct device *dev, struct sdw_slave *slave) /* Mark Slave initialization complete */ rt712->hw_init = true; - pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c index 570c2af1245d..5b298db5f0f6 100644 --- a/sound/soc/codecs/rt712-sdca.c +++ b/sound/soc/codecs/rt712-sdca.c @@ -479,7 +479,6 @@ static int rt712_sdca_set_jack_detect(struct snd_soc_component *component, rt712_sdca_jack_init(rt712); - pm_runtime_mark_last_busy(component->dev); pm_runtime_put_autosuspend(component->dev); return 0; @@ -1925,7 +1924,6 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); suspend: - pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); return 0; diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c index 7fb02654c16b..db7d43349d7d 100644 --- a/sound/soc/codecs/rt715-sdca.c +++ b/sound/soc/codecs/rt715-sdca.c @@ -1065,7 +1065,6 @@ int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave) /* Mark Slave initialization complete */ rt715->hw_init = true; - pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); return 0; diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 2cf461852091..0fa445d88e23 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -1129,7 +1129,6 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave) /* Mark Slave initialization complete */ rt715->hw_init = true; - pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); return 0; diff --git a/sound/soc/codecs/rt721-sdca.c b/sound/soc/codecs/rt721-sdca.c index 1c9f32e405cf..2949e3d59049 100644 --- a/sound/soc/codecs/rt721-sdca.c +++ b/sound/soc/codecs/rt721-sdca.c @@ -327,7 +327,6 @@ static int rt721_sdca_set_jack_detect(struct snd_soc_component *component, rt721_sdca_jack_init(rt721); - pm_runtime_mark_last_busy(component->dev); pm_runtime_put_autosuspend(component->dev); return 0; @@ -1533,7 +1532,6 @@ int rt721_sdca_io_init(struct device *dev, struct sdw_slave *slave) /* Mark Slave initialization complete */ rt721->hw_init = true; - pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c index ac9588284a95..333611490ae3 100644 --- a/sound/soc/codecs/rt722-sdca.c +++ b/sound/soc/codecs/rt722-sdca.c @@ -339,7 +339,6 @@ static int rt722_sdca_set_jack_detect(struct snd_soc_component *component, rt722_sdca_jack_init(rt722); - pm_runtime_mark_last_busy(component->dev); pm_runtime_put_autosuspend(component->dev); return 0; @@ -1559,7 +1558,6 @@ int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave) /* Mark Slave initialization complete */ rt722->hw_init = true; - pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); diff --git a/sound/soc/codecs/rt9123.c b/sound/soc/codecs/rt9123.c index 242e8c975a62..b162824526d6 100644 --- a/sound/soc/codecs/rt9123.c +++ b/sound/soc/codecs/rt9123.c @@ -77,7 +77,6 @@ static int rt9123_enable_event(struct snd_soc_dapm_widget *w, struct snd_kcontro /* AMPON bit is located in volatile RG, use pm_runtime to guarantee the RG access */ snd_soc_component_write_field(comp, RT9123_REG_AMPCTRL, RT9123_MASK_AMPON, enable); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; @@ -140,7 +139,6 @@ static int rt9123_xhandler_get(struct snd_kcontrol *kcontrol, struct snd_ctl_ele if (ret < 0) dev_err(dev, "Failed to get control (%d)\n", ret); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; } @@ -168,7 +166,6 @@ static int rt9123_xhandler_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele if (ret < 0) dev_err(dev, "Failed to put control (%d)\n", ret); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; } diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index b56dd279d90a..43449d7c2584 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -724,7 +724,6 @@ static int tas2552_probe(struct i2c_client *client) pm_runtime_set_autosuspend_delay(&client->dev, 1000); pm_runtime_use_autosuspend(&client->dev); pm_runtime_enable(&client->dev); - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_sync_autosuspend(&client->dev); dev_set_drvdata(&client->dev, data); diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index 4b7c3d6080a1..26ebcdadeb7d 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -825,7 +825,6 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) mutex_unlock(&mbhc->lock); - pm_runtime_mark_last_busy(component->dev); pm_runtime_put_autosuspend(component->dev); return 0; @@ -1319,7 +1318,6 @@ exit: if (mbhc->mbhc_cb->hph_pull_down_ctrl) mbhc->mbhc_cb->hph_pull_down_ctrl(component, true); - pm_runtime_mark_last_busy(component->dev); pm_runtime_put_autosuspend(component->dev); } diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index 6627d2da3722..11e9b97754d4 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -775,7 +775,6 @@ static int wsa881x_put_pa_gain(struct snd_kcontrol *kc, usleep_range(1000, 1010); } - pm_runtime_mark_last_busy(comp->dev); pm_runtime_put_autosuspend(comp->dev); return 1; diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index f04d99c66f33..12eaf21774f3 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -1491,7 +1491,6 @@ static int wsa883x_get_temp(struct wsa883x_priv *wsa883x, long *temp) ret = -EAGAIN; } out: - pm_runtime_mark_last_busy(wsa883x->dev); pm_runtime_put_autosuspend(wsa883x->dev); return ret; diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c index fd6ebc25fe89..415c9df9bb16 100644 --- a/sound/soc/codecs/wsa884x.c +++ b/sound/soc/codecs/wsa884x.c @@ -1941,7 +1941,6 @@ static int wsa884x_get_temp(struct wsa884x_priv *wsa884x, long *temp) } out: - pm_runtime_mark_last_busy(wsa884x->dev); pm_runtime_put_autosuspend(wsa884x->dev); return ret; From 077e700cd709b9a0334bd442a1a4090c9de0d152 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 4 Jul 2025 10:54:57 +0300 Subject: [PATCH 185/385] ASoC: Intel: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Signed-off-by: Sakari Ailus Link: https://patch.msgid.link/20250704075457.3222746-1-sakari.ailus@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_pvt.c | 1 - sound/soc/intel/avs/core.c | 1 - sound/soc/intel/avs/debugfs.c | 2 -- sound/soc/intel/avs/ipc.c | 1 - sound/soc/intel/avs/pcm.c | 1 - sound/soc/intel/catpt/pcm.c | 6 ------ sound/soc/intel/catpt/sysfs.c | 1 - 7 files changed, 13 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c index 5d08f7d803f9..c01b29616ebc 100644 --- a/sound/soc/intel/atom/sst/sst_pvt.c +++ b/sound/soc/intel/atom/sst/sst_pvt.c @@ -259,7 +259,6 @@ int sst_pm_runtime_put(struct intel_sst_drv *sst_drv) { int ret; - pm_runtime_mark_last_busy(sst_drv->dev); ret = pm_runtime_put_autosuspend(sst_drv->dev); if (ret < 0) return ret; diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c index ec1b3f55cb5c..7af324753673 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -231,7 +231,6 @@ static void avs_hda_probe_work(struct work_struct *work) /* configure PM */ pm_runtime_set_autosuspend_delay(bus->dev, 2000); pm_runtime_use_autosuspend(bus->dev); - pm_runtime_mark_last_busy(bus->dev); pm_runtime_put_autosuspend(bus->dev); pm_runtime_allow(bus->dev); } diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c index c625cf879f17..f508f215ecd2 100644 --- a/sound/soc/intel/avs/debugfs.c +++ b/sound/soc/intel/avs/debugfs.c @@ -315,7 +315,6 @@ err_ipc: if (!adev->logged_resources) { avs_dsp_enable_d0ix(adev); err_d0ix: - pm_runtime_mark_last_busy(adev->dev); pm_runtime_put_autosuspend(adev->dev); } @@ -342,7 +341,6 @@ static int disable_logs(struct avs_dev *adev, u32 resource_mask) /* If that's the last resource, allow for D3. */ if (!adev->logged_resources) { avs_dsp_enable_d0ix(adev); - pm_runtime_mark_last_busy(adev->dev); pm_runtime_put_autosuspend(adev->dev); } diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c index 0314f9d4ea5f..6bfb9d1a1ca8 100644 --- a/sound/soc/intel/avs/ipc.c +++ b/sound/soc/intel/avs/ipc.c @@ -141,7 +141,6 @@ static void avs_dsp_recovery(struct avs_dev *adev) if (ret < 0) dev_err(adev->dev, "dsp reboot failed: %d\n", ret); - pm_runtime_mark_last_busy(adev->dev); pm_runtime_enable(adev->dev); pm_request_autosuspend(adev->dev); diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index ccf90428126d..3a22a8cb5185 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -979,7 +979,6 @@ static int avs_component_load_libraries(struct avs_soc_component *acomp) if (!ret) ret = avs_module_info_init(adev, false); - pm_runtime_mark_last_busy(adev->dev); pm_runtime_put_autosuspend(adev->dev); return ret; diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c index 81a2f0339e05..46acb7fdc547 100644 --- a/sound/soc/intel/catpt/pcm.c +++ b/sound/soc/intel/catpt/pcm.c @@ -673,7 +673,6 @@ static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm, ret = catpt_ipc_set_device_format(cdev, &devfmt); - pm_runtime_mark_last_busy(cdev->dev); pm_runtime_put_autosuspend(cdev->dev); if (ret) @@ -871,7 +870,6 @@ static int catpt_mixer_volume_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[i] = dspvol_to_ctlvol(dspvol); } - pm_runtime_mark_last_busy(cdev->dev); pm_runtime_put_autosuspend(cdev->dev); return 0; @@ -892,7 +890,6 @@ static int catpt_mixer_volume_put(struct snd_kcontrol *kcontrol, ret = catpt_set_dspvol(cdev, cdev->mixer.mixer_hw_id, ucontrol->value.integer.value); - pm_runtime_mark_last_busy(cdev->dev); pm_runtime_put_autosuspend(cdev->dev); return ret; @@ -927,7 +924,6 @@ static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[i] = dspvol_to_ctlvol(dspvol); } - pm_runtime_mark_last_busy(cdev->dev); pm_runtime_put_autosuspend(cdev->dev); return 0; @@ -958,7 +954,6 @@ static int catpt_stream_volume_put(struct snd_kcontrol *kcontrol, ret = catpt_set_dspvol(cdev, stream->info.stream_hw_id, ucontrol->value.integer.value); - pm_runtime_mark_last_busy(cdev->dev); pm_runtime_put_autosuspend(cdev->dev); if (ret) @@ -1035,7 +1030,6 @@ static int catpt_loopback_switch_put(struct snd_kcontrol *kcontrol, ret = catpt_ipc_mute_loopback(cdev, stream->info.stream_hw_id, mute); - pm_runtime_mark_last_busy(cdev->dev); pm_runtime_put_autosuspend(cdev->dev); if (ret) diff --git a/sound/soc/intel/catpt/sysfs.c b/sound/soc/intel/catpt/sysfs.c index 936ac9d503ff..048253002ec8 100644 --- a/sound/soc/intel/catpt/sysfs.c +++ b/sound/soc/intel/catpt/sysfs.c @@ -21,7 +21,6 @@ static ssize_t fw_version_show(struct device *dev, ret = catpt_ipc_get_fw_version(cdev, &version); - pm_runtime_mark_last_busy(cdev->dev); pm_runtime_put_autosuspend(cdev->dev); if (ret) From e879f14d88c8ce4ecb647d80983f74b2fdd9f18b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 4 Jul 2025 10:54:58 +0300 Subject: [PATCH 186/385] ASoC: component: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Signed-off-by: Sakari Ailus Link: https://patch.msgid.link/20250704075458.3222817-1-sakari.ailus@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-component.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 25f5e543ae8d..65c495094024 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -1278,7 +1278,6 @@ void snd_soc_pcm_component_pm_runtime_put(struct snd_soc_pcm_runtime *rtd, if (rollback && !soc_component_mark_match(component, stream, pm)) continue; - pm_runtime_mark_last_busy(component->dev); pm_runtime_put_autosuspend(component->dev); /* remove marked stream */ From 2bd9648d5a8d329ca734ca2c273a80934867471e Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 4 Jul 2025 10:54:59 +0300 Subject: [PATCH 187/385] ASoC: SOF: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Signed-off-by: Sakari Ailus Acked-by: Peter Ujfalusi Link: https://patch.msgid.link/20250704075459.3222908-1-sakari.ailus@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/control.c | 1 - sound/soc/sof/debug.c | 1 - sound/soc/sof/ipc3-dtrace.c | 1 - sound/soc/sof/ipc4-loader.c | 1 - sound/soc/sof/pcm.c | 1 - sound/soc/sof/sof-client-ipc-flood-test.c | 1 - sound/soc/sof/sof-client-ipc-kernel-injector.c | 1 - sound/soc/sof/sof-client-ipc-msg-injector.c | 1 - sound/soc/sof/sof-client-probes.c | 3 --- 9 files changed, 11 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 463d418e7200..a3fd1d523c09 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -196,7 +196,6 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _ if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_ext_volatile_get) ret = tplg_ops->control->bytes_ext_volatile_get(scontrol, binary_data, size); - pm_runtime_mark_last_busy(scomp->dev); err = pm_runtime_put_autosuspend(scomp->dev); if (err < 0) dev_err_ratelimited(scomp->dev, "%s: failed to idle %d\n", __func__, err); diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index d0ffa1d71145..b24943a65c89 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -217,7 +217,6 @@ static int memory_info_update(struct snd_sof_dev *sdev, char *buf, size_t buff_s } ret = sof_ipc_tx_message(sdev->ipc, &msg, msg.size, reply, SOF_IPC_MSG_MAX_SIZE); - pm_runtime_mark_last_busy(sdev->dev); pm_runtime_put_autosuspend(sdev->dev); if (ret < 0 || reply->rhdr.error < 0) { ret = min(ret, reply->rhdr.error); diff --git a/sound/soc/sof/ipc3-dtrace.c b/sound/soc/sof/ipc3-dtrace.c index 744a91a150bc..e5c8fec173c4 100644 --- a/sound/soc/sof/ipc3-dtrace.c +++ b/sound/soc/sof/ipc3-dtrace.c @@ -172,7 +172,6 @@ static int ipc3_trace_update_filter(struct snd_sof_dev *sdev, int num_elems, goto error; } ret = sof_ipc_tx_message_no_reply(sdev->ipc, msg, msg->hdr.size); - pm_runtime_mark_last_busy(sdev->dev); pm_runtime_put_autosuspend(sdev->dev); error: diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c index d2f534d65edf..6bcdb495267d 100644 --- a/sound/soc/sof/ipc4-loader.c +++ b/sound/soc/sof/ipc4-loader.c @@ -236,7 +236,6 @@ static int sof_ipc4_load_library(struct snd_sof_dev *sdev, unsigned long lib_id, ret = ipc4_data->load_library(sdev, fw_lib, false); - pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) dev_err_ratelimited(sdev->dev, "%s: pm_runtime idle failed: %d\n", diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index d584a72e6f52..c51d61b18db9 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -728,7 +728,6 @@ static int sof_pcm_probe(struct snd_soc_component *component) ret); pm_error: - pm_runtime_mark_last_busy(component->dev); pm_runtime_put_autosuspend(component->dev); return ret; diff --git a/sound/soc/sof/sof-client-ipc-flood-test.c b/sound/soc/sof/sof-client-ipc-flood-test.c index 11b6f7da2882..373f3a125372 100644 --- a/sound/soc/sof/sof-client-ipc-flood-test.c +++ b/sound/soc/sof/sof-client-ipc-flood-test.c @@ -223,7 +223,6 @@ static ssize_t sof_ipc_flood_dfs_write(struct file *file, const char __user *buf ret = sof_debug_ipc_flood_test(cdev, flood_duration_test, ipc_duration_ms, ipc_count); - pm_runtime_mark_last_busy(dev); err = pm_runtime_put_autosuspend(dev); if (err < 0) dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err); diff --git a/sound/soc/sof/sof-client-ipc-kernel-injector.c b/sound/soc/sof/sof-client-ipc-kernel-injector.c index 8b28c3dc920c..249bd2d6c8d2 100644 --- a/sound/soc/sof/sof-client-ipc-kernel-injector.c +++ b/sound/soc/sof/sof-client-ipc-kernel-injector.c @@ -65,7 +65,6 @@ static ssize_t sof_kernel_msg_inject_dfs_write(struct file *file, const char __u sof_client_ipc_rx_message(cdev, hdr, priv->kernel_buffer); - pm_runtime_mark_last_busy(dev); ret = pm_runtime_put_autosuspend(dev); if (ret < 0) dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", ret); diff --git a/sound/soc/sof/sof-client-ipc-msg-injector.c b/sound/soc/sof/sof-client-ipc-msg-injector.c index ba7ca1c5027f..9c8a0fbfb8df 100644 --- a/sound/soc/sof/sof-client-ipc-msg-injector.c +++ b/sound/soc/sof/sof-client-ipc-msg-injector.c @@ -137,7 +137,6 @@ static int sof_msg_inject_send_message(struct sof_client_dev *cdev) if (ret) dev_err(dev, "IPC message send failed: %d\n", ret); - pm_runtime_mark_last_busy(dev); err = pm_runtime_put_autosuspend(dev); if (err < 0) dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err); diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c index aff9ce980429..663c0d3c314c 100644 --- a/sound/soc/sof/sof-client-probes.c +++ b/sound/soc/sof/sof-client-probes.c @@ -238,7 +238,6 @@ static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to, kfree(desc); pm_error: - pm_runtime_mark_last_busy(dev); err = pm_runtime_put_autosuspend(dev); if (err < 0) dev_err_ratelimited(dev, "debugfs read failed to idle %d\n", err); @@ -289,7 +288,6 @@ sof_probes_dfs_points_write(struct file *file, const char __user *from, if (!ret) ret = count; - pm_runtime_mark_last_busy(dev); err = pm_runtime_put_autosuspend(dev); if (err < 0) dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err); @@ -337,7 +335,6 @@ sof_probes_dfs_points_remove_write(struct file *file, const char __user *from, if (!ret) ret = count; - pm_runtime_mark_last_busy(dev); err = pm_runtime_put_autosuspend(dev); if (err < 0) dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err); From a094f846276068d21878b47cf552cf18ee3720fb Mon Sep 17 00:00:00 2001 From: Baojun Xu Date: Sat, 5 Jul 2025 10:53:33 +0800 Subject: [PATCH 188/385] ALSA: hda/tas2781: Add bus name in device name check Device name start from bus name, as we use strstarts() to do compare, need add it for TXNW2781 device. Fixes: b2904df0a347 ("ALSA: hda/tas2781: Add compatible for hardware id TIAS2781 and TXNW2781") Signed-off-by: Baojun Xu Link: https://patch.msgid.link/20250705025333.24346-1-baojun.xu@ti.com Signed-off-by: Takashi Iwai --- sound/pci/hda/tas2781_hda_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index b9cdbca951e4..530c2266ab3b 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -588,7 +588,7 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt) hda_priv->save_calibration = tas2781_save_calibration; tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR; } else if (strstarts(dev_name(&clt->dev), - "TXNW2781:00-tas2781-hda.0")) { + "i2c-TXNW2781:00-tas2781-hda.0")) { device_name = "TXNW2781"; hda_priv->save_calibration = tas2781_save_calibration; tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR; From 6eda9429501508196001845998bb8c73307d311a Mon Sep 17 00:00:00 2001 From: GalaxySnail Date: Tue, 24 Jun 2025 18:17:17 +0800 Subject: [PATCH 189/385] ALSA: hda: add MODULE_FIRMWARE for cs35l41/cs35l56 add firmware information in the .modinfo section, so that userspace tools can find out firmware required by cs35l41/cs35l56 kernel module Signed-off-by: GalaxySnail Reviewed-by: Richard Fitzgerald Link: https://patch.msgid.link/20250624101716.2365302-2-me@glxys.nl Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda.c | 2 ++ sound/pci/hda/cs35l56_hda.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index c2cf3813872a..6155a8d2ef4e 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -2112,3 +2112,5 @@ MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB"); MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, "); MODULE_LICENSE("GPL"); MODULE_IMPORT_NS("FW_CS_DSP"); +MODULE_FIRMWARE("cirrus/cs35l41-*.wmfw"); +MODULE_FIRMWARE("cirrus/cs35l41-*.bin"); diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index 3f2fd32f4ad9..eedd8fdd3b8b 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -1122,3 +1122,7 @@ MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB"); MODULE_AUTHOR("Richard Fitzgerald "); MODULE_AUTHOR("Simon Trimmer "); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("cirrus/cs35l54-*.wmfw"); +MODULE_FIRMWARE("cirrus/cs35l54-*.bin"); +MODULE_FIRMWARE("cirrus/cs35l56-*.wmfw"); +MODULE_FIRMWARE("cirrus/cs35l56-*.bin"); From 5b32627c8ead7534c528bd57e896d0e9dcd4542a Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 4 Jul 2025 10:55:00 +0300 Subject: [PATCH 190/385] ALSA: intel_hdmi: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Signed-off-by: Sakari Ailus Link: https://patch.msgid.link/20250704075500.3222950-1-sakari.ailus@linux.intel.com Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index fe5cb4139088..cc54539c6030 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1102,7 +1102,6 @@ static int had_pcm_open(struct snd_pcm_substream *substream) return retval; error: - pm_runtime_mark_last_busy(intelhaddata->dev); pm_runtime_put_autosuspend(intelhaddata->dev); return retval; } @@ -1127,7 +1126,6 @@ static int had_pcm_close(struct snd_pcm_substream *substream) } spin_unlock_irq(&intelhaddata->had_spinlock); - pm_runtime_mark_last_busy(intelhaddata->dev); pm_runtime_put_autosuspend(intelhaddata->dev); return 0; } @@ -1589,7 +1587,6 @@ static void had_audio_wq(struct work_struct *work) } mutex_unlock(&ctx->mutex); - pm_runtime_mark_last_busy(ctx->dev); pm_runtime_put_autosuspend(ctx->dev); } From fc2f0135a913d0ed3aa5dab2bef193e4e23ca5a7 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 4 Jul 2025 10:54:55 +0300 Subject: [PATCH 191/385] ALSA: hda: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Signed-off-by: Sakari Ailus Link: https://patch.msgid.link/20250704075455.3222438-1-sakari.ailus@linux.intel.com Signed-off-by: Takashi Iwai --- sound/hda/hdac_device.c | 1 - sound/pci/hda/cs35l41_hda.c | 4 ---- sound/pci/hda/cs35l56_hda.c | 1 - sound/pci/hda/tas2781_hda_i2c.c | 3 --- sound/pci/hda/tas2781_hda_spi.c | 4 ---- 5 files changed, 13 deletions(-) diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index 0053831eed2d..a02dce5f6a88 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -581,7 +581,6 @@ int snd_hdac_power_down(struct hdac_device *codec) { struct device *dev = &codec->dev; - pm_runtime_mark_last_busy(dev); return pm_runtime_put_autosuspend(dev); } EXPORT_SYMBOL_GPL(snd_hdac_power_down); diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index 6155a8d2ef4e..2d7ee121a7fd 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -836,7 +836,6 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action) * Playback must be finished for all amps before we start runtime suspend. * This ensures no amps are playing back when we start putting them to sleep. */ - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); break; default: @@ -1284,7 +1283,6 @@ static void cs35l41_fw_load_work(struct work_struct *work) cs35l41->fw_request_ongoing = false; mutex_unlock(&cs35l41->fw_mutex); - pm_runtime_mark_last_busy(cs35l41->dev); pm_runtime_put_autosuspend(cs35l41->dev); } @@ -1515,7 +1513,6 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas dev_warn(dev, "Unable to create device link\n"); unlock_system_sleep(sleep_flags); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); dev_info(cs35l41->dev, @@ -2036,7 +2033,6 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i pm_runtime_set_autosuspend_delay(cs35l41->dev, 3000); pm_runtime_use_autosuspend(cs35l41->dev); - pm_runtime_mark_last_busy(cs35l41->dev); pm_runtime_set_active(cs35l41->dev); pm_runtime_get_noresume(cs35l41->dev); pm_runtime_enable(cs35l41->dev); diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index eedd8fdd3b8b..e8b4995118bb 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -89,7 +89,6 @@ static void cs35l56_hda_pause(struct cs35l56_hda *cs35l56) BIT(CS35L56_ASP_TX1_EN_SHIFT) | BIT(CS35L56_ASP_TX2_EN_SHIFT) | BIT(CS35L56_ASP_TX3_EN_SHIFT) | BIT(CS35L56_ASP_TX4_EN_SHIFT)); - pm_runtime_mark_last_busy(cs35l56->base.dev); pm_runtime_put_autosuspend(cs35l56->base.dev); } diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index 530c2266ab3b..b7ee22840d78 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -157,7 +157,6 @@ static void tas2781_hda_playback_hook(struct device *dev, int action) tas_hda->priv->playback_started = false; mutex_unlock(&tas_hda->priv->codec_lock); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); break; default: @@ -483,7 +482,6 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) out: mutex_unlock(&tas_hda->priv->codec_lock); release_firmware(fmw); - pm_runtime_mark_last_busy(tas_hda->dev); pm_runtime_put_autosuspend(tas_hda->dev); } @@ -526,7 +524,6 @@ static int tas2781_hda_bind(struct device *dev, struct device *master, if (!ret) comp->playback_hook = tas2781_hda_playback_hook; - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; diff --git a/sound/pci/hda/tas2781_hda_spi.c b/sound/pci/hda/tas2781_hda_spi.c index 5c03e9d2283a..c4b9a3c1a7f0 100644 --- a/sound/pci/hda/tas2781_hda_spi.c +++ b/sound/pci/hda/tas2781_hda_spi.c @@ -400,7 +400,6 @@ static void tas2781_hda_playback_hook(struct device *dev, int action) guard(mutex)(&tas_priv->codec_lock); if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK) tasdevice_tuning_switch(tas_priv, 1); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); } } @@ -698,7 +697,6 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) tas2781_save_calibration(tas_hda); out: release_firmware(fmw); - pm_runtime_mark_last_busy(tas_hda->priv->dev); pm_runtime_put_autosuspend(tas_hda->priv->dev); } @@ -731,7 +729,6 @@ static int tas2781_hda_bind(struct device *dev, struct device *master, if (!ret) comp->playback_hook = tas2781_hda_playback_hook; - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -816,7 +813,6 @@ static int tas2781_hda_spi_probe(struct spi_device *spi) pm_runtime_set_autosuspend_delay(tas_priv->dev, 3000); pm_runtime_use_autosuspend(tas_priv->dev); - pm_runtime_mark_last_busy(tas_priv->dev); pm_runtime_set_active(tas_priv->dev); pm_runtime_get_noresume(tas_priv->dev); pm_runtime_enable(tas_priv->dev); From 3263a554f396422b07ab42831c2f106f9596b9f4 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 6 Jul 2025 18:09:03 +0200 Subject: [PATCH 192/385] ALSA: mts64: Replace deprecated strcpy() with strscpy() strcpy() is deprecated; use strscpy() instead. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20250706160906.416270-1-thorsten.blum@linux.dev Signed-off-by: Takashi Iwai --- sound/drivers/mts64.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c index 17f215bad0ec..bbeebbe467ea 100644 --- a/sound/drivers/mts64.c +++ b/sound/drivers/mts64.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -763,7 +764,7 @@ static int snd_mts64_rawmidi_create(struct snd_card *card) return err; rmidi->private_data = mts; - strcpy(rmidi->name, CARD_NAME); + strscpy(rmidi->name, CARD_NAME); rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; @@ -791,7 +792,7 @@ static int snd_mts64_rawmidi_create(struct snd_card *card) mts->midi_input_substream[substream->number] = substream; switch(substream->number) { case MTS64_SMPTE_SUBSTREAM: - strcpy(substream->name, "Miditerminal SMPTE"); + strscpy(substream->name, "Miditerminal SMPTE"); break; default: sprintf(substream->name, @@ -929,8 +930,8 @@ static int snd_mts64_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Cannot create card\n"); return err; } - strcpy(card->driver, DRIVER_NAME); - strcpy(card->shortname, "ESI " CARD_NAME); + strscpy(card->driver, DRIVER_NAME); + strscpy(card->shortname, "ESI " CARD_NAME); sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, p->base, p->irq); From e199e85556bd83806baf4689cbecfa31c41a6cfa Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 1 Jul 2025 00:10:20 +0000 Subject: [PATCH 193/385] ASoC: soc-dapm: remove unnecessary definition Below functions are already defined in soc-dapm.h, it is not necessary in soc-dapm.c. Remove these snd_soc_dapm_new_control() snd_soc_dapm_new_control_unlocked() Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87wm8shitv.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index f26f9e9d7ce7..091ab31ae42d 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -55,14 +55,6 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, int (*connected)(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink)); -struct snd_soc_dapm_widget * -snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_widget *widget); - -struct snd_soc_dapm_widget * -snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_widget *widget); - static unsigned int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg); /* dapm power sequences - make this per codec in the future */ From 58baaea26659ab24ba396afd592c2423aefc067c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 1 Jul 2025 00:10:27 +0000 Subject: [PATCH 194/385] ASoC: soc-dapm: remove EXPORT_SYMBOL_GPL() for snd_soc_dapm_free() snd_soc_dapm_free() is called from soc-dapm.c / soc-core.c only. All these are compiled by snd-soc-core-y. So EXPORT_SYMBOL_GPL() is not needed. Remove it. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87v7ochitp.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 091ab31ae42d..98b35600904d 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -4883,7 +4883,6 @@ void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm) dapm_free_widgets(dapm); list_del(&dapm->list); } -EXPORT_SYMBOL_GPL(snd_soc_dapm_free); void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm, struct snd_soc_card *card, From 2ec1067d1e5acb9e7aeb1fe6d5178424fc3107ab Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 1 Jul 2025 00:10:33 +0000 Subject: [PATCH 195/385] ASoC: soc-dapm: remove snd_soc_dapm_nc_pin[_unlocked]() snd_soc_dapm_nc_pin() was added in commit 5817b52a298a ("ALSA: ASoC: Allow machine drivers to mark pins as not connected") at 2008. It is identical to snd_soc_dapm_disable_pin[_unlocked](). It was expected to be updated, but were enough as-is for this 17 years. We might update these, but renaming function name by define is enough for now. We can re-create these if needed in the future. Let's remove it. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87tt3whitj.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 12 ++++++++-- sound/soc/soc-dapm.c | 51 ---------------------------------------- 2 files changed, 10 insertions(+), 53 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 400584474bc8..2a0250fff9ba 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -498,8 +498,6 @@ int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin); int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin); int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm, const char *pin); int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin); -int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin); -int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin); int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm, const char *pin); int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm); int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm); @@ -509,6 +507,16 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, const char *p unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol); void dapm_mark_endpoints_dirty(struct snd_soc_card *card); +/* + * Marks the specified pin as being not connected, disabling it along + * any parent or child widgets. At present this is identical to + * snd_soc_dapm_disable_pin[_unlocked]() but in future it will be extended to do + * additional things such as disabling controls which only affect + * paths through the pin. + */ +#define snd_soc_dapm_nc_pin snd_soc_dapm_disable_pin +#define snd_soc_dapm_nc_pin_unlocked snd_soc_dapm_disable_pin_unlocked + /* dapm path query */ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, struct snd_soc_dapm_widget_list **list, diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 98b35600904d..e4c2feec6e39 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -4772,57 +4772,6 @@ int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm, } EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); -/** - * snd_soc_dapm_nc_pin_unlocked - permanently disable pin. - * @dapm: DAPM context - * @pin: pin name - * - * Marks the specified pin as being not connected, disabling it along - * any parent or child widgets. At present this is identical to - * snd_soc_dapm_disable_pin() but in future it will be extended to do - * additional things such as disabling controls which only affect - * paths through the pin. - * - * Requires external locking. - * - * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to - * do any widget power switching. - */ -int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm, - const char *pin) -{ - return snd_soc_dapm_set_pin(dapm, pin, 0); -} -EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked); - -/** - * snd_soc_dapm_nc_pin - permanently disable pin. - * @dapm: DAPM context - * @pin: pin name - * - * Marks the specified pin as being not connected, disabling it along - * any parent or child widgets. At present this is identical to - * snd_soc_dapm_disable_pin() but in future it will be extended to do - * additional things such as disabling controls which only affect - * paths through the pin. - * - * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to - * do any widget power switching. - */ -int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin) -{ - int ret; - - snd_soc_dapm_mutex_lock(dapm); - - ret = snd_soc_dapm_set_pin(dapm, pin, 0); - - snd_soc_dapm_mutex_unlock(dapm); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin); - /** * snd_soc_dapm_get_pin_status - get audio pin status * @dapm: DAPM context From d6f240031afbd780431ef289357373e2bbf2f793 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 1 Jul 2025 00:10:39 +0000 Subject: [PATCH 196/385] ASoC: soc-dapm: remove snd_soc_dapm_weak_routes() No one is using snd_soc_dapm_weak_routes(), let's remove it. Because snd_soc_dapm_weak_routes() was removed, path->weak is not needed either. Remove it, too. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87sejghitd.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 3 -- sound/soc/soc-dapm.c | 91 ++-------------------------------------- 2 files changed, 4 insertions(+), 90 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 2a0250fff9ba..6d854c727bca 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -473,8 +473,6 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_route *route, int num); int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_route *route, int num); -int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_route *route, int num); void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w); /* dapm events */ @@ -611,7 +609,6 @@ struct snd_soc_dapm_path { /* status */ u32 connect:1; /* source and sink widgets are connected */ u32 walking:1; /* path is in the process of being walked */ - u32 weak:1; /* path ignored for power management */ u32 is_supply:1; /* At least one of the connected widgets is a supply */ int (*connected)(struct snd_soc_dapm_widget *source, diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index e4c2feec6e39..79cd3c93a4fd 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -214,7 +214,7 @@ static __always_inline void dapm_widget_invalidate_paths( list_for_each_entry(w, &list, work_list) { snd_soc_dapm_widget_for_each_path(w, dir, p) { - if (p->is_supply || p->weak || !p->connect) + if (p->is_supply || !p->connect) continue; node = p->node[rdir]; if (node->endpoints[dir] != -1) { @@ -276,7 +276,7 @@ static void dapm_path_invalidate(struct snd_soc_dapm_path *p) * Weak paths or supply paths do not influence the number of input or * output paths of their neighbors. */ - if (p->weak || p->is_supply) + if (p->is_supply) return; /* @@ -1162,7 +1162,7 @@ static void invalidate_paths_ep(struct snd_soc_dapm_widget *widget, widget->endpoints[dir] = -1; snd_soc_dapm_widget_for_each_path(widget, rdir, path) { - if (path->weak || path->is_supply) + if (path->is_supply) continue; if (path->walking) @@ -1217,7 +1217,7 @@ static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget, snd_soc_dapm_widget_for_each_path(widget, rdir, path) { DAPM_UPDATE_STAT(widget, neighbour_checks); - if (path->weak || path->is_supply) + if (path->is_supply) continue; if (path->walking) @@ -1454,9 +1454,6 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) snd_soc_dapm_widget_for_each_sink_path(w, path) { DAPM_UPDATE_STAT(w, neighbour_checks); - if (path->weak) - continue; - if (path->connected && !path->connected(path->source, path->sink)) continue; @@ -3202,86 +3199,6 @@ int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm, } EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes); -static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_route *route) -{ - struct snd_soc_dapm_widget *source = dapm_find_widget(dapm, - route->source, - true); - struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm, - route->sink, - true); - struct snd_soc_dapm_path *path; - int count = 0; - - if (!source) { - dev_err(dapm->dev, "ASoC: Unable to find source %s for weak route\n", - route->source); - return -ENODEV; - } - - if (!sink) { - dev_err(dapm->dev, "ASoC: Unable to find sink %s for weak route\n", - route->sink); - return -ENODEV; - } - - if (route->control || route->connected) - dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n", - route->source, route->sink); - - snd_soc_dapm_widget_for_each_sink_path(source, path) { - if (path->sink == sink) { - path->weak = 1; - count++; - } - } - - if (count == 0) - dev_err(dapm->dev, "ASoC: No path found for weak route %s->%s\n", - route->source, route->sink); - if (count > 1) - dev_warn(dapm->dev, "ASoC: %d paths found for weak route %s->%s\n", - count, route->source, route->sink); - - return 0; -} - -/** - * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak - * @dapm: DAPM context - * @route: audio routes - * @num: number of routes - * - * Mark existing routes matching those specified in the passed array - * as being weak, meaning that they are ignored for the purpose of - * power decisions. The main intended use case is for sidetone paths - * which couple audio between other independent paths if they are both - * active in order to make the combination work better at the user - * level but which aren't intended to be "used". - * - * Note that CODEC drivers should not use this as sidetone type paths - * can frequently also be used as bypass paths. - */ -int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_route *route, int num) -{ - int i; - int ret = 0; - - snd_soc_dapm_mutex_lock_root(dapm); - for (i = 0; i < num; i++) { - int err = snd_soc_dapm_weak_route(dapm, route); - if (err) - ret = err; - route++; - } - snd_soc_dapm_mutex_unlock(dapm); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes); - /** * snd_soc_dapm_new_widgets - add new dapm widgets * @card: card to be checked for new dapm widgets From 0d516af948536c3fdefadd465a516e1f1317f696 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 1 Jul 2025 00:10:45 +0000 Subject: [PATCH 197/385] ASoC: soc-dapm: reordering function definitions Because functions are defined randomly, it needs function name definitions on top of soc-dapm.c. it is not needed if functions are implemented in correct order. This patch has big change from change-line point of view, but is just reordering, nothing changed in meaning. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87qzz0hit6.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 633 +++++++++++++++++++++---------------------- 1 file changed, 314 insertions(+), 319 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 79cd3c93a4fd..babb642c9655 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -49,14 +49,6 @@ for ((dir) = SND_SOC_DAPM_DIR_IN; (dir) <= SND_SOC_DAPM_DIR_OUT; \ (dir)++) -static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, - struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, - const char *control, - int (*connected)(struct snd_soc_dapm_widget *source, - struct snd_soc_dapm_widget *sink)); - -static unsigned int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg); - /* dapm power sequences - make this per codec in the future */ static int dapm_up_seq[] = { [snd_soc_dapm_pre] = 1, @@ -346,6 +338,320 @@ struct dapm_kcontrol_data { struct snd_soc_dapm_widget_list *wlist; }; +static unsigned int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg) +{ + if (!dapm->component) + return -EIO; + return snd_soc_component_read(dapm->component, reg); +} + +/* set up initial codec paths */ +static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i, + int nth_path) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *) + p->sink->kcontrol_news[i].private_value; + unsigned int reg = mc->reg; + unsigned int invert = mc->invert; + + if (reg != SND_SOC_NOPM) { + unsigned int shift = mc->shift; + unsigned int max = mc->max; + unsigned int mask = (1 << fls(max)) - 1; + unsigned int val = soc_dapm_read(p->sink->dapm, reg); + + /* + * The nth_path argument allows this function to know + * which path of a kcontrol it is setting the initial + * status for. Ideally this would support any number + * of paths and channels. But since kcontrols only come + * in mono and stereo variants, we are limited to 2 + * channels. + * + * The following code assumes for stereo controls the + * first path is the left channel, and all remaining + * paths are the right channel. + */ + if (snd_soc_volsw_is_stereo(mc) && nth_path > 0) { + if (reg != mc->rreg) + val = soc_dapm_read(p->sink->dapm, mc->rreg); + val = (val >> mc->rshift) & mask; + } else { + val = (val >> shift) & mask; + } + if (invert) + val = max - val; + p->connect = !!val; + } else { + /* since a virtual mixer has no backing registers to + * decide which path to connect, it will try to match + * with initial state. This is to ensure + * that the default mixer choice will be + * correctly powered up during initialization. + */ + p->connect = invert; + } +} + +/* connect mux widget to its interconnecting audio paths */ +static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, + struct snd_soc_dapm_path *path, const char *control_name, + struct snd_soc_dapm_widget *w) +{ + const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0]; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int item; + int i; + + if (e->reg != SND_SOC_NOPM) { + unsigned int val; + + val = soc_dapm_read(dapm, e->reg); + val = (val >> e->shift_l) & e->mask; + item = snd_soc_enum_val_to_item(e, val); + } else { + /* since a virtual mux has no backing registers to + * decide which path to connect, it will try to match + * with the first enumeration. This is to ensure + * that the default mux choice (the first) will be + * correctly powered up during initialization. + */ + item = 0; + } + + i = match_string(e->texts, e->items, control_name); + if (i < 0) + return -ENODEV; + + path->name = e->texts[i]; + path->connect = (i == item); + return 0; + +} + +/* connect mixer widget to its interconnecting audio paths */ +static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, + struct snd_soc_dapm_path *path, const char *control_name) +{ + int i, nth_path = 0; + + /* search for mixer kcontrol */ + for (i = 0; i < path->sink->num_kcontrols; i++) { + if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) { + path->name = path->sink->kcontrol_news[i].name; + dapm_set_mixer_path_status(path, i, nth_path++); + return 0; + } + } + return -ENODEV; +} + +/* + * dapm_update_widget_flags() - Re-compute widget sink and source flags + * @w: The widget for which to update the flags + * + * Some widgets have a dynamic category which depends on which neighbors they + * are connected to. This function update the category for these widgets. + * + * This function must be called whenever a path is added or removed to a widget. + */ +static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) +{ + enum snd_soc_dapm_direction dir; + struct snd_soc_dapm_path *p; + unsigned int ep; + + switch (w->id) { + case snd_soc_dapm_input: + /* On a fully routed card an input is never a source */ + if (w->dapm->card->fully_routed) + return; + ep = SND_SOC_DAPM_EP_SOURCE; + snd_soc_dapm_widget_for_each_source_path(w, p) { + if (p->source->id == snd_soc_dapm_micbias || + p->source->id == snd_soc_dapm_mic || + p->source->id == snd_soc_dapm_line || + p->source->id == snd_soc_dapm_output) { + ep = 0; + break; + } + } + break; + case snd_soc_dapm_output: + /* On a fully routed card a output is never a sink */ + if (w->dapm->card->fully_routed) + return; + ep = SND_SOC_DAPM_EP_SINK; + snd_soc_dapm_widget_for_each_sink_path(w, p) { + if (p->sink->id == snd_soc_dapm_spk || + p->sink->id == snd_soc_dapm_hp || + p->sink->id == snd_soc_dapm_line || + p->sink->id == snd_soc_dapm_input) { + ep = 0; + break; + } + } + break; + case snd_soc_dapm_line: + ep = 0; + snd_soc_dapm_for_each_direction(dir) { + if (!list_empty(&w->edges[dir])) + ep |= SND_SOC_DAPM_DIR_TO_EP(dir); + } + break; + default: + return; + } + + w->is_ep = ep; +} + +static int snd_soc_dapm_check_dynamic_path( + struct snd_soc_dapm_context *dapm, + struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink, + const char *control) +{ + bool dynamic_source = false; + bool dynamic_sink = false; + + if (!control) + return 0; + + switch (source->id) { + case snd_soc_dapm_demux: + dynamic_source = true; + break; + default: + break; + } + + switch (sink->id) { + case snd_soc_dapm_mux: + case snd_soc_dapm_switch: + case snd_soc_dapm_mixer: + case snd_soc_dapm_mixer_named_ctl: + dynamic_sink = true; + break; + default: + break; + } + + if (dynamic_source && dynamic_sink) { + dev_err(dapm->dev, + "Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n", + source->name, control, sink->name); + return -EINVAL; + } else if (!dynamic_source && !dynamic_sink) { + dev_err(dapm->dev, + "Control not supported for path %s -> [%s] -> %s\n", + source->name, control, sink->name); + return -EINVAL; + } + + return 0; +} + +static int snd_soc_dapm_add_path( + struct snd_soc_dapm_context *dapm, + struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, + const char *control, + int (*connected)(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink)) +{ + enum snd_soc_dapm_direction dir; + struct snd_soc_dapm_path *path; + int ret; + + if (wsink->is_supply && !wsource->is_supply) { + dev_err(dapm->dev, + "Connecting non-supply widget to supply widget is not supported (%s -> %s)\n", + wsource->name, wsink->name); + return -EINVAL; + } + + if (connected && !wsource->is_supply) { + dev_err(dapm->dev, + "connected() callback only supported for supply widgets (%s -> %s)\n", + wsource->name, wsink->name); + return -EINVAL; + } + + if (wsource->is_supply && control) { + dev_err(dapm->dev, + "Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n", + wsource->name, control, wsink->name); + return -EINVAL; + } + + ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control); + if (ret) + return ret; + + path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); + if (!path) + return -ENOMEM; + + path->node[SND_SOC_DAPM_DIR_IN] = wsource; + path->node[SND_SOC_DAPM_DIR_OUT] = wsink; + + path->connected = connected; + INIT_LIST_HEAD(&path->list); + INIT_LIST_HEAD(&path->list_kcontrol); + + if (wsource->is_supply || wsink->is_supply) + path->is_supply = 1; + + /* connect static paths */ + if (control == NULL) { + path->connect = 1; + } else { + switch (wsource->id) { + case snd_soc_dapm_demux: + ret = dapm_connect_mux(dapm, path, control, wsource); + if (ret) + goto err; + break; + default: + break; + } + + switch (wsink->id) { + case snd_soc_dapm_mux: + ret = dapm_connect_mux(dapm, path, control, wsink); + if (ret != 0) + goto err; + break; + case snd_soc_dapm_switch: + case snd_soc_dapm_mixer: + case snd_soc_dapm_mixer_named_ctl: + ret = dapm_connect_mixer(dapm, path, control); + if (ret != 0) + goto err; + break; + default: + break; + } + } + + list_add(&path->list, &dapm->card->paths); + + snd_soc_dapm_for_each_direction(dir) + list_add(&path->list_node[dir], &path->node[dir]->edges[dir]); + + snd_soc_dapm_for_each_direction(dir) { + dapm_update_widget_flags(path->node[dir]); + dapm_mark_dirty(path->node[dir], "Route added"); + } + + if (snd_soc_card_is_instantiated(dapm->card) && path->connect) + dapm_path_invalidate(path); + + return 0; +err: + kfree(path); + return ret; +} + static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, struct snd_kcontrol *kcontrol, const char *ctrl_name) { @@ -618,13 +924,6 @@ static const char *soc_dapm_prefix(struct snd_soc_dapm_context *dapm) return dapm->component->name_prefix; } -static unsigned int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg) -{ - if (!dapm->component) - return -EIO; - return snd_soc_component_read(dapm->component, reg); -} - static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm, int reg, unsigned int mask, unsigned int value) { @@ -734,106 +1033,6 @@ out: return ret; } -/* connect mux widget to its interconnecting audio paths */ -static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, - struct snd_soc_dapm_path *path, const char *control_name, - struct snd_soc_dapm_widget *w) -{ - const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0]; - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned int item; - int i; - - if (e->reg != SND_SOC_NOPM) { - unsigned int val; - val = soc_dapm_read(dapm, e->reg); - val = (val >> e->shift_l) & e->mask; - item = snd_soc_enum_val_to_item(e, val); - } else { - /* since a virtual mux has no backing registers to - * decide which path to connect, it will try to match - * with the first enumeration. This is to ensure - * that the default mux choice (the first) will be - * correctly powered up during initialization. - */ - item = 0; - } - - i = match_string(e->texts, e->items, control_name); - if (i < 0) - return -ENODEV; - - path->name = e->texts[i]; - path->connect = (i == item); - return 0; - -} - -/* set up initial codec paths */ -static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i, - int nth_path) -{ - struct soc_mixer_control *mc = (struct soc_mixer_control *) - p->sink->kcontrol_news[i].private_value; - unsigned int reg = mc->reg; - unsigned int invert = mc->invert; - - if (reg != SND_SOC_NOPM) { - unsigned int shift = mc->shift; - unsigned int max = mc->max; - unsigned int mask = (1 << fls(max)) - 1; - unsigned int val = soc_dapm_read(p->sink->dapm, reg); - - /* - * The nth_path argument allows this function to know - * which path of a kcontrol it is setting the initial - * status for. Ideally this would support any number - * of paths and channels. But since kcontrols only come - * in mono and stereo variants, we are limited to 2 - * channels. - * - * The following code assumes for stereo controls the - * first path is the left channel, and all remaining - * paths are the right channel. - */ - if (snd_soc_volsw_is_stereo(mc) && nth_path > 0) { - if (reg != mc->rreg) - val = soc_dapm_read(p->sink->dapm, mc->rreg); - val = (val >> mc->rshift) & mask; - } else { - val = (val >> shift) & mask; - } - if (invert) - val = max - val; - p->connect = !!val; - } else { - /* since a virtual mixer has no backing registers to - * decide which path to connect, it will try to match - * with initial state. This is to ensure - * that the default mixer choice will be - * correctly powered up during initialization. - */ - p->connect = invert; - } -} - -/* connect mixer widget to its interconnecting audio paths */ -static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, - struct snd_soc_dapm_path *path, const char *control_name) -{ - int i, nth_path = 0; - - /* search for mixer kcontrol */ - for (i = 0; i < path->sink->num_kcontrols; i++) { - if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) { - path->name = path->sink->kcontrol_news[i].name; - dapm_set_mixer_path_status(path, i, nth_path++); - return 0; - } - } - return -ENODEV; -} - static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm, struct snd_soc_dapm_widget *kcontrolw, const struct snd_kcontrol_new *kcontrol_new, @@ -2783,210 +2982,6 @@ int snd_soc_dapm_widget_name_cmp(struct snd_soc_dapm_widget *widget, const char } EXPORT_SYMBOL_GPL(snd_soc_dapm_widget_name_cmp); -/* - * dapm_update_widget_flags() - Re-compute widget sink and source flags - * @w: The widget for which to update the flags - * - * Some widgets have a dynamic category which depends on which neighbors they - * are connected to. This function update the category for these widgets. - * - * This function must be called whenever a path is added or removed to a widget. - */ -static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) -{ - enum snd_soc_dapm_direction dir; - struct snd_soc_dapm_path *p; - unsigned int ep; - - switch (w->id) { - case snd_soc_dapm_input: - /* On a fully routed card an input is never a source */ - if (w->dapm->card->fully_routed) - return; - ep = SND_SOC_DAPM_EP_SOURCE; - snd_soc_dapm_widget_for_each_source_path(w, p) { - if (p->source->id == snd_soc_dapm_micbias || - p->source->id == snd_soc_dapm_mic || - p->source->id == snd_soc_dapm_line || - p->source->id == snd_soc_dapm_output) { - ep = 0; - break; - } - } - break; - case snd_soc_dapm_output: - /* On a fully routed card a output is never a sink */ - if (w->dapm->card->fully_routed) - return; - ep = SND_SOC_DAPM_EP_SINK; - snd_soc_dapm_widget_for_each_sink_path(w, p) { - if (p->sink->id == snd_soc_dapm_spk || - p->sink->id == snd_soc_dapm_hp || - p->sink->id == snd_soc_dapm_line || - p->sink->id == snd_soc_dapm_input) { - ep = 0; - break; - } - } - break; - case snd_soc_dapm_line: - ep = 0; - snd_soc_dapm_for_each_direction(dir) { - if (!list_empty(&w->edges[dir])) - ep |= SND_SOC_DAPM_DIR_TO_EP(dir); - } - break; - default: - return; - } - - w->is_ep = ep; -} - -static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm, - struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink, - const char *control) -{ - bool dynamic_source = false; - bool dynamic_sink = false; - - if (!control) - return 0; - - switch (source->id) { - case snd_soc_dapm_demux: - dynamic_source = true; - break; - default: - break; - } - - switch (sink->id) { - case snd_soc_dapm_mux: - case snd_soc_dapm_switch: - case snd_soc_dapm_mixer: - case snd_soc_dapm_mixer_named_ctl: - dynamic_sink = true; - break; - default: - break; - } - - if (dynamic_source && dynamic_sink) { - dev_err(dapm->dev, - "Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n", - source->name, control, sink->name); - return -EINVAL; - } else if (!dynamic_source && !dynamic_sink) { - dev_err(dapm->dev, - "Control not supported for path %s -> [%s] -> %s\n", - source->name, control, sink->name); - return -EINVAL; - } - - return 0; -} - -static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, - struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, - const char *control, - int (*connected)(struct snd_soc_dapm_widget *source, - struct snd_soc_dapm_widget *sink)) -{ - enum snd_soc_dapm_direction dir; - struct snd_soc_dapm_path *path; - int ret; - - if (wsink->is_supply && !wsource->is_supply) { - dev_err(dapm->dev, - "Connecting non-supply widget to supply widget is not supported (%s -> %s)\n", - wsource->name, wsink->name); - return -EINVAL; - } - - if (connected && !wsource->is_supply) { - dev_err(dapm->dev, - "connected() callback only supported for supply widgets (%s -> %s)\n", - wsource->name, wsink->name); - return -EINVAL; - } - - if (wsource->is_supply && control) { - dev_err(dapm->dev, - "Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n", - wsource->name, control, wsink->name); - return -EINVAL; - } - - ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control); - if (ret) - return ret; - - path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); - if (!path) - return -ENOMEM; - - path->node[SND_SOC_DAPM_DIR_IN] = wsource; - path->node[SND_SOC_DAPM_DIR_OUT] = wsink; - - path->connected = connected; - INIT_LIST_HEAD(&path->list); - INIT_LIST_HEAD(&path->list_kcontrol); - - if (wsource->is_supply || wsink->is_supply) - path->is_supply = 1; - - /* connect static paths */ - if (control == NULL) { - path->connect = 1; - } else { - switch (wsource->id) { - case snd_soc_dapm_demux: - ret = dapm_connect_mux(dapm, path, control, wsource); - if (ret) - goto err; - break; - default: - break; - } - - switch (wsink->id) { - case snd_soc_dapm_mux: - ret = dapm_connect_mux(dapm, path, control, wsink); - if (ret != 0) - goto err; - break; - case snd_soc_dapm_switch: - case snd_soc_dapm_mixer: - case snd_soc_dapm_mixer_named_ctl: - ret = dapm_connect_mixer(dapm, path, control); - if (ret != 0) - goto err; - break; - default: - break; - } - } - - list_add(&path->list, &dapm->card->paths); - - snd_soc_dapm_for_each_direction(dir) - list_add(&path->list_node[dir], &path->node[dir]->edges[dir]); - - snd_soc_dapm_for_each_direction(dir) { - dapm_update_widget_flags(path->node[dir]); - dapm_mark_dirty(path->node[dir], "Route added"); - } - - if (snd_soc_card_is_instantiated(dapm->card) && path->connect) - dapm_path_invalidate(path); - - return 0; -err: - kfree(path); - return ret; -} - static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_route *route) { From f02ccc8c0b99382807bac0065918a90ba974e9ab Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 1 Jul 2025 00:10:51 +0000 Subject: [PATCH 198/385] ASoC: soc-dapm: reordering header definitions Because header defined randomly, it needs name definitions on top of soc-dapm.h. it is not needed if definitions are implemented in correct order. This patch has big change from change-line point of view, but is just reordering, nothing changed in meaning. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87plekhit0.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 235 ++++++++++++++++++--------------------- 1 file changed, 110 insertions(+), 125 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 6d854c727bca..5aeb0822ce0b 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -16,9 +16,10 @@ #include struct device; +struct regulator; +struct soc_enum; struct snd_pcm_substream; struct snd_soc_pcm_runtime; -struct soc_enum; /* widget has no PM register bit */ #define SND_SOC_NOPM -1 @@ -399,17 +400,6 @@ struct soc_enum; /* regulator widget flags */ #define SND_SOC_DAPM_REGULATOR_BYPASS 0x1 /* bypass when disabled */ -struct snd_soc_dapm_widget; -enum snd_soc_dapm_type; -struct snd_soc_dapm_path; -struct snd_soc_dapm_pin; -struct snd_soc_dapm_route; -struct snd_soc_dapm_context; -struct regulator; -struct snd_soc_dapm_widget_list; -struct snd_soc_dapm_update; -enum snd_soc_dapm_direction; - /* * Bias levels * @@ -428,104 +418,6 @@ enum snd_soc_bias_level { SND_SOC_BIAS_ON = 3, }; -int dapm_regulator_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); -int dapm_clock_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); -int dapm_pinctrl_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); - -/* dapm controls */ -int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo); -int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *uncontrol); -int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *uncontrol); -int snd_soc_dapm_get_component_pin_switch(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *uncontrol); -int snd_soc_dapm_put_component_pin_switch(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *uncontrol); -int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_widget *widget, unsigned int num); -struct snd_soc_dapm_widget *snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_widget *widget); -struct snd_soc_dapm_widget *snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_widget *widget); -int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, struct snd_soc_dai *dai); -void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w); -int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card); -void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card); - -int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, struct snd_soc_dai *dai); -int snd_soc_dapm_widget_name_cmp(struct snd_soc_dapm_widget *widget, const char *s); - -/* dapm path setup */ -int snd_soc_dapm_new_widgets(struct snd_soc_card *card); -void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm); -void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm, - struct snd_soc_card *card, struct snd_soc_component *component); -int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_route *route, int num); -int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_route *route, int num); -void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w); - -/* dapm events */ -void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, int event); -void snd_soc_dapm_stream_stop(struct snd_soc_pcm_runtime *rtd, int stream); -void snd_soc_dapm_shutdown(struct snd_soc_card *card); - -/* external DAPM widget events */ -int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm, - struct snd_kcontrol *kcontrol, int connect, struct snd_soc_dapm_update *update); -int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm, - struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e, - struct snd_soc_dapm_update *update); - -/* dapm sys fs - used by the core */ -extern struct attribute *soc_dapm_dev_attrs[]; -void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, struct dentry *parent); - -/* dapm audio pin control and status */ -int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin); -int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin); -int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm, const char *pin); -int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin); -int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm, const char *pin); -int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm); -int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm); -int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin); -int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin); -int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, const char *pin); -unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol); -void dapm_mark_endpoints_dirty(struct snd_soc_card *card); - -/* - * Marks the specified pin as being not connected, disabling it along - * any parent or child widgets. At present this is identical to - * snd_soc_dapm_disable_pin[_unlocked]() but in future it will be extended to do - * additional things such as disabling controls which only affect - * paths through the pin. - */ -#define snd_soc_dapm_nc_pin snd_soc_dapm_disable_pin -#define snd_soc_dapm_nc_pin_unlocked snd_soc_dapm_disable_pin_unlocked - -/* dapm path query */ -int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, - struct snd_soc_dapm_widget_list **list, - bool (*custom_stop_condition)(struct snd_soc_dapm_widget *, enum snd_soc_dapm_direction)); -void snd_soc_dapm_dai_free_widgets(struct snd_soc_dapm_widget_list **list); - -struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(struct snd_kcontrol *kcontrol); -struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(struct snd_kcontrol *kcontrol); - -int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level); - /* dapm widget types */ enum snd_soc_dapm_type { snd_soc_dapm_input = 0, /* input pin */ @@ -717,11 +609,6 @@ struct snd_soc_dapm_widget_list { struct snd_soc_dapm_widget *widgets[] __counted_by(num_widgets); }; -#define for_each_dapm_widgets(list, i, widget) \ - for ((i) = 0; \ - (i) < list->num_widgets && (widget = list->widgets[i]); \ - (i)++) - struct snd_soc_dapm_stats { int power_checks; int path_checks; @@ -733,6 +620,114 @@ struct snd_soc_dapm_pinctrl_priv { const char *sleep_state; }; +enum snd_soc_dapm_direction { + SND_SOC_DAPM_DIR_IN, + SND_SOC_DAPM_DIR_OUT +}; + +#define SND_SOC_DAPM_DIR_TO_EP(x) BIT(x) + +#define SND_SOC_DAPM_EP_SOURCE SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_IN) +#define SND_SOC_DAPM_EP_SINK SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_OUT) + +int dapm_regulator_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); +int dapm_clock_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); +int dapm_pinctrl_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); + +/* dapm controls */ +int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); +int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uncontrol); +int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uncontrol); +int snd_soc_dapm_get_component_pin_switch(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uncontrol); +int snd_soc_dapm_put_component_pin_switch(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uncontrol); +int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, + const struct snd_soc_dapm_widget *widget, unsigned int num); +struct snd_soc_dapm_widget *snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, + const struct snd_soc_dapm_widget *widget); +struct snd_soc_dapm_widget *snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, + const struct snd_soc_dapm_widget *widget); +int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, struct snd_soc_dai *dai); +void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w); +int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card); +void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card); + +int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai); +int snd_soc_dapm_widget_name_cmp(struct snd_soc_dapm_widget *widget, const char *s); + +/* dapm path setup */ +int snd_soc_dapm_new_widgets(struct snd_soc_card *card); +void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm); +void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm, + struct snd_soc_card *card, struct snd_soc_component *component); +int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, + const struct snd_soc_dapm_route *route, int num); +int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm, + const struct snd_soc_dapm_route *route, int num); +void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w); + +/* dapm events */ +void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, int event); +void snd_soc_dapm_stream_stop(struct snd_soc_pcm_runtime *rtd, int stream); +void snd_soc_dapm_shutdown(struct snd_soc_card *card); + +/* external DAPM widget events */ +int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm, + struct snd_kcontrol *kcontrol, int connect, struct snd_soc_dapm_update *update); +int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm, + struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e, + struct snd_soc_dapm_update *update); + +/* dapm sys fs - used by the core */ +extern struct attribute *soc_dapm_dev_attrs[]; +void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, struct dentry *parent); + +/* dapm audio pin control and status */ +int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin); +int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin); +int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm, const char *pin); +int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin); +int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm, const char *pin); +int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm); +int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm); +int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin); +int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin); +int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, const char *pin); +unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol); +void dapm_mark_endpoints_dirty(struct snd_soc_card *card); + +/* + * Marks the specified pin as being not connected, disabling it along + * any parent or child widgets. At present this is identical to + * snd_soc_dapm_disable_pin[_unlocked]() but in future it will be extended to do + * additional things such as disabling controls which only affect + * paths through the pin. + */ +#define snd_soc_dapm_nc_pin snd_soc_dapm_disable_pin +#define snd_soc_dapm_nc_pin_unlocked snd_soc_dapm_disable_pin_unlocked + +/* dapm path query */ +int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, + struct snd_soc_dapm_widget_list **list, + bool (*custom_stop_condition)(struct snd_soc_dapm_widget *, enum snd_soc_dapm_direction)); +void snd_soc_dapm_dai_free_widgets(struct snd_soc_dapm_widget_list **list); + +struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(struct snd_kcontrol *kcontrol); +struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(struct snd_kcontrol *kcontrol); + +int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level); + +#define for_each_dapm_widgets(list, i, widget) \ + for ((i) = 0; \ + (i) < list->num_widgets && (widget = list->widgets[i]); \ + (i)++) + /** * snd_soc_dapm_init_bias_level() - Initialize DAPM bias level * @dapm: The DAPM context to initialize @@ -764,16 +759,6 @@ static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level( return dapm->bias_level; } -enum snd_soc_dapm_direction { - SND_SOC_DAPM_DIR_IN, - SND_SOC_DAPM_DIR_OUT -}; - -#define SND_SOC_DAPM_DIR_TO_EP(x) BIT(x) - -#define SND_SOC_DAPM_EP_SOURCE SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_IN) -#define SND_SOC_DAPM_EP_SINK SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_OUT) - /** * snd_soc_dapm_widget_for_each_path - Iterates over all paths in the * specified direction of a widget From fbd09117a38e5ff477040629f7b5fc442883746a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 1 Jul 2025 00:10:57 +0000 Subject: [PATCH 199/385] ASoC: soc-dapm: use component instead of cmpnt Use normal "component" instead of short "cmpnt" Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87o6u4hisu.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index babb642c9655..d4cf047bc93e 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2628,10 +2628,10 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm, } EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); -static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt, +static ssize_t dapm_widget_show_component(struct snd_soc_component *component, char *buf, int count) { - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct snd_soc_dapm_widget *w; char *state = "not set"; @@ -2639,10 +2639,10 @@ static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt, * we're checking for that case specifically here but in future * we will ensure that the dummy component looks like others. */ - if (!cmpnt->card) + if (!component->card) return 0; - for_each_card_widgets(cmpnt->card, w) { + for_each_card_widgets(component->card, w) { if (w->dapm != dapm) continue; @@ -2703,9 +2703,9 @@ static ssize_t dapm_widget_show(struct device *dev, snd_soc_dapm_mutex_lock_root(rtd->card); for_each_rtd_codec_dais(rtd, i, codec_dai) { - struct snd_soc_component *cmpnt = codec_dai->component; + struct snd_soc_component *component = codec_dai->component; - count = dapm_widget_show_component(cmpnt, buf, count); + count = dapm_widget_show_component(component, buf, count); } snd_soc_dapm_mutex_unlock(rtd->card); From 1ac23653840f784d0f5846ac253d04ecef9a26f6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 1 Jul 2025 00:11:03 +0000 Subject: [PATCH 200/385] ASoC: soc-dapm: use common name for dapm Let's use "dapm", instead of "d". This is prepare for dapm cleanup. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87ms9ohisp.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 58 ++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index d4cf047bc93e..16f8eff42835 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1985,29 +1985,29 @@ static void dapm_widget_update(struct snd_soc_card *card, struct snd_soc_dapm_up */ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie) { - struct snd_soc_dapm_context *d = data; + struct snd_soc_dapm_context *dapm = data; int ret; /* If we're off and we're not supposed to go into STANDBY */ - if (d->bias_level == SND_SOC_BIAS_OFF && - d->target_bias_level != SND_SOC_BIAS_OFF) { - if (d->dev && cookie) - pm_runtime_get_sync(d->dev); + if (dapm->bias_level == SND_SOC_BIAS_OFF && + dapm->target_bias_level != SND_SOC_BIAS_OFF) { + if (dapm->dev && cookie) + pm_runtime_get_sync(dapm->dev); - ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); + ret = snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_STANDBY); if (ret != 0) - dev_err(d->dev, + dev_err(dapm->dev, "ASoC: Failed to turn on bias: %d\n", ret); } /* Prepare for a transition to ON or away from ON */ - if ((d->target_bias_level == SND_SOC_BIAS_ON && - d->bias_level != SND_SOC_BIAS_ON) || - (d->target_bias_level != SND_SOC_BIAS_ON && - d->bias_level == SND_SOC_BIAS_ON)) { - ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE); + if ((dapm->target_bias_level == SND_SOC_BIAS_ON && + dapm->bias_level != SND_SOC_BIAS_ON) || + (dapm->target_bias_level != SND_SOC_BIAS_ON && + dapm->bias_level == SND_SOC_BIAS_ON)) { + ret = snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_PREPARE); if (ret != 0) - dev_err(d->dev, + dev_err(dapm->dev, "ASoC: Failed to prepare bias: %d\n", ret); } } @@ -2017,37 +2017,37 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie) */ static void dapm_post_sequence_async(void *data, async_cookie_t cookie) { - struct snd_soc_dapm_context *d = data; + struct snd_soc_dapm_context *dapm = data; int ret; /* If we just powered the last thing off drop to standby bias */ - if (d->bias_level == SND_SOC_BIAS_PREPARE && - (d->target_bias_level == SND_SOC_BIAS_STANDBY || - d->target_bias_level == SND_SOC_BIAS_OFF)) { - ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); + if (dapm->bias_level == SND_SOC_BIAS_PREPARE && + (dapm->target_bias_level == SND_SOC_BIAS_STANDBY || + dapm->target_bias_level == SND_SOC_BIAS_OFF)) { + ret = snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_STANDBY); if (ret != 0) - dev_err(d->dev, "ASoC: Failed to apply standby bias: %d\n", + dev_err(dapm->dev, "ASoC: Failed to apply standby bias: %d\n", ret); } /* If we're in standby and can support bias off then do that */ - if (d->bias_level == SND_SOC_BIAS_STANDBY && - d->target_bias_level == SND_SOC_BIAS_OFF) { - ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF); + if (dapm->bias_level == SND_SOC_BIAS_STANDBY && + dapm->target_bias_level == SND_SOC_BIAS_OFF) { + ret = snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_OFF); if (ret != 0) - dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n", + dev_err(dapm->dev, "ASoC: Failed to turn off bias: %d\n", ret); - if (d->dev && cookie) - pm_runtime_put(d->dev); + if (dapm->dev && cookie) + pm_runtime_put(dapm->dev); } /* If we just powered up then move to active bias */ - if (d->bias_level == SND_SOC_BIAS_PREPARE && - d->target_bias_level == SND_SOC_BIAS_ON) { - ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON); + if (dapm->bias_level == SND_SOC_BIAS_PREPARE && + dapm->target_bias_level == SND_SOC_BIAS_ON) { + ret = snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_ON); if (ret != 0) - dev_err(d->dev, "ASoC: Failed to apply active bias: %d\n", + dev_err(dapm->dev, "ASoC: Failed to apply active bias: %d\n", ret); } } From 805c019fbb94795e391974f673c5b3e57b825f6d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 1 Jul 2025 00:11:08 +0000 Subject: [PATCH 201/385] ASoC: soc-dapm: add prefix on dapm_mark_endpoints_dirty() dapm_mark_endpoints_dirty() is global function. Let's add snd_soc_ prefix. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87ldp8hisj.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 2 +- sound/soc/soc-core.c | 6 +++--- sound/soc/soc-dapm.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 5aeb0822ce0b..ee77a80765c6 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -700,7 +700,7 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, const char int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin); int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, const char *pin); unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol); -void dapm_mark_endpoints_dirty(struct snd_soc_card *card); +void snd_soc_dapm_mark_endpoints_dirty(struct snd_soc_card *card); /* * Marks the specified pin as being not connected, disabling it along diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 67bebc339148..b59f612de4e5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -681,7 +681,7 @@ int snd_soc_suspend(struct device *dev) soc_dapm_suspend_resume(card, SND_SOC_DAPM_STREAM_SUSPEND); /* Recheck all endpoints too, their state is affected by suspend */ - dapm_mark_endpoints_dirty(card); + snd_soc_dapm_mark_endpoints_dirty(card); snd_soc_dapm_sync(&card->dapm); /* suspend all COMPONENTs */ @@ -778,7 +778,7 @@ static void soc_resume_deferred(struct work_struct *work) dev_dbg(card->dev, "ASoC: resume work completed\n"); /* Recheck all endpoints too, their state is affected by suspend */ - dapm_mark_endpoints_dirty(card); + snd_soc_dapm_mark_endpoints_dirty(card); snd_soc_dapm_sync(&card->dapm); /* userspace can access us now we are back as we were before */ @@ -2286,7 +2286,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card) } card->instantiated = 1; - dapm_mark_endpoints_dirty(card); + snd_soc_dapm_mark_endpoints_dirty(card); snd_soc_dapm_sync(&card->dapm); /* deactivate pins to sleep state */ diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 16f8eff42835..d612dfbd245e 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -283,7 +283,7 @@ static void dapm_path_invalidate(struct snd_soc_dapm_path *p) dapm_widget_invalidate_output_paths(p->source); } -void dapm_mark_endpoints_dirty(struct snd_soc_card *card) +void snd_soc_dapm_mark_endpoints_dirty(struct snd_soc_card *card) { struct snd_soc_dapm_widget *w; From 9d33f9ca4404e532453a0305ce11bf76a9945c5d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 1 Jul 2025 00:11:15 +0000 Subject: [PATCH 202/385] ASoC: soc-dapm: add prefix on dapm_xxx_event() dapm_xxx_event() is global function. Let's add snd_soc_ prefix. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87jz4shisc.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 12 ++++++------ sound/soc/mediatek/mt8188/mt8188-mt6359.c | 4 ++-- sound/soc/soc-dapm.c | 20 ++++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index ee77a80765c6..be5ecc276562 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -295,7 +295,7 @@ struct snd_soc_pcm_runtime; #define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \ (struct snd_soc_dapm_widget) { \ .id = snd_soc_dapm_clock_supply, .name = wname, \ - .reg = SND_SOC_NOPM, .event = dapm_clock_event, \ + .reg = SND_SOC_NOPM, .event = snd_soc_dapm_clock_event, \ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD } /* generic widgets */ @@ -312,7 +312,7 @@ struct snd_soc_pcm_runtime; #define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay, wflags) \ (struct snd_soc_dapm_widget) { \ .id = snd_soc_dapm_regulator_supply, .name = wname, \ - .reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \ + .reg = SND_SOC_NOPM, .shift = wdelay, .event = snd_soc_dapm_regulator_event, \ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \ .on_val = wflags} #define SND_SOC_DAPM_PINCTRL(wname, active, sleep) \ @@ -320,7 +320,7 @@ struct snd_soc_pcm_runtime; .id = snd_soc_dapm_pinctrl, .name = wname, \ .priv = (&(struct snd_soc_dapm_pinctrl_priv) \ { .active_state = active, .sleep_state = sleep,}), \ - .reg = SND_SOC_NOPM, .event = dapm_pinctrl_event, \ + .reg = SND_SOC_NOPM, .event = snd_soc_dapm_pinctrl_event, \ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD } @@ -630,9 +630,9 @@ enum snd_soc_dapm_direction { #define SND_SOC_DAPM_EP_SOURCE SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_IN) #define SND_SOC_DAPM_EP_SINK SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_OUT) -int dapm_regulator_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); -int dapm_clock_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); -int dapm_pinctrl_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); +int snd_soc_dapm_regulator_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); +int snd_soc_dapm_clock_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); +int snd_soc_dapm_pinctrl_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); /* dapm controls */ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); diff --git a/sound/soc/mediatek/mt8188/mt8188-mt6359.c b/sound/soc/mediatek/mt8188/mt8188-mt6359.c index a2a76b6df631..ea814a0f726d 100644 --- a/sound/soc/mediatek/mt8188/mt8188-mt6359.c +++ b/sound/soc/mediatek/mt8188/mt8188-mt6359.c @@ -408,7 +408,7 @@ static int mt8188_mt6359_mtkaif_calibration(struct snd_soc_pcm_runtime *rtd) } if (pin_w) - dapm_pinctrl_event(pin_w, NULL, SND_SOC_DAPM_PRE_PMU); + snd_soc_dapm_pinctrl_event(pin_w, NULL, SND_SOC_DAPM_PRE_PMU); else dev_dbg(afe->dev, "%s(), no pinmux widget, please check if default on\n", __func__); @@ -510,7 +510,7 @@ static int mt8188_mt6359_mtkaif_calibration(struct snd_soc_pcm_runtime *rtd) param->mtkaif_phase_cycle[i] = mtkaif_phase_cycle[i]; if (pin_w) - dapm_pinctrl_event(pin_w, NULL, SND_SOC_DAPM_POST_PMD); + snd_soc_dapm_pinctrl_event(pin_w, NULL, SND_SOC_DAPM_POST_PMD); dev_dbg(afe->dev, "%s(), end, calibration ok %d\n", __func__, param->mtkaif_calibration_ok); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index d612dfbd245e..e8bd83fb9ef4 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1537,8 +1537,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_dai_free_widgets); /* * Handler for regulator supply widget. */ -int dapm_regulator_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +int snd_soc_dapm_regulator_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) { int ret; @@ -1566,13 +1566,13 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, return regulator_disable_deferred(w->regulator, w->shift); } } -EXPORT_SYMBOL_GPL(dapm_regulator_event); +EXPORT_SYMBOL_GPL(snd_soc_dapm_regulator_event); /* * Handler for pinctrl widget. */ -int dapm_pinctrl_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +int snd_soc_dapm_pinctrl_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) { struct snd_soc_dapm_pinctrl_priv *priv = w->priv; struct pinctrl *p = w->pinctrl; @@ -1591,13 +1591,13 @@ int dapm_pinctrl_event(struct snd_soc_dapm_widget *w, return pinctrl_select_state(p, s); } -EXPORT_SYMBOL_GPL(dapm_pinctrl_event); +EXPORT_SYMBOL_GPL(snd_soc_dapm_pinctrl_event); /* * Handler for clock supply widget. */ -int dapm_clock_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +int snd_soc_dapm_clock_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) { if (!w->clk) return -EIO; @@ -1613,7 +1613,7 @@ int dapm_clock_event(struct snd_soc_dapm_widget *w, return 0; } -EXPORT_SYMBOL_GPL(dapm_clock_event); +EXPORT_SYMBOL_GPL(snd_soc_dapm_clock_event); static int dapm_widget_power_check(struct snd_soc_dapm_widget *w) { @@ -3668,7 +3668,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, } /* set to sleep_state when initializing */ - dapm_pinctrl_event(w, NULL, SND_SOC_DAPM_POST_PMD); + snd_soc_dapm_pinctrl_event(w, NULL, SND_SOC_DAPM_POST_PMD); break; case snd_soc_dapm_clock_supply: w->clk = devm_clk_get(dapm->dev, widget->name); From 08dc0f5cc26a203e8008c38d9b436c079e7dbb45 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 1 Jul 2025 00:11:23 +0000 Subject: [PATCH 203/385] ASoC: soc-dapm: add prefix on soc_dapm_dev_attrs soc_dapm_dev_attrs is global variable. Let's add snd_soc_ prefix. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87ikkchis6.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 2 +- sound/soc/soc-core.c | 2 +- sound/soc/soc-dapm.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index be5ecc276562..0b5c7e6a90c8 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -685,7 +685,7 @@ int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm, struct snd_soc_dapm_update *update); /* dapm sys fs - used by the core */ -extern struct attribute *soc_dapm_dev_attrs[]; +extern struct attribute *snd_soc_dapm_dev_attrs[]; void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, struct dentry *parent); /* dapm audio pin control and status */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b59f612de4e5..ebe94956df44 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -112,7 +112,7 @@ static umode_t soc_dev_attr_is_visible(struct kobject *kobj, } static const struct attribute_group soc_dapm_dev_group = { - .attrs = soc_dapm_dev_attrs, + .attrs = snd_soc_dapm_dev_attrs, .is_visible = soc_dev_attr_is_visible, }; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index e8bd83fb9ef4..b8a5875378c8 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2715,7 +2715,7 @@ static ssize_t dapm_widget_show(struct device *dev, static DEVICE_ATTR_RO(dapm_widget); -struct attribute *soc_dapm_dev_attrs[] = { +struct attribute *snd_soc_dapm_dev_attrs[] = { &dev_attr_dapm_widget.attr, NULL }; From a3c3e84fc495dd983374f041e145e13df3525a15 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Jul 2025 02:46:42 +0000 Subject: [PATCH 204/385] ASoC: rt700: don't set dapm->bias_level snd_soc_component_set_bias_level() (A) which will call .set_bias_level() callback (B) will be called from snd_soc_dapm_force_bias_level() (C) only, and it sets dapm->bias_level (D) inside. No need to set it by each driver. Remove it. (A) int snd_soc_component_set_bias_level(...) { ... if (component->driver->set_bias_level) (B) ret = component->driver->set_bias_level(...); ... } (C) int snd_soc_dapm_force_bias_level(...) { ... if (dapm->component) (A) ret = snd_soc_component_set_bias_level(...); if (ret == 0) (D) dapm->bias_level = level; ... } Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87qzyrmmb2.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt700.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index 434b926f96c8..f817209316c2 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -862,7 +862,7 @@ static int rt700_set_bias_level(struct snd_soc_component *component, default: break; } - dapm->bias_level = level; + return 0; } From 67bdd67aedcec8c63e3158c3c82991fbde0c4d22 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Jul 2025 02:46:46 +0000 Subject: [PATCH 205/385] ASoC: rt715: don't set dapm->bias_level snd_soc_component_set_bias_level() (A) which will call .set_bias_level() callback (B) will be called from snd_soc_dapm_force_bias_level() (C) only, and it sets dapm->bias_level (D) inside. No need to set it by each driver. Remove it. (A) int snd_soc_component_set_bias_level(...) { ... if (component->driver->set_bias_level) (B) ret = component->driver->set_bias_level(...); ... } (C) int snd_soc_dapm_force_bias_level(...) { ... if (dapm->component) (A) ret = snd_soc_component_set_bias_level(...); if (ret == 0) (D) dapm->bias_level = level; ... } Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87plebmmax.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt715.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 2cf461852091..06ac2b56d9e4 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -775,7 +775,7 @@ static int rt715_set_bias_level(struct snd_soc_component *component, default: break; } - dapm->bias_level = level; + return 0; } From 2813f535b5847771d9e56df678c523a7e64f860e Mon Sep 17 00:00:00 2001 From: Balamurugan C Date: Tue, 8 Jul 2025 16:00:26 +0800 Subject: [PATCH 206/385] ASoC: Intel: soc-acpi: Add entry for sof_es8336 in PTL match table. Adding ES83x6 I2S codec support for PTL platforms and entry in match table. Signed-off-by: Balamurugan C Reviewed-by: Liam Girdwood Signed-off-by: Bard Liao Link: https://patch.msgid.link/20250708080030.1257790-2-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-ptl-match.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c index eae75f3f0fa4..ff4f2fbf9271 100644 --- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c @@ -21,6 +21,11 @@ static const struct snd_soc_acpi_codecs ptl_rt5682_rt5682s_hp = { .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID}, }; +static const struct snd_soc_acpi_codecs ptl_essx_83x6 = { + .num_codecs = 3, + .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_machines[] = { { .comp_ids = &ptl_rt5682_rt5682s_hp, @@ -29,6 +34,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_machines[] = { .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, }, + { + .comp_ids = &ptl_essx_83x6, + .drv_name = "sof-essx8336", + .sof_tplg_filename = "sof-ptl-es8336", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER | + SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | + SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ptl_machines); From fb00ab1f39369e49d25c74f0d41e4c1ec2f12576 Mon Sep 17 00:00:00 2001 From: Balamurugan C Date: Tue, 8 Jul 2025 16:00:27 +0800 Subject: [PATCH 207/385] ASoC: Intel: soc-acpi: Add entry for HDMI_In capture support in PTL match table Adding HDMI-In capture via I2S feature support in PTL platform. Signed-off-by: Balamurugan C Reviewed-by: Liam Girdwood Signed-off-by: Bard Liao Link: https://patch.msgid.link/20250708080030.1257790-3-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_es8336.c | 10 ++++++++++ sound/soc/intel/common/soc-acpi-intel-ptl-match.c | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index a0b3679b17b4..1211a2b8a2a2 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -826,6 +826,16 @@ static const struct platform_device_id board_ids[] = { SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | SOF_ES8336_JD_INVERTED), }, + { + .name = "ptl_es83x6_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) | + SOF_NO_OF_HDMI_CAPTURE_SSP(2) | + SOF_HDMI_CAPTURE_1_SSP(0) | + SOF_HDMI_CAPTURE_2_SSP(2) | + SOF_SSP_HDMI_CAPTURE_PRESENT | + SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | + SOF_ES8336_JD_INVERTED), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c index ff4f2fbf9271..67f1091483dc 100644 --- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c @@ -26,6 +26,11 @@ static const struct snd_soc_acpi_codecs ptl_essx_83x6 = { .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, }; +static const struct snd_soc_acpi_codecs ptl_lt6911_hdmi = { + .num_codecs = 1, + .codecs = {"INTC10B0"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_machines[] = { { .comp_ids = &ptl_rt5682_rt5682s_hp, @@ -34,6 +39,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_machines[] = { .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, }, + { + .comp_ids = &ptl_essx_83x6, + .drv_name = "ptl_es83x6_c1_h02", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &ptl_lt6911_hdmi, + .sof_tplg_filename = "sof-ptl-es83x6-ssp1-hdmi-ssp02.tplg", + }, { .comp_ids = &ptl_essx_83x6, .drv_name = "sof-essx8336", From e149d870687a5cfd702b700d81ae75ec6f41dd57 Mon Sep 17 00:00:00 2001 From: Mac Chiang Date: Tue, 8 Jul 2025 16:00:28 +0800 Subject: [PATCH 208/385] ASoC: Intel: soc-acpi-intel-ptl-match: add support ptl-rt721-l0 This patch adds support for rt721 on Soundwire Link 0. Signed-off-by: Mac Chiang Reviewed-by: Liam Girdwood Signed-off-by: Bard Liao Link: https://patch.msgid.link/20250708080030.1257790-4-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- .../intel/common/soc-acpi-intel-ptl-match.c | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c index 67f1091483dc..a8fee8cf4913 100644 --- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c @@ -355,6 +355,15 @@ static const struct snd_soc_acpi_adr_device rt1320_3_group1_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt721_0_single_adr[] = { + { + .adr = 0x000030025d072101ull, + .num_endpoints = ARRAY_SIZE(rt_mf_endpoints), + .endpoints = rt_mf_endpoints, + .name_prefix = "rt721" + } +}; + static const struct snd_soc_acpi_adr_device rt721_3_single_adr[] = { { .adr = 0x000330025d072101ull, @@ -473,6 +482,15 @@ static const struct snd_soc_acpi_link_adr ptl_cs42l43_l3[] = { {} }; +static const struct snd_soc_acpi_link_adr ptl_rt721_l0[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt721_0_single_adr), + .adr_d = rt721_0_single_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr ptl_rt722_only[] = { { .mask = BIT(0), @@ -660,6 +678,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-ptl-rt711.tplg", }, + { + .link_mask = BIT(0), + .links = ptl_rt721_l0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt721.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, { .link_mask = BIT(0), .links = ptl_rt722_only, From 86ccd4d3e8bc9eeb5dde4080fcc67e0505d1d2c6 Mon Sep 17 00:00:00 2001 From: Mac Chiang Date: Tue, 8 Jul 2025 16:00:29 +0800 Subject: [PATCH 209/385] ASoC: Intel: soc-acpi-intel-lnl-match: add rt1320_l12_rt714_l0 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch add acpi matching support for the rt1320 left and right amplifiers on soundwire link 1 and 2, and the rt714 dmic on soundwire link 0. Signed-off-by: Mac Chiang Reviewed-by: Péter Ujfalusi Signed-off-by: Bard Liao Link: https://patch.msgid.link/20250708080030.1257790-5-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- .../intel/common/soc-acpi-intel-lnl-match.c | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c index 558dc4c91239..937a74a5d523 100644 --- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c @@ -419,6 +419,15 @@ static const struct snd_soc_acpi_adr_device rt1320_1_group1_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1320_2_group2_adr[] = { + { + .adr = 0x000231025D132001ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1320-2" + } +}; + static const struct snd_soc_acpi_adr_device rt1320_1_group2_adr[] = { { .adr = 0x000130025D132001ull, @@ -609,6 +618,25 @@ static const struct snd_soc_acpi_link_adr lnl_sdw_rt1318_l12_rt714_l0[] = { {} }; +static const struct snd_soc_acpi_link_adr lnl_sdw_rt1320_l12_rt714_l0[] = { + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1320_1_group2_adr), + .adr_d = rt1320_1_group2_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1320_2_group2_adr), + .adr_d = rt1320_2_group2_adr, + }, + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt714_0_adr), + .adr_d = rt714_0_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr lnl_sdw_rt713_l0_rt1318_l1[] = { { .mask = BIT(0), @@ -740,6 +768,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-lnl-rt1318-l12-rt714-l0.tplg" }, + { + .link_mask = GENMASK(2, 0), + .links = lnl_sdw_rt1320_l12_rt714_l0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-rt1320-l12-rt714-l0.tplg" + }, { .link_mask = BIT(0) | BIT(1), .links = lnl_sdw_rt713_l0_rt1318_l1, From 68e4dadacb7faa393b532b41bbf99a2dbfec3b1b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 8 Jul 2025 17:47:29 +0200 Subject: [PATCH 210/385] ASoC: img: Imagination Technologies sound should depend on MIPS Before, all Imagination sound symbols were gated by the SND_SOC_IMG symbol, offering the user a simple option to hide them all. After the removal of this gate symbol, all symbols are exposed to the user, even when configuring a kernel for a non-Imagination platform. Fix this by adding a dependency on MIPS, to prevent asking the user about these drivers when configuring a kernel for a different architecture. Fixes: b13f7eef9ff82e01 ("ASoC: img: Standardize ASoC menu") Signed-off-by: Geert Uytterhoeven Link: https://patch.msgid.link/242832f225ae68018111648ea9934dc059741567.1751989463.git.geert+renesas@glider.be Signed-off-by: Mark Brown --- sound/soc/img/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/img/Kconfig b/sound/soc/img/Kconfig index 9a4cba6fdb50..22b75a8144a1 100644 --- a/sound/soc/img/Kconfig +++ b/sound/soc/img/Kconfig @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only menu "Imagination Technologies" + depends on MIPS || COMPILE_TEST config SND_SOC_IMG_I2S_IN tristate "Imagination I2S Input Device Driver" From c61da55412a08268ea0cdef99dea11f7ade934ee Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 9 Jul 2025 10:57:45 +0800 Subject: [PATCH 211/385] ASoC: sdw_utils: Add missed component_name strings for speaker amps Several speaker amp was missed when the compoennt_name was added, which results missing " spk:" from the components string, confusing UCM. Fixes: f792733e08d5 ("ASoC: sdw_utils: add component_name string to dai_info") Cc: stable@vger.kernel.org Signed-off-by: Peter Ujfalusi Signed-off-by: Bard Liao Link: https://patch.msgid.link/20250709025745.1285788-1-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sdw_utils/soc_sdw_utils.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index a744ca019378..1580331cd34c 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -218,6 +218,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { { .direction = {true, false}, .dai_name = "rt1308-aif", + .component_name = "rt1308", .dai_type = SOC_SDW_DAI_TYPE_AMP, .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, .init = asoc_sdw_rt_amp_init, @@ -238,6 +239,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { { .direction = {true, true}, .dai_name = "rt1316-aif", + .component_name = "rt1316", .dai_type = SOC_SDW_DAI_TYPE_AMP, .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, .init = asoc_sdw_rt_amp_init, @@ -257,6 +259,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { { .direction = {true, true}, .dai_name = "rt1318-aif", + .component_name = "rt1318", .dai_type = SOC_SDW_DAI_TYPE_AMP, .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, .init = asoc_sdw_rt_amp_init, @@ -370,6 +373,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { { .direction = {true, false}, .dai_name = "rt721-sdca-aif2", + .component_name = "rt721", .dai_type = SOC_SDW_DAI_TYPE_AMP, /* No feedback capability is provided by rt721-sdca codec driver*/ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, @@ -596,6 +600,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { { .direction = {true, false}, .dai_name = "cs42l43-dp6", + .component_name = "cs42l43", .dai_type = SOC_SDW_DAI_TYPE_AMP, .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, .init = asoc_sdw_cs42l43_spk_init, From 907e01b3ce4cee04aed33cdffcd444d6bd2a684e Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 9 Jul 2025 14:46:52 +0200 Subject: [PATCH 212/385] ALSA: echoaudio: Replace deprecated strcpy() with strscpy() strcpy() is deprecated; use strscpy() instead. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20250709124655.1195-1-thorsten.blum@linux.dev Signed-off-by: Takashi Iwai --- sound/pci/echoaudio/echoaudio.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 80d8ce75fdbb..2b33ef588ac3 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -6,6 +6,7 @@ */ #include +#include MODULE_AUTHOR("Giuliano Pochini "); MODULE_LICENSE("GPL v2"); @@ -916,7 +917,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip) return err; pcm->private_data = chip; chip->analog_pcm = pcm; - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops); snd_echo_preallocate_pages(pcm, &chip->pci->dev); @@ -929,7 +930,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip) return err; pcm->private_data = chip; chip->digital_pcm = pcm; - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops); snd_echo_preallocate_pages(pcm, &chip->pci->dev); #endif /* ECHOCARD_HAS_DIGITAL_IO */ @@ -949,7 +950,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip) return err; pcm->private_data = chip; chip->analog_pcm = pcm; - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops); snd_echo_preallocate_pages(pcm, &chip->pci->dev); @@ -963,7 +964,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip) return err; pcm->private_data = chip; chip->digital_pcm = pcm; - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &digital_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops); snd_echo_preallocate_pages(pcm, &chip->pci->dev); @@ -1985,8 +1986,8 @@ static int __snd_echo_probe(struct pci_dev *pci, if (err < 0) return err; - strcpy(card->driver, "Echo_" ECHOCARD_NAME); - strcpy(card->shortname, chip->card_name); + strscpy(card->driver, "Echo_" ECHOCARD_NAME); + strscpy(card->shortname, chip->card_name); dsp = "56301"; if (pci_id->device == 0x3410) From ad4655653a6c463026ed3c300e5fb34f39abff48 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 9 Jul 2025 17:24:17 +0200 Subject: [PATCH 213/385] ASoC: SDCA: fix HID dependency It is not possible to enable SND_SOC_SDCA_HID when SND_SOC_SDCA is built-in but HID is in a loadable module, as that results in a link failure: x86_64-linux-ld: sound/soc/sdca/sdca_functions.o: in function `find_sdca_entity_hide': sdca_functions.c:(.text+0x25b): undefined reference to `sdca_add_hid_device' Change SND_SOC_SDCA_HID into a 'bool' option that can only be enabled if this results in a working build, and change the Makefile so this driver is a loadable module if possible. Fixes: ac558015dfd8 ("ASoC: SDCA: add a HID device for HIDE entity") Reviewed-by: Charles Keepax Signed-off-by: Arnd Bergmann Link: https://patch.msgid.link/20250709152430.1498427-1-arnd@kernel.org Signed-off-by: Mark Brown --- sound/soc/sdca/Kconfig | 5 +++-- sound/soc/sdca/Makefile | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/soc/sdca/Kconfig b/sound/soc/sdca/Kconfig index 53f6926255ae..2253a300dcc3 100644 --- a/sound/soc/sdca/Kconfig +++ b/sound/soc/sdca/Kconfig @@ -12,8 +12,9 @@ config SND_SOC_SDCA_OPTIONAL def_tristate SND_SOC_SDCA || !SND_SOC_SDCA config SND_SOC_SDCA_HID - tristate "SDCA HID support" - depends on SND_SOC_SDCA && HID + bool "SDCA HID support" + depends on SND_SOC_SDCA + depends on HID=y || HID=SND_SOC_SDCA config SND_SOC_SDCA_IRQ tristate diff --git a/sound/soc/sdca/Makefile b/sound/soc/sdca/Makefile index 2a3938d11ca9..1efc869c6cbc 100644 --- a/sound/soc/sdca/Makefile +++ b/sound/soc/sdca/Makefile @@ -5,5 +5,7 @@ snd-soc-sdca-hid-y := sdca_hid.o snd-soc-sdca-irq-y := sdca_interrupts.o obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca.o -obj-$(CONFIG_SND_SOC_SDCA_HID) += snd-soc-sdca-hid.o +ifdef CONFIG_SND_SOC_SDCA_HID +obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca-hid.o +endif obj-$(CONFIG_SND_SOC_SDCA_IRQ) += snd-soc-sdca-irq.o From 8bb0a5fcde7b424172e48cf2b85664e7fe201417 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:05:43 +0200 Subject: [PATCH 214/385] ALSA: control: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-2-tiwai@suse.de --- sound/core/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/control.c b/sound/core/control.c index 11f660fc6f2b..9c3fd5113a61 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1435,7 +1435,7 @@ static int snd_ctl_elem_user_enum_info(struct snd_kcontrol *kcontrol, names = ue->priv_data; for (; item > 0; --item) names += strlen(names) + 1; - strcpy(uinfo->value.enumerated.name, names); + strscpy(uinfo->value.enumerated.name, names); return 0; } From d8cd23a0d2da68650a0710908aeefbe8b799fec3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:05:44 +0200 Subject: [PATCH 215/385] ALSA: rawmidi: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-3-tiwai@suse.de --- sound/core/rawmidi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 70a958ac1112..20d36a346cca 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -631,9 +631,9 @@ static int snd_rawmidi_info(struct snd_rawmidi_substream *substream, info->flags = rmidi->info_flags; if (substream->inactive) info->flags |= SNDRV_RAWMIDI_INFO_STREAM_INACTIVE; - strcpy(info->id, rmidi->id); - strcpy(info->name, rmidi->name); - strcpy(info->subname, substream->name); + strscpy(info->id, rmidi->id); + strscpy(info->name, rmidi->name); + strscpy(info->subname, substream->name); info->subdevices_count = substream->pstr->substream_count; info->subdevices_avail = (substream->pstr->substream_count - substream->pstr->substream_opened); From 7df6224dec68eaa266663206d899a77d7a947541 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:05:45 +0200 Subject: [PATCH 216/385] ALSA: seq: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-4-tiwai@suse.de --- sound/core/seq/oss/seq_oss_init.c | 4 ++-- sound/core/seq/seq_clientmgr.c | 2 +- sound/core/seq/seq_midi.c | 2 +- sound/core/seq/seq_system.c | 4 ++-- sound/core/seq/seq_ump_client.c | 2 +- sound/core/seq/seq_virmidi.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index e6d7d83ed0e7..973f057eb731 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c @@ -79,7 +79,7 @@ snd_seq_oss_create_client(void) system_client = rc; /* create announcement receiver port */ - strcpy(port->name, "Receiver"); + strscpy(port->name, "Receiver"); port->addr.client = system_client; port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* receive only */ port->type = 0; @@ -347,7 +347,7 @@ alloc_seq_queue(struct seq_oss_devinfo *dp) memset(&qinfo, 0, sizeof(qinfo)); qinfo.owner = system_client; qinfo.locked = 1; - strcpy(qinfo.name, "OSS Sequencer Emulation"); + strscpy(qinfo.name, "OSS Sequencer Emulation"); rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo); if (rc < 0) return rc; diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 880240924bfd..aa9c956d2581 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1256,7 +1256,7 @@ static void get_client_info(struct snd_seq_client *cptr, /* fill the info fields */ info->type = cptr->type; - strcpy(info->name, cptr->name); + strscpy(info->name, cptr->name); info->filter = cptr->filter; info->event_lost = cptr->event_lost; memcpy(info->event_filter, cptr->event_filter, 32); diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index ba52a77eda38..581e138a3115 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -344,7 +344,7 @@ snd_seq_midisynth_probe(struct device *_dev) info->stream = SNDRV_RAWMIDI_STREAM_INPUT; info->subdevice = p; if (snd_rawmidi_info_select(card, info) >= 0) - strcpy(port->name, info->subname); + strscpy(port->name, info->subname); if (! port->name[0]) { if (info->name[0]) { if (ports > 1) diff --git a/sound/core/seq/seq_system.c b/sound/core/seq/seq_system.c index 853920f79016..5b5603e5970b 100644 --- a/sound/core/seq/seq_system.c +++ b/sound/core/seq/seq_system.c @@ -146,7 +146,7 @@ int __init snd_seq_system_client_init(void) } /* register timer */ - strcpy(port->name, "Timer"); + strscpy(port->name, "Timer"); port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* accept queue control */ port->capability |= SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast */ port->kernel = &pcallbacks; @@ -160,7 +160,7 @@ int __init snd_seq_system_client_init(void) goto error_port; /* register announcement port */ - strcpy(port->name, "Announce"); + strscpy(port->name, "Announce"); port->capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast only */ pcallbacks.event_input = NULL; pcallbacks.subscribe = sys_announce_subscribe; diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c index 1255351b59ce..27247babb16d 100644 --- a/sound/core/seq/seq_ump_client.c +++ b/sound/core/seq/seq_ump_client.c @@ -310,7 +310,7 @@ static int create_ump_endpoint_port(struct seq_ump_client *client) SNDRV_SEQ_PORT_TYPE_HARDWARE | SNDRV_SEQ_PORT_TYPE_PORT; port->midi_channels = 16; - strcpy(port->name, "MIDI 2.0"); + strscpy(port->name, "MIDI 2.0"); memset(&pcallbacks, 0, sizeof(pcallbacks)); pcallbacks.owner = THIS_MODULE; pcallbacks.private_data = client; diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index b4672613c261..9e7fd4993a10 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -497,7 +497,7 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi &rmidi); if (err < 0) return err; - strcpy(rmidi->name, rmidi->id); + strscpy(rmidi->name, rmidi->id); rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); if (rdev == NULL) { snd_device_free(card, rmidi); From 59cea894bf3b80a4a3581ea614d465bf54474272 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:05:46 +0200 Subject: [PATCH 217/385] ALSA: mpu401: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-5-tiwai@suse.de --- sound/drivers/mpu401/mpu401.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c index cd01af5fa4ed..d3f9424088d4 100644 --- a/sound/drivers/mpu401/mpu401.c +++ b/sound/drivers/mpu401/mpu401.c @@ -63,8 +63,8 @@ static int snd_mpu401_create(struct device *devptr, int dev, 0, &card); if (err < 0) return err; - strcpy(card->driver, "MPU-401 UART"); - strcpy(card->shortname, card->driver); + strscpy(card->driver, "MPU-401 UART"); + strscpy(card->shortname, card->driver); sprintf(card->longname, "%s at %#lx, ", card->shortname, port[dev]); if (irq[dev] >= 0) { sprintf(card->longname + strlen(card->longname), "irq %d", irq[dev]); From bb246ab0943d4a8253e001d03b607b046f7588b3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:05:47 +0200 Subject: [PATCH 218/385] ALSA: opl3: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-6-tiwai@suse.de --- sound/drivers/opl3/opl3_lib.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c index 4e57e3b2f118..cd9642a6689b 100644 --- a/sound/drivers/opl3/opl3_lib.c +++ b/sound/drivers/opl3/opl3_lib.c @@ -245,7 +245,7 @@ static int snd_opl3_timer1_init(struct snd_opl3 * opl3, int timer_no) tid.subdevice = 0; err = snd_timer_new(opl3->card, "AdLib timer #1", &tid, &timer); if (err >= 0) { - strcpy(timer->name, "AdLib timer #1"); + strscpy(timer->name, "AdLib timer #1"); timer->private_data = opl3; timer->hw = snd_opl3_timer1; } @@ -266,7 +266,7 @@ static int snd_opl3_timer2_init(struct snd_opl3 * opl3, int timer_no) tid.subdevice = 0; err = snd_timer_new(opl3->card, "AdLib timer #2", &tid, &timer); if (err >= 0) { - strcpy(timer->name, "AdLib timer #2"); + strscpy(timer->name, "AdLib timer #2"); timer->private_data = opl3; timer->hw = snd_opl3_timer2; } @@ -497,18 +497,18 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3, if (device == 0) hw->oss_type = SNDRV_OSS_DEVICE_TYPE_DMFM; #endif - strcpy(hw->name, hw->id); + strscpy(hw->name, hw->id); switch (opl3->hardware & OPL3_HW_MASK) { case OPL3_HW_OPL2: - strcpy(hw->name, "OPL2 FM"); + strscpy(hw->name, "OPL2 FM"); hw->iface = SNDRV_HWDEP_IFACE_OPL2; break; case OPL3_HW_OPL3: - strcpy(hw->name, "OPL3 FM"); + strscpy(hw->name, "OPL3 FM"); hw->iface = SNDRV_HWDEP_IFACE_OPL3; break; case OPL3_HW_OPL4: - strcpy(hw->name, "OPL4 FM"); + strscpy(hw->name, "OPL4 FM"); hw->iface = SNDRV_HWDEP_IFACE_OPL4; break; } @@ -524,7 +524,7 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3, #if IS_ENABLED(CONFIG_SND_SEQUENCER) if (snd_seq_device_new(card, seq_device, SNDRV_SEQ_DEV_ID_OPL3, sizeof(struct snd_opl3 *), &opl3->seq_dev) >= 0) { - strcpy(opl3->seq_dev->name, hw->name); + strscpy(opl3->seq_dev->name, hw->name); *(struct snd_opl3 **)SNDRV_SEQ_DEVICE_ARGPTR(opl3->seq_dev) = opl3; } #endif From 0676ccf26f1cfb4a9aff96f933f52580357049db Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:05:48 +0200 Subject: [PATCH 219/385] ALSA: opl4: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-7-tiwai@suse.de --- sound/drivers/opl4/opl4_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c index 8fa61596875a..ef6b2d533958 100644 --- a/sound/drivers/opl4/opl4_lib.c +++ b/sound/drivers/opl4/opl4_lib.c @@ -152,7 +152,7 @@ static int snd_opl4_create_seq_dev(struct snd_opl4 *opl4, int seq_device) opl4->seq_dev_num = seq_device; if (snd_seq_device_new(opl4->card, seq_device, SNDRV_SEQ_DEV_ID_OPL4, sizeof(struct snd_opl4 *), &opl4->seq_dev) >= 0) { - strcpy(opl4->seq_dev->name, "OPL4 Wavetable"); + strscpy(opl4->seq_dev->name, "OPL4 Wavetable"); *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(opl4->seq_dev) = opl4; opl4->seq_dev->private_data = opl4; opl4->seq_dev->private_free = snd_opl4_seq_dev_free; From 6d352251e905c13f4363ca7780a94ee703077900 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:05:49 +0200 Subject: [PATCH 220/385] ALSA: pcsp: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-8-tiwai@suse.de --- sound/drivers/pcsp/pcsp.c | 4 ++-- sound/drivers/pcsp/pcsp_lib.c | 2 +- sound/drivers/pcsp/pcsp_mixer.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c index e8482c2290c3..ff6bb375c900 100644 --- a/sound/drivers/pcsp/pcsp.c +++ b/sound/drivers/pcsp/pcsp.c @@ -122,8 +122,8 @@ static int snd_card_pcsp_probe(int devnum, struct device *dev) if (err < 0) return err; - strcpy(card->driver, "PC-Speaker"); - strcpy(card->shortname, "pcsp"); + strscpy(card->driver, "PC-Speaker"); + strscpy(card->shortname, "pcsp"); sprintf(card->longname, "Internal PC-Speaker at port 0x%x", pcsp_chip.port); diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c index d9bc1ea1b53c..80b313f4fcd3 100644 --- a/sound/drivers/pcsp/pcsp_lib.c +++ b/sound/drivers/pcsp/pcsp_lib.c @@ -340,7 +340,7 @@ int snd_pcsp_new_pcm(struct snd_pcsp *chip) chip->pcm->private_data = chip; chip->pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; - strcpy(chip->pcm->name, "pcsp"); + strscpy(chip->pcm->name, "pcsp"); snd_pcm_set_managed_buffer_all(chip->pcm, SNDRV_DMA_TYPE_CONTINUOUS, diff --git a/sound/drivers/pcsp/pcsp_mixer.c b/sound/drivers/pcsp/pcsp_mixer.c index c0ae942358b9..27d6150329a8 100644 --- a/sound/drivers/pcsp/pcsp_mixer.c +++ b/sound/drivers/pcsp/pcsp_mixer.c @@ -158,7 +158,7 @@ int snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm) if (err < 0) return err; - strcpy(card->mixername, "PC-Speaker"); + strscpy(card->mixername, "PC-Speaker"); return 0; } From 7ba740ecf54cf1990e37607545d7e96673166f1e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:05:50 +0200 Subject: [PATCH 221/385] ALSA: portman2x4: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-9-tiwai@suse.de --- sound/drivers/portman2x4.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c index 5e4ef25a83a4..b4fa6625a3d6 100644 --- a/sound/drivers/portman2x4.c +++ b/sound/drivers/portman2x4.c @@ -549,7 +549,7 @@ static int snd_portman_rawmidi_create(struct snd_card *card) return err; rmidi->private_data = pm; - strcpy(rmidi->name, CARD_NAME); + strscpy(rmidi->name, CARD_NAME); rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; @@ -714,8 +714,8 @@ static int snd_portman_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Cannot create card\n"); return err; } - strcpy(card->driver, DRIVER_NAME); - strcpy(card->shortname, CARD_NAME); + strscpy(card->driver, DRIVER_NAME); + strscpy(card->shortname, CARD_NAME); sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, p->base, p->irq); From eb264bc529545756f314f14fa294681178f27fd9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:05:51 +0200 Subject: [PATCH 222/385] ALSA: serial-generic: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-10-tiwai@suse.de --- sound/drivers/serial-generic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/drivers/serial-generic.c b/sound/drivers/serial-generic.c index 36409a56c675..21ae053c0576 100644 --- a/sound/drivers/serial-generic.c +++ b/sound/drivers/serial-generic.c @@ -300,7 +300,7 @@ static int snd_serial_generic_rmidi(struct snd_serial_generic *drvdata, &snd_serial_generic_input); snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_serial_generic_output); - strcpy(rrawmidi->name, drvdata->card->shortname); + strscpy(rrawmidi->name, drvdata->card->shortname); snd_serial_generic_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT], drvdata->serdev->ctrl->nr); @@ -329,7 +329,7 @@ static int snd_serial_generic_probe(struct serdev_device *serdev) if (err < 0) return err; - strcpy(card->driver, "SerialMIDI"); + strscpy(card->driver, "SerialMIDI"); sprintf(card->shortname, "SerialMIDI-%d", serdev->ctrl->nr); sprintf(card->longname, "Serial MIDI device at serial%d", serdev->ctrl->nr); From a725f6fa5835e518b1b52176894f62da7e587c45 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:05:52 +0200 Subject: [PATCH 223/385] ALSA: serial-u16550: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-11-tiwai@suse.de --- sound/drivers/serial-u16550.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 6d0656fcd574..52772ccfc377 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c @@ -845,7 +845,7 @@ static int snd_uart16550_rmidi(struct snd_uart16550 *uart, int device, &snd_uart16550_input); snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_uart16550_output); - strcpy(rrawmidi->name, "Serial MIDI"); + strscpy(rrawmidi->name, "Serial MIDI"); snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]); snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]); rrawmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | @@ -905,8 +905,8 @@ static int snd_serial_probe(struct platform_device *devptr) if (err < 0) return err; - strcpy(card->driver, "Serial"); - strcpy(card->shortname, "Serial MIDI (UART16550A)"); + strscpy(card->driver, "Serial"); + strscpy(card->shortname, "Serial MIDI (UART16550A)"); err = snd_uart16550_create(card, port[dev], irq[dev], speed[dev], base[dev], adaptor[dev], droponfull[dev], From 73e86d3666379b458e93e8a76fcd019f006b000d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:05:53 +0200 Subject: [PATCH 224/385] ALSA: virmidi: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-12-tiwai@suse.de --- sound/drivers/virmidi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c index 5f7b65ad63e3..a204f42d1026 100644 --- a/sound/drivers/virmidi.c +++ b/sound/drivers/virmidi.c @@ -95,11 +95,11 @@ static int snd_virmidi_probe(struct platform_device *devptr) if (err < 0) return err; vmidi->midi[idx] = rmidi; - strcpy(rmidi->name, "Virtual Raw MIDI"); + strscpy(rmidi->name, "Virtual Raw MIDI"); } - strcpy(card->driver, "VirMIDI"); - strcpy(card->shortname, "VirMIDI"); + strscpy(card->driver, "VirMIDI"); + strscpy(card->shortname, "VirMIDI"); sprintf(card->longname, "Virtual MIDI Card %i", dev + 1); err = snd_card_register(card); From c4a38b94bad184a140d357541e50576d4f288592 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:05:54 +0200 Subject: [PATCH 225/385] ALSA: vx: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-13-tiwai@suse.de --- sound/drivers/vx/vx_core.c | 2 +- sound/drivers/vx/vx_mixer.c | 2 +- sound/drivers/vx/vx_pcm.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index e2def8719ed2..7f25fa7c0404 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c @@ -806,7 +806,7 @@ struct vx_core *snd_vx_create(struct snd_card *card, chip->card = card; card->private_data = chip; - strcpy(card->driver, hw->name); + strscpy(card->driver, hw->name); sprintf(card->shortname, "Digigram %s", hw->name); vx_proc_init(chip); diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c index 53d78eb13c53..0a51ecdc084a 100644 --- a/sound/drivers/vx/vx_mixer.c +++ b/sound/drivers/vx/vx_mixer.c @@ -903,7 +903,7 @@ int snd_vx_mixer_new(struct vx_core *chip) struct snd_card *card = chip->card; char name[32]; - strcpy(card->mixername, card->driver); + strscpy(card->mixername, card->driver); /* output level controls */ for (i = 0; i < chip->hw->num_outs; i++) { diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index cbc77ca1ebdd..defc489494af 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -1226,7 +1226,7 @@ int snd_vx_pcm_new(struct vx_core *chip) pcm->private_free = snd_vx_pcm_free; pcm->info_flags = 0; pcm->nonatomic = true; - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); chip->pcm[i] = pcm; } From f9f63cb6eb91b67244c0fb5e91e98638178eadac Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:05:55 +0200 Subject: [PATCH 226/385] ALSA: firewire: bebob: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Reviewed-by: Takashi Sakamoto Link: https://patch.msgid.link/20250710100727.22653-14-tiwai@suse.de --- sound/firewire/bebob/bebob.c | 6 +++--- sound/firewire/bebob/bebob_hwdep.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index 2ba5962beb30..4ebaeff16455 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -105,9 +105,9 @@ name_device(struct snd_bebob *bebob) if (err < 0) goto end; - strcpy(bebob->card->driver, "BeBoB"); - strcpy(bebob->card->shortname, model); - strcpy(bebob->card->mixername, model); + strscpy(bebob->card->driver, "BeBoB"); + strscpy(bebob->card->shortname, model); + strscpy(bebob->card->mixername, model); snprintf(bebob->card->longname, sizeof(bebob->card->longname), "%s %s (id:%d, rev:%d), GUID %08x%08x at %s, S%d", vendor, model, hw_id, revision, diff --git a/sound/firewire/bebob/bebob_hwdep.c b/sound/firewire/bebob/bebob_hwdep.c index 6f9331655d43..5779e99a6bb2 100644 --- a/sound/firewire/bebob/bebob_hwdep.c +++ b/sound/firewire/bebob/bebob_hwdep.c @@ -183,7 +183,7 @@ int snd_bebob_create_hwdep_device(struct snd_bebob *bebob) err = snd_hwdep_new(bebob->card, "BeBoB", 0, &hwdep); if (err < 0) goto end; - strcpy(hwdep->name, "BeBoB"); + strscpy(hwdep->name, "BeBoB"); hwdep->iface = SNDRV_HWDEP_IFACE_FW_BEBOB; hwdep->ops = ops; hwdep->private_data = bebob; From ae2cdfc616722533332db129dbec385e32f467e0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:05:56 +0200 Subject: [PATCH 227/385] ALSA: firewire: dice: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Reviewed-by: Takashi Sakamoto Link: https://patch.msgid.link/20250710100727.22653-15-tiwai@suse.de --- sound/firewire/dice/dice-hwdep.c | 2 +- sound/firewire/dice/dice-pcm.c | 2 +- sound/firewire/dice/dice.c | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/firewire/dice/dice-hwdep.c b/sound/firewire/dice/dice-hwdep.c index ffc0b97782d6..d165dd427bd3 100644 --- a/sound/firewire/dice/dice-hwdep.c +++ b/sound/firewire/dice/dice-hwdep.c @@ -179,7 +179,7 @@ int snd_dice_create_hwdep(struct snd_dice *dice) err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep); if (err < 0) return err; - strcpy(hwdep->name, "DICE"); + strscpy(hwdep->name, "DICE"); hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE; hwdep->ops = ops; hwdep->private_data = dice; diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 2cf2adb48f2a..cfc19bd0d5dd 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -442,7 +442,7 @@ int snd_dice_create_pcm(struct snd_dice *dice) return err; pcm->private_data = dice; pcm->nonatomic = true; - strcpy(pcm->name, dice->card->shortname); + strscpy(pcm->name, dice->card->shortname); if (capture > 0) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index d362e4251c68..9675ec14271d 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -102,9 +102,9 @@ static void dice_card_strings(struct snd_dice *dice) unsigned int i; int err; - strcpy(card->driver, "DICE"); + strscpy(card->driver, "DICE"); - strcpy(card->shortname, "DICE"); + strscpy(card->shortname, "DICE"); BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname)); err = snd_dice_transaction_read_global(dice, GLOBAL_NICK_NAME, card->shortname, @@ -117,16 +117,16 @@ static void dice_card_strings(struct snd_dice *dice) card->shortname[sizeof(card->shortname) - 1] = '\0'; } - strcpy(vendor, "?"); + strscpy(vendor, "?"); fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor)); - strcpy(model, "?"); + strscpy(model, "?"); fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model)); snprintf(card->longname, sizeof(card->longname), "%s %s (serial %u) at %s, S%d", vendor, model, dev->config_rom[4] & 0x3fffff, dev_name(&dice->unit->device), 100 << dev->max_speed); - strcpy(card->mixername, "DICE"); + strscpy(card->mixername, "DICE"); } static void dice_card_free(struct snd_card *card) From 662dacfc6466e9eb07ae6be18799b62dbdaa2a0a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:05:57 +0200 Subject: [PATCH 228/385] ALSA: firewire: digi00x: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Reviewed-by: Takashi Sakamoto Link: https://patch.msgid.link/20250710100727.22653-16-tiwai@suse.de --- sound/firewire/digi00x/digi00x-hwdep.c | 2 +- sound/firewire/digi00x/digi00x.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/firewire/digi00x/digi00x-hwdep.c b/sound/firewire/digi00x/digi00x-hwdep.c index aadf7d724856..b150607c0a0d 100644 --- a/sound/firewire/digi00x/digi00x-hwdep.c +++ b/sound/firewire/digi00x/digi00x-hwdep.c @@ -188,7 +188,7 @@ int snd_dg00x_create_hwdep_device(struct snd_dg00x *dg00x) if (err < 0) return err; - strcpy(hwdep->name, "Digi00x"); + strscpy(hwdep->name, "Digi00x"); hwdep->iface = SNDRV_HWDEP_IFACE_FW_DIGI00X; hwdep->ops = ops; hwdep->private_data = dg00x; diff --git a/sound/firewire/digi00x/digi00x.c b/sound/firewire/digi00x/digi00x.c index 704ae2a5316b..cebc35dcf8cd 100644 --- a/sound/firewire/digi00x/digi00x.c +++ b/sound/firewire/digi00x/digi00x.c @@ -30,9 +30,9 @@ static int name_card(struct snd_dg00x *dg00x) model = skip_spaces(name); - strcpy(dg00x->card->driver, "Digi00x"); - strcpy(dg00x->card->shortname, model); - strcpy(dg00x->card->mixername, model); + strscpy(dg00x->card->driver, "Digi00x"); + strscpy(dg00x->card->shortname, model); + strscpy(dg00x->card->mixername, model); snprintf(dg00x->card->longname, sizeof(dg00x->card->longname), "Digidesign %s, GUID %08x%08x at %s, S%d", model, fw_dev->config_rom[3], fw_dev->config_rom[4], From 4b366c9d78e70bbf2e52f0a2fa2aca3e505ce95e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:05:58 +0200 Subject: [PATCH 229/385] ALSA: firewire: fireface: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Reviewed-by: Takashi Sakamoto Link: https://patch.msgid.link/20250710100727.22653-17-tiwai@suse.de --- sound/firewire/fireface/ff-hwdep.c | 2 +- sound/firewire/fireface/ff.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/firewire/fireface/ff-hwdep.c b/sound/firewire/fireface/ff-hwdep.c index 8a741b3b0436..ca5c5dee71f2 100644 --- a/sound/firewire/fireface/ff-hwdep.c +++ b/sound/firewire/fireface/ff-hwdep.c @@ -197,7 +197,7 @@ int snd_ff_create_hwdep_devices(struct snd_ff *ff) if (err < 0) return err; - strcpy(hwdep->name, ff->card->driver); + strscpy(hwdep->name, ff->card->driver); hwdep->iface = SNDRV_HWDEP_IFACE_FW_FIREFACE; hwdep->ops = hwdep_ops; hwdep->private_data = ff; diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index 6e84e4787259..5d2c4fbf4434 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -27,9 +27,9 @@ static void name_card(struct snd_ff *ff) name = names[ff->unit_version]; - strcpy(ff->card->driver, "Fireface"); - strcpy(ff->card->shortname, name); - strcpy(ff->card->mixername, name); + strscpy(ff->card->driver, "Fireface"); + strscpy(ff->card->shortname, name); + strscpy(ff->card->mixername, name); snprintf(ff->card->longname, sizeof(ff->card->longname), "RME %s, GUID %08x%08x at %s, S%d", name, fw_dev->config_rom[3], fw_dev->config_rom[4], From fcd7979273af35d79999bfd0e897fa34d4b047d5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:05:59 +0200 Subject: [PATCH 230/385] ALSA: firewire: fireworks: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Reviewed-by: Takashi Sakamoto Link: https://patch.msgid.link/20250710100727.22653-18-tiwai@suse.de --- sound/firewire/fireworks/fireworks.c | 6 +++--- sound/firewire/fireworks/fireworks_hwdep.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index e3ed4e094ccd..69f722244362 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -90,9 +90,9 @@ get_hardware_info(struct snd_efw *efw) (hwinfo->arm_version >> 16) & 0xff); efw->firmware_version = hwinfo->arm_version; - strcpy(efw->card->driver, "Fireworks"); - strcpy(efw->card->shortname, hwinfo->model_name); - strcpy(efw->card->mixername, hwinfo->model_name); + strscpy(efw->card->driver, "Fireworks"); + strscpy(efw->card->shortname, hwinfo->model_name); + strscpy(efw->card->mixername, hwinfo->model_name); scnprintf(efw->card->longname, sizeof(efw->card->longname), "%s %s v%s, GUID %08x%08x at %s, S%d", hwinfo->vendor_name, hwinfo->model_name, version, diff --git a/sound/firewire/fireworks/fireworks_hwdep.c b/sound/firewire/fireworks/fireworks_hwdep.c index 3a53914277d3..037833cd066e 100644 --- a/sound/firewire/fireworks/fireworks_hwdep.c +++ b/sound/firewire/fireworks/fireworks_hwdep.c @@ -319,7 +319,7 @@ int snd_efw_create_hwdep_device(struct snd_efw *efw) err = snd_hwdep_new(efw->card, "Fireworks", 0, &hwdep); if (err < 0) goto end; - strcpy(hwdep->name, "Fireworks"); + strscpy(hwdep->name, "Fireworks"); hwdep->iface = SNDRV_HWDEP_IFACE_FW_FIREWORKS; hwdep->ops = ops; hwdep->private_data = efw; From 6e96433010646c71a9f14ea305bda46189360b3a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:00 +0200 Subject: [PATCH 231/385] ALSA: firewire: isight: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Reviewed-by: Takashi Sakamoto Link: https://patch.msgid.link/20250710100727.22653-19-tiwai@suse.de --- sound/firewire/isight.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c index b1e059f0d473..ee574b5d7406 100644 --- a/sound/firewire/isight.c +++ b/sound/firewire/isight.c @@ -455,7 +455,7 @@ static int isight_create_pcm(struct isight *isight) return err; pcm->private_data = isight; pcm->nonatomic = true; - strcpy(pcm->name, "iSight"); + strscpy(pcm->name, "iSight"); isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; isight->pcm->ops = &ops; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); @@ -638,13 +638,13 @@ static int isight_probe(struct fw_unit *unit, card->private_free = isight_card_free; - strcpy(card->driver, "iSight"); - strcpy(card->shortname, "Apple iSight"); + strscpy(card->driver, "iSight"); + strscpy(card->shortname, "Apple iSight"); snprintf(card->longname, sizeof(card->longname), "Apple iSight (GUID %08x%08x) at %s, S%d", fw_dev->config_rom[3], fw_dev->config_rom[4], dev_name(&unit->device), 100 << fw_dev->max_speed); - strcpy(card->mixername, "iSight"); + strscpy(card->mixername, "iSight"); err = isight_create_pcm(isight); if (err < 0) From 97f54683816dad23896c3a93a83253044369f3f0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:01 +0200 Subject: [PATCH 232/385] ALSA: firewire: motu: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Reviewed-by: Takashi Sakamoto Link: https://patch.msgid.link/20250710100727.22653-20-tiwai@suse.de --- sound/firewire/motu/motu-hwdep.c | 2 +- sound/firewire/motu/motu-pcm.c | 2 +- sound/firewire/motu/motu.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/firewire/motu/motu-hwdep.c b/sound/firewire/motu/motu-hwdep.c index 88d1f4b56e4b..1ed60618220d 100644 --- a/sound/firewire/motu/motu-hwdep.c +++ b/sound/firewire/motu/motu-hwdep.c @@ -290,7 +290,7 @@ int snd_motu_create_hwdep_device(struct snd_motu *motu) if (err < 0) return err; - strcpy(hwdep->name, "MOTU"); + strscpy(hwdep->name, "MOTU"); hwdep->iface = SNDRV_HWDEP_IFACE_FW_MOTU; hwdep->ops = ops; hwdep->private_data = motu; diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c index f3b48495acae..7b4d476af348 100644 --- a/sound/firewire/motu/motu-pcm.c +++ b/sound/firewire/motu/motu-pcm.c @@ -361,7 +361,7 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu) return err; pcm->private_data = motu; pcm->nonatomic = true; - strcpy(pcm->name, motu->card->shortname); + strscpy(pcm->name, motu->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c index d14ab5dd5bea..fd2a9dddbfa6 100644 --- a/sound/firewire/motu/motu.c +++ b/sound/firewire/motu/motu.c @@ -41,9 +41,9 @@ static void name_card(struct snd_motu *motu) } } - strcpy(motu->card->driver, "FW-MOTU"); - strcpy(motu->card->shortname, motu->spec->name); - strcpy(motu->card->mixername, motu->spec->name); + strscpy(motu->card->driver, "FW-MOTU"); + strscpy(motu->card->shortname, motu->spec->name); + strscpy(motu->card->mixername, motu->spec->name); snprintf(motu->card->longname, sizeof(motu->card->longname), "MOTU %s (version:%06x), GUID %08x%08x at %s, S%d", motu->spec->name, version, From 74e4255b2058642eb7913d9da442cee6b740cae9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:02 +0200 Subject: [PATCH 233/385] ALSA: firewire: oxfw: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Reviewed-by: Takashi Sakamoto Link: https://patch.msgid.link/20250710100727.22653-21-tiwai@suse.de --- sound/firewire/oxfw/oxfw-hwdep.c | 2 +- sound/firewire/oxfw/oxfw-pcm.c | 2 +- sound/firewire/oxfw/oxfw.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/firewire/oxfw/oxfw-hwdep.c b/sound/firewire/oxfw/oxfw-hwdep.c index a0fe99618554..3be214d8a922 100644 --- a/sound/firewire/oxfw/oxfw-hwdep.c +++ b/sound/firewire/oxfw/oxfw-hwdep.c @@ -177,7 +177,7 @@ int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw) err = snd_hwdep_new(oxfw->card, oxfw->card->driver, 0, &hwdep); if (err < 0) goto end; - strcpy(hwdep->name, oxfw->card->driver); + strscpy(hwdep->name, oxfw->card->driver); hwdep->iface = SNDRV_HWDEP_IFACE_FW_OXFW; hwdep->ops = hwdep_ops; hwdep->private_data = oxfw; diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index 8ca9dde54ec6..e13dc817fc28 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -441,7 +441,7 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) pcm->private_data = oxfw; pcm->nonatomic = true; - strcpy(pcm->name, oxfw->card->shortname); + strscpy(pcm->name, oxfw->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); if (cap > 0) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 98ae0e8cba87..7a985f3cb8f6 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -105,9 +105,9 @@ static int name_card(struct snd_oxfw *oxfw, const struct ieee1394_device_id *ent m = model; } - strcpy(oxfw->card->driver, d); - strcpy(oxfw->card->mixername, m); - strcpy(oxfw->card->shortname, m); + strscpy(oxfw->card->driver, d); + strscpy(oxfw->card->mixername, m); + strscpy(oxfw->card->shortname, m); scnprintf(oxfw->card->longname, sizeof(oxfw->card->longname), "%s %s (OXFW%x %04x), GUID %08x%08x at %s, S%d", From c03ebbdfddc1a8ae5a50a77819069688f0cffbe3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:03 +0200 Subject: [PATCH 234/385] ALSA: firewire: tascam: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Reviewed-by: Takashi Sakamoto Link: https://patch.msgid.link/20250710100727.22653-22-tiwai@suse.de --- sound/firewire/tascam/tascam-hwdep.c | 2 +- sound/firewire/tascam/tascam.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/firewire/tascam/tascam-hwdep.c b/sound/firewire/tascam/tascam-hwdep.c index 74eed9505665..8fc30cba29d5 100644 --- a/sound/firewire/tascam/tascam-hwdep.c +++ b/sound/firewire/tascam/tascam-hwdep.c @@ -265,7 +265,7 @@ int snd_tscm_create_hwdep_device(struct snd_tscm *tscm) if (err < 0) return err; - strcpy(hwdep->name, "Tascam"); + strscpy(hwdep->name, "Tascam"); hwdep->iface = SNDRV_HWDEP_IFACE_FW_TASCAM; hwdep->ops = ops; hwdep->private_data = tscm; diff --git a/sound/firewire/tascam/tascam.c b/sound/firewire/tascam/tascam.c index 86880089de28..4f68bb4c58bc 100644 --- a/sound/firewire/tascam/tascam.c +++ b/sound/firewire/tascam/tascam.c @@ -73,9 +73,9 @@ static int identify_model(struct snd_tscm *tscm) if (tscm->spec == NULL) return -ENODEV; - strcpy(tscm->card->driver, "FW-TASCAM"); - strcpy(tscm->card->shortname, model); - strcpy(tscm->card->mixername, model); + strscpy(tscm->card->driver, "FW-TASCAM"); + strscpy(tscm->card->shortname, model); + strscpy(tscm->card->mixername, model); snprintf(tscm->card->longname, sizeof(tscm->card->longname), "TASCAM %s, GUID %08x%08x at %s, S%d", model, fw_dev->config_rom[3], fw_dev->config_rom[4], From 94d7b8beae3574fe7167b8e0f31d1d480442ccdf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:04 +0200 Subject: [PATCH 235/385] ALSA: ad1816a: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-23-tiwai@suse.de --- sound/isa/ad1816a/ad1816a.c | 4 ++-- sound/isa/ad1816a/ad1816a_lib.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index 5c9e2d41d900..8e84d4091f1e 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/sound/isa/ad1816a/ad1816a.c @@ -143,8 +143,8 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard, if (clockfreq[dev] >= 5000 && clockfreq[dev] <= 100000) chip->clock_freq = clockfreq[dev]; - strcpy(card->driver, "AD1816A"); - strcpy(card->shortname, "ADI SoundPort AD1816A"); + strscpy(card->driver, "AD1816A"); + strscpy(card->shortname, "ADI SoundPort AD1816A"); sprintf(card->longname, "%s, SS at 0x%lx, irq %d, dma %d&%d", card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]); diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index 2b87036cb94f..400ae547bcba 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -631,7 +631,7 @@ int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device) pcm->private_data = chip; pcm->info_flags = (chip->dma1 == chip->dma2 ) ? SNDRV_PCM_INFO_JOINT_DUPLEX : 0; - strcpy(pcm->name, snd_ad1816a_chip_id(chip)); + strscpy(pcm->name, snd_ad1816a_chip_id(chip)); snd_ad1816a_init(chip); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, chip->card->dev, @@ -655,7 +655,7 @@ int snd_ad1816a_timer(struct snd_ad1816a *chip, int device) error = snd_timer_new(chip->card, "AD1816A", &tid, &timer); if (error < 0) return error; - strcpy(timer->name, snd_ad1816a_chip_id(chip)); + strscpy(timer->name, snd_ad1816a_chip_id(chip)); timer->private_data = chip; chip->timer = timer; timer->hw = snd_ad1816a_timer_table; @@ -912,7 +912,7 @@ int snd_ad1816a_mixer(struct snd_ad1816a *chip) card = chip->card; - strcpy(card->mixername, snd_ad1816a_chip_id(chip)); + strscpy(card->mixername, snd_ad1816a_chip_id(chip)); for (idx = 0; idx < ARRAY_SIZE(snd_ad1816a_controls); idx++) { err = snd_ctl_add(card, snd_ctl_new1(&snd_ad1816a_controls[idx], chip)); From 461cef4d7d0270b5d11c2738c3a0a4e099351718 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:05 +0200 Subject: [PATCH 236/385] ALSA: adlib: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-24-tiwai@suse.de --- sound/isa/adlib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/isa/adlib.c b/sound/isa/adlib.c index f079ba4ef1a0..03fb2bce9255 100644 --- a/sound/isa/adlib.c +++ b/sound/isa/adlib.c @@ -61,8 +61,8 @@ static int snd_adlib_probe(struct device *dev, unsigned int n) return -EBUSY; } - strcpy(card->driver, DEV_NAME); - strcpy(card->shortname, CRD_NAME); + strscpy(card->driver, DEV_NAME); + strscpy(card->shortname, CRD_NAME); sprintf(card->longname, CRD_NAME " at %#lx", port[n]); error = snd_opl3_create(card, port[n], port[n] + 2, OPL3_HW_AUTO, 1, &opl3); From dd9de1a144e10d5498ea1f0fb4ab70fa6d953ff0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:06 +0200 Subject: [PATCH 237/385] ALSA: als100: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-25-tiwai@suse.de --- sound/isa/als100.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/isa/als100.c b/sound/isa/als100.c index e70dbf0b099a..cfc241bd252e 100644 --- a/sound/isa/als100.c +++ b/sound/isa/als100.c @@ -192,14 +192,14 @@ static int snd_card_als100_probe(int dev, acard->chip = chip; if (pid->driver_data == SB_HW_DT019X) { - strcpy(card->driver, "DT-019X"); - strcpy(card->shortname, "Diamond Tech. DT-019X"); + strscpy(card->driver, "DT-019X"); + strscpy(card->shortname, "Diamond Tech. DT-019X"); snprintf(card->longname, sizeof(card->longname), "Diamond Tech. DT-019X, %s at 0x%lx, irq %d, dma %d", chip->name, chip->port, irq[dev], dma8[dev]); } else { - strcpy(card->driver, "ALS100"); - strcpy(card->shortname, "Avance Logic ALS100"); + strscpy(card->driver, "ALS100"); + strscpy(card->shortname, "Avance Logic ALS100"); snprintf(card->longname, sizeof(card->longname), "Avance Logic ALS100, %s at 0x%lx, irq %d, dma %d&%d", chip->name, chip->port, irq[dev], dma8[dev], From 231d135055a685e75b7d815e2aacdf85cb5bcc3e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:07 +0200 Subject: [PATCH 238/385] ALSA: cmi8328: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-26-tiwai@suse.de --- sound/isa/cmi8328.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c index d30cce4cc7e3..4e6d823af103 100644 --- a/sound/isa/cmi8328.c +++ b/sound/isa/cmi8328.c @@ -155,34 +155,34 @@ static int snd_cmi8328_mixer(struct snd_wss *chip) memset(&id2, 0, sizeof(id2)); id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; /* rename AUX0 switch to CD */ - strcpy(id1.name, "Aux Playback Switch"); - strcpy(id2.name, "CD Playback Switch"); + strscpy(id1.name, "Aux Playback Switch"); + strscpy(id2.name, "CD Playback Switch"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) { dev_err(card->dev, "error renaming control\n"); return err; } /* rename AUX0 volume to CD */ - strcpy(id1.name, "Aux Playback Volume"); - strcpy(id2.name, "CD Playback Volume"); + strscpy(id1.name, "Aux Playback Volume"); + strscpy(id2.name, "CD Playback Volume"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) { dev_err(card->dev, "error renaming control\n"); return err; } /* rename AUX1 switch to Synth */ - strcpy(id1.name, "Aux Playback Switch"); + strscpy(id1.name, "Aux Playback Switch"); id1.index = 1; - strcpy(id2.name, "Synth Playback Switch"); + strscpy(id2.name, "Synth Playback Switch"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) { dev_err(card->dev, "error renaming control\n"); return err; } /* rename AUX1 volume to Synth */ - strcpy(id1.name, "Aux Playback Volume"); + strscpy(id1.name, "Aux Playback Volume"); id1.index = 1; - strcpy(id2.name, "Synth Playback Volume"); + strscpy(id2.name, "Synth Playback Volume"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) { dev_err(card->dev, "error renaming control\n"); @@ -362,8 +362,8 @@ static int snd_cmi8328_probe(struct device *pdev, unsigned int ndev) if (snd_opl3_hwdep_new(opl3, 0, 1, NULL) < 0) dev_warn(pdev, "error initializing OPL3 hwdep\n"); - strcpy(card->driver, "CMI8328"); - strcpy(card->shortname, "C-Media CMI8328"); + strscpy(card->driver, "CMI8328"); + strscpy(card->shortname, "C-Media CMI8328"); sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d,%d", card->shortname, cmi->wss->port, irq[ndev], dma1[ndev], (dma2[ndev] >= 0) ? dma2[ndev] : dma1[ndev]); From 4e55e03e4c17150218c6869cee7cb754bd291522 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:08 +0200 Subject: [PATCH 239/385] ALSA: cmi8330: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-27-tiwai@suse.de --- sound/isa/cmi8330.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index 25b4dc181089..e681c2c82474 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -297,7 +297,7 @@ static int snd_cmi8330_mixer(struct snd_card *card, struct snd_cmi8330 *acard) unsigned int idx; int err; - strcpy(card->mixername, (acard->type == CMI8329) ? "CMI8329" : "CMI8330/C3D"); + strscpy(card->mixername, (acard->type == CMI8329) ? "CMI8329" : "CMI8330/C3D"); for (idx = 0; idx < ARRAY_SIZE(snd_cmi8330_controls); idx++) { err = snd_ctl_add(card, @@ -437,7 +437,7 @@ static int snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 *chip) err = snd_pcm_new(card, (chip->type == CMI8329) ? "CMI8329" : "CMI8330", 0, 1, 1, &pcm); if (err < 0) return err; - strcpy(pcm->name, (chip->type == CMI8329) ? "CMI8329" : "CMI8330"); + strscpy(pcm->name, (chip->type == CMI8329) ? "CMI8329" : "CMI8330"); pcm->private_data = chip; /* SB16 */ @@ -590,8 +590,8 @@ static int snd_cmi8330_probe(struct snd_card *card, int dev) mpuport[dev]); } - strcpy(card->driver, (acard->type == CMI8329) ? "CMI8329" : "CMI8330/C3D"); - strcpy(card->shortname, (acard->type == CMI8329) ? "C-Media CMI8329" : "C-Media CMI8330/C3D"); + strscpy(card->driver, (acard->type == CMI8329) ? "CMI8329" : "CMI8330/C3D"); + strscpy(card->shortname, (acard->type == CMI8329) ? "C-Media CMI8329" : "C-Media CMI8330/C3D"); sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", card->shortname, acard->wss->port, From 9a5cca8d838bc67da5c742ab1776d952364eccb5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:09 +0200 Subject: [PATCH 240/385] ALSA: cs423x: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-28-tiwai@suse.de --- sound/isa/cs423x/cs4236.c | 2 +- sound/isa/cs423x/cs4236_lib.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index ad20bb2649bd..e36cc147651a 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -510,7 +510,7 @@ static int snd_cs423x_pnpbios_detect(struct pnp_dev *pdev, return -ENODEV; /* prepare second id */ - strcpy(cid, pdev->id[0].id); + strscpy(cid, pdev->id[0].id); cid[5] = '1'; cdev = NULL; list_for_each_entry(iter, &(pdev->protocol->devices), protocol_list) { diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index 1a03cff6915b..eaaf39aae526 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c @@ -1023,7 +1023,7 @@ int snd_cs4236_mixer(struct snd_wss *chip) if (snd_BUG_ON(!chip || !chip->card)) return -EINVAL; card = chip->card; - strcpy(card->mixername, snd_wss_chip_id(chip)); + strscpy(card->mixername, snd_wss_chip_id(chip)); if (chip->hardware == WSS_HW_CS4235 || chip->hardware == WSS_HW_CS4239) { From 22095c0515e0cb34738e1600b54f8bceb7cf7b42 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:10 +0200 Subject: [PATCH 241/385] ALSA: es1688: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-29-tiwai@suse.de --- sound/isa/es1688/es1688_lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index c0c230149a75..2ef183f197ad 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c @@ -706,7 +706,7 @@ int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device) pcm->private_data = chip; pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; - strcpy(pcm->name, snd_es1688_chip_id(chip)); + strscpy(pcm->name, snd_es1688_chip_id(chip)); chip->pcm = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, card->dev, @@ -971,7 +971,7 @@ int snd_es1688_mixer(struct snd_card *card, struct snd_es1688 *chip) if (snd_BUG_ON(!chip || !card)) return -EINVAL; - strcpy(card->mixername, snd_es1688_chip_id(chip)); + strscpy(card->mixername, snd_es1688_chip_id(chip)); for (idx = 0; idx < ARRAY_SIZE(snd_es1688_controls); idx++) { err = snd_ctl_add(card, snd_ctl_new1(&snd_es1688_controls[idx], chip)); From 962dba349a76dd6872371c793f074704e57d2dc9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:11 +0200 Subject: [PATCH 242/385] ALSA: es18xx: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-30-tiwai@suse.de --- sound/isa/es18xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index e35c727a52fa..3e89a84c6244 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -1771,7 +1771,7 @@ static int snd_es18xx_mixer(struct snd_card *card) int err; unsigned int idx; - strcpy(card->mixername, chip->pcm->name); + strscpy(card->mixername, chip->pcm->name); for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_base_controls); idx++) { struct snd_kcontrol *kctl; From 74987a0cc4614477a9a5279f645a6d4b0dd66d74 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:12 +0200 Subject: [PATCH 243/385] ALSA: galaxy: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-31-tiwai@suse.de --- sound/isa/galaxy/galaxy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c index 3164eb8510fa..b0f1562d0fc0 100644 --- a/sound/isa/galaxy/galaxy.c +++ b/sound/isa/galaxy/galaxy.c @@ -542,8 +542,8 @@ static int __snd_galaxy_probe(struct device *dev, unsigned int n) return err; } - strcpy(card->driver, DRV_NAME); - strcpy(card->shortname, DRV_NAME); + strscpy(card->driver, DRV_NAME); + strscpy(card->shortname, DRV_NAME); sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d", card->shortname, port[n], wss_port[n], irq[n], dma1[n], dma2[n]); From 72b1baa1d650dd8b15c8a60daff2e37889d0e627 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:13 +0200 Subject: [PATCH 244/385] ALSA: gus: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-32-tiwai@suse.de --- sound/isa/gus/gus_main.c | 16 ++++++++-------- sound/isa/gus/gus_mixer.c | 2 +- sound/isa/gus/gus_pcm.c | 2 +- sound/isa/gus/gus_timer.c | 4 ++-- sound/isa/gus/gus_uart.c | 2 +- sound/isa/gus/gusextreme.c | 8 ++++---- sound/isa/gus/gusmax.c | 16 ++++++++-------- sound/isa/gus/interwave.c | 34 +++++++++++++++++----------------- 8 files changed, 42 insertions(+), 42 deletions(-) diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index 7166869e423d..873ef4046cd6 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c @@ -348,8 +348,8 @@ static int snd_gus_check_version(struct snd_gus_card * gus) rev = inb(GUSP(gus, BOARDVERSION)); spin_unlock_irqrestore(&gus->reg_lock, flags); dev_dbg(card->dev, "GF1 [0x%lx] init - val = 0x%x, rev = 0x%x\n", gus->gf1.port, val, rev); - strcpy(card->driver, "GUS"); - strcpy(card->longname, "Gravis UltraSound Classic (2.4)"); + strscpy(card->driver, "GUS"); + strscpy(card->longname, "Gravis UltraSound Classic (2.4)"); if ((val != 255 && (val & 0x06)) || (rev >= 5 && rev != 255)) { if (rev >= 5 && rev <= 9) { gus->ics_flag = 1; @@ -360,16 +360,16 @@ static int snd_gus_check_version(struct snd_gus_card * gus) } if (rev >= 10 && rev != 255) { if (rev >= 10 && rev <= 11) { - strcpy(card->driver, "GUS MAX"); - strcpy(card->longname, "Gravis UltraSound MAX"); + strscpy(card->driver, "GUS MAX"); + strscpy(card->longname, "Gravis UltraSound MAX"); gus->max_flag = 1; } else if (rev == 0x30) { - strcpy(card->driver, "GUS ACE"); - strcpy(card->longname, "Gravis UltraSound Ace"); + strscpy(card->driver, "GUS ACE"); + strscpy(card->longname, "Gravis UltraSound Ace"); gus->ace_flag = 1; } else if (rev == 0x50) { - strcpy(card->driver, "GUS Extreme"); - strcpy(card->longname, "Gravis UltraSound Extreme"); + strscpy(card->driver, "GUS Extreme"); + strscpy(card->longname, "Gravis UltraSound Extreme"); gus->ess_flag = 1; } else { dev_err(card->dev, diff --git a/sound/isa/gus/gus_mixer.c b/sound/isa/gus/gus_mixer.c index 03f9cfcbf601..60c3a8219770 100644 --- a/sound/isa/gus/gus_mixer.c +++ b/sound/isa/gus/gus_mixer.c @@ -152,7 +152,7 @@ int snd_gf1_new_mixer(struct snd_gus_card * gus) if (gus->ics_flag) snd_component_add(card, "ICS2101"); if (card->mixername[0] == '\0') { - strcpy(card->mixername, gus->ics_flag ? "GF1,ICS2101" : "GF1"); + strscpy(card->mixername, gus->ics_flag ? "GF1,ICS2101" : "GF1"); } else { if (gus->ics_flag) strcat(card->mixername, ",ICS2101"); diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index 16f9bbb43a54..8b9b7b8d92b2 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c @@ -851,7 +851,7 @@ int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index) SNDRV_DMA_TYPE_DEV, card->dev, 64*1024, gus->gf1.dma2 > 3 ? 128*1024 : 64*1024); } - strcpy(pcm->name, pcm->id); + strscpy(pcm->name, pcm->id); if (gus->interwave) { sprintf(pcm->name + strlen(pcm->name), " rev %c", gus->revision + 'A'); } diff --git a/sound/isa/gus/gus_timer.c b/sound/isa/gus/gus_timer.c index 047ddbc6192f..7267fb5bf8e5 100644 --- a/sound/isa/gus/gus_timer.c +++ b/sound/isa/gus/gus_timer.c @@ -156,7 +156,7 @@ void snd_gf1_timers_init(struct snd_gus_card * gus) tid.subdevice = 0; if (snd_timer_new(gus->card, "GF1 timer", &tid, &timer) >= 0) { - strcpy(timer->name, "GF1 timer #1"); + strscpy(timer->name, "GF1 timer #1"); timer->private_data = gus; timer->private_free = snd_gf1_timer1_free; timer->hw = snd_gf1_timer1; @@ -166,7 +166,7 @@ void snd_gf1_timers_init(struct snd_gus_card * gus) tid.device++; if (snd_timer_new(gus->card, "GF1 timer", &tid, &timer) >= 0) { - strcpy(timer->name, "GF1 timer #2"); + strscpy(timer->name, "GF1 timer #2"); timer->private_data = gus; timer->private_free = snd_gf1_timer2_free; timer->hw = snd_gf1_timer2; diff --git a/sound/isa/gus/gus_uart.c b/sound/isa/gus/gus_uart.c index 08276509447f..e207f274f240 100644 --- a/sound/isa/gus/gus_uart.c +++ b/sound/isa/gus/gus_uart.c @@ -236,7 +236,7 @@ int snd_gf1_rawmidi_new(struct snd_gus_card *gus, int device) err = snd_rawmidi_new(gus->card, "GF1", device, 1, 1, &rmidi); if (err < 0) return err; - strcpy(rmidi->name, gus->interwave ? "AMD InterWave" : "GF1"); + strscpy(rmidi->name, gus->interwave ? "AMD InterWave" : "GF1"); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_gf1_uart_output); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_gf1_uart_input); rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c index 6eab95bd49c1..28827a2e6cbd 100644 --- a/sound/isa/gus/gusextreme.c +++ b/sound/isa/gus/gusextreme.c @@ -204,15 +204,15 @@ static int snd_gusextreme_mixer(struct snd_card *card) id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; /* reassign AUX to SYNTHESIZER */ - strcpy(id1.name, "Aux Playback Volume"); - strcpy(id2.name, "Synth Playback Volume"); + strscpy(id1.name, "Aux Playback Volume"); + strscpy(id2.name, "Synth Playback Volume"); error = snd_ctl_rename_id(card, &id1, &id2); if (error < 0) return error; /* reassign Master Playback Switch to Synth Playback Switch */ - strcpy(id1.name, "Master Playback Switch"); - strcpy(id2.name, "Synth Playback Switch"); + strscpy(id1.name, "Master Playback Switch"); + strscpy(id2.name, "Synth Playback Switch"); error = snd_ctl_rename_id(card, &id1, &id2); if (error < 0) return error; diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index 445fd2fb50f1..b572411c4422 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c @@ -134,24 +134,24 @@ static int snd_gusmax_mixer(struct snd_wss *chip) memset(&id2, 0, sizeof(id2)); id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; /* reassign AUXA to SYNTHESIZER */ - strcpy(id1.name, "Aux Playback Switch"); - strcpy(id2.name, "Synth Playback Switch"); + strscpy(id1.name, "Aux Playback Switch"); + strscpy(id2.name, "Synth Playback Switch"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) return err; - strcpy(id1.name, "Aux Playback Volume"); - strcpy(id2.name, "Synth Playback Volume"); + strscpy(id1.name, "Aux Playback Volume"); + strscpy(id2.name, "Synth Playback Volume"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) return err; /* reassign AUXB to CD */ - strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; - strcpy(id2.name, "CD Playback Switch"); + strscpy(id1.name, "Aux Playback Switch"); id1.index = 1; + strscpy(id2.name, "CD Playback Switch"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) return err; - strcpy(id1.name, "Aux Playback Volume"); - strcpy(id2.name, "CD Playback Volume"); + strscpy(id1.name, "Aux Playback Volume"); + strscpy(id2.name, "CD Playback Volume"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) return err; diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index 18a98123e286..0e0bcd85a648 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c @@ -271,7 +271,7 @@ static int snd_interwave_detect(struct snd_interwave *iwcard, dev_dbg(gus->card->dev, "[0x%lx] InterWave check - passed\n", gus->gf1.port); gus->interwave = 1; - strcpy(gus->card->shortname, "AMD InterWave"); + strscpy(gus->card->shortname, "AMD InterWave"); gus->revision = rev1 >> 4; #ifndef SNDRV_STB return 0; /* ok.. We have an InterWave board */ @@ -500,11 +500,11 @@ static int snd_interwave_mixer(struct snd_wss *chip) id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; #if 0 /* remove mono microphone controls */ - strcpy(id1.name, "Mic Playback Switch"); + strscpy(id1.name, "Mic Playback Switch"); err = snd_ctl_remove_id(card, &id1); if (err < 0) return err; - strcpy(id1.name, "Mic Playback Volume"); + strscpy(id1.name, "Mic Playback Volume"); err = snd_ctl_remove_id(card, &id1); if (err < 0) return err; @@ -520,24 +520,24 @@ static int snd_interwave_mixer(struct snd_wss *chip) snd_wss_out(chip, CS4231_LEFT_MIC_INPUT, 0x9f); snd_wss_out(chip, CS4231_RIGHT_MIC_INPUT, 0x9f); /* reassign AUXA to SYNTHESIZER */ - strcpy(id1.name, "Aux Playback Switch"); - strcpy(id2.name, "Synth Playback Switch"); + strscpy(id1.name, "Aux Playback Switch"); + strscpy(id2.name, "Synth Playback Switch"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) return err; - strcpy(id1.name, "Aux Playback Volume"); - strcpy(id2.name, "Synth Playback Volume"); + strscpy(id1.name, "Aux Playback Volume"); + strscpy(id2.name, "Synth Playback Volume"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) return err; /* reassign AUXB to CD */ - strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; - strcpy(id2.name, "CD Playback Switch"); + strscpy(id1.name, "Aux Playback Switch"); id1.index = 1; + strscpy(id2.name, "CD Playback Switch"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) return err; - strcpy(id1.name, "Aux Playback Volume"); - strcpy(id2.name, "CD Playback Volume"); + strscpy(id1.name, "Aux Playback Volume"); + strscpy(id2.name, "CD Playback Volume"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) return err; @@ -713,14 +713,14 @@ static int snd_interwave_probe(struct snd_card *card, int dev, memset(&id1, 0, sizeof(id1)); memset(&id2, 0, sizeof(id2)); id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strcpy(id1.name, "Master Playback Switch"); - strcpy(id2.name, id1.name); + strscpy(id1.name, "Master Playback Switch"); + strscpy(id2.name, id1.name); id2.index = 1; err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) return err; - strcpy(id1.name, "Master Playback Volume"); - strcpy(id2.name, id1.name); + strscpy(id1.name, "Master Playback Volume"); + strscpy(id2.name, id1.name); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) return err; @@ -742,8 +742,8 @@ static int snd_interwave_probe(struct snd_card *card, int dev, #else str = "InterWave STB"; #endif - strcpy(card->driver, str); - strcpy(card->shortname, str); + strscpy(card->driver, str); + strscpy(card->shortname, str); sprintf(card->longname, "%s at 0x%lx, irq %i, dma %d", str, gus->gf1.port, From 9c4e42967dc5c358d4bec463b71a9ac7c7b9e855 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:14 +0200 Subject: [PATCH 245/385] ALSA: msnd: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-33-tiwai@suse.de --- sound/isa/msnd/msnd.c | 2 +- sound/isa/msnd/msnd_pinnacle.c | 22 +++++++++++----------- sound/isa/msnd/msnd_pinnacle_mixer.c | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/sound/isa/msnd/msnd.c b/sound/isa/msnd/msnd.c index 69c515421dd8..8c1d2e27854b 100644 --- a/sound/isa/msnd/msnd.c +++ b/sound/isa/msnd/msnd.c @@ -673,7 +673,7 @@ int snd_msnd_pcm(struct snd_card *card, int device) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_msnd_capture_ops); pcm->private_data = chip; - strcpy(pcm->name, "Hurricane"); + strscpy(pcm->name, "Hurricane"); return 0; } diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c index 8caf431677e5..969bbb18657b 100644 --- a/sound/isa/msnd/msnd_pinnacle.c +++ b/sound/isa/msnd/msnd_pinnacle.c @@ -221,8 +221,8 @@ static int snd_msnd_probe(struct snd_card *card) } #ifdef MSND_CLASSIC - strcpy(card->shortname, "Classic/Tahiti/Monterey"); - strcpy(card->longname, "Turtle Beach Multisound"); + strscpy(card->shortname, "Classic/Tahiti/Monterey"); + strscpy(card->longname, "Turtle Beach Multisound"); dev_info(card->dev, LOGNAME ": %s, " "I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n", card->shortname, @@ -251,38 +251,38 @@ static int snd_msnd_probe(struct snd_card *card) switch (info & 0x7) { case 0x0: rev = "I"; - strcpy(card->shortname, pin); + strscpy(card->shortname, pin); break; case 0x1: rev = "F"; - strcpy(card->shortname, pin); + strscpy(card->shortname, pin); break; case 0x2: rev = "G"; - strcpy(card->shortname, pin); + strscpy(card->shortname, pin); break; case 0x3: rev = "H"; - strcpy(card->shortname, pin); + strscpy(card->shortname, pin); break; case 0x4: rev = "E"; - strcpy(card->shortname, fiji); + strscpy(card->shortname, fiji); break; case 0x5: rev = "C"; - strcpy(card->shortname, fiji); + strscpy(card->shortname, fiji); break; case 0x6: rev = "D"; - strcpy(card->shortname, fiji); + strscpy(card->shortname, fiji); break; case 0x7: rev = "A-B (Fiji) or A-E (Pinnacle)"; - strcpy(card->shortname, pinfiji); + strscpy(card->shortname, pinfiji); break; } - strcpy(card->longname, "Turtle Beach Multisound Pinnacle"); + strscpy(card->longname, "Turtle Beach Multisound Pinnacle"); dev_info(card->dev, LOGNAME ": %s revision %s, Xilinx version %s, " "I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n", card->shortname, diff --git a/sound/isa/msnd/msnd_pinnacle_mixer.c b/sound/isa/msnd/msnd_pinnacle_mixer.c index 63633bd41e5b..2f1bb5a2b376 100644 --- a/sound/isa/msnd/msnd_pinnacle_mixer.c +++ b/sound/isa/msnd/msnd_pinnacle_mixer.c @@ -299,7 +299,7 @@ int snd_msndmix_new(struct snd_card *card) if (snd_BUG_ON(!chip)) return -EINVAL; spin_lock_init(&chip->mixer_lock); - strcpy(card->mixername, "MSND Pinnacle Mixer"); + strscpy(card->mixername, "MSND Pinnacle Mixer"); for (idx = 0; idx < ARRAY_SIZE(snd_msnd_controls); idx++) { err = snd_ctl_add(card, From c7eaa0ebed3589fe416aac22b2deb23c7ee4ff4f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:15 +0200 Subject: [PATCH 246/385] ALSA: opl3sa2: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-34-tiwai@suse.de --- sound/isa/opl3sa2.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index a5ed5aa0606f..5e8e1326d5c0 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c @@ -488,30 +488,30 @@ static int snd_opl3sa2_mixer(struct snd_card *card) memset(&id2, 0, sizeof(id2)); id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; /* reassign AUX0 to CD */ - strcpy(id1.name, "Aux Playback Switch"); - strcpy(id2.name, "CD Playback Switch"); + strscpy(id1.name, "Aux Playback Switch"); + strscpy(id2.name, "CD Playback Switch"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) { dev_err(card->dev, "Cannot rename opl3sa2 control\n"); return err; } - strcpy(id1.name, "Aux Playback Volume"); - strcpy(id2.name, "CD Playback Volume"); + strscpy(id1.name, "Aux Playback Volume"); + strscpy(id2.name, "CD Playback Volume"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) { dev_err(card->dev, "Cannot rename opl3sa2 control\n"); return err; } /* reassign AUX1 to FM */ - strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; - strcpy(id2.name, "FM Playback Switch"); + strscpy(id1.name, "Aux Playback Switch"); id1.index = 1; + strscpy(id2.name, "FM Playback Switch"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) { dev_err(card->dev, "Cannot rename opl3sa2 control\n"); return err; } - strcpy(id1.name, "Aux Playback Volume"); - strcpy(id2.name, "FM Playback Volume"); + strscpy(id1.name, "Aux Playback Volume"); + strscpy(id2.name, "FM Playback Volume"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) { dev_err(card->dev, "Cannot rename opl3sa2 control\n"); @@ -618,8 +618,8 @@ static int snd_opl3sa2_card_new(struct device *pdev, int dev, sizeof(struct snd_opl3sa2), &card); if (err < 0) return err; - strcpy(card->driver, "OPL3SA2"); - strcpy(card->shortname, "Yamaha OPL3-SA"); + strscpy(card->driver, "OPL3SA2"); + strscpy(card->shortname, "Yamaha OPL3-SA"); chip = card->private_data; spin_lock_init(&chip->reg_lock); chip->irq = -1; From b4a82a97c4d4126143e08966405c6b3b653d3b0d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:16 +0200 Subject: [PATCH 247/385] ALSA: opti9xx: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-35-tiwai@suse.de --- sound/isa/opti9xx/miro.c | 8 ++++---- sound/isa/opti9xx/opti92x-ad1848.c | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index 31d736d1dd10..ad7180d7c0c2 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -718,10 +718,10 @@ static int snd_miro_mixer(struct snd_card *card, switch (miro->hardware) { case OPTi9XX_HW_82C924: - strcpy(card->mixername, "ACI & OPTi924"); + strscpy(card->mixername, "ACI & OPTi924"); break; case OPTi9XX_HW_82C929: - strcpy(card->mixername, "ACI & OPTi929"); + strscpy(card->mixername, "ACI & OPTi929"); break; default: snd_BUG(); @@ -779,7 +779,7 @@ static int snd_miro_init(struct snd_miro *chip, static const int opti9xx_mc_size[] = {7, 7, 10, 10, 2, 2, 2}; chip->hardware = hardware; - strcpy(chip->name, snd_opti9xx_names[hardware]); + strscpy(chip->name, snd_opti9xx_names[hardware]); chip->mc_base_size = opti9xx_mc_size[hardware]; @@ -1351,7 +1351,7 @@ static int snd_miro_probe(struct snd_card *card) sprintf(card->shortname, "unknown Cardinal Technologies"); } - strcpy(card->driver, "miro"); + strscpy(card->driver, "miro"); scnprintf(card->longname, sizeof(card->longname), "%s: OPTi%s, %s at 0x%lx, irq %d, dma %d&%d", card->shortname, miro->name, codec->pcm->name, diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index a07a665d93dc..328d043a1619 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -171,7 +171,7 @@ static int snd_opti9xx_init(struct snd_opti9xx *chip, static const int opti9xx_mc_size[] = {7, 7, 10, 10, 2, 2, 2}; chip->hardware = hardware; - strcpy(chip->name, snd_opti9xx_names[hardware]); + strscpy(chip->name, snd_opti9xx_names[hardware]); spin_lock_init(&chip->lock); @@ -594,35 +594,35 @@ static int snd_opti93x_mixer(struct snd_wss *chip) card = chip->card; - strcpy(card->mixername, chip->pcm->name); + strscpy(card->mixername, chip->pcm->name); memset(&id1, 0, sizeof(id1)); memset(&id2, 0, sizeof(id2)); id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; /* reassign AUX0 switch to CD */ - strcpy(id1.name, "Aux Playback Switch"); - strcpy(id2.name, "CD Playback Switch"); + strscpy(id1.name, "Aux Playback Switch"); + strscpy(id2.name, "CD Playback Switch"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) { dev_err(card->dev, "Cannot rename opti93x control\n"); return err; } /* reassign AUX1 switch to FM */ - strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; - strcpy(id2.name, "FM Playback Switch"); + strscpy(id1.name, "Aux Playback Switch"); id1.index = 1; + strscpy(id2.name, "FM Playback Switch"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) { dev_err(card->dev, "Cannot rename opti93x control\n"); return err; } /* remove AUX1 volume */ - strcpy(id1.name, "Aux Playback Volume"); id1.index = 1; + strscpy(id1.name, "Aux Playback Volume"); id1.index = 1; snd_ctl_remove_id(card, &id1); /* Replace WSS volume controls with OPTi93x volume controls */ id1.index = 0; for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { - strcpy(id1.name, snd_opti93x_controls[idx].name); + strscpy(id1.name, snd_opti93x_controls[idx].name); snd_ctl_remove_id(card, &id1); err = snd_ctl_add(card, @@ -857,7 +857,7 @@ static int snd_opti9xx_probe(struct snd_card *card) #endif chip->irq = irq; card->sync_irq = chip->irq; - strcpy(card->driver, chip->name); + strscpy(card->driver, chip->name); sprintf(card->shortname, "OPTi %s", card->driver); #if defined(CS4231) || defined(OPTi93X) scnprintf(card->longname, sizeof(card->longname), From c8eef317e66bb958eaa3b156386fdd3962706bf0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:17 +0200 Subject: [PATCH 248/385] ALSA: sc6000: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-36-tiwai@suse.de --- sound/isa/sc6000.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c index 3115c32b4061..6d618cc2ba45 100644 --- a/sound/isa/sc6000.c +++ b/sound/isa/sc6000.c @@ -469,24 +469,24 @@ static int snd_sc6000_mixer(struct snd_wss *chip) id1.iface = SNDRV_CTL_ELEM_IFACE_MIXER; id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; /* reassign AUX0 to FM */ - strcpy(id1.name, "Aux Playback Switch"); - strcpy(id2.name, "FM Playback Switch"); + strscpy(id1.name, "Aux Playback Switch"); + strscpy(id2.name, "FM Playback Switch"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) return err; - strcpy(id1.name, "Aux Playback Volume"); - strcpy(id2.name, "FM Playback Volume"); + strscpy(id1.name, "Aux Playback Volume"); + strscpy(id2.name, "FM Playback Volume"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) return err; /* reassign AUX1 to CD */ - strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; - strcpy(id2.name, "CD Playback Switch"); + strscpy(id1.name, "Aux Playback Switch"); id1.index = 1; + strscpy(id2.name, "CD Playback Switch"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) return err; - strcpy(id1.name, "Aux Playback Volume"); - strcpy(id2.name, "CD Playback Volume"); + strscpy(id1.name, "Aux Playback Volume"); + strscpy(id2.name, "CD Playback Volume"); err = snd_ctl_rename_id(card, &id1, &id2); if (err < 0) return err; @@ -652,8 +652,8 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) mpu_port[dev]); } - strcpy(card->driver, DRV_NAME); - strcpy(card->shortname, "SC-6000"); + strscpy(card->driver, DRV_NAME); + strscpy(card->shortname, "SC-6000"); sprintf(card->longname, "Gallant SC-6000 at 0x%lx, irq %d, dma %d", mss_port[dev], xirq, xdma); From 96b1776d019a7f1865fc3078c68650654319b509 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:18 +0200 Subject: [PATCH 249/385] ALSA: sscape: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-37-tiwai@suse.de --- sound/isa/sscape.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 09120e38f4c2..709a1659d66f 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -1047,8 +1047,8 @@ static int create_sscape(int dev, struct snd_card *card) wss_port[dev], irq[dev]); return err; } - strcpy(card->driver, "SoundScape"); - strcpy(card->shortname, name); + strscpy(card->driver, "SoundScape"); + strscpy(card->shortname, name); snprintf(card->longname, sizeof(card->longname), "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n", name, sscape->chip->port, sscape->chip->irq, From 2e2a2feb915c90d2a2be96373339157e11a614fb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:19 +0200 Subject: [PATCH 250/385] ALSA: wavefront: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-38-tiwai@suse.de --- sound/isa/wavefront/wavefront.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c index 621ab420a60f..07c68568091d 100644 --- a/sound/isa/wavefront/wavefront.c +++ b/sound/isa/wavefront/wavefront.c @@ -234,7 +234,7 @@ static struct snd_hwdep *snd_wavefront_new_synth(struct snd_card *card, if (snd_hwdep_new(card, "WaveFront", hw_dev, &wavefront_synth) < 0) return NULL; - strcpy (wavefront_synth->name, + strscpy (wavefront_synth->name, "WaveFront (ICS2115) wavetable synthesizer"); wavefront_synth->ops.open = snd_wavefront_synth_open; wavefront_synth->ops.release = snd_wavefront_synth_release; @@ -292,10 +292,10 @@ static struct snd_rawmidi *snd_wavefront_new_midi(struct snd_card *card, return NULL; if (mpu == internal_mpu) { - strcpy(rmidi->name, "WaveFront MIDI (Internal)"); + strscpy(rmidi->name, "WaveFront MIDI (Internal)"); rmidi->private_data = &internal_id; } else { - strcpy(rmidi->name, "WaveFront MIDI (External)"); + strscpy(rmidi->name, "WaveFront MIDI (External)"); rmidi->private_data = &external_id; } @@ -407,7 +407,7 @@ snd_wavefront_probe (struct snd_card *card, int dev) return -ENOMEM; } - strcpy (wavefront_synth->name, "ICS2115 Wavetable MIDI Synthesizer"); + strscpy (wavefront_synth->name, "ICS2115 Wavetable MIDI Synthesizer"); wavefront_synth->iface = SNDRV_HWDEP_IFACE_ICS2115; hw_dev++; @@ -478,12 +478,12 @@ snd_wavefront_probe (struct snd_card *card, int dev) hw_dev++; - strcpy(card->driver, "Tropez+"); - strcpy(card->shortname, "Turtle Beach Tropez+"); + strscpy(card->driver, "Tropez+"); + strscpy(card->shortname, "Turtle Beach Tropez+"); } else { /* Need a way to distinguish between Maui and Tropez */ - strcpy(card->driver, "WaveFront"); - strcpy(card->shortname, "Turtle Beach WaveFront"); + strscpy(card->driver, "WaveFront"); + strscpy(card->shortname, "Turtle Beach WaveFront"); } /* ----- Register the card --------- */ From fc52ff69c5f1b144bfc9edaa7160fde993c874f5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:20 +0200 Subject: [PATCH 251/385] ALSA: wss: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-39-tiwai@suse.de --- sound/isa/wss/wss_lib.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 9c655789574d..1b6a80021d18 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -1865,7 +1865,7 @@ int snd_wss_pcm(struct snd_wss *chip, int device) pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX; if (chip->hardware != WSS_HW_INTERWAVE) pcm->info_flags |= SNDRV_PCM_INFO_JOINT_DUPLEX; - strcpy(pcm->name, snd_wss_chip_id(chip)); + strscpy(pcm->name, snd_wss_chip_id(chip)); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, chip->card->dev, 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); @@ -1896,7 +1896,7 @@ int snd_wss_timer(struct snd_wss *chip, int device) err = snd_timer_new(chip->card, "CS4231", &tid, &timer); if (err < 0) return err; - strcpy(timer->name, snd_wss_chip_id(chip)); + strscpy(timer->name, snd_wss_chip_id(chip)); timer->private_data = chip; timer->private_free = snd_wss_timer_free; timer->hw = snd_wss_timer_table; @@ -2176,7 +2176,7 @@ int snd_wss_mixer(struct snd_wss *chip) card = chip->card; - strcpy(card->mixername, chip->pcm->name); + strscpy(card->mixername, chip->pcm->name); /* Use only the first 11 entries on AD1848 */ if (chip->hardware & WSS_HW_AD1848_MASK) From 7169b6a6763d5a879f42ce1a1aad72b6d611e375 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:21 +0200 Subject: [PATCH 252/385] ALSA: mips: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-40-tiwai@suse.de --- sound/mips/hal2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c index 991793e6bda9..f88e6a6733a5 100644 --- a/sound/mips/hal2.c +++ b/sound/mips/hal2.c @@ -706,7 +706,7 @@ static int hal2_pcm_create(struct snd_hal2 *hal2) return err; pcm->private_data = hal2; - strcpy(pcm->name, "SGI HAL2"); + strscpy(pcm->name, "SGI HAL2"); /* set operators */ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, @@ -862,8 +862,8 @@ static int hal2_probe(struct platform_device *pdev) return err; } - strcpy(card->driver, "SGI HAL2 Audio"); - strcpy(card->shortname, "SGI HAL2 Audio"); + strscpy(card->driver, "SGI HAL2 Audio"); + strscpy(card->shortname, "SGI HAL2 Audio"); sprintf(card->longname, "%s irq %i", card->shortname, SGI_HPCDMA_IRQ); From c9b41682945f3c389bd230aa74bd1409df31b521 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:22 +0200 Subject: [PATCH 253/385] ALSA: parisc: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-41-tiwai@suse.de --- sound/parisc/harmony.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c index db9c296dd688..76dd2210f9ea 100644 --- a/sound/parisc/harmony.c +++ b/sound/parisc/harmony.c @@ -601,7 +601,7 @@ snd_harmony_pcm_init(struct snd_harmony *h) pcm->private_data = h; pcm->info_flags = 0; - strcpy(pcm->name, "harmony"); + strscpy(pcm->name, "harmony"); h->pcm = pcm; h->psubs = NULL; @@ -823,7 +823,7 @@ snd_harmony_mixer_init(struct snd_harmony *h) if (snd_BUG_ON(!h)) return -EINVAL; card = h->card; - strcpy(card->mixername, "Harmony Gain control interface"); + strscpy(card->mixername, "Harmony Gain control interface"); for (idx = 0; idx < HARMONY_CONTROLS; idx++) { err = snd_ctl_add(card, @@ -937,8 +937,8 @@ snd_harmony_probe(struct parisc_device *padev) if (err < 0) goto free_and_ret; - strcpy(card->driver, "harmony"); - strcpy(card->shortname, "Harmony"); + strscpy(card->driver, "harmony"); + strscpy(card->shortname, "Harmony"); sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, h->hpa, h->irq); From c9b7c4b628817f8aae757924210f55374362e91d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:23 +0200 Subject: [PATCH 254/385] ALSA: ac97: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-42-tiwai@suse.de --- sound/pci/ac97/ac97_codec.c | 4 ++-- sound/pci/ac97/ac97_patch.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 88ac37739b76..588c094080be 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -2303,7 +2303,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, if (ac97_is_audio(ac97)) { char comp[16]; if (card->mixername[0] == '\0') { - strcpy(card->mixername, name); + strscpy(card->mixername, name); } else { if (strlen(card->mixername) + 1 + strlen(name) + 1 <= sizeof(card->mixername)) { strcat(card->mixername, ","); @@ -2324,7 +2324,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, if (ac97_is_modem(ac97)) { char comp[16]; if (card->mixername[0] == '\0') { - strcpy(card->mixername, name); + strscpy(card->mixername, name); } else { if (strlen(card->mixername) + 1 + strlen(name) + 1 <= sizeof(card->mixername)) { strcat(card->mixername, ","); diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index cd83aa864ea3..3002be9d88f3 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -298,7 +298,7 @@ static int patch_yamaha_ymf7x3_3d(struct snd_ac97 *ac97) err = snd_ctl_add(ac97->bus->card, kctl); if (err < 0) return err; - strcpy(kctl->id.name, "3D Control - Wide"); + strscpy(kctl->id.name, "3D Control - Wide"); kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 9, 7, 0); snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); err = snd_ctl_add(ac97->bus->card, @@ -891,7 +891,7 @@ static int patch_sigmatel_stac9700_3d(struct snd_ac97 * ac97) err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97)); if (err < 0) return err; - strcpy(kctl->id.name, "3D Control Sigmatel - Depth"); + strscpy(kctl->id.name, "3D Control Sigmatel - Depth"); kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 2, 3, 0); snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); return 0; @@ -906,13 +906,13 @@ static int patch_sigmatel_stac9708_3d(struct snd_ac97 * ac97) err = snd_ctl_add(ac97->bus->card, kctl); if (err < 0) return err; - strcpy(kctl->id.name, "3D Control Sigmatel - Depth"); + strscpy(kctl->id.name, "3D Control Sigmatel - Depth"); kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 0, 3, 0); kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97); err = snd_ctl_add(ac97->bus->card, kctl); if (err < 0) return err; - strcpy(kctl->id.name, "3D Control Sigmatel - Rear Depth"); + strscpy(kctl->id.name, "3D Control Sigmatel - Rear Depth"); kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 2, 3, 0); snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); return 0; From 48102e32203178012567e6b78192e707d5ca7668 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:24 +0200 Subject: [PATCH 255/385] ALSA: ad1889: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-43-tiwai@suse.de --- sound/pci/ad1889.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index ac27a93ce4ff..020cbb467e7e 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -605,7 +605,7 @@ snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device) pcm->private_data = chip; pcm->info_flags = 0; - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); chip->pcm = pcm; chip->psubs = NULL; @@ -866,8 +866,8 @@ __snd_ad1889_probe(struct pci_dev *pci, return err; chip = card->private_data; - strcpy(card->driver, "AD1889"); - strcpy(card->shortname, "Analog Devices AD1889"); + strscpy(card->driver, "AD1889"); + strscpy(card->shortname, "Analog Devices AD1889"); /* (3) */ err = snd_ad1889_create(card, pci); From 1d68ba24a79c2dce7cdb4bfbc6fdd8e0b2e69b85 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:25 +0200 Subject: [PATCH 256/385] ALSA: ak4531: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-44-tiwai@suse.de --- sound/pci/ak4531_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/ak4531_codec.c b/sound/pci/ak4531_codec.c index 6af88e7b86f8..e54812bfb2c6 100644 --- a/sound/pci/ak4531_codec.c +++ b/sound/pci/ak4531_codec.c @@ -389,7 +389,7 @@ int snd_ak4531_mixer(struct snd_card *card, snd_ak4531_free(ak4531); return err; } - strcpy(card->mixername, "Asahi Kasei AK4531"); + strscpy(card->mixername, "Asahi Kasei AK4531"); ak4531->write(ak4531, AK4531_RESET, 0x03); /* no RST, PD */ udelay(100); ak4531->write(ak4531, AK4531_CLOCK, 0x00); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off LRCLK2 PLL */ From 3edc76a671f761f6797e55cab88157f43256dedd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:26 +0200 Subject: [PATCH 257/385] ALSA: ali5451: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-45-tiwai@suse.de --- sound/pci/ali5451/ali5451.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 69c02bdd38ce..a6e499e0ceda 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -1645,7 +1645,7 @@ static int snd_ali_pcm(struct snd_ali *codec, int device, pcm->info_flags = 0; pcm->dev_class = desc->class; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; - strcpy(pcm->name, desc->name); + strscpy(pcm->name, desc->name); codec->pcm[0] = pcm; return 0; } @@ -2133,8 +2133,8 @@ static int __snd_ali_probe(struct pci_dev *pci, snd_ali_proc_init(codec); - strcpy(card->driver, "ALI5451"); - strcpy(card->shortname, "ALI 5451"); + strscpy(card->driver, "ALI5451"); + strscpy(card->shortname, "ALI 5451"); sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, codec->port, codec->irq); From 03b0a614e2292a4afcaf5d196752d02803e2e6ca Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:27 +0200 Subject: [PATCH 258/385] ALSA: als300: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-46-tiwai@suse.de --- sound/pci/als300.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 43f98719e61b..f9e8424dc77f 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -546,7 +546,7 @@ static int snd_als300_new_pcm(struct snd_als300 *chip) if (err < 0) return err; pcm->private_data = chip; - strcpy(pcm->name, "ALS300"); + strscpy(pcm->name, "ALS300"); chip->pcm = pcm; /* set operators */ @@ -705,7 +705,7 @@ static int snd_als300_probe(struct pci_dev *pci, if (err < 0) goto error; - strcpy(card->driver, "ALS300"); + strscpy(card->driver, "ALS300"); if (chip->chip_type == DEVICE_ALS300_PLUS) /* don't know much about ALS300+ yet * print revision number for now */ From 1813fa7c587a35aa1d73e1d6d4f1599ecac8bd33 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:28 +0200 Subject: [PATCH 259/385] ALSA: als4000: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-47-tiwai@suse.de --- sound/pci/als4000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 3f4f3037f71f..eb159497c905 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -877,8 +877,8 @@ static int __snd_card_als4000_probe(struct pci_dev *pci, snd_als4000_configure(chip); - strcpy(card->driver, "ALS4000"); - strcpy(card->shortname, "Avance Logic ALS4000"); + strscpy(card->driver, "ALS4000"); + strscpy(card->shortname, "Avance Logic ALS4000"); sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, chip->alt_port, chip->irq); From 1882c12ae2ab01d52b33d72b7b3203c44819a8f9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:29 +0200 Subject: [PATCH 260/385] ALSA: asihpi: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-48-tiwai@suse.de --- sound/pci/asihpi/asihpi.c | 10 +++++----- sound/pci/asihpi/hpi6000.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index cbd964f87349..8419f2b6e589 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -1257,7 +1257,7 @@ static int snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi, int device) pcm->private_data = asihpi; pcm->info_flags = 0; - strcpy(pcm->name, "Asihpi PCM"); + strscpy(pcm->name, "Asihpi PCM"); /*? do we want to emulate MMAP for non-BBM cards? Jack doesn't work with ALSAs MMAP emulation - WHY NOT? */ @@ -2310,7 +2310,7 @@ static int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol, uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, + strscpy(uinfo->value.enumerated.name, clkcache->s[uinfo->value.enumerated.item].name); return 0; } @@ -2530,7 +2530,7 @@ static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) if (snd_BUG_ON(!asihpi)) return -EINVAL; card = asihpi->card; - strcpy(card->mixername, "Asihpi Mixer"); + strscpy(card->mixername, "Asihpi Mixer"); err = hpi_mixer_open(asihpi->hpi->adapter->index, @@ -2741,7 +2741,7 @@ static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, int device) err = snd_hwdep_new(asihpi->card, "HPI", device, &hw); if (err < 0) return err; - strcpy(hw->name, "asihpi (HPI)"); + strscpy(hw->name, "asihpi (HPI)"); hw->iface = SNDRV_HWDEP_IFACE_LAST; hw->ops.open = snd_asihpi_hpi_open; hw->ops.ioctl = snd_asihpi_hpi_ioctl; @@ -2889,7 +2889,7 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev, by enable_hwdep module param*/ snd_asihpi_hpi_new(asihpi, 0); - strcpy(card->driver, "ASIHPI"); + strscpy(card->driver, "ASIHPI"); sprintf(card->shortname, "AudioScience ASI%4X", asihpi->hpi->adapter->type); diff --git a/sound/pci/asihpi/hpi6000.c b/sound/pci/asihpi/hpi6000.c index 72aa135d69f8..b08578c93c6a 100644 --- a/sound/pci/asihpi/hpi6000.c +++ b/sound/pci/asihpi/hpi6000.c @@ -608,7 +608,7 @@ static void adapter_get_asserts(struct hpi_adapter_obj *pao, phr->u.ax.assert.p2 = 0; phr->u.ax.assert.count = 1; /* assert count */ phr->u.ax.assert.dsp_index = -1; /* "dsp index" */ - strcpy(phr->u.ax.assert.sz_message, "PCI2040 error"); + strscpy(phr->u.ax.assert.sz_message, "PCI2040 error"); phr->u.ax.assert.dsp_msg_addr = 0; gw_pci_read_asserts = 0; gw_pci_write_asserts = 0; From 2dc364f96536b7b5e6c32f8dc5fa4917d92acf4c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:30 +0200 Subject: [PATCH 261/385] ALSA: atiixp: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-49-tiwai@suse.de --- sound/pci/atiixp.c | 10 +++++----- sound/pci/atiixp_modem.c | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 427006be240b..4f544950ee7b 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1271,7 +1271,7 @@ static int snd_atiixp_pcm_new(struct atiixp *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_atiixp_capture_ops); pcm->private_data = chip; - strcpy(pcm->name, "ATI IXP AC97"); + strscpy(pcm->name, "ATI IXP AC97"); chip->pcmdevs[ATI_PCMDEV_ANALOG] = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -1301,9 +1301,9 @@ static int snd_atiixp_pcm_new(struct atiixp *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_spdif_ops); pcm->private_data = chip; if (chip->spdif_over_aclink) - strcpy(pcm->name, "ATI IXP IEC958 (AC97)"); + strscpy(pcm->name, "ATI IXP IEC958 (AC97)"); else - strcpy(pcm->name, "ATI IXP IEC958 (Direct)"); + strscpy(pcm->name, "ATI IXP IEC958 (Direct)"); chip->pcmdevs[ATI_PCMDEV_DIGITAL] = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -1576,8 +1576,8 @@ static int __snd_atiixp_probe(struct pci_dev *pci, return err; chip = card->private_data; - strcpy(card->driver, spdif_aclink ? "ATIIXP" : "ATIIXP-SPDMA"); - strcpy(card->shortname, "ATI IXP"); + strscpy(card->driver, spdif_aclink ? "ATIIXP" : "ATIIXP-SPDMA"); + strscpy(card->shortname, "ATI IXP"); err = snd_atiixp_init(card, pci); if (err < 0) return err; diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 8d3083b9b024..f7417c2bb477 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -982,7 +982,7 @@ static int snd_atiixp_pcm_new(struct atiixp_modem *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_atiixp_capture_ops); pcm->dev_class = SNDRV_PCM_CLASS_MODEM; pcm->private_data = chip; - strcpy(pcm->name, "ATI IXP MC97"); + strscpy(pcm->name, "ATI IXP MC97"); chip->pcmdevs[ATI_PCMDEV_ANALOG] = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -1206,8 +1206,8 @@ static int __snd_atiixp_probe(struct pci_dev *pci, return err; chip = card->private_data; - strcpy(card->driver, "ATIIXP-MODEM"); - strcpy(card->shortname, "ATI IXP Modem"); + strscpy(card->driver, "ATIIXP-MODEM"); + strscpy(card->shortname, "ATI IXP Modem"); err = snd_atiixp_init(card, pci); if (err < 0) return err; From 5cd156964fe731f0c852ed5c51b9b64aaf046a53 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:31 +0200 Subject: [PATCH 262/385] ALSA: au88x0: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-50-tiwai@suse.de --- sound/pci/au88x0/au88x0.c | 4 ++-- sound/pci/au88x0/au88x0_mixer.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index fd986247331a..de56e83d8e10 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c @@ -220,7 +220,7 @@ __snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) snd_vortex_workaround(pci, pcifix[dev]); // Card details needed in snd_vortex_midi - strcpy(card->driver, CARD_NAME_SHORT); + strscpy(card->driver, CARD_NAME_SHORT); sprintf(card->shortname, "Aureal Vortex %s", CARD_NAME_SHORT); sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->io, chip->irq); @@ -270,7 +270,7 @@ __snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) snd_vortex_synth_arg_t *arg; arg = SNDRV_SEQ_DEVICE_ARGPTR(wave); - strcpy(wave->name, "Aureal Synth"); + strscpy(wave->name, "Aureal Synth"); arg->hwptr = vortex; arg->index = 1; arg->seq_ports = seq_ports[dev]; diff --git a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c index aeba684b8d18..00781a7fd28c 100644 --- a/sound/pci/au88x0/au88x0_mixer.c +++ b/sound/pci/au88x0/au88x0_mixer.c @@ -15,7 +15,7 @@ static int remove_ctl(struct snd_card *card, const char *name) { struct snd_ctl_elem_id id; memset(&id, 0, sizeof(id)); - strcpy(id.name, name); + strscpy(id.name, name); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; return snd_ctl_remove_id(card, &id); } From f6e41e48d994f4e569df2f4be69f12e9b5641b87 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:32 +0200 Subject: [PATCH 263/385] ALSA: aw2: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-51-tiwai@suse.de --- sound/pci/aw2/aw2-alsa.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index 7b4b8f785517..1d7aab14579e 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c @@ -281,8 +281,8 @@ static int snd_aw2_probe(struct pci_dev *pci, /* init spinlock */ spin_lock_init(&chip->reg_lock); /* (4) Define driver ID and name string */ - strcpy(card->driver, "aw2"); - strcpy(card->shortname, "Audiowerk2"); + strscpy(card->driver, "aw2"); + strscpy(card->shortname, "Audiowerk2"); sprintf(card->longname, "%s with SAA7146 irq %i", card->shortname, chip->irq); @@ -509,7 +509,7 @@ static int snd_aw2_new_pcm(struct aw2 *chip) pcm_device = &chip->device_playback[NUM_STREAM_PLAYBACK_ANA]; /* Set PCM device name */ - strcpy(pcm_playback_ana->name, "Analog playback"); + strscpy(pcm_playback_ana->name, "Analog playback"); /* Associate private data to PCM device */ pcm_playback_ana->private_data = pcm_device; /* set operators of PCM device */ @@ -541,7 +541,7 @@ static int snd_aw2_new_pcm(struct aw2 *chip) pcm_device = &chip->device_playback[NUM_STREAM_PLAYBACK_DIG]; /* Set PCM device name */ - strcpy(pcm_playback_num->name, "Digital playback"); + strscpy(pcm_playback_num->name, "Digital playback"); /* Associate private data to PCM device */ pcm_playback_num->private_data = pcm_device; /* set operators of PCM device */ @@ -574,7 +574,7 @@ static int snd_aw2_new_pcm(struct aw2 *chip) pcm_device = &chip->device_capture[NUM_STREAM_CAPTURE_ANA]; /* Set PCM device name */ - strcpy(pcm_capture->name, "Capture"); + strscpy(pcm_capture->name, "Capture"); /* Associate private data to PCM device */ pcm_capture->private_data = pcm_device; /* set operators of PCM device */ From 8b1208d70ae49c56e7742f172ae6f39fcebca2ba Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:33 +0200 Subject: [PATCH 264/385] ALSA: azt3328: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-52-tiwai@suse.de --- sound/pci/azt3328.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 053a18f434bf..4418b9ae33e6 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -1188,7 +1188,7 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip) return err; } snd_component_add(card, "AZF3328 mixer"); - strcpy(card->mixername, "AZF3328 mixer"); + strscpy(card->mixername, "AZF3328 mixer"); return 0; } @@ -2095,7 +2095,7 @@ snd_azf3328_pcm(struct snd_azf3328 *chip) pcm->private_data = chip; pcm->info_flags = 0; - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); /* same pcm object for playback/capture (see snd_pcm_new() above) */ chip->pcm[AZF_CODEC_PLAYBACK] = pcm; chip->pcm[AZF_CODEC_CAPTURE] = pcm; @@ -2112,7 +2112,7 @@ snd_azf3328_pcm(struct snd_azf3328 *chip) pcm->private_data = chip; pcm->info_flags = 0; - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); chip->pcm[AZF_CODEC_I2S_OUT] = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &chip->pci->dev, @@ -2217,7 +2217,7 @@ snd_azf3328_timer(struct snd_azf3328 *chip, int device) if (err < 0) goto out; - strcpy(timer->name, "AZF3328 timer"); + strscpy(timer->name, "AZF3328 timer"); timer->private_data = chip; timer->hw = snd_azf3328_timer_hw; @@ -2437,8 +2437,8 @@ __snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) return err; chip = card->private_data; - strcpy(card->driver, "AZF3328"); - strcpy(card->shortname, "Aztech AZF3328 (PCI168)"); + strscpy(card->driver, "AZF3328"); + strscpy(card->shortname, "Aztech AZF3328 (PCI168)"); err = snd_azf3328_create(card, pci, pci_id->driver_data); if (err < 0) From dd4fcc8f04929a53a8001915266a7beccc5e0652 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:34 +0200 Subject: [PATCH 265/385] ALSA: bt87x: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-53-tiwai@suse.de --- sound/pci/bt87x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 91492dd2b38a..b70f6f4ffe67 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -672,7 +672,7 @@ static int snd_bt87x_pcm(struct snd_bt87x *chip, int device, char *name) if (err < 0) return err; pcm->private_data = chip; - strcpy(pcm->name, name); + strscpy(pcm->name, name); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_bt87x_pcm_ops); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_SG, &chip->pci->dev, @@ -872,12 +872,12 @@ static int __snd_bt87x_probe(struct pci_dev *pci, chip->board.no_analog ? "no " : "", chip->board.no_digital ? "no " : "", chip->board.dig_rate); - strcpy(card->driver, "Bt87x"); + strscpy(card->driver, "Bt87x"); sprintf(card->shortname, "Brooktree Bt%x", pci->device); sprintf(card->longname, "%s at %#llx, irq %i", card->shortname, (unsigned long long)pci_resource_start(pci, 0), chip->irq); - strcpy(card->mixername, "Bt87x"); + strscpy(card->mixername, "Bt87x"); err = snd_card_register(card); if (err < 0) From 32aeb8606936d4f928aa28fb85c2785b5fa5870e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:35 +0200 Subject: [PATCH 266/385] ALSA: ca0106: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-54-tiwai@suse.de --- sound/pci/ca0106/ca0106_main.c | 6 +++--- sound/pci/ca0106/ca0106_mixer.c | 4 ++-- sound/pci/ca0106/ca_midi.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 7c7119cad63c..242618793181 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1315,7 +1315,7 @@ static int snd_ca0106_pcm(struct snd_ca0106 *emu, int device) } pcm->info_flags = 0; - strcpy(pcm->name, "CA0106"); + strscpy(pcm->name, "CA0106"); for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; @@ -1617,8 +1617,8 @@ static int snd_ca0106_create(int dev, struct snd_card *card, pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); dev_info(card->dev, "Model %04x Rev %08x Serial %08x\n", chip->model, pci->revision, chip->serial); - strcpy(card->driver, "CA0106"); - strcpy(card->shortname, "CA0106"); + strscpy(card->driver, "CA0106"); + strscpy(card->shortname, "CA0106"); for (c = ca0106_chip_details; c->serial; c++) { if (subsystem[dev]) { diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 1d5a899b2c24..f7b6b2db889b 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -701,7 +701,7 @@ static int remove_ctl(struct snd_card *card, const char *name) { struct snd_ctl_elem_id id; memset(&id, 0, sizeof(id)); - strcpy(id.name, name); + strscpy(id.name, name); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; return snd_ctl_remove_id(card, &id); } @@ -849,7 +849,7 @@ int snd_ca0106_mixer(struct snd_ca0106 *emu) return err; } - strcpy(card->mixername, "CA0106"); + strscpy(card->mixername, "CA0106"); return 0; } diff --git a/sound/pci/ca0106/ca_midi.c b/sound/pci/ca0106/ca_midi.c index 957e60f64821..f9cec67f31ac 100644 --- a/sound/pci/ca0106/ca_midi.c +++ b/sound/pci/ca0106/ca_midi.c @@ -287,7 +287,7 @@ int ca_midi_init(void *dev_id, struct snd_ca_midi *midi, int device, char *name) spin_lock_init(&midi->input_lock); spin_lock_init(&midi->output_lock); - strcpy(rmidi->name, name); + strscpy(rmidi->name, name); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &ca_midi_output); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &ca_midi_input); rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | From e43c8878e9dd7f9dc0b75c8f57bdeaa351efe3ef Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:36 +0200 Subject: [PATCH 267/385] ALSA: cmipci: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-55-tiwai@suse.de --- sound/pci/cmipci.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index b00df0a60d3f..9056214e9cda 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -1868,7 +1868,7 @@ static int snd_cmipci_pcm_new(struct cmipci *cm, int device) pcm->private_data = cm; pcm->info_flags = 0; - strcpy(pcm->name, "C-Media PCI DAC/ADC"); + strscpy(pcm->name, "C-Media PCI DAC/ADC"); cm->pcm = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -1890,7 +1890,7 @@ static int snd_cmipci_pcm2_new(struct cmipci *cm, int device) pcm->private_data = cm; pcm->info_flags = 0; - strcpy(pcm->name, "C-Media PCI 2nd DAC"); + strscpy(pcm->name, "C-Media PCI 2nd DAC"); cm->pcm2 = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -1913,7 +1913,7 @@ static int snd_cmipci_pcm_spdif_new(struct cmipci *cm, int device) pcm->private_data = cm; pcm->info_flags = 0; - strcpy(pcm->name, "C-Media PCI IEC958"); + strscpy(pcm->name, "C-Media PCI IEC958"); cm->pcm_spdif = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -2633,7 +2633,7 @@ static int snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device) card = cm->card; - strcpy(card->mixername, "CMedia PCI"); + strscpy(card->mixername, "CMedia PCI"); spin_lock_irq(&cm->reg_lock); snd_cmipci_mixer_write(cm, 0x00, 0x00); /* mixer reset */ @@ -3216,14 +3216,14 @@ static int snd_cmipci_probe(struct pci_dev *pci, switch (pci->device) { case PCI_DEVICE_ID_CMEDIA_CM8738: case PCI_DEVICE_ID_CMEDIA_CM8738B: - strcpy(card->driver, "CMI8738"); + strscpy(card->driver, "CMI8738"); break; case PCI_DEVICE_ID_CMEDIA_CM8338A: case PCI_DEVICE_ID_CMEDIA_CM8338B: - strcpy(card->driver, "CMI8338"); + strscpy(card->driver, "CMI8338"); break; default: - strcpy(card->driver, "CMIPCI"); + strscpy(card->driver, "CMIPCI"); break; } From e3502b8672cafc679b57717e4f9c1abca8106061 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:37 +0200 Subject: [PATCH 268/385] ALSA: cs4281: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-56-tiwai@suse.de --- sound/pci/cs4281.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 90958a422b75..31cb9cbe2f03 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -950,7 +950,7 @@ static int snd_cs4281_pcm(struct cs4281 *chip, int device) pcm->private_data = chip; pcm->info_flags = 0; - strcpy(pcm->name, "CS4281"); + strscpy(pcm->name, "CS4281"); chip->pcm = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &chip->pci->dev, @@ -1715,7 +1715,7 @@ static int snd_cs4281_midi(struct cs4281 *chip, int device) err = snd_rawmidi_new(chip->card, "CS4281", device, 1, 1, &rmidi); if (err < 0) return err; - strcpy(rmidi->name, "CS4281"); + strscpy(rmidi->name, "CS4281"); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_cs4281_midi_output); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_cs4281_midi_input); rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; @@ -1870,8 +1870,8 @@ static int __snd_cs4281_probe(struct pci_dev *pci, if (err < 0) return err; snd_cs4281_create_gameport(chip); - strcpy(card->driver, "CS4281"); - strcpy(card->shortname, "Cirrus Logic CS4281"); + strscpy(card->driver, "CS4281"); + strscpy(card->shortname, "Cirrus Logic CS4281"); sprintf(card->longname, "%s at 0x%lx, irq %d", card->shortname, chip->ba0_addr, From 0eb71ea6d7f3e64137c19e8d4a3bdcffc57c5b05 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:38 +0200 Subject: [PATCH 269/385] ALSA: cs46xx: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-57-tiwai@suse.de --- sound/pci/cs46xx/cs46xx.c | 4 ++-- sound/pci/cs46xx/cs46xx_lib.c | 20 ++++++++++---------- sound/pci/cs46xx/dsp_spos.c | 8 ++++---- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 8634004a606b..9c1995737eb7 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c @@ -107,8 +107,8 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci, snd_cs46xx_gameport(chip); - strcpy(card->driver, "CS46xx"); - strcpy(card->shortname, "Sound Fusion CS46xx"); + strscpy(card->driver, "CS46xx"); + strscpy(card->shortname, "Sound Fusion CS46xx"); sprintf(card->longname, "%s at 0x%lx/0x%lx, irq %i", card->shortname, chip->ba0_addr, diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index fb733633740b..85a7988cf822 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -1760,7 +1760,7 @@ int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device) /* global setup */ pcm->info_flags = 0; - strcpy(pcm->name, "CS46xx"); + strscpy(pcm->name, "CS46xx"); chip->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -1787,7 +1787,7 @@ int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device) /* global setup */ pcm->info_flags = 0; - strcpy(pcm->name, "CS46xx - Rear"); + strscpy(pcm->name, "CS46xx - Rear"); chip->pcm_rear = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -1812,7 +1812,7 @@ int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device) /* global setup */ pcm->info_flags = 0; - strcpy(pcm->name, "CS46xx - Center LFE"); + strscpy(pcm->name, "CS46xx - Center LFE"); chip->pcm_center_lfe = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -1837,7 +1837,7 @@ int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device) /* global setup */ pcm->info_flags = 0; - strcpy(pcm->name, "CS46xx - IEC958"); + strscpy(pcm->name, "CS46xx - IEC958"); chip->pcm_iec958 = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -2672,7 +2672,7 @@ int snd_cs46xx_midi(struct snd_cs46xx *chip, int device) err = snd_rawmidi_new(chip->card, "CS46XX", device, 1, 1, &rmidi); if (err < 0) return err; - strcpy(rmidi->name, "CS46XX"); + strscpy(rmidi->name, "CS46XX"); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_cs46xx_midi_output); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_cs46xx_midi_input); rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; @@ -3853,27 +3853,27 @@ int snd_cs46xx_create(struct snd_card *card, } region = &chip->region.name.ba0; - strcpy(region->name, "CS46xx_BA0"); + strscpy(region->name, "CS46xx_BA0"); region->base = chip->ba0_addr; region->size = CS46XX_BA0_SIZE; region = &chip->region.name.data0; - strcpy(region->name, "CS46xx_BA1_data0"); + strscpy(region->name, "CS46xx_BA1_data0"); region->base = chip->ba1_addr + BA1_SP_DMEM0; region->size = CS46XX_BA1_DATA0_SIZE; region = &chip->region.name.data1; - strcpy(region->name, "CS46xx_BA1_data1"); + strscpy(region->name, "CS46xx_BA1_data1"); region->base = chip->ba1_addr + BA1_SP_DMEM1; region->size = CS46XX_BA1_DATA1_SIZE; region = &chip->region.name.pmem; - strcpy(region->name, "CS46xx_BA1_pmem"); + strscpy(region->name, "CS46xx_BA1_pmem"); region->base = chip->ba1_addr + BA1_SP_PMEM; region->size = CS46XX_BA1_PRG_SIZE; region = &chip->region.name.reg; - strcpy(region->name, "CS46xx_BA1_reg"); + strscpy(region->name, "CS46xx_BA1_reg"); region->base = chip->ba1_addr + BA1_SP_REG; region->size = CS46XX_BA1_REG_SIZE; diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index 1db6bc58d6a6..e07f85322f1c 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c @@ -203,7 +203,7 @@ add_symbol (struct snd_cs46xx * chip, char * symbol_name, u32 address, int type) index = find_free_symbol_index (ins); - strcpy (ins->symbol_table.symbols[index].symbol_name, symbol_name); + strscpy (ins->symbol_table.symbols[index].symbol_name, symbol_name); ins->symbol_table.symbols[index].address = address; ins->symbol_table.symbols[index].symbol_type = type; ins->symbol_table.symbols[index].module = NULL; @@ -923,7 +923,7 @@ static struct dsp_scb_descriptor * _map_scb (struct snd_cs46xx *chip, char * nam index = find_free_scb_index (ins); memset(&ins->scbs[index], 0, sizeof(ins->scbs[index])); - strcpy(ins->scbs[index].scb_name, name); + strscpy(ins->scbs[index].scb_name, name); ins->scbs[index].address = dest; ins->scbs[index].index = index; ins->scbs[index].ref_count = 1; @@ -953,9 +953,9 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size) } if (name) - strcpy(ins->tasks[ins->ntask].task_name, name); + strscpy(ins->tasks[ins->ntask].task_name, name); else - strcpy(ins->tasks[ins->ntask].task_name, "(NULL)"); + strscpy(ins->tasks[ins->ntask].task_name, "(NULL)"); ins->tasks[ins->ntask].address = dest; ins->tasks[ins->ntask].size = size; From 2d5239eab8ee2d474b5c1a70475f6fe87c74ba57 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:39 +0200 Subject: [PATCH 270/385] ALSA: cs5530: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-58-tiwai@suse.de --- sound/pci/cs5530.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c index 532891e67c34..292b65aa758a 100644 --- a/sound/pci/cs5530.c +++ b/sound/pci/cs5530.c @@ -207,8 +207,8 @@ static int snd_cs5530_probe(struct pci_dev *pci, if (err < 0) return err; - strcpy(card->driver, "CS5530"); - strcpy(card->shortname, "CS5530 Audio"); + strscpy(card->driver, "CS5530"); + strscpy(card->shortname, "CS5530 Audio"); sprintf(card->longname, "%s at 0x%lx", card->shortname, chip->pci_base); err = snd_card_register(card); From fe9502be46f7b76b9d95fc5df7b018f48b8a22ce Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:40 +0200 Subject: [PATCH 271/385] ALSA: cs5535audio: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-59-tiwai@suse.de --- sound/pci/cs5535audio/cs5535audio.c | 4 ++-- sound/pci/cs5535audio/cs5535audio_pcm.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 0f319013a2a2..76566e7baea0 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -315,9 +315,9 @@ static int __snd_cs5535audio_probe(struct pci_dev *pci, if (err < 0) return err; - strcpy(card->driver, DRIVER_NAME); + strscpy(card->driver, DRIVER_NAME); - strcpy(card->shortname, "CS5535 Audio"); + strscpy(card->shortname, "CS5535 Audio"); sprintf(card->longname, "%s %s at 0x%lx, irq %i", card->shortname, card->driver, cs5535au->port, cs5535au->irq); diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index 9c88e99e3750..f296b2c63026 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -423,7 +423,7 @@ int snd_cs5535audio_pcm(struct cs5535audio *cs5535au) pcm->private_data = cs5535au; pcm->info_flags = 0; - strcpy(pcm->name, "CS5535 Audio"); + strscpy(pcm->name, "CS5535 Audio"); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &cs5535au->pci->dev, From ea9deed52d7f196454456f775fddf53328e90f2a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:41 +0200 Subject: [PATCH 272/385] ALSA: ctxfi: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-60-tiwai@suse.de --- sound/pci/ctxfi/ctmixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c index 6797fde3d788..496682613db5 100644 --- a/sound/pci/ctxfi/ctmixer.c +++ b/sound/pci/ctxfi/ctmixer.c @@ -1219,7 +1219,7 @@ int ct_alsa_mix_create(struct ct_atc *atc, if (err) return err; - strcpy(atc->card->mixername, device_name); + strscpy(atc->card->mixername, device_name); return 0; } From 7bab02a32c6ae08aeb60aa6f85363cd5847d0911 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:42 +0200 Subject: [PATCH 273/385] ALSA: echoaudio: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-61-tiwai@suse.de --- sound/pci/echoaudio/midi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c index c3f3c9129561..4ee230794b4e 100644 --- a/sound/pci/echoaudio/midi.c +++ b/sound/pci/echoaudio/midi.c @@ -311,7 +311,7 @@ static int snd_echo_midi_create(struct snd_card *card, if (err < 0) return err; - strcpy(chip->rmidi->name, card->shortname); + strscpy(chip->rmidi->name, card->shortname); chip->rmidi->private_data = chip; snd_rawmidi_set_ops(chip->rmidi, SNDRV_RAWMIDI_STREAM_INPUT, From 3ddbb87d99946b6d21ded58f983fb4642ad57845 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:43 +0200 Subject: [PATCH 274/385] ALSA: emu10k1: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-62-tiwai@suse.de --- sound/pci/emu10k1/emumpu401.c | 2 +- sound/pci/emu10k1/emupcm.c | 10 +++++----- sound/pci/emu10k1/p16v.c | 2 +- sound/pci/emu10k1/timer.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c index 747c34b3d566..efff19bbc0e9 100644 --- a/sound/pci/emu10k1/emumpu401.c +++ b/sound/pci/emu10k1/emumpu401.c @@ -320,7 +320,7 @@ static int emu10k1_midi_init(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *m spin_lock_init(&midi->open_lock); spin_lock_init(&midi->input_lock); spin_lock_init(&midi->output_lock); - strcpy(rmidi->name, name); + strscpy(rmidi->name, name); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_emu10k1_midi_output); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_emu10k1_midi_input); rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 1bf6e3d652f8..5414148057ea 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1425,7 +1425,7 @@ int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device) pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; - strcpy(pcm->name, "ADC Capture/Standard PCM Playback"); + strscpy(pcm->name, "ADC Capture/Standard PCM Playback"); emu->pcm = pcm; /* playback substream can't use managed buffers due to alignment */ @@ -1457,7 +1457,7 @@ int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device) pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; - strcpy(pcm->name, "Multichannel Playback"); + strscpy(pcm->name, "Multichannel Playback"); emu->pcm_multi = pcm; for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) @@ -1491,7 +1491,7 @@ int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_mic_ops); pcm->info_flags = 0; - strcpy(pcm->name, "Mic Capture"); + strscpy(pcm->name, "Mic Capture"); emu->pcm_mic = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &emu->pci->dev, @@ -1818,9 +1818,9 @@ int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device) pcm->info_flags = 0; if (emu->audigy) - strcpy(pcm->name, "Multichannel Capture"); + strscpy(pcm->name, "Multichannel Capture"); else - strcpy(pcm->name, "Multichannel Capture/PT Playback"); + strscpy(pcm->name, "Multichannel Capture/PT Playback"); emu->pcm_efx = pcm; if (!emu->card_capabilities->emu_model) { diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index a9a75891f1da..e774174d10de 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -573,7 +573,7 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device) pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; - strcpy(pcm->name, "p16v"); + strscpy(pcm->name, "p16v"); emu->pcm_p16v = pcm; emu->p16v_interrupt = snd_p16v_interrupt; diff --git a/sound/pci/emu10k1/timer.c b/sound/pci/emu10k1/timer.c index bb2478319361..1231ae2bf931 100644 --- a/sound/pci/emu10k1/timer.c +++ b/sound/pci/emu10k1/timer.c @@ -80,7 +80,7 @@ int snd_emu10k1_timer(struct snd_emu10k1 *emu, int device) tid.subdevice = 0; err = snd_timer_new(emu->card, "EMU10K1", &tid, &timer); if (err >= 0) { - strcpy(timer->name, "EMU10K1 timer"); + strscpy(timer->name, "EMU10K1 timer"); timer->private_data = emu; timer->hw = snd_emu10k1_timer_hw; } From d24457cae235e97d00fd6305d76b3858d2390a8b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:44 +0200 Subject: [PATCH 275/385] ALSA: ens1370: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-63-tiwai@suse.de --- sound/pci/ens1370.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 1e6adf1ae304..82e10ecb9196 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -1244,7 +1244,7 @@ static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device) pcm->private_data = ensoniq; pcm->info_flags = 0; - strcpy(pcm->name, CHIP_NAME " DAC2/ADC"); + strscpy(pcm->name, CHIP_NAME " DAC2/ADC"); ensoniq->pcm1 = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -1276,7 +1276,7 @@ static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device) #endif pcm->private_data = ensoniq; pcm->info_flags = 0; - strcpy(pcm->name, CHIP_NAME " DAC1"); + strscpy(pcm->name, CHIP_NAME " DAC1"); ensoniq->pcm2 = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -2250,7 +2250,7 @@ static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device) err = snd_rawmidi_new(ensoniq->card, "ES1370/1", device, 1, 1, &rmidi); if (err < 0) return err; - strcpy(rmidi->name, CHIP_NAME); + strscpy(rmidi->name, CHIP_NAME); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_ensoniq_midi_output); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_ensoniq_midi_input); rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | @@ -2346,9 +2346,9 @@ static int __snd_audiopci_probe(struct pci_dev *pci, snd_ensoniq_create_gameport(ensoniq, dev); - strcpy(card->driver, DRIVER_NAME); + strscpy(card->driver, DRIVER_NAME); - strcpy(card->shortname, "Ensoniq AudioPCI"); + strscpy(card->shortname, "Ensoniq AudioPCI"); sprintf(card->longname, "%s %s at 0x%lx, irq %i", card->shortname, card->driver, From 6df1d279dbfb0498ec984e55d11d91c56728ad77 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:45 +0200 Subject: [PATCH 276/385] ALSA: es1938: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-64-tiwai@suse.de --- sound/pci/es1938.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 27728bdfac57..0ce7076206f9 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -982,7 +982,7 @@ static int snd_es1938_new_pcm(struct es1938 *chip, int device) pcm->private_data = chip; pcm->info_flags = 0; - strcpy(pcm->name, "ESS Solo-1"); + strscpy(pcm->name, "ESS Solo-1"); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &chip->pci->dev, 64*1024, 64*1024); @@ -1658,7 +1658,7 @@ static int snd_es1938_mixer(struct es1938 *chip) card = chip->card; - strcpy(card->mixername, "ESS Solo-1"); + strscpy(card->mixername, "ESS Solo-1"); for (idx = 0; idx < ARRAY_SIZE(snd_es1938_controls); idx++) { struct snd_kcontrol *kctl; @@ -1720,8 +1720,8 @@ static int __snd_es1938_probe(struct pci_dev *pci, if (err < 0) return err; - strcpy(card->driver, "ES1938"); - strcpy(card->shortname, "ESS ES1938 (Solo-1)"); + strscpy(card->driver, "ES1938"); + strscpy(card->shortname, "ESS ES1938 (Solo-1)"); sprintf(card->longname, "%s rev %i, irq %i", card->shortname, chip->revision, From 42b68e73568d3ddb4b571d9277fceeff91aded0b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:46 +0200 Subject: [PATCH 277/385] ALSA: es1968: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-65-tiwai@suse.de --- sound/pci/es1968.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 37bac890613e..624ba7d47566 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -1812,7 +1812,7 @@ snd_es1968_pcm(struct es1968 *chip, int device) pcm->info_flags = 0; - strcpy(pcm->name, "ESS Maestro"); + strscpy(pcm->name, "ESS Maestro"); chip->pcm = pcm; @@ -2761,16 +2761,16 @@ static int __snd_es1968_probe(struct pci_dev *pci, switch (chip->type) { case TYPE_MAESTRO2E: - strcpy(card->driver, "ES1978"); - strcpy(card->shortname, "ESS ES1978 (Maestro 2E)"); + strscpy(card->driver, "ES1978"); + strscpy(card->shortname, "ESS ES1978 (Maestro 2E)"); break; case TYPE_MAESTRO2: - strcpy(card->driver, "ES1968"); - strcpy(card->shortname, "ESS ES1968 (Maestro 2)"); + strscpy(card->driver, "ES1968"); + strscpy(card->shortname, "ESS ES1968 (Maestro 2)"); break; case TYPE_MAESTRO: - strcpy(card->driver, "ESM1"); - strcpy(card->shortname, "ESS Maestro 1"); + strscpy(card->driver, "ESM1"); + strscpy(card->shortname, "ESS Maestro 1"); break; } From 7deb4eac7d65a37c138076565f2717c2a6c63342 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:47 +0200 Subject: [PATCH 278/385] ALSA: fm801: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-66-tiwai@suse.de --- sound/pci/fm801.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index f283256eda0d..cf40bd06b734 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -726,7 +726,7 @@ static int snd_fm801_pcm(struct fm801 *chip, int device) pcm->private_data = chip; pcm->info_flags = 0; - strcpy(pcm->name, "FM801"); + strscpy(pcm->name, "FM801"); chip->pcm = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &pdev->dev, @@ -1291,8 +1291,8 @@ static int __snd_card_fm801_probe(struct pci_dev *pci, if (err < 0) return err; - strcpy(card->driver, "FM801"); - strcpy(card->shortname, "ForteMedia FM801-"); + strscpy(card->driver, "FM801"); + strscpy(card->shortname, "ForteMedia FM801-"); strcat(card->shortname, chip->multichannel ? "AU" : "AS"); sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, chip->port, chip->irq); From b51681287f9c9fb14436d3705e268b1d65c19b2d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:48 +0200 Subject: [PATCH 279/385] ALSA: ice1712: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-67-tiwai@suse.de --- sound/pci/ice1712/ice1712.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index a8ac14887676..1aefd46ebf6b 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -850,7 +850,7 @@ static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device) pcm->private_data = ice; pcm->info_flags = 0; - strcpy(pcm->name, "ICE1712 consumer"); + strscpy(pcm->name, "ICE1712 consumer"); ice->pcm = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -875,7 +875,7 @@ static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device) pcm->private_data = ice; pcm->info_flags = 0; - strcpy(pcm->name, "ICE1712 consumer (DS)"); + strscpy(pcm->name, "ICE1712 consumer (DS)"); ice->pcm_ds = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -1216,7 +1216,7 @@ static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device) pcm->private_data = ice; pcm->info_flags = 0; - strcpy(pcm->name, "ICE1712 multi"); + strscpy(pcm->name, "ICE1712 multi"); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &ice->pci->dev, 256*1024, 256*1024); @@ -2559,8 +2559,8 @@ static int snd_ice1712_probe(struct pci_dev *pci, return err; ice = card->private_data; - strcpy(card->driver, "ICE1712"); - strcpy(card->shortname, "ICEnsemble ICE1712"); + strscpy(card->driver, "ICE1712"); + strscpy(card->shortname, "ICEnsemble ICE1712"); err = snd_ice1712_create(card, pci, model[dev], omni[dev], cs8427_timeout[dev], dxr_enable[dev]); @@ -2570,9 +2570,9 @@ static int snd_ice1712_probe(struct pci_dev *pci, for (tbl = card_tables; *tbl; tbl++) { for (c = *tbl; c->subvendor; c++) { if (c->subvendor == ice->eeprom.subvendor) { - strcpy(card->shortname, c->name); + strscpy(card->shortname, c->name); if (c->driver) /* specific driver? */ - strcpy(card->driver, c->driver); + strscpy(card->driver, c->driver); if (c->chip_init) { err = c->chip_init(ice); if (err < 0) From f79d7aef3e4e260bef96be3638f9b37f9c70fdf1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:49 +0200 Subject: [PATCH 280/385] ALSA: ice1724: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-68-tiwai@suse.de --- sound/pci/ice1712/ice1724.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index be22b159e65a..0445d2e8e548 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -1118,7 +1118,7 @@ static int snd_vt1724_pcm_profi(struct snd_ice1712 *ice, int device) pcm->private_data = ice; pcm->info_flags = 0; - strcpy(pcm->name, "ICE1724"); + strscpy(pcm->name, "ICE1724"); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &ice->pci->dev, 256*1024, 256*1024); @@ -1313,7 +1313,7 @@ static int snd_vt1724_pcm_spdif(struct snd_ice1712 *ice, int device) pcm->private_data = ice; pcm->info_flags = 0; - strcpy(pcm->name, name); + strscpy(pcm->name, name); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &ice->pci->dev, 256*1024, 256*1024); @@ -1425,7 +1425,7 @@ static int snd_vt1724_pcm_indep(struct snd_ice1712 *ice, int device) pcm->private_data = ice; pcm->info_flags = 0; - strcpy(pcm->name, "ICE1724 Surround PCM"); + strscpy(pcm->name, "ICE1724 Surround PCM"); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &ice->pci->dev, 256*1024, 256*1024); @@ -1820,7 +1820,7 @@ static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol, uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; if (uinfo->value.enumerated.item >= hw_rates_count) /* ext_clock items */ - strcpy(uinfo->value.enumerated.name, + strscpy(uinfo->value.enumerated.name, ice->ext_clock_names[ uinfo->value.enumerated.item - hw_rates_count]); else @@ -2545,8 +2545,8 @@ static int __snd_vt1724_probe(struct pci_dev *pci, return err; ice = card->private_data; - strcpy(card->driver, "ICE1724"); - strcpy(card->shortname, "ICEnsemble ICE1724"); + strscpy(card->driver, "ICE1724"); + strscpy(card->shortname, "ICEnsemble ICE1724"); err = snd_vt1724_create(card, pci, model[dev]); if (err < 0) @@ -2557,9 +2557,9 @@ static int __snd_vt1724_probe(struct pci_dev *pci, c = ice->card_info; if (c) { - strcpy(card->shortname, c->name); + strscpy(card->shortname, c->name); if (c->driver) /* specific driver? */ - strcpy(card->driver, c->driver); + strscpy(card->driver, c->driver); if (c->chip_init) { err = c->chip_init(ice); if (err < 0) @@ -2637,7 +2637,7 @@ static int __snd_vt1724_probe(struct pci_dev *pci, return err; ice->rmidi[0] = rmidi; rmidi->private_data = ice; - strcpy(rmidi->name, "ICE1724 MIDI"); + strscpy(rmidi->name, "ICE1724 MIDI"); rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; From 9a86ffe73b22260bd25274a6fb0579f77f20342a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:50 +0200 Subject: [PATCH 281/385] ALSA: intel8x0: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-69-tiwai@suse.de --- sound/pci/intel8x0.c | 14 +++++++------- sound/pci/intel8x0m.c | 10 +++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index b521cec20333..9e6a5065ffbf 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1436,7 +1436,7 @@ static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device, if (rec->suffix) sprintf(name, "Intel ICH - %s", rec->suffix); else - strcpy(name, "Intel ICH"); + strscpy(name, "Intel ICH"); err = snd_pcm_new(chip->card, name, device, rec->playback_ops ? 1 : 0, rec->capture_ops ? 1 : 0, &pcm); @@ -1453,7 +1453,7 @@ static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device, if (rec->suffix) sprintf(pcm->name, "%s - %s", chip->card->shortname, rec->suffix); else - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); chip->pcm[device] = pcm; snd_pcm_set_managed_buffer_all(pcm, intel8x0_dma_type(chip), @@ -3118,21 +3118,21 @@ static int __snd_intel8x0_probe(struct pci_dev *pci, if (spdif_aclink < 0) spdif_aclink = check_default_spdif_aclink(pci); - strcpy(card->driver, "ICH"); + strscpy(card->driver, "ICH"); if (!spdif_aclink) { switch (pci_id->driver_data) { case DEVICE_NFORCE: - strcpy(card->driver, "NFORCE"); + strscpy(card->driver, "NFORCE"); break; case DEVICE_INTEL_ICH4: - strcpy(card->driver, "ICH4"); + strscpy(card->driver, "ICH4"); } } - strcpy(card->shortname, "Intel ICH"); + strscpy(card->shortname, "Intel ICH"); for (name = shortnames; name->id; name++) { if (pci->device == name->id) { - strcpy(card->shortname, name->s); + strscpy(card->shortname, name->s); break; } } diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 1ce775fe8a70..9e5988583abe 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -678,7 +678,7 @@ static int snd_intel8x0m_pcm1(struct intel8x0m *chip, int device, if (rec->suffix) sprintf(name, "Intel ICH - %s", rec->suffix); else - strcpy(name, "Intel ICH"); + strscpy(name, "Intel ICH"); err = snd_pcm_new(chip->card, name, device, rec->playback_ops ? 1 : 0, rec->capture_ops ? 1 : 0, &pcm); @@ -696,7 +696,7 @@ static int snd_intel8x0m_pcm1(struct intel8x0m *chip, int device, if (rec->suffix) sprintf(pcm->name, "%s - %s", chip->card->shortname, rec->suffix); else - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); chip->pcm[device] = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -1184,11 +1184,11 @@ static int __snd_intel8x0m_probe(struct pci_dev *pci, return err; chip = card->private_data; - strcpy(card->driver, "ICH-MODEM"); - strcpy(card->shortname, "Intel ICH"); + strscpy(card->driver, "ICH-MODEM"); + strscpy(card->shortname, "Intel ICH"); for (name = shortnames; name->id; name++) { if (pci->device == name->id) { - strcpy(card->shortname, name->s); + strscpy(card->shortname, name->s); break; } } From 22b331f5a2a0e6534214b38c58d806d2aa43ae82 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:51 +0200 Subject: [PATCH 282/385] ALSA: korg1212: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-70-tiwai@suse.de --- sound/pci/korg1212/korg1212.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 56dea5b10828..0a66d5cfc090 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -2249,7 +2249,7 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci) korg1212->pcm->private_data = korg1212; korg1212->pcm->private_free = snd_korg1212_free_pcm; - strcpy(korg1212->pcm->name, "korg1212"); + strscpy(korg1212->pcm->name, "korg1212"); snd_pcm_set_ops(korg1212->pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_korg1212_playback_ops); @@ -2298,8 +2298,8 @@ snd_korg1212_probe(struct pci_dev *pci, if (err < 0) goto error; - strcpy(card->driver, "korg1212"); - strcpy(card->shortname, "korg1212"); + strscpy(card->driver, "korg1212"); + strscpy(card->shortname, "korg1212"); sprintf(card->longname, "%s at 0x%lx, irq %d", card->shortname, korg1212->iomem, korg1212->irq); From cc519d221f9c8f1ff574b7fec0d875fb76a436b8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:52 +0200 Subject: [PATCH 283/385] ALSA: lola: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-71-tiwai@suse.de --- sound/pci/lola/lola.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c index fb8bd54e4c2d..8d927ecba165 100644 --- a/sound/pci/lola/lola.c +++ b/sound/pci/lola/lola.c @@ -630,12 +630,12 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci, int dev) if (err < 0) return err; - strcpy(card->driver, "Lola"); + strscpy(card->driver, "Lola"); strscpy(card->shortname, "Digigram Lola", sizeof(card->shortname)); snprintf(card->longname, sizeof(card->longname), "%s at 0x%lx irq %i", card->shortname, chip->bar[0].addr, chip->irq); - strcpy(card->mixername, card->shortname); + strscpy(card->mixername, card->shortname); lola_irq_enable(chip); From ec4894f82775c9abe14afef9a29b913ee549ec06 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:53 +0200 Subject: [PATCH 284/385] ALSA: lx6464es: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-72-tiwai@suse.de --- sound/pci/lx6464es/lx6464es.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index 63ebf9803ea8..9f12c936bb1f 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c @@ -814,7 +814,7 @@ static int lx_pcm_create(struct lx6464es *chip) pcm->info_flags = 0; pcm->nonatomic = true; - strcpy(pcm->name, card_name); + strscpy(pcm->name, card_name); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &chip->pci->dev, size, size); @@ -1022,7 +1022,7 @@ static int snd_lx6464es_probe(struct pci_dev *pci, goto error; } - strcpy(card->driver, "LX6464ES"); + strscpy(card->driver, "LX6464ES"); sprintf(card->id, "LX6464ES_%02X%02X%02X", chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]); From c1b4f94c7645c58111cf53eb5165ab5fc65ec67d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:54 +0200 Subject: [PATCH 285/385] ALSA: maestro3: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-73-tiwai@suse.de --- sound/pci/maestro3.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index e61e15774706..e092097599ff 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -1846,7 +1846,7 @@ snd_m3_pcm(struct snd_m3 * chip, int device) pcm->private_data = chip; pcm->info_flags = 0; - strcpy(pcm->name, chip->card->driver); + strscpy(pcm->name, chip->card->driver); chip->pcm = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -2648,14 +2648,14 @@ __snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) switch (pci->device) { case PCI_DEVICE_ID_ESS_ALLEGRO: case PCI_DEVICE_ID_ESS_ALLEGRO_1: - strcpy(card->driver, "Allegro"); + strscpy(card->driver, "Allegro"); break; case PCI_DEVICE_ID_ESS_CANYON3D_2LE: case PCI_DEVICE_ID_ESS_CANYON3D_2: - strcpy(card->driver, "Canyon3D-2"); + strscpy(card->driver, "Canyon3D-2"); break; default: - strcpy(card->driver, "Maestro3"); + strscpy(card->driver, "Maestro3"); break; } From ed04b49e21f05b0f84bbaa86a59abd3ef64de946 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:55 +0200 Subject: [PATCH 286/385] ALSA: mixart: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-74-tiwai@suse.de --- sound/pci/mixart/mixart.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 7ceaf6a7a77e..cdc0ba5dd1ad 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -970,7 +970,7 @@ static int snd_mixart_pcm_analog(struct snd_mixart *chip) pcm->info_flags = 0; pcm->nonatomic = true; - strcpy(pcm->name, name); + strscpy(pcm->name, name); preallocate_buffers(chip, pcm); @@ -1004,7 +1004,7 @@ static int snd_mixart_pcm_digital(struct snd_mixart *chip) pcm->info_flags = 0; pcm->nonatomic = true; - strcpy(pcm->name, name); + strscpy(pcm->name, name); preallocate_buffers(chip, pcm); @@ -1330,7 +1330,7 @@ static int snd_mixart_probe(struct pci_dev *pci, return err; } - strcpy(card->driver, CARD_NAME); + strscpy(card->driver, CARD_NAME); snprintf(card->shortname, sizeof(card->shortname), "Digigram miXart [PCM #%d]", i); snprintf(card->longname, sizeof(card->longname), From 6ffb7be30ba0c064e3b42c3d643a1419b9ccc981 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:56 +0200 Subject: [PATCH 287/385] ALSA: nm256: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-75-tiwai@suse.de --- sound/pci/nm256/nm256.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index cd4dc43dbff1..39464d171f6b 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -1595,13 +1595,13 @@ static int snd_nm256_probe(struct pci_dev *pci, switch (pci->device) { case PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO: - strcpy(card->driver, "NM256AV"); + strscpy(card->driver, "NM256AV"); break; case PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO: - strcpy(card->driver, "NM256ZX"); + strscpy(card->driver, "NM256ZX"); break; case PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO: - strcpy(card->driver, "NM256XL+"); + strscpy(card->driver, "NM256XL+"); break; default: dev_err(&pci->dev, "invalid device id 0x%x\n", pci->device); From 1c8e3ebdfe3342b885cdf519d0bbc9e5a494c60a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:57 +0200 Subject: [PATCH 288/385] ALSA: oxygen: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-76-tiwai@suse.de --- sound/pci/oxygen/oxygen_lib.c | 6 +++--- sound/pci/oxygen/oxygen_pcm.c | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 39b8ccf37cdd..9c7270e4c35e 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -655,11 +655,11 @@ static int __oxygen_pci_probe(struct pci_dev *pci, int index, char *id, chip->irq = pci->irq; card->sync_irq = chip->irq; - strcpy(card->driver, chip->model.chip); - strcpy(card->shortname, chip->model.shortname); + strscpy(card->driver, chip->model.chip); + strscpy(card->shortname, chip->model.shortname); sprintf(card->longname, "%s at %#lx, irq %i", chip->model.longname, chip->addr, chip->irq); - strcpy(card->mixername, chip->model.chip); + strscpy(card->mixername, chip->model.chip); snd_component_add(card, chip->model.chip); err = oxygen_pcm_init(chip); diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index b2a3fcfe31d4..643141f345bb 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c @@ -697,7 +697,7 @@ int oxygen_pcm_init(struct oxygen *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &oxygen_rec_b_ops); pcm->private_data = chip; - strcpy(pcm->name, "Multichannel"); + strscpy(pcm->name, "Multichannel"); if (outs) snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, SNDRV_DMA_TYPE_DEV, @@ -725,7 +725,7 @@ int oxygen_pcm_init(struct oxygen *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &oxygen_rec_c_ops); pcm->private_data = chip; - strcpy(pcm->name, "Digital"); + strscpy(pcm->name, "Digital"); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &chip->pci->dev, DEFAULT_BUFFER_BYTES, @@ -755,7 +755,7 @@ int oxygen_pcm_init(struct oxygen *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &oxygen_rec_b_ops); pcm->private_data = chip; - strcpy(pcm->name, outs ? "Front Panel" : "Analog 2"); + strscpy(pcm->name, outs ? "Front Panel" : "Analog 2"); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &chip->pci->dev, DEFAULT_BUFFER_BYTES, @@ -773,7 +773,7 @@ int oxygen_pcm_init(struct oxygen *chip) OXYGEN_REC_C_ROUTE_I2S_ADC_3, OXYGEN_REC_C_ROUTE_MASK); pcm->private_data = chip; - strcpy(pcm->name, "Analog 3"); + strscpy(pcm->name, "Analog 3"); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &chip->pci->dev, DEFAULT_BUFFER_BYTES, From c810473253842bf8df21bd0dee5195ef62d95a3c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:58 +0200 Subject: [PATCH 289/385] ALSA: pcxhr: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-77-tiwai@suse.de --- sound/pci/pcxhr/pcxhr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 242bd7e04b3e..bfd84c50e981 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -1149,7 +1149,7 @@ int pcxhr_create_pcm(struct snd_pcxhr *chip) pcm->info_flags = 0; pcm->nonatomic = true; - strcpy(pcm->name, name); + strscpy(pcm->name, name); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &chip->mgr->pci->dev, @@ -1605,7 +1605,7 @@ static int pcxhr_probe(struct pci_dev *pci, return err; } - strcpy(card->driver, DRIVER_NAME); + strscpy(card->driver, DRIVER_NAME); snprintf(card->shortname, sizeof(card->shortname), "Digigram [PCM #%d]", i); snprintf(card->longname, sizeof(card->longname), From 9885bd7c4ce531c784cc1ce6b3f07ba84480ff5b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:06:59 +0200 Subject: [PATCH 290/385] ALSA: riptide: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-78-tiwai@suse.de --- sound/pci/riptide/riptide.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 578be0755b8a..e983cd657e28 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1688,7 +1688,7 @@ static int snd_riptide_pcm(struct snd_riptide *chip, int device) &snd_riptide_capture_ops); pcm->private_data = chip; pcm->info_flags = 0; - strcpy(pcm->name, "RIPTIDE"); + strscpy(pcm->name, "RIPTIDE"); chip->pcm = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_SG, &chip->pci->dev, 64 * 1024, 128 * 1024); @@ -2098,8 +2098,8 @@ __snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id } #endif - strcpy(card->driver, "RIPTIDE"); - strcpy(card->shortname, "Riptide"); + strscpy(card->driver, "RIPTIDE"); + strscpy(card->shortname, "Riptide"); #ifdef SUPPORT_JOYSTICK scnprintf(card->longname, sizeof(card->longname), "%s at 0x%lx, irq %i mpu 0x%x opl3 0x%x gameport 0x%x", From ca485569ca35c4a5dd4e744ef4d4f9ef9c5a3e1b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:00 +0200 Subject: [PATCH 291/385] ALSA: rme32: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-79-tiwai@suse.de --- sound/pci/rme32.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 4bf122abea48..f07b6023473a 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -1314,7 +1314,7 @@ static int snd_rme32_create(struct rme32 *rme32) return err; rme32->spdif_pcm->private_data = rme32; rme32->spdif_pcm->private_free = snd_rme32_free_spdif_pcm; - strcpy(rme32->spdif_pcm->name, "Digi32 IEC958"); + strscpy(rme32->spdif_pcm->name, "Digi32 IEC958"); if (rme32->fullduplex_mode) { snd_pcm_set_ops(rme32->spdif_pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_rme32_playback_spdif_fd_ops); @@ -1344,7 +1344,7 @@ static int snd_rme32_create(struct rme32 *rme32) return err; rme32->adat_pcm->private_data = rme32; rme32->adat_pcm->private_free = snd_rme32_free_adat_pcm; - strcpy(rme32->adat_pcm->name, "Digi32 ADAT"); + strscpy(rme32->adat_pcm->name, "Digi32 ADAT"); if (rme32->fullduplex_mode) { snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_rme32_playback_adat_fd_ops); @@ -1879,16 +1879,16 @@ __snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) if (err < 0) return err; - strcpy(card->driver, "Digi32"); + strscpy(card->driver, "Digi32"); switch (rme32->pci->device) { case PCI_DEVICE_ID_RME_DIGI32: - strcpy(card->shortname, "RME Digi32"); + strscpy(card->shortname, "RME Digi32"); break; case PCI_DEVICE_ID_RME_DIGI32_8: - strcpy(card->shortname, "RME Digi32/8"); + strscpy(card->shortname, "RME Digi32/8"); break; case PCI_DEVICE_ID_RME_DIGI32_PRO: - strcpy(card->shortname, "RME Digi32 PRO"); + strscpy(card->shortname, "RME Digi32 PRO"); break; } sprintf(card->longname, "%s (Rev. %d) at 0x%lx, irq %d", From 50301b7a02c341b09d3191c9ea02b3d04bdd2bb8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:01 +0200 Subject: [PATCH 292/385] ALSA: rme96: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-80-tiwai@suse.de --- sound/pci/rme96.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 01029843d7f3..5cdbbe9cf994 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -1607,7 +1607,7 @@ snd_rme96_create(struct rme96 *rme96) rme96->spdif_pcm->private_data = rme96; rme96->spdif_pcm->private_free = snd_rme96_free_spdif_pcm; - strcpy(rme96->spdif_pcm->name, "Digi96 IEC958"); + strscpy(rme96->spdif_pcm->name, "Digi96 IEC958"); snd_pcm_set_ops(rme96->spdif_pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_rme96_playback_spdif_ops); snd_pcm_set_ops(rme96->spdif_pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_rme96_capture_spdif_ops); @@ -1624,7 +1624,7 @@ snd_rme96_create(struct rme96 *rme96) return err; rme96->adat_pcm->private_data = rme96; rme96->adat_pcm->private_free = snd_rme96_free_adat_pcm; - strcpy(rme96->adat_pcm->name, "Digi96 ADAT"); + strscpy(rme96->adat_pcm->name, "Digi96 ADAT"); snd_pcm_set_ops(rme96->adat_pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_rme96_playback_adat_ops); snd_pcm_set_ops(rme96->adat_pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_rme96_capture_adat_ops); @@ -2434,23 +2434,23 @@ __snd_rme96_probe(struct pci_dev *pci, return -ENOMEM; } - strcpy(card->driver, "Digi96"); + strscpy(card->driver, "Digi96"); switch (rme96->pci->device) { case PCI_DEVICE_ID_RME_DIGI96: - strcpy(card->shortname, "RME Digi96"); + strscpy(card->shortname, "RME Digi96"); break; case PCI_DEVICE_ID_RME_DIGI96_8: - strcpy(card->shortname, "RME Digi96/8"); + strscpy(card->shortname, "RME Digi96/8"); break; case PCI_DEVICE_ID_RME_DIGI96_8_PRO: - strcpy(card->shortname, "RME Digi96/8 PRO"); + strscpy(card->shortname, "RME Digi96/8 PRO"); break; case PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST: pci_read_config_byte(rme96->pci, 8, &val); if (val < 5) { - strcpy(card->shortname, "RME Digi96/8 PAD"); + strscpy(card->shortname, "RME Digi96/8 PAD"); } else { - strcpy(card->shortname, "RME Digi96/8 PST"); + strscpy(card->shortname, "RME Digi96/8 PST"); } break; } From 43b90c3fe5528abb638ebc4a84924c08d636f82f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:02 +0200 Subject: [PATCH 293/385] ALSA: hdsp: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-81-tiwai@suse.de --- sound/pci/rme9652/hdsp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 8df0f5bba0f6..7ce73746168a 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -4944,7 +4944,7 @@ static int snd_hdsp_create_hwdep(struct snd_card *card, struct hdsp *hdsp) hdsp->hwdep = hw; hw->private_data = hdsp; - strcpy(hw->name, "HDSP hwdep interface"); + strscpy(hw->name, "HDSP hwdep interface"); hw->ops.ioctl = snd_hdsp_hwdep_ioctl; hw->ops.ioctl_compat = snd_hdsp_hwdep_ioctl; @@ -4963,7 +4963,7 @@ static int snd_hdsp_create_pcm(struct snd_card *card, struct hdsp *hdsp) hdsp->pcm = pcm; pcm->private_data = hdsp; - strcpy(pcm->name, hdsp->card_name); + strscpy(pcm->name, hdsp->card_name); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_hdsp_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_hdsp_capture_ops); @@ -5111,7 +5111,7 @@ static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp } if (!(hdsp->state & HDSP_InitializationComplete)) { - strcpy(card->shortname, "Hammerfall DSP"); + strscpy(card->shortname, "Hammerfall DSP"); sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name, hdsp->port, hdsp->irq); @@ -5255,8 +5255,8 @@ static int snd_hdsp_create(struct snd_card *card, */ pci_write_config_byte(hdsp->pci, PCI_LATENCY_TIMER, 0xFF); - strcpy(card->driver, "H-DSP"); - strcpy(card->mixername, "Xilinx FPGA"); + strscpy(card->driver, "H-DSP"); + strscpy(card->mixername, "Xilinx FPGA"); if (hdsp->firmware_rev < 0xa) return -ENODEV; @@ -5412,7 +5412,7 @@ static int snd_hdsp_probe(struct pci_dev *pci, if (err) goto error; - strcpy(card->shortname, "Hammerfall DSP"); + strscpy(card->shortname, "Hammerfall DSP"); sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name, hdsp->port, hdsp->irq); err = snd_card_register(card); From 4a9b01c7e58602a084edcb36bfce0b80f2775691 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:03 +0200 Subject: [PATCH 294/385] ALSA: hdspm: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-82-tiwai@suse.de --- sound/pci/rme9652/hdspm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 2041cf00cca0..a0976824beda 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -6355,7 +6355,7 @@ static int snd_hdspm_create_hwdep(struct snd_card *card, hdspm->hwdep = hw; hw->private_data = hdspm; - strcpy(hw->name, "HDSPM hwdep interface"); + strscpy(hw->name, "HDSPM hwdep interface"); hw->ops.open = snd_hdspm_hwdep_dummy_op; hw->ops.ioctl = snd_hdspm_hwdep_ioctl; @@ -6412,7 +6412,7 @@ static int snd_hdspm_create_pcm(struct snd_card *card, hdspm->pcm = pcm; pcm->private_data = hdspm; - strcpy(pcm->name, hdspm->card_name); + strscpy(pcm->name, hdspm->card_name); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_hdspm_ops); @@ -6512,8 +6512,8 @@ static int snd_hdspm_create(struct snd_card *card, pci_read_config_word(hdspm->pci, PCI_CLASS_REVISION, &hdspm->firmware_rev); - strcpy(card->mixername, "Xilinx FPGA"); - strcpy(card->driver, "HDSPM"); + strscpy(card->mixername, "Xilinx FPGA"); + strscpy(card->driver, "HDSPM"); switch (hdspm->firmware_rev) { case HDSPM_RAYDAT_REV: From a8b1aba400a9348d474ffc5ba9a34fbd10f2107f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:04 +0200 Subject: [PATCH 295/385] ALSA: rme9652: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-83-tiwai@suse.de --- sound/pci/rme9652/rme9652.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 34d9c7995ddd..7dc8e3777c37 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -2364,7 +2364,7 @@ static int snd_rme9652_create_pcm(struct snd_card *card, rme9652->pcm = pcm; pcm->private_data = rme9652; - strcpy(pcm->name, rme9652->card_name); + strscpy(pcm->name, rme9652->card_name); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_rme9652_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_rme9652_capture_ops); @@ -2447,7 +2447,7 @@ static int snd_rme9652_create(struct snd_card *card, switch (rev) { case 8: /* original eprom */ - strcpy(card->driver, "RME9636"); + strscpy(card->driver, "RME9636"); if (rme9652->hw_rev == 15) { rme9652->card_name = "RME Digi9636 (Rev 1.5)"; } else { @@ -2456,17 +2456,17 @@ static int snd_rme9652_create(struct snd_card *card, rme9652->ss_channels = RME9636_NCHANNELS; break; case 9: /* W36_G EPROM */ - strcpy(card->driver, "RME9636"); + strscpy(card->driver, "RME9636"); rme9652->card_name = "RME Digi9636 (Rev G)"; rme9652->ss_channels = RME9636_NCHANNELS; break; case 4: /* W52_G EPROM */ - strcpy(card->driver, "RME9652"); + strscpy(card->driver, "RME9652"); rme9652->card_name = "RME Digi9652 (Rev G)"; rme9652->ss_channels = RME9652_NCHANNELS; break; case 3: /* original eprom */ - strcpy(card->driver, "RME9652"); + strscpy(card->driver, "RME9652"); if (rme9652->hw_rev == 15) { rme9652->card_name = "RME Digi9652 (Rev 1.5)"; } else { @@ -2539,7 +2539,7 @@ static int snd_rme9652_probe(struct pci_dev *pci, if (err) goto error; - strcpy(card->shortname, rme9652->card_name); + strscpy(card->shortname, rme9652->card_name); sprintf(card->longname, "%s at 0x%lx, irq %d", card->shortname, rme9652->port, rme9652->irq); From b097bdf5e92d4bcb5eb9bb76165558d0c11f5cb9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:05 +0200 Subject: [PATCH 296/385] ALSA: sis7019: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-84-tiwai@suse.de --- sound/pci/sis7019.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 42b22f123fa7..3d7abcb31679 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -868,7 +868,7 @@ static int sis_pcm_create(struct sis7019 *sis) return rc; pcm->private_data = sis; - strcpy(pcm->name, "SiS7019"); + strscpy(pcm->name, "SiS7019"); sis->pcm = pcm; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &sis_playback_ops); @@ -1348,8 +1348,8 @@ static int __snd_sis7019_probe(struct pci_dev *pci, if (rc < 0) return rc; - strcpy(card->driver, "SiS7019"); - strcpy(card->shortname, "SiS7019"); + strscpy(card->driver, "SiS7019"); + strscpy(card->shortname, "SiS7019"); rc = sis_chip_create(card, pci); if (rc) return rc; From 7ffad83d527e7ab3ac33df47e93dd94eccffc15f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:06 +0200 Subject: [PATCH 297/385] ALSA: sonicvibes: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-85-tiwai@suse.de --- sound/pci/sonicvibes.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 808a793ff4da..f85a9556dacb 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -863,7 +863,7 @@ static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device) pcm->private_data = sonic; pcm->info_flags = 0; - strcpy(pcm->name, "S3 SonicVibes"); + strscpy(pcm->name, "S3 SonicVibes"); sonic->pcm = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -1091,7 +1091,7 @@ static int snd_sonicvibes_mixer(struct sonicvibes *sonic) if (snd_BUG_ON(!sonic || !sonic->card)) return -EINVAL; card = sonic->card; - strcpy(card->mixername, "S3 SonicVibes"); + strscpy(card->mixername, "S3 SonicVibes"); for (idx = 0; idx < ARRAY_SIZE(snd_sonicvibes_controls); idx++) { kctl = snd_ctl_new1(&snd_sonicvibes_controls[idx], sonic); @@ -1415,8 +1415,8 @@ static int __snd_sonic_probe(struct pci_dev *pci, if (err < 0) return err; - strcpy(card->driver, "SonicVibes"); - strcpy(card->shortname, "S3 SonicVibes"); + strscpy(card->driver, "SonicVibes"); + strscpy(card->shortname, "S3 SonicVibes"); sprintf(card->longname, "%s rev %i at 0x%llx, irq %i", card->shortname, sonic->revision, From b28309eac3b755d9021544960e6f6ea0507678fd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:07 +0200 Subject: [PATCH 298/385] ALSA: trident: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-86-tiwai@suse.de --- sound/pci/trident/trident.c | 6 +++--- sound/pci/trident/trident_main.c | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index 9922ab40798c..ddb6ccc72e44 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -88,11 +88,11 @@ static int snd_trident_probe(struct pci_dev *pci, default: str = "Unknown"; } - strcpy(card->driver, str); + strscpy(card->driver, str); if (trident->device == TRIDENT_DEVICE_ID_SI7018) { - strcpy(card->shortname, "SiS "); + strscpy(card->shortname, "SiS "); } else { - strcpy(card->shortname, "Trident "); + strscpy(card->shortname, "Trident "); } strcat(card->shortname, str); sprintf(card->longname, "%s PCI Audio at 0x%lx, irq %d", diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 4e16b79d6584..39ed52bf8631 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -2137,7 +2137,7 @@ int snd_trident_pcm(struct snd_trident *trident, int device) pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; - strcpy(pcm->name, "Trident 4DWave"); + strscpy(pcm->name, "Trident 4DWave"); trident->pcm = pcm; if (trident->tlb.entries) { @@ -2189,16 +2189,16 @@ int snd_trident_foldback_pcm(struct snd_trident *trident, int device) else snd_pcm_set_ops(foldback, SNDRV_PCM_STREAM_CAPTURE, &snd_trident_foldback_ops); foldback->info_flags = 0; - strcpy(foldback->name, "Trident 4DWave"); + strscpy(foldback->name, "Trident 4DWave"); substream = foldback->streams[SNDRV_PCM_STREAM_CAPTURE].substream; - strcpy(substream->name, "Front Mixer"); + strscpy(substream->name, "Front Mixer"); substream = substream->next; - strcpy(substream->name, "Reverb Mixer"); + strscpy(substream->name, "Reverb Mixer"); substream = substream->next; - strcpy(substream->name, "Chorus Mixer"); + strscpy(substream->name, "Chorus Mixer"); if (num_chan == 4) { substream = substream->next; - strcpy(substream->name, "Second AC'97 ADC"); + strscpy(substream->name, "Second AC'97 ADC"); } trident->foldback = foldback; @@ -2241,7 +2241,7 @@ int snd_trident_spdif_pcm(struct snd_trident *trident, int device) snd_pcm_set_ops(spdif, SNDRV_PCM_STREAM_PLAYBACK, &snd_trident_spdif_7018_ops); } spdif->info_flags = 0; - strcpy(spdif->name, "Trident 4DWave IEC958"); + strscpy(spdif->name, "Trident 4DWave IEC958"); trident->spdif = spdif; snd_pcm_set_managed_buffer_all(spdif, SNDRV_DMA_TYPE_DEV, From fd86b9bbf5663b8f4752bbf780be55fd8437bf00 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:08 +0200 Subject: [PATCH 299/385] ALSA: via82xx: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-87-tiwai@suse.de --- sound/pci/via82xx.c | 20 ++++++++++---------- sound/pci/via82xx_modem.c | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index a04dbc0a420f..0753c0c73f51 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -1436,7 +1436,7 @@ static int snd_via8233_pcm_new(struct via82xx *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via8233_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via8233_capture_ops); pcm->private_data = chip; - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); chip->pcms[0] = pcm; /* set up playbacks */ for (i = 0; i < 4; i++) @@ -1461,7 +1461,7 @@ static int snd_via8233_pcm_new(struct via82xx *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via8233_multi_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via8233_capture_ops); pcm->private_data = chip; - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); chip->pcms[1] = pcm; /* set up playback */ init_viadev(chip, chip->multi_devno, VIA_REG_MULTPLAY_STATUS, 4, 0); @@ -1504,7 +1504,7 @@ static int snd_via8233a_pcm_new(struct via82xx *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via8233_multi_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via8233_capture_ops); pcm->private_data = chip; - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); chip->pcms[0] = pcm; /* set up playback */ init_viadev(chip, chip->multi_devno, VIA_REG_MULTPLAY_STATUS, 4, 0); @@ -1532,7 +1532,7 @@ static int snd_via8233a_pcm_new(struct via82xx *chip) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via8233_playback_ops); pcm->private_data = chip; - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); chip->pcms[1] = pcm; /* set up playback */ init_viadev(chip, chip->playback_devno, 0x30, 3, 0); @@ -1562,7 +1562,7 @@ static int snd_via686_pcm_new(struct via82xx *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via686_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via686_capture_ops); pcm->private_data = chip; - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); chip->pcms[0] = pcm; init_viadev(chip, 0, VIA_REG_PLAYBACK_STATUS, 0, 0); init_viadev(chip, 1, VIA_REG_CAPTURE_STATUS, 0, 1); @@ -2461,7 +2461,7 @@ static int __snd_via82xx_probe(struct pci_dev *pci, card_type = pci_id->driver_data; switch (card_type) { case TYPE_CARD_VIA686: - strcpy(card->driver, "VIA686A"); + strscpy(card->driver, "VIA686A"); sprintf(card->shortname, "VIA 82C686A/B rev%x", pci->revision); chip_type = TYPE_VIA686; break; @@ -2471,7 +2471,7 @@ static int __snd_via82xx_probe(struct pci_dev *pci, for (i = 0; i < ARRAY_SIZE(via823x_cards); i++) { if (pci->revision == via823x_cards[i].revision) { chip_type = via823x_cards[i].type; - strcpy(card->shortname, via823x_cards[i].name); + strscpy(card->shortname, via823x_cards[i].name); break; } } @@ -2487,11 +2487,11 @@ static int __snd_via82xx_probe(struct pci_dev *pci, chip_type = TYPE_VIA8233; } if (chip_type == TYPE_VIA8233A) - strcpy(card->driver, "VIA8233A"); + strscpy(card->driver, "VIA8233A"); else if (pci->revision >= VIA_REV_8237) - strcpy(card->driver, "VIA8237"); /* no slog assignment */ + strscpy(card->driver, "VIA8237"); /* no slog assignment */ else - strcpy(card->driver, "VIA8233"); + strscpy(card->driver, "VIA8233"); break; default: dev_err(card->dev, "invalid card type %d\n", card_type); diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index eef0f9ddaae0..12a8c620724d 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -842,7 +842,7 @@ static int snd_via686_pcm_new(struct via82xx_modem *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via686_capture_ops); pcm->dev_class = SNDRV_PCM_CLASS_MODEM; pcm->private_data = chip; - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); chip->pcms[0] = pcm; init_viadev(chip, 0, VIA_REG_MO_STATUS, 0); init_viadev(chip, 1, VIA_REG_MI_STATUS, 1); @@ -1116,7 +1116,7 @@ static int __snd_via82xx_probe(struct pci_dev *pci, card_type = pci_id->driver_data; switch (card_type) { case TYPE_CARD_VIA82XX_MODEM: - strcpy(card->driver, "VIA82XX-MODEM"); + strscpy(card->driver, "VIA82XX-MODEM"); sprintf(card->shortname, "VIA 82XX modem"); break; default: From 362c6bbe367c769ef4526c4a2d3cebfcbc58d0ee Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:09 +0200 Subject: [PATCH 300/385] ALSA: ymfpci: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-88-tiwai@suse.de --- sound/pci/ymfpci/ymfpci.c | 2 +- sound/pci/ymfpci/ymfpci_main.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index 48444dda44de..764ca59e98d1 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -188,7 +188,7 @@ static int __snd_card_ymfpci_probe(struct pci_dev *pci, default: model = str = "???"; break; } - strcpy(card->driver, str); + strscpy(card->driver, str); sprintf(card->shortname, "Yamaha %s (%s)", model, str); sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index d495f53a8324..75e013b66c5b 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -1134,7 +1134,7 @@ int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device) /* global setup */ pcm->info_flags = 0; - strcpy(pcm->name, "YMFPCI"); + strscpy(pcm->name, "YMFPCI"); chip->pcm = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -1201,7 +1201,7 @@ int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device) /* global setup */ pcm->info_flags = 0; - strcpy(pcm->name, "YMFPCI - IEC958"); + strscpy(pcm->name, "YMFPCI - IEC958"); chip->pcm_spdif = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -1242,7 +1242,7 @@ int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device) /* global setup */ pcm->info_flags = 0; - strcpy(pcm->name, "YMFPCI - Rear PCM"); + strscpy(pcm->name, "YMFPCI - Rear PCM"); chip->pcm_4ch = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -1948,7 +1948,7 @@ int snd_ymfpci_timer(struct snd_ymfpci *chip, int device) tid.subdevice = 0; err = snd_timer_new(chip->card, "YMFPCI", &tid, &timer); if (err >= 0) { - strcpy(timer->name, "YMFPCI timer"); + strscpy(timer->name, "YMFPCI timer"); timer->private_data = chip; timer->hw = snd_ymfpci_timer_hw; } From a5546578af79da589e27d50441ef6881de21e65d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:10 +0200 Subject: [PATCH 301/385] ALSA: pdaudiocf: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-89-tiwai@suse.de --- sound/pcmcia/pdaudiocf/pdaudiocf.c | 2 +- sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 494460746614..13419837dfb7 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -160,7 +160,7 @@ static int snd_pdacf_assign_resources(struct snd_pdacf *pdacf, int port, int irq if (err < 0) return err; - strcpy(card->driver, "PDAudio-CF"); + strscpy(card->driver, "PDAudio-CF"); sprintf(card->shortname, "Core Sound %s", card->driver); sprintf(card->longname, "%s at 0x%x, irq %i", card->shortname, port, irq); diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c index aaa82ec36540..20aba745f1dc 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c @@ -263,7 +263,7 @@ int snd_pdacf_pcm_new(struct snd_pdacf *chip) pcm->private_data = chip; pcm->info_flags = 0; pcm->nonatomic = true; - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); chip->pcm = pcm; err = snd_ak4117_build(chip->ak4117, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); From 704a54b84f567ecbefdce250f455c9ff2d4f3860 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:11 +0200 Subject: [PATCH 302/385] ALSA: vxpocket: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-90-tiwai@suse.de --- sound/pcmcia/vx/vxpocket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index d2d5f64d63b4..2e09f2a513a6 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -187,7 +187,7 @@ static int vxpocket_config(struct pcmcia_device *link) /* overwrite the hardware information */ chip->hw = &vxp440_hw; chip->type = vxp440_hw.type; - strcpy(chip->card->driver, vxp440_hw.name); + strscpy(chip->card->driver, vxp440_hw.name); } ret = pcmcia_request_io(link); From 292e4adb954b8584b74bff0d1f9044af297fa248 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:12 +0200 Subject: [PATCH 303/385] ALSA: ppc: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-91-tiwai@suse.de --- sound/ppc/awacs.c | 2 +- sound/ppc/burgundy.c | 2 +- sound/ppc/daca.c | 2 +- sound/ppc/pmac.c | 2 +- sound/ppc/powermac.c | 8 ++++---- sound/ppc/snd_ps3.c | 8 ++++---- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c index 49399a4a290d..13a6f3af13ef 100644 --- a/sound/ppc/awacs.c +++ b/sound/ppc/awacs.c @@ -956,7 +956,7 @@ snd_pmac_awacs_init(struct snd_pmac *chip) /* * build mixers */ - strcpy(chip->card->mixername, "PowerMac AWACS"); + strscpy(chip->card->mixername, "PowerMac AWACS"); err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers), snd_pmac_awacs_mixers); diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c index 400a886562b1..ba15bc34c9ec 100644 --- a/sound/ppc/burgundy.c +++ b/sound/ppc/burgundy.c @@ -665,7 +665,7 @@ int snd_pmac_burgundy_init(struct snd_pmac *chip) /* * build burgundy mixers */ - strcpy(chip->card->mixername, "PowerMac Burgundy"); + strscpy(chip->card->mixername, "PowerMac Burgundy"); for (i = 0; i < ARRAY_SIZE(snd_pmac_burgundy_mixers); i++) { err = snd_ctl_add(chip->card, diff --git a/sound/ppc/daca.c b/sound/ppc/daca.c index d5766952f3db..a74114225b67 100644 --- a/sound/ppc/daca.c +++ b/sound/ppc/daca.c @@ -261,7 +261,7 @@ int snd_pmac_daca_init(struct snd_pmac *chip) /* * build mixers */ - strcpy(chip->card->mixername, "PowerMac DACA"); + strscpy(chip->card->mixername, "PowerMac DACA"); for (i = 0; i < ARRAY_SIZE(daca_mixers); i++) { err = snd_ctl_add(chip->card, snd_ctl_new1(&daca_mixers[i], chip)); diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 76674c43fa7e..a3d346f1cc05 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -679,7 +679,7 @@ int snd_pmac_pcm_new(struct snd_pmac *chip) pcm->private_data = chip; pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); chip->pcm = pcm; chip->formats_ok = SNDRV_PCM_FMTBIT_S16_BE; diff --git a/sound/ppc/powermac.c b/sound/ppc/powermac.c index f1b0cf9ea555..e685d245883e 100644 --- a/sound/ppc/powermac.c +++ b/sound/ppc/powermac.c @@ -55,8 +55,8 @@ static int snd_pmac_probe(struct platform_device *devptr) switch (chip->model) { case PMAC_BURGUNDY: - strcpy(card->driver, "PMac Burgundy"); - strcpy(card->shortname, "PowerMac Burgundy"); + strscpy(card->driver, "PMac Burgundy"); + strscpy(card->shortname, "PowerMac Burgundy"); sprintf(card->longname, "%s (Dev %d) Sub-frame %d", card->shortname, chip->device_id, chip->subframe); err = snd_pmac_burgundy_init(chip); @@ -64,8 +64,8 @@ static int snd_pmac_probe(struct platform_device *devptr) goto __error; break; case PMAC_DACA: - strcpy(card->driver, "PMac DACA"); - strcpy(card->shortname, "PowerMac DACA"); + strscpy(card->driver, "PMac DACA"); + strscpy(card->shortname, "PowerMac DACA"); sprintf(card->longname, "%s (Dev %d) Sub-frame %d", card->shortname, chip->device_id, chip->subframe); err = snd_pmac_daca_init(chip); diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index a6cff2c46ac7..ce7ee2713f9d 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c @@ -951,9 +951,9 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev) if (ret < 0) goto clean_irq; - strcpy(the_card.card->driver, "PS3"); - strcpy(the_card.card->shortname, "PS3"); - strcpy(the_card.card->longname, "PS3 sound"); + strscpy(the_card.card->driver, "PS3"); + strscpy(the_card.card->shortname, "PS3"); + strscpy(the_card.card->longname, "PS3 sound"); /* create control elements */ for (i = 0; i < ARRAY_SIZE(spdif_ctls); i++) { @@ -975,7 +975,7 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev) goto clean_card; the_card.pcm->private_data = &the_card; - strcpy(the_card.pcm->name, "SPDIF"); + strscpy(the_card.pcm->name, "SPDIF"); /* set pcm ops */ snd_pcm_set_ops(the_card.pcm, SNDRV_PCM_STREAM_PLAYBACK, From 61d4db8f7c6c63fd4dfba67bda86754770eed627 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:13 +0200 Subject: [PATCH 304/385] ALSA: sh: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-92-tiwai@suse.de --- sound/sh/aica.c | 8 ++++---- sound/sh/sh_dac_audio.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/sh/aica.c b/sound/sh/aica.c index 40ea843113a7..fa81bfba59c1 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -424,7 +424,7 @@ static int __init snd_aicapcmchip(struct snd_card_aica if (unlikely(err < 0)) return err; pcm->private_data = dreamcastcard; - strcpy(pcm->name, "AICA PCM"); + strscpy(pcm->name, "AICA PCM"); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_aicapcm_playback_ops); /* Allocate the DMA buffers */ @@ -568,9 +568,9 @@ static int snd_aica_probe(struct platform_device *devptr) kfree(dreamcastcard); return err; } - strcpy(dreamcastcard->card->driver, "snd_aica"); - strcpy(dreamcastcard->card->shortname, SND_AICA_DRIVER); - strcpy(dreamcastcard->card->longname, + strscpy(dreamcastcard->card->driver, "snd_aica"); + strscpy(dreamcastcard->card->shortname, SND_AICA_DRIVER); + strscpy(dreamcastcard->card->longname, "Yamaha AICA Super Intelligent Sound Processor for SEGA Dreamcast"); /* Prepare to use the queue */ INIT_WORK(&(dreamcastcard->spu_dma_work), run_spu_dma); diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c index 84a4b17a0cc2..164f91240d02 100644 --- a/sound/sh/sh_dac_audio.c +++ b/sound/sh/sh_dac_audio.c @@ -224,7 +224,7 @@ static int snd_sh_dac_pcm(struct snd_sh_dac *chip, int device) return err; pcm->private_data = chip; - strcpy(pcm->name, "SH_DAC PCM"); + strscpy(pcm->name, "SH_DAC PCM"); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sh_dac_pcm_ops); /* buffer size=48K */ @@ -358,8 +358,8 @@ static int snd_sh_dac_probe(struct platform_device *devptr) if (err < 0) goto probe_error; - strcpy(card->driver, "snd_sh_dac"); - strcpy(card->shortname, "SuperH DAC audio driver"); + strscpy(card->driver, "snd_sh_dac"); + strscpy(card->shortname, "SuperH DAC audio driver"); dev_info(&devptr->dev, "%s %s\n", card->longname, card->shortname); err = snd_card_register(card); From fee48aed6b8d87667128b2c937fcedecc7da7c1c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:14 +0200 Subject: [PATCH 305/385] ALSA: sparc: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-93-tiwai@suse.de --- sound/sparc/cs4231.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index 1b44119edfbc..1a1fe3ceb76c 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -1230,7 +1230,7 @@ static int snd_cs4231_pcm(struct snd_card *card) /* global setup */ pcm->private_data = chip; pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; - strcpy(pcm->name, "CS4231"); + strscpy(pcm->name, "CS4231"); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &chip->op->dev, 64 * 1024, 128 * 1024); @@ -1256,7 +1256,7 @@ static int snd_cs4231_timer(struct snd_card *card) err = snd_timer_new(card, "CS4231", &tid, &timer); if (err < 0) return err; - strcpy(timer->name, "CS4231"); + strscpy(timer->name, "CS4231"); timer->private_data = chip; timer->hw = snd_cs4231_timer_table; chip->timer = timer; @@ -1530,7 +1530,7 @@ static int snd_cs4231_mixer(struct snd_card *card) if (snd_BUG_ON(!chip || !chip->pcm)) return -EINVAL; - strcpy(card->mixername, chip->pcm->name); + strscpy(card->mixername, chip->pcm->name); for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) { err = snd_ctl_add(card, @@ -1565,8 +1565,8 @@ static int cs4231_attach_begin(struct platform_device *op, if (err < 0) return err; - strcpy(card->driver, "CS4231"); - strcpy(card->shortname, "Sun CS4231"); + strscpy(card->driver, "CS4231"); + strscpy(card->shortname, "Sun CS4231"); chip = card->private_data; chip->card = card; @@ -1964,12 +1964,12 @@ static int snd_cs4231_ebus_create(struct snd_card *card, chip->op = op; memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image)); - strcpy(chip->c_dma.ebus_info.name, "cs4231(capture)"); + strscpy(chip->c_dma.ebus_info.name, "cs4231(capture)"); chip->c_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER; chip->c_dma.ebus_info.callback = snd_cs4231_ebus_capture_callback; chip->c_dma.ebus_info.client_cookie = chip; chip->c_dma.ebus_info.irq = op->archdata.irqs[0]; - strcpy(chip->p_dma.ebus_info.name, "cs4231(play)"); + strscpy(chip->p_dma.ebus_info.name, "cs4231(play)"); chip->p_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER; chip->p_dma.ebus_info.callback = snd_cs4231_ebus_play_callback; chip->p_dma.ebus_info.client_cookie = chip; From 3fb167d7ceb7f22462743df93d9ed7f06eeaf6d0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:15 +0200 Subject: [PATCH 306/385] ALSA: spi: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-94-tiwai@suse.de --- sound/spi/at73c213.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index 8f6929ced2c8..a0a7f90b6146 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c @@ -336,7 +336,7 @@ static int snd_at73c213_pcm_new(struct snd_at73c213 *chip, int device) pcm->private_data = chip; pcm->info_flags = SNDRV_PCM_INFO_BLOCK_TRANSFER; - strcpy(pcm->name, "at73c213"); + strscpy(pcm->name, "at73c213"); chip->pcm = pcm; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &at73c213_playback_ops); @@ -713,7 +713,7 @@ static int snd_at73c213_mixer(struct snd_at73c213 *chip) card = chip->card; - strcpy(card->mixername, chip->pcm->name); + strscpy(card->mixername, chip->pcm->name); for (idx = 0; idx < ARRAY_SIZE(snd_at73c213_controls); idx++) { errval = snd_ctl_add(card, @@ -983,8 +983,8 @@ static int snd_at73c213_probe(struct spi_device *spi) if (retval) goto out_ssc; - strcpy(card->driver, "at73c213"); - strcpy(card->shortname, board->shortname); + strscpy(card->driver, "at73c213"); + strscpy(card->shortname, board->shortname); sprintf(card->longname, "%s on irq %d", card->shortname, chip->irq); retval = snd_card_register(card); From 2173cee16c2cad741d14c2eb17d39928f7b162c9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:16 +0200 Subject: [PATCH 307/385] ALSA: synth: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-95-tiwai@suse.de --- sound/synth/emux/emux_hwdep.c | 2 +- sound/synth/emux/emux_oss.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c index 9e98c4c73fd1..14b990cf3b22 100644 --- a/sound/synth/emux/emux_hwdep.c +++ b/sound/synth/emux/emux_hwdep.c @@ -121,7 +121,7 @@ snd_emux_init_hwdep(struct snd_emux *emu) if (err < 0) return err; emu->hwdep = hw; - strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME); + strscpy(hw->name, SNDRV_EMUX_HWDEP_NAME); hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE; hw->ops.ioctl = snd_emux_hwdep_ioctl; /* The ioctl parameter types are compatible between 32- and diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c index 5f98d5201ba2..1145c7956afd 100644 --- a/sound/synth/emux/emux_oss.c +++ b/sound/synth/emux/emux_oss.c @@ -60,7 +60,7 @@ snd_emux_init_seq_oss(struct snd_emux *emu) return; emu->oss_synth = dev; - strcpy(dev->name, emu->name); + strscpy(dev->name, emu->name); arg = SNDRV_SEQ_DEVICE_ARGPTR(dev); arg->type = SYNTH_TYPE_SAMPLE; arg->subtype = SAMPLE_TYPE_AWE32; From 19a28b8c7f9f63019fa1b6ccfbbe78f5fd4bc77c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:17 +0200 Subject: [PATCH 308/385] ALSA: 6fire: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-96-tiwai@suse.de --- sound/usb/6fire/chip.c | 4 ++-- sound/usb/6fire/midi.c | 2 +- sound/usb/6fire/pcm.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c index d562a30b087f..9eb4bf9b138b 100644 --- a/sound/usb/6fire/chip.c +++ b/sound/usb/6fire/chip.c @@ -125,8 +125,8 @@ static int usb6fire_chip_probe(struct usb_interface *intf, dev_err(&intf->dev, "cannot create alsa card.\n"); return ret; } - strcpy(card->driver, "6FireUSB"); - strcpy(card->shortname, "TerraTec DMX6FireUSB"); + strscpy(card->driver, "6FireUSB"); + strscpy(card->shortname, "TerraTec DMX6FireUSB"); sprintf(card->longname, "%s at %d:%d", card->shortname, device->bus->busnum, device->devnum); diff --git a/sound/usb/6fire/midi.c b/sound/usb/6fire/midi.c index de2691d58de6..923f7767e62f 100644 --- a/sound/usb/6fire/midi.c +++ b/sound/usb/6fire/midi.c @@ -183,7 +183,7 @@ int usb6fire_midi_init(struct sfire_chip *chip) return ret; } rt->instance->private_data = rt; - strcpy(rt->instance->name, "DMX6FireUSB MIDI"); + strscpy(rt->instance->name, "DMX6FireUSB MIDI"); rt->instance->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index 32c39d8bd2e5..d53cad97889a 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c @@ -640,7 +640,7 @@ int usb6fire_pcm_init(struct sfire_chip *chip) } pcm->private_data = rt; - strcpy(pcm->name, "DMX 6Fire USB"); + strscpy(pcm->name, "DMX 6Fire USB"); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_ops); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); From 2d41b6f40637210a6f41642cfb343d339fa95b52 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:18 +0200 Subject: [PATCH 309/385] ALSA: line6: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-97-tiwai@suse.de --- sound/usb/line6/driver.c | 8 ++++---- sound/usb/line6/midi.c | 4 ++-- sound/usb/line6/pcm.c | 2 +- sound/usb/line6/toneport.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index e9eb5c74d6c7..f2f9261489a2 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -678,7 +678,7 @@ static int line6_hwdep_init(struct usb_line6 *line6) err = snd_hwdep_new(line6->card, "config", 0, &hwdep); if (err < 0) goto end; - strcpy(hwdep->name, "config"); + strscpy(hwdep->name, "config"); hwdep->iface = SNDRV_HWDEP_IFACE_LINE6; hwdep->ops = hwdep_ops; hwdep->private_data = line6; @@ -770,9 +770,9 @@ int line6_probe(struct usb_interface *interface, line6->ifcdev = &interface->dev; INIT_DELAYED_WORK(&line6->startup_work, line6_startup_work); - strcpy(card->id, properties->id); - strcpy(card->driver, driver_name); - strcpy(card->shortname, properties->name); + strscpy(card->id, properties->id); + strscpy(card->driver, driver_name); + strscpy(card->shortname, properties->name); sprintf(card->longname, "Line 6 %s at USB %s", properties->name, dev_name(line6->ifcdev)); card->private_free = line6_destruct; diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c index 9b5176086280..1d77794b4490 100644 --- a/sound/usb/line6/midi.c +++ b/sound/usb/line6/midi.c @@ -228,8 +228,8 @@ static int snd_line6_new_midi(struct usb_line6 *line6, return err; rmidi = *rmidi_ret; - strcpy(rmidi->id, line6->properties->id); - strcpy(rmidi->name, line6->properties->name); + strscpy(rmidi->id, line6->properties->id); + strscpy(rmidi->name, line6->properties->name); rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index d4dbbc432505..c1e2a8ab66fa 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -486,7 +486,7 @@ static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret) if (err < 0) return err; pcm = *pcm_ret; - strcpy(pcm->name, line6->properties->name); + strscpy(pcm->name, line6->properties->name); /* set operators */ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index c073b38cd673..68cda7bf330c 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c @@ -199,7 +199,7 @@ static int snd_toneport_source_info(struct snd_kcontrol *kcontrol, if (uinfo->value.enumerated.item >= size) uinfo->value.enumerated.item = size - 1; - strcpy(uinfo->value.enumerated.name, + strscpy(uinfo->value.enumerated.name, toneport_source_info[uinfo->value.enumerated.item].name); return 0; From f3d81c058f4878f31bbf9dcb33b0acc41d02675c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:19 +0200 Subject: [PATCH 310/385] ALSA: usx2y: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-98-tiwai@suse.de --- sound/usb/usx2y/us122l.c | 2 +- sound/usb/usx2y/usX2Yhwdep.c | 2 +- sound/usb/usx2y/usbusx2y.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 6bcf8b859ebb..2ace3ba46091 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -495,7 +495,7 @@ static int usx2y_create_card(struct usb_device *device, init_waitqueue_head(&US122L(card)->sk.sleep); US122L(card)->is_us144 = flags & US122L_FLAG_US144; INIT_LIST_HEAD(&US122L(card)->midi_list); - strcpy(card->driver, "USB "NAME_ALLCAPS""); + strscpy(card->driver, "USB "NAME_ALLCAPS""); sprintf(card->shortname, "TASCAM "NAME_ALLCAPS""); sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)", card->shortname, diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index 9fd6a86cc08e..4d7925184826 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c @@ -102,7 +102,7 @@ static int snd_usx2y_hwdep_dsp_status(struct snd_hwdep *hw, } if (id < 0) return -ENODEV; - strcpy(info->id, type_ids[id]); + strscpy(info->id, type_ids[id]); info->num_dsps = 2; // 0: Prepad Data, 1: FPGA Code if (us428->chip_status & USX2Y_STAT_CHIP_INIT) info->chip_ready = 1; diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index 5756ff3528a2..f34e78910200 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -382,7 +382,7 @@ static int usx2y_create_card(struct usb_device *device, init_waitqueue_head(&usx2y(card)->us428ctls_wait_queue_head); mutex_init(&usx2y(card)->pcm_mutex); INIT_LIST_HEAD(&usx2y(card)->midi_list); - strcpy(card->driver, "USB "NAME_ALLCAPS""); + strscpy(card->driver, "USB "NAME_ALLCAPS""); sprintf(card->shortname, "TASCAM "NAME_ALLCAPS""); sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)", card->shortname, From 414e4f01f663d9d46cee98d1c8d2ef33f10ec26e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:20 +0200 Subject: [PATCH 311/385] ALSA: ua101: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-99-tiwai@suse.de --- sound/usb/misc/ua101.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c index 4f6b20ed29dd..e200e4af799c 100644 --- a/sound/usb/misc/ua101.c +++ b/sound/usb/misc/ua101.c @@ -1246,8 +1246,8 @@ static int ua101_probe(struct usb_interface *interface, goto probe_error; name = usb_id->idProduct == 0x0044 ? "UA-1000" : "UA-101"; - strcpy(card->driver, "UA-101"); - strcpy(card->shortname, name); + strscpy(card->driver, "UA-101"); + strscpy(card->shortname, name); usb_make_path(ua->dev, usb_path, sizeof(usb_path)); snprintf(ua->card->longname, sizeof(ua->card->longname), "EDIROL %s (serial %s), %u Hz at %s, %s speed", name, @@ -1272,7 +1272,7 @@ static int ua101_probe(struct usb_interface *interface, if (err < 0) goto probe_error; ua->pcm->private_data = ua; - strcpy(ua->pcm->name, name); + strscpy(ua->pcm->name, name); snd_pcm_set_ops(ua->pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_pcm_ops); snd_pcm_set_ops(ua->pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_pcm_ops); snd_pcm_set_managed_buffer_all(ua->pcm, SNDRV_DMA_TYPE_VMALLOC, From a9b25e8a437586fb1e1749caae96e305dc9e4906 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:21 +0200 Subject: [PATCH 312/385] ALSA: usb-audio: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-100-tiwai@suse.de --- sound/usb/card.c | 2 +- sound/usb/midi.c | 2 +- sound/usb/mixer.c | 2 +- sound/usb/stream.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index 9fb8726a6c93..630ce40ed2c9 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -756,7 +756,7 @@ static int snd_usb_audio_create(struct usb_interface *intf, card->private_free = snd_usb_audio_free; - strcpy(card->driver, "USB-Audio"); + strscpy(card->driver, "USB-Audio"); sprintf(component, "USB%04x:%04x", USB_ID_VENDOR(chip->usb_id), USB_ID_PRODUCT(chip->usb_id)); snd_component_add(card, component); diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 866e613fee4f..acb3bf92857c 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -2407,7 +2407,7 @@ static int snd_usbmidi_create_rawmidi(struct snd_usb_midi *umidi, out_ports, in_ports, &rmidi); if (err < 0) return err; - strcpy(rmidi->name, umidi->card->shortname); + strscpy(rmidi->name, umidi->card->shortname); rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 11be79af26db..a7cd7d51e66b 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -3569,7 +3569,7 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif) struct usb_mixer_interface *mixer; int err; - strcpy(chip->card->mixername, "USB Mixer"); + strscpy(chip->card->mixername, "USB Mixer"); mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); if (!mixer) diff --git a/sound/usb/stream.c b/sound/usb/stream.c index aa91d63749f2..749498fbf9cb 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -538,7 +538,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, if (chip->pcm_devs > 0) sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs); else - strcpy(pcm->name, "USB Audio"); + strscpy(pcm->name, "USB Audio"); snd_usb_init_substream(as, stream, fp, pd); From 926359588170882ab39c578774a989a5237a3747 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:22 +0200 Subject: [PATCH 313/385] ALSA: ac97: Copy string more safely snd_ac97_get_name() blindly assumes that the name buffer is large enough, but we should be more careful. Pass the max buffer length and allow trimming to the size. Only a cosmetic safety matter, no functional changes intended. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-101-tiwai@suse.de --- sound/pci/ac97/ac97_codec.c | 19 +++++++++++-------- sound/pci/ac97/ac97_local.h | 2 +- sound/pci/ac97/ac97_proc.c | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 588c094080be..cd60c856a92e 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -1840,7 +1840,8 @@ static const struct ac97_codec_id *look_for_codec_id(const struct ac97_codec_id return NULL; } -void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name, int modem) +void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name, + size_t maxlen, int modem) { const struct ac97_codec_id *pid; @@ -1852,7 +1853,7 @@ void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name, int m if (! pid) return; - strcpy(name, pid->name); + strscpy(name, pid->name, maxlen); if (ac97 && pid->patch) { if ((modem && (pid->flags & AC97_MODEM_PATCH)) || (! modem && ! (pid->flags & AC97_MODEM_PATCH))) @@ -1861,8 +1862,8 @@ void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name, int m pid = look_for_codec_id(snd_ac97_codec_ids, id); if (pid) { - strcat(name, " "); - strcat(name, pid->name); + strlcat(name, " ", maxlen); + strlcat(name, pid->name, maxlen); if (pid->mask != 0xffffffff) sprintf(name + strlen(name), " rev %u", id & ~pid->mask); if (ac97 && pid->patch) { @@ -1870,8 +1871,10 @@ void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name, int m (! modem && ! (pid->flags & AC97_MODEM_PATCH))) pid->patch(ac97); } - } else - sprintf(name + strlen(name), " id %x", id & 0xff); + } else { + int l = strlen(name); + snprintf(name + l, maxlen - l, " id %x", id & 0xff); + } } /** @@ -2295,8 +2298,8 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, /* additional initializations */ if (bus->ops->init) bus->ops->init(ac97); - snd_ac97_get_name(ac97, ac97->id, name, !ac97_is_audio(ac97)); - snd_ac97_get_name(NULL, ac97->id, name, !ac97_is_audio(ac97)); // ac97->id might be changed in the special setup code + snd_ac97_get_name(ac97, ac97->id, name, sizeof(name), !ac97_is_audio(ac97)); + snd_ac97_get_name(NULL, ac97->id, name, sizeof(name), !ac97_is_audio(ac97)); // ac97->id might be changed in the special setup code if (! ac97->build_ops) ac97->build_ops = &null_build_ops; diff --git a/sound/pci/ac97/ac97_local.h b/sound/pci/ac97/ac97_local.h index 8eeae2dec552..965284eb4b33 100644 --- a/sound/pci/ac97/ac97_local.h +++ b/sound/pci/ac97/ac97_local.h @@ -8,7 +8,7 @@ */ void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name, - int modem); + size_t maxlen, int modem); int snd_ac97_update_bits_nolock(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value); diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c index 518834964b7b..2df3ba9a08dc 100644 --- a/sound/pci/ac97/ac97_proc.c +++ b/sound/pci/ac97/ac97_proc.c @@ -98,7 +98,7 @@ static void snd_ac97_proc_read_main(struct snd_ac97 *ac97, struct snd_info_buffe static const char *spdif_rates_cs4205[4] = { " Rate=48kHz", " Rate=44.1kHz", " Rate=res", " Rate=res" }; static const char *double_rate_slots[4] = { "10/11", "7/8", "reserved", "reserved" }; - snd_ac97_get_name(NULL, ac97->id, name, 0); + snd_ac97_get_name(NULL, ac97->id, name, sizeof(name), 0); snd_iprintf(buffer, "%d-%d/%d: %s\n\n", ac97->addr, ac97->num, subidx, name); if ((ac97->scaps & AC97_SCAP_AUDIO) == 0) From f15be4dca2a622fa397eae43f03e71e68e50a266 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:23 +0200 Subject: [PATCH 314/385] ALSA: cmipci: Copy string more safely The probe code uses sprintf() and strcat() without caring about the string buffer size. Replace with safer code. Only a cosmetic safety matter, no functional changes intended. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-102-tiwai@suse.de --- sound/pci/cmipci.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 9056214e9cda..c4ee550d7c96 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -3008,11 +3008,12 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci, pci->device != PCI_DEVICE_ID_CMEDIA_CM8338B) query_chip(cm); /* added -MCx suffix for chip supporting multi-channels */ - if (cm->can_multi_ch) - sprintf(cm->card->driver + strlen(cm->card->driver), - "-MC%d", cm->max_channels); - else if (cm->can_ac3_sw) - strcpy(cm->card->driver + strlen(cm->card->driver), "-SWIEC"); + if (cm->can_multi_ch) { + int l = strlen(cm->card->driver); + scnprintf(cm->card->driver + l, sizeof(cm->card->driver) - l, + "-MC%d", cm->max_channels); + } else if (cm->can_ac3_sw) + strlcat(cm->card->driver, "-SWIEC", sizeof(cm->card->driver)); cm->dig_status = SNDRV_PCM_DEFAULT_CON_SPDIF; cm->dig_pcm_status = SNDRV_PCM_DEFAULT_CON_SPDIF; From 53beb4d0ed8f9bf31ba30e65953abb473b191bd0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:24 +0200 Subject: [PATCH 315/385] ALSA: usb-audio: Copy string more safely Replace strcpy() and sprintf() usages in the USB audio drivers with the safer versions (strscpy() and scnprintf()) with the proper max size evaluation. Only for safety, no actual behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-103-tiwai@suse.de --- sound/usb/card.c | 11 ++++++----- sound/usb/midi2.c | 3 ++- sound/usb/mixer.c | 22 +++++++++++----------- sound/usb/mixer_scarlett.c | 31 ++++++++++++++++++------------- sound/usb/mixer_scarlett2.c | 14 ++++++++------ sound/usb/proc.c | 2 +- sound/usb/stream.c | 3 ++- 7 files changed, 48 insertions(+), 38 deletions(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index 630ce40ed2c9..10d9b7285597 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -616,9 +616,10 @@ static void usb_audio_make_shortname(struct usb_device *dev, usb_string(dev, dev->descriptor.iProduct, card->shortname, sizeof(card->shortname)) <= 0) { /* no name available from anywhere, so use ID */ - sprintf(card->shortname, "USB Device %#04x:%#04x", - USB_ID_VENDOR(chip->usb_id), - USB_ID_PRODUCT(chip->usb_id)); + scnprintf(card->shortname, sizeof(card->shortname), + "USB Device %#04x:%#04x", + USB_ID_VENDOR(chip->usb_id), + USB_ID_PRODUCT(chip->usb_id)); } strim(card->shortname); @@ -757,8 +758,8 @@ static int snd_usb_audio_create(struct usb_interface *intf, card->private_free = snd_usb_audio_free; strscpy(card->driver, "USB-Audio"); - sprintf(component, "USB%04x:%04x", - USB_ID_VENDOR(chip->usb_id), USB_ID_PRODUCT(chip->usb_id)); + scnprintf(component, sizeof(component), "USB%04x:%04x", + USB_ID_VENDOR(chip->usb_id), USB_ID_PRODUCT(chip->usb_id)); snd_component_add(card, component); usb_audio_make_shortname(dev, chip, quirk); diff --git a/sound/usb/midi2.c b/sound/usb/midi2.c index 692dfc3c182f..030569fda416 100644 --- a/sound/usb/midi2.c +++ b/sound/usb/midi2.c @@ -1058,7 +1058,8 @@ static void set_fallback_rawmidi_names(struct snd_usb_midi2_interface *umidi) fill_ump_ep_name(ump, dev, dev->descriptor.iProduct); /* fill fallback name */ if (!*ump->info.name) - sprintf(ump->info.name, "USB MIDI %d", rmidi->index); + scnprintf(ump->info.name, sizeof(ump->info.name), + "USB MIDI %d", rmidi->index); /* copy as rawmidi name if not set */ if (!*ump->core.name) strscpy(ump->core.name, ump->info.name, diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index a7cd7d51e66b..63b300bc67ba 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -674,40 +674,40 @@ static int get_term_name(struct snd_usb_audio *chip, struct usb_audio_term *iter return 0; switch (iterm->type >> 16) { case UAC3_SELECTOR_UNIT: - strcpy(name, "Selector"); + strscpy(name, "Selector", maxlen); return 8; case UAC3_PROCESSING_UNIT: - strcpy(name, "Process Unit"); + strscpy(name, "Process Unit", maxlen); return 12; case UAC3_EXTENSION_UNIT: - strcpy(name, "Ext Unit"); + strscpy(name, "Ext Unit", maxlen); return 8; case UAC3_MIXER_UNIT: - strcpy(name, "Mixer"); + strscpy(name, "Mixer", maxlen); return 5; default: - return sprintf(name, "Unit %d", iterm->id); + return scnprintf(name, maxlen, "Unit %d", iterm->id); } } switch (iterm->type & 0xff00) { case 0x0100: - strcpy(name, "PCM"); + strscpy(name, "PCM", maxlen); return 3; case 0x0200: - strcpy(name, "Mic"); + strscpy(name, "Mic", maxlen); return 3; case 0x0400: - strcpy(name, "Headset"); + strscpy(name, "Headset", maxlen); return 7; case 0x0500: - strcpy(name, "Phone"); + strscpy(name, "Phone", maxlen); return 5; } for (names = iterm_names; names->type; names++) { if (names->type == iterm->type) { - strcpy(name, names->name); + strscpy(name, names->name, maxlen); return strlen(names->name); } } @@ -2804,7 +2804,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, len = get_term_name(state->chip, &iterm, namelist[i], MAX_ITEM_NAME_LEN, 0); if (! len) - sprintf(namelist[i], "Input %u", i); + scnprintf(namelist[i], MAX_ITEM_NAME_LEN, "Input %u", i); } kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval); diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c index ff548041679b..8babfa3f7c45 100644 --- a/sound/usb/mixer_scarlett.c +++ b/sound/usb/mixer_scarlett.c @@ -357,21 +357,21 @@ static int scarlett_ctl_put(struct snd_kcontrol *kctl, return changed; } -static void scarlett_generate_name(int i, char *dst, int offsets[]) +static void scarlett_generate_name(int i, char *dst, size_t size, int offsets[]) { if (i > offsets[SCARLETT_OFFSET_MIX]) - sprintf(dst, "Mix %c", - 'A'+(i - offsets[SCARLETT_OFFSET_MIX] - 1)); + scnprintf(dst, size, "Mix %c", + 'A'+(i - offsets[SCARLETT_OFFSET_MIX] - 1)); else if (i > offsets[SCARLETT_OFFSET_ADAT]) - sprintf(dst, "ADAT %d", i - offsets[SCARLETT_OFFSET_ADAT]); + scnprintf(dst, size, "ADAT %d", i - offsets[SCARLETT_OFFSET_ADAT]); else if (i > offsets[SCARLETT_OFFSET_SPDIF]) - sprintf(dst, "SPDIF %d", i - offsets[SCARLETT_OFFSET_SPDIF]); + scnprintf(dst, size, "SPDIF %d", i - offsets[SCARLETT_OFFSET_SPDIF]); else if (i > offsets[SCARLETT_OFFSET_ANALOG]) - sprintf(dst, "Analog %d", i - offsets[SCARLETT_OFFSET_ANALOG]); + scnprintf(dst, size, "Analog %d", i - offsets[SCARLETT_OFFSET_ANALOG]); else if (i > offsets[SCARLETT_OFFSET_PCM]) - sprintf(dst, "PCM %d", i - offsets[SCARLETT_OFFSET_PCM]); + scnprintf(dst, size, "PCM %d", i - offsets[SCARLETT_OFFSET_PCM]); else - sprintf(dst, "Off"); + scnprintf(dst, size, "Off"); } static int scarlett_ctl_enum_dynamic_info(struct snd_kcontrol *kctl, @@ -391,6 +391,7 @@ static int scarlett_ctl_enum_dynamic_info(struct snd_kcontrol *kctl, /* generate name dynamically based on item number and offset info */ scarlett_generate_name(uinfo->value.enumerated.item, uinfo->value.enumerated.name, + sizeof(uinfo->value.enumerated.name), opt->offsets); return 0; @@ -876,7 +877,8 @@ static int scarlett_controls_create_generic(struct usb_mixer_interface *mixer, return err; break; case SCARLETT_SWITCH_IMPEDANCE: - sprintf(mx, "Input %d Impedance Switch", ctl->num); + scnprintf(mx, sizeof(mx), + "Input %d Impedance Switch", ctl->num); err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, scarlett_ctl_enum_resume, 0x01, 0x09, ctl->num, USB_MIXER_S16, 1, mx, @@ -885,7 +887,8 @@ static int scarlett_controls_create_generic(struct usb_mixer_interface *mixer, return err; break; case SCARLETT_SWITCH_PAD: - sprintf(mx, "Input %d Pad Switch", ctl->num); + scnprintf(mx, sizeof(mx), + "Input %d Pad Switch", ctl->num); err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, scarlett_ctl_enum_resume, 0x01, 0x0b, ctl->num, USB_MIXER_S16, 1, mx, @@ -894,7 +897,8 @@ static int scarlett_controls_create_generic(struct usb_mixer_interface *mixer, return err; break; case SCARLETT_SWITCH_GAIN: - sprintf(mx, "Input %d Gain Switch", ctl->num); + scnprintf(mx, sizeof(mx), + "Input %d Gain Switch", ctl->num); err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, scarlett_ctl_enum_resume, 0x01, 0x08, ctl->num, USB_MIXER_S16, 1, mx, @@ -960,8 +964,9 @@ int snd_scarlett_controls_create(struct usb_mixer_interface *mixer) return err; for (o = 0; o < info->matrix_out; o++) { - sprintf(mx, "Matrix %02d Mix %c Playback Volume", i+1, - o+'A'); + scnprintf(mx, sizeof(mx), + "Matrix %02d Mix %c Playback Volume", i+1, + o+'A'); err = add_new_ctl(mixer, &usb_scarlett_ctl, scarlett_ctl_resume, 0x3c, 0x00, (i << 3) + (o & 0x07), USB_MIXER_S16, diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index 93589e86828a..49eeb1444dce 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -7396,13 +7396,15 @@ static int scarlett2_mux_src_enum_ctl_info(struct snd_kcontrol *kctl, if (port_type == SCARLETT2_PORT_TYPE_MIX && item >= private->num_mix_out) - sprintf(uinfo->value.enumerated.name, - port->dsp_src_descr, - item - private->num_mix_out + 1); + scnprintf(uinfo->value.enumerated.name, + sizeof(uinfo->value.enumerated.name), + port->dsp_src_descr, + item - private->num_mix_out + 1); else - sprintf(uinfo->value.enumerated.name, - port->src_descr, - item + port->src_num_offset); + scnprintf(uinfo->value.enumerated.name, + sizeof(uinfo->value.enumerated.name), + port->src_descr, + item + port->src_num_offset); return 0; } diff --git a/sound/usb/proc.c b/sound/usb/proc.c index e9bbaea7b2fa..c8b967bd7065 100644 --- a/sound/usb/proc.c +++ b/sound/usb/proc.c @@ -231,7 +231,7 @@ void snd_usb_proc_pcm_format_add(struct snd_usb_stream *stream) char name[32]; struct snd_card *card = stream->chip->card; - sprintf(name, "stream%d", stream->pcm_index); + scnprintf(name, sizeof(name), "stream%d", stream->pcm_index); snd_card_ro_proc_new(card, name, stream, proc_pcm_format_read); } diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 749498fbf9cb..ad6ced780634 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -536,7 +536,8 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, pcm->private_free = snd_usb_audio_pcm_free; pcm->info_flags = 0; if (chip->pcm_devs > 0) - sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs); + scnprintf(pcm->name, sizeof(pcm->name), "USB Audio #%d", + chip->pcm_devs); else strscpy(pcm->name, "USB Audio"); From bee60f019606827363d7e355b2e859e29e928c3a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Jul 2025 12:07:25 +0200 Subject: [PATCH 316/385] ALSA: core: Copy string more safely Replace the remaining strcpy() and sprintf() usages in the ALSA core code with the safer versions. The first strcpy() points actually to card->id, hence just use strscpy() with card->id instead. The append of suffix string is slightly rewritten so that we can use scnprintf() and strscpy(). Only for safety, no actual behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250710100727.22653-104-tiwai@suse.de --- sound/core/init.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/sound/core/init.c b/sound/core/init.c index 114fb87de990..c372b3228785 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -723,27 +723,25 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src, * ("card" conflicts with proc directories) */ if (!*id || !strncmp(id, "card", 4)) { - strcpy(id, "Default"); + strscpy(card->id, "Default"); is_default = true; } len = strlen(id); for (loops = 0; loops < SNDRV_CARDS; loops++) { - char *spos; char sfxstr[5]; /* "_012" */ - int sfxlen; + int sfxlen, slen; if (card_id_ok(card, id)) return; /* OK */ /* Add _XYZ suffix */ - sprintf(sfxstr, "_%X", loops + 1); - sfxlen = strlen(sfxstr); + sfxlen = scnprintf(sfxstr, sizeof(sfxstr), "_%X", loops + 1); if (len + sfxlen >= sizeof(card->id)) - spos = id + sizeof(card->id) - sfxlen - 1; + slen = sizeof(card->id) - sfxlen - 1; else - spos = id + len; - strcpy(spos, sfxstr); + slen = len; + strscpy(id + slen, sfxstr, sizeof(card->id) - slen); } /* fallback to the default id */ if (!is_default) { @@ -801,7 +799,7 @@ static ssize_t id_store(struct device *dev, struct device_attribute *attr, guard(mutex)(&snd_card_mutex); if (!card_id_ok(NULL, buf1)) return -EEXIST; - strcpy(card->id, buf1); + strscpy(card->id, buf1); snd_info_card_id_change(card); return count; From ed677858d4fe8d165952c1794898d6fc0b65ddfe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:04 +0200 Subject: [PATCH 317/385] ALSA: hda: Move widget capability macros into hdaudio.h The get_wcaps() and co are used not only by HD-audio core but also other driver code, hence it'd be better to put into the common header instead of local.h. OTOH, there are macros of the same name like get_wcaps() that are still used in sound/pci/hda/* locally, and those conflict with each other. So we need to rename get_wcaps() (to be moved from hda-core) with the proper snd_hdac prefix for avoiding name conflicts, and define in the common hdaudio.h. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-2-tiwai@suse.de --- include/sound/hdaudio.h | 24 ++++++++++++++++++++++++ sound/hda/hdac_device.c | 8 ++++---- sound/hda/hdac_sysfs.c | 14 +++++++------- sound/hda/local.h | 21 --------------------- sound/soc/codecs/hdac_hdmi.c | 21 ++++++++++----------- 5 files changed, 45 insertions(+), 43 deletions(-) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 25668eee65cf..d38234f8fe44 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -680,6 +680,30 @@ static inline void snd_hdac_dsp_cleanup(struct hdac_stream *azx_dev, } #endif /* CONFIG_SND_HDA_DSP_LOADER */ +/* + * Easy macros for widget capabilities + */ +#define snd_hdac_get_wcaps(codec, nid) \ + snd_hdac_read_parm(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) + +/* get the widget type from widget capability bits */ +static inline int snd_hdac_get_wcaps_type(unsigned int wcaps) +{ + if (!wcaps) + return -1; /* invalid type */ + return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; +} + +/* get the number of supported channels */ +static inline unsigned int snd_hdac_get_wcaps_channels(u32 wcaps) +{ + unsigned int chans; + + chans = (wcaps & AC_WCAP_CHAN_CNT_EXT) >> 13; + chans = (chans + 1) * 2; + + return chans; +} /* * generic array helpers diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index a02dce5f6a88..018f9e176b1b 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -436,11 +436,11 @@ EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets); /* return CONNLIST_LEN parameter of the given widget */ static unsigned int get_num_conns(struct hdac_device *codec, hda_nid_t nid) { - unsigned int wcaps = get_wcaps(codec, nid); + unsigned int wcaps = snd_hdac_get_wcaps(codec, nid); unsigned int parm; if (!(wcaps & AC_WCAP_CONN_LIST) && - get_wcaps_type(wcaps) != AC_WID_VOL_KNB) + snd_hdac_get_wcaps_type(wcaps) != AC_WID_VOL_KNB) return 0; parm = snd_hdac_read_parm(codec, nid, AC_PAR_CONNLIST_LEN); @@ -854,7 +854,7 @@ static unsigned int query_pcm_param(struct hdac_device *codec, hda_nid_t nid) unsigned int val = 0; if (nid != codec->afg && - (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) + (snd_hdac_get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) val = snd_hdac_read_parm(codec, nid, AC_PAR_PCM); if (!val || val == -1) val = snd_hdac_read_parm(codec, codec->afg, AC_PAR_PCM); @@ -894,7 +894,7 @@ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid, { unsigned int i, val, wcaps; - wcaps = get_wcaps(codec, nid); + wcaps = snd_hdac_get_wcaps(codec, nid); val = query_pcm_param(codec, nid); if (ratesp) { diff --git a/sound/hda/hdac_sysfs.c b/sound/hda/hdac_sysfs.c index 60b0a70428d5..bffe52859dba 100644 --- a/sound/hda/hdac_sysfs.c +++ b/sound/hda/hdac_sysfs.c @@ -161,13 +161,13 @@ static const struct kobj_type widget_ktype = { static ssize_t caps_show(struct hdac_device *codec, hda_nid_t nid, struct widget_attribute *attr, char *buf) { - return sysfs_emit(buf, "0x%08x\n", get_wcaps(codec, nid)); + return sysfs_emit(buf, "0x%08x\n", snd_hdac_get_wcaps(codec, nid)); } static ssize_t pin_caps_show(struct hdac_device *codec, hda_nid_t nid, struct widget_attribute *attr, char *buf) { - if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) + if (snd_hdac_get_wcaps_type(snd_hdac_get_wcaps(codec, nid)) != AC_WID_PIN) return 0; return sysfs_emit(buf, "0x%08x\n", snd_hdac_read_parm(codec, nid, AC_PAR_PIN_CAP)); @@ -178,7 +178,7 @@ static ssize_t pin_cfg_show(struct hdac_device *codec, hda_nid_t nid, { unsigned int val; - if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) + if (snd_hdac_get_wcaps_type(snd_hdac_get_wcaps(codec, nid)) != AC_WID_PIN) return 0; if (snd_hdac_read(codec, nid, AC_VERB_GET_CONFIG_DEFAULT, 0, &val)) return 0; @@ -189,7 +189,7 @@ static bool has_pcm_cap(struct hdac_device *codec, hda_nid_t nid) { if (nid == codec->afg || nid == codec->mfg) return true; - switch (get_wcaps_type(get_wcaps(codec, nid))) { + switch (snd_hdac_get_wcaps_type(snd_hdac_get_wcaps(codec, nid))) { case AC_WID_AUD_OUT: case AC_WID_AUD_IN: return true; @@ -219,7 +219,7 @@ static ssize_t pcm_formats_show(struct hdac_device *codec, hda_nid_t nid, static ssize_t amp_in_caps_show(struct hdac_device *codec, hda_nid_t nid, struct widget_attribute *attr, char *buf) { - if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) + if (nid != codec->afg && !(snd_hdac_get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) return 0; return sysfs_emit(buf, "0x%08x\n", snd_hdac_read_parm(codec, nid, AC_PAR_AMP_IN_CAP)); @@ -228,7 +228,7 @@ static ssize_t amp_in_caps_show(struct hdac_device *codec, hda_nid_t nid, static ssize_t amp_out_caps_show(struct hdac_device *codec, hda_nid_t nid, struct widget_attribute *attr, char *buf) { - if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) + if (nid != codec->afg && !(snd_hdac_get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) return 0; return sysfs_emit(buf, "0x%08x\n", snd_hdac_read_parm(codec, nid, AC_PAR_AMP_OUT_CAP)); @@ -237,7 +237,7 @@ static ssize_t amp_out_caps_show(struct hdac_device *codec, hda_nid_t nid, static ssize_t power_caps_show(struct hdac_device *codec, hda_nid_t nid, struct widget_attribute *attr, char *buf) { - if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_POWER)) + if (nid != codec->afg && !(snd_hdac_get_wcaps(codec, nid) & AC_WCAP_POWER)) return 0; return sysfs_emit(buf, "0x%08x\n", snd_hdac_read_parm(codec, nid, AC_PAR_POWER_STATE)); diff --git a/sound/hda/local.h b/sound/hda/local.h index 896ba142e8bc..5f03b203c416 100644 --- a/sound/hda/local.h +++ b/sound/hda/local.h @@ -6,27 +6,6 @@ #ifndef __HDAC_LOCAL_H #define __HDAC_LOCAL_H -#define get_wcaps(codec, nid) \ - snd_hdac_read_parm(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) - -/* get the widget type from widget capability bits */ -static inline int get_wcaps_type(unsigned int wcaps) -{ - if (!wcaps) - return -1; /* invalid type */ - return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; -} - -static inline unsigned int get_wcaps_channels(u32 wcaps) -{ - unsigned int chans; - - chans = (wcaps & AC_WCAP_CHAN_CNT_EXT) >> 13; - chans = (chans + 1) * 2; - - return chans; -} - extern const struct attribute_group *hdac_dev_attr_groups[]; int hda_widget_sysfs_init(struct hdac_device *codec); int hda_widget_sysfs_reinit(struct hdac_device *codec, hda_nid_t start_nid, diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 1139a2754ca3..b33cd5178008 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -24,7 +24,6 @@ #include #include #include -#include "../../hda/local.h" #include "hdac_hdmi.h" #define NAME_SIZE 32 @@ -221,8 +220,8 @@ static int hdac_hdmi_get_port_len(struct hdac_device *hdev, hda_nid_t nid) unsigned int caps; unsigned int type, param; - caps = get_wcaps(hdev, nid); - type = get_wcaps_type(caps); + caps = snd_hdac_get_wcaps(hdev, nid); + type = snd_hdac_get_wcaps_type(caps); if (!(caps & AC_WCAP_DIGITAL) || (type != AC_WID_PIN)) return 0; @@ -492,10 +491,10 @@ static int hdac_hdmi_query_port_connlist(struct hdac_device *hdev, struct hdac_hdmi_pin *pin, struct hdac_hdmi_port *port) { - if (!(get_wcaps(hdev, pin->nid) & AC_WCAP_CONN_LIST)) { + if (!(snd_hdac_get_wcaps(hdev, pin->nid) & AC_WCAP_CONN_LIST)) { dev_warn(&hdev->dev, "HDMI: pin %d wcaps %#x does not support connection list\n", - pin->nid, get_wcaps(hdev, pin->nid)); + pin->nid, snd_hdac_get_wcaps(hdev, pin->nid)); return -EINVAL; } @@ -660,8 +659,8 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdev, struct hdac_hdmi_cvt *cvt) struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); int err; - chans = get_wcaps(hdev, cvt->nid); - chans = get_wcaps_channels(chans); + chans = snd_hdac_get_wcaps(hdev, cvt->nid); + chans = snd_hdac_get_wcaps_channels(chans); cvt->params.channels_min = 2; @@ -743,7 +742,7 @@ static void hdac_hdmi_set_power_state(struct hdac_device *hdev, int count; unsigned int state; - if (get_wcaps(hdev, nid) & AC_WCAP_POWER) { + if (snd_hdac_get_wcaps(hdev, nid) & AC_WCAP_POWER) { if (!snd_hdac_check_power_state(hdev, nid, pwr_state)) { for (count = 0; count < 10; count++) { snd_hdac_codec_read(hdev, nid, 0, @@ -761,7 +760,7 @@ static void hdac_hdmi_set_power_state(struct hdac_device *hdev, static void hdac_hdmi_set_amp(struct hdac_device *hdev, hda_nid_t nid, int val) { - if (get_wcaps(hdev, nid) & AC_WCAP_OUT_AMP) + if (snd_hdac_get_wcaps(hdev, nid) & AC_WCAP_OUT_AMP) snd_hdac_codec_write(hdev, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val); } @@ -1648,8 +1647,8 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev, unsigned int caps; unsigned int type; - caps = get_wcaps(hdev, nid); - type = get_wcaps_type(caps); + caps = snd_hdac_get_wcaps(hdev, nid); + type = snd_hdac_get_wcaps_type(caps); if (!(caps & AC_WCAP_DIGITAL)) continue; From b2660d1ebde1ba8f3edf963f3aac2bea884457c3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:05 +0200 Subject: [PATCH 318/385] ALSA: hda: Move HD-audio core stuff into sound/hda/core This is a part of HD-audio code restructuring. Simply move the current code of sound/hda/* into the subdirectory sound/hda/core, so that more stuff can be moved into sound/hda cleanly later. Most of file names with hdac_ and hdac_ext_ prefix are renamed without the prefix, since they can be identified well in the directory name and superfluous. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-3-tiwai@suse.de --- sound/hda/Kconfig | 67 +------------------ sound/hda/Makefile | 22 +----- sound/hda/core/Kconfig | 67 +++++++++++++++++++ sound/hda/core/Makefile | 22 ++++++ sound/hda/{ => core}/array.c | 0 sound/hda/{hdac_bus.c => core/bus.c} | 0 .../{hdac_component.c => core/component.c} | 0 .../{hdac_controller.c => core/controller.c} | 0 sound/hda/{hdac_device.c => core/device.c} | 0 sound/hda/{ => core}/ext/Makefile | 2 +- .../{ext/hdac_ext_bus.c => core/ext/bus.c} | 0 .../ext/controller.c} | 0 .../hdac_ext_stream.c => core/ext/stream.c} | 0 sound/hda/{ => core}/hda_bus_type.c | 0 sound/hda/{ => core}/hdmi_chmap.c | 0 sound/hda/{hdac_i915.c => core/i915.c} | 0 sound/hda/{ => core}/intel-dsp-config.c | 0 sound/hda/{ => core}/intel-nhlt.c | 0 sound/hda/{ => core}/intel-sdw-acpi.c | 0 sound/hda/{ => core}/local.h | 0 sound/hda/{hdac_regmap.c => core/regmap.c} | 0 sound/hda/{hdac_stream.c => core/stream.c} | 0 sound/hda/{hdac_sysfs.c => core/sysfs.c} | 0 sound/hda/{ => core}/trace.c | 0 sound/hda/{ => core}/trace.h | 0 25 files changed, 92 insertions(+), 88 deletions(-) create mode 100644 sound/hda/core/Kconfig create mode 100644 sound/hda/core/Makefile rename sound/hda/{ => core}/array.c (100%) rename sound/hda/{hdac_bus.c => core/bus.c} (100%) rename sound/hda/{hdac_component.c => core/component.c} (100%) rename sound/hda/{hdac_controller.c => core/controller.c} (100%) rename sound/hda/{hdac_device.c => core/device.c} (100%) rename sound/hda/{ => core}/ext/Makefile (54%) rename sound/hda/{ext/hdac_ext_bus.c => core/ext/bus.c} (100%) rename sound/hda/{ext/hdac_ext_controller.c => core/ext/controller.c} (100%) rename sound/hda/{ext/hdac_ext_stream.c => core/ext/stream.c} (100%) rename sound/hda/{ => core}/hda_bus_type.c (100%) rename sound/hda/{ => core}/hdmi_chmap.c (100%) rename sound/hda/{hdac_i915.c => core/i915.c} (100%) rename sound/hda/{ => core}/intel-dsp-config.c (100%) rename sound/hda/{ => core}/intel-nhlt.c (100%) rename sound/hda/{ => core}/intel-sdw-acpi.c (100%) rename sound/hda/{ => core}/local.h (100%) rename sound/hda/{hdac_regmap.c => core/regmap.c} (100%) rename sound/hda/{hdac_stream.c => core/stream.c} (100%) rename sound/hda/{hdac_sysfs.c => core/sysfs.c} (100%) rename sound/hda/{ => core}/trace.c (100%) rename sound/hda/{ => core}/trace.h (100%) diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig index eb488a522572..e38014656077 100644 --- a/sound/hda/Kconfig +++ b/sound/hda/Kconfig @@ -1,67 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -config SND_HDA_CORE - tristate - select REGMAP - -config SND_HDA_DSP_LOADER - bool - -config SND_HDA_ALIGNED_MMIO - bool - -config SND_HDA_COMPONENT - bool - -config SND_HDA_I915 - bool - select SND_HDA_COMPONENT - -config SND_HDA_EXT_CORE - tristate - select SND_HDA_CORE - -config SND_HDA_PREALLOC_SIZE - int "Pre-allocated buffer size for HD-audio driver" - range 0 32768 - default 0 if SND_DMA_SGBUF - default 64 if !SND_DMA_SGBUF - help - Specifies the default pre-allocated buffer-size in kB for the - HD-audio driver. A larger buffer (e.g. 2048) is preferred - for systems using PulseAudio. The default 64 is chosen just - for compatibility reasons. - On x86 systems, the default is zero as S/G allocation works - and no preallocation is needed in most cases. - - Note that the pre-allocation size can be changed dynamically - via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too. - -config SND_INTEL_NHLT - bool - # this config should be selected only for Intel ACPI platforms. - # A fallback is provided so that the code compiles in all cases. - -config SND_INTEL_DSP_CONFIG - tristate - select ACPI_NHLT if ACPI - select SND_INTEL_NHLT if ACPI - select SND_INTEL_SOUNDWIRE_ACPI if ACPI - # this config should be selected only for Intel DSP platforms. - # A fallback is provided so that the code compiles in all cases. - -config SND_INTEL_SOUNDWIRE_ACPI - tristate - -config SND_INTEL_BYT_PREFER_SOF - bool "Prefer SOF driver over SST on BY/CHT platforms" - depends on SND_SST_ATOM_HIFI2_PLATFORM_ACPI && SND_SOC_SOF_BAYTRAIL - default n - help - The kernel has 2 drivers for the Low Power Engine audio-block on - Bay- and Cherry-Trail SoCs. The old SST driver and the new SOF - driver. If both drivers are enabled then the kernel will default - to using the old SST driver, unless told otherwise through the - snd_intel_dspcfg.dsp_driver module-parameter. - - Set this option to Y to make the kernel default to the new SOF - driver instead. +source "sound/hda/core/Kconfig" diff --git a/sound/hda/Makefile b/sound/hda/Makefile index 83cceafe0d4c..3fdbc22b1530 100644 --- a/sound/hda/Makefile +++ b/sound/hda/Makefile @@ -1,22 +1,2 @@ # SPDX-License-Identifier: GPL-2.0 -snd-hda-core-y := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o \ - hdac_regmap.o hdac_controller.o hdac_stream.o array.o hdmi_chmap.o - -snd-hda-core-y += trace.o -CFLAGS_trace.o := -I$(src) - -# for sync with i915 gfx driver -snd-hda-core-$(CONFIG_SND_HDA_COMPONENT) += hdac_component.o -snd-hda-core-$(CONFIG_SND_HDA_I915) += hdac_i915.o - -obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o - -#extended hda -obj-$(CONFIG_SND_HDA_EXT_CORE) += ext/ - -snd-intel-dspcfg-y := intel-dsp-config.o -snd-intel-dspcfg-$(CONFIG_SND_INTEL_NHLT) += intel-nhlt.o -obj-$(CONFIG_SND_INTEL_DSP_CONFIG) += snd-intel-dspcfg.o - -snd-intel-sdw-acpi-y := intel-sdw-acpi.o -obj-$(CONFIG_SND_INTEL_SOUNDWIRE_ACPI) += snd-intel-sdw-acpi.o +obj-y += core/ diff --git a/sound/hda/core/Kconfig b/sound/hda/core/Kconfig new file mode 100644 index 000000000000..eb488a522572 --- /dev/null +++ b/sound/hda/core/Kconfig @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: GPL-2.0-only +config SND_HDA_CORE + tristate + select REGMAP + +config SND_HDA_DSP_LOADER + bool + +config SND_HDA_ALIGNED_MMIO + bool + +config SND_HDA_COMPONENT + bool + +config SND_HDA_I915 + bool + select SND_HDA_COMPONENT + +config SND_HDA_EXT_CORE + tristate + select SND_HDA_CORE + +config SND_HDA_PREALLOC_SIZE + int "Pre-allocated buffer size for HD-audio driver" + range 0 32768 + default 0 if SND_DMA_SGBUF + default 64 if !SND_DMA_SGBUF + help + Specifies the default pre-allocated buffer-size in kB for the + HD-audio driver. A larger buffer (e.g. 2048) is preferred + for systems using PulseAudio. The default 64 is chosen just + for compatibility reasons. + On x86 systems, the default is zero as S/G allocation works + and no preallocation is needed in most cases. + + Note that the pre-allocation size can be changed dynamically + via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too. + +config SND_INTEL_NHLT + bool + # this config should be selected only for Intel ACPI platforms. + # A fallback is provided so that the code compiles in all cases. + +config SND_INTEL_DSP_CONFIG + tristate + select ACPI_NHLT if ACPI + select SND_INTEL_NHLT if ACPI + select SND_INTEL_SOUNDWIRE_ACPI if ACPI + # this config should be selected only for Intel DSP platforms. + # A fallback is provided so that the code compiles in all cases. + +config SND_INTEL_SOUNDWIRE_ACPI + tristate + +config SND_INTEL_BYT_PREFER_SOF + bool "Prefer SOF driver over SST on BY/CHT platforms" + depends on SND_SST_ATOM_HIFI2_PLATFORM_ACPI && SND_SOC_SOF_BAYTRAIL + default n + help + The kernel has 2 drivers for the Low Power Engine audio-block on + Bay- and Cherry-Trail SoCs. The old SST driver and the new SOF + driver. If both drivers are enabled then the kernel will default + to using the old SST driver, unless told otherwise through the + snd_intel_dspcfg.dsp_driver module-parameter. + + Set this option to Y to make the kernel default to the new SOF + driver instead. diff --git a/sound/hda/core/Makefile b/sound/hda/core/Makefile new file mode 100644 index 000000000000..89cb46143050 --- /dev/null +++ b/sound/hda/core/Makefile @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0 +snd-hda-core-y := hda_bus_type.o bus.o device.o sysfs.o \ + regmap.o controller.o stream.o array.o hdmi_chmap.o + +snd-hda-core-y += trace.o +CFLAGS_trace.o := -I$(src) + +# for sync with i915 gfx driver +snd-hda-core-$(CONFIG_SND_HDA_COMPONENT) += component.o +snd-hda-core-$(CONFIG_SND_HDA_I915) += i915.o + +obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o + +#extended hda +obj-$(CONFIG_SND_HDA_EXT_CORE) += ext/ + +snd-intel-dspcfg-y := intel-dsp-config.o +snd-intel-dspcfg-$(CONFIG_SND_INTEL_NHLT) += intel-nhlt.o +obj-$(CONFIG_SND_INTEL_DSP_CONFIG) += snd-intel-dspcfg.o + +snd-intel-sdw-acpi-y := intel-sdw-acpi.o +obj-$(CONFIG_SND_INTEL_SOUNDWIRE_ACPI) += snd-intel-sdw-acpi.o diff --git a/sound/hda/array.c b/sound/hda/core/array.c similarity index 100% rename from sound/hda/array.c rename to sound/hda/core/array.c diff --git a/sound/hda/hdac_bus.c b/sound/hda/core/bus.c similarity index 100% rename from sound/hda/hdac_bus.c rename to sound/hda/core/bus.c diff --git a/sound/hda/hdac_component.c b/sound/hda/core/component.c similarity index 100% rename from sound/hda/hdac_component.c rename to sound/hda/core/component.c diff --git a/sound/hda/hdac_controller.c b/sound/hda/core/controller.c similarity index 100% rename from sound/hda/hdac_controller.c rename to sound/hda/core/controller.c diff --git a/sound/hda/hdac_device.c b/sound/hda/core/device.c similarity index 100% rename from sound/hda/hdac_device.c rename to sound/hda/core/device.c diff --git a/sound/hda/ext/Makefile b/sound/hda/core/ext/Makefile similarity index 54% rename from sound/hda/ext/Makefile rename to sound/hda/core/ext/Makefile index 05883fb28d28..85190a7eb5de 100644 --- a/sound/hda/ext/Makefile +++ b/sound/hda/core/ext/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-hda-ext-core-y := hdac_ext_bus.o hdac_ext_controller.o hdac_ext_stream.o +snd-hda-ext-core-y := bus.o controller.o stream.o obj-$(CONFIG_SND_HDA_EXT_CORE) += snd-hda-ext-core.o diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/core/ext/bus.c similarity index 100% rename from sound/hda/ext/hdac_ext_bus.c rename to sound/hda/core/ext/bus.c diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/core/ext/controller.c similarity index 100% rename from sound/hda/ext/hdac_ext_controller.c rename to sound/hda/core/ext/controller.c diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/core/ext/stream.c similarity index 100% rename from sound/hda/ext/hdac_ext_stream.c rename to sound/hda/core/ext/stream.c diff --git a/sound/hda/hda_bus_type.c b/sound/hda/core/hda_bus_type.c similarity index 100% rename from sound/hda/hda_bus_type.c rename to sound/hda/core/hda_bus_type.c diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/core/hdmi_chmap.c similarity index 100% rename from sound/hda/hdmi_chmap.c rename to sound/hda/core/hdmi_chmap.c diff --git a/sound/hda/hdac_i915.c b/sound/hda/core/i915.c similarity index 100% rename from sound/hda/hdac_i915.c rename to sound/hda/core/i915.c diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/core/intel-dsp-config.c similarity index 100% rename from sound/hda/intel-dsp-config.c rename to sound/hda/core/intel-dsp-config.c diff --git a/sound/hda/intel-nhlt.c b/sound/hda/core/intel-nhlt.c similarity index 100% rename from sound/hda/intel-nhlt.c rename to sound/hda/core/intel-nhlt.c diff --git a/sound/hda/intel-sdw-acpi.c b/sound/hda/core/intel-sdw-acpi.c similarity index 100% rename from sound/hda/intel-sdw-acpi.c rename to sound/hda/core/intel-sdw-acpi.c diff --git a/sound/hda/local.h b/sound/hda/core/local.h similarity index 100% rename from sound/hda/local.h rename to sound/hda/core/local.h diff --git a/sound/hda/hdac_regmap.c b/sound/hda/core/regmap.c similarity index 100% rename from sound/hda/hdac_regmap.c rename to sound/hda/core/regmap.c diff --git a/sound/hda/hdac_stream.c b/sound/hda/core/stream.c similarity index 100% rename from sound/hda/hdac_stream.c rename to sound/hda/core/stream.c diff --git a/sound/hda/hdac_sysfs.c b/sound/hda/core/sysfs.c similarity index 100% rename from sound/hda/hdac_sysfs.c rename to sound/hda/core/sysfs.c diff --git a/sound/hda/trace.c b/sound/hda/core/trace.c similarity index 100% rename from sound/hda/trace.c rename to sound/hda/core/trace.c diff --git a/sound/hda/trace.h b/sound/hda/core/trace.h similarity index 100% rename from sound/hda/trace.h rename to sound/hda/core/trace.h From 05be28fe8521f183f945d052d5019197e5934f0e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:06 +0200 Subject: [PATCH 319/385] ALSA: hda: Move common codec driver into sound/hda/common directory The snd-hda-codec module contains the most of common code used by both HD-audio controller and codec drivers, and it's basically independent from PCI. Let's move the code to sound/hda/common directory as a part of code reorganization. The hda_ prefix is dropped from the most of file names as it's rather superfluous. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-4-tiwai@suse.de --- sound/hda/Kconfig | 5 ++ sound/hda/Makefile | 1 + sound/hda/common/Kconfig | 80 +++++++++++++++++++ sound/hda/common/Makefile | 13 +++ .../common/auto_parser.c} | 0 .../{pci/hda/hda_beep.c => hda/common/beep.c} | 0 .../{pci/hda/hda_bind.c => hda/common/bind.c} | 0 .../hda/hda_codec.c => hda/common/codec.c} | 0 .../common/controller.c} | 2 +- .../common/controller_trace.h} | 2 +- .../{pci/hda => hda/common}/hda_auto_parser.h | 0 sound/{pci/hda => hda/common}/hda_beep.h | 0 .../{pci/hda => hda/common}/hda_controller.h | 0 sound/{pci/hda => hda/common}/hda_jack.h | 0 sound/{pci/hda => hda/common}/hda_local.h | 0 .../hda/hda_hwdep.c => hda/common/hwdep.c} | 0 .../{pci/hda/hda_jack.c => hda/common/jack.c} | 0 .../{pci/hda/hda_proc.c => hda/common/proc.c} | 0 .../hda/hda_sysfs.c => hda/common/sysfs.c} | 0 sound/pci/hda/Kconfig | 76 ------------------ sound/pci/hda/Makefile | 13 +-- 21 files changed, 103 insertions(+), 89 deletions(-) create mode 100644 sound/hda/common/Kconfig create mode 100644 sound/hda/common/Makefile rename sound/{pci/hda/hda_auto_parser.c => hda/common/auto_parser.c} (100%) rename sound/{pci/hda/hda_beep.c => hda/common/beep.c} (100%) rename sound/{pci/hda/hda_bind.c => hda/common/bind.c} (100%) rename sound/{pci/hda/hda_codec.c => hda/common/codec.c} (100%) rename sound/{pci/hda/hda_controller.c => hda/common/controller.c} (99%) rename sound/{pci/hda/hda_controller_trace.h => hda/common/controller_trace.h} (97%) rename sound/{pci/hda => hda/common}/hda_auto_parser.h (100%) rename sound/{pci/hda => hda/common}/hda_beep.h (100%) rename sound/{pci/hda => hda/common}/hda_controller.h (100%) rename sound/{pci/hda => hda/common}/hda_jack.h (100%) rename sound/{pci/hda => hda/common}/hda_local.h (100%) rename sound/{pci/hda/hda_hwdep.c => hda/common/hwdep.c} (100%) rename sound/{pci/hda/hda_jack.c => hda/common/jack.c} (100%) rename sound/{pci/hda/hda_proc.c => hda/common/proc.c} (100%) rename sound/{pci/hda/hda_sysfs.c => hda/common/sysfs.c} (100%) diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig index e38014656077..2928cb570ec6 100644 --- a/sound/hda/Kconfig +++ b/sound/hda/Kconfig @@ -1,2 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "HD-Audio" + +source "sound/hda/common/Kconfig" source "sound/hda/core/Kconfig" + +endmenu diff --git a/sound/hda/Makefile b/sound/hda/Makefile index 3fdbc22b1530..e7596bf736a4 100644 --- a/sound/hda/Makefile +++ b/sound/hda/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 obj-y += core/ +obj-$(CONFIG_SND_HDA) += common/ diff --git a/sound/hda/common/Kconfig b/sound/hda/common/Kconfig new file mode 100644 index 000000000000..d1e2bfd24c11 --- /dev/null +++ b/sound/hda/common/Kconfig @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config SND_HDA + tristate + select SND_PCM + select SND_VMASTER + select SND_JACK + select SND_HDA_CORE + +if SND_HDA + +config SND_HDA_HWDEP + bool "Build hwdep interface for HD-audio driver" + select SND_HWDEP + help + Say Y here to build a hwdep interface for HD-audio driver. + This interface can be used for out-of-band communication + with codecs for debugging purposes. + +config SND_HDA_RECONFIG + bool "Allow dynamic codec reconfiguration" + help + Say Y here to enable the HD-audio codec re-configuration feature. + It allows user to clear the whole codec configuration, change the + codec setup, add extra verbs, and re-configure the codec dynamically. + + Note that this item alone doesn't provide the sysfs interface, but + enables the feature just for the patch loader below. + If you need the traditional sysfs entries for the manual interaction, + turn on CONFIG_SND_HDA_HWDEP as well. + +config SND_HDA_INPUT_BEEP + bool "Support digital beep via input layer" + depends on INPUT=y || INPUT=SND_HDA + help + Say Y here to build a digital beep interface for HD-audio + driver. This interface is used to generate digital beeps. + +config SND_HDA_INPUT_BEEP_MODE + int "Digital beep registration mode (0=off, 1=on)" + depends on SND_HDA_INPUT_BEEP=y + default "1" + range 0 1 + help + Set 0 to disable the digital beep interface for HD-audio by default. + Set 1 to always enable the digital beep interface for HD-audio by + default. + +config SND_HDA_PATCH_LOADER + bool "Support initialization patch loading for HD-audio" + select FW_LOADER + select SND_HDA_RECONFIG + help + Say Y here to allow the HD-audio driver to load a pseudo + firmware file ("patch") for overriding the BIOS setup at + start up. The "patch" file can be specified via patch module + option, such as patch=hda-init. + +config SND_HDA_POWER_SAVE_DEFAULT + int "Default time-out for HD-audio power-save mode" + depends on PM + default 0 + help + The default time-out value in seconds for HD-audio automatic + power-save mode. 0 means to disable the power-save mode. + +config SND_HDA_CTL_DEV_ID + bool "Use the device identifier field for controls" + depends on SND_HDA_INTEL + help + Say Y to use the device identifier field for (mixer) + controls (old behaviour until this option is available). + + When enabled, the multiple HDA codecs may set the device + field in control (mixer) element identifiers. The use + of this field is not recommended and defined for mixer controls. + + The old behaviour (Y) is obsolete and will be removed. Consider + to not enable this option. +endif diff --git a/sound/hda/common/Makefile b/sound/hda/common/Makefile new file mode 100644 index 000000000000..3344fa0efe75 --- /dev/null +++ b/sound/hda/common/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0 +snd-hda-codec-y := bind.o codec.o jack.o auto_parser.o sysfs.o +snd-hda-codec-y += controller.o +snd-hda-codec-$(CONFIG_SND_PROC_FS) += proc.o + +snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hwdep.o +snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += beep.o + +# for trace-points +CFLAGS_controller.o := -I$(src) + +# common driver +obj-$(CONFIG_SND_HDA) := snd-hda-codec.o diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/hda/common/auto_parser.c similarity index 100% rename from sound/pci/hda/hda_auto_parser.c rename to sound/hda/common/auto_parser.c diff --git a/sound/pci/hda/hda_beep.c b/sound/hda/common/beep.c similarity index 100% rename from sound/pci/hda/hda_beep.c rename to sound/hda/common/beep.c diff --git a/sound/pci/hda/hda_bind.c b/sound/hda/common/bind.c similarity index 100% rename from sound/pci/hda/hda_bind.c rename to sound/hda/common/bind.c diff --git a/sound/pci/hda/hda_codec.c b/sound/hda/common/codec.c similarity index 100% rename from sound/pci/hda/hda_codec.c rename to sound/hda/common/codec.c diff --git a/sound/pci/hda/hda_controller.c b/sound/hda/common/controller.c similarity index 99% rename from sound/pci/hda/hda_controller.c rename to sound/hda/common/controller.c index f3330b7e0fcf..84387ed761be 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/hda/common/controller.c @@ -29,7 +29,7 @@ #include "hda_local.h" #define CREATE_TRACE_POINTS -#include "hda_controller_trace.h" +#include "controller_trace.h" /* DSP lock helpers */ #define dsp_lock(dev) snd_hdac_dsp_lock(azx_stream(dev)) diff --git a/sound/pci/hda/hda_controller_trace.h b/sound/hda/common/controller_trace.h similarity index 97% rename from sound/pci/hda/hda_controller_trace.h rename to sound/hda/common/controller_trace.h index bf48304e230a..7f5841f8919e 100644 --- a/sound/pci/hda/hda_controller_trace.h +++ b/sound/hda/common/controller_trace.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ #undef TRACE_SYSTEM #define TRACE_SYSTEM hda_controller -#define TRACE_INCLUDE_FILE hda_controller_trace +#define TRACE_INCLUDE_FILE controller_trace #if !defined(_TRACE_HDA_CONTROLLER_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HDA_CONTROLLER_H diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/hda/common/hda_auto_parser.h similarity index 100% rename from sound/pci/hda/hda_auto_parser.h rename to sound/hda/common/hda_auto_parser.h diff --git a/sound/pci/hda/hda_beep.h b/sound/hda/common/hda_beep.h similarity index 100% rename from sound/pci/hda/hda_beep.h rename to sound/hda/common/hda_beep.h diff --git a/sound/pci/hda/hda_controller.h b/sound/hda/common/hda_controller.h similarity index 100% rename from sound/pci/hda/hda_controller.h rename to sound/hda/common/hda_controller.h diff --git a/sound/pci/hda/hda_jack.h b/sound/hda/common/hda_jack.h similarity index 100% rename from sound/pci/hda/hda_jack.h rename to sound/hda/common/hda_jack.h diff --git a/sound/pci/hda/hda_local.h b/sound/hda/common/hda_local.h similarity index 100% rename from sound/pci/hda/hda_local.h rename to sound/hda/common/hda_local.h diff --git a/sound/pci/hda/hda_hwdep.c b/sound/hda/common/hwdep.c similarity index 100% rename from sound/pci/hda/hda_hwdep.c rename to sound/hda/common/hwdep.c diff --git a/sound/pci/hda/hda_jack.c b/sound/hda/common/jack.c similarity index 100% rename from sound/pci/hda/hda_jack.c rename to sound/hda/common/jack.c diff --git a/sound/pci/hda/hda_proc.c b/sound/hda/common/proc.c similarity index 100% rename from sound/pci/hda/hda_proc.c rename to sound/hda/common/proc.c diff --git a/sound/pci/hda/hda_sysfs.c b/sound/hda/common/sysfs.c similarity index 100% rename from sound/pci/hda/hda_sysfs.c rename to sound/hda/common/sysfs.c diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 745f120a5cee..1dfd56493d39 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -1,13 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only menu "HD-Audio" -config SND_HDA - tristate - select SND_PCM - select SND_VMASTER - select SND_JACK - select SND_HDA_CORE - config SND_HDA_GENERIC_LEDS bool @@ -55,53 +48,6 @@ config SND_HDA_ACPI if SND_HDA -config SND_HDA_HWDEP - bool "Build hwdep interface for HD-audio driver" - select SND_HWDEP - help - Say Y here to build a hwdep interface for HD-audio driver. - This interface can be used for out-of-band communication - with codecs for debugging purposes. - -config SND_HDA_RECONFIG - bool "Allow dynamic codec reconfiguration" - help - Say Y here to enable the HD-audio codec re-configuration feature. - It allows user to clear the whole codec configuration, change the - codec setup, add extra verbs, and re-configure the codec dynamically. - - Note that this item alone doesn't provide the sysfs interface, but - enables the feature just for the patch loader below. - If you need the traditional sysfs entries for the manual interaction, - turn on CONFIG_SND_HDA_HWDEP as well. - -config SND_HDA_INPUT_BEEP - bool "Support digital beep via input layer" - depends on INPUT=y || INPUT=SND_HDA - help - Say Y here to build a digital beep interface for HD-audio - driver. This interface is used to generate digital beeps. - -config SND_HDA_INPUT_BEEP_MODE - int "Digital beep registration mode (0=off, 1=on)" - depends on SND_HDA_INPUT_BEEP=y - default "1" - range 0 1 - help - Set 0 to disable the digital beep interface for HD-audio by default. - Set 1 to always enable the digital beep interface for HD-audio by - default. - -config SND_HDA_PATCH_LOADER - bool "Support initialization patch loading for HD-audio" - select FW_LOADER - select SND_HDA_RECONFIG - help - Say Y here to allow the HD-audio driver to load a pseudo - firmware file ("patch") for overriding the BIOS setup at - start up. The "patch" file can be specified via patch module - option, such as patch=hda-init. - config SND_HDA_CIRRUS_SCODEC tristate @@ -394,14 +340,6 @@ config SND_HDA_GENERIC comment "Set to Y if you want auto-loading the codec driver" depends on SND_HDA=y && SND_HDA_GENERIC=m -config SND_HDA_POWER_SAVE_DEFAULT - int "Default time-out for HD-audio power-save mode" - depends on PM - default 0 - help - The default time-out value in seconds for HD-audio automatic - power-save mode. 0 means to disable the power-save mode. - config SND_HDA_INTEL_HDMI_SILENT_STREAM bool "Enable Silent Stream always for HDMI" depends on SND_HDA_INTEL @@ -417,20 +355,6 @@ config SND_HDA_INTEL_HDMI_SILENT_STREAM This feature can impact power consumption as resources are kept reserved both at transmitter and receiver. -config SND_HDA_CTL_DEV_ID - bool "Use the device identifier field for controls" - depends on SND_HDA_INTEL - help - Say Y to use the device identifier field for (mixer) - controls (old behaviour until this option is available). - - When enabled, the multiple HDA codecs may set the device - field in control (mixer) element identifiers. The use - of this field is not recommended and defined for mixer controls. - - The old behaviour (Y) is obsolete and will be removed. Consider - to not enable this option. - endif endmenu diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index a5ab8ee2d7f9..920011bb1b06 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -3,17 +3,11 @@ snd-hda-intel-y := hda_intel.o snd-hda-tegra-y := hda_tegra.o snd-hda-acpi-y := hda_acpi.o -snd-hda-codec-y := hda_bind.o hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o -snd-hda-codec-y += hda_controller.o -snd-hda-codec-$(CONFIG_SND_PROC_FS) += hda_proc.o - -snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o -snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o - # for trace-points -CFLAGS_hda_controller.o := -I$(src) CFLAGS_hda_intel.o := -I$(src) +subdir-ccflags-y += -I$(src)/../../hda/common + snd-hda-codec-generic-y := hda_generic.o snd-hda-codec-realtek-y := patch_realtek.o snd-hda-codec-cmedia-y := patch_cmedia.o @@ -43,9 +37,6 @@ snd-hda-scodec-tas2781-y := tas2781_hda.o snd-hda-scodec-tas2781-i2c-y := tas2781_hda_i2c.o snd-hda-scodec-tas2781-spi-y := tas2781_hda_spi.o -# common driver -obj-$(CONFIG_SND_HDA) := snd-hda-codec.o - # codec drivers obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o obj-$(CONFIG_SND_HDA_CODEC_REALTEK) += snd-hda-codec-realtek.o From 146355ee880e6d15ba12e2baf5be70e5efe07796 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:07 +0200 Subject: [PATCH 320/385] ALSA: hda: Move CONFIG_SND_HDA_PREALLOC_SIZE into sound/hda/common CONFIG_SND_HDA_PREALLOC_SIZE is used only by controller.c in sound/hda/common, hence it depends on CONFIG_SND_HDA. Move the definition to the right place inside SND_HDA if/endif block in sound/hda/common/Kconfig. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-5-tiwai@suse.de --- sound/hda/common/Kconfig | 17 +++++++++++++++++ sound/hda/core/Kconfig | 16 ---------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/sound/hda/common/Kconfig b/sound/hda/common/Kconfig index d1e2bfd24c11..f38e1947fb3e 100644 --- a/sound/hda/common/Kconfig +++ b/sound/hda/common/Kconfig @@ -77,4 +77,21 @@ config SND_HDA_CTL_DEV_ID The old behaviour (Y) is obsolete and will be removed. Consider to not enable this option. + +config SND_HDA_PREALLOC_SIZE + int "Pre-allocated buffer size for HD-audio driver" + range 0 32768 + default 0 if SND_DMA_SGBUF + default 64 if !SND_DMA_SGBUF + help + Specifies the default pre-allocated buffer-size in kB for the + HD-audio driver. A larger buffer (e.g. 2048) is preferred + for systems using PulseAudio. The default 64 is chosen just + for compatibility reasons. + On x86 systems, the default is zero as S/G allocation works + and no preallocation is needed in most cases. + + Note that the pre-allocation size can be changed dynamically + via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too. + endif diff --git a/sound/hda/core/Kconfig b/sound/hda/core/Kconfig index eb488a522572..bfdcf6384c52 100644 --- a/sound/hda/core/Kconfig +++ b/sound/hda/core/Kconfig @@ -20,22 +20,6 @@ config SND_HDA_EXT_CORE tristate select SND_HDA_CORE -config SND_HDA_PREALLOC_SIZE - int "Pre-allocated buffer size for HD-audio driver" - range 0 32768 - default 0 if SND_DMA_SGBUF - default 64 if !SND_DMA_SGBUF - help - Specifies the default pre-allocated buffer-size in kB for the - HD-audio driver. A larger buffer (e.g. 2048) is preferred - for systems using PulseAudio. The default 64 is chosen just - for compatibility reasons. - On x86 systems, the default is zero as S/G allocation works - and no preallocation is needed in most cases. - - Note that the pre-allocation size can be changed dynamically - via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too. - config SND_INTEL_NHLT bool # this config should be selected only for Intel ACPI platforms. From 2d9223d2d64cb5216859ced6cc33fb3b04e5f98f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:08 +0200 Subject: [PATCH 321/385] ALSA: hda: Move controller drivers into sound/hda/controllers directory Now HD-audio controller drivers are moved into sound/hda/controllers directory as a part of HD-audio code reorganization. Most of drivers are independent from PCI bus, hence it makes more sense to put under sound/hda. The hda_ prefix is dropped from most of files at moving, as it's more or less superfluous. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-6-tiwai@suse.de --- sound/hda/Kconfig | 1 + sound/hda/Makefile | 4 ++ sound/hda/controllers/Kconfig | 42 +++++++++++++++++++ sound/hda/controllers/Makefile | 13 ++++++ .../hda/hda_acpi.c => hda/controllers/acpi.c} | 0 .../hda_intel.c => hda/controllers/intel.c} | 5 +-- .../hda_intel.h => hda/controllers/intel.h} | 0 .../controllers/intel_trace.h} | 2 +- .../hda_tegra.c => hda/controllers/tegra.c} | 0 sound/pci/hda/Kconfig | 42 ------------------- sound/pci/hda/Makefile | 14 ------- 11 files changed, 63 insertions(+), 60 deletions(-) create mode 100644 sound/hda/controllers/Kconfig create mode 100644 sound/hda/controllers/Makefile rename sound/{pci/hda/hda_acpi.c => hda/controllers/acpi.c} (100%) rename sound/{pci/hda/hda_intel.c => hda/controllers/intel.c} (99%) rename sound/{pci/hda/hda_intel.h => hda/controllers/intel.h} (100%) rename sound/{pci/hda/hda_intel_trace.h => hda/controllers/intel_trace.h} (95%) rename sound/{pci/hda/hda_tegra.c => hda/controllers/tegra.c} (100%) diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig index 2928cb570ec6..d360c884bd6d 100644 --- a/sound/hda/Kconfig +++ b/sound/hda/Kconfig @@ -2,6 +2,7 @@ menu "HD-Audio" source "sound/hda/common/Kconfig" +source "sound/hda/controllers/Kconfig" source "sound/hda/core/Kconfig" endmenu diff --git a/sound/hda/Makefile b/sound/hda/Makefile index e7596bf736a4..fc76086a1f5e 100644 --- a/sound/hda/Makefile +++ b/sound/hda/Makefile @@ -1,3 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-y += core/ obj-$(CONFIG_SND_HDA) += common/ +# this must be the last entry after codec drivers; +# otherwise the codec patches won't be hooked before the PCI probe +# when built in kernel +obj-$(CONFIG_SND_HDA) += controllers/ diff --git a/sound/hda/controllers/Kconfig b/sound/hda/controllers/Kconfig new file mode 100644 index 000000000000..34721f50b055 --- /dev/null +++ b/sound/hda/controllers/Kconfig @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0-only +config SND_HDA_INTEL + tristate "HD Audio PCI" + depends on SND_PCI + select SND_HDA + select SND_INTEL_DSP_CONFIG + help + Say Y here to include support for Intel "High Definition + Audio" (Azalia) and its compatible devices. + + This option enables the HD-audio controller. Don't forget + to choose the appropriate HD-audio codec options. + + To compile this driver as a module, choose M here: the module + will be called snd-hda-intel. + +config SND_HDA_TEGRA + tristate "NVIDIA Tegra HD Audio" + depends on ARCH_TEGRA + select SND_HDA + select SND_HDA_ALIGNED_MMIO + help + Say Y here to support the HDA controller present in NVIDIA + Tegra SoCs + + This options enables support for the HD Audio controller + present in some NVIDIA Tegra SoCs, used to communicate audio + to the HDMI output. + + To compile this driver as a module, choose M here: the module + will be called snd-hda-tegra. + +config SND_HDA_ACPI + tristate "HD Audio ACPI" + depends on ACPI + select SND_HDA + help + Say Y here to include support for Azalia-compatible HDA controllers + which are advertised via ACPI objects. + + To compile this driver as a module, choose M here: the module + will be called snd-hda-acpi. diff --git a/sound/hda/controllers/Makefile b/sound/hda/controllers/Makefile new file mode 100644 index 000000000000..a4bcd055e9ae --- /dev/null +++ b/sound/hda/controllers/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0 +snd-hda-intel-y := intel.o +snd-hda-tegra-y := tegra.o +snd-hda-acpi-y := acpi.o + +subdir-ccflags-y += -I$(src)/../common + +# for trace-points +CFLAGS_intel.o := -I$(src) + +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o +obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o +obj-$(CONFIG_SND_HDA_ACPI) += snd-hda-acpi.o diff --git a/sound/pci/hda/hda_acpi.c b/sound/hda/controllers/acpi.c similarity index 100% rename from sound/pci/hda/hda_acpi.c rename to sound/hda/controllers/acpi.c diff --git a/sound/pci/hda/hda_intel.c b/sound/hda/controllers/intel.c similarity index 99% rename from sound/pci/hda/hda_intel.c rename to sound/hda/controllers/intel.c index 439cf1bda6e6..ebfc999156f4 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/hda/controllers/intel.c @@ -54,11 +54,10 @@ #include #include #include -#include "hda_controller.h" -#include "hda_intel.h" +#include "intel.h" #define CREATE_TRACE_POINTS -#include "hda_intel_trace.h" +#include "intel_trace.h" /* position fix mode */ enum { diff --git a/sound/pci/hda/hda_intel.h b/sound/hda/controllers/intel.h similarity index 100% rename from sound/pci/hda/hda_intel.h rename to sound/hda/controllers/intel.h diff --git a/sound/pci/hda/hda_intel_trace.h b/sound/hda/controllers/intel_trace.h similarity index 95% rename from sound/pci/hda/hda_intel_trace.h rename to sound/hda/controllers/intel_trace.h index 2775fa81a500..fb10ab9e7e55 100644 --- a/sound/pci/hda/hda_intel_trace.h +++ b/sound/hda/controllers/intel_trace.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ #undef TRACE_SYSTEM #define TRACE_SYSTEM hda_intel -#define TRACE_INCLUDE_FILE hda_intel_trace +#define TRACE_INCLUDE_FILE intel_trace #if !defined(_TRACE_HDA_INTEL_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HDA_INTEL_H diff --git a/sound/pci/hda/hda_tegra.c b/sound/hda/controllers/tegra.c similarity index 100% rename from sound/pci/hda/hda_tegra.c rename to sound/hda/controllers/tegra.c diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 1dfd56493d39..a5d345514cf3 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -4,48 +4,6 @@ menu "HD-Audio" config SND_HDA_GENERIC_LEDS bool -config SND_HDA_INTEL - tristate "HD Audio PCI" - depends on SND_PCI - select SND_HDA - select SND_INTEL_DSP_CONFIG - help - Say Y here to include support for Intel "High Definition - Audio" (Azalia) and its compatible devices. - - This option enables the HD-audio controller. Don't forget - to choose the appropriate codec options below. - - To compile this driver as a module, choose M here: the module - will be called snd-hda-intel. - -config SND_HDA_TEGRA - tristate "NVIDIA Tegra HD Audio" - depends on ARCH_TEGRA - select SND_HDA - select SND_HDA_ALIGNED_MMIO - help - Say Y here to support the HDA controller present in NVIDIA - Tegra SoCs - - This options enables support for the HD Audio controller - present in some NVIDIA Tegra SoCs, used to communicate audio - to the HDMI output. - - To compile this driver as a module, choose M here: the module - will be called snd-hda-tegra. - -config SND_HDA_ACPI - tristate "HD Audio ACPI" - depends on ACPI - select SND_HDA - help - Say Y here to include support for Azalia-compatible HDA controllers - which are advertised via ACPI objects. - - To compile this driver as a module, choose M here: the module - will be called snd-hda-acpi. - if SND_HDA config SND_HDA_CIRRUS_SCODEC diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 920011bb1b06..79de0af71ad4 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,11 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -snd-hda-intel-y := hda_intel.o -snd-hda-tegra-y := hda_tegra.o -snd-hda-acpi-y := hda_acpi.o - -# for trace-points -CFLAGS_hda_intel.o := -I$(src) - subdir-ccflags-y += -I$(src)/../../hda/common snd-hda-codec-generic-y := hda_generic.o @@ -66,10 +59,3 @@ obj-$(CONFIG_SND_HDA_SCODEC_COMPONENT) += snd-hda-scodec-component.o obj-$(CONFIG_SND_HDA_SCODEC_TAS2781) += snd-hda-scodec-tas2781.o obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_I2C) += snd-hda-scodec-tas2781-i2c.o obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o - -# this must be the last entry after codec drivers; -# otherwise the codec patches won't be hooked before the PCI probe -# when built in kernel -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o -obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o -obj-$(CONFIG_SND_HDA_ACPI) += snd-hda-acpi.o From 6014e9021b28e634935c776c0271b5cbcabdc5d6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:09 +0200 Subject: [PATCH 322/385] ALSA: hda: Move codec drivers into sound/hda/codecs directory Now move the all remaining codec drivers from sound/pci/hda to sound/hda/codecs subdirectory. Some drivers are put under the further vendor subdirectory, and the vendor helper code (*_helper.c) are put under helpers subdirectory. Also the sub-codec drivers are moved under a different subdirectory, sound/hda/codecs/sub-codecs, for distinguishing from the main HD-audio codec drivers. The prefix patch_ and hda_ as well as the suffix _helper are dropped from file names as they are mostly superfluous. No functional changes but just file path shuffling. Reviewed-by: Richard Fitzgerald Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-7-tiwai@suse.de --- sound/hda/Kconfig | 1 + sound/hda/Makefile | 1 + sound/{pci/hda => hda/codecs}/Kconfig | 158 +----------------- sound/hda/codecs/Makefile | 31 ++++ .../patch_analog.c => hda/codecs/analog.c} | 2 +- .../patch_ca0110.c => hda/codecs/ca0110.c} | 2 +- .../patch_ca0132.c => hda/codecs/ca0132.c} | 2 +- sound/{pci/hda => hda/codecs}/ca0132_regs.h | 0 sound/hda/codecs/cirrus/Kconfig | 21 +++ sound/hda/codecs/cirrus/Makefile | 8 + .../codecs/cirrus/cirrus.c} | 2 +- .../codecs/cirrus/cs8409-tables.c} | 4 +- .../codecs/cirrus/cs8409.c} | 2 +- .../codecs/cirrus/cs8409.h} | 2 +- .../patch_cmedia.c => hda/codecs/cmedia.c} | 2 +- .../codecs/conexant.c} | 6 +- .../hda_generic.c => hda/codecs/generic.c} | 2 +- .../hda_generic.h => hda/codecs/generic.h} | 0 sound/hda/codecs/hdmi/Makefile | 6 + .../hda/hda_eld.c => hda/codecs/hdmi/eld.c} | 0 .../patch_hdmi.c => hda/codecs/hdmi/hdmi.c} | 2 +- .../codecs/helpers/hp_x360.c} | 0 .../codecs/helpers/ideapad_hotkey_led.c} | 0 .../codecs/helpers/ideapad_s740.c} | 0 .../codecs/helpers/thinkpad.c} | 0 .../patch_realtek.c => hda/codecs/realtek.c} | 12 +- .../codecs/senarytech.c} | 4 +- .../patch_si3054.c => hda/codecs/si3054.c} | 0 sound/hda/codecs/side-codecs/Kconfig | 128 ++++++++++++++ sound/hda/codecs/side-codecs/Makefile | 28 ++++ .../codecs/side-codecs}/cirrus_scodec.c | 0 .../codecs/side-codecs}/cirrus_scodec.h | 0 .../codecs/side-codecs}/cirrus_scodec_test.c | 0 .../codecs/side-codecs}/cs35l41_hda.c | 2 +- .../codecs/side-codecs}/cs35l41_hda.h | 0 .../codecs/side-codecs}/cs35l41_hda_i2c.c | 0 .../side-codecs}/cs35l41_hda_property.c | 0 .../side-codecs}/cs35l41_hda_property.h | 0 .../codecs/side-codecs}/cs35l41_hda_spi.c | 0 .../codecs/side-codecs}/cs35l56_hda.c | 2 +- .../codecs/side-codecs}/cs35l56_hda.h | 0 .../codecs/side-codecs}/cs35l56_hda_i2c.c | 0 .../codecs/side-codecs}/cs35l56_hda_spi.c | 0 .../codecs/side-codecs}/hda_component.c | 0 .../codecs/side-codecs}/hda_component.h | 0 .../codecs/side-codecs}/tas2781_hda.c | 0 .../codecs/side-codecs}/tas2781_hda.h | 0 .../codecs/side-codecs}/tas2781_hda_i2c.c | 2 +- .../codecs/side-codecs}/tas2781_hda_spi.c | 2 +- .../codecs/sigmatel.c} | 4 +- .../{pci/hda/patch_via.c => hda/codecs/via.c} | 2 +- sound/pci/Kconfig | 2 - sound/pci/Makefile | 1 - sound/pci/hda/Makefile | 61 ------- 54 files changed, 257 insertions(+), 247 deletions(-) rename sound/{pci/hda => hda/codecs}/Kconfig (55%) create mode 100644 sound/hda/codecs/Makefile rename sound/{pci/hda/patch_analog.c => hda/codecs/analog.c} (99%) rename sound/{pci/hda/patch_ca0110.c => hda/codecs/ca0110.c} (98%) rename sound/{pci/hda/patch_ca0132.c => hda/codecs/ca0132.c} (99%) rename sound/{pci/hda => hda/codecs}/ca0132_regs.h (100%) create mode 100644 sound/hda/codecs/cirrus/Kconfig create mode 100644 sound/hda/codecs/cirrus/Makefile rename sound/{pci/hda/patch_cirrus.c => hda/codecs/cirrus/cirrus.c} (99%) rename sound/{pci/hda/patch_cs8409-tables.c => hda/codecs/cirrus/cs8409-tables.c} (99%) rename sound/{pci/hda/patch_cs8409.c => hda/codecs/cirrus/cs8409.c} (99%) rename sound/{pci/hda/patch_cs8409.h => hda/codecs/cirrus/cs8409.h} (99%) rename sound/{pci/hda/patch_cmedia.c => hda/codecs/cmedia.c} (99%) rename sound/{pci/hda/patch_conexant.c => hda/codecs/conexant.c} (99%) rename sound/{pci/hda/hda_generic.c => hda/codecs/generic.c} (99%) rename sound/{pci/hda/hda_generic.h => hda/codecs/generic.h} (100%) create mode 100644 sound/hda/codecs/hdmi/Makefile rename sound/{pci/hda/hda_eld.c => hda/codecs/hdmi/eld.c} (100%) rename sound/{pci/hda/patch_hdmi.c => hda/codecs/hdmi/hdmi.c} (99%) rename sound/{pci/hda/hp_x360_helper.c => hda/codecs/helpers/hp_x360.c} (100%) rename sound/{pci/hda/ideapad_hotkey_led_helper.c => hda/codecs/helpers/ideapad_hotkey_led.c} (100%) rename sound/{pci/hda/ideapad_s740_helper.c => hda/codecs/helpers/ideapad_s740.c} (100%) rename sound/{pci/hda/thinkpad_helper.c => hda/codecs/helpers/thinkpad.c} (100%) rename sound/{pci/hda/patch_realtek.c => hda/codecs/realtek.c} (99%) rename sound/{pci/hda/patch_senarytech.c => hda/codecs/senarytech.c} (98%) rename sound/{pci/hda/patch_si3054.c => hda/codecs/si3054.c} (100%) create mode 100644 sound/hda/codecs/side-codecs/Kconfig create mode 100644 sound/hda/codecs/side-codecs/Makefile rename sound/{pci/hda => hda/codecs/side-codecs}/cirrus_scodec.c (100%) rename sound/{pci/hda => hda/codecs/side-codecs}/cirrus_scodec.h (100%) rename sound/{pci/hda => hda/codecs/side-codecs}/cirrus_scodec_test.c (100%) rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda.c (99%) rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda.h (100%) rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_i2c.c (100%) rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_property.c (100%) rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_property.h (100%) rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_spi.c (100%) rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda.c (99%) rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda.h (100%) rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda_i2c.c (100%) rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda_spi.c (100%) rename sound/{pci/hda => hda/codecs/side-codecs}/hda_component.c (100%) rename sound/{pci/hda => hda/codecs/side-codecs}/hda_component.h (100%) rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda.c (100%) rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda.h (100%) rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda_i2c.c (99%) rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda_spi.c (99%) rename sound/{pci/hda/patch_sigmatel.c => hda/codecs/sigmatel.c} (99%) rename sound/{pci/hda/patch_via.c => hda/codecs/via.c} (99%) delete mode 100644 sound/pci/hda/Makefile diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig index d360c884bd6d..7797f44b3d0c 100644 --- a/sound/hda/Kconfig +++ b/sound/hda/Kconfig @@ -3,6 +3,7 @@ menu "HD-Audio" source "sound/hda/common/Kconfig" source "sound/hda/controllers/Kconfig" +source "sound/hda/codecs/Kconfig" source "sound/hda/core/Kconfig" endmenu diff --git a/sound/hda/Makefile b/sound/hda/Makefile index fc76086a1f5e..31b9fbedaa77 100644 --- a/sound/hda/Makefile +++ b/sound/hda/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-y += core/ obj-$(CONFIG_SND_HDA) += common/ +obj-$(CONFIG_SND_HDA) += codecs/ # this must be the last entry after codec drivers; # otherwise the codec patches won't be hooked before the PCI probe # when built in kernel diff --git a/sound/pci/hda/Kconfig b/sound/hda/codecs/Kconfig similarity index 55% rename from sound/pci/hda/Kconfig rename to sound/hda/codecs/Kconfig index a5d345514cf3..bac19a664be0 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/hda/codecs/Kconfig @@ -1,140 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-only -menu "HD-Audio" +if SND_HDA config SND_HDA_GENERIC_LEDS bool -if SND_HDA - -config SND_HDA_CIRRUS_SCODEC - tristate - -config SND_HDA_CIRRUS_SCODEC_KUNIT_TEST - tristate "KUnit test for Cirrus side-codec library" if !KUNIT_ALL_TESTS - depends on SND_HDA_CIRRUS_SCODEC && GPIOLIB && KUNIT - default KUNIT_ALL_TESTS - help - This builds KUnit tests for the cirrus side-codec library. - For more information on KUnit and unit tests in general, - please refer to the KUnit documentation in - Documentation/dev-tools/kunit/. - If in doubt, say "N". - -config SND_HDA_SCODEC_CS35L41 - tristate - select SND_HDA_GENERIC - select REGMAP_IRQ - select FW_CS_DSP - -config SND_HDA_SCODEC_COMPONENT - tristate - -config SND_HDA_SCODEC_CS35L41_I2C - tristate "Build CS35L41 HD-audio side codec support for I2C Bus" - depends on I2C - depends on ACPI - depends on EFI - depends on SND_SOC - select SND_SOC_CS35L41_LIB - select SND_HDA_SCODEC_CS35L41 - select SND_SOC_CS_AMP_LIB - help - Say Y or M here to include CS35L41 I2C HD-audio side codec support - in snd-hda-intel driver, such as ALC287. - -comment "Set to Y if you want auto-loading the side codec driver" - depends on SND_HDA=y && SND_HDA_SCODEC_CS35L41_I2C=m - -config SND_HDA_SCODEC_CS35L41_SPI - tristate "Build CS35L41 HD-audio codec support for SPI Bus" - depends on SPI_MASTER - depends on ACPI - depends on EFI - depends on SND_SOC - select SND_SOC_CS35L41_LIB - select SND_HDA_SCODEC_CS35L41 - select SND_SOC_CS_AMP_LIB - help - Say Y or M here to include CS35L41 SPI HD-audio side codec support - in snd-hda-intel driver, such as ALC287. - -comment "Set to Y if you want auto-loading the side codec driver" - depends on SND_HDA=y && SND_HDA_SCODEC_CS35L41_SPI=m - -config SND_HDA_SCODEC_CS35L56 - tristate - -config SND_HDA_SCODEC_CS35L56_I2C - tristate "Build CS35L56 HD-audio side codec support for I2C Bus" - depends on I2C - depends on ACPI - depends on SND_SOC - select FW_CS_DSP - imply SERIAL_MULTI_INSTANTIATE - select SND_HDA_GENERIC - select SND_SOC_CS35L56_SHARED - select SND_HDA_SCODEC_CS35L56 - select SND_HDA_CIRRUS_SCODEC - select SND_SOC_CS_AMP_LIB - help - Say Y or M here to include CS35L56 amplifier support with - I2C control. - -config SND_HDA_SCODEC_CS35L56_SPI - tristate "Build CS35L56 HD-audio side codec support for SPI Bus" - depends on SPI_MASTER - depends on ACPI - depends on SND_SOC - select FW_CS_DSP - imply SERIAL_MULTI_INSTANTIATE - select SND_HDA_GENERIC - select SND_SOC_CS35L56_SHARED - select SND_HDA_SCODEC_CS35L56 - select SND_HDA_CIRRUS_SCODEC - select SND_SOC_CS_AMP_LIB - help - Say Y or M here to include CS35L56 amplifier support with - SPI control. - -config SND_HDA_SCODEC_TAS2781 - tristate - select SND_HDA_GENERIC - -config SND_HDA_SCODEC_TAS2781_I2C - tristate "Build TAS2781 HD-audio side codec support for I2C Bus" - depends on I2C - depends on ACPI - depends on EFI - depends on SND_SOC - select SND_HDA_SCODEC_TAS2781 - select SND_SOC_TAS2781_COMLIB_I2C - select SND_SOC_TAS2781_FMWLIB - select CRC32 - help - Say Y or M here to include TAS2781 I2C HD-audio side codec support - in snd-hda-intel driver, such as ALC287. - -comment "Set to Y if you want auto-loading the side codec driver" - depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_I2C=m - -config SND_HDA_SCODEC_TAS2781_SPI - tristate "Build TAS2781 HD-audio side codec support for SPI Bus" - depends on SPI_MASTER - depends on ACPI - depends on EFI - depends on SND_SOC - select SND_HDA_SCODEC_TAS2781 - select SND_SOC_TAS2781_COMLIB - select SND_SOC_TAS2781_FMWLIB - select CRC8 - select CRC32 - help - Say Y or M here to include TAS2781 SPI HD-audio side codec support - in snd-hda-intel driver, such as ALC287. - -comment "Set to Y if you want auto-loading the side codec driver" - depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_SPI=m - config SND_HDA_CODEC_REALTEK tristate "Build Realtek HD-audio codec support" depends on INPUT @@ -194,26 +63,6 @@ config SND_HDA_CODEC_HDMI comment "Set to Y if you want auto-loading the codec driver" depends on SND_HDA=y && SND_HDA_CODEC_HDMI=m -config SND_HDA_CODEC_CIRRUS - tristate "Build Cirrus Logic codec support" - select SND_HDA_GENERIC - help - Say Y or M here to include Cirrus Logic codec support in - snd-hda-intel driver, such as CS4206. - -comment "Set to Y if you want auto-loading the codec driver" - depends on SND_HDA=y && SND_HDA_CODEC_CIRRUS=m - -config SND_HDA_CODEC_CS8409 - tristate "Build Cirrus Logic HDA bridge support" - select SND_HDA_GENERIC - help - Say Y or M here to include Cirrus Logic HDA bridge support in - snd-hda-intel driver, such as CS8409. - -comment "Set to Y if you want auto-loading the codec driver" - depends on SND_HDA=y && SND_HDA_CODEC_CS8409=m - config SND_HDA_CODEC_CONEXANT tristate "Build Conexant HD-audio codec support" select SND_HDA_GENERIC @@ -313,6 +162,7 @@ config SND_HDA_INTEL_HDMI_SILENT_STREAM This feature can impact power consumption as resources are kept reserved both at transmitter and receiver. -endif +source "sound/hda/codecs/cirrus/Kconfig" +source "sound/hda/codecs/side-codecs/Kconfig" -endmenu +endif # SND_HDA diff --git a/sound/hda/codecs/Makefile b/sound/hda/codecs/Makefile new file mode 100644 index 000000000000..205cd1373b42 --- /dev/null +++ b/sound/hda/codecs/Makefile @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0 +subdir-ccflags-y += -I$(src)/../common + +snd-hda-codec-generic-y := generic.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 += side-codecs/ + +# codec drivers +obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.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 diff --git a/sound/pci/hda/patch_analog.c b/sound/hda/codecs/analog.c similarity index 99% rename from sound/pci/hda/patch_analog.c rename to sound/hda/codecs/analog.c index 56354fe060a1..3557e06c6d2b 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/hda/codecs/analog.c @@ -16,7 +16,7 @@ #include "hda_auto_parser.h" #include "hda_beep.h" #include "hda_jack.h" -#include "hda_generic.h" +#include "generic.h" struct ad198x_spec { diff --git a/sound/pci/hda/patch_ca0110.c b/sound/hda/codecs/ca0110.c similarity index 98% rename from sound/pci/hda/patch_ca0110.c rename to sound/hda/codecs/ca0110.c index 1818ce67f761..0353544435b9 100644 --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/hda/codecs/ca0110.c @@ -13,7 +13,7 @@ #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" -#include "hda_generic.h" +#include "generic.h" static const struct hda_codec_ops ca0110_patch_ops = { diff --git a/sound/pci/hda/patch_ca0132.c b/sound/hda/codecs/ca0132.c similarity index 99% rename from sound/pci/hda/patch_ca0132.c rename to sound/hda/codecs/ca0132.c index 686ce0947131..35a979465c75 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/hda/codecs/ca0132.c @@ -4,7 +4,7 @@ * * Copyright (c) 2011, Creative Technology Ltd. * - * Based on patch_ca0110.c + * Based on ca0110.c * Copyright (c) 2008 Takashi Iwai */ diff --git a/sound/pci/hda/ca0132_regs.h b/sound/hda/codecs/ca0132_regs.h similarity index 100% rename from sound/pci/hda/ca0132_regs.h rename to sound/hda/codecs/ca0132_regs.h diff --git a/sound/hda/codecs/cirrus/Kconfig b/sound/hda/codecs/cirrus/Kconfig new file mode 100644 index 000000000000..f6cefb65c5f8 --- /dev/null +++ b/sound/hda/codecs/cirrus/Kconfig @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config SND_HDA_CODEC_CIRRUS + tristate "Build Cirrus Logic codec support" + select SND_HDA_GENERIC + help + Say Y or M here to include Cirrus Logic codec support in + snd-hda-intel driver, such as CS4206. + +comment "Set to Y if you want auto-loading the codec driver" + depends on SND_HDA=y && SND_HDA_CODEC_CIRRUS=m + +config SND_HDA_CODEC_CS8409 + tristate "Build Cirrus Logic HDA bridge support" + select SND_HDA_GENERIC + help + Say Y or M here to include Cirrus Logic HDA bridge support in + snd-hda-intel driver, such as CS8409. + +comment "Set to Y if you want auto-loading the codec driver" + depends on SND_HDA=y && SND_HDA_CODEC_CS8409=m diff --git a/sound/hda/codecs/cirrus/Makefile b/sound/hda/codecs/cirrus/Makefile new file mode 100644 index 000000000000..fa40c893fb09 --- /dev/null +++ b/sound/hda/codecs/cirrus/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +subdir-ccflags-y += -I$(src)/../../common + +snd-hda-codec-cirrus-y := cirrus.o +snd-hda-codec-cs8409-y := cs8409.o cs8409-tables.o + +obj-$(CONFIG_SND_HDA_CODEC_CIRRUS) += snd-hda-codec-cirrus.o +obj-$(CONFIG_SND_HDA_CODEC_CS8409) += snd-hda-codec-cs8409.o diff --git a/sound/pci/hda/patch_cirrus.c b/sound/hda/codecs/cirrus/cirrus.c similarity index 99% rename from sound/pci/hda/patch_cirrus.c rename to sound/hda/codecs/cirrus/cirrus.c index 06e046214a41..81ea66c4e9d3 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/hda/codecs/cirrus/cirrus.c @@ -15,7 +15,7 @@ #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" -#include "hda_generic.h" +#include "../generic.h" /* */ diff --git a/sound/pci/hda/patch_cs8409-tables.c b/sound/hda/codecs/cirrus/cs8409-tables.c similarity index 99% rename from sound/pci/hda/patch_cs8409-tables.c rename to sound/hda/codecs/cirrus/cs8409-tables.c index 09240138e087..5fe49f13c0da 100644 --- a/sound/pci/hda/patch_cs8409-tables.c +++ b/sound/hda/codecs/cirrus/cs8409-tables.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * patch_cs8409-tables.c -- HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip + * cs8409-tables.c -- HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip * * Copyright (C) 2021 Cirrus Logic, Inc. and * Cirrus Logic International Semiconductor Ltd. @@ -8,7 +8,7 @@ * Author: Lucas Tanure */ -#include "patch_cs8409.h" +#include "cs8409.h" /****************************************************************************** * CS42L42 Specific Data diff --git a/sound/pci/hda/patch_cs8409.c b/sound/hda/codecs/cirrus/cs8409.c similarity index 99% rename from sound/pci/hda/patch_cs8409.c rename to sound/hda/codecs/cirrus/cs8409.c index e50006757a2c..5ec1126b2a55 100644 --- a/sound/pci/hda/patch_cs8409.c +++ b/sound/hda/codecs/cirrus/cs8409.c @@ -13,7 +13,7 @@ #include #include -#include "patch_cs8409.h" +#include "cs8409.h" /****************************************************************************** * CS8409 Specific Functions diff --git a/sound/pci/hda/patch_cs8409.h b/sound/hda/codecs/cirrus/cs8409.h similarity index 99% rename from sound/pci/hda/patch_cs8409.h rename to sound/hda/codecs/cirrus/cs8409.h index e4bd2e12110b..35072cd009dc 100644 --- a/sound/pci/hda/patch_cs8409.h +++ b/sound/hda/codecs/cirrus/cs8409.h @@ -17,7 +17,7 @@ #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" -#include "hda_generic.h" +#include "../generic.h" /* CS8409 Specific Definitions */ diff --git a/sound/pci/hda/patch_cmedia.c b/sound/hda/codecs/cmedia.c similarity index 99% rename from sound/pci/hda/patch_cmedia.c rename to sound/hda/codecs/cmedia.c index fe946d407830..c88da2f8233e 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/hda/codecs/cmedia.c @@ -15,7 +15,7 @@ #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" -#include "hda_generic.h" +#include "generic.h" /* CM9825 Offset Definitions */ diff --git a/sound/pci/hda/patch_conexant.c b/sound/hda/codecs/conexant.c similarity index 99% rename from sound/pci/hda/patch_conexant.c rename to sound/hda/codecs/conexant.c index e584a7b2877d..b7710a81fd87 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/hda/codecs/conexant.c @@ -19,7 +19,7 @@ #include "hda_auto_parser.h" #include "hda_beep.h" #include "hda_jack.h" -#include "hda_generic.h" +#include "generic.h" struct conexant_spec { struct hda_gen_spec gen; @@ -312,10 +312,10 @@ enum { }; /* for hda_fixup_thinkpad_acpi() */ -#include "thinkpad_helper.c" +#include "helpers/thinkpad.c" /* for hda_fixup_ideapad_acpi() */ -#include "ideapad_hotkey_led_helper.c" +#include "helpers/ideapad_hotkey_led.c" static void cxt_fixup_stereo_dmic(struct hda_codec *codec, const struct hda_fixup *fix, int action) diff --git a/sound/pci/hda/hda_generic.c b/sound/hda/codecs/generic.c similarity index 99% rename from sound/pci/hda/hda_generic.c rename to sound/hda/codecs/generic.c index 2a28c8b6ba55..873fd4b7f451 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/hda/codecs/generic.c @@ -25,7 +25,7 @@ #include "hda_auto_parser.h" #include "hda_jack.h" #include "hda_beep.h" -#include "hda_generic.h" +#include "generic.h" /** diff --git a/sound/pci/hda/hda_generic.h b/sound/hda/codecs/generic.h similarity index 100% rename from sound/pci/hda/hda_generic.h rename to sound/hda/codecs/generic.h diff --git a/sound/hda/codecs/hdmi/Makefile b/sound/hda/codecs/hdmi/Makefile new file mode 100644 index 000000000000..371818d4e9b2 --- /dev/null +++ b/sound/hda/codecs/hdmi/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +subdir-ccflags-y += -I$(src)/../../common + +snd-hda-codec-hdmi-y := hdmi.o eld.o + +obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o diff --git a/sound/pci/hda/hda_eld.c b/sound/hda/codecs/hdmi/eld.c similarity index 100% rename from sound/pci/hda/hda_eld.c rename to sound/hda/codecs/hdmi/eld.c diff --git a/sound/pci/hda/patch_hdmi.c b/sound/hda/codecs/hdmi/hdmi.c similarity index 99% rename from sound/pci/hda/patch_hdmi.c rename to sound/hda/codecs/hdmi/hdmi.c index 9a7793eb16e9..3811eb1dc998 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/hda/codecs/hdmi/hdmi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * - * patch_hdmi.c - routines for HDMI/DisplayPort codecs + * hdmi.c - routines for HDMI/DisplayPort codecs * * Copyright(c) 2008-2010 Intel Corporation * Copyright (c) 2006 ATI Technologies Inc. diff --git a/sound/pci/hda/hp_x360_helper.c b/sound/hda/codecs/helpers/hp_x360.c similarity index 100% rename from sound/pci/hda/hp_x360_helper.c rename to sound/hda/codecs/helpers/hp_x360.c diff --git a/sound/pci/hda/ideapad_hotkey_led_helper.c b/sound/hda/codecs/helpers/ideapad_hotkey_led.c similarity index 100% rename from sound/pci/hda/ideapad_hotkey_led_helper.c rename to sound/hda/codecs/helpers/ideapad_hotkey_led.c diff --git a/sound/pci/hda/ideapad_s740_helper.c b/sound/hda/codecs/helpers/ideapad_s740.c similarity index 100% rename from sound/pci/hda/ideapad_s740_helper.c rename to sound/hda/codecs/helpers/ideapad_s740.c diff --git a/sound/pci/hda/thinkpad_helper.c b/sound/hda/codecs/helpers/thinkpad.c similarity index 100% rename from sound/pci/hda/thinkpad_helper.c rename to sound/hda/codecs/helpers/thinkpad.c diff --git a/sound/pci/hda/patch_realtek.c b/sound/hda/codecs/realtek.c similarity index 99% rename from sound/pci/hda/patch_realtek.c rename to sound/hda/codecs/realtek.c index 936c3470a13b..eea42bf5aec2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/hda/codecs/realtek.c @@ -30,8 +30,8 @@ #include "hda_auto_parser.h" #include "hda_beep.h" #include "hda_jack.h" -#include "hda_generic.h" -#include "hda_component.h" +#include "generic.h" +#include "side-codecs/hda_component.h" /* keep halting ALC5505 DSP, for power saving */ #define HALT_REALTEK_ALC5505 @@ -7120,7 +7120,7 @@ static void alc285_fixup_hp_beep(struct hda_codec *codec, } /* for hda_fixup_thinkpad_acpi() */ -#include "thinkpad_helper.c" +#include "helpers/thinkpad.c" static void alc_fixup_thinkpad_acpi(struct hda_codec *codec, const struct hda_fixup *fix, int action) @@ -7130,7 +7130,7 @@ static void alc_fixup_thinkpad_acpi(struct hda_codec *codec, } /* for hda_fixup_ideapad_acpi() */ -#include "ideapad_hotkey_led_helper.c" +#include "helpers/ideapad_hotkey_led.c" static void alc_fixup_ideapad_acpi(struct hda_codec *codec, const struct hda_fixup *fix, int action) @@ -7362,10 +7362,10 @@ static void alc256_fixup_acer_sfg16_micmute_led(struct hda_codec *codec, /* for alc295_fixup_hp_top_speakers */ -#include "hp_x360_helper.c" +#include "helpers/hp_x360.c" /* for alc285_fixup_ideapad_s740_coef() */ -#include "ideapad_s740_helper.c" +#include "helpers/ideapad_s740.c" static const struct coef_fw alc256_fixup_set_coef_defaults_coefs[] = { WRITE_COEF(0x10, 0x0020), WRITE_COEF(0x24, 0x0000), diff --git a/sound/pci/hda/patch_senarytech.c b/sound/hda/codecs/senarytech.c similarity index 98% rename from sound/pci/hda/patch_senarytech.c rename to sound/hda/codecs/senarytech.c index 0691996fa971..9a253ad19f4d 100644 --- a/sound/pci/hda/patch_senarytech.c +++ b/sound/hda/codecs/senarytech.c @@ -2,7 +2,7 @@ /* * HD audio interface patch for Senary HDA audio codec * - * Initially based on sound/pci/hda/patch_conexant.c + * Initially based on conexant.c */ #include @@ -17,7 +17,7 @@ #include "hda_auto_parser.h" #include "hda_beep.h" #include "hda_jack.h" -#include "hda_generic.h" +#include "generic.h" struct senary_spec { struct hda_gen_spec gen; diff --git a/sound/pci/hda/patch_si3054.c b/sound/hda/codecs/si3054.c similarity index 100% rename from sound/pci/hda/patch_si3054.c rename to sound/hda/codecs/si3054.c diff --git a/sound/hda/codecs/side-codecs/Kconfig b/sound/hda/codecs/side-codecs/Kconfig new file mode 100644 index 000000000000..cbf1847896bc --- /dev/null +++ b/sound/hda/codecs/side-codecs/Kconfig @@ -0,0 +1,128 @@ +config SND_HDA_CIRRUS_SCODEC + tristate + +config SND_HDA_CIRRUS_SCODEC_KUNIT_TEST + tristate "KUnit test for Cirrus side-codec library" if !KUNIT_ALL_TESTS + depends on SND_HDA_CIRRUS_SCODEC && GPIOLIB && KUNIT + default KUNIT_ALL_TESTS + help + This builds KUnit tests for the cirrus side-codec library. + For more information on KUnit and unit tests in general, + please refer to the KUnit documentation in + Documentation/dev-tools/kunit/. + If in doubt, say "N". + +config SND_HDA_SCODEC_CS35L41 + tristate + select SND_HDA_GENERIC + select REGMAP_IRQ + select FW_CS_DSP + +config SND_HDA_SCODEC_COMPONENT + tristate + +config SND_HDA_SCODEC_CS35L41_I2C + tristate "Build CS35L41 HD-audio side codec support for I2C Bus" + depends on I2C + depends on ACPI + depends on EFI + depends on SND_SOC + select SND_SOC_CS35L41_LIB + select SND_HDA_SCODEC_CS35L41 + select SND_SOC_CS_AMP_LIB + help + Say Y or M here to include CS35L41 I2C HD-audio side codec support + in snd-hda-intel driver, such as ALC287. + +comment "Set to Y if you want auto-loading the side codec driver" + depends on SND_HDA=y && SND_HDA_SCODEC_CS35L41_I2C=m + +config SND_HDA_SCODEC_CS35L41_SPI + tristate "Build CS35L41 HD-audio codec support for SPI Bus" + depends on SPI_MASTER + depends on ACPI + depends on EFI + depends on SND_SOC + select SND_SOC_CS35L41_LIB + select SND_HDA_SCODEC_CS35L41 + select SND_SOC_CS_AMP_LIB + help + Say Y or M here to include CS35L41 SPI HD-audio side codec support + in snd-hda-intel driver, such as ALC287. + +comment "Set to Y if you want auto-loading the side codec driver" + depends on SND_HDA=y && SND_HDA_SCODEC_CS35L41_SPI=m + +config SND_HDA_SCODEC_CS35L56 + tristate + +config SND_HDA_SCODEC_CS35L56_I2C + tristate "Build CS35L56 HD-audio side codec support for I2C Bus" + depends on I2C + depends on ACPI + depends on SND_SOC + select FW_CS_DSP + imply SERIAL_MULTI_INSTANTIATE + select SND_HDA_GENERIC + select SND_SOC_CS35L56_SHARED + select SND_HDA_SCODEC_CS35L56 + select SND_HDA_CIRRUS_SCODEC + select SND_SOC_CS_AMP_LIB + help + Say Y or M here to include CS35L56 amplifier support with + I2C control. + +config SND_HDA_SCODEC_CS35L56_SPI + tristate "Build CS35L56 HD-audio side codec support for SPI Bus" + depends on SPI_MASTER + depends on ACPI + depends on SND_SOC + select FW_CS_DSP + imply SERIAL_MULTI_INSTANTIATE + select SND_HDA_GENERIC + select SND_SOC_CS35L56_SHARED + select SND_HDA_SCODEC_CS35L56 + select SND_HDA_CIRRUS_SCODEC + select SND_SOC_CS_AMP_LIB + help + Say Y or M here to include CS35L56 amplifier support with + SPI control. + +config SND_HDA_SCODEC_TAS2781 + tristate + select SND_HDA_GENERIC + +config SND_HDA_SCODEC_TAS2781_I2C + tristate "Build TAS2781 HD-audio side codec support for I2C Bus" + depends on I2C + depends on ACPI + depends on EFI + depends on SND_SOC + select SND_HDA_SCODEC_TAS2781 + select SND_SOC_TAS2781_COMLIB_I2C + select SND_SOC_TAS2781_FMWLIB + select CRC32 + help + Say Y or M here to include TAS2781 I2C HD-audio side codec support + in snd-hda-intel driver, such as ALC287. + +comment "Set to Y if you want auto-loading the side codec driver" + depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_I2C=m + +config SND_HDA_SCODEC_TAS2781_SPI + tristate "Build TAS2781 HD-audio side codec support for SPI Bus" + depends on SPI_MASTER + depends on ACPI + depends on EFI + depends on SND_SOC + select SND_HDA_SCODEC_TAS2781 + select SND_SOC_TAS2781_COMLIB + select SND_SOC_TAS2781_FMWLIB + select CRC8 + select CRC32 + help + Say Y or M here to include TAS2781 SPI HD-audio side codec support + in snd-hda-intel driver, such as ALC287. + +comment "Set to Y if you want auto-loading the side codec driver" + depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_SPI=m diff --git a/sound/hda/codecs/side-codecs/Makefile b/sound/hda/codecs/side-codecs/Makefile new file mode 100644 index 000000000000..245e84f6a121 --- /dev/null +++ b/sound/hda/codecs/side-codecs/Makefile @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0 +subdir-ccflags-y += -I$(src)/../../common + +snd-hda-cirrus-scodec-y := cirrus_scodec.o +snd-hda-cirrus-scodec-test-y := cirrus_scodec_test.o +snd-hda-scodec-cs35l41-y := cs35l41_hda.o cs35l41_hda_property.o +snd-hda-scodec-cs35l41-i2c-y := cs35l41_hda_i2c.o +snd-hda-scodec-cs35l41-spi-y := cs35l41_hda_spi.o +snd-hda-scodec-cs35l56-y := cs35l56_hda.o +snd-hda-scodec-cs35l56-i2c-y := cs35l56_hda_i2c.o +snd-hda-scodec-cs35l56-spi-y := cs35l56_hda_spi.o +snd-hda-scodec-component-y := hda_component.o +snd-hda-scodec-tas2781-y := tas2781_hda.o +snd-hda-scodec-tas2781-i2c-y := tas2781_hda_i2c.o +snd-hda-scodec-tas2781-spi-y := tas2781_hda_spi.o + +obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC) += snd-hda-cirrus-scodec.o +obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC_KUNIT_TEST) += snd-hda-cirrus-scodec-test.o +obj-$(CONFIG_SND_HDA_SCODEC_CS35L41) += snd-hda-scodec-cs35l41.o +obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_I2C) += snd-hda-scodec-cs35l41-i2c.o +obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_SPI) += snd-hda-scodec-cs35l41-spi.o +obj-$(CONFIG_SND_HDA_SCODEC_CS35L56) += snd-hda-scodec-cs35l56.o +obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_I2C) += snd-hda-scodec-cs35l56-i2c.o +obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_SPI) += snd-hda-scodec-cs35l56-spi.o +obj-$(CONFIG_SND_HDA_SCODEC_COMPONENT) += snd-hda-scodec-component.o +obj-$(CONFIG_SND_HDA_SCODEC_TAS2781) += snd-hda-scodec-tas2781.o +obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_I2C) += snd-hda-scodec-tas2781-i2c.o +obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o diff --git a/sound/pci/hda/cirrus_scodec.c b/sound/hda/codecs/side-codecs/cirrus_scodec.c similarity index 100% rename from sound/pci/hda/cirrus_scodec.c rename to sound/hda/codecs/side-codecs/cirrus_scodec.c diff --git a/sound/pci/hda/cirrus_scodec.h b/sound/hda/codecs/side-codecs/cirrus_scodec.h similarity index 100% rename from sound/pci/hda/cirrus_scodec.h rename to sound/hda/codecs/side-codecs/cirrus_scodec.h diff --git a/sound/pci/hda/cirrus_scodec_test.c b/sound/hda/codecs/side-codecs/cirrus_scodec_test.c similarity index 100% rename from sound/pci/hda/cirrus_scodec_test.c rename to sound/hda/codecs/side-codecs/cirrus_scodec_test.c diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/hda/codecs/side-codecs/cs35l41_hda.c similarity index 99% rename from sound/pci/hda/cs35l41_hda.c rename to sound/hda/codecs/side-codecs/cs35l41_hda.c index 2d7ee121a7fd..37f2cdc8ce82 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/hda/codecs/side-codecs/cs35l41_hda.c @@ -17,7 +17,7 @@ #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" -#include "hda_generic.h" +#include "../generic.h" #include "hda_component.h" #include "cs35l41_hda.h" #include "cs35l41_hda_property.h" diff --git a/sound/pci/hda/cs35l41_hda.h b/sound/hda/codecs/side-codecs/cs35l41_hda.h similarity index 100% rename from sound/pci/hda/cs35l41_hda.h rename to sound/hda/codecs/side-codecs/cs35l41_hda.h diff --git a/sound/pci/hda/cs35l41_hda_i2c.c b/sound/hda/codecs/side-codecs/cs35l41_hda_i2c.c similarity index 100% rename from sound/pci/hda/cs35l41_hda_i2c.c rename to sound/hda/codecs/side-codecs/cs35l41_hda_i2c.c diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/hda/codecs/side-codecs/cs35l41_hda_property.c similarity index 100% rename from sound/pci/hda/cs35l41_hda_property.c rename to sound/hda/codecs/side-codecs/cs35l41_hda_property.c diff --git a/sound/pci/hda/cs35l41_hda_property.h b/sound/hda/codecs/side-codecs/cs35l41_hda_property.h similarity index 100% rename from sound/pci/hda/cs35l41_hda_property.h rename to sound/hda/codecs/side-codecs/cs35l41_hda_property.h diff --git a/sound/pci/hda/cs35l41_hda_spi.c b/sound/hda/codecs/side-codecs/cs35l41_hda_spi.c similarity index 100% rename from sound/pci/hda/cs35l41_hda_spi.c rename to sound/hda/codecs/side-codecs/cs35l41_hda_spi.c diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/hda/codecs/side-codecs/cs35l56_hda.c similarity index 99% rename from sound/pci/hda/cs35l56_hda.c rename to sound/hda/codecs/side-codecs/cs35l56_hda.c index e8b4995118bb..8d43119b3dd2 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/hda/codecs/side-codecs/cs35l56_hda.c @@ -20,7 +20,7 @@ #include "cirrus_scodec.h" #include "cs35l56_hda.h" #include "hda_component.h" -#include "hda_generic.h" +#include "../generic.h" /* * The cs35l56_hda_dai_config[] reg sequence configures the device as diff --git a/sound/pci/hda/cs35l56_hda.h b/sound/hda/codecs/side-codecs/cs35l56_hda.h similarity index 100% rename from sound/pci/hda/cs35l56_hda.h rename to sound/hda/codecs/side-codecs/cs35l56_hda.h diff --git a/sound/pci/hda/cs35l56_hda_i2c.c b/sound/hda/codecs/side-codecs/cs35l56_hda_i2c.c similarity index 100% rename from sound/pci/hda/cs35l56_hda_i2c.c rename to sound/hda/codecs/side-codecs/cs35l56_hda_i2c.c diff --git a/sound/pci/hda/cs35l56_hda_spi.c b/sound/hda/codecs/side-codecs/cs35l56_hda_spi.c similarity index 100% rename from sound/pci/hda/cs35l56_hda_spi.c rename to sound/hda/codecs/side-codecs/cs35l56_hda_spi.c diff --git a/sound/pci/hda/hda_component.c b/sound/hda/codecs/side-codecs/hda_component.c similarity index 100% rename from sound/pci/hda/hda_component.c rename to sound/hda/codecs/side-codecs/hda_component.c diff --git a/sound/pci/hda/hda_component.h b/sound/hda/codecs/side-codecs/hda_component.h similarity index 100% rename from sound/pci/hda/hda_component.h rename to sound/hda/codecs/side-codecs/hda_component.h diff --git a/sound/pci/hda/tas2781_hda.c b/sound/hda/codecs/side-codecs/tas2781_hda.c similarity index 100% rename from sound/pci/hda/tas2781_hda.c rename to sound/hda/codecs/side-codecs/tas2781_hda.c diff --git a/sound/pci/hda/tas2781_hda.h b/sound/hda/codecs/side-codecs/tas2781_hda.h similarity index 100% rename from sound/pci/hda/tas2781_hda.h rename to sound/hda/codecs/side-codecs/tas2781_hda.h diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c similarity index 99% rename from sound/pci/hda/tas2781_hda_i2c.c rename to sound/hda/codecs/side-codecs/tas2781_hda_i2c.c index b7ee22840d78..bacc3f6ed4bd 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c @@ -30,7 +30,7 @@ #include "hda_auto_parser.h" #include "hda_component.h" #include "hda_jack.h" -#include "hda_generic.h" +#include "../generic.h" #include "tas2781_hda.h" #define TAS2563_CAL_VAR_NAME_MAX 16 diff --git a/sound/pci/hda/tas2781_hda_spi.c b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c similarity index 99% rename from sound/pci/hda/tas2781_hda_spi.c rename to sound/hda/codecs/side-codecs/tas2781_hda_spi.c index c4b9a3c1a7f0..09a5d0f131b2 100644 --- a/sound/pci/hda/tas2781_hda_spi.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c @@ -35,7 +35,7 @@ #include "hda_auto_parser.h" #include "hda_component.h" #include "hda_jack.h" -#include "hda_generic.h" +#include "../generic.h" #include "tas2781_hda.h" #define TASDEVICE_RANGE_MAX_SIZE (256 * 128) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/hda/codecs/sigmatel.c similarity index 99% rename from sound/pci/hda/patch_sigmatel.c rename to sound/hda/codecs/sigmatel.c index bde6b7373858..56274ff49b0b 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/hda/codecs/sigmatel.c @@ -7,7 +7,7 @@ * Copyright (c) 2005 Embedded Alley Solutions, Inc. * Matt Porter * - * Based on patch_cmedia.c and patch_realtek.c + * Based on cmedia.c and realtek.c * Copyright (c) 2004 Takashi Iwai */ @@ -24,7 +24,7 @@ #include "hda_auto_parser.h" #include "hda_beep.h" #include "hda_jack.h" -#include "hda_generic.h" +#include "generic.h" enum { STAC_REF, diff --git a/sound/pci/hda/patch_via.c b/sound/hda/codecs/via.c similarity index 99% rename from sound/pci/hda/patch_via.c rename to sound/hda/codecs/via.c index d0893059b1b9..e3ce563f866b 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/hda/codecs/via.c @@ -43,7 +43,7 @@ #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" -#include "hda_generic.h" +#include "generic.h" /* Pin Widget NID */ #define VT1708_HP_PIN_NID 0x20 diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 787868c9e91b..e0996a9d90b0 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -933,5 +933,3 @@ config SND_YMFPCI will be called snd-ymfpci. endif # SND_PCI - -source "sound/pci/hda/Kconfig" diff --git a/sound/pci/Makefile b/sound/pci/Makefile index 18b673018dfd..9d5e8e12ae73 100644 --- a/sound/pci/Makefile +++ b/sound/pci/Makefile @@ -69,7 +69,6 @@ obj-$(CONFIG_SND) += \ lx6464es/ \ echoaudio/ \ emu10k1/ \ - hda/ \ ice1712/ \ korg1212/ \ mixart/ \ diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile deleted file mode 100644 index 79de0af71ad4..000000000000 --- a/sound/pci/hda/Makefile +++ /dev/null @@ -1,61 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -subdir-ccflags-y += -I$(src)/../../hda/common - -snd-hda-codec-generic-y := hda_generic.o -snd-hda-codec-realtek-y := patch_realtek.o -snd-hda-codec-cmedia-y := patch_cmedia.o -snd-hda-codec-analog-y := patch_analog.o -snd-hda-codec-idt-y := patch_sigmatel.o -snd-hda-codec-si3054-y := patch_si3054.o -snd-hda-codec-cirrus-y := patch_cirrus.o -snd-hda-codec-cs8409-y := patch_cs8409.o patch_cs8409-tables.o -snd-hda-codec-ca0110-y := patch_ca0110.o -snd-hda-codec-ca0132-y := patch_ca0132.o -snd-hda-codec-conexant-y := patch_conexant.o -snd-hda-codec-senarytech-y :=patch_senarytech.o -snd-hda-codec-via-y := patch_via.o -snd-hda-codec-hdmi-y := patch_hdmi.o hda_eld.o - -# side codecs -snd-hda-cirrus-scodec-y := cirrus_scodec.o -snd-hda-cirrus-scodec-test-y := cirrus_scodec_test.o -snd-hda-scodec-cs35l41-y := cs35l41_hda.o cs35l41_hda_property.o -snd-hda-scodec-cs35l41-i2c-y := cs35l41_hda_i2c.o -snd-hda-scodec-cs35l41-spi-y := cs35l41_hda_spi.o -snd-hda-scodec-cs35l56-y := cs35l56_hda.o -snd-hda-scodec-cs35l56-i2c-y := cs35l56_hda_i2c.o -snd-hda-scodec-cs35l56-spi-y := cs35l56_hda_spi.o -snd-hda-scodec-component-y := hda_component.o -snd-hda-scodec-tas2781-y := tas2781_hda.o -snd-hda-scodec-tas2781-i2c-y := tas2781_hda_i2c.o -snd-hda-scodec-tas2781-spi-y := tas2781_hda_spi.o - -# codec drivers -obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o -obj-$(CONFIG_SND_HDA_CODEC_REALTEK) += snd-hda-codec-realtek.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_SIGMATEL) += snd-hda-codec-idt.o -obj-$(CONFIG_SND_HDA_CODEC_SI3054) += snd-hda-codec-si3054.o -obj-$(CONFIG_SND_HDA_CODEC_CIRRUS) += snd-hda-codec-cirrus.o -obj-$(CONFIG_SND_HDA_CODEC_CS8409) += snd-hda-codec-cs8409.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_CONEXANT) += snd-hda-codec-conexant.o -obj-$(CONFIG_SND_HDA_CODEC_SENARYTECH) += snd-hda-codec-senarytech.o -obj-$(CONFIG_SND_HDA_CODEC_VIA) += snd-hda-codec-via.o -obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o - -# side codecs -obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC) += snd-hda-cirrus-scodec.o -obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC_KUNIT_TEST) += snd-hda-cirrus-scodec-test.o -obj-$(CONFIG_SND_HDA_SCODEC_CS35L41) += snd-hda-scodec-cs35l41.o -obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_I2C) += snd-hda-scodec-cs35l41-i2c.o -obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_SPI) += snd-hda-scodec-cs35l41-spi.o -obj-$(CONFIG_SND_HDA_SCODEC_CS35L56) += snd-hda-scodec-cs35l56.o -obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_I2C) += snd-hda-scodec-cs35l56-i2c.o -obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_SPI) += snd-hda-scodec-cs35l56-spi.o -obj-$(CONFIG_SND_HDA_SCODEC_COMPONENT) += snd-hda-scodec-component.o -obj-$(CONFIG_SND_HDA_SCODEC_TAS2781) += snd-hda-scodec-tas2781.o -obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_I2C) += snd-hda-scodec-tas2781-i2c.o -obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o From aeeb85f26c3bbef6f702ac20167c45812251501d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:10 +0200 Subject: [PATCH 323/385] 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: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-8-tiwai@suse.de --- sound/hda/codecs/Kconfig | 14 +- sound/hda/codecs/Makefile | 5 +- sound/hda/codecs/realtek/Kconfig | 90 + sound/hda/codecs/realtek/Makefile | 26 + sound/hda/codecs/realtek/alc260.c | 276 + sound/hda/codecs/realtek/alc262.c | 199 + sound/hda/codecs/realtek/alc268.c | 176 + .../codecs/{realtek.c => realtek/alc269.c} | 5727 +---------------- sound/hda/codecs/realtek/alc662.c | 1102 ++++ sound/hda/codecs/realtek/alc680.c | 53 + sound/hda/codecs/realtek/alc861.c | 149 + sound/hda/codecs/realtek/alc861vd.c | 123 + sound/hda/codecs/realtek/alc880.c | 497 ++ sound/hda/codecs/realtek/alc882.c | 847 +++ sound/hda/codecs/realtek/realtek.c | 2314 +++++++ sound/hda/codecs/realtek/realtek.h | 302 + 16 files changed, 6191 insertions(+), 5709 deletions(-) create mode 100644 sound/hda/codecs/realtek/Kconfig create mode 100644 sound/hda/codecs/realtek/Makefile create mode 100644 sound/hda/codecs/realtek/alc260.c create mode 100644 sound/hda/codecs/realtek/alc262.c create mode 100644 sound/hda/codecs/realtek/alc268.c rename sound/hda/codecs/{realtek.c => realtek/alc269.c} (64%) create mode 100644 sound/hda/codecs/realtek/alc662.c create mode 100644 sound/hda/codecs/realtek/alc680.c create mode 100644 sound/hda/codecs/realtek/alc861.c create mode 100644 sound/hda/codecs/realtek/alc861vd.c create mode 100644 sound/hda/codecs/realtek/alc880.c create mode 100644 sound/hda/codecs/realtek/alc882.c create mode 100644 sound/hda/codecs/realtek/realtek.c create mode 100644 sound/hda/codecs/realtek/realtek.h diff --git a/sound/hda/codecs/Kconfig b/sound/hda/codecs/Kconfig index bac19a664be0..0bb675ab84fe 100644 --- a/sound/hda/codecs/Kconfig +++ b/sound/hda/codecs/Kconfig @@ -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" diff --git a/sound/hda/codecs/Makefile b/sound/hda/codecs/Makefile index 205cd1373b42..14e5041aa4f0 100644 --- a/sound/hda/codecs/Makefile +++ b/sound/hda/codecs/Makefile @@ -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 diff --git a/sound/hda/codecs/realtek/Kconfig b/sound/hda/codecs/realtek/Kconfig new file mode 100644 index 000000000000..4b3ab28203b4 --- /dev/null +++ b/sound/hda/codecs/realtek/Kconfig @@ -0,0 +1,90 @@ +# 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 + + diff --git a/sound/hda/codecs/realtek/Makefile b/sound/hda/codecs/realtek/Makefile new file mode 100644 index 000000000000..c6ee4e526a40 --- /dev/null +++ b/sound/hda/codecs/realtek/Makefile @@ -0,0 +1,26 @@ +# 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 diff --git a/sound/hda/codecs/realtek/alc260.c b/sound/hda/codecs/realtek/alc260.c new file mode 100644 index 000000000000..ebe20eaec58a --- /dev/null +++ b/sound/hda/codecs/realtek/alc260.c @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Realtek ALC260 codec +// + +#include +#include +#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); diff --git a/sound/hda/codecs/realtek/alc262.c b/sound/hda/codecs/realtek/alc262.c new file mode 100644 index 000000000000..ffe61f447667 --- /dev/null +++ b/sound/hda/codecs/realtek/alc262.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Realtek ALC262 codec +// + +#include +#include +#include "realtek.h" + +static int alc262_parse_auto_config(struct hda_codec *codec) +{ + static const hda_nid_t alc262_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 }; + return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids); +} + +/* + * Pin config fixes + */ +enum { + ALC262_FIXUP_FSC_H270, + ALC262_FIXUP_FSC_S7110, + ALC262_FIXUP_HP_Z200, + ALC262_FIXUP_TYAN, + ALC262_FIXUP_LENOVO_3000, + ALC262_FIXUP_BENQ, + ALC262_FIXUP_BENQ_T31, + ALC262_FIXUP_INV_DMIC, + ALC262_FIXUP_INTEL_BAYLEYBAY, +}; + +static const struct hda_fixup alc262_fixups[] = { + [ALC262_FIXUP_FSC_H270] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x99130110 }, /* speaker */ + { 0x15, 0x0221142f }, /* front HP */ + { 0x1b, 0x0121141f }, /* rear HP */ + { } + } + }, + [ALC262_FIXUP_FSC_S7110] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x15, 0x90170110 }, /* speaker */ + { } + }, + .chained = true, + .chain_id = ALC262_FIXUP_BENQ, + }, + [ALC262_FIXUP_HP_Z200] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x16, 0x99130120 }, /* internal speaker */ + { } + } + }, + [ALC262_FIXUP_TYAN] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x1993e1f0 }, /* int AUX */ + { } + } + }, + [ALC262_FIXUP_LENOVO_3000] = { + .type = HDA_FIXUP_PINCTLS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, PIN_VREF50 }, + {} + }, + .chained = true, + .chain_id = ALC262_FIXUP_BENQ, + }, + [ALC262_FIXUP_BENQ] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 }, + {} + } + }, + [ALC262_FIXUP_BENQ_T31] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 }, + {} + } + }, + [ALC262_FIXUP_INV_DMIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_inv_dmic, + }, + [ALC262_FIXUP_INTEL_BAYLEYBAY] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_no_depop_delay, + }, +}; + +static const struct hda_quirk alc262_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200), + SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110), + SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ), + SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN), + SND_PCI_QUIRK(0x1734, 0x1141, "FSC ESPRIMO U9210", ALC262_FIXUP_FSC_H270), + SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270), + SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000), + SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ), + SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_FIXUP_BENQ_T31), + SND_PCI_QUIRK(0x8086, 0x7270, "BayleyBay", ALC262_FIXUP_INTEL_BAYLEYBAY), + {} +}; + +static const struct hda_model_fixup alc262_fixup_models[] = { + {.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"}, + {.id = ALC262_FIXUP_FSC_H270, .name = "fsc-h270"}, + {.id = ALC262_FIXUP_FSC_S7110, .name = "fsc-s7110"}, + {.id = ALC262_FIXUP_HP_Z200, .name = "hp-z200"}, + {.id = ALC262_FIXUP_TYAN, .name = "tyan"}, + {.id = ALC262_FIXUP_LENOVO_3000, .name = "lenovo-3000"}, + {.id = ALC262_FIXUP_BENQ, .name = "benq"}, + {.id = ALC262_FIXUP_BENQ_T31, .name = "benq-t31"}, + {.id = ALC262_FIXUP_INTEL_BAYLEYBAY, .name = "bayleybay"}, + {} +}; + +/* + */ +static int patch_alc262(struct hda_codec *codec) +{ + struct alc_spec *spec; + int err; + + err = alc_alloc_spec(codec, 0x0b); + if (err < 0) + return err; + + spec = codec->spec; + spec->gen.shared_mic_vref_pin = 0x18; + + spec->shutup = alc_eapd_shutup; + +#if 0 + /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is + * under-run + */ + alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x80); +#endif + alc_fix_pll_init(codec, 0x20, 0x0a, 10); + + alc_pre_init(codec); + + snd_hda_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl, + alc262_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + alc_auto_parse_customize_define(codec); + + if (has_cdefine_beep(codec)) + spec->gen.beep_nid = 0x01; + + /* automatic parse from the BIOS config */ + err = alc262_parse_auto_config(codec); + if (err < 0) + goto error; + + if (!spec->gen.no_analog && spec->gen.beep_nid) { + err = set_beep_amp(spec, 0x0b, 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_alc262[] = { + HDA_CODEC_ENTRY(0x10ec0262, "ALC262", patch_alc262), + {} /* terminator */ +}; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc262); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek ALC262 HD-audio codec"); +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); + +static struct hda_codec_driver alc262_driver = { + .id = snd_hda_id_alc262, +}; + +module_hda_codec_driver(alc262_driver); diff --git a/sound/hda/codecs/realtek/alc268.c b/sound/hda/codecs/realtek/alc268.c new file mode 100644 index 000000000000..d018f9982feb --- /dev/null +++ b/sound/hda/codecs/realtek/alc268.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include "realtek.h" + +/* bind Beep switches of both NID 0x0f and 0x10 */ +static int alc268_beep_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned long pval; + int err; + + mutex_lock(&codec->control_mutex); + pval = kcontrol->private_value; + kcontrol->private_value = (pval & ~0xff) | 0x0f; + err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); + if (err >= 0) { + kcontrol->private_value = (pval & ~0xff) | 0x10; + err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); + } + kcontrol->private_value = pval; + mutex_unlock(&codec->control_mutex); + return err; +} + +static const struct snd_kcontrol_new alc268_beep_mixer[] = { + HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Beep Playback Switch", + .subdevice = HDA_SUBDEV_AMP_FLAG, + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc268_beep_switch_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT) + }, +}; + +/* set PCBEEP vol = 0, mute connections */ +static const struct hda_verb alc268_beep_init_verbs[] = { + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + { } +}; + +enum { + ALC268_FIXUP_INV_DMIC, + ALC268_FIXUP_HP_EAPD, + ALC268_FIXUP_SPDIF, +}; + +static const struct hda_fixup alc268_fixups[] = { + [ALC268_FIXUP_INV_DMIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_inv_dmic, + }, + [ALC268_FIXUP_HP_EAPD] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 0}, + {} + } + }, + [ALC268_FIXUP_SPDIF] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1e, 0x014b1180 }, /* enable SPDIF out */ + {} + } + }, +}; + +static const struct hda_model_fixup alc268_fixup_models[] = { + {.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"}, + {.id = ALC268_FIXUP_HP_EAPD, .name = "hp-eapd"}, + {.id = ALC268_FIXUP_SPDIF, .name = "spdif"}, + {} +}; + +static const struct hda_quirk alc268_fixup_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x0139, "Acer TravelMate 6293", ALC268_FIXUP_SPDIF), + SND_PCI_QUIRK(0x1025, 0x015b, "Acer AOA 150 (ZG5)", ALC268_FIXUP_INV_DMIC), + /* below is codec SSID since multiple Toshiba laptops have the + * same PCI SSID 1179:ff00 + */ + SND_PCI_QUIRK(0x1179, 0xff06, "Toshiba P200", ALC268_FIXUP_HP_EAPD), + {} +}; + +/* + * BIOS auto configuration + */ +static int alc268_parse_auto_config(struct hda_codec *codec) +{ + static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 }; + return alc_parse_auto_config(codec, NULL, alc268_ssids); +} + +/* + */ +static int patch_alc268(struct hda_codec *codec) +{ + struct alc_spec *spec; + int i, err; + + /* ALC268 has no aa-loopback mixer */ + err = alc_alloc_spec(codec, 0); + if (err < 0) + return err; + + spec = codec->spec; + if (has_cdefine_beep(codec)) + spec->gen.beep_nid = 0x01; + + spec->shutup = alc_eapd_shutup; + + alc_pre_init(codec); + + snd_hda_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + /* automatic parse from the BIOS config */ + err = alc268_parse_auto_config(codec); + if (err < 0) + goto error; + + if (err > 0 && !spec->gen.no_analog && + spec->gen.autocfg.speaker_pins[0] != 0x1d) { + for (i = 0; i < ARRAY_SIZE(alc268_beep_mixer); i++) { + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, + &alc268_beep_mixer[i])) { + err = -ENOMEM; + goto error; + } + } + snd_hda_add_verbs(codec, alc268_beep_init_verbs); + if (!query_amp_caps(codec, 0x1d, HDA_INPUT)) + /* override the amp caps for beep generator */ + snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT, + (0x0c << AC_AMPCAP_OFFSET_SHIFT) | + (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (0 << AC_AMPCAP_MUTE_SHIFT)); + } + + 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_alc268[] = { + HDA_CODEC_ENTRY(0x10ec0267, "ALC267", patch_alc268), + HDA_CODEC_ENTRY(0x10ec0268, "ALC268", patch_alc268), + {} /* terminator */ +}; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc268); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek ALC267/268 HD-audio codec"); +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); + +static struct hda_codec_driver alc268_driver = { + .id = snd_hda_id_alc268, +}; + +module_hda_codec_driver(alc268_driver); diff --git a/sound/hda/codecs/realtek.c b/sound/hda/codecs/realtek/alc269.c similarity index 64% rename from sound/hda/codecs/realtek.c rename to sound/hda/codecs/realtek/alc269.c index eea42bf5aec2..13549b5b9c42 100644 --- a/sound/hda/codecs/realtek.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -1,3160 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/* - * Universal Interface for Intel High Definition Audio Codec - * - * HD audio interface patch for Realtek ALC codecs - * - * Copyright (c) 2004 Kailang Yang - * PeiSen Hou - * Takashi Iwai - * Jonathan Woithe - */ +// +// Realtek ALC269 and compatible codecs +// -#include -#include #include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include "hda_local.h" -#include "hda_auto_parser.h" -#include "hda_beep.h" -#include "hda_jack.h" -#include "generic.h" -#include "side-codecs/hda_component.h" +#include "realtek.h" /* keep halting ALC5505 DSP, for power saving */ #define HALT_REALTEK_ALC5505 -/* extra amp-initialization sequence types */ -enum { - ALC_INIT_UNDEFINED, - ALC_INIT_NONE, - ALC_INIT_DEFAULT, -}; - -enum { - ALC_HEADSET_MODE_UNKNOWN, - ALC_HEADSET_MODE_UNPLUGGED, - ALC_HEADSET_MODE_HEADSET, - ALC_HEADSET_MODE_MIC, - ALC_HEADSET_MODE_HEADPHONE, -}; - -enum { - ALC_HEADSET_TYPE_UNKNOWN, - ALC_HEADSET_TYPE_CTIA, - ALC_HEADSET_TYPE_OMTP, -}; - -enum { - ALC_KEY_MICMUTE_INDEX, -}; - -struct alc_customize_define { - unsigned int sku_cfg; - unsigned char port_connectivity; - unsigned char check_sum; - unsigned char customization; - unsigned char external_amp; - unsigned int enable_pcbeep:1; - unsigned int platform_type:1; - unsigned int swap:1; - unsigned int override:1; - unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */ -}; - -struct alc_coef_led { - unsigned int idx; - unsigned int mask; - unsigned int on; - unsigned int off; -}; - -struct alc_spec { - struct hda_gen_spec gen; /* must be at head */ - - /* codec parameterization */ - struct alc_customize_define cdefine; - unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ - - /* GPIO bits */ - unsigned int gpio_mask; - unsigned int gpio_dir; - unsigned int gpio_data; - bool gpio_write_delay; /* add a delay before writing gpio_data */ - - /* mute LED for HP laptops, see vref_mute_led_set() */ - int mute_led_polarity; - int micmute_led_polarity; - hda_nid_t mute_led_nid; - hda_nid_t cap_mute_led_nid; - - unsigned int gpio_mute_led_mask; - unsigned int gpio_mic_led_mask; - struct alc_coef_led mute_led_coef; - struct alc_coef_led mic_led_coef; - struct mutex coef_mutex; - - hda_nid_t headset_mic_pin; - hda_nid_t headphone_mic_pin; - int current_headset_mode; - int current_headset_type; - - /* hooks */ - void (*init_hook)(struct hda_codec *codec); - void (*power_hook)(struct hda_codec *codec); - void (*shutup)(struct hda_codec *codec); - - int init_amp; - int codec_variant; /* flag for other variants */ - unsigned int has_alc5505_dsp:1; - unsigned int no_depop_delay:1; - unsigned int done_hp_init:1; - unsigned int no_shutup_pins:1; - unsigned int ultra_low_power:1; - unsigned int has_hs_key:1; - unsigned int no_internal_mic_pin:1; - unsigned int en_3kpull_low:1; - int num_speaker_amps; - - /* for PLL fix */ - hda_nid_t pll_nid; - unsigned int pll_coef_idx, pll_coef_bit; - unsigned int coef0; - struct input_dev *kb_dev; - u8 alc_mute_keycode_map[1]; - - /* component binding */ - struct hda_component_parent comps; -}; - -/* - * COEF access helper functions - */ - -static void coef_mutex_lock(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - snd_hda_power_up_pm(codec); - mutex_lock(&spec->coef_mutex); -} - -static void coef_mutex_unlock(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - mutex_unlock(&spec->coef_mutex); - snd_hda_power_down_pm(codec); -} - -static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid, - unsigned int coef_idx) -{ - unsigned int val; - - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx); - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0); - return val; -} - -static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid, - unsigned int coef_idx) -{ - unsigned int val; - - coef_mutex_lock(codec); - val = __alc_read_coefex_idx(codec, nid, coef_idx); - coef_mutex_unlock(codec); - return val; -} - -#define alc_read_coef_idx(codec, coef_idx) \ - alc_read_coefex_idx(codec, 0x20, coef_idx) - -static void __alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid, - unsigned int coef_idx, unsigned int coef_val) -{ - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coef_val); -} - -static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid, - unsigned int coef_idx, unsigned int coef_val) -{ - coef_mutex_lock(codec); - __alc_write_coefex_idx(codec, nid, coef_idx, coef_val); - coef_mutex_unlock(codec); -} - -#define alc_write_coef_idx(codec, coef_idx, coef_val) \ - alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val) - -static void __alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid, - unsigned int coef_idx, unsigned int mask, - unsigned int bits_set) -{ - unsigned int val = __alc_read_coefex_idx(codec, nid, coef_idx); - - if (val != -1) - __alc_write_coefex_idx(codec, nid, coef_idx, - (val & ~mask) | bits_set); -} - -static void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid, - unsigned int coef_idx, unsigned int mask, - unsigned int bits_set) -{ - coef_mutex_lock(codec); - __alc_update_coefex_idx(codec, nid, coef_idx, mask, bits_set); - coef_mutex_unlock(codec); -} - -#define alc_update_coef_idx(codec, coef_idx, mask, bits_set) \ - alc_update_coefex_idx(codec, 0x20, coef_idx, mask, bits_set) - -/* a special bypass for COEF 0; read the cached value at the second time */ -static unsigned int alc_get_coef0(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - if (!spec->coef0) - spec->coef0 = alc_read_coef_idx(codec, 0); - return spec->coef0; -} - -/* coef writes/updates batch */ -struct coef_fw { - unsigned char nid; - unsigned char idx; - unsigned short mask; - unsigned short val; -}; - -#define UPDATE_COEFEX(_nid, _idx, _mask, _val) \ - { .nid = (_nid), .idx = (_idx), .mask = (_mask), .val = (_val) } -#define WRITE_COEFEX(_nid, _idx, _val) UPDATE_COEFEX(_nid, _idx, -1, _val) -#define WRITE_COEF(_idx, _val) WRITE_COEFEX(0x20, _idx, _val) -#define UPDATE_COEF(_idx, _mask, _val) UPDATE_COEFEX(0x20, _idx, _mask, _val) - -static void alc_process_coef_fw(struct hda_codec *codec, - const struct coef_fw *fw) -{ - coef_mutex_lock(codec); - for (; fw->nid; fw++) { - if (fw->mask == (unsigned short)-1) - __alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val); - else - __alc_update_coefex_idx(codec, fw->nid, fw->idx, - fw->mask, fw->val); - } - coef_mutex_unlock(codec); -} - -/* - * GPIO setup tables, used in initialization - */ - -/* Enable GPIO mask and set output */ -static void alc_setup_gpio(struct hda_codec *codec, unsigned int mask) -{ - struct alc_spec *spec = codec->spec; - - spec->gpio_mask |= mask; - spec->gpio_dir |= mask; - spec->gpio_data |= mask; -} - -static void alc_write_gpio_data(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, - spec->gpio_data); -} - -static void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask, - bool on) -{ - struct alc_spec *spec = codec->spec; - unsigned int oldval = spec->gpio_data; - - if (on) - spec->gpio_data |= mask; - else - spec->gpio_data &= ~mask; - if (oldval != spec->gpio_data) - alc_write_gpio_data(codec); -} - -static void alc_write_gpio(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - if (!spec->gpio_mask) - return; - - snd_hda_codec_write(codec, codec->core.afg, 0, - AC_VERB_SET_GPIO_MASK, spec->gpio_mask); - snd_hda_codec_write(codec, codec->core.afg, 0, - AC_VERB_SET_GPIO_DIRECTION, spec->gpio_dir); - if (spec->gpio_write_delay) - msleep(1); - alc_write_gpio_data(codec); -} - -static void alc_fixup_gpio(struct hda_codec *codec, int action, - unsigned int mask) -{ - if (action == HDA_FIXUP_ACT_PRE_PROBE) - alc_setup_gpio(codec, mask); -} - -static void alc_fixup_gpio1(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - alc_fixup_gpio(codec, action, 0x01); -} - -static void alc_fixup_gpio2(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - alc_fixup_gpio(codec, action, 0x02); -} - -static void alc_fixup_gpio3(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - alc_fixup_gpio(codec, action, 0x03); -} - -static void alc_fixup_gpio4(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - alc_fixup_gpio(codec, action, 0x04); -} - -static void alc_fixup_micmute_led(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - if (action == HDA_FIXUP_ACT_PRE_PROBE) - snd_hda_gen_add_micmute_led_cdev(codec, NULL); -} - -/* - * Fix hardware PLL issue - * On some codecs, the analog PLL gating control must be off while - * the default value is 1. - */ -static void alc_fix_pll(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - if (spec->pll_nid) - alc_update_coefex_idx(codec, spec->pll_nid, spec->pll_coef_idx, - 1 << spec->pll_coef_bit, 0); -} - -static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, - unsigned int coef_idx, unsigned int coef_bit) -{ - struct alc_spec *spec = codec->spec; - spec->pll_nid = nid; - spec->pll_coef_idx = coef_idx; - spec->pll_coef_bit = coef_bit; - alc_fix_pll(codec); -} - -/* update the master volume per volume-knob's unsol event */ -static void alc_update_knob_master(struct hda_codec *codec, - struct hda_jack_callback *jack) -{ - unsigned int val; - struct snd_kcontrol *kctl; - struct snd_ctl_elem_value *uctl; - - kctl = snd_hda_find_mixer_ctl(codec, "Master Playback Volume"); - if (!kctl) - return; - uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); - if (!uctl) - return; - val = snd_hda_codec_read(codec, jack->nid, 0, - AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); - val &= HDA_AMP_VOLMASK; - uctl->value.integer.value[0] = val; - uctl->value.integer.value[1] = val; - kctl->put(kctl, uctl); - kfree(uctl); -} - -static void alc880_unsol_event(struct hda_codec *codec, unsigned int res) -{ - /* For some reason, the res given from ALC880 is broken. - Here we adjust it properly. */ - snd_hda_jack_unsol_event(codec, res >> 2); -} - -/* Change EAPD to verb control */ -static void alc_fill_eapd_coef(struct hda_codec *codec) -{ - int coef; - - coef = alc_get_coef0(codec); - - switch (codec->core.vendor_id) { - case 0x10ec0262: - alc_update_coef_idx(codec, 0x7, 0, 1<<5); - break; - case 0x10ec0267: - case 0x10ec0268: - alc_update_coef_idx(codec, 0x7, 0, 1<<13); - break; - case 0x10ec0269: - if ((coef & 0x00f0) == 0x0010) - alc_update_coef_idx(codec, 0xd, 0, 1<<14); - if ((coef & 0x00f0) == 0x0020) - alc_update_coef_idx(codec, 0x4, 1<<15, 0); - if ((coef & 0x00f0) == 0x0030) - alc_update_coef_idx(codec, 0x10, 1<<9, 0); - break; - case 0x10ec0280: - case 0x10ec0284: - case 0x10ec0290: - case 0x10ec0292: - alc_update_coef_idx(codec, 0x4, 1<<15, 0); - break; - case 0x10ec0225: - case 0x10ec0295: - case 0x10ec0299: - alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000); - fallthrough; - case 0x10ec0215: - case 0x10ec0236: - case 0x10ec0245: - case 0x10ec0256: - case 0x10ec0257: - case 0x10ec0285: - case 0x10ec0289: - alc_update_coef_idx(codec, 0x36, 1<<13, 0); - fallthrough; - case 0x10ec0230: - case 0x10ec0233: - case 0x10ec0235: - case 0x10ec0255: - case 0x19e58326: - case 0x10ec0282: - case 0x10ec0283: - case 0x10ec0286: - case 0x10ec0288: - case 0x10ec0298: - case 0x10ec0300: - alc_update_coef_idx(codec, 0x10, 1<<9, 0); - break; - case 0x10ec0275: - alc_update_coef_idx(codec, 0xe, 0, 1<<0); - break; - case 0x10ec0287: - alc_update_coef_idx(codec, 0x10, 1<<9, 0); - alc_write_coef_idx(codec, 0x8, 0x4ab7); - break; - case 0x10ec0293: - alc_update_coef_idx(codec, 0xa, 1<<13, 0); - break; - case 0x10ec0234: - case 0x10ec0274: - alc_write_coef_idx(codec, 0x6e, 0x0c25); - fallthrough; - case 0x10ec0294: - case 0x10ec0700: - case 0x10ec0701: - case 0x10ec0703: - case 0x10ec0711: - alc_update_coef_idx(codec, 0x10, 1<<15, 0); - break; - case 0x10ec0662: - if ((coef & 0x00f0) == 0x0030) - alc_update_coef_idx(codec, 0x4, 1<<10, 0); /* EAPD Ctrl */ - break; - case 0x10ec0272: - case 0x10ec0273: - case 0x10ec0663: - case 0x10ec0665: - case 0x10ec0670: - case 0x10ec0671: - case 0x10ec0672: - alc_update_coef_idx(codec, 0xd, 0, 1<<14); /* EAPD Ctrl */ - break; - case 0x10ec0222: - case 0x10ec0623: - alc_update_coef_idx(codec, 0x19, 1<<13, 0); - break; - case 0x10ec0668: - alc_update_coef_idx(codec, 0x7, 3<<13, 0); - break; - case 0x10ec0867: - alc_update_coef_idx(codec, 0x4, 1<<10, 0); - break; - case 0x10ec0888: - if ((coef & 0x00f0) == 0x0020 || (coef & 0x00f0) == 0x0030) - alc_update_coef_idx(codec, 0x7, 1<<5, 0); - break; - case 0x10ec0892: - case 0x10ec0897: - alc_update_coef_idx(codec, 0x7, 1<<5, 0); - break; - case 0x10ec0899: - case 0x10ec0900: - case 0x10ec0b00: - case 0x10ec1168: - case 0x10ec1220: - alc_update_coef_idx(codec, 0x7, 1<<1, 0); - break; - } -} - -/* additional initialization for ALC888 variants */ -static void alc888_coef_init(struct hda_codec *codec) -{ - switch (alc_get_coef0(codec) & 0x00f0) { - /* alc888-VA */ - case 0x00: - /* alc888-VB */ - case 0x10: - alc_update_coef_idx(codec, 7, 0, 0x2030); /* Turn EAPD to High */ - break; - } -} - -/* turn on/off EAPD control (only if available) */ -static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on) -{ - if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) - return; - if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, - on ? 2 : 0); -} - -/* turn on/off EAPD controls of the codec */ -static void alc_auto_setup_eapd(struct hda_codec *codec, bool on) -{ - /* We currently only handle front, HP */ - static const hda_nid_t pins[] = { - 0x0f, 0x10, 0x14, 0x15, 0x17, 0 - }; - const hda_nid_t *p; - for (p = pins; *p; p++) - set_eapd(codec, *p, on); -} - -static int find_ext_mic_pin(struct hda_codec *codec); - -static void alc_headset_mic_no_shutup(struct hda_codec *codec) -{ - const struct hda_pincfg *pin; - int mic_pin = find_ext_mic_pin(codec); - int i; - - /* don't shut up pins when unloading the driver; otherwise it breaks - * the default pin setup at the next load of the driver - */ - if (codec->bus->shutdown) - return; - - snd_array_for_each(&codec->init_pins, i, pin) { - /* use read here for syncing after issuing each verb */ - if (pin->nid != mic_pin) - snd_hda_codec_read(codec, pin->nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); - } - - codec->pins_shutup = 1; -} - -static void alc_shutup_pins(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - if (spec->no_shutup_pins) - return; - - switch (codec->core.vendor_id) { - case 0x10ec0236: - case 0x10ec0256: - case 0x10ec0257: - case 0x19e58326: - case 0x10ec0283: - case 0x10ec0285: - case 0x10ec0286: - case 0x10ec0287: - case 0x10ec0288: - case 0x10ec0295: - case 0x10ec0298: - alc_headset_mic_no_shutup(codec); - break; - default: - snd_hda_shutup_pins(codec); - break; - } -} - -/* generic shutup callback; - * just turning off EAPD and a little pause for avoiding pop-noise - */ -static void alc_eapd_shutup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - alc_auto_setup_eapd(codec, false); - if (!spec->no_depop_delay) - msleep(200); - alc_shutup_pins(codec); -} - -/* generic EAPD initialization */ -static void alc_auto_init_amp(struct hda_codec *codec, int type) -{ - alc_auto_setup_eapd(codec, true); - alc_write_gpio(codec); - switch (type) { - case ALC_INIT_DEFAULT: - switch (codec->core.vendor_id) { - case 0x10ec0260: - alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x2010); - break; - case 0x10ec0880: - case 0x10ec0882: - case 0x10ec0883: - case 0x10ec0885: - alc_update_coef_idx(codec, 7, 0, 0x2030); - break; - case 0x10ec0888: - alc888_coef_init(codec); - break; - } - break; - } -} - -/* get a primary headphone pin if available */ -static hda_nid_t alc_get_hp_pin(struct alc_spec *spec) -{ - if (spec->gen.autocfg.hp_pins[0]) - return spec->gen.autocfg.hp_pins[0]; - if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT) - return spec->gen.autocfg.line_out_pins[0]; - return 0; -} - -/* - * Realtek SSID verification - */ - -/* Could be any non-zero and even value. When used as fixup, tells - * the driver to ignore any present sku defines. - */ -#define ALC_FIXUP_SKU_IGNORE (2) - -static void alc_fixup_sku_ignore(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->cdefine.fixup = 1; - spec->cdefine.sku_cfg = ALC_FIXUP_SKU_IGNORE; - } -} - -static void alc_fixup_no_depop_delay(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - struct alc_spec *spec = codec->spec; - - if (action == HDA_FIXUP_ACT_PROBE) { - spec->no_depop_delay = 1; - codec->depop_delay = 0; - } -} - -static int alc_auto_parse_customize_define(struct hda_codec *codec) -{ - unsigned int ass, tmp, i; - unsigned nid = 0; - struct alc_spec *spec = codec->spec; - - spec->cdefine.enable_pcbeep = 1; /* assume always enabled */ - - if (spec->cdefine.fixup) { - ass = spec->cdefine.sku_cfg; - if (ass == ALC_FIXUP_SKU_IGNORE) - return -1; - goto do_sku; - } - - if (!codec->bus->pci) - return -1; - ass = codec->core.subsystem_id & 0xffff; - if (ass != codec->bus->pci->subsystem_device && (ass & 1)) - goto do_sku; - - nid = 0x1d; - if (codec->core.vendor_id == 0x10ec0260) - nid = 0x17; - ass = snd_hda_codec_get_pincfg(codec, nid); - - if (!(ass & 1)) { - codec_info(codec, "%s: SKU not ready 0x%08x\n", - codec->core.chip_name, ass); - return -1; - } - - /* check sum */ - tmp = 0; - for (i = 1; i < 16; i++) { - if ((ass >> i) & 1) - tmp++; - } - if (((ass >> 16) & 0xf) != tmp) - return -1; - - spec->cdefine.port_connectivity = ass >> 30; - spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20; - spec->cdefine.check_sum = (ass >> 16) & 0xf; - spec->cdefine.customization = ass >> 8; -do_sku: - spec->cdefine.sku_cfg = ass; - spec->cdefine.external_amp = (ass & 0x38) >> 3; - spec->cdefine.platform_type = (ass & 0x4) >> 2; - spec->cdefine.swap = (ass & 0x2) >> 1; - spec->cdefine.override = ass & 0x1; - - codec_dbg(codec, "SKU: Nid=0x%x sku_cfg=0x%08x\n", - nid, spec->cdefine.sku_cfg); - codec_dbg(codec, "SKU: port_connectivity=0x%x\n", - spec->cdefine.port_connectivity); - codec_dbg(codec, "SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep); - codec_dbg(codec, "SKU: check_sum=0x%08x\n", spec->cdefine.check_sum); - codec_dbg(codec, "SKU: customization=0x%08x\n", spec->cdefine.customization); - codec_dbg(codec, "SKU: external_amp=0x%x\n", spec->cdefine.external_amp); - codec_dbg(codec, "SKU: platform_type=0x%x\n", spec->cdefine.platform_type); - codec_dbg(codec, "SKU: swap=0x%x\n", spec->cdefine.swap); - codec_dbg(codec, "SKU: override=0x%x\n", spec->cdefine.override); - - return 0; -} - -/* return the position of NID in the list, or -1 if not found */ -static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) -{ - int i; - for (i = 0; i < nums; i++) - if (list[i] == nid) - return i; - return -1; -} -/* return true if the given NID is found in the list */ -static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) -{ - return find_idx_in_nid_list(nid, list, nums) >= 0; -} - -/* check subsystem ID and set up device-specific initialization; - * return 1 if initialized, 0 if invalid SSID - */ -/* 32-bit subsystem ID for BIOS loading in HD Audio codec. - * 31 ~ 16 : Manufacture ID - * 15 ~ 8 : SKU ID - * 7 ~ 0 : Assembly ID - * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36 - */ -static int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports) -{ - unsigned int ass, tmp, i; - unsigned nid; - struct alc_spec *spec = codec->spec; - - if (spec->cdefine.fixup) { - ass = spec->cdefine.sku_cfg; - if (ass == ALC_FIXUP_SKU_IGNORE) - return 0; - goto do_sku; - } - - ass = codec->core.subsystem_id & 0xffff; - if (codec->bus->pci && - ass != codec->bus->pci->subsystem_device && (ass & 1)) - goto do_sku; - - /* invalid SSID, check the special NID pin defcfg instead */ - /* - * 31~30 : port connectivity - * 29~21 : reserve - * 20 : PCBEEP input - * 19~16 : Check sum (15:1) - * 15~1 : Custom - * 0 : override - */ - nid = 0x1d; - if (codec->core.vendor_id == 0x10ec0260) - nid = 0x17; - ass = snd_hda_codec_get_pincfg(codec, nid); - codec_dbg(codec, - "realtek: No valid SSID, checking pincfg 0x%08x for NID 0x%x\n", - ass, nid); - if (!(ass & 1)) - return 0; - if ((ass >> 30) != 1) /* no physical connection */ - return 0; - - /* check sum */ - tmp = 0; - for (i = 1; i < 16; i++) { - if ((ass >> i) & 1) - tmp++; - } - if (((ass >> 16) & 0xf) != tmp) - return 0; -do_sku: - codec_dbg(codec, "realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n", - ass & 0xffff, codec->core.vendor_id); - /* - * 0 : override - * 1 : Swap Jack - * 2 : 0 --> Desktop, 1 --> Laptop - * 3~5 : External Amplifier control - * 7~6 : Reserved - */ - tmp = (ass & 0x38) >> 3; /* external Amp control */ - if (spec->init_amp == ALC_INIT_UNDEFINED) { - switch (tmp) { - case 1: - alc_setup_gpio(codec, 0x01); - break; - case 3: - alc_setup_gpio(codec, 0x02); - break; - case 7: - alc_setup_gpio(codec, 0x04); - break; - case 5: - default: - spec->init_amp = ALC_INIT_DEFAULT; - break; - } - } - - /* is laptop or Desktop and enable the function "Mute internal speaker - * when the external headphone out jack is plugged" - */ - if (!(ass & 0x8000)) - return 1; - /* - * 10~8 : Jack location - * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered - * 14~13: Resvered - * 15 : 1 --> enable the function "Mute internal speaker - * when the external headphone out jack is plugged" - */ - if (!alc_get_hp_pin(spec)) { - hda_nid_t nid; - tmp = (ass >> 11) & 0x3; /* HP to chassis */ - nid = ports[tmp]; - if (found_in_nid_list(nid, spec->gen.autocfg.line_out_pins, - spec->gen.autocfg.line_outs)) - return 1; - spec->gen.autocfg.hp_pins[0] = nid; - } - return 1; -} - -/* Check the validity of ALC subsystem-id - * ports contains an array of 4 pin NIDs for port-A, E, D and I */ -static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports) -{ - if (!alc_subsystem_id(codec, ports)) { - struct alc_spec *spec = codec->spec; - if (spec->init_amp == ALC_INIT_UNDEFINED) { - codec_dbg(codec, - "realtek: Enable default setup for auto mode as fallback\n"); - spec->init_amp = ALC_INIT_DEFAULT; - } - } -} - -/* inverted digital-mic */ -static void alc_fixup_inv_dmic(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - struct alc_spec *spec = codec->spec; - - spec->gen.inv_dmic_split = 1; -} - - -static int alc_build_controls(struct hda_codec *codec) -{ - int err; - - err = snd_hda_gen_build_controls(codec); - if (err < 0) - return err; - - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD); - return 0; -} - - -/* - * Common callbacks - */ - -static void alc_pre_init(struct hda_codec *codec) -{ - alc_fill_eapd_coef(codec); -} - -#define is_s3_resume(codec) \ - ((codec)->core.dev.power.power_state.event == PM_EVENT_RESUME) -#define is_s4_resume(codec) \ - ((codec)->core.dev.power.power_state.event == PM_EVENT_RESTORE) -#define is_s4_suspend(codec) \ - ((codec)->core.dev.power.power_state.event == PM_EVENT_FREEZE) - -static int alc_init(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - /* hibernation resume needs the full chip initialization */ - if (is_s4_resume(codec)) - alc_pre_init(codec); - - if (spec->init_hook) - spec->init_hook(codec); - - spec->gen.skip_verbs = 1; /* applied in below */ - snd_hda_gen_init(codec); - alc_fix_pll(codec); - alc_auto_init_amp(codec, spec->init_amp); - snd_hda_apply_verbs(codec); /* apply verbs here after own init */ - - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); - - return 0; -} - -/* forward declaration */ -static const struct component_master_ops comp_master_ops; - -static void alc_free(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - if (spec) - hda_component_manager_free(&spec->comps, &comp_master_ops); - - snd_hda_gen_free(codec); -} - -static inline void alc_shutup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - if (!snd_hda_get_bool_hint(codec, "shutup")) - return; /* disabled explicitly by hints */ - - if (spec && spec->shutup) - spec->shutup(codec); - else - alc_shutup_pins(codec); -} - -static void alc_power_eapd(struct hda_codec *codec) -{ - alc_auto_setup_eapd(codec, false); -} - -static int alc_suspend(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - alc_shutup(codec); - if (spec && spec->power_hook) - spec->power_hook(codec); - return 0; -} - -static int alc_resume(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - if (!spec->no_depop_delay) - msleep(150); /* to avoid pop noise */ - codec->patch_ops.init(codec); - snd_hda_regmap_sync(codec); - hda_call_check_power_status(codec, 0x01); - return 0; -} - -/* - */ -static const struct hda_codec_ops alc_patch_ops = { - .build_controls = alc_build_controls, - .build_pcms = snd_hda_gen_build_pcms, - .init = alc_init, - .free = alc_free, - .unsol_event = snd_hda_jack_unsol_event, - .resume = alc_resume, - .suspend = alc_suspend, - .check_power_status = snd_hda_gen_check_power_status, -}; - - -#define alc_codec_rename(codec, name) snd_hda_codec_set_name(codec, name) - -/* - * Rename codecs appropriately from COEF value or subvendor id - */ -struct alc_codec_rename_table { - unsigned int vendor_id; - unsigned short coef_mask; - unsigned short coef_bits; - const char *name; -}; - -struct alc_codec_rename_pci_table { - unsigned int codec_vendor_id; - unsigned short pci_subvendor; - unsigned short pci_subdevice; - const char *name; -}; - -static const struct alc_codec_rename_table rename_tbl[] = { - { 0x10ec0221, 0xf00f, 0x1003, "ALC231" }, - { 0x10ec0269, 0xfff0, 0x3010, "ALC277" }, - { 0x10ec0269, 0xf0f0, 0x2010, "ALC259" }, - { 0x10ec0269, 0xf0f0, 0x3010, "ALC258" }, - { 0x10ec0269, 0x00f0, 0x0010, "ALC269VB" }, - { 0x10ec0269, 0xffff, 0xa023, "ALC259" }, - { 0x10ec0269, 0xffff, 0x6023, "ALC281X" }, - { 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" }, - { 0x10ec0269, 0x00f0, 0x0030, "ALC269VD" }, - { 0x10ec0662, 0xffff, 0x4020, "ALC656" }, - { 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" }, - { 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" }, - { 0x10ec0888, 0xf0f0, 0x3020, "ALC886" }, - { 0x10ec0899, 0x2000, 0x2000, "ALC899" }, - { 0x10ec0892, 0xffff, 0x8020, "ALC661" }, - { 0x10ec0892, 0xffff, 0x8011, "ALC661" }, - { 0x10ec0892, 0xffff, 0x4011, "ALC656" }, - { } /* terminator */ -}; - -static const struct alc_codec_rename_pci_table rename_pci_tbl[] = { - { 0x10ec0280, 0x1028, 0, "ALC3220" }, - { 0x10ec0282, 0x1028, 0, "ALC3221" }, - { 0x10ec0283, 0x1028, 0, "ALC3223" }, - { 0x10ec0288, 0x1028, 0, "ALC3263" }, - { 0x10ec0292, 0x1028, 0, "ALC3226" }, - { 0x10ec0293, 0x1028, 0, "ALC3235" }, - { 0x10ec0255, 0x1028, 0, "ALC3234" }, - { 0x10ec0668, 0x1028, 0, "ALC3661" }, - { 0x10ec0275, 0x1028, 0, "ALC3260" }, - { 0x10ec0899, 0x1028, 0, "ALC3861" }, - { 0x10ec0298, 0x1028, 0, "ALC3266" }, - { 0x10ec0236, 0x1028, 0, "ALC3204" }, - { 0x10ec0256, 0x1028, 0, "ALC3246" }, - { 0x10ec0225, 0x1028, 0, "ALC3253" }, - { 0x10ec0295, 0x1028, 0, "ALC3254" }, - { 0x10ec0299, 0x1028, 0, "ALC3271" }, - { 0x10ec0670, 0x1025, 0, "ALC669X" }, - { 0x10ec0676, 0x1025, 0, "ALC679X" }, - { 0x10ec0282, 0x1043, 0, "ALC3229" }, - { 0x10ec0233, 0x1043, 0, "ALC3236" }, - { 0x10ec0280, 0x103c, 0, "ALC3228" }, - { 0x10ec0282, 0x103c, 0, "ALC3227" }, - { 0x10ec0286, 0x103c, 0, "ALC3242" }, - { 0x10ec0290, 0x103c, 0, "ALC3241" }, - { 0x10ec0668, 0x103c, 0, "ALC3662" }, - { 0x10ec0283, 0x17aa, 0, "ALC3239" }, - { 0x10ec0292, 0x17aa, 0, "ALC3232" }, - { 0x10ec0257, 0x12f0, 0, "ALC3328" }, - { } /* terminator */ -}; - -static int alc_codec_rename_from_preset(struct hda_codec *codec) -{ - const struct alc_codec_rename_table *p; - const struct alc_codec_rename_pci_table *q; - - for (p = rename_tbl; p->vendor_id; p++) { - if (p->vendor_id != codec->core.vendor_id) - continue; - if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits) - return alc_codec_rename(codec, p->name); - } - - if (!codec->bus->pci) - return 0; - for (q = rename_pci_tbl; q->codec_vendor_id; q++) { - if (q->codec_vendor_id != codec->core.vendor_id) - continue; - if (q->pci_subvendor != codec->bus->pci->subsystem_vendor) - continue; - if (!q->pci_subdevice || - q->pci_subdevice == codec->bus->pci->subsystem_device) - return alc_codec_rename(codec, q->name); - } - - return 0; -} - - -/* - * Digital-beep handlers - */ -#ifdef CONFIG_SND_HDA_INPUT_BEEP - -/* additional beep mixers; private_value will be overwritten */ -static const struct snd_kcontrol_new alc_beep_mixer[] = { - HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT), - HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT), -}; - -/* set up and create beep controls */ -static int set_beep_amp(struct alc_spec *spec, hda_nid_t nid, - int idx, int dir) -{ - struct snd_kcontrol_new *knew; - unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir); - int i; - - for (i = 0; i < ARRAY_SIZE(alc_beep_mixer); i++) { - knew = snd_hda_gen_add_kctl(&spec->gen, NULL, - &alc_beep_mixer[i]); - if (!knew) - return -ENOMEM; - knew->private_value = beep_amp; - } - return 0; -} - -static const struct snd_pci_quirk beep_allow_list[] = { - SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1), - SND_PCI_QUIRK(0x1043, 0x115d, "ASUS", 1), - SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), - SND_PCI_QUIRK(0x1043, 0x8376, "EeePC", 1), - SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1), - SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1), - SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1), - SND_PCI_QUIRK(0x1458, 0xa002, "GA-MA790X", 1), - SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1), - /* denylist -- no beep available */ - SND_PCI_QUIRK(0x17aa, 0x309e, "Lenovo ThinkCentre M73", 0), - SND_PCI_QUIRK(0x17aa, 0x30a3, "Lenovo ThinkCentre M93", 0), - {} -}; - -static inline int has_cdefine_beep(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - const struct snd_pci_quirk *q; - q = snd_pci_quirk_lookup(codec->bus->pci, beep_allow_list); - if (q) - return q->value; - return spec->cdefine.enable_pcbeep; -} -#else -#define set_beep_amp(spec, nid, idx, dir) 0 -#define has_cdefine_beep(codec) 0 -#endif - -/* parse the BIOS configuration and set up the alc_spec */ -/* return 1 if successful, 0 if the proper config is not found, - * or a negative error code - */ -static int alc_parse_auto_config(struct hda_codec *codec, - const hda_nid_t *ignore_nids, - const hda_nid_t *ssid_nids) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->gen.autocfg; - int err; - - err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids, - spec->parse_flags); - if (err < 0) - return err; - - if (ssid_nids) - alc_ssid_check(codec, ssid_nids); - - err = snd_hda_gen_parse_auto_config(codec, cfg); - if (err < 0) - return err; - - return 1; -} - -/* common preparation job for alc_spec */ -static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid) -{ - struct alc_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL); - int err; - - if (!spec) - return -ENOMEM; - codec->spec = spec; - snd_hda_gen_spec_init(&spec->gen); - spec->gen.mixer_nid = mixer_nid; - spec->gen.own_eapd_ctl = 1; - codec->single_adc_amp = 1; - /* FIXME: do we need this for all Realtek codec models? */ - codec->spdif_status_reset = 1; - codec->forced_resume = 1; - codec->patch_ops = alc_patch_ops; - mutex_init(&spec->coef_mutex); - - err = alc_codec_rename_from_preset(codec); - if (err < 0) { - kfree(spec); - return err; - } - return 0; -} - -static int alc880_parse_auto_config(struct hda_codec *codec) -{ - static const hda_nid_t alc880_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids); -} - -/* - * ALC880 fix-ups - */ -enum { - ALC880_FIXUP_GPIO1, - ALC880_FIXUP_GPIO2, - ALC880_FIXUP_MEDION_RIM, - ALC880_FIXUP_LG, - ALC880_FIXUP_LG_LW25, - ALC880_FIXUP_W810, - ALC880_FIXUP_EAPD_COEF, - ALC880_FIXUP_TCL_S700, - ALC880_FIXUP_VOL_KNOB, - ALC880_FIXUP_FUJITSU, - ALC880_FIXUP_F1734, - ALC880_FIXUP_UNIWILL, - ALC880_FIXUP_UNIWILL_DIG, - ALC880_FIXUP_Z71V, - ALC880_FIXUP_ASUS_W5A, - ALC880_FIXUP_3ST_BASE, - ALC880_FIXUP_3ST, - ALC880_FIXUP_3ST_DIG, - ALC880_FIXUP_5ST_BASE, - ALC880_FIXUP_5ST, - ALC880_FIXUP_5ST_DIG, - ALC880_FIXUP_6ST_BASE, - ALC880_FIXUP_6ST, - ALC880_FIXUP_6ST_DIG, - ALC880_FIXUP_6ST_AUTOMUTE, -}; - -/* enable the volume-knob widget support on NID 0x21 */ -static void alc880_fixup_vol_knob(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - if (action == HDA_FIXUP_ACT_PROBE) - snd_hda_jack_detect_enable_callback(codec, 0x21, - alc_update_knob_master); -} - -static const struct hda_fixup alc880_fixups[] = { - [ALC880_FIXUP_GPIO1] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_gpio1, - }, - [ALC880_FIXUP_GPIO2] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_gpio2, - }, - [ALC880_FIXUP_MEDION_RIM] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 }, - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_GPIO2, - }, - [ALC880_FIXUP_LG] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - /* disable bogus unused pins */ - { 0x16, 0x411111f0 }, - { 0x18, 0x411111f0 }, - { 0x1a, 0x411111f0 }, - { } - } - }, - [ALC880_FIXUP_LG_LW25] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x1a, 0x0181344f }, /* line-in */ - { 0x1b, 0x0321403f }, /* headphone */ - { } - } - }, - [ALC880_FIXUP_W810] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - /* disable bogus unused pins */ - { 0x17, 0x411111f0 }, - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_GPIO2, - }, - [ALC880_FIXUP_EAPD_COEF] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - /* change to EAPD mode */ - { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 }, - {} - }, - }, - [ALC880_FIXUP_TCL_S700] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - /* change to EAPD mode */ - { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 }, - {} - }, - .chained = true, - .chain_id = ALC880_FIXUP_GPIO2, - }, - [ALC880_FIXUP_VOL_KNOB] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc880_fixup_vol_knob, - }, - [ALC880_FIXUP_FUJITSU] = { - /* override all pins as BIOS on old Amilo is broken */ - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x0121401f }, /* HP */ - { 0x15, 0x99030120 }, /* speaker */ - { 0x16, 0x99030130 }, /* bass speaker */ - { 0x17, 0x411111f0 }, /* N/A */ - { 0x18, 0x411111f0 }, /* N/A */ - { 0x19, 0x01a19950 }, /* mic-in */ - { 0x1a, 0x411111f0 }, /* N/A */ - { 0x1b, 0x411111f0 }, /* N/A */ - { 0x1c, 0x411111f0 }, /* N/A */ - { 0x1d, 0x411111f0 }, /* N/A */ - { 0x1e, 0x01454140 }, /* SPDIF out */ - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_VOL_KNOB, - }, - [ALC880_FIXUP_F1734] = { - /* almost compatible with FUJITSU, but no bass and SPDIF */ - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x0121401f }, /* HP */ - { 0x15, 0x99030120 }, /* speaker */ - { 0x16, 0x411111f0 }, /* N/A */ - { 0x17, 0x411111f0 }, /* N/A */ - { 0x18, 0x411111f0 }, /* N/A */ - { 0x19, 0x01a19950 }, /* mic-in */ - { 0x1a, 0x411111f0 }, /* N/A */ - { 0x1b, 0x411111f0 }, /* N/A */ - { 0x1c, 0x411111f0 }, /* N/A */ - { 0x1d, 0x411111f0 }, /* N/A */ - { 0x1e, 0x411111f0 }, /* N/A */ - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_VOL_KNOB, - }, - [ALC880_FIXUP_UNIWILL] = { - /* need to fix HP and speaker pins to be parsed correctly */ - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x0121411f }, /* HP */ - { 0x15, 0x99030120 }, /* speaker */ - { 0x16, 0x99030130 }, /* bass speaker */ - { } - }, - }, - [ALC880_FIXUP_UNIWILL_DIG] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - /* disable bogus unused pins */ - { 0x17, 0x411111f0 }, - { 0x19, 0x411111f0 }, - { 0x1b, 0x411111f0 }, - { 0x1f, 0x411111f0 }, - { } - } - }, - [ALC880_FIXUP_Z71V] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - /* set up the whole pins as BIOS is utterly broken */ - { 0x14, 0x99030120 }, /* speaker */ - { 0x15, 0x0121411f }, /* HP */ - { 0x16, 0x411111f0 }, /* N/A */ - { 0x17, 0x411111f0 }, /* N/A */ - { 0x18, 0x01a19950 }, /* mic-in */ - { 0x19, 0x411111f0 }, /* N/A */ - { 0x1a, 0x01813031 }, /* line-in */ - { 0x1b, 0x411111f0 }, /* N/A */ - { 0x1c, 0x411111f0 }, /* N/A */ - { 0x1d, 0x411111f0 }, /* N/A */ - { 0x1e, 0x0144111e }, /* SPDIF */ - { } - } - }, - [ALC880_FIXUP_ASUS_W5A] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - /* set up the whole pins as BIOS is utterly broken */ - { 0x14, 0x0121411f }, /* HP */ - { 0x15, 0x411111f0 }, /* N/A */ - { 0x16, 0x411111f0 }, /* N/A */ - { 0x17, 0x411111f0 }, /* N/A */ - { 0x18, 0x90a60160 }, /* mic */ - { 0x19, 0x411111f0 }, /* N/A */ - { 0x1a, 0x411111f0 }, /* N/A */ - { 0x1b, 0x411111f0 }, /* N/A */ - { 0x1c, 0x411111f0 }, /* N/A */ - { 0x1d, 0x411111f0 }, /* N/A */ - { 0x1e, 0xb743111e }, /* SPDIF out */ - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_GPIO1, - }, - [ALC880_FIXUP_3ST_BASE] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x01014010 }, /* line-out */ - { 0x15, 0x411111f0 }, /* N/A */ - { 0x16, 0x411111f0 }, /* N/A */ - { 0x17, 0x411111f0 }, /* N/A */ - { 0x18, 0x01a19c30 }, /* mic-in */ - { 0x19, 0x0121411f }, /* HP */ - { 0x1a, 0x01813031 }, /* line-in */ - { 0x1b, 0x02a19c40 }, /* front-mic */ - { 0x1c, 0x411111f0 }, /* N/A */ - { 0x1d, 0x411111f0 }, /* N/A */ - /* 0x1e is filled in below */ - { 0x1f, 0x411111f0 }, /* N/A */ - { } - } - }, - [ALC880_FIXUP_3ST] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x1e, 0x411111f0 }, /* N/A */ - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_3ST_BASE, - }, - [ALC880_FIXUP_3ST_DIG] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x1e, 0x0144111e }, /* SPDIF */ - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_3ST_BASE, - }, - [ALC880_FIXUP_5ST_BASE] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x01014010 }, /* front */ - { 0x15, 0x411111f0 }, /* N/A */ - { 0x16, 0x01011411 }, /* CLFE */ - { 0x17, 0x01016412 }, /* surr */ - { 0x18, 0x01a19c30 }, /* mic-in */ - { 0x19, 0x0121411f }, /* HP */ - { 0x1a, 0x01813031 }, /* line-in */ - { 0x1b, 0x02a19c40 }, /* front-mic */ - { 0x1c, 0x411111f0 }, /* N/A */ - { 0x1d, 0x411111f0 }, /* N/A */ - /* 0x1e is filled in below */ - { 0x1f, 0x411111f0 }, /* N/A */ - { } - } - }, - [ALC880_FIXUP_5ST] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x1e, 0x411111f0 }, /* N/A */ - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_5ST_BASE, - }, - [ALC880_FIXUP_5ST_DIG] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x1e, 0x0144111e }, /* SPDIF */ - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_5ST_BASE, - }, - [ALC880_FIXUP_6ST_BASE] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x01014010 }, /* front */ - { 0x15, 0x01016412 }, /* surr */ - { 0x16, 0x01011411 }, /* CLFE */ - { 0x17, 0x01012414 }, /* side */ - { 0x18, 0x01a19c30 }, /* mic-in */ - { 0x19, 0x02a19c40 }, /* front-mic */ - { 0x1a, 0x01813031 }, /* line-in */ - { 0x1b, 0x0121411f }, /* HP */ - { 0x1c, 0x411111f0 }, /* N/A */ - { 0x1d, 0x411111f0 }, /* N/A */ - /* 0x1e is filled in below */ - { 0x1f, 0x411111f0 }, /* N/A */ - { } - } - }, - [ALC880_FIXUP_6ST] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x1e, 0x411111f0 }, /* N/A */ - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_6ST_BASE, - }, - [ALC880_FIXUP_6ST_DIG] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x1e, 0x0144111e }, /* SPDIF */ - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_6ST_BASE, - }, - [ALC880_FIXUP_6ST_AUTOMUTE] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x1b, 0x0121401f }, /* HP with jack detect */ - { } - }, - .chained_before = true, - .chain_id = ALC880_FIXUP_6ST_BASE, - }, -}; - -static const struct hda_quirk alc880_fixup_tbl[] = { - SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810), - SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS W5A", ALC880_FIXUP_ASUS_W5A), - SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V), - SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1), - SND_PCI_QUIRK(0x147b, 0x1045, "ABit AA8XE", ALC880_FIXUP_6ST_AUTOMUTE), - SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2), - SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF), - SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG), - SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_FIXUP_F1734), - SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_FIXUP_UNIWILL), - SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB), - SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810), - SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM), - SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST_AUTOMUTE), - SND_PCI_QUIRK(0x1734, 0x107c, "FSC Amilo M1437", ALC880_FIXUP_FUJITSU), - SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU), - SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734), - SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU), - SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG), - SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG), - SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG), - SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_FIXUP_LG_LW25), - SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700), - - /* Below is the copied entries from alc880_quirks.c. - * It's not quite sure whether BIOS sets the correct pin-config table - * on these machines, thus they are kept to be compatible with - * the old static quirks. Once when it's confirmed to work without - * these overrides, it'd be better to remove. - */ - SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_FIXUP_6ST), - SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_FIXUP_3ST_DIG), - SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_FIXUP_6ST_DIG), - SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_FIXUP_6ST_DIG), - SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_FIXUP_6ST_DIG), - SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_FIXUP_3ST_DIG), - SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_FIXUP_3ST), - SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_FIXUP_6ST_DIG), - SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_FIXUP_3ST), - SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_FIXUP_3ST), - SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_FIXUP_5ST), - SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_FIXUP_5ST), - SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_FIXUP_5ST), - SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_FIXUP_6ST_DIG), - SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_FIXUP_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_FIXUP_6ST_DIG), - SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_FIXUP_6ST_DIG), - SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_FIXUP_6ST_DIG), /* broken BIOS */ - SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_FIXUP_6ST_DIG), - SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_FIXUP_3ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_FIXUP_3ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_FIXUP_3ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_FIXUP_5ST_DIG), - /* default Intel */ - SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_FIXUP_3ST), - SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_FIXUP_6ST_DIG), - {} -}; - -static const struct hda_model_fixup alc880_fixup_models[] = { - {.id = ALC880_FIXUP_3ST, .name = "3stack"}, - {.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"}, - {.id = ALC880_FIXUP_5ST, .name = "5stack"}, - {.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"}, - {.id = ALC880_FIXUP_6ST, .name = "6stack"}, - {.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"}, - {.id = ALC880_FIXUP_6ST_AUTOMUTE, .name = "6stack-automute"}, - {} -}; - - -/* - * OK, here we have finally the patch for ALC880 - */ -static int patch_alc880(struct hda_codec *codec) -{ - struct alc_spec *spec; - int err; - - err = alc_alloc_spec(codec, 0x0b); - if (err < 0) - return err; - - spec = codec->spec; - spec->gen.need_dac_fix = 1; - spec->gen.beep_nid = 0x01; - - codec->patch_ops.unsol_event = alc880_unsol_event; - - alc_pre_init(codec); - - snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl, - alc880_fixups); - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - - /* automatic parse from the BIOS config */ - err = alc880_parse_auto_config(codec); - if (err < 0) - goto error; - - if (!spec->gen.no_analog) { - err = set_beep_amp(spec, 0x0b, 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; -} - - -/* - * ALC260 support - */ -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; -} - - -/* - * ALC882/883/885/888/889 support - * - * ALC882 is almost identical with ALC880 but has cleaner and more flexible - * configuration. Each pin widget can choose any input DACs and a mixer. - * Each ADC is connected from a mixer of all inputs. This makes possible - * 6-channel independent captures. - * - * In addition, an independent DAC for the multi-playback (not used in this - * driver yet). - */ - -/* - * Pin config fixes - */ -enum { - ALC882_FIXUP_ABIT_AW9D_MAX, - ALC882_FIXUP_LENOVO_Y530, - ALC882_FIXUP_PB_M5210, - ALC882_FIXUP_ACER_ASPIRE_7736, - ALC882_FIXUP_ASUS_W90V, - ALC889_FIXUP_CD, - ALC889_FIXUP_FRONT_HP_NO_PRESENCE, - ALC889_FIXUP_VAIO_TT, - ALC888_FIXUP_EEE1601, - ALC886_FIXUP_EAPD, - ALC882_FIXUP_EAPD, - ALC883_FIXUP_EAPD, - ALC883_FIXUP_ACER_EAPD, - ALC882_FIXUP_GPIO1, - ALC882_FIXUP_GPIO2, - ALC882_FIXUP_GPIO3, - ALC889_FIXUP_COEF, - ALC882_FIXUP_ASUS_W2JC, - ALC882_FIXUP_ACER_ASPIRE_4930G, - ALC882_FIXUP_ACER_ASPIRE_8930G, - ALC882_FIXUP_ASPIRE_8930G_VERBS, - ALC885_FIXUP_MACPRO_GPIO, - ALC889_FIXUP_DAC_ROUTE, - ALC889_FIXUP_MBP_VREF, - ALC889_FIXUP_IMAC91_VREF, - ALC889_FIXUP_MBA11_VREF, - ALC889_FIXUP_MBA21_VREF, - ALC889_FIXUP_MP11_VREF, - ALC889_FIXUP_MP41_VREF, - ALC882_FIXUP_INV_DMIC, - ALC882_FIXUP_NO_PRIMARY_HP, - ALC887_FIXUP_ASUS_BASS, - ALC887_FIXUP_BASS_CHMAP, - ALC1220_FIXUP_GB_DUAL_CODECS, - ALC1220_FIXUP_GB_X570, - ALC1220_FIXUP_CLEVO_P950, - ALC1220_FIXUP_CLEVO_PB51ED, - ALC1220_FIXUP_CLEVO_PB51ED_PINS, - ALC887_FIXUP_ASUS_AUDIO, - ALC887_FIXUP_ASUS_HMIC, - ALCS1200A_FIXUP_MIC_VREF, - ALC888VD_FIXUP_MIC_100VREF, -}; - -static void alc889_fixup_coef(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - if (action != HDA_FIXUP_ACT_INIT) - return; - alc_update_coef_idx(codec, 7, 0, 0x2030); -} - -/* set up GPIO at initialization */ -static void alc885_fixup_macpro_gpio(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - struct alc_spec *spec = codec->spec; - - spec->gpio_write_delay = true; - alc_fixup_gpio3(codec, fix, action); -} - -/* Fix the connection of some pins for ALC889: - * At least, Acer Aspire 5935 shows the connections to DAC3/4 don't - * work correctly (bko#42740) - */ -static void alc889_fixup_dac_route(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - if (action == HDA_FIXUP_ACT_PRE_PROBE) { - /* fake the connections during parsing the tree */ - static const hda_nid_t conn1[] = { 0x0c, 0x0d }; - static const hda_nid_t conn2[] = { 0x0e, 0x0f }; - snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1); - snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn1), conn1); - snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn2), conn2); - snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn2), conn2); - } else if (action == HDA_FIXUP_ACT_PROBE) { - /* restore the connections */ - static const hda_nid_t conn[] = { 0x0c, 0x0d, 0x0e, 0x0f, 0x26 }; - snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn); - snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn), conn); - snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn), conn); - snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn), conn); - } -} - -/* Set VREF on HP pin */ -static void alc889_fixup_mbp_vref(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - static const hda_nid_t nids[] = { 0x14, 0x15, 0x19 }; - struct alc_spec *spec = codec->spec; - int i; - - if (action != HDA_FIXUP_ACT_INIT) - return; - for (i = 0; i < ARRAY_SIZE(nids); i++) { - unsigned int val = snd_hda_codec_get_pincfg(codec, nids[i]); - if (get_defcfg_device(val) != AC_JACK_HP_OUT) - continue; - val = snd_hda_codec_get_pin_target(codec, nids[i]); - val |= AC_PINCTL_VREF_80; - snd_hda_set_pin_ctl(codec, nids[i], val); - spec->gen.keep_vref_in_automute = 1; - break; - } -} - -static void alc889_fixup_mac_pins(struct hda_codec *codec, - const hda_nid_t *nids, int num_nids) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < num_nids; i++) { - unsigned int val; - val = snd_hda_codec_get_pin_target(codec, nids[i]); - val |= AC_PINCTL_VREF_50; - snd_hda_set_pin_ctl(codec, nids[i], val); - } - spec->gen.keep_vref_in_automute = 1; -} - -/* Set VREF on speaker pins on imac91 */ -static void alc889_fixup_imac91_vref(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - static const hda_nid_t nids[] = { 0x18, 0x1a }; - - if (action == HDA_FIXUP_ACT_INIT) - alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids)); -} - -/* Set VREF on speaker pins on mba11 */ -static void alc889_fixup_mba11_vref(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - static const hda_nid_t nids[] = { 0x18 }; - - if (action == HDA_FIXUP_ACT_INIT) - alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids)); -} - -/* Set VREF on speaker pins on mba21 */ -static void alc889_fixup_mba21_vref(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - static const hda_nid_t nids[] = { 0x18, 0x19 }; - - if (action == HDA_FIXUP_ACT_INIT) - alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids)); -} - -/* Don't take HP output as primary - * Strangely, the speaker output doesn't work on Vaio Z and some Vaio - * all-in-one desktop PCs (for example VGC-LN51JGB) through DAC 0x05 - */ -static void alc882_fixup_no_primary_hp(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.no_primary_hp = 1; - spec->gen.no_multi_io = 1; - } -} - -static void alc_fixup_bass_chmap(struct hda_codec *codec, - const struct hda_fixup *fix, int action); - -/* For dual-codec configuration, we need to disable some features to avoid - * conflicts of kctls and PCM streams - */ -static void alc_fixup_dual_codecs(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - struct alc_spec *spec = codec->spec; - - if (action != HDA_FIXUP_ACT_PRE_PROBE) - return; - /* disable vmaster */ - spec->gen.suppress_vmaster = 1; - /* auto-mute and auto-mic switch don't work with multiple codecs */ - spec->gen.suppress_auto_mute = 1; - spec->gen.suppress_auto_mic = 1; - /* disable aamix as well */ - spec->gen.mixer_nid = 0; - /* add location prefix to avoid conflicts */ - codec->force_pin_prefix = 1; -} - -static void rename_ctl(struct hda_codec *codec, const char *oldname, - const char *newname) -{ - struct snd_kcontrol *kctl; - - kctl = snd_hda_find_mixer_ctl(codec, oldname); - if (kctl) - snd_ctl_rename(codec->card, kctl, newname); -} - -static void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec, - const struct hda_fixup *fix, - int action) -{ - alc_fixup_dual_codecs(codec, fix, action); - switch (action) { - case HDA_FIXUP_ACT_PRE_PROBE: - /* override card longname to provide a unique UCM profile */ - strcpy(codec->card->longname, "HDAudio-Gigabyte-ALC1220DualCodecs"); - break; - case HDA_FIXUP_ACT_BUILD: - /* rename Capture controls depending on the codec */ - rename_ctl(codec, "Capture Volume", - codec->addr == 0 ? - "Rear-Panel Capture Volume" : - "Front-Panel Capture Volume"); - rename_ctl(codec, "Capture Switch", - codec->addr == 0 ? - "Rear-Panel Capture Switch" : - "Front-Panel Capture Switch"); - break; - } -} - -static void alc1220_fixup_gb_x570(struct hda_codec *codec, - const struct hda_fixup *fix, - int action) -{ - static const hda_nid_t conn1[] = { 0x0c }; - static const struct coef_fw gb_x570_coefs[] = { - WRITE_COEF(0x07, 0x03c0), - WRITE_COEF(0x1a, 0x01c1), - WRITE_COEF(0x1b, 0x0202), - WRITE_COEF(0x43, 0x3005), - {} - }; - - switch (action) { - case HDA_FIXUP_ACT_PRE_PROBE: - snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1); - snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1); - break; - case HDA_FIXUP_ACT_INIT: - alc_process_coef_fw(codec, gb_x570_coefs); - break; - } -} - -static void alc1220_fixup_clevo_p950(struct hda_codec *codec, - const struct hda_fixup *fix, - int action) -{ - static const hda_nid_t conn1[] = { 0x0c }; - - if (action != HDA_FIXUP_ACT_PRE_PROBE) - return; - - alc_update_coef_idx(codec, 0x7, 0, 0x3c3); - /* We therefore want to make sure 0x14 (front headphone) and - * 0x1b (speakers) use the stereo DAC 0x02 - */ - snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1); - snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1); -} - -static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec, - const struct hda_fixup *fix, int action); - -static void alc1220_fixup_clevo_pb51ed(struct hda_codec *codec, - const struct hda_fixup *fix, - int action) -{ - alc1220_fixup_clevo_p950(codec, fix, action); - alc_fixup_headset_mode_no_hp_mic(codec, fix, action); -} - -static void alc887_asus_hp_automute_hook(struct hda_codec *codec, - struct hda_jack_callback *jack) -{ - struct alc_spec *spec = codec->spec; - unsigned int vref; - - snd_hda_gen_hp_automute(codec, jack); - - if (spec->gen.hp_jack_present) - vref = AC_PINCTL_VREF_80; - else - vref = AC_PINCTL_VREF_HIZ; - snd_hda_set_pin_ctl(codec, 0x19, PIN_HP | vref); -} - -static void alc887_fixup_asus_jack(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - struct alc_spec *spec = codec->spec; - if (action != HDA_FIXUP_ACT_PROBE) - return; - snd_hda_set_pin_ctl_cache(codec, 0x1b, PIN_HP); - spec->gen.hp_automute_hook = alc887_asus_hp_automute_hook; -} - -static const struct hda_fixup alc882_fixups[] = { - [ALC882_FIXUP_ABIT_AW9D_MAX] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x15, 0x01080104 }, /* side */ - { 0x16, 0x01011012 }, /* rear */ - { 0x17, 0x01016011 }, /* clfe */ - { } - } - }, - [ALC882_FIXUP_LENOVO_Y530] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x15, 0x99130112 }, /* rear int speakers */ - { 0x16, 0x99130111 }, /* subwoofer */ - { } - } - }, - [ALC882_FIXUP_PB_M5210] = { - .type = HDA_FIXUP_PINCTLS, - .v.pins = (const struct hda_pintbl[]) { - { 0x19, PIN_VREF50 }, - {} - } - }, - [ALC882_FIXUP_ACER_ASPIRE_7736] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_sku_ignore, - }, - [ALC882_FIXUP_ASUS_W90V] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x16, 0x99130110 }, /* fix sequence for CLFE */ - { } - } - }, - [ALC889_FIXUP_CD] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x1c, 0x993301f0 }, /* CD */ - { } - } - }, - [ALC889_FIXUP_FRONT_HP_NO_PRESENCE] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x1b, 0x02214120 }, /* Front HP jack is flaky, disable jack detect */ - { } - }, - .chained = true, - .chain_id = ALC889_FIXUP_CD, - }, - [ALC889_FIXUP_VAIO_TT] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x17, 0x90170111 }, /* hidden surround speaker */ - { } - } - }, - [ALC888_FIXUP_EEE1601] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x0838 }, - { } - } - }, - [ALC886_FIXUP_EAPD] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - /* change to EAPD mode */ - { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x0068 }, - { } - } - }, - [ALC882_FIXUP_EAPD] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - /* change to EAPD mode */ - { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 }, - { } - } - }, - [ALC883_FIXUP_EAPD] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - /* change to EAPD mode */ - { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 }, - { } - } - }, - [ALC883_FIXUP_ACER_EAPD] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - /* eanable EAPD on Acer laptops */ - { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 }, - { } - } - }, - [ALC882_FIXUP_GPIO1] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_gpio1, - }, - [ALC882_FIXUP_GPIO2] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_gpio2, - }, - [ALC882_FIXUP_GPIO3] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_gpio3, - }, - [ALC882_FIXUP_ASUS_W2JC] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_gpio1, - .chained = true, - .chain_id = ALC882_FIXUP_EAPD, - }, - [ALC889_FIXUP_COEF] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc889_fixup_coef, - }, - [ALC882_FIXUP_ACER_ASPIRE_4930G] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x16, 0x99130111 }, /* CLFE speaker */ - { 0x17, 0x99130112 }, /* surround speaker */ - { } - }, - .chained = true, - .chain_id = ALC882_FIXUP_GPIO1, - }, - [ALC882_FIXUP_ACER_ASPIRE_8930G] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x16, 0x99130111 }, /* CLFE speaker */ - { 0x1b, 0x99130112 }, /* surround speaker */ - { } - }, - .chained = true, - .chain_id = ALC882_FIXUP_ASPIRE_8930G_VERBS, - }, - [ALC882_FIXUP_ASPIRE_8930G_VERBS] = { - /* additional init verbs for Acer Aspire 8930G */ - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - /* Enable all DACs */ - /* DAC DISABLE/MUTE 1? */ - /* setting bits 1-5 disables DAC nids 0x02-0x06 - * apparently. Init=0x38 */ - { 0x20, AC_VERB_SET_COEF_INDEX, 0x03 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, - /* DAC DISABLE/MUTE 2? */ - /* some bit here disables the other DACs. - * Init=0x4900 */ - { 0x20, AC_VERB_SET_COEF_INDEX, 0x08 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, - /* DMIC fix - * This laptop has a stereo digital microphone. - * The mics are only 1cm apart which makes the stereo - * useless. However, either the mic or the ALC889 - * makes the signal become a difference/sum signal - * instead of standard stereo, which is annoying. - * So instead we flip this bit which makes the - * codec replicate the sum signal to both channels, - * turning it into a normal mono mic. - */ - /* DMIC_CONTROL? Init value = 0x0001 */ - { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x0003 }, - { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 }, - { } - }, - .chained = true, - .chain_id = ALC882_FIXUP_GPIO1, - }, - [ALC885_FIXUP_MACPRO_GPIO] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc885_fixup_macpro_gpio, - }, - [ALC889_FIXUP_DAC_ROUTE] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc889_fixup_dac_route, - }, - [ALC889_FIXUP_MBP_VREF] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc889_fixup_mbp_vref, - .chained = true, - .chain_id = ALC882_FIXUP_GPIO1, - }, - [ALC889_FIXUP_IMAC91_VREF] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc889_fixup_imac91_vref, - .chained = true, - .chain_id = ALC882_FIXUP_GPIO1, - }, - [ALC889_FIXUP_MBA11_VREF] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc889_fixup_mba11_vref, - .chained = true, - .chain_id = ALC889_FIXUP_MBP_VREF, - }, - [ALC889_FIXUP_MBA21_VREF] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc889_fixup_mba21_vref, - .chained = true, - .chain_id = ALC889_FIXUP_MBP_VREF, - }, - [ALC889_FIXUP_MP11_VREF] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc889_fixup_mba11_vref, - .chained = true, - .chain_id = ALC885_FIXUP_MACPRO_GPIO, - }, - [ALC889_FIXUP_MP41_VREF] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc889_fixup_mbp_vref, - .chained = true, - .chain_id = ALC885_FIXUP_MACPRO_GPIO, - }, - [ALC882_FIXUP_INV_DMIC] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_inv_dmic, - }, - [ALC882_FIXUP_NO_PRIMARY_HP] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc882_fixup_no_primary_hp, - }, - [ALC887_FIXUP_ASUS_BASS] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - {0x16, 0x99130130}, /* bass speaker */ - {} - }, - .chained = true, - .chain_id = ALC887_FIXUP_BASS_CHMAP, - }, - [ALC887_FIXUP_BASS_CHMAP] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_bass_chmap, - }, - [ALC1220_FIXUP_GB_DUAL_CODECS] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc1220_fixup_gb_dual_codecs, - }, - [ALC1220_FIXUP_GB_X570] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc1220_fixup_gb_x570, - }, - [ALC1220_FIXUP_CLEVO_P950] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc1220_fixup_clevo_p950, - }, - [ALC1220_FIXUP_CLEVO_PB51ED] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc1220_fixup_clevo_pb51ed, - }, - [ALC1220_FIXUP_CLEVO_PB51ED_PINS] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */ - {} - }, - .chained = true, - .chain_id = ALC1220_FIXUP_CLEVO_PB51ED, - }, - [ALC887_FIXUP_ASUS_AUDIO] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x15, 0x02a14150 }, /* use as headset mic, without its own jack detect */ - { 0x19, 0x22219420 }, - {} - }, - }, - [ALC887_FIXUP_ASUS_HMIC] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc887_fixup_asus_jack, - .chained = true, - .chain_id = ALC887_FIXUP_ASUS_AUDIO, - }, - [ALCS1200A_FIXUP_MIC_VREF] = { - .type = HDA_FIXUP_PINCTLS, - .v.pins = (const struct hda_pintbl[]) { - { 0x18, PIN_VREF50 }, /* rear mic */ - { 0x19, PIN_VREF50 }, /* front mic */ - {} - } - }, - [ALC888VD_FIXUP_MIC_100VREF] = { - .type = HDA_FIXUP_PINCTLS, - .v.pins = (const struct hda_pintbl[]) { - { 0x18, PIN_VREF100 }, /* headset mic */ - {} - } - }, -}; - -static const struct hda_quirk alc882_fixup_tbl[] = { - SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD), - SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), - SND_PCI_QUIRK(0x1025, 0x0107, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), - SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_FIXUP_ACER_EAPD), - SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), - SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_FIXUP_ACER_EAPD), - SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_FIXUP_ACER_EAPD), - SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G", - ALC882_FIXUP_ACER_ASPIRE_4930G), - SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G", - ALC882_FIXUP_ACER_ASPIRE_4930G), - SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G", - ALC882_FIXUP_ACER_ASPIRE_8930G), - SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G", - ALC882_FIXUP_ACER_ASPIRE_8930G), - SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G", - ALC882_FIXUP_ACER_ASPIRE_4930G), - SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210), - SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", - ALC882_FIXUP_ACER_ASPIRE_4930G), - SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G", - ALC882_FIXUP_ACER_ASPIRE_4930G), - SND_PCI_QUIRK(0x1025, 0x021e, "Acer Aspire 5739G", - ALC882_FIXUP_ACER_ASPIRE_4930G), - SND_PCI_QUIRK(0x1025, 0x0259, "Acer Aspire 5935", ALC889_FIXUP_DAC_ROUTE), - SND_PCI_QUIRK(0x1025, 0x026b, "Acer Aspire 8940G", ALC882_FIXUP_ACER_ASPIRE_8930G), - SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", ALC882_FIXUP_ACER_ASPIRE_7736), - SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_FIXUP_EAPD), - SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V), - SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC), - SND_PCI_QUIRK(0x1043, 0x2390, "Asus D700SA", ALC887_FIXUP_ASUS_HMIC), - SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601), - SND_PCI_QUIRK(0x1043, 0x84bc, "ASUS ET2700", ALC887_FIXUP_ASUS_BASS), - SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3), - SND_PCI_QUIRK(0x1043, 0x8797, "ASUS TUF B550M-PLUS", ALCS1200A_FIXUP_MIC_VREF), - SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP), - SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP), - SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT), - SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP), - SND_PCI_QUIRK(0x104d, 0x9060, "Sony Vaio VPCL14M1R", ALC882_FIXUP_NO_PRIMARY_HP), - - /* All Apple entries are in codec SSIDs */ - SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF), - SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF), - SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF), - SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC889_FIXUP_MP11_VREF), - SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO), - SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO), - SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF), - SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF), - SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD), - SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBA11_VREF), - SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBA21_VREF), - SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF), - SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF), - SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO), - SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF), - SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF), - SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF), - SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 4,1/5,1", ALC889_FIXUP_MP41_VREF), - SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF), - SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF), - SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF), - SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_MBA11_VREF), - - SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD), - SND_PCI_QUIRK(0x10ec, 0x12d8, "iBase Elo Touch", ALC888VD_FIXUP_MIC_100VREF), - SND_PCI_QUIRK(0x13fe, 0x1009, "Advantech MIT-W101", ALC886_FIXUP_EAPD), - SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE), - SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS), - SND_PCI_QUIRK(0x1458, 0xa0cd, "Gigabyte X570 Aorus Master", ALC1220_FIXUP_GB_X570), - SND_PCI_QUIRK(0x1458, 0xa0ce, "Gigabyte X570 Aorus Xtreme", ALC1220_FIXUP_GB_X570), - SND_PCI_QUIRK(0x1458, 0xa0d5, "Gigabyte X570S Aorus Master", ALC1220_FIXUP_GB_X570), - SND_PCI_QUIRK(0x1462, 0x11f7, "MSI-GE63", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1462, 0x1228, "MSI-GP63", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1462, 0x1229, "MSI-GP73", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1462, 0x1275, "MSI-GL63", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1462, 0x1276, "MSI-GL73", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1462, 0x1293, "MSI-GP65", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD), - SND_PCI_QUIRK(0x1462, 0xcc34, "MSI Godlike X570", ALC1220_FIXUP_GB_DUAL_CODECS), - SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS), - SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), - SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX), - SND_PCI_QUIRK(0x1558, 0x3702, "Clevo X370SN[VW]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x50d3, "Clevo PC50[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x5802, "Clevo X58[05]WN[RST]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x65e1, "Clevo PB51[ED][DF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x65e5, "Clevo PC50D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x65f1, "Clevo PC50HS", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x65f5, "Clevo PD50PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x66a2, "Clevo PE60RNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x66a6, "Clevo PE60SN[CDE]-[GS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x67f1, "Clevo PC70H[PRS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x67f5, "Clevo PD70PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x70d1, "Clevo PC70[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x7714, "Clevo X170SM", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x7715, "Clevo X170KM-G", ALC1220_FIXUP_CLEVO_PB51ED), - SND_PCI_QUIRK(0x1558, 0x9501, "Clevo P950HR", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x9506, "Clevo P955HQ", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x950a, "Clevo P955H[PR]", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x95e1, "Clevo P95xER", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x95e2, "Clevo P950ER", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x95e3, "Clevo P955[ER]T", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x95e4, "Clevo P955ER", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x95e5, "Clevo P955EE6", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x95e6, "Clevo P950R[CDF]", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x96e1, "Clevo P960[ER][CDFN]-K", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x97e1, "Clevo P970[ER][CDFN]", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x97e2, "Clevo P970RC-M", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0xd502, "Clevo PD50SNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - 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), - SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_FIXUP_COEF), - {} -}; - -static const struct hda_model_fixup alc882_fixup_models[] = { - {.id = ALC882_FIXUP_ABIT_AW9D_MAX, .name = "abit-aw9d"}, - {.id = ALC882_FIXUP_LENOVO_Y530, .name = "lenovo-y530"}, - {.id = ALC882_FIXUP_ACER_ASPIRE_7736, .name = "acer-aspire-7736"}, - {.id = ALC882_FIXUP_ASUS_W90V, .name = "asus-w90v"}, - {.id = ALC889_FIXUP_CD, .name = "cd"}, - {.id = ALC889_FIXUP_FRONT_HP_NO_PRESENCE, .name = "no-front-hp"}, - {.id = ALC889_FIXUP_VAIO_TT, .name = "vaio-tt"}, - {.id = ALC888_FIXUP_EEE1601, .name = "eee1601"}, - {.id = ALC882_FIXUP_EAPD, .name = "alc882-eapd"}, - {.id = ALC883_FIXUP_EAPD, .name = "alc883-eapd"}, - {.id = ALC882_FIXUP_GPIO1, .name = "gpio1"}, - {.id = ALC882_FIXUP_GPIO2, .name = "gpio2"}, - {.id = ALC882_FIXUP_GPIO3, .name = "gpio3"}, - {.id = ALC889_FIXUP_COEF, .name = "alc889-coef"}, - {.id = ALC882_FIXUP_ASUS_W2JC, .name = "asus-w2jc"}, - {.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"}, - {.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"}, - {.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"}, - {.id = ALC885_FIXUP_MACPRO_GPIO, .name = "macpro-gpio"}, - {.id = ALC889_FIXUP_DAC_ROUTE, .name = "dac-route"}, - {.id = ALC889_FIXUP_MBP_VREF, .name = "mbp-vref"}, - {.id = ALC889_FIXUP_IMAC91_VREF, .name = "imac91-vref"}, - {.id = ALC889_FIXUP_MBA11_VREF, .name = "mba11-vref"}, - {.id = ALC889_FIXUP_MBA21_VREF, .name = "mba21-vref"}, - {.id = ALC889_FIXUP_MP11_VREF, .name = "mp11-vref"}, - {.id = ALC889_FIXUP_MP41_VREF, .name = "mp41-vref"}, - {.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"}, - {.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"}, - {.id = ALC887_FIXUP_ASUS_BASS, .name = "asus-bass"}, - {.id = ALC1220_FIXUP_GB_DUAL_CODECS, .name = "dual-codecs"}, - {.id = ALC1220_FIXUP_GB_X570, .name = "gb-x570"}, - {.id = ALC1220_FIXUP_CLEVO_P950, .name = "clevo-p950"}, - {} -}; - -static const struct snd_hda_pin_quirk alc882_pin_fixup_tbl[] = { - SND_HDA_PIN_QUIRK(0x10ec1220, 0x1043, "ASUS", ALC1220_FIXUP_CLEVO_P950, - {0x14, 0x01014010}, - {0x15, 0x01011012}, - {0x16, 0x01016011}, - {0x18, 0x01a19040}, - {0x19, 0x02a19050}, - {0x1a, 0x0181304f}, - {0x1b, 0x0221401f}, - {0x1e, 0x01456130}), - SND_HDA_PIN_QUIRK(0x10ec1220, 0x1462, "MS-7C35", ALC1220_FIXUP_CLEVO_P950, - {0x14, 0x01015010}, - {0x15, 0x01011012}, - {0x16, 0x01011011}, - {0x18, 0x01a11040}, - {0x19, 0x02a19050}, - {0x1a, 0x0181104f}, - {0x1b, 0x0221401f}, - {0x1e, 0x01451130}), - {} -}; - -/* - * BIOS auto configuration - */ -/* almost identical with ALC880 parser... */ -static int alc882_parse_auto_config(struct hda_codec *codec) -{ - static const hda_nid_t alc882_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids); -} - -/* - */ -static int patch_alc882(struct hda_codec *codec) -{ - struct alc_spec *spec; - int err; - - err = alc_alloc_spec(codec, 0x0b); - if (err < 0) - return err; - - spec = codec->spec; - - switch (codec->core.vendor_id) { - case 0x10ec0882: - case 0x10ec0885: - case 0x10ec0900: - case 0x10ec0b00: - case 0x10ec1220: - break; - default: - /* ALC883 and variants */ - alc_fix_pll_init(codec, 0x20, 0x0a, 10); - break; - } - - alc_pre_init(codec); - - snd_hda_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl, - alc882_fixups); - snd_hda_pick_pin_fixup(codec, alc882_pin_fixup_tbl, alc882_fixups, true); - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - - alc_auto_parse_customize_define(codec); - - if (has_cdefine_beep(codec)) - spec->gen.beep_nid = 0x01; - - /* automatic parse from the BIOS config */ - err = alc882_parse_auto_config(codec); - if (err < 0) - goto error; - - if (!spec->gen.no_analog && spec->gen.beep_nid) { - err = set_beep_amp(spec, 0x0b, 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; -} - - -/* - * ALC262 support - */ -static int alc262_parse_auto_config(struct hda_codec *codec) -{ - static const hda_nid_t alc262_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids); -} - -/* - * Pin config fixes - */ -enum { - ALC262_FIXUP_FSC_H270, - ALC262_FIXUP_FSC_S7110, - ALC262_FIXUP_HP_Z200, - ALC262_FIXUP_TYAN, - ALC262_FIXUP_LENOVO_3000, - ALC262_FIXUP_BENQ, - ALC262_FIXUP_BENQ_T31, - ALC262_FIXUP_INV_DMIC, - ALC262_FIXUP_INTEL_BAYLEYBAY, -}; - -static const struct hda_fixup alc262_fixups[] = { - [ALC262_FIXUP_FSC_H270] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x15, 0x0221142f }, /* front HP */ - { 0x1b, 0x0121141f }, /* rear HP */ - { } - } - }, - [ALC262_FIXUP_FSC_S7110] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x15, 0x90170110 }, /* speaker */ - { } - }, - .chained = true, - .chain_id = ALC262_FIXUP_BENQ, - }, - [ALC262_FIXUP_HP_Z200] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x16, 0x99130120 }, /* internal speaker */ - { } - } - }, - [ALC262_FIXUP_TYAN] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x1993e1f0 }, /* int AUX */ - { } - } - }, - [ALC262_FIXUP_LENOVO_3000] = { - .type = HDA_FIXUP_PINCTLS, - .v.pins = (const struct hda_pintbl[]) { - { 0x19, PIN_VREF50 }, - {} - }, - .chained = true, - .chain_id = ALC262_FIXUP_BENQ, - }, - [ALC262_FIXUP_BENQ] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 }, - {} - } - }, - [ALC262_FIXUP_BENQ_T31] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 }, - {} - } - }, - [ALC262_FIXUP_INV_DMIC] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_inv_dmic, - }, - [ALC262_FIXUP_INTEL_BAYLEYBAY] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_no_depop_delay, - }, -}; - -static const struct hda_quirk alc262_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200), - SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110), - SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ), - SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN), - SND_PCI_QUIRK(0x1734, 0x1141, "FSC ESPRIMO U9210", ALC262_FIXUP_FSC_H270), - SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270), - SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000), - SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ), - SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_FIXUP_BENQ_T31), - SND_PCI_QUIRK(0x8086, 0x7270, "BayleyBay", ALC262_FIXUP_INTEL_BAYLEYBAY), - {} -}; - -static const struct hda_model_fixup alc262_fixup_models[] = { - {.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"}, - {.id = ALC262_FIXUP_FSC_H270, .name = "fsc-h270"}, - {.id = ALC262_FIXUP_FSC_S7110, .name = "fsc-s7110"}, - {.id = ALC262_FIXUP_HP_Z200, .name = "hp-z200"}, - {.id = ALC262_FIXUP_TYAN, .name = "tyan"}, - {.id = ALC262_FIXUP_LENOVO_3000, .name = "lenovo-3000"}, - {.id = ALC262_FIXUP_BENQ, .name = "benq"}, - {.id = ALC262_FIXUP_BENQ_T31, .name = "benq-t31"}, - {.id = ALC262_FIXUP_INTEL_BAYLEYBAY, .name = "bayleybay"}, - {} -}; - -/* - */ -static int patch_alc262(struct hda_codec *codec) -{ - struct alc_spec *spec; - int err; - - err = alc_alloc_spec(codec, 0x0b); - if (err < 0) - return err; - - spec = codec->spec; - spec->gen.shared_mic_vref_pin = 0x18; - - spec->shutup = alc_eapd_shutup; - -#if 0 - /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is - * under-run - */ - alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x80); -#endif - alc_fix_pll_init(codec, 0x20, 0x0a, 10); - - alc_pre_init(codec); - - snd_hda_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl, - alc262_fixups); - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - - alc_auto_parse_customize_define(codec); - - if (has_cdefine_beep(codec)) - spec->gen.beep_nid = 0x01; - - /* automatic parse from the BIOS config */ - err = alc262_parse_auto_config(codec); - if (err < 0) - goto error; - - if (!spec->gen.no_analog && spec->gen.beep_nid) { - err = set_beep_amp(spec, 0x0b, 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; -} - -/* - * ALC268 - */ -/* bind Beep switches of both NID 0x0f and 0x10 */ -static int alc268_beep_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned long pval; - int err; - - mutex_lock(&codec->control_mutex); - pval = kcontrol->private_value; - kcontrol->private_value = (pval & ~0xff) | 0x0f; - err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - if (err >= 0) { - kcontrol->private_value = (pval & ~0xff) | 0x10; - err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - } - kcontrol->private_value = pval; - mutex_unlock(&codec->control_mutex); - return err; -} - -static const struct snd_kcontrol_new alc268_beep_mixer[] = { - HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Beep Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = alc268_beep_switch_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT) - }, -}; - -/* set PCBEEP vol = 0, mute connections */ -static const struct hda_verb alc268_beep_init_verbs[] = { - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - { } -}; - -enum { - ALC268_FIXUP_INV_DMIC, - ALC268_FIXUP_HP_EAPD, - ALC268_FIXUP_SPDIF, -}; - -static const struct hda_fixup alc268_fixups[] = { - [ALC268_FIXUP_INV_DMIC] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_inv_dmic, - }, - [ALC268_FIXUP_HP_EAPD] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 0}, - {} - } - }, - [ALC268_FIXUP_SPDIF] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x1e, 0x014b1180 }, /* enable SPDIF out */ - {} - } - }, -}; - -static const struct hda_model_fixup alc268_fixup_models[] = { - {.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"}, - {.id = ALC268_FIXUP_HP_EAPD, .name = "hp-eapd"}, - {.id = ALC268_FIXUP_SPDIF, .name = "spdif"}, - {} -}; - -static const struct hda_quirk alc268_fixup_tbl[] = { - SND_PCI_QUIRK(0x1025, 0x0139, "Acer TravelMate 6293", ALC268_FIXUP_SPDIF), - SND_PCI_QUIRK(0x1025, 0x015b, "Acer AOA 150 (ZG5)", ALC268_FIXUP_INV_DMIC), - /* below is codec SSID since multiple Toshiba laptops have the - * same PCI SSID 1179:ff00 - */ - SND_PCI_QUIRK(0x1179, 0xff06, "Toshiba P200", ALC268_FIXUP_HP_EAPD), - {} -}; - -/* - * BIOS auto configuration - */ -static int alc268_parse_auto_config(struct hda_codec *codec) -{ - static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - return alc_parse_auto_config(codec, NULL, alc268_ssids); -} - -/* - */ -static int patch_alc268(struct hda_codec *codec) -{ - struct alc_spec *spec; - int i, err; - - /* ALC268 has no aa-loopback mixer */ - err = alc_alloc_spec(codec, 0); - if (err < 0) - return err; - - spec = codec->spec; - if (has_cdefine_beep(codec)) - spec->gen.beep_nid = 0x01; - - spec->shutup = alc_eapd_shutup; - - alc_pre_init(codec); - - snd_hda_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups); - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - - /* automatic parse from the BIOS config */ - err = alc268_parse_auto_config(codec); - if (err < 0) - goto error; - - if (err > 0 && !spec->gen.no_analog && - spec->gen.autocfg.speaker_pins[0] != 0x1d) { - for (i = 0; i < ARRAY_SIZE(alc268_beep_mixer); i++) { - if (!snd_hda_gen_add_kctl(&spec->gen, NULL, - &alc268_beep_mixer[i])) { - err = -ENOMEM; - goto error; - } - } - snd_hda_add_verbs(codec, alc268_beep_init_verbs); - if (!query_amp_caps(codec, 0x1d, HDA_INPUT)) - /* override the amp caps for beep generator */ - snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT, - (0x0c << AC_AMPCAP_OFFSET_SHIFT) | - (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (0 << AC_AMPCAP_MUTE_SHIFT)); - } - - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); - - return 0; - - error: - alc_free(codec); - return err; -} - -/* - * ALC269 - */ - static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = { .rates = SNDRV_PCM_RATE_44100, /* fixed rate */ }; @@ -4191,15 +1046,6 @@ static void alc269_fixup_hweq(struct hda_codec *codec, alc_update_coef_idx(codec, 0x1e, 0, 0x80); } -static void alc269_fixup_headset_mic(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->parse_flags |= HDA_PINCFG_HEADSET_MIC; -} - static void alc271_fixup_dmic(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -4470,61 +1316,6 @@ static void alc269_fixup_hp_mute_led_mic3(struct hda_codec *codec, alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x1b); } -/* update LED status via GPIO */ -static void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask, - int polarity, bool enabled) -{ - if (polarity) - enabled = !enabled; - alc_update_gpio_data(codec, mask, !enabled); /* muted -> LED on */ -} - -/* turn on/off mute LED via GPIO per vmaster hook */ -static int gpio_mute_led_set(struct led_classdev *led_cdev, - enum led_brightness brightness) -{ - struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent); - struct alc_spec *spec = codec->spec; - - alc_update_gpio_led(codec, spec->gpio_mute_led_mask, - spec->mute_led_polarity, !brightness); - return 0; -} - -/* turn on/off mic-mute LED via GPIO per capture hook */ -static int micmute_led_set(struct led_classdev *led_cdev, - enum led_brightness brightness) -{ - struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent); - struct alc_spec *spec = codec->spec; - - alc_update_gpio_led(codec, spec->gpio_mic_led_mask, - spec->micmute_led_polarity, !brightness); - return 0; -} - -/* setup mute and mic-mute GPIO bits, add hooks appropriately */ -static void alc_fixup_hp_gpio_led(struct hda_codec *codec, - int action, - unsigned int mute_mask, - unsigned int micmute_mask) -{ - struct alc_spec *spec = codec->spec; - - alc_fixup_gpio(codec, action, mute_mask | micmute_mask); - - if (action != HDA_FIXUP_ACT_PRE_PROBE) - return; - if (mute_mask) { - spec->gpio_mute_led_mask = mute_mask; - snd_hda_gen_add_mute_led_cdev(codec, gpio_mute_led_set); - } - if (micmute_mask) { - spec->gpio_mic_led_mask = micmute_mask; - snd_hda_gen_add_micmute_led_cdev(codec, micmute_led_set); - } -} - static void alc236_fixup_hp_gpio_led(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -5167,985 +1958,6 @@ static void alc233_fixup_lenovo_low_en_micmute_led(struct hda_codec *codec, alc233_fixup_lenovo_line2_mic_hotkey(codec, fix, action); } -static void alc_hp_mute_disable(struct hda_codec *codec, unsigned int delay) -{ - if (delay <= 0) - delay = 75; - snd_hda_codec_write(codec, 0x21, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - msleep(delay); - snd_hda_codec_write(codec, 0x21, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); - msleep(delay); -} - -static void alc_hp_enable_unmute(struct hda_codec *codec, unsigned int delay) -{ - if (delay <= 0) - delay = 75; - snd_hda_codec_write(codec, 0x21, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - msleep(delay); - snd_hda_codec_write(codec, 0x21, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - msleep(delay); -} - -static const struct coef_fw alc225_pre_hsmode[] = { - UPDATE_COEF(0x4a, 1<<8, 0), - UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), - UPDATE_COEF(0x63, 3<<14, 3<<14), - UPDATE_COEF(0x4a, 3<<4, 2<<4), - UPDATE_COEF(0x4a, 3<<10, 3<<10), - UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10), - UPDATE_COEF(0x4a, 3<<10, 0), - {} -}; - -static void alc_headset_mode_unplugged(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - static const struct coef_fw coef0255[] = { - WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */ - WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */ - UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/ - WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */ - WRITE_COEFEX(0x57, 0x03, 0x8aa6), /* Direct Drive HP Amp control */ - {} - }; - static const struct coef_fw coef0256[] = { - WRITE_COEF(0x1b, 0x0c4b), /* LDO and MISC control */ - WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */ - WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */ - WRITE_COEFEX(0x57, 0x03, 0x09a3), /* Direct Drive HP Amp control */ - UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/ - {} - }; - static const struct coef_fw coef0233[] = { - WRITE_COEF(0x1b, 0x0c0b), - WRITE_COEF(0x45, 0xc429), - UPDATE_COEF(0x35, 0x4000, 0), - WRITE_COEF(0x06, 0x2104), - WRITE_COEF(0x1a, 0x0001), - WRITE_COEF(0x26, 0x0004), - WRITE_COEF(0x32, 0x42a3), - {} - }; - static const struct coef_fw coef0288[] = { - UPDATE_COEF(0x4f, 0xfcc0, 0xc400), - UPDATE_COEF(0x50, 0x2000, 0x2000), - UPDATE_COEF(0x56, 0x0006, 0x0006), - UPDATE_COEF(0x66, 0x0008, 0), - UPDATE_COEF(0x67, 0x2000, 0), - {} - }; - static const struct coef_fw coef0298[] = { - UPDATE_COEF(0x19, 0x1300, 0x0300), - {} - }; - static const struct coef_fw coef0292[] = { - WRITE_COEF(0x76, 0x000e), - WRITE_COEF(0x6c, 0x2400), - WRITE_COEF(0x18, 0x7308), - WRITE_COEF(0x6b, 0xc429), - {} - }; - static const struct coef_fw coef0293[] = { - UPDATE_COEF(0x10, 7<<8, 6<<8), /* SET Line1 JD to 0 */ - UPDATE_COEFEX(0x57, 0x05, 1<<15|1<<13, 0x0), /* SET charge pump by verb */ - UPDATE_COEFEX(0x57, 0x03, 1<<10, 1<<10), /* SET EN_OSW to 1 */ - UPDATE_COEF(0x1a, 1<<3, 1<<3), /* Combo JD gating with LINE1-VREFO */ - WRITE_COEF(0x45, 0xc429), /* Set to TRS type */ - UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */ - {} - }; - static const struct coef_fw coef0668[] = { - WRITE_COEF(0x15, 0x0d40), - WRITE_COEF(0xb7, 0x802b), - {} - }; - static const struct coef_fw coef0225[] = { - UPDATE_COEF(0x63, 3<<14, 0), - {} - }; - static const struct coef_fw coef0274[] = { - UPDATE_COEF(0x4a, 0x0100, 0), - UPDATE_COEFEX(0x57, 0x05, 0x4000, 0), - UPDATE_COEF(0x6b, 0xf000, 0x5000), - UPDATE_COEF(0x4a, 0x0010, 0), - UPDATE_COEF(0x4a, 0x0c00, 0x0c00), - WRITE_COEF(0x45, 0x5289), - UPDATE_COEF(0x4a, 0x0c00, 0), - {} - }; - - if (spec->no_internal_mic_pin) { - alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12); - return; - } - - switch (codec->core.vendor_id) { - case 0x10ec0255: - alc_process_coef_fw(codec, coef0255); - break; - case 0x10ec0230: - case 0x10ec0236: - case 0x10ec0256: - case 0x19e58326: - alc_hp_mute_disable(codec, 75); - alc_process_coef_fw(codec, coef0256); - break; - case 0x10ec0234: - case 0x10ec0274: - case 0x10ec0294: - alc_process_coef_fw(codec, coef0274); - break; - case 0x10ec0233: - case 0x10ec0283: - alc_process_coef_fw(codec, coef0233); - break; - case 0x10ec0286: - case 0x10ec0288: - alc_process_coef_fw(codec, coef0288); - break; - case 0x10ec0298: - alc_process_coef_fw(codec, coef0298); - alc_process_coef_fw(codec, coef0288); - break; - case 0x10ec0292: - alc_process_coef_fw(codec, coef0292); - break; - case 0x10ec0293: - alc_process_coef_fw(codec, coef0293); - break; - case 0x10ec0668: - alc_process_coef_fw(codec, coef0668); - break; - case 0x10ec0215: - case 0x10ec0225: - case 0x10ec0285: - case 0x10ec0295: - case 0x10ec0289: - case 0x10ec0299: - alc_hp_mute_disable(codec, 75); - alc_process_coef_fw(codec, alc225_pre_hsmode); - alc_process_coef_fw(codec, coef0225); - break; - case 0x10ec0867: - alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0); - break; - } - codec_dbg(codec, "Headset jack set to unplugged mode.\n"); -} - - -static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, - hda_nid_t mic_pin) -{ - static const struct coef_fw coef0255[] = { - WRITE_COEFEX(0x57, 0x03, 0x8aa6), - WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */ - {} - }; - static const struct coef_fw coef0256[] = { - UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14), /* Direct Drive HP Amp control(Set to verb control)*/ - WRITE_COEFEX(0x57, 0x03, 0x09a3), - WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */ - {} - }; - static const struct coef_fw coef0233[] = { - UPDATE_COEF(0x35, 0, 1<<14), - WRITE_COEF(0x06, 0x2100), - WRITE_COEF(0x1a, 0x0021), - WRITE_COEF(0x26, 0x008c), - {} - }; - static const struct coef_fw coef0288[] = { - UPDATE_COEF(0x4f, 0x00c0, 0), - UPDATE_COEF(0x50, 0x2000, 0), - UPDATE_COEF(0x56, 0x0006, 0), - UPDATE_COEF(0x4f, 0xfcc0, 0xc400), - UPDATE_COEF(0x66, 0x0008, 0x0008), - UPDATE_COEF(0x67, 0x2000, 0x2000), - {} - }; - static const struct coef_fw coef0292[] = { - WRITE_COEF(0x19, 0xa208), - WRITE_COEF(0x2e, 0xacf0), - {} - }; - static const struct coef_fw coef0293[] = { - UPDATE_COEFEX(0x57, 0x05, 0, 1<<15|1<<13), /* SET charge pump by verb */ - UPDATE_COEFEX(0x57, 0x03, 1<<10, 0), /* SET EN_OSW to 0 */ - UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */ - {} - }; - static const struct coef_fw coef0688[] = { - WRITE_COEF(0xb7, 0x802b), - WRITE_COEF(0xb5, 0x1040), - UPDATE_COEF(0xc3, 0, 1<<12), - {} - }; - static const struct coef_fw coef0225[] = { - UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14), - UPDATE_COEF(0x4a, 3<<4, 2<<4), - UPDATE_COEF(0x63, 3<<14, 0), - {} - }; - static const struct coef_fw coef0274[] = { - UPDATE_COEFEX(0x57, 0x05, 0x4000, 0x4000), - UPDATE_COEF(0x4a, 0x0010, 0), - UPDATE_COEF(0x6b, 0xf000, 0), - {} - }; - - switch (codec->core.vendor_id) { - case 0x10ec0255: - alc_write_coef_idx(codec, 0x45, 0xc489); - snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - alc_process_coef_fw(codec, coef0255); - snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); - break; - case 0x10ec0230: - case 0x10ec0236: - case 0x10ec0256: - case 0x19e58326: - alc_write_coef_idx(codec, 0x45, 0xc489); - snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - alc_process_coef_fw(codec, coef0256); - snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); - break; - case 0x10ec0234: - case 0x10ec0274: - case 0x10ec0294: - alc_write_coef_idx(codec, 0x45, 0x4689); - snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - alc_process_coef_fw(codec, coef0274); - snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); - break; - case 0x10ec0233: - case 0x10ec0283: - alc_write_coef_idx(codec, 0x45, 0xc429); - snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - alc_process_coef_fw(codec, coef0233); - snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); - break; - case 0x10ec0286: - case 0x10ec0288: - case 0x10ec0298: - snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - alc_process_coef_fw(codec, coef0288); - snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); - break; - case 0x10ec0292: - snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - alc_process_coef_fw(codec, coef0292); - break; - case 0x10ec0293: - /* Set to TRS mode */ - alc_write_coef_idx(codec, 0x45, 0xc429); - snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - alc_process_coef_fw(codec, coef0293); - snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); - break; - case 0x10ec0867: - alc_update_coefex_idx(codec, 0x57, 0x5, 0, 1<<14); - fallthrough; - case 0x10ec0221: - case 0x10ec0662: - snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); - break; - case 0x10ec0668: - alc_write_coef_idx(codec, 0x11, 0x0001); - snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - alc_process_coef_fw(codec, coef0688); - snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); - break; - case 0x10ec0215: - case 0x10ec0225: - case 0x10ec0285: - case 0x10ec0295: - case 0x10ec0289: - case 0x10ec0299: - alc_process_coef_fw(codec, alc225_pre_hsmode); - alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10); - snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - alc_process_coef_fw(codec, coef0225); - snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); - break; - } - codec_dbg(codec, "Headset jack set to mic-in mode.\n"); -} - -static void alc_headset_mode_default(struct hda_codec *codec) -{ - static const struct coef_fw coef0225[] = { - UPDATE_COEF(0x45, 0x3f<<10, 0x30<<10), - UPDATE_COEF(0x45, 0x3f<<10, 0x31<<10), - UPDATE_COEF(0x49, 3<<8, 0<<8), - UPDATE_COEF(0x4a, 3<<4, 3<<4), - UPDATE_COEF(0x63, 3<<14, 0), - UPDATE_COEF(0x67, 0xf000, 0x3000), - {} - }; - static const struct coef_fw coef0255[] = { - WRITE_COEF(0x45, 0xc089), - WRITE_COEF(0x45, 0xc489), - WRITE_COEFEX(0x57, 0x03, 0x8ea6), - WRITE_COEF(0x49, 0x0049), - {} - }; - static const struct coef_fw coef0256[] = { - WRITE_COEF(0x45, 0xc489), - WRITE_COEFEX(0x57, 0x03, 0x0da3), - WRITE_COEF(0x49, 0x0049), - UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/ - WRITE_COEF(0x06, 0x6100), - {} - }; - static const struct coef_fw coef0233[] = { - WRITE_COEF(0x06, 0x2100), - WRITE_COEF(0x32, 0x4ea3), - {} - }; - static const struct coef_fw coef0288[] = { - UPDATE_COEF(0x4f, 0xfcc0, 0xc400), /* Set to TRS type */ - UPDATE_COEF(0x50, 0x2000, 0x2000), - UPDATE_COEF(0x56, 0x0006, 0x0006), - UPDATE_COEF(0x66, 0x0008, 0), - UPDATE_COEF(0x67, 0x2000, 0), - {} - }; - static const struct coef_fw coef0292[] = { - WRITE_COEF(0x76, 0x000e), - WRITE_COEF(0x6c, 0x2400), - WRITE_COEF(0x6b, 0xc429), - WRITE_COEF(0x18, 0x7308), - {} - }; - static const struct coef_fw coef0293[] = { - UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */ - WRITE_COEF(0x45, 0xC429), /* Set to TRS type */ - UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */ - {} - }; - static const struct coef_fw coef0688[] = { - WRITE_COEF(0x11, 0x0041), - WRITE_COEF(0x15, 0x0d40), - WRITE_COEF(0xb7, 0x802b), - {} - }; - static const struct coef_fw coef0274[] = { - WRITE_COEF(0x45, 0x4289), - UPDATE_COEF(0x4a, 0x0010, 0x0010), - UPDATE_COEF(0x6b, 0x0f00, 0), - UPDATE_COEF(0x49, 0x0300, 0x0300), - {} - }; - - switch (codec->core.vendor_id) { - case 0x10ec0215: - case 0x10ec0225: - case 0x10ec0285: - case 0x10ec0295: - case 0x10ec0289: - case 0x10ec0299: - alc_process_coef_fw(codec, alc225_pre_hsmode); - alc_process_coef_fw(codec, coef0225); - alc_hp_enable_unmute(codec, 75); - break; - case 0x10ec0255: - alc_process_coef_fw(codec, coef0255); - break; - case 0x10ec0230: - case 0x10ec0236: - case 0x10ec0256: - case 0x19e58326: - alc_write_coef_idx(codec, 0x1b, 0x0e4b); - alc_write_coef_idx(codec, 0x45, 0xc089); - msleep(50); - alc_process_coef_fw(codec, coef0256); - alc_hp_enable_unmute(codec, 75); - break; - case 0x10ec0234: - case 0x10ec0274: - case 0x10ec0294: - alc_process_coef_fw(codec, coef0274); - break; - case 0x10ec0233: - case 0x10ec0283: - alc_process_coef_fw(codec, coef0233); - break; - case 0x10ec0286: - case 0x10ec0288: - case 0x10ec0298: - alc_process_coef_fw(codec, coef0288); - break; - case 0x10ec0292: - alc_process_coef_fw(codec, coef0292); - break; - case 0x10ec0293: - alc_process_coef_fw(codec, coef0293); - break; - case 0x10ec0668: - alc_process_coef_fw(codec, coef0688); - break; - case 0x10ec0867: - alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0); - break; - } - codec_dbg(codec, "Headset jack set to headphone (default) mode.\n"); -} - -/* Iphone type */ -static void alc_headset_mode_ctia(struct hda_codec *codec) -{ - int val; - - static const struct coef_fw coef0255[] = { - WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */ - WRITE_COEF(0x1b, 0x0c2b), - WRITE_COEFEX(0x57, 0x03, 0x8ea6), - {} - }; - static const struct coef_fw coef0256[] = { - WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */ - WRITE_COEF(0x1b, 0x0e6b), - {} - }; - static const struct coef_fw coef0233[] = { - WRITE_COEF(0x45, 0xd429), - WRITE_COEF(0x1b, 0x0c2b), - WRITE_COEF(0x32, 0x4ea3), - {} - }; - static const struct coef_fw coef0288[] = { - UPDATE_COEF(0x50, 0x2000, 0x2000), - UPDATE_COEF(0x56, 0x0006, 0x0006), - UPDATE_COEF(0x66, 0x0008, 0), - UPDATE_COEF(0x67, 0x2000, 0), - {} - }; - static const struct coef_fw coef0292[] = { - WRITE_COEF(0x6b, 0xd429), - WRITE_COEF(0x76, 0x0008), - WRITE_COEF(0x18, 0x7388), - {} - }; - static const struct coef_fw coef0293[] = { - WRITE_COEF(0x45, 0xd429), /* Set to ctia type */ - UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */ - {} - }; - static const struct coef_fw coef0688[] = { - WRITE_COEF(0x11, 0x0001), - WRITE_COEF(0x15, 0x0d60), - WRITE_COEF(0xc3, 0x0000), - {} - }; - static const struct coef_fw coef0225_1[] = { - UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10), - UPDATE_COEF(0x63, 3<<14, 2<<14), - {} - }; - static const struct coef_fw coef0225_2[] = { - UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10), - UPDATE_COEF(0x63, 3<<14, 1<<14), - {} - }; - - switch (codec->core.vendor_id) { - case 0x10ec0255: - alc_process_coef_fw(codec, coef0255); - break; - case 0x10ec0230: - case 0x10ec0236: - case 0x10ec0256: - case 0x19e58326: - alc_process_coef_fw(codec, coef0256); - alc_hp_enable_unmute(codec, 75); - break; - case 0x10ec0234: - case 0x10ec0274: - case 0x10ec0294: - alc_write_coef_idx(codec, 0x45, 0xd689); - break; - case 0x10ec0233: - case 0x10ec0283: - alc_process_coef_fw(codec, coef0233); - break; - case 0x10ec0298: - val = alc_read_coef_idx(codec, 0x50); - if (val & (1 << 12)) { - alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020); - alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400); - msleep(300); - } else { - alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010); - alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400); - msleep(300); - } - break; - case 0x10ec0286: - case 0x10ec0288: - alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400); - msleep(300); - alc_process_coef_fw(codec, coef0288); - break; - case 0x10ec0292: - alc_process_coef_fw(codec, coef0292); - break; - case 0x10ec0293: - alc_process_coef_fw(codec, coef0293); - break; - case 0x10ec0668: - alc_process_coef_fw(codec, coef0688); - break; - case 0x10ec0215: - case 0x10ec0225: - case 0x10ec0285: - case 0x10ec0295: - case 0x10ec0289: - case 0x10ec0299: - val = alc_read_coef_idx(codec, 0x45); - if (val & (1 << 9)) - alc_process_coef_fw(codec, coef0225_2); - else - alc_process_coef_fw(codec, coef0225_1); - alc_hp_enable_unmute(codec, 75); - break; - case 0x10ec0867: - alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0); - break; - } - codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n"); -} - -/* Nokia type */ -static void alc_headset_mode_omtp(struct hda_codec *codec) -{ - static const struct coef_fw coef0255[] = { - WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */ - WRITE_COEF(0x1b, 0x0c2b), - WRITE_COEFEX(0x57, 0x03, 0x8ea6), - {} - }; - static const struct coef_fw coef0256[] = { - WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */ - WRITE_COEF(0x1b, 0x0e6b), - {} - }; - static const struct coef_fw coef0233[] = { - WRITE_COEF(0x45, 0xe429), - WRITE_COEF(0x1b, 0x0c2b), - WRITE_COEF(0x32, 0x4ea3), - {} - }; - static const struct coef_fw coef0288[] = { - UPDATE_COEF(0x50, 0x2000, 0x2000), - UPDATE_COEF(0x56, 0x0006, 0x0006), - UPDATE_COEF(0x66, 0x0008, 0), - UPDATE_COEF(0x67, 0x2000, 0), - {} - }; - static const struct coef_fw coef0292[] = { - WRITE_COEF(0x6b, 0xe429), - WRITE_COEF(0x76, 0x0008), - WRITE_COEF(0x18, 0x7388), - {} - }; - static const struct coef_fw coef0293[] = { - WRITE_COEF(0x45, 0xe429), /* Set to omtp type */ - UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */ - {} - }; - static const struct coef_fw coef0688[] = { - WRITE_COEF(0x11, 0x0001), - WRITE_COEF(0x15, 0x0d50), - WRITE_COEF(0xc3, 0x0000), - {} - }; - static const struct coef_fw coef0225[] = { - UPDATE_COEF(0x45, 0x3f<<10, 0x39<<10), - UPDATE_COEF(0x63, 3<<14, 2<<14), - {} - }; - - switch (codec->core.vendor_id) { - case 0x10ec0255: - alc_process_coef_fw(codec, coef0255); - break; - case 0x10ec0230: - case 0x10ec0236: - case 0x10ec0256: - case 0x19e58326: - alc_process_coef_fw(codec, coef0256); - alc_hp_enable_unmute(codec, 75); - break; - case 0x10ec0234: - case 0x10ec0274: - case 0x10ec0294: - alc_write_coef_idx(codec, 0x45, 0xe689); - break; - case 0x10ec0233: - case 0x10ec0283: - alc_process_coef_fw(codec, coef0233); - break; - case 0x10ec0298: - alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);/* Headset output enable */ - alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400); - msleep(300); - break; - case 0x10ec0286: - case 0x10ec0288: - alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400); - msleep(300); - alc_process_coef_fw(codec, coef0288); - break; - case 0x10ec0292: - alc_process_coef_fw(codec, coef0292); - break; - case 0x10ec0293: - alc_process_coef_fw(codec, coef0293); - break; - case 0x10ec0668: - alc_process_coef_fw(codec, coef0688); - break; - case 0x10ec0215: - case 0x10ec0225: - case 0x10ec0285: - case 0x10ec0295: - case 0x10ec0289: - case 0x10ec0299: - alc_process_coef_fw(codec, coef0225); - alc_hp_enable_unmute(codec, 75); - break; - } - codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n"); -} - -static void alc_determine_headset_type(struct hda_codec *codec) -{ - int val; - bool is_ctia = false; - struct alc_spec *spec = codec->spec; - static const struct coef_fw coef0255[] = { - WRITE_COEF(0x45, 0xd089), /* combo jack auto switch control(Check type)*/ - WRITE_COEF(0x49, 0x0149), /* combo jack auto switch control(Vref - conteol) */ - {} - }; - static const struct coef_fw coef0288[] = { - UPDATE_COEF(0x4f, 0xfcc0, 0xd400), /* Check Type */ - {} - }; - static const struct coef_fw coef0298[] = { - UPDATE_COEF(0x50, 0x2000, 0x2000), - UPDATE_COEF(0x56, 0x0006, 0x0006), - UPDATE_COEF(0x66, 0x0008, 0), - UPDATE_COEF(0x67, 0x2000, 0), - UPDATE_COEF(0x19, 0x1300, 0x1300), - {} - }; - static const struct coef_fw coef0293[] = { - UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */ - WRITE_COEF(0x45, 0xD429), /* Set to ctia type */ - {} - }; - static const struct coef_fw coef0688[] = { - WRITE_COEF(0x11, 0x0001), - WRITE_COEF(0xb7, 0x802b), - WRITE_COEF(0x15, 0x0d60), - WRITE_COEF(0xc3, 0x0c00), - {} - }; - static const struct coef_fw coef0274[] = { - UPDATE_COEF(0x4a, 0x0010, 0), - UPDATE_COEF(0x4a, 0x8000, 0), - WRITE_COEF(0x45, 0xd289), - UPDATE_COEF(0x49, 0x0300, 0x0300), - {} - }; - - if (spec->no_internal_mic_pin) { - alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12); - return; - } - - switch (codec->core.vendor_id) { - case 0x10ec0255: - alc_process_coef_fw(codec, coef0255); - msleep(300); - val = alc_read_coef_idx(codec, 0x46); - is_ctia = (val & 0x0070) == 0x0070; - break; - case 0x10ec0230: - case 0x10ec0236: - case 0x10ec0256: - case 0x19e58326: - alc_write_coef_idx(codec, 0x1b, 0x0e4b); - alc_write_coef_idx(codec, 0x06, 0x6104); - alc_write_coefex_idx(codec, 0x57, 0x3, 0x09a3); - - alc_process_coef_fw(codec, coef0255); - msleep(300); - val = alc_read_coef_idx(codec, 0x46); - is_ctia = (val & 0x0070) == 0x0070; - if (!is_ctia) { - alc_write_coef_idx(codec, 0x45, 0xe089); - msleep(100); - val = alc_read_coef_idx(codec, 0x46); - if ((val & 0x0070) == 0x0070) - is_ctia = false; - else - is_ctia = true; - } - alc_write_coefex_idx(codec, 0x57, 0x3, 0x0da3); - alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0); - break; - case 0x10ec0234: - case 0x10ec0274: - case 0x10ec0294: - alc_process_coef_fw(codec, coef0274); - msleep(850); - val = alc_read_coef_idx(codec, 0x46); - is_ctia = (val & 0x00f0) == 0x00f0; - break; - case 0x10ec0233: - case 0x10ec0283: - alc_write_coef_idx(codec, 0x45, 0xd029); - msleep(300); - val = alc_read_coef_idx(codec, 0x46); - is_ctia = (val & 0x0070) == 0x0070; - break; - case 0x10ec0298: - snd_hda_codec_write(codec, 0x21, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - msleep(100); - snd_hda_codec_write(codec, 0x21, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); - msleep(200); - - val = alc_read_coef_idx(codec, 0x50); - if (val & (1 << 12)) { - alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020); - alc_process_coef_fw(codec, coef0288); - msleep(350); - val = alc_read_coef_idx(codec, 0x50); - is_ctia = (val & 0x0070) == 0x0070; - } else { - alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010); - alc_process_coef_fw(codec, coef0288); - msleep(350); - val = alc_read_coef_idx(codec, 0x50); - is_ctia = (val & 0x0070) == 0x0070; - } - alc_process_coef_fw(codec, coef0298); - snd_hda_codec_write(codec, 0x21, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); - msleep(75); - snd_hda_codec_write(codec, 0x21, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - break; - case 0x10ec0286: - case 0x10ec0288: - alc_process_coef_fw(codec, coef0288); - msleep(350); - val = alc_read_coef_idx(codec, 0x50); - is_ctia = (val & 0x0070) == 0x0070; - break; - case 0x10ec0292: - alc_write_coef_idx(codec, 0x6b, 0xd429); - msleep(300); - val = alc_read_coef_idx(codec, 0x6c); - is_ctia = (val & 0x001c) == 0x001c; - break; - case 0x10ec0293: - alc_process_coef_fw(codec, coef0293); - msleep(300); - val = alc_read_coef_idx(codec, 0x46); - is_ctia = (val & 0x0070) == 0x0070; - break; - case 0x10ec0668: - alc_process_coef_fw(codec, coef0688); - msleep(300); - val = alc_read_coef_idx(codec, 0xbe); - is_ctia = (val & 0x1c02) == 0x1c02; - break; - case 0x10ec0215: - case 0x10ec0225: - case 0x10ec0285: - case 0x10ec0295: - case 0x10ec0289: - case 0x10ec0299: - alc_process_coef_fw(codec, alc225_pre_hsmode); - alc_update_coef_idx(codec, 0x67, 0xf000, 0x1000); - val = alc_read_coef_idx(codec, 0x45); - if (val & (1 << 9)) { - alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10); - alc_update_coef_idx(codec, 0x49, 3<<8, 2<<8); - msleep(800); - val = alc_read_coef_idx(codec, 0x46); - is_ctia = (val & 0x00f0) == 0x00f0; - } else { - alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10); - alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8); - msleep(800); - val = alc_read_coef_idx(codec, 0x46); - is_ctia = (val & 0x00f0) == 0x00f0; - } - if (!is_ctia) { - alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x38<<10); - alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8); - msleep(100); - val = alc_read_coef_idx(codec, 0x46); - if ((val & 0x00f0) == 0x00f0) - is_ctia = false; - else - is_ctia = true; - } - alc_update_coef_idx(codec, 0x4a, 7<<6, 7<<6); - alc_update_coef_idx(codec, 0x4a, 3<<4, 3<<4); - alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000); - break; - case 0x10ec0867: - is_ctia = true; - break; - } - - codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n", - str_yes_no(is_ctia)); - spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP; -} - -static void alc_update_headset_mode(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]]; - hda_nid_t hp_pin = alc_get_hp_pin(spec); - - int new_headset_mode; - - if (!snd_hda_jack_detect(codec, hp_pin)) - new_headset_mode = ALC_HEADSET_MODE_UNPLUGGED; - else if (mux_pin == spec->headset_mic_pin) - new_headset_mode = ALC_HEADSET_MODE_HEADSET; - else if (mux_pin == spec->headphone_mic_pin) - new_headset_mode = ALC_HEADSET_MODE_MIC; - else - new_headset_mode = ALC_HEADSET_MODE_HEADPHONE; - - if (new_headset_mode == spec->current_headset_mode) { - snd_hda_gen_update_outputs(codec); - return; - } - - switch (new_headset_mode) { - case ALC_HEADSET_MODE_UNPLUGGED: - alc_headset_mode_unplugged(codec); - spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN; - spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN; - spec->gen.hp_jack_present = false; - break; - case ALC_HEADSET_MODE_HEADSET: - if (spec->current_headset_type == ALC_HEADSET_TYPE_UNKNOWN) - alc_determine_headset_type(codec); - if (spec->current_headset_type == ALC_HEADSET_TYPE_CTIA) - alc_headset_mode_ctia(codec); - else if (spec->current_headset_type == ALC_HEADSET_TYPE_OMTP) - alc_headset_mode_omtp(codec); - spec->gen.hp_jack_present = true; - break; - case ALC_HEADSET_MODE_MIC: - alc_headset_mode_mic_in(codec, hp_pin, spec->headphone_mic_pin); - spec->gen.hp_jack_present = false; - break; - case ALC_HEADSET_MODE_HEADPHONE: - alc_headset_mode_default(codec); - spec->gen.hp_jack_present = true; - break; - } - if (new_headset_mode != ALC_HEADSET_MODE_MIC) { - snd_hda_set_pin_ctl_cache(codec, hp_pin, - AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); - if (spec->headphone_mic_pin && spec->headphone_mic_pin != hp_pin) - snd_hda_set_pin_ctl_cache(codec, spec->headphone_mic_pin, - PIN_VREFHIZ); - } - spec->current_headset_mode = new_headset_mode; - - snd_hda_gen_update_outputs(codec); -} - -static void alc_update_headset_mode_hook(struct hda_codec *codec, - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - alc_update_headset_mode(codec); -} - -static void alc_update_headset_jack_cb(struct hda_codec *codec, - struct hda_jack_callback *jack) -{ - snd_hda_gen_hp_automute(codec, jack); - alc_update_headset_mode(codec); -} - -static void alc_probe_headset_mode(struct hda_codec *codec) -{ - int i; - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->gen.autocfg; - - /* Find mic pins */ - for (i = 0; i < cfg->num_inputs; i++) { - if (cfg->inputs[i].is_headset_mic && !spec->headset_mic_pin) - spec->headset_mic_pin = cfg->inputs[i].pin; - if (cfg->inputs[i].is_headphone_mic && !spec->headphone_mic_pin) - spec->headphone_mic_pin = cfg->inputs[i].pin; - } - - WARN_ON(spec->gen.cap_sync_hook); - spec->gen.cap_sync_hook = alc_update_headset_mode_hook; - spec->gen.automute_hook = alc_update_headset_mode; - spec->gen.hp_automute_hook = alc_update_headset_jack_cb; -} - -static void alc_fixup_headset_mode(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - struct alc_spec *spec = codec->spec; - - switch (action) { - case HDA_FIXUP_ACT_PRE_PROBE: - spec->parse_flags |= HDA_PINCFG_HEADSET_MIC | HDA_PINCFG_HEADPHONE_MIC; - break; - case HDA_FIXUP_ACT_PROBE: - alc_probe_headset_mode(codec); - break; - case HDA_FIXUP_ACT_INIT: - if (is_s3_resume(codec) || is_s4_resume(codec)) { - spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN; - spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN; - } - alc_update_headset_mode(codec); - break; - } -} - -static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - if (action == HDA_FIXUP_ACT_PRE_PROBE) { - struct alc_spec *spec = codec->spec; - spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; - } - else - alc_fixup_headset_mode(codec, fix, action); -} - static void alc255_set_default_jack_type(struct hda_codec *codec) { /* Set to iphone type */ @@ -6223,15 +2035,6 @@ static void alc_fixup_headset_mode_dell_alc288(struct hda_codec *codec, } } -static void alc_fixup_auto_mute_via_amp(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - if (action == HDA_FIXUP_ACT_PRE_PROBE) { - struct alc_spec *spec = codec->spec; - spec->gen.auto_mute_via_amp = 1; - } -} - static void alc_fixup_no_shutup(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -6241,16 +2044,6 @@ static void alc_fixup_no_shutup(struct hda_codec *codec, } } -static void alc_fixup_disable_aamix(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - if (action == HDA_FIXUP_ACT_PRE_PROBE) { - struct alc_spec *spec = codec->spec; - /* Disable AA-loopback as it causes white noise */ - spec->gen.mixer_nid = 0; - } -} - /* fixup for Thinkpad docks: add dock pins, avoid HP parser fixup */ static void alc_fixup_tpt440_dock(struct hda_codec *codec, const struct hda_fixup *fix, int action) @@ -6321,94 +2114,6 @@ static void alc295_fixup_asus_dacs(struct hda_codec *codec, spec->gen.preferred_dacs = preferred_pairs; } -static void alc_shutup_dell_xps13(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int hp_pin = alc_get_hp_pin(spec); - - /* Prevent pop noises when headphones are plugged in */ - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - msleep(20); -} - -static void alc_fixup_dell_xps13(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - struct alc_spec *spec = codec->spec; - struct hda_input_mux *imux = &spec->gen.input_mux; - int i; - - switch (action) { - case HDA_FIXUP_ACT_PRE_PROBE: - /* mic pin 0x19 must be initialized with Vref Hi-Z, otherwise - * it causes a click noise at start up - */ - snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ); - spec->shutup = alc_shutup_dell_xps13; - break; - case HDA_FIXUP_ACT_PROBE: - /* Make the internal mic the default input source. */ - for (i = 0; i < imux->num_items; i++) { - if (spec->gen.imux_pins[i] == 0x12) { - spec->gen.cur_mux[0] = i; - break; - } - } - break; - } -} - -static void alc_fixup_headset_mode_alc662(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->parse_flags |= HDA_PINCFG_HEADSET_MIC; - spec->gen.hp_mic = 1; /* Mic-in is same pin as headphone */ - - /* Disable boost for mic-in permanently. (This code is only called - from quirks that guarantee that the headphone is at NID 0x1b.) */ - snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000); - snd_hda_override_wcaps(codec, 0x1b, get_wcaps(codec, 0x1b) & ~AC_WCAP_IN_AMP); - } else - alc_fixup_headset_mode(codec, fix, action); -} - -static void alc_fixup_headset_mode_alc668(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - if (action == HDA_FIXUP_ACT_PRE_PROBE) { - alc_write_coef_idx(codec, 0xc4, 0x8000); - alc_update_coef_idx(codec, 0xc2, ~0xfe, 0); - snd_hda_set_pin_ctl_cache(codec, 0x18, 0); - } - alc_fixup_headset_mode(codec, fix, action); -} - -/* Returns the nid of the external mic input pin, or 0 if it cannot be found. */ -static int find_ext_mic_pin(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->gen.autocfg; - hda_nid_t nid; - unsigned int defcfg; - int i; - - for (i = 0; i < cfg->num_inputs; i++) { - if (cfg->inputs[i].type != AUTO_PIN_MIC) - continue; - nid = cfg->inputs[i].pin; - defcfg = snd_hda_codec_get_pincfg(codec, nid); - if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT) - continue; - return nid; - } - - return 0; -} - static void alc271_hp_gate_mic_jack(struct hda_codec *codec, const struct hda_fixup *fix, int action) @@ -6416,7 +2121,7 @@ static void alc271_hp_gate_mic_jack(struct hda_codec *codec, struct alc_spec *spec = codec->spec; if (action == HDA_FIXUP_ACT_PROBE) { - int mic_pin = find_ext_mic_pin(codec); + int mic_pin = alc_find_ext_mic_pin(codec); int hp_pin = alc_get_hp_pin(spec); if (snd_BUG_ON(!mic_pin || !hp_pin)) @@ -6694,30 +2399,6 @@ static void alc285_fixup_thinkpad_x1_gen7(struct hda_codec *codec, } } -static void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec, - const struct hda_fixup *fix, - int action) -{ - alc_fixup_dual_codecs(codec, fix, action); - switch (action) { - case HDA_FIXUP_ACT_PRE_PROBE: - /* override card longname to provide a unique UCM profile */ - strcpy(codec->card->longname, "HDAudio-Lenovo-DualCodecs"); - break; - case HDA_FIXUP_ACT_BUILD: - /* rename Capture controls depending on the codec */ - rename_ctl(codec, "Capture Volume", - codec->addr == 0 ? - "Rear-Panel Capture Volume" : - "Front-Panel Capture Volume"); - rename_ctl(codec, "Capture Switch", - codec->addr == 0 ? - "Rear-Panel Capture Switch" : - "Front-Panel Capture Switch"); - break; - } -} - static void alc225_fixup_s3_pop_noise(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -7120,7 +2801,7 @@ static void alc285_fixup_hp_beep(struct hda_codec *codec, } /* for hda_fixup_thinkpad_acpi() */ -#include "helpers/thinkpad.c" +#include "../helpers/thinkpad.c" static void alc_fixup_thinkpad_acpi(struct hda_codec *codec, const struct hda_fixup *fix, int action) @@ -7130,7 +2811,7 @@ static void alc_fixup_thinkpad_acpi(struct hda_codec *codec, } /* for hda_fixup_ideapad_acpi() */ -#include "helpers/ideapad_hotkey_led.c" +#include "../helpers/ideapad_hotkey_led.c" static void alc_fixup_ideapad_acpi(struct hda_codec *codec, const struct hda_fixup *fix, int action) @@ -7362,10 +3043,10 @@ static void alc256_fixup_acer_sfg16_micmute_led(struct hda_codec *codec, /* for alc295_fixup_hp_top_speakers */ -#include "helpers/hp_x360.c" +#include "../helpers/hp_x360.c" /* for alc285_fixup_ideapad_s740_coef() */ -#include "helpers/ideapad_s740.c" +#include "../helpers/ideapad_s740.c" static const struct coef_fw alc256_fixup_set_coef_defaults_coefs[] = { WRITE_COEF(0x10, 0x0020), WRITE_COEF(0x24, 0x0000), @@ -7567,9 +3248,10 @@ static void alc287_fixup_bind_dacs(struct hda_codec *codec, 0x0); /* Make sure 0x14 was disable */ } } + /* Fix none verb table of Headset Mic pin */ -static void alc_fixup_headset_mic(struct hda_codec *codec, - const struct hda_fixup *fix, int action) +static void alc2xx_fixup_headset_mic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; static const struct hda_pintbl pincfgs[] = { @@ -8164,7 +3846,7 @@ static const struct hda_fixup alc269_fixups[] = { }, [ALC269_FIXUP_HEADSET_MIC] = { .type = HDA_FIXUP_FUNC, - .v.func = alc269_fixup_headset_mic, + .v.func = alc_fixup_headset_mic, }, [ALC269_FIXUP_QUANTA_MUTE] = { .type = HDA_FIXUP_FUNC, @@ -10324,7 +6006,7 @@ static const struct hda_fixup alc269_fixups[] = { }, [ALC2XX_FIXUP_HEADSET_MIC] = { .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_headset_mic, + .v.func = alc2xx_fixup_headset_mic, }, [ALC289_FIXUP_DELL_CS35L41_SPI_2] = { .type = HDA_FIXUP_FUNC, @@ -12160,6 +7842,16 @@ static void alc269_fill_coef(struct hda_codec *codec) alc_update_coef_idx(codec, 0x4, 0, 1<<11); } +static void alc269_free(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (spec) + hda_component_manager_free(&spec->comps, &comp_master_ops); + + alc_free(codec); +} + /* */ static int patch_alc269(struct hda_codec *codec) @@ -12178,6 +7870,7 @@ static int patch_alc269(struct hda_codec *codec) codec->patch_ops.suspend = alc269_suspend; codec->patch_ops.resume = alc269_resume; + codec->patch_ops.free = alc269_free; spec->shutup = alc_default_shutup; spec->init_hook = alc_default_init; @@ -12380,1327 +8073,9 @@ static int patch_alc269(struct hda_codec *codec) } /* - * ALC861 + * driver entries */ - -static int alc861_parse_auto_config(struct hda_codec *codec) -{ - static const hda_nid_t alc861_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 }; - return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids); -} - -/* Pin config fixes */ -enum { - ALC861_FIXUP_FSC_AMILO_PI1505, - ALC861_FIXUP_AMP_VREF_0F, - ALC861_FIXUP_NO_JACK_DETECT, - ALC861_FIXUP_ASUS_A6RP, - ALC660_FIXUP_ASUS_W7J, -}; - -/* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */ -static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - struct alc_spec *spec = codec->spec; - unsigned int val; - - if (action != HDA_FIXUP_ACT_INIT) - return; - val = snd_hda_codec_get_pin_target(codec, 0x0f); - if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))) - val |= AC_PINCTL_IN_EN; - val |= AC_PINCTL_VREF_50; - snd_hda_set_pin_ctl(codec, 0x0f, val); - spec->gen.keep_vref_in_automute = 1; -} - -/* suppress the jack-detection */ -static void alc_fixup_no_jack_detect(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - if (action == HDA_FIXUP_ACT_PRE_PROBE) - codec->no_jack_detect = 1; -} - -static const struct hda_fixup alc861_fixups[] = { - [ALC861_FIXUP_FSC_AMILO_PI1505] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x0b, 0x0221101f }, /* HP */ - { 0x0f, 0x90170310 }, /* speaker */ - { } - } - }, - [ALC861_FIXUP_AMP_VREF_0F] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc861_fixup_asus_amp_vref_0f, - }, - [ALC861_FIXUP_NO_JACK_DETECT] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_no_jack_detect, - }, - [ALC861_FIXUP_ASUS_A6RP] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc861_fixup_asus_amp_vref_0f, - .chained = true, - .chain_id = ALC861_FIXUP_NO_JACK_DETECT, - }, - [ALC660_FIXUP_ASUS_W7J] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - /* ASUS W7J needs a magic pin setup on unused NID 0x10 - * for enabling outputs - */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - { } - }, - } -}; - -static const struct hda_quirk alc861_fixup_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1253, "ASUS W7J", ALC660_FIXUP_ASUS_W7J), - SND_PCI_QUIRK(0x1043, 0x1263, "ASUS Z35HL", ALC660_FIXUP_ASUS_W7J), - SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP), - SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F), - SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT), - SND_PCI_QUIRK_VENDOR(0x1584, "Haier/Uniwill", ALC861_FIXUP_AMP_VREF_0F), - SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", ALC861_FIXUP_FSC_AMILO_PI1505), - {} -}; - -/* - */ -static int patch_alc861(struct hda_codec *codec) -{ - struct alc_spec *spec; - int err; - - err = alc_alloc_spec(codec, 0x15); - if (err < 0) - return err; - - spec = codec->spec; - if (has_cdefine_beep(codec)) - spec->gen.beep_nid = 0x23; - - spec->power_hook = alc_power_eapd; - - alc_pre_init(codec); - - snd_hda_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups); - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - - /* automatic parse from the BIOS config */ - err = alc861_parse_auto_config(codec); - if (err < 0) - goto error; - - if (!spec->gen.no_analog) { - err = set_beep_amp(spec, 0x23, 0, HDA_OUTPUT); - if (err < 0) - goto error; - } - - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); - - return 0; - - error: - alc_free(codec); - return err; -} - -/* - * ALC861-VD support - * - * Based on ALC882 - * - * In addition, an independent DAC - */ -static int alc861vd_parse_auto_config(struct hda_codec *codec) -{ - static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids); -} - -enum { - ALC660VD_FIX_ASUS_GPIO1, - ALC861VD_FIX_DALLAS, -}; - -/* exclude VREF80 */ -static void alc861vd_fixup_dallas(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - if (action == HDA_FIXUP_ACT_PRE_PROBE) { - snd_hda_override_pin_caps(codec, 0x18, 0x00000734); - snd_hda_override_pin_caps(codec, 0x19, 0x0000073c); - } -} - -/* reset GPIO1 */ -static void alc660vd_fixup_asus_gpio1(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->gpio_mask |= 0x02; - alc_fixup_gpio(codec, action, 0x01); -} - -static const struct hda_fixup alc861vd_fixups[] = { - [ALC660VD_FIX_ASUS_GPIO1] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc660vd_fixup_asus_gpio1, - }, - [ALC861VD_FIX_DALLAS] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc861vd_fixup_dallas, - }, -}; - -static const struct hda_quirk alc861vd_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS), - SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1), - SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS), - {} -}; - -/* - */ -static int patch_alc861vd(struct hda_codec *codec) -{ - struct alc_spec *spec; - int err; - - err = alc_alloc_spec(codec, 0x0b); - if (err < 0) - return err; - - spec = codec->spec; - if (has_cdefine_beep(codec)) - spec->gen.beep_nid = 0x23; - - spec->shutup = alc_eapd_shutup; - - alc_pre_init(codec); - - snd_hda_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups); - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - - /* automatic parse from the BIOS config */ - err = alc861vd_parse_auto_config(codec); - if (err < 0) - goto error; - - if (!spec->gen.no_analog) { - err = set_beep_amp(spec, 0x0b, 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; -} - -/* - * ALC662 support - * - * ALC662 is almost identical with ALC880 but has cleaner and more flexible - * configuration. Each pin widget can choose any input DACs and a mixer. - * Each ADC is connected from a mixer of all inputs. This makes possible - * 6-channel independent captures. - * - * In addition, an independent DAC for the multi-playback (not used in this - * driver yet). - */ - -/* - * BIOS auto configuration - */ - -static int alc662_parse_auto_config(struct hda_codec *codec) -{ - static const hda_nid_t alc662_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 }; - static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - const hda_nid_t *ssids; - - if (codec->core.vendor_id == 0x10ec0272 || codec->core.vendor_id == 0x10ec0663 || - codec->core.vendor_id == 0x10ec0665 || codec->core.vendor_id == 0x10ec0670 || - codec->core.vendor_id == 0x10ec0671) - ssids = alc663_ssids; - else - ssids = alc662_ssids; - return alc_parse_auto_config(codec, alc662_ignore, ssids); -} - -static void alc272_fixup_mario(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - if (action != HDA_FIXUP_ACT_PRE_PROBE) - return; - if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT, - (0x3b << AC_AMPCAP_OFFSET_SHIFT) | - (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (0 << AC_AMPCAP_MUTE_SHIFT))) - codec_warn(codec, "failed to override amp caps for NID 0x2\n"); -} - -static const struct snd_pcm_chmap_elem asus_pcm_2_1_chmaps[] = { - { .channels = 2, - .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, - { .channels = 4, - .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, - SNDRV_CHMAP_NA, SNDRV_CHMAP_LFE } }, /* LFE only on right */ - { } -}; - -/* override the 2.1 chmap */ -static void alc_fixup_bass_chmap(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - if (action == HDA_FIXUP_ACT_BUILD) { - struct alc_spec *spec = codec->spec; - spec->gen.pcm_rec[0]->stream[0].chmap = asus_pcm_2_1_chmaps; - } -} - -/* avoid D3 for keeping GPIO up */ -static unsigned int gpio_led_power_filter(struct hda_codec *codec, - hda_nid_t nid, - unsigned int power_state) -{ - struct alc_spec *spec = codec->spec; - if (nid == codec->core.afg && power_state == AC_PWRST_D3 && spec->gpio_data) - return AC_PWRST_D0; - return power_state; -} - -static void alc662_fixup_led_gpio1(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - struct alc_spec *spec = codec->spec; - - alc_fixup_hp_gpio_led(codec, action, 0x01, 0); - if (action == HDA_FIXUP_ACT_PRE_PROBE) { - spec->mute_led_polarity = 1; - codec->power_filter = gpio_led_power_filter; - } -} - -static void alc662_usi_automute_hook(struct hda_codec *codec, - struct hda_jack_callback *jack) -{ - struct alc_spec *spec = codec->spec; - int vref; - msleep(200); - snd_hda_gen_hp_automute(codec, jack); - - vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0; - msleep(100); - snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - vref); -} - -static void alc662_fixup_usi_headset_mic(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->parse_flags |= HDA_PINCFG_HEADSET_MIC; - spec->gen.hp_automute_hook = alc662_usi_automute_hook; - } -} - -static void alc662_aspire_ethos_mute_speakers(struct hda_codec *codec, - struct hda_jack_callback *cb) -{ - /* surround speakers at 0x1b already get muted automatically when - * headphones are plugged in, but we have to mute/unmute the remaining - * channels manually: - * 0x15 - front left/front right - * 0x18 - front center/ LFE - */ - if (snd_hda_jack_detect_state(codec, 0x1b) == HDA_JACK_PRESENT) { - snd_hda_set_pin_ctl_cache(codec, 0x15, 0); - snd_hda_set_pin_ctl_cache(codec, 0x18, 0); - } else { - snd_hda_set_pin_ctl_cache(codec, 0x15, PIN_OUT); - snd_hda_set_pin_ctl_cache(codec, 0x18, PIN_OUT); - } -} - -static void alc662_fixup_aspire_ethos_hp(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - /* Pin 0x1b: shared headphones jack and surround speakers */ - if (!is_jack_detectable(codec, 0x1b)) - return; - - switch (action) { - case HDA_FIXUP_ACT_PRE_PROBE: - snd_hda_jack_detect_enable_callback(codec, 0x1b, - alc662_aspire_ethos_mute_speakers); - /* subwoofer needs an extra GPIO setting to become audible */ - alc_setup_gpio(codec, 0x02); - break; - case HDA_FIXUP_ACT_INIT: - /* Make sure to start in a correct state, i.e. if - * headphones have been plugged in before powering up the system - */ - alc662_aspire_ethos_mute_speakers(codec, NULL); - break; - } -} - -static void alc671_fixup_hp_headset_mic2(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - struct alc_spec *spec = codec->spec; - - static const struct hda_pintbl pincfgs[] = { - { 0x19, 0x02a11040 }, /* use as headset mic, with its own jack detect */ - { 0x1b, 0x0181304f }, - { } - }; - - switch (action) { - case HDA_FIXUP_ACT_PRE_PROBE: - spec->gen.mixer_nid = 0; - spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; - snd_hda_apply_pincfgs(codec, pincfgs); - break; - case HDA_FIXUP_ACT_INIT: - alc_write_coef_idx(codec, 0x19, 0xa054); - break; - } -} - -static void alc897_hp_automute_hook(struct hda_codec *codec, - struct hda_jack_callback *jack) -{ - struct alc_spec *spec = codec->spec; - int vref; - - snd_hda_gen_hp_automute(codec, jack); - vref = spec->gen.hp_jack_present ? (PIN_HP | AC_PINCTL_VREF_100) : PIN_HP; - snd_hda_set_pin_ctl(codec, 0x1b, vref); -} - -static void alc897_fixup_lenovo_headset_mic(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.hp_automute_hook = alc897_hp_automute_hook; - spec->no_shutup_pins = 1; - } - if (action == HDA_FIXUP_ACT_PROBE) { - snd_hda_set_pin_ctl_cache(codec, 0x1a, PIN_IN | AC_PINCTL_VREF_100); - } -} - -static void alc897_fixup_lenovo_headset_mode(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->parse_flags |= HDA_PINCFG_HEADSET_MIC; - spec->gen.hp_automute_hook = alc897_hp_automute_hook; - } -} - -static const struct coef_fw alc668_coefs[] = { - WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03, 0x0), - WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06, 0x0), WRITE_COEF(0x07, 0x0f80), - WRITE_COEF(0x08, 0x0031), WRITE_COEF(0x0a, 0x0060), WRITE_COEF(0x0b, 0x0), - WRITE_COEF(0x0c, 0x7cf7), WRITE_COEF(0x0d, 0x1080), WRITE_COEF(0x0e, 0x7f7f), - WRITE_COEF(0x0f, 0xcccc), WRITE_COEF(0x10, 0xddcc), WRITE_COEF(0x11, 0x0001), - WRITE_COEF(0x13, 0x0), WRITE_COEF(0x14, 0x2aa0), WRITE_COEF(0x17, 0xa940), - WRITE_COEF(0x19, 0x0), WRITE_COEF(0x1a, 0x0), WRITE_COEF(0x1b, 0x0), - WRITE_COEF(0x1c, 0x0), WRITE_COEF(0x1d, 0x0), WRITE_COEF(0x1e, 0x7418), - WRITE_COEF(0x1f, 0x0804), WRITE_COEF(0x20, 0x4200), WRITE_COEF(0x21, 0x0468), - WRITE_COEF(0x22, 0x8ccc), WRITE_COEF(0x23, 0x0250), WRITE_COEF(0x24, 0x7418), - WRITE_COEF(0x27, 0x0), WRITE_COEF(0x28, 0x8ccc), WRITE_COEF(0x2a, 0xff00), - WRITE_COEF(0x2b, 0x8000), WRITE_COEF(0xa7, 0xff00), WRITE_COEF(0xa8, 0x8000), - WRITE_COEF(0xaa, 0x2e17), WRITE_COEF(0xab, 0xa0c0), WRITE_COEF(0xac, 0x0), - WRITE_COEF(0xad, 0x0), WRITE_COEF(0xae, 0x2ac6), WRITE_COEF(0xaf, 0xa480), - WRITE_COEF(0xb0, 0x0), WRITE_COEF(0xb1, 0x0), WRITE_COEF(0xb2, 0x0), - WRITE_COEF(0xb3, 0x0), WRITE_COEF(0xb4, 0x0), WRITE_COEF(0xb5, 0x1040), - WRITE_COEF(0xb6, 0xd697), WRITE_COEF(0xb7, 0x902b), WRITE_COEF(0xb8, 0xd697), - WRITE_COEF(0xb9, 0x902b), WRITE_COEF(0xba, 0xb8ba), WRITE_COEF(0xbb, 0xaaab), - WRITE_COEF(0xbc, 0xaaaf), WRITE_COEF(0xbd, 0x6aaa), WRITE_COEF(0xbe, 0x1c02), - WRITE_COEF(0xc0, 0x00ff), WRITE_COEF(0xc1, 0x0fa6), - {} -}; - -static void alc668_restore_default_value(struct hda_codec *codec) -{ - alc_process_coef_fw(codec, alc668_coefs); -} - -enum { - ALC662_FIXUP_ASPIRE, - ALC662_FIXUP_LED_GPIO1, - ALC662_FIXUP_IDEAPAD, - ALC272_FIXUP_MARIO, - ALC662_FIXUP_CZC_ET26, - ALC662_FIXUP_CZC_P10T, - ALC662_FIXUP_SKU_IGNORE, - ALC662_FIXUP_HP_RP5800, - ALC662_FIXUP_ASUS_MODE1, - ALC662_FIXUP_ASUS_MODE2, - ALC662_FIXUP_ASUS_MODE3, - ALC662_FIXUP_ASUS_MODE4, - ALC662_FIXUP_ASUS_MODE5, - ALC662_FIXUP_ASUS_MODE6, - ALC662_FIXUP_ASUS_MODE7, - ALC662_FIXUP_ASUS_MODE8, - ALC662_FIXUP_NO_JACK_DETECT, - ALC662_FIXUP_ZOTAC_Z68, - ALC662_FIXUP_INV_DMIC, - ALC662_FIXUP_DELL_MIC_NO_PRESENCE, - ALC668_FIXUP_DELL_MIC_NO_PRESENCE, - ALC662_FIXUP_HEADSET_MODE, - ALC668_FIXUP_HEADSET_MODE, - ALC662_FIXUP_BASS_MODE4_CHMAP, - ALC662_FIXUP_BASS_16, - ALC662_FIXUP_BASS_1A, - ALC662_FIXUP_BASS_CHMAP, - ALC668_FIXUP_AUTO_MUTE, - ALC668_FIXUP_DELL_DISABLE_AAMIX, - ALC668_FIXUP_DELL_XPS13, - ALC662_FIXUP_ASUS_Nx50, - ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE, - ALC668_FIXUP_ASUS_Nx51, - ALC668_FIXUP_MIC_COEF, - ALC668_FIXUP_ASUS_G751, - ALC891_FIXUP_HEADSET_MODE, - ALC891_FIXUP_DELL_MIC_NO_PRESENCE, - ALC662_FIXUP_ACER_VERITON, - ALC892_FIXUP_ASROCK_MOBO, - ALC662_FIXUP_USI_FUNC, - ALC662_FIXUP_USI_HEADSET_MODE, - ALC662_FIXUP_LENOVO_MULTI_CODECS, - ALC669_FIXUP_ACER_ASPIRE_ETHOS, - ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET, - ALC671_FIXUP_HP_HEADSET_MIC2, - ALC662_FIXUP_ACER_X2660G_HEADSET_MODE, - ALC662_FIXUP_ACER_NITRO_HEADSET_MODE, - ALC668_FIXUP_ASUS_NO_HEADSET_MIC, - ALC668_FIXUP_HEADSET_MIC, - ALC668_FIXUP_MIC_DET_COEF, - ALC897_FIXUP_LENOVO_HEADSET_MIC, - ALC897_FIXUP_HEADSET_MIC_PIN, - ALC897_FIXUP_HP_HSMIC_VERB, - ALC897_FIXUP_LENOVO_HEADSET_MODE, - ALC897_FIXUP_HEADSET_MIC_PIN2, - ALC897_FIXUP_UNIS_H3C_X500S, - ALC897_FIXUP_HEADSET_MIC_PIN3, -}; - -static const struct hda_fixup alc662_fixups[] = { - [ALC662_FIXUP_ASPIRE] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x15, 0x99130112 }, /* subwoofer */ - { } - } - }, - [ALC662_FIXUP_LED_GPIO1] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc662_fixup_led_gpio1, - }, - [ALC662_FIXUP_IDEAPAD] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x17, 0x99130112 }, /* subwoofer */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_LED_GPIO1, - }, - [ALC272_FIXUP_MARIO] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc272_fixup_mario, - }, - [ALC662_FIXUP_CZC_ET26] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - {0x12, 0x403cc000}, - {0x14, 0x90170110}, /* speaker */ - {0x15, 0x411111f0}, - {0x16, 0x411111f0}, - {0x18, 0x01a19030}, /* mic */ - {0x19, 0x90a7013f}, /* int-mic */ - {0x1a, 0x01014020}, - {0x1b, 0x0121401f}, - {0x1c, 0x411111f0}, - {0x1d, 0x411111f0}, - {0x1e, 0x40478e35}, - {} - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, - [ALC662_FIXUP_CZC_P10T] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0}, - {} - } - }, - [ALC662_FIXUP_SKU_IGNORE] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_sku_ignore, - }, - [ALC662_FIXUP_HP_RP5800] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x0221201f }, /* HP out */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, - [ALC662_FIXUP_ASUS_MODE1] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x18, 0x01a19c20 }, /* mic */ - { 0x19, 0x99a3092f }, /* int-mic */ - { 0x21, 0x0121401f }, /* HP out */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, - [ALC662_FIXUP_ASUS_MODE2] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x18, 0x01a19820 }, /* mic */ - { 0x19, 0x99a3092f }, /* int-mic */ - { 0x1b, 0x0121401f }, /* HP out */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, - [ALC662_FIXUP_ASUS_MODE3] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x15, 0x0121441f }, /* HP */ - { 0x18, 0x01a19840 }, /* mic */ - { 0x19, 0x99a3094f }, /* int-mic */ - { 0x21, 0x01211420 }, /* HP2 */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, - [ALC662_FIXUP_ASUS_MODE4] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x16, 0x99130111 }, /* speaker */ - { 0x18, 0x01a19840 }, /* mic */ - { 0x19, 0x99a3094f }, /* int-mic */ - { 0x21, 0x0121441f }, /* HP */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, - [ALC662_FIXUP_ASUS_MODE5] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x15, 0x0121441f }, /* HP */ - { 0x16, 0x99130111 }, /* speaker */ - { 0x18, 0x01a19840 }, /* mic */ - { 0x19, 0x99a3094f }, /* int-mic */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, - [ALC662_FIXUP_ASUS_MODE6] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x15, 0x01211420 }, /* HP2 */ - { 0x18, 0x01a19840 }, /* mic */ - { 0x19, 0x99a3094f }, /* int-mic */ - { 0x1b, 0x0121441f }, /* HP */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, - [ALC662_FIXUP_ASUS_MODE7] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x17, 0x99130111 }, /* speaker */ - { 0x18, 0x01a19840 }, /* mic */ - { 0x19, 0x99a3094f }, /* int-mic */ - { 0x1b, 0x01214020 }, /* HP */ - { 0x21, 0x0121401f }, /* HP */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, - [ALC662_FIXUP_ASUS_MODE8] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x12, 0x99a30970 }, /* int-mic */ - { 0x15, 0x01214020 }, /* HP */ - { 0x17, 0x99130111 }, /* speaker */ - { 0x18, 0x01a19840 }, /* mic */ - { 0x21, 0x0121401f }, /* HP */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, - [ALC662_FIXUP_NO_JACK_DETECT] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_no_jack_detect, - }, - [ALC662_FIXUP_ZOTAC_Z68] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x1b, 0x02214020 }, /* Front HP */ - { } - } - }, - [ALC662_FIXUP_INV_DMIC] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_inv_dmic, - }, - [ALC668_FIXUP_DELL_XPS13] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_dell_xps13, - .chained = true, - .chain_id = ALC668_FIXUP_DELL_DISABLE_AAMIX - }, - [ALC668_FIXUP_DELL_DISABLE_AAMIX] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_disable_aamix, - .chained = true, - .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE - }, - [ALC668_FIXUP_AUTO_MUTE] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_auto_mute_via_amp, - .chained = true, - .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE - }, - [ALC662_FIXUP_DELL_MIC_NO_PRESENCE] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x19, 0x03a1113c }, /* use as headset mic, without its own jack detect */ - /* headphone mic by setting pin control of 0x1b (headphone out) to in + vref_50 */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_HEADSET_MODE - }, - [ALC662_FIXUP_HEADSET_MODE] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_headset_mode_alc662, - }, - [ALC668_FIXUP_DELL_MIC_NO_PRESENCE] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */ - { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */ - { } - }, - .chained = true, - .chain_id = ALC668_FIXUP_HEADSET_MODE - }, - [ALC668_FIXUP_HEADSET_MODE] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_headset_mode_alc668, - }, - [ALC662_FIXUP_BASS_MODE4_CHMAP] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_bass_chmap, - .chained = true, - .chain_id = ALC662_FIXUP_ASUS_MODE4 - }, - [ALC662_FIXUP_BASS_16] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - {0x16, 0x80106111}, /* bass speaker */ - {} - }, - .chained = true, - .chain_id = ALC662_FIXUP_BASS_CHMAP, - }, - [ALC662_FIXUP_BASS_1A] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - {0x1a, 0x80106111}, /* bass speaker */ - {} - }, - .chained = true, - .chain_id = ALC662_FIXUP_BASS_CHMAP, - }, - [ALC662_FIXUP_BASS_CHMAP] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_bass_chmap, - }, - [ALC662_FIXUP_ASUS_Nx50] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_auto_mute_via_amp, - .chained = true, - .chain_id = ALC662_FIXUP_BASS_1A - }, - [ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_headset_mode_alc668, - .chain_id = ALC662_FIXUP_BASS_CHMAP - }, - [ALC668_FIXUP_ASUS_Nx51] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */ - { 0x1a, 0x90170151 }, /* bass speaker */ - { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */ - {} - }, - .chained = true, - .chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE, - }, - [ALC668_FIXUP_MIC_COEF] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - { 0x20, AC_VERB_SET_COEF_INDEX, 0xc3 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x4000 }, - {} - }, - }, - [ALC668_FIXUP_ASUS_G751] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x16, 0x0421101f }, /* HP */ - {} - }, - .chained = true, - .chain_id = ALC668_FIXUP_MIC_COEF - }, - [ALC891_FIXUP_HEADSET_MODE] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_headset_mode, - }, - [ALC891_FIXUP_DELL_MIC_NO_PRESENCE] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */ - { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */ - { } - }, - .chained = true, - .chain_id = ALC891_FIXUP_HEADSET_MODE - }, - [ALC662_FIXUP_ACER_VERITON] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x15, 0x50170120 }, /* no internal speaker */ - { } - } - }, - [ALC892_FIXUP_ASROCK_MOBO] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x15, 0x40f000f0 }, /* disabled */ - { 0x16, 0x40f000f0 }, /* disabled */ - { } - } - }, - [ALC662_FIXUP_USI_FUNC] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc662_fixup_usi_headset_mic, - }, - [ALC662_FIXUP_USI_HEADSET_MODE] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x19, 0x02a1913c }, /* use as headset mic, without its own jack detect */ - { 0x18, 0x01a1903d }, - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_USI_FUNC - }, - [ALC662_FIXUP_LENOVO_MULTI_CODECS] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc233_alc662_fixup_lenovo_dual_codecs, - }, - [ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc662_fixup_aspire_ethos_hp, - }, - [ALC669_FIXUP_ACER_ASPIRE_ETHOS] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x15, 0x92130110 }, /* front speakers */ - { 0x18, 0x99130111 }, /* center/subwoofer */ - { 0x1b, 0x11130012 }, /* surround plus jack for HP */ - { } - }, - .chained = true, - .chain_id = ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET - }, - [ALC671_FIXUP_HP_HEADSET_MIC2] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc671_fixup_hp_headset_mic2, - }, - [ALC662_FIXUP_ACER_X2660G_HEADSET_MODE] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x1a, 0x02a1113c }, /* use as headset mic, without its own jack detect */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_USI_FUNC - }, - [ALC662_FIXUP_ACER_NITRO_HEADSET_MODE] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */ - { 0x1b, 0x0221144f }, - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_USI_FUNC - }, - [ALC668_FIXUP_ASUS_NO_HEADSET_MIC] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x1b, 0x04a1112c }, - { } - }, - .chained = true, - .chain_id = ALC668_FIXUP_HEADSET_MIC - }, - [ALC668_FIXUP_HEADSET_MIC] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc269_fixup_headset_mic, - .chained = true, - .chain_id = ALC668_FIXUP_MIC_DET_COEF - }, - [ALC668_FIXUP_MIC_DET_COEF] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - { 0x20, AC_VERB_SET_COEF_INDEX, 0x15 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x0d60 }, - {} - }, - }, - [ALC897_FIXUP_LENOVO_HEADSET_MIC] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc897_fixup_lenovo_headset_mic, - }, - [ALC897_FIXUP_HEADSET_MIC_PIN] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x1a, 0x03a11050 }, - { } - }, - .chained = true, - .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MIC - }, - [ALC897_FIXUP_HP_HSMIC_VERB] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */ - { } - }, - }, - [ALC897_FIXUP_LENOVO_HEADSET_MODE] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc897_fixup_lenovo_headset_mode, - }, - [ALC897_FIXUP_HEADSET_MIC_PIN2] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */ - { } - }, - .chained = true, - .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MODE - }, - [ALC897_FIXUP_UNIS_H3C_X500S] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - { 0x14, AC_VERB_SET_EAPD_BTLENABLE, 0 }, - {} - }, - }, - [ALC897_FIXUP_HEADSET_MIC_PIN3] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x19, 0x03a11050 }, /* use as headset mic */ - { } - }, - }, -}; - -static const struct hda_quirk alc662_fixup_tbl[] = { - SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1019, 0x9859, "JP-IK LEAP W502", ALC897_FIXUP_HEADSET_MIC_PIN3), - SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC), - SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC), - SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE), - SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE), - SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC), - SND_PCI_QUIRK(0x1025, 0x034a, "Gateway LT27", ALC662_FIXUP_INV_DMIC), - SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), - SND_PCI_QUIRK(0x1025, 0x0566, "Acer Aspire Ethos 8951G", ALC669_FIXUP_ACER_ASPIRE_ETHOS), - SND_PCI_QUIRK(0x1025, 0x123c, "Acer Nitro N50-600", ALC662_FIXUP_ACER_NITRO_HEADSET_MODE), - SND_PCI_QUIRK(0x1025, 0x124e, "Acer 2660G", ALC662_FIXUP_ACER_X2660G_HEADSET_MODE), - SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05fe, "Dell XPS 15", ALC668_FIXUP_DELL_XPS13), - SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_XPS13), - SND_PCI_QUIRK(0x1028, 0x060d, "Dell M3800", ALC668_FIXUP_DELL_XPS13), - SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), - SND_PCI_QUIRK(0x103c, 0x870c, "HP", ALC897_FIXUP_HP_HSMIC_VERB), - SND_PCI_QUIRK(0x103c, 0x8719, "HP", ALC897_FIXUP_HP_HSMIC_VERB), - SND_PCI_QUIRK(0x103c, 0x872b, "HP", ALC897_FIXUP_HP_HSMIC_VERB), - SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2), - SND_PCI_QUIRK(0x103c, 0x8768, "HP Slim Desktop S01", ALC671_FIXUP_HP_HEADSET_MIC2), - SND_PCI_QUIRK(0x103c, 0x877e, "HP 288 Pro G6", ALC671_FIXUP_HP_HEADSET_MIC2), - SND_PCI_QUIRK(0x103c, 0x885f, "HP 288 Pro G8", ALC671_FIXUP_HP_HEADSET_MIC2), - SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE), - SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50), - SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50), - SND_PCI_QUIRK(0x1043, 0x12ff, "ASUS G751", ALC668_FIXUP_ASUS_G751), - SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A), - SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), - SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16), - SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51), - SND_PCI_QUIRK(0x1043, 0x17bd, "ASUS N751", ALC668_FIXUP_ASUS_Nx51), - SND_PCI_QUIRK(0x1043, 0x185d, "ASUS G551JW", ALC668_FIXUP_ASUS_NO_HEADSET_MIC), - SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71SL", ALC662_FIXUP_ASUS_MODE8), - SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16), - SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), - SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT), - SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), - SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE), - SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS), - SND_PCI_QUIRK(0x17aa, 0x1057, "Lenovo P360", ALC897_FIXUP_HEADSET_MIC_PIN), - SND_PCI_QUIRK(0x17aa, 0x1064, "Lenovo P3 Tower", ALC897_FIXUP_HEADSET_MIC_PIN), - SND_PCI_QUIRK(0x17aa, 0x32ca, "Lenovo ThinkCentre M80", ALC897_FIXUP_HEADSET_MIC_PIN), - SND_PCI_QUIRK(0x17aa, 0x32cb, "Lenovo ThinkCentre M70", ALC897_FIXUP_HEADSET_MIC_PIN), - SND_PCI_QUIRK(0x17aa, 0x32cf, "Lenovo ThinkCentre M950", ALC897_FIXUP_HEADSET_MIC_PIN), - SND_PCI_QUIRK(0x17aa, 0x32f7, "Lenovo ThinkCentre M90", ALC897_FIXUP_HEADSET_MIC_PIN), - SND_PCI_QUIRK(0x17aa, 0x3321, "Lenovo ThinkCentre M70 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN), - SND_PCI_QUIRK(0x17aa, 0x331b, "Lenovo ThinkCentre M90 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN), - SND_PCI_QUIRK(0x17aa, 0x3364, "Lenovo ThinkCentre M90 Gen5", ALC897_FIXUP_HEADSET_MIC_PIN), - SND_PCI_QUIRK(0x17aa, 0x3742, "Lenovo TianYi510Pro-14IOB", ALC897_FIXUP_HEADSET_MIC_PIN2), - SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), - SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD), - SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO), - SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68), - SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON), - SND_PCI_QUIRK(0x1b35, 0x1234, "CZC ET26", ALC662_FIXUP_CZC_ET26), - SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T), - SND_PCI_QUIRK(0x1c6c, 0x1239, "Compaq N14JP6-V2", ALC897_FIXUP_HP_HSMIC_VERB), - -#if 0 - /* Below is a quirk table taken from the old code. - * Basically the device should work as is without the fixup table. - * If BIOS doesn't give a proper info, enable the corresponding - * fixup entry. - */ - SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC662_FIXUP_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC662_FIXUP_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC662_FIXUP_ASUS_MODE7), - SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC662_FIXUP_ASUS_MODE7), - SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC662_FIXUP_ASUS_MODE8), - SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC662_FIXUP_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC662_FIXUP_ASUS_MODE6), - SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC662_FIXUP_ASUS_MODE6), - SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC662_FIXUP_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC662_FIXUP_ASUS_MODE5), - SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC662_FIXUP_ASUS_MODE6), - SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC662_FIXUP_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC662_FIXUP_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC662_FIXUP_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE4), -#endif - {} -}; - -static const struct hda_model_fixup alc662_fixup_models[] = { - {.id = ALC662_FIXUP_ASPIRE, .name = "aspire"}, - {.id = ALC662_FIXUP_IDEAPAD, .name = "ideapad"}, - {.id = ALC272_FIXUP_MARIO, .name = "mario"}, - {.id = ALC662_FIXUP_HP_RP5800, .name = "hp-rp5800"}, - {.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"}, - {.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"}, - {.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"}, - {.id = ALC662_FIXUP_ASUS_MODE4, .name = "asus-mode4"}, - {.id = ALC662_FIXUP_ASUS_MODE5, .name = "asus-mode5"}, - {.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"}, - {.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"}, - {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"}, - {.id = ALC662_FIXUP_ZOTAC_Z68, .name = "zotac-z68"}, - {.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"}, - {.id = ALC662_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc662-headset-multi"}, - {.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"}, - {.id = ALC662_FIXUP_HEADSET_MODE, .name = "alc662-headset"}, - {.id = ALC668_FIXUP_HEADSET_MODE, .name = "alc668-headset"}, - {.id = ALC662_FIXUP_BASS_16, .name = "bass16"}, - {.id = ALC662_FIXUP_BASS_1A, .name = "bass1a"}, - {.id = ALC668_FIXUP_AUTO_MUTE, .name = "automute"}, - {.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"}, - {.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"}, - {.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"}, - {.id = ALC668_FIXUP_ASUS_G751, .name = "asus-g751"}, - {.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"}, - {.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"}, - {.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"}, - {.id = ALC892_FIXUP_ASROCK_MOBO, .name = "asrock-mobo"}, - {.id = ALC662_FIXUP_USI_HEADSET_MODE, .name = "usi-headset"}, - {.id = ALC662_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"}, - {.id = ALC669_FIXUP_ACER_ASPIRE_ETHOS, .name = "aspire-ethos"}, - {.id = ALC897_FIXUP_UNIS_H3C_X500S, .name = "unis-h3c-x500s"}, - {} -}; - -static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = { - SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE, - {0x17, 0x02211010}, - {0x18, 0x01a19030}, - {0x1a, 0x01813040}, - {0x21, 0x01014020}), - SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE, - {0x16, 0x01813030}, - {0x17, 0x02211010}, - {0x18, 0x01a19040}, - {0x21, 0x01014020}), - SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE, - {0x14, 0x01014010}, - {0x18, 0x01a19020}, - {0x1a, 0x0181302f}, - {0x1b, 0x0221401f}), - SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, - {0x12, 0x99a30130}, - {0x14, 0x90170110}, - {0x15, 0x0321101f}, - {0x16, 0x03011020}), - SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, - {0x12, 0x99a30140}, - {0x14, 0x90170110}, - {0x15, 0x0321101f}, - {0x16, 0x03011020}), - SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, - {0x12, 0x99a30150}, - {0x14, 0x90170110}, - {0x15, 0x0321101f}, - {0x16, 0x03011020}), - SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, - {0x14, 0x90170110}, - {0x15, 0x0321101f}, - {0x16, 0x03011020}), - SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell XPS 15", ALC668_FIXUP_AUTO_MUTE, - {0x12, 0x90a60130}, - {0x14, 0x90170110}, - {0x15, 0x0321101f}), - SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2, - {0x14, 0x01014010}, - {0x17, 0x90170150}, - {0x19, 0x02a11060}, - {0x1b, 0x01813030}, - {0x21, 0x02211020}), - SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2, - {0x14, 0x01014010}, - {0x18, 0x01a19040}, - {0x1b, 0x01813030}, - {0x21, 0x02211020}), - SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2, - {0x14, 0x01014020}, - {0x17, 0x90170110}, - {0x18, 0x01a19050}, - {0x1b, 0x01813040}, - {0x21, 0x02211030}), - {} -}; - -/* - */ -static int patch_alc662(struct hda_codec *codec) -{ - struct alc_spec *spec; - int err; - - err = alc_alloc_spec(codec, 0x0b); - if (err < 0) - return err; - - spec = codec->spec; - - spec->shutup = alc_eapd_shutup; - - /* handle multiple HPs as is */ - spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP; - - alc_fix_pll_init(codec, 0x20, 0x04, 15); - - switch (codec->core.vendor_id) { - case 0x10ec0668: - spec->init_hook = alc668_restore_default_value; - break; - } - - alc_pre_init(codec); - - snd_hda_pick_fixup(codec, alc662_fixup_models, - alc662_fixup_tbl, alc662_fixups); - snd_hda_pick_pin_fixup(codec, alc662_pin_fixup_tbl, alc662_fixups, true); - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - - alc_auto_parse_customize_define(codec); - - if (has_cdefine_beep(codec)) - spec->gen.beep_nid = 0x01; - - if ((alc_get_coef0(codec) & (1 << 14)) && - codec->bus->pci && codec->bus->pci->subsystem_vendor == 0x1025 && - spec->cdefine.platform_type == 1) { - err = alc_codec_rename(codec, "ALC272X"); - if (err < 0) - goto error; - } - - /* automatic parse from the BIOS config */ - err = alc662_parse_auto_config(codec); - if (err < 0) - goto error; - - if (!spec->gen.no_analog && spec->gen.beep_nid) { - switch (codec->core.vendor_id) { - case 0x10ec0662: - err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - break; - case 0x10ec0272: - case 0x10ec0663: - case 0x10ec0665: - case 0x10ec0668: - err = set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); - break; - case 0x10ec0273: - err = set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT); - break; - } - if (err < 0) - goto error; - } - - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); - - return 0; - - error: - alc_free(codec); - return err; -} - -/* - * ALC680 support - */ - -static int alc680_parse_auto_config(struct hda_codec *codec) -{ - return alc_parse_auto_config(codec, NULL, NULL); -} - -/* - */ -static int patch_alc680(struct hda_codec *codec) -{ - int err; - - /* ALC680 has no aa-loopback mixer */ - err = alc_alloc_spec(codec, 0); - if (err < 0) - return err; - - /* automatic parse from the BIOS config */ - err = alc680_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } - - return 0; -} - -/* - * patch entries - */ -static const struct hda_device_id snd_hda_id_realtek[] = { +static const struct hda_device_id snd_hda_id_alc269[] = { HDA_CODEC_ENTRY(0x10ec0215, "ALC215", patch_alc269), HDA_CODEC_ENTRY(0x10ec0221, "ALC221", patch_alc269), HDA_CODEC_ENTRY(0x10ec0222, "ALC222", patch_alc269), @@ -13715,13 +8090,8 @@ static const struct hda_device_id snd_hda_id_realtek[] = { HDA_CODEC_ENTRY(0x10ec0255, "ALC255", patch_alc269), HDA_CODEC_ENTRY(0x10ec0256, "ALC256", patch_alc269), HDA_CODEC_ENTRY(0x10ec0257, "ALC257", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260), - HDA_CODEC_ENTRY(0x10ec0262, "ALC262", patch_alc262), - HDA_CODEC_ENTRY(0x10ec0267, "ALC267", patch_alc268), - HDA_CODEC_ENTRY(0x10ec0268, "ALC268", patch_alc268), HDA_CODEC_ENTRY(0x10ec0269, "ALC269", patch_alc269), HDA_CODEC_ENTRY(0x10ec0270, "ALC270", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0272, "ALC272", patch_alc662), HDA_CODEC_ENTRY(0x10ec0274, "ALC274", patch_alc269), HDA_CODEC_ENTRY(0x10ec0275, "ALC275", patch_alc269), HDA_CODEC_ENTRY(0x10ec0276, "ALC276", patch_alc269), @@ -13743,53 +8113,22 @@ static const struct hda_device_id snd_hda_id_realtek[] = { HDA_CODEC_ENTRY(0x10ec0299, "ALC299", patch_alc269), HDA_CODEC_ENTRY(0x10ec0300, "ALC300", patch_alc269), HDA_CODEC_ENTRY(0x10ec0623, "ALC623", patch_alc269), - HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861), - HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd), - HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861), - HDA_CODEC_ENTRY(0x10ec0862, "ALC861-VD", patch_alc861vd), - HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100002, "ALC662 rev2", patch_alc882), - HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100101, "ALC662 rev1", patch_alc662), - HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100300, "ALC662 rev3", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0663, "ALC663", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0665, "ALC665", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0667, "ALC667", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0668, "ALC668", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0670, "ALC670", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0671, "ALC671", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0680, "ALC680", patch_alc680), HDA_CODEC_ENTRY(0x10ec0700, "ALC700", patch_alc269), HDA_CODEC_ENTRY(0x10ec0701, "ALC701", patch_alc269), HDA_CODEC_ENTRY(0x10ec0703, "ALC703", patch_alc269), HDA_CODEC_ENTRY(0x10ec0711, "ALC711", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0867, "ALC891", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0880, "ALC880", patch_alc880), - HDA_CODEC_ENTRY(0x10ec0882, "ALC882", patch_alc882), - HDA_CODEC_ENTRY(0x10ec0883, "ALC883", patch_alc882), - HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100101, "ALC889A", patch_alc882), - HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100103, "ALC889A", patch_alc882), - HDA_CODEC_ENTRY(0x10ec0885, "ALC885", patch_alc882), - HDA_CODEC_ENTRY(0x10ec0887, "ALC887", patch_alc882), - HDA_CODEC_REV_ENTRY(0x10ec0888, 0x100101, "ALC1200", patch_alc882), - HDA_CODEC_ENTRY(0x10ec0888, "ALC888", patch_alc882), - HDA_CODEC_ENTRY(0x10ec0889, "ALC889", patch_alc882), - HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0897, "ALC897", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882), - HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882), - HDA_CODEC_ENTRY(0x10ec0b00, "ALCS1200A", patch_alc882), - HDA_CODEC_ENTRY(0x10ec1168, "ALC1220", patch_alc882), - HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882), HDA_CODEC_ENTRY(0x19e58326, "HW8326", patch_alc269), {} /* terminator */ }; -MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek); +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc269); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Realtek HD-audio codec"); +MODULE_DESCRIPTION("Realtek ALC269 and compatible HD-audio codecs"); +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); MODULE_IMPORT_NS("SND_HDA_SCODEC_COMPONENT"); -static struct hda_codec_driver realtek_driver = { - .id = snd_hda_id_realtek, +static struct hda_codec_driver alc269_driver = { + .id = snd_hda_id_alc269, }; -module_hda_codec_driver(realtek_driver); +module_hda_codec_driver(alc269_driver); diff --git a/sound/hda/codecs/realtek/alc662.c b/sound/hda/codecs/realtek/alc662.c new file mode 100644 index 000000000000..94e4a313e5e2 --- /dev/null +++ b/sound/hda/codecs/realtek/alc662.c @@ -0,0 +1,1102 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Realtek ALC662 and compatible codecs +// + +#include +#include +#include "realtek.h" + +/* + * ALC662 support + * + * ALC662 is almost identical with ALC880 but has cleaner and more flexible + * configuration. Each pin widget can choose any input DACs and a mixer. + * Each ADC is connected from a mixer of all inputs. This makes possible + * 6-channel independent captures. + * + * In addition, an independent DAC for the multi-playback (not used in this + * driver yet). + */ + +/* + * BIOS auto configuration + */ + +static int alc662_parse_auto_config(struct hda_codec *codec) +{ + static const hda_nid_t alc662_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 }; + static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 }; + const hda_nid_t *ssids; + + if (codec->core.vendor_id == 0x10ec0272 || codec->core.vendor_id == 0x10ec0663 || + codec->core.vendor_id == 0x10ec0665 || codec->core.vendor_id == 0x10ec0670 || + codec->core.vendor_id == 0x10ec0671) + ssids = alc663_ssids; + else + ssids = alc662_ssids; + return alc_parse_auto_config(codec, alc662_ignore, ssids); +} + +static void alc272_fixup_mario(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT, + (0x3b << AC_AMPCAP_OFFSET_SHIFT) | + (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (0 << AC_AMPCAP_MUTE_SHIFT))) + codec_warn(codec, "failed to override amp caps for NID 0x2\n"); +} + +/* avoid D3 for keeping GPIO up */ +static unsigned int gpio_led_power_filter(struct hda_codec *codec, + hda_nid_t nid, + unsigned int power_state) +{ + struct alc_spec *spec = codec->spec; + if (nid == codec->core.afg && power_state == AC_PWRST_D3 && spec->gpio_data) + return AC_PWRST_D0; + return power_state; +} + +static void alc662_fixup_led_gpio1(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + alc_fixup_hp_gpio_led(codec, action, 0x01, 0); + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->mute_led_polarity = 1; + codec->power_filter = gpio_led_power_filter; + } +} + +static void alc662_usi_automute_hook(struct hda_codec *codec, + struct hda_jack_callback *jack) +{ + struct alc_spec *spec = codec->spec; + int vref; + msleep(200); + snd_hda_gen_hp_automute(codec, jack); + + vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0; + msleep(100); + snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + vref); +} + +static void alc662_fixup_usi_headset_mic(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->parse_flags |= HDA_PINCFG_HEADSET_MIC; + spec->gen.hp_automute_hook = alc662_usi_automute_hook; + } +} + +static void alc662_aspire_ethos_mute_speakers(struct hda_codec *codec, + struct hda_jack_callback *cb) +{ + /* surround speakers at 0x1b already get muted automatically when + * headphones are plugged in, but we have to mute/unmute the remaining + * channels manually: + * 0x15 - front left/front right + * 0x18 - front center/ LFE + */ + if (snd_hda_jack_detect_state(codec, 0x1b) == HDA_JACK_PRESENT) { + snd_hda_set_pin_ctl_cache(codec, 0x15, 0); + snd_hda_set_pin_ctl_cache(codec, 0x18, 0); + } else { + snd_hda_set_pin_ctl_cache(codec, 0x15, PIN_OUT); + snd_hda_set_pin_ctl_cache(codec, 0x18, PIN_OUT); + } +} + +static void alc662_fixup_aspire_ethos_hp(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + /* Pin 0x1b: shared headphones jack and surround speakers */ + if (!is_jack_detectable(codec, 0x1b)) + return; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_jack_detect_enable_callback(codec, 0x1b, + alc662_aspire_ethos_mute_speakers); + /* subwoofer needs an extra GPIO setting to become audible */ + alc_setup_gpio(codec, 0x02); + break; + case HDA_FIXUP_ACT_INIT: + /* Make sure to start in a correct state, i.e. if + * headphones have been plugged in before powering up the system + */ + alc662_aspire_ethos_mute_speakers(codec, NULL); + break; + } +} + +static void alc671_fixup_hp_headset_mic2(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + static const struct hda_pintbl pincfgs[] = { + { 0x19, 0x02a11040 }, /* use as headset mic, with its own jack detect */ + { 0x1b, 0x0181304f }, + { } + }; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + spec->gen.mixer_nid = 0; + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + snd_hda_apply_pincfgs(codec, pincfgs); + break; + case HDA_FIXUP_ACT_INIT: + alc_write_coef_idx(codec, 0x19, 0xa054); + break; + } +} + +static void alc897_hp_automute_hook(struct hda_codec *codec, + struct hda_jack_callback *jack) +{ + struct alc_spec *spec = codec->spec; + int vref; + + snd_hda_gen_hp_automute(codec, jack); + vref = spec->gen.hp_jack_present ? (PIN_HP | AC_PINCTL_VREF_100) : PIN_HP; + snd_hda_set_pin_ctl(codec, 0x1b, vref); +} + +static void alc897_fixup_lenovo_headset_mic(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.hp_automute_hook = alc897_hp_automute_hook; + spec->no_shutup_pins = 1; + } + if (action == HDA_FIXUP_ACT_PROBE) { + snd_hda_set_pin_ctl_cache(codec, 0x1a, PIN_IN | AC_PINCTL_VREF_100); + } +} + +static void alc897_fixup_lenovo_headset_mode(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->parse_flags |= HDA_PINCFG_HEADSET_MIC; + spec->gen.hp_automute_hook = alc897_hp_automute_hook; + } +} + +static const struct coef_fw alc668_coefs[] = { + WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03, 0x0), + WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06, 0x0), WRITE_COEF(0x07, 0x0f80), + WRITE_COEF(0x08, 0x0031), WRITE_COEF(0x0a, 0x0060), WRITE_COEF(0x0b, 0x0), + WRITE_COEF(0x0c, 0x7cf7), WRITE_COEF(0x0d, 0x1080), WRITE_COEF(0x0e, 0x7f7f), + WRITE_COEF(0x0f, 0xcccc), WRITE_COEF(0x10, 0xddcc), WRITE_COEF(0x11, 0x0001), + WRITE_COEF(0x13, 0x0), WRITE_COEF(0x14, 0x2aa0), WRITE_COEF(0x17, 0xa940), + WRITE_COEF(0x19, 0x0), WRITE_COEF(0x1a, 0x0), WRITE_COEF(0x1b, 0x0), + WRITE_COEF(0x1c, 0x0), WRITE_COEF(0x1d, 0x0), WRITE_COEF(0x1e, 0x7418), + WRITE_COEF(0x1f, 0x0804), WRITE_COEF(0x20, 0x4200), WRITE_COEF(0x21, 0x0468), + WRITE_COEF(0x22, 0x8ccc), WRITE_COEF(0x23, 0x0250), WRITE_COEF(0x24, 0x7418), + WRITE_COEF(0x27, 0x0), WRITE_COEF(0x28, 0x8ccc), WRITE_COEF(0x2a, 0xff00), + WRITE_COEF(0x2b, 0x8000), WRITE_COEF(0xa7, 0xff00), WRITE_COEF(0xa8, 0x8000), + WRITE_COEF(0xaa, 0x2e17), WRITE_COEF(0xab, 0xa0c0), WRITE_COEF(0xac, 0x0), + WRITE_COEF(0xad, 0x0), WRITE_COEF(0xae, 0x2ac6), WRITE_COEF(0xaf, 0xa480), + WRITE_COEF(0xb0, 0x0), WRITE_COEF(0xb1, 0x0), WRITE_COEF(0xb2, 0x0), + WRITE_COEF(0xb3, 0x0), WRITE_COEF(0xb4, 0x0), WRITE_COEF(0xb5, 0x1040), + WRITE_COEF(0xb6, 0xd697), WRITE_COEF(0xb7, 0x902b), WRITE_COEF(0xb8, 0xd697), + WRITE_COEF(0xb9, 0x902b), WRITE_COEF(0xba, 0xb8ba), WRITE_COEF(0xbb, 0xaaab), + WRITE_COEF(0xbc, 0xaaaf), WRITE_COEF(0xbd, 0x6aaa), WRITE_COEF(0xbe, 0x1c02), + WRITE_COEF(0xc0, 0x00ff), WRITE_COEF(0xc1, 0x0fa6), + {} +}; + +static void alc668_restore_default_value(struct hda_codec *codec) +{ + alc_process_coef_fw(codec, alc668_coefs); +} + +static void alc_fixup_headset_mode_alc662(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->parse_flags |= HDA_PINCFG_HEADSET_MIC; + spec->gen.hp_mic = 1; /* Mic-in is same pin as headphone */ + + /* Disable boost for mic-in permanently. (This code is only called + from quirks that guarantee that the headphone is at NID 0x1b.) */ + snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000); + snd_hda_override_wcaps(codec, 0x1b, get_wcaps(codec, 0x1b) & ~AC_WCAP_IN_AMP); + } else + alc_fixup_headset_mode(codec, fix, action); +} + +static void alc_fixup_headset_mode_alc668(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + alc_write_coef_idx(codec, 0xc4, 0x8000); + alc_update_coef_idx(codec, 0xc2, ~0xfe, 0); + snd_hda_set_pin_ctl_cache(codec, 0x18, 0); + } + alc_fixup_headset_mode(codec, fix, action); +} + +enum { + ALC662_FIXUP_ASPIRE, + ALC662_FIXUP_LED_GPIO1, + ALC662_FIXUP_IDEAPAD, + ALC272_FIXUP_MARIO, + ALC662_FIXUP_CZC_ET26, + ALC662_FIXUP_CZC_P10T, + ALC662_FIXUP_SKU_IGNORE, + ALC662_FIXUP_HP_RP5800, + ALC662_FIXUP_ASUS_MODE1, + ALC662_FIXUP_ASUS_MODE2, + ALC662_FIXUP_ASUS_MODE3, + ALC662_FIXUP_ASUS_MODE4, + ALC662_FIXUP_ASUS_MODE5, + ALC662_FIXUP_ASUS_MODE6, + ALC662_FIXUP_ASUS_MODE7, + ALC662_FIXUP_ASUS_MODE8, + ALC662_FIXUP_NO_JACK_DETECT, + ALC662_FIXUP_ZOTAC_Z68, + ALC662_FIXUP_INV_DMIC, + ALC662_FIXUP_DELL_MIC_NO_PRESENCE, + ALC668_FIXUP_DELL_MIC_NO_PRESENCE, + ALC662_FIXUP_HEADSET_MODE, + ALC668_FIXUP_HEADSET_MODE, + ALC662_FIXUP_BASS_MODE4_CHMAP, + ALC662_FIXUP_BASS_16, + ALC662_FIXUP_BASS_1A, + ALC662_FIXUP_BASS_CHMAP, + ALC668_FIXUP_AUTO_MUTE, + ALC668_FIXUP_DELL_DISABLE_AAMIX, + ALC668_FIXUP_DELL_XPS13, + ALC662_FIXUP_ASUS_Nx50, + ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE, + ALC668_FIXUP_ASUS_Nx51, + ALC668_FIXUP_MIC_COEF, + ALC668_FIXUP_ASUS_G751, + ALC891_FIXUP_HEADSET_MODE, + ALC891_FIXUP_DELL_MIC_NO_PRESENCE, + ALC662_FIXUP_ACER_VERITON, + ALC892_FIXUP_ASROCK_MOBO, + ALC662_FIXUP_USI_FUNC, + ALC662_FIXUP_USI_HEADSET_MODE, + ALC662_FIXUP_LENOVO_MULTI_CODECS, + ALC669_FIXUP_ACER_ASPIRE_ETHOS, + ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET, + ALC671_FIXUP_HP_HEADSET_MIC2, + ALC662_FIXUP_ACER_X2660G_HEADSET_MODE, + ALC662_FIXUP_ACER_NITRO_HEADSET_MODE, + ALC668_FIXUP_ASUS_NO_HEADSET_MIC, + ALC668_FIXUP_HEADSET_MIC, + ALC668_FIXUP_MIC_DET_COEF, + ALC897_FIXUP_LENOVO_HEADSET_MIC, + ALC897_FIXUP_HEADSET_MIC_PIN, + ALC897_FIXUP_HP_HSMIC_VERB, + ALC897_FIXUP_LENOVO_HEADSET_MODE, + ALC897_FIXUP_HEADSET_MIC_PIN2, + ALC897_FIXUP_UNIS_H3C_X500S, + ALC897_FIXUP_HEADSET_MIC_PIN3, +}; + +static const struct hda_fixup alc662_fixups[] = { + [ALC662_FIXUP_ASPIRE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x15, 0x99130112 }, /* subwoofer */ + { } + } + }, + [ALC662_FIXUP_LED_GPIO1] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc662_fixup_led_gpio1, + }, + [ALC662_FIXUP_IDEAPAD] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x17, 0x99130112 }, /* subwoofer */ + { } + }, + .chained = true, + .chain_id = ALC662_FIXUP_LED_GPIO1, + }, + [ALC272_FIXUP_MARIO] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc272_fixup_mario, + }, + [ALC662_FIXUP_CZC_ET26] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + {0x12, 0x403cc000}, + {0x14, 0x90170110}, /* speaker */ + {0x15, 0x411111f0}, + {0x16, 0x411111f0}, + {0x18, 0x01a19030}, /* mic */ + {0x19, 0x90a7013f}, /* int-mic */ + {0x1a, 0x01014020}, + {0x1b, 0x0121401f}, + {0x1c, 0x411111f0}, + {0x1d, 0x411111f0}, + {0x1e, 0x40478e35}, + {} + }, + .chained = true, + .chain_id = ALC662_FIXUP_SKU_IGNORE + }, + [ALC662_FIXUP_CZC_P10T] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0}, + {} + } + }, + [ALC662_FIXUP_SKU_IGNORE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_sku_ignore, + }, + [ALC662_FIXUP_HP_RP5800] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x0221201f }, /* HP out */ + { } + }, + .chained = true, + .chain_id = ALC662_FIXUP_SKU_IGNORE + }, + [ALC662_FIXUP_ASUS_MODE1] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x99130110 }, /* speaker */ + { 0x18, 0x01a19c20 }, /* mic */ + { 0x19, 0x99a3092f }, /* int-mic */ + { 0x21, 0x0121401f }, /* HP out */ + { } + }, + .chained = true, + .chain_id = ALC662_FIXUP_SKU_IGNORE + }, + [ALC662_FIXUP_ASUS_MODE2] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x99130110 }, /* speaker */ + { 0x18, 0x01a19820 }, /* mic */ + { 0x19, 0x99a3092f }, /* int-mic */ + { 0x1b, 0x0121401f }, /* HP out */ + { } + }, + .chained = true, + .chain_id = ALC662_FIXUP_SKU_IGNORE + }, + [ALC662_FIXUP_ASUS_MODE3] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x99130110 }, /* speaker */ + { 0x15, 0x0121441f }, /* HP */ + { 0x18, 0x01a19840 }, /* mic */ + { 0x19, 0x99a3094f }, /* int-mic */ + { 0x21, 0x01211420 }, /* HP2 */ + { } + }, + .chained = true, + .chain_id = ALC662_FIXUP_SKU_IGNORE + }, + [ALC662_FIXUP_ASUS_MODE4] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x99130110 }, /* speaker */ + { 0x16, 0x99130111 }, /* speaker */ + { 0x18, 0x01a19840 }, /* mic */ + { 0x19, 0x99a3094f }, /* int-mic */ + { 0x21, 0x0121441f }, /* HP */ + { } + }, + .chained = true, + .chain_id = ALC662_FIXUP_SKU_IGNORE + }, + [ALC662_FIXUP_ASUS_MODE5] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x99130110 }, /* speaker */ + { 0x15, 0x0121441f }, /* HP */ + { 0x16, 0x99130111 }, /* speaker */ + { 0x18, 0x01a19840 }, /* mic */ + { 0x19, 0x99a3094f }, /* int-mic */ + { } + }, + .chained = true, + .chain_id = ALC662_FIXUP_SKU_IGNORE + }, + [ALC662_FIXUP_ASUS_MODE6] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x99130110 }, /* speaker */ + { 0x15, 0x01211420 }, /* HP2 */ + { 0x18, 0x01a19840 }, /* mic */ + { 0x19, 0x99a3094f }, /* int-mic */ + { 0x1b, 0x0121441f }, /* HP */ + { } + }, + .chained = true, + .chain_id = ALC662_FIXUP_SKU_IGNORE + }, + [ALC662_FIXUP_ASUS_MODE7] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x99130110 }, /* speaker */ + { 0x17, 0x99130111 }, /* speaker */ + { 0x18, 0x01a19840 }, /* mic */ + { 0x19, 0x99a3094f }, /* int-mic */ + { 0x1b, 0x01214020 }, /* HP */ + { 0x21, 0x0121401f }, /* HP */ + { } + }, + .chained = true, + .chain_id = ALC662_FIXUP_SKU_IGNORE + }, + [ALC662_FIXUP_ASUS_MODE8] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x99130110 }, /* speaker */ + { 0x12, 0x99a30970 }, /* int-mic */ + { 0x15, 0x01214020 }, /* HP */ + { 0x17, 0x99130111 }, /* speaker */ + { 0x18, 0x01a19840 }, /* mic */ + { 0x21, 0x0121401f }, /* HP */ + { } + }, + .chained = true, + .chain_id = ALC662_FIXUP_SKU_IGNORE + }, + [ALC662_FIXUP_NO_JACK_DETECT] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_no_jack_detect, + }, + [ALC662_FIXUP_ZOTAC_Z68] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1b, 0x02214020 }, /* Front HP */ + { } + } + }, + [ALC662_FIXUP_INV_DMIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_inv_dmic, + }, + [ALC668_FIXUP_DELL_XPS13] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_dell_xps13, + .chained = true, + .chain_id = ALC668_FIXUP_DELL_DISABLE_AAMIX + }, + [ALC668_FIXUP_DELL_DISABLE_AAMIX] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_disable_aamix, + .chained = true, + .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE + }, + [ALC668_FIXUP_AUTO_MUTE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_auto_mute_via_amp, + .chained = true, + .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE + }, + [ALC662_FIXUP_DELL_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x03a1113c }, /* use as headset mic, without its own jack detect */ + /* headphone mic by setting pin control of 0x1b (headphone out) to in + vref_50 */ + { } + }, + .chained = true, + .chain_id = ALC662_FIXUP_HEADSET_MODE + }, + [ALC662_FIXUP_HEADSET_MODE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_headset_mode_alc662, + }, + [ALC668_FIXUP_DELL_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */ + { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC668_FIXUP_HEADSET_MODE + }, + [ALC668_FIXUP_HEADSET_MODE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_headset_mode_alc668, + }, + [ALC662_FIXUP_BASS_MODE4_CHMAP] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_bass_chmap, + .chained = true, + .chain_id = ALC662_FIXUP_ASUS_MODE4 + }, + [ALC662_FIXUP_BASS_16] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + {0x16, 0x80106111}, /* bass speaker */ + {} + }, + .chained = true, + .chain_id = ALC662_FIXUP_BASS_CHMAP, + }, + [ALC662_FIXUP_BASS_1A] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + {0x1a, 0x80106111}, /* bass speaker */ + {} + }, + .chained = true, + .chain_id = ALC662_FIXUP_BASS_CHMAP, + }, + [ALC662_FIXUP_BASS_CHMAP] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_bass_chmap, + }, + [ALC662_FIXUP_ASUS_Nx50] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_auto_mute_via_amp, + .chained = true, + .chain_id = ALC662_FIXUP_BASS_1A + }, + [ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_headset_mode_alc668, + .chain_id = ALC662_FIXUP_BASS_CHMAP + }, + [ALC668_FIXUP_ASUS_Nx51] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */ + { 0x1a, 0x90170151 }, /* bass speaker */ + { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */ + {} + }, + .chained = true, + .chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE, + }, + [ALC668_FIXUP_MIC_COEF] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + { 0x20, AC_VERB_SET_COEF_INDEX, 0xc3 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x4000 }, + {} + }, + }, + [ALC668_FIXUP_ASUS_G751] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x16, 0x0421101f }, /* HP */ + {} + }, + .chained = true, + .chain_id = ALC668_FIXUP_MIC_COEF + }, + [ALC891_FIXUP_HEADSET_MODE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_headset_mode, + }, + [ALC891_FIXUP_DELL_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */ + { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC891_FIXUP_HEADSET_MODE + }, + [ALC662_FIXUP_ACER_VERITON] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x15, 0x50170120 }, /* no internal speaker */ + { } + } + }, + [ALC892_FIXUP_ASROCK_MOBO] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x15, 0x40f000f0 }, /* disabled */ + { 0x16, 0x40f000f0 }, /* disabled */ + { } + } + }, + [ALC662_FIXUP_USI_FUNC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc662_fixup_usi_headset_mic, + }, + [ALC662_FIXUP_USI_HEADSET_MODE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x02a1913c }, /* use as headset mic, without its own jack detect */ + { 0x18, 0x01a1903d }, + { } + }, + .chained = true, + .chain_id = ALC662_FIXUP_USI_FUNC + }, + [ALC662_FIXUP_LENOVO_MULTI_CODECS] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc233_alc662_fixup_lenovo_dual_codecs, + }, + [ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc662_fixup_aspire_ethos_hp, + }, + [ALC669_FIXUP_ACER_ASPIRE_ETHOS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x15, 0x92130110 }, /* front speakers */ + { 0x18, 0x99130111 }, /* center/subwoofer */ + { 0x1b, 0x11130012 }, /* surround plus jack for HP */ + { } + }, + .chained = true, + .chain_id = ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET + }, + [ALC671_FIXUP_HP_HEADSET_MIC2] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc671_fixup_hp_headset_mic2, + }, + [ALC662_FIXUP_ACER_X2660G_HEADSET_MODE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1a, 0x02a1113c }, /* use as headset mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC662_FIXUP_USI_FUNC + }, + [ALC662_FIXUP_ACER_NITRO_HEADSET_MODE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */ + { 0x1b, 0x0221144f }, + { } + }, + .chained = true, + .chain_id = ALC662_FIXUP_USI_FUNC + }, + [ALC668_FIXUP_ASUS_NO_HEADSET_MIC] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1b, 0x04a1112c }, + { } + }, + .chained = true, + .chain_id = ALC668_FIXUP_HEADSET_MIC + }, + [ALC668_FIXUP_HEADSET_MIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_headset_mic, + .chained = true, + .chain_id = ALC668_FIXUP_MIC_DET_COEF + }, + [ALC668_FIXUP_MIC_DET_COEF] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + { 0x20, AC_VERB_SET_COEF_INDEX, 0x15 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x0d60 }, + {} + }, + }, + [ALC897_FIXUP_LENOVO_HEADSET_MIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc897_fixup_lenovo_headset_mic, + }, + [ALC897_FIXUP_HEADSET_MIC_PIN] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1a, 0x03a11050 }, + { } + }, + .chained = true, + .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MIC + }, + [ALC897_FIXUP_HP_HSMIC_VERB] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */ + { } + }, + }, + [ALC897_FIXUP_LENOVO_HEADSET_MODE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc897_fixup_lenovo_headset_mode, + }, + [ALC897_FIXUP_HEADSET_MIC_PIN2] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MODE + }, + [ALC897_FIXUP_UNIS_H3C_X500S] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + { 0x14, AC_VERB_SET_EAPD_BTLENABLE, 0 }, + {} + }, + }, + [ALC897_FIXUP_HEADSET_MIC_PIN3] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x03a11050 }, /* use as headset mic */ + { } + }, + }, +}; + +static const struct hda_quirk alc662_fixup_tbl[] = { + SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1019, 0x9859, "JP-IK LEAP W502", ALC897_FIXUP_HEADSET_MIC_PIN3), + SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC), + SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC), + SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC), + SND_PCI_QUIRK(0x1025, 0x034a, "Gateway LT27", ALC662_FIXUP_INV_DMIC), + SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x0566, "Acer Aspire Ethos 8951G", ALC669_FIXUP_ACER_ASPIRE_ETHOS), + SND_PCI_QUIRK(0x1025, 0x123c, "Acer Nitro N50-600", ALC662_FIXUP_ACER_NITRO_HEADSET_MODE), + SND_PCI_QUIRK(0x1025, 0x124e, "Acer 2660G", ALC662_FIXUP_ACER_X2660G_HEADSET_MODE), + SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05fe, "Dell XPS 15", ALC668_FIXUP_DELL_XPS13), + SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_XPS13), + SND_PCI_QUIRK(0x1028, 0x060d, "Dell M3800", ALC668_FIXUP_DELL_XPS13), + SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), + SND_PCI_QUIRK(0x103c, 0x870c, "HP", ALC897_FIXUP_HP_HSMIC_VERB), + SND_PCI_QUIRK(0x103c, 0x8719, "HP", ALC897_FIXUP_HP_HSMIC_VERB), + SND_PCI_QUIRK(0x103c, 0x872b, "HP", ALC897_FIXUP_HP_HSMIC_VERB), + SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2), + SND_PCI_QUIRK(0x103c, 0x8768, "HP Slim Desktop S01", ALC671_FIXUP_HP_HEADSET_MIC2), + SND_PCI_QUIRK(0x103c, 0x877e, "HP 288 Pro G6", ALC671_FIXUP_HP_HEADSET_MIC2), + SND_PCI_QUIRK(0x103c, 0x885f, "HP 288 Pro G8", ALC671_FIXUP_HP_HEADSET_MIC2), + SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE), + SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50), + SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50), + SND_PCI_QUIRK(0x1043, 0x12ff, "ASUS G751", ALC668_FIXUP_ASUS_G751), + SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A), + SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), + SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16), + SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51), + SND_PCI_QUIRK(0x1043, 0x17bd, "ASUS N751", ALC668_FIXUP_ASUS_Nx51), + SND_PCI_QUIRK(0x1043, 0x185d, "ASUS G551JW", ALC668_FIXUP_ASUS_NO_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71SL", ALC662_FIXUP_ASUS_MODE8), + SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16), + SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), + SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT), + SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), + SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE), + SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS), + SND_PCI_QUIRK(0x17aa, 0x1057, "Lenovo P360", ALC897_FIXUP_HEADSET_MIC_PIN), + SND_PCI_QUIRK(0x17aa, 0x1064, "Lenovo P3 Tower", ALC897_FIXUP_HEADSET_MIC_PIN), + SND_PCI_QUIRK(0x17aa, 0x32ca, "Lenovo ThinkCentre M80", ALC897_FIXUP_HEADSET_MIC_PIN), + SND_PCI_QUIRK(0x17aa, 0x32cb, "Lenovo ThinkCentre M70", ALC897_FIXUP_HEADSET_MIC_PIN), + SND_PCI_QUIRK(0x17aa, 0x32cf, "Lenovo ThinkCentre M950", ALC897_FIXUP_HEADSET_MIC_PIN), + SND_PCI_QUIRK(0x17aa, 0x32f7, "Lenovo ThinkCentre M90", ALC897_FIXUP_HEADSET_MIC_PIN), + SND_PCI_QUIRK(0x17aa, 0x3321, "Lenovo ThinkCentre M70 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN), + SND_PCI_QUIRK(0x17aa, 0x331b, "Lenovo ThinkCentre M90 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN), + SND_PCI_QUIRK(0x17aa, 0x3364, "Lenovo ThinkCentre M90 Gen5", ALC897_FIXUP_HEADSET_MIC_PIN), + SND_PCI_QUIRK(0x17aa, 0x3742, "Lenovo TianYi510Pro-14IOB", ALC897_FIXUP_HEADSET_MIC_PIN2), + SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), + SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD), + SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO), + SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68), + SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON), + SND_PCI_QUIRK(0x1b35, 0x1234, "CZC ET26", ALC662_FIXUP_CZC_ET26), + SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T), + SND_PCI_QUIRK(0x1c6c, 0x1239, "Compaq N14JP6-V2", ALC897_FIXUP_HP_HSMIC_VERB), + +#if 0 + /* Below is a quirk table taken from the old code. + * Basically the device should work as is without the fixup table. + * If BIOS doesn't give a proper info, enable the corresponding + * fixup entry. + */ + SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC662_FIXUP_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC662_FIXUP_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC662_FIXUP_ASUS_MODE7), + SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC662_FIXUP_ASUS_MODE7), + SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC662_FIXUP_ASUS_MODE8), + SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC662_FIXUP_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC662_FIXUP_ASUS_MODE6), + SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC662_FIXUP_ASUS_MODE6), + SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC662_FIXUP_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC662_FIXUP_ASUS_MODE5), + SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC662_FIXUP_ASUS_MODE6), + SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC662_FIXUP_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC662_FIXUP_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC662_FIXUP_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE4), +#endif + {} +}; + +static const struct hda_model_fixup alc662_fixup_models[] = { + {.id = ALC662_FIXUP_ASPIRE, .name = "aspire"}, + {.id = ALC662_FIXUP_IDEAPAD, .name = "ideapad"}, + {.id = ALC272_FIXUP_MARIO, .name = "mario"}, + {.id = ALC662_FIXUP_HP_RP5800, .name = "hp-rp5800"}, + {.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"}, + {.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"}, + {.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"}, + {.id = ALC662_FIXUP_ASUS_MODE4, .name = "asus-mode4"}, + {.id = ALC662_FIXUP_ASUS_MODE5, .name = "asus-mode5"}, + {.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"}, + {.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"}, + {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"}, + {.id = ALC662_FIXUP_ZOTAC_Z68, .name = "zotac-z68"}, + {.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"}, + {.id = ALC662_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc662-headset-multi"}, + {.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"}, + {.id = ALC662_FIXUP_HEADSET_MODE, .name = "alc662-headset"}, + {.id = ALC668_FIXUP_HEADSET_MODE, .name = "alc668-headset"}, + {.id = ALC662_FIXUP_BASS_16, .name = "bass16"}, + {.id = ALC662_FIXUP_BASS_1A, .name = "bass1a"}, + {.id = ALC668_FIXUP_AUTO_MUTE, .name = "automute"}, + {.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"}, + {.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"}, + {.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"}, + {.id = ALC668_FIXUP_ASUS_G751, .name = "asus-g751"}, + {.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"}, + {.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"}, + {.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"}, + {.id = ALC892_FIXUP_ASROCK_MOBO, .name = "asrock-mobo"}, + {.id = ALC662_FIXUP_USI_HEADSET_MODE, .name = "usi-headset"}, + {.id = ALC662_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"}, + {.id = ALC669_FIXUP_ACER_ASPIRE_ETHOS, .name = "aspire-ethos"}, + {.id = ALC897_FIXUP_UNIS_H3C_X500S, .name = "unis-h3c-x500s"}, + {} +}; + +static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = { + SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE, + {0x17, 0x02211010}, + {0x18, 0x01a19030}, + {0x1a, 0x01813040}, + {0x21, 0x01014020}), + SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE, + {0x16, 0x01813030}, + {0x17, 0x02211010}, + {0x18, 0x01a19040}, + {0x21, 0x01014020}), + SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE, + {0x14, 0x01014010}, + {0x18, 0x01a19020}, + {0x1a, 0x0181302f}, + {0x1b, 0x0221401f}), + SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, + {0x12, 0x99a30130}, + {0x14, 0x90170110}, + {0x15, 0x0321101f}, + {0x16, 0x03011020}), + SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, + {0x12, 0x99a30140}, + {0x14, 0x90170110}, + {0x15, 0x0321101f}, + {0x16, 0x03011020}), + SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, + {0x12, 0x99a30150}, + {0x14, 0x90170110}, + {0x15, 0x0321101f}, + {0x16, 0x03011020}), + SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, + {0x14, 0x90170110}, + {0x15, 0x0321101f}, + {0x16, 0x03011020}), + SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell XPS 15", ALC668_FIXUP_AUTO_MUTE, + {0x12, 0x90a60130}, + {0x14, 0x90170110}, + {0x15, 0x0321101f}), + SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2, + {0x14, 0x01014010}, + {0x17, 0x90170150}, + {0x19, 0x02a11060}, + {0x1b, 0x01813030}, + {0x21, 0x02211020}), + SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2, + {0x14, 0x01014010}, + {0x18, 0x01a19040}, + {0x1b, 0x01813030}, + {0x21, 0x02211020}), + SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2, + {0x14, 0x01014020}, + {0x17, 0x90170110}, + {0x18, 0x01a19050}, + {0x1b, 0x01813040}, + {0x21, 0x02211030}), + {} +}; + +/* + */ +static int patch_alc662(struct hda_codec *codec) +{ + struct alc_spec *spec; + int err; + + err = alc_alloc_spec(codec, 0x0b); + if (err < 0) + return err; + + spec = codec->spec; + + spec->shutup = alc_eapd_shutup; + + /* handle multiple HPs as is */ + spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP; + + alc_fix_pll_init(codec, 0x20, 0x04, 15); + + switch (codec->core.vendor_id) { + case 0x10ec0668: + spec->init_hook = alc668_restore_default_value; + break; + } + + alc_pre_init(codec); + + snd_hda_pick_fixup(codec, alc662_fixup_models, + alc662_fixup_tbl, alc662_fixups); + snd_hda_pick_pin_fixup(codec, alc662_pin_fixup_tbl, alc662_fixups, true); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + alc_auto_parse_customize_define(codec); + + if (has_cdefine_beep(codec)) + spec->gen.beep_nid = 0x01; + + if ((alc_get_coef0(codec) & (1 << 14)) && + codec->bus->pci && codec->bus->pci->subsystem_vendor == 0x1025 && + spec->cdefine.platform_type == 1) { + err = alc_codec_rename(codec, "ALC272X"); + if (err < 0) + goto error; + } + + /* automatic parse from the BIOS config */ + err = alc662_parse_auto_config(codec); + if (err < 0) + goto error; + + if (!spec->gen.no_analog && spec->gen.beep_nid) { + switch (codec->core.vendor_id) { + case 0x10ec0662: + err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + break; + case 0x10ec0272: + case 0x10ec0663: + case 0x10ec0665: + case 0x10ec0668: + err = set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); + break; + case 0x10ec0273: + err = set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT); + break; + } + 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_alc662[] = { + HDA_CODEC_ENTRY(0x10ec0272, "ALC272", patch_alc662), + HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100101, "ALC662 rev1", patch_alc662), + HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100300, "ALC662 rev3", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0663, "ALC663", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0665, "ALC665", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0667, "ALC667", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0668, "ALC668", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0670, "ALC670", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0671, "ALC671", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0867, "ALC891", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0897, "ALC897", patch_alc662), + {} /* terminator */ +}; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc662); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek ALC662 and compatible HD-audio codec"); +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); + +static struct hda_codec_driver alc662_driver = { + .id = snd_hda_id_alc662, +}; + +module_hda_codec_driver(alc662_driver); diff --git a/sound/hda/codecs/realtek/alc680.c b/sound/hda/codecs/realtek/alc680.c new file mode 100644 index 000000000000..baf19ee3bc2f --- /dev/null +++ b/sound/hda/codecs/realtek/alc680.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Realtek ALC680 codec +// + +#include +#include +#include "realtek.h" + +static int alc680_parse_auto_config(struct hda_codec *codec) +{ + return alc_parse_auto_config(codec, NULL, NULL); +} + +/* + */ +static int patch_alc680(struct hda_codec *codec) +{ + int err; + + /* ALC680 has no aa-loopback mixer */ + err = alc_alloc_spec(codec, 0); + if (err < 0) + return err; + + /* automatic parse from the BIOS config */ + err = alc680_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } + + return 0; +} + +/* + * driver entries + */ +static const struct hda_device_id snd_hda_id_alc680[] = { + HDA_CODEC_ENTRY(0x10ec0680, "ALC680", patch_alc680), + {} /* terminator */ +}; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc680); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek ALC680 HD-audio codec"); +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); + +static struct hda_codec_driver alc680_driver = { + .id = snd_hda_id_alc680, +}; + +module_hda_codec_driver(alc680_driver); diff --git a/sound/hda/codecs/realtek/alc861.c b/sound/hda/codecs/realtek/alc861.c new file mode 100644 index 000000000000..0eb70b44dc05 --- /dev/null +++ b/sound/hda/codecs/realtek/alc861.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Realtek ALC861 codec +// + +#include +#include +#include "realtek.h" + +static int alc861_parse_auto_config(struct hda_codec *codec) +{ + static const hda_nid_t alc861_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 }; + return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids); +} + +/* Pin config fixes */ +enum { + ALC861_FIXUP_FSC_AMILO_PI1505, + ALC861_FIXUP_AMP_VREF_0F, + ALC861_FIXUP_NO_JACK_DETECT, + ALC861_FIXUP_ASUS_A6RP, + ALC660_FIXUP_ASUS_W7J, +}; + +/* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */ +static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + unsigned int val; + + if (action != HDA_FIXUP_ACT_INIT) + return; + val = snd_hda_codec_get_pin_target(codec, 0x0f); + if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))) + val |= AC_PINCTL_IN_EN; + val |= AC_PINCTL_VREF_50; + snd_hda_set_pin_ctl(codec, 0x0f, val); + spec->gen.keep_vref_in_automute = 1; +} + +static const struct hda_fixup alc861_fixups[] = { + [ALC861_FIXUP_FSC_AMILO_PI1505] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x0b, 0x0221101f }, /* HP */ + { 0x0f, 0x90170310 }, /* speaker */ + { } + } + }, + [ALC861_FIXUP_AMP_VREF_0F] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc861_fixup_asus_amp_vref_0f, + }, + [ALC861_FIXUP_NO_JACK_DETECT] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_no_jack_detect, + }, + [ALC861_FIXUP_ASUS_A6RP] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc861_fixup_asus_amp_vref_0f, + .chained = true, + .chain_id = ALC861_FIXUP_NO_JACK_DETECT, + }, + [ALC660_FIXUP_ASUS_W7J] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* ASUS W7J needs a magic pin setup on unused NID 0x10 + * for enabling outputs + */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + { } + }, + } +}; + +static const struct hda_quirk alc861_fixup_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x1253, "ASUS W7J", ALC660_FIXUP_ASUS_W7J), + SND_PCI_QUIRK(0x1043, 0x1263, "ASUS Z35HL", ALC660_FIXUP_ASUS_W7J), + SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP), + SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F), + SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT), + SND_PCI_QUIRK_VENDOR(0x1584, "Haier/Uniwill", ALC861_FIXUP_AMP_VREF_0F), + SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", ALC861_FIXUP_FSC_AMILO_PI1505), + {} +}; + +/* + */ +static int patch_alc861(struct hda_codec *codec) +{ + struct alc_spec *spec; + int err; + + err = alc_alloc_spec(codec, 0x15); + if (err < 0) + return err; + + spec = codec->spec; + if (has_cdefine_beep(codec)) + spec->gen.beep_nid = 0x23; + + spec->power_hook = alc_power_eapd; + + alc_pre_init(codec); + + snd_hda_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + /* automatic parse from the BIOS config */ + err = alc861_parse_auto_config(codec); + if (err < 0) + goto error; + + if (!spec->gen.no_analog) { + err = set_beep_amp(spec, 0x23, 0, HDA_OUTPUT); + 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_alc861[] = { + HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861), + HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861), + {} /* terminator */ +}; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc861); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek ALC861 HD-audio codec"); +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); + +static struct hda_codec_driver alc861_driver = { + .id = snd_hda_id_alc861, +}; + +module_hda_codec_driver(alc861_driver); diff --git a/sound/hda/codecs/realtek/alc861vd.c b/sound/hda/codecs/realtek/alc861vd.c new file mode 100644 index 000000000000..ebf274ad730b --- /dev/null +++ b/sound/hda/codecs/realtek/alc861vd.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Realtek ALC861-VD codec +// Based on ALC882 +// In addition, an independent DAC +// + +#include +#include +#include "realtek.h" + +static int alc861vd_parse_auto_config(struct hda_codec *codec) +{ + static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 }; + return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids); +} + +enum { + ALC660VD_FIX_ASUS_GPIO1, + ALC861VD_FIX_DALLAS, +}; + +/* exclude VREF80 */ +static void alc861vd_fixup_dallas(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + snd_hda_override_pin_caps(codec, 0x18, 0x00000734); + snd_hda_override_pin_caps(codec, 0x19, 0x0000073c); + } +} + +/* reset GPIO1 */ +static void alc660vd_fixup_asus_gpio1(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->gpio_mask |= 0x02; + alc_fixup_gpio(codec, action, 0x01); +} + +static const struct hda_fixup alc861vd_fixups[] = { + [ALC660VD_FIX_ASUS_GPIO1] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc660vd_fixup_asus_gpio1, + }, + [ALC861VD_FIX_DALLAS] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc861vd_fixup_dallas, + }, +}; + +static const struct hda_quirk alc861vd_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS), + SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1), + SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS), + {} +}; + +/* + */ +static int patch_alc861vd(struct hda_codec *codec) +{ + struct alc_spec *spec; + int err; + + err = alc_alloc_spec(codec, 0x0b); + if (err < 0) + return err; + + spec = codec->spec; + if (has_cdefine_beep(codec)) + spec->gen.beep_nid = 0x23; + + spec->shutup = alc_eapd_shutup; + + alc_pre_init(codec); + + snd_hda_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + /* automatic parse from the BIOS config */ + err = alc861vd_parse_auto_config(codec); + if (err < 0) + goto error; + + if (!spec->gen.no_analog) { + err = set_beep_amp(spec, 0x0b, 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_alc861vd[] = { + HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd), + HDA_CODEC_ENTRY(0x10ec0862, "ALC861-VD", patch_alc861vd), + {} /* terminator */ +}; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc861vd); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek ALC861-VD HD-audio codec"); +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); + +static struct hda_codec_driver alc861vd_driver = { + .id = snd_hda_id_alc861vd, +}; + +module_hda_codec_driver(alc861vd_driver); diff --git a/sound/hda/codecs/realtek/alc880.c b/sound/hda/codecs/realtek/alc880.c new file mode 100644 index 000000000000..2e828ab96dc5 --- /dev/null +++ b/sound/hda/codecs/realtek/alc880.c @@ -0,0 +1,497 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Realtek ALC880 codec +// + +#include +#include +#include "realtek.h" + +static void alc880_unsol_event(struct hda_codec *codec, unsigned int res) +{ + /* For some reason, the res given from ALC880 is broken. + Here we adjust it properly. */ + snd_hda_jack_unsol_event(codec, res >> 2); +} + +static int alc880_parse_auto_config(struct hda_codec *codec) +{ + static const hda_nid_t alc880_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 }; + return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids); +} + +/* + * ALC880 fix-ups + */ +enum { + ALC880_FIXUP_GPIO1, + ALC880_FIXUP_GPIO2, + ALC880_FIXUP_MEDION_RIM, + ALC880_FIXUP_LG, + ALC880_FIXUP_LG_LW25, + ALC880_FIXUP_W810, + ALC880_FIXUP_EAPD_COEF, + ALC880_FIXUP_TCL_S700, + ALC880_FIXUP_VOL_KNOB, + ALC880_FIXUP_FUJITSU, + ALC880_FIXUP_F1734, + ALC880_FIXUP_UNIWILL, + ALC880_FIXUP_UNIWILL_DIG, + ALC880_FIXUP_Z71V, + ALC880_FIXUP_ASUS_W5A, + ALC880_FIXUP_3ST_BASE, + ALC880_FIXUP_3ST, + ALC880_FIXUP_3ST_DIG, + ALC880_FIXUP_5ST_BASE, + ALC880_FIXUP_5ST, + ALC880_FIXUP_5ST_DIG, + ALC880_FIXUP_6ST_BASE, + ALC880_FIXUP_6ST, + ALC880_FIXUP_6ST_DIG, + ALC880_FIXUP_6ST_AUTOMUTE, +}; + +/* enable the volume-knob widget support on NID 0x21 */ +static void alc880_fixup_vol_knob(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PROBE) + snd_hda_jack_detect_enable_callback(codec, 0x21, + alc_update_knob_master); +} + +static const struct hda_fixup alc880_fixups[] = { + [ALC880_FIXUP_GPIO1] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_gpio1, + }, + [ALC880_FIXUP_GPIO2] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_gpio2, + }, + [ALC880_FIXUP_MEDION_RIM] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 }, + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_GPIO2, + }, + [ALC880_FIXUP_LG] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + /* disable bogus unused pins */ + { 0x16, 0x411111f0 }, + { 0x18, 0x411111f0 }, + { 0x1a, 0x411111f0 }, + { } + } + }, + [ALC880_FIXUP_LG_LW25] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1a, 0x0181344f }, /* line-in */ + { 0x1b, 0x0321403f }, /* headphone */ + { } + } + }, + [ALC880_FIXUP_W810] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + /* disable bogus unused pins */ + { 0x17, 0x411111f0 }, + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_GPIO2, + }, + [ALC880_FIXUP_EAPD_COEF] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* change to EAPD mode */ + { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 }, + {} + }, + }, + [ALC880_FIXUP_TCL_S700] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* change to EAPD mode */ + { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 }, + {} + }, + .chained = true, + .chain_id = ALC880_FIXUP_GPIO2, + }, + [ALC880_FIXUP_VOL_KNOB] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc880_fixup_vol_knob, + }, + [ALC880_FIXUP_FUJITSU] = { + /* override all pins as BIOS on old Amilo is broken */ + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x0121401f }, /* HP */ + { 0x15, 0x99030120 }, /* speaker */ + { 0x16, 0x99030130 }, /* bass speaker */ + { 0x17, 0x411111f0 }, /* N/A */ + { 0x18, 0x411111f0 }, /* N/A */ + { 0x19, 0x01a19950 }, /* mic-in */ + { 0x1a, 0x411111f0 }, /* N/A */ + { 0x1b, 0x411111f0 }, /* N/A */ + { 0x1c, 0x411111f0 }, /* N/A */ + { 0x1d, 0x411111f0 }, /* N/A */ + { 0x1e, 0x01454140 }, /* SPDIF out */ + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_VOL_KNOB, + }, + [ALC880_FIXUP_F1734] = { + /* almost compatible with FUJITSU, but no bass and SPDIF */ + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x0121401f }, /* HP */ + { 0x15, 0x99030120 }, /* speaker */ + { 0x16, 0x411111f0 }, /* N/A */ + { 0x17, 0x411111f0 }, /* N/A */ + { 0x18, 0x411111f0 }, /* N/A */ + { 0x19, 0x01a19950 }, /* mic-in */ + { 0x1a, 0x411111f0 }, /* N/A */ + { 0x1b, 0x411111f0 }, /* N/A */ + { 0x1c, 0x411111f0 }, /* N/A */ + { 0x1d, 0x411111f0 }, /* N/A */ + { 0x1e, 0x411111f0 }, /* N/A */ + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_VOL_KNOB, + }, + [ALC880_FIXUP_UNIWILL] = { + /* need to fix HP and speaker pins to be parsed correctly */ + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x0121411f }, /* HP */ + { 0x15, 0x99030120 }, /* speaker */ + { 0x16, 0x99030130 }, /* bass speaker */ + { } + }, + }, + [ALC880_FIXUP_UNIWILL_DIG] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + /* disable bogus unused pins */ + { 0x17, 0x411111f0 }, + { 0x19, 0x411111f0 }, + { 0x1b, 0x411111f0 }, + { 0x1f, 0x411111f0 }, + { } + } + }, + [ALC880_FIXUP_Z71V] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + /* set up the whole pins as BIOS is utterly broken */ + { 0x14, 0x99030120 }, /* speaker */ + { 0x15, 0x0121411f }, /* HP */ + { 0x16, 0x411111f0 }, /* N/A */ + { 0x17, 0x411111f0 }, /* N/A */ + { 0x18, 0x01a19950 }, /* mic-in */ + { 0x19, 0x411111f0 }, /* N/A */ + { 0x1a, 0x01813031 }, /* line-in */ + { 0x1b, 0x411111f0 }, /* N/A */ + { 0x1c, 0x411111f0 }, /* N/A */ + { 0x1d, 0x411111f0 }, /* N/A */ + { 0x1e, 0x0144111e }, /* SPDIF */ + { } + } + }, + [ALC880_FIXUP_ASUS_W5A] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + /* set up the whole pins as BIOS is utterly broken */ + { 0x14, 0x0121411f }, /* HP */ + { 0x15, 0x411111f0 }, /* N/A */ + { 0x16, 0x411111f0 }, /* N/A */ + { 0x17, 0x411111f0 }, /* N/A */ + { 0x18, 0x90a60160 }, /* mic */ + { 0x19, 0x411111f0 }, /* N/A */ + { 0x1a, 0x411111f0 }, /* N/A */ + { 0x1b, 0x411111f0 }, /* N/A */ + { 0x1c, 0x411111f0 }, /* N/A */ + { 0x1d, 0x411111f0 }, /* N/A */ + { 0x1e, 0xb743111e }, /* SPDIF out */ + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_GPIO1, + }, + [ALC880_FIXUP_3ST_BASE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x01014010 }, /* line-out */ + { 0x15, 0x411111f0 }, /* N/A */ + { 0x16, 0x411111f0 }, /* N/A */ + { 0x17, 0x411111f0 }, /* N/A */ + { 0x18, 0x01a19c30 }, /* mic-in */ + { 0x19, 0x0121411f }, /* HP */ + { 0x1a, 0x01813031 }, /* line-in */ + { 0x1b, 0x02a19c40 }, /* front-mic */ + { 0x1c, 0x411111f0 }, /* N/A */ + { 0x1d, 0x411111f0 }, /* N/A */ + /* 0x1e is filled in below */ + { 0x1f, 0x411111f0 }, /* N/A */ + { } + } + }, + [ALC880_FIXUP_3ST] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1e, 0x411111f0 }, /* N/A */ + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_3ST_BASE, + }, + [ALC880_FIXUP_3ST_DIG] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1e, 0x0144111e }, /* SPDIF */ + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_3ST_BASE, + }, + [ALC880_FIXUP_5ST_BASE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x01014010 }, /* front */ + { 0x15, 0x411111f0 }, /* N/A */ + { 0x16, 0x01011411 }, /* CLFE */ + { 0x17, 0x01016412 }, /* surr */ + { 0x18, 0x01a19c30 }, /* mic-in */ + { 0x19, 0x0121411f }, /* HP */ + { 0x1a, 0x01813031 }, /* line-in */ + { 0x1b, 0x02a19c40 }, /* front-mic */ + { 0x1c, 0x411111f0 }, /* N/A */ + { 0x1d, 0x411111f0 }, /* N/A */ + /* 0x1e is filled in below */ + { 0x1f, 0x411111f0 }, /* N/A */ + { } + } + }, + [ALC880_FIXUP_5ST] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1e, 0x411111f0 }, /* N/A */ + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_5ST_BASE, + }, + [ALC880_FIXUP_5ST_DIG] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1e, 0x0144111e }, /* SPDIF */ + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_5ST_BASE, + }, + [ALC880_FIXUP_6ST_BASE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x01014010 }, /* front */ + { 0x15, 0x01016412 }, /* surr */ + { 0x16, 0x01011411 }, /* CLFE */ + { 0x17, 0x01012414 }, /* side */ + { 0x18, 0x01a19c30 }, /* mic-in */ + { 0x19, 0x02a19c40 }, /* front-mic */ + { 0x1a, 0x01813031 }, /* line-in */ + { 0x1b, 0x0121411f }, /* HP */ + { 0x1c, 0x411111f0 }, /* N/A */ + { 0x1d, 0x411111f0 }, /* N/A */ + /* 0x1e is filled in below */ + { 0x1f, 0x411111f0 }, /* N/A */ + { } + } + }, + [ALC880_FIXUP_6ST] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1e, 0x411111f0 }, /* N/A */ + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_6ST_BASE, + }, + [ALC880_FIXUP_6ST_DIG] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1e, 0x0144111e }, /* SPDIF */ + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_6ST_BASE, + }, + [ALC880_FIXUP_6ST_AUTOMUTE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1b, 0x0121401f }, /* HP with jack detect */ + { } + }, + .chained_before = true, + .chain_id = ALC880_FIXUP_6ST_BASE, + }, +}; + +static const struct hda_quirk alc880_fixup_tbl[] = { + SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810), + SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS W5A", ALC880_FIXUP_ASUS_W5A), + SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V), + SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1), + SND_PCI_QUIRK(0x147b, 0x1045, "ABit AA8XE", ALC880_FIXUP_6ST_AUTOMUTE), + SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2), + SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF), + SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG), + SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_FIXUP_F1734), + SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_FIXUP_UNIWILL), + SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB), + SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810), + SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM), + SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST_AUTOMUTE), + SND_PCI_QUIRK(0x1734, 0x107c, "FSC Amilo M1437", ALC880_FIXUP_FUJITSU), + SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU), + SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734), + SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU), + SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG), + SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG), + SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG), + SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_FIXUP_LG_LW25), + SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700), + + /* Below is the copied entries from alc880_quirks.c. + * It's not quite sure whether BIOS sets the correct pin-config table + * on these machines, thus they are kept to be compatible with + * the old static quirks. Once when it's confirmed to work without + * these overrides, it'd be better to remove. + */ + SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_FIXUP_6ST), + SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_FIXUP_3ST_DIG), + SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_FIXUP_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_FIXUP_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_FIXUP_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_FIXUP_3ST_DIG), + SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_FIXUP_3ST), + SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_FIXUP_6ST_DIG), + SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_FIXUP_3ST), + SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_FIXUP_3ST), + SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_FIXUP_5ST), + SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_FIXUP_5ST), + SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_FIXUP_5ST), + SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_FIXUP_6ST_DIG), + SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_FIXUP_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_FIXUP_6ST_DIG), + SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_FIXUP_6ST_DIG), + SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_FIXUP_6ST_DIG), /* broken BIOS */ + SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_FIXUP_6ST_DIG), + SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_FIXUP_3ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_FIXUP_3ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_FIXUP_3ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_FIXUP_5ST_DIG), + /* default Intel */ + SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_FIXUP_3ST), + SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_FIXUP_6ST_DIG), + {} +}; + +static const struct hda_model_fixup alc880_fixup_models[] = { + {.id = ALC880_FIXUP_3ST, .name = "3stack"}, + {.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"}, + {.id = ALC880_FIXUP_5ST, .name = "5stack"}, + {.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"}, + {.id = ALC880_FIXUP_6ST, .name = "6stack"}, + {.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"}, + {.id = ALC880_FIXUP_6ST_AUTOMUTE, .name = "6stack-automute"}, + {} +}; + + +/* + * OK, here we have finally the patch for ALC880 + */ +static int patch_alc880(struct hda_codec *codec) +{ + struct alc_spec *spec; + int err; + + err = alc_alloc_spec(codec, 0x0b); + if (err < 0) + return err; + + spec = codec->spec; + spec->gen.need_dac_fix = 1; + spec->gen.beep_nid = 0x01; + + codec->patch_ops.unsol_event = alc880_unsol_event; + + alc_pre_init(codec); + + snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl, + alc880_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + /* automatic parse from the BIOS config */ + err = alc880_parse_auto_config(codec); + if (err < 0) + goto error; + + if (!spec->gen.no_analog) { + err = set_beep_amp(spec, 0x0b, 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_alc880[] = { + HDA_CODEC_ENTRY(0x10ec0880, "ALC880", patch_alc880), + {} /* terminator */ +}; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc880); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek ALC880 HD-audio codec"); +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); + +static struct hda_codec_driver alc880_driver = { + .id = snd_hda_id_alc880, +}; + +module_hda_codec_driver(alc880_driver); diff --git a/sound/hda/codecs/realtek/alc882.c b/sound/hda/codecs/realtek/alc882.c new file mode 100644 index 000000000000..6af2f7fcc6bb --- /dev/null +++ b/sound/hda/codecs/realtek/alc882.c @@ -0,0 +1,847 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Realtek ALC882/883/885/888/889 codec support +// +// ALC882 is almost identical with ALC880 but has cleaner and more flexible +// configuration. Each pin widget can choose any input DACs and a mixer. +// Each ADC is connected from a mixer of all inputs. This makes possible +// 6-channel independent captures. +// +// In addition, an independent DAC for the multi-playback (not used in this +// driver yet). +// + +#include +#include +#include "realtek.h" + +/* + * Pin config fixes + */ +enum { + ALC882_FIXUP_ABIT_AW9D_MAX, + ALC882_FIXUP_LENOVO_Y530, + ALC882_FIXUP_PB_M5210, + ALC882_FIXUP_ACER_ASPIRE_7736, + ALC882_FIXUP_ASUS_W90V, + ALC889_FIXUP_CD, + ALC889_FIXUP_FRONT_HP_NO_PRESENCE, + ALC889_FIXUP_VAIO_TT, + ALC888_FIXUP_EEE1601, + ALC886_FIXUP_EAPD, + ALC882_FIXUP_EAPD, + ALC883_FIXUP_EAPD, + ALC883_FIXUP_ACER_EAPD, + ALC882_FIXUP_GPIO1, + ALC882_FIXUP_GPIO2, + ALC882_FIXUP_GPIO3, + ALC889_FIXUP_COEF, + ALC882_FIXUP_ASUS_W2JC, + ALC882_FIXUP_ACER_ASPIRE_4930G, + ALC882_FIXUP_ACER_ASPIRE_8930G, + ALC882_FIXUP_ASPIRE_8930G_VERBS, + ALC885_FIXUP_MACPRO_GPIO, + ALC889_FIXUP_DAC_ROUTE, + ALC889_FIXUP_MBP_VREF, + ALC889_FIXUP_IMAC91_VREF, + ALC889_FIXUP_MBA11_VREF, + ALC889_FIXUP_MBA21_VREF, + ALC889_FIXUP_MP11_VREF, + ALC889_FIXUP_MP41_VREF, + ALC882_FIXUP_INV_DMIC, + ALC882_FIXUP_NO_PRIMARY_HP, + ALC887_FIXUP_ASUS_BASS, + ALC887_FIXUP_BASS_CHMAP, + ALC1220_FIXUP_GB_DUAL_CODECS, + ALC1220_FIXUP_GB_X570, + ALC1220_FIXUP_CLEVO_P950, + ALC1220_FIXUP_CLEVO_PB51ED, + ALC1220_FIXUP_CLEVO_PB51ED_PINS, + ALC887_FIXUP_ASUS_AUDIO, + ALC887_FIXUP_ASUS_HMIC, + ALCS1200A_FIXUP_MIC_VREF, + ALC888VD_FIXUP_MIC_100VREF, +}; + +static void alc889_fixup_coef(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action != HDA_FIXUP_ACT_INIT) + return; + alc_update_coef_idx(codec, 7, 0, 0x2030); +} + +/* set up GPIO at initialization */ +static void alc885_fixup_macpro_gpio(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + spec->gpio_write_delay = true; + alc_fixup_gpio3(codec, fix, action); +} + +/* Fix the connection of some pins for ALC889: + * At least, Acer Aspire 5935 shows the connections to DAC3/4 don't + * work correctly (bko#42740) + */ +static void alc889_fixup_dac_route(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + /* fake the connections during parsing the tree */ + static const hda_nid_t conn1[] = { 0x0c, 0x0d }; + static const hda_nid_t conn2[] = { 0x0e, 0x0f }; + snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1); + snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn1), conn1); + snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn2), conn2); + snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn2), conn2); + } else if (action == HDA_FIXUP_ACT_PROBE) { + /* restore the connections */ + static const hda_nid_t conn[] = { 0x0c, 0x0d, 0x0e, 0x0f, 0x26 }; + snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn); + snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn), conn); + snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn), conn); + snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn), conn); + } +} + +/* Set VREF on HP pin */ +static void alc889_fixup_mbp_vref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + static const hda_nid_t nids[] = { 0x14, 0x15, 0x19 }; + struct alc_spec *spec = codec->spec; + int i; + + if (action != HDA_FIXUP_ACT_INIT) + return; + for (i = 0; i < ARRAY_SIZE(nids); i++) { + unsigned int val = snd_hda_codec_get_pincfg(codec, nids[i]); + if (get_defcfg_device(val) != AC_JACK_HP_OUT) + continue; + val = snd_hda_codec_get_pin_target(codec, nids[i]); + val |= AC_PINCTL_VREF_80; + snd_hda_set_pin_ctl(codec, nids[i], val); + spec->gen.keep_vref_in_automute = 1; + break; + } +} + +static void alc889_fixup_mac_pins(struct hda_codec *codec, + const hda_nid_t *nids, int num_nids) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < num_nids; i++) { + unsigned int val; + val = snd_hda_codec_get_pin_target(codec, nids[i]); + val |= AC_PINCTL_VREF_50; + snd_hda_set_pin_ctl(codec, nids[i], val); + } + spec->gen.keep_vref_in_automute = 1; +} + +/* Set VREF on speaker pins on imac91 */ +static void alc889_fixup_imac91_vref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + static const hda_nid_t nids[] = { 0x18, 0x1a }; + + if (action == HDA_FIXUP_ACT_INIT) + alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids)); +} + +/* Set VREF on speaker pins on mba11 */ +static void alc889_fixup_mba11_vref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + static const hda_nid_t nids[] = { 0x18 }; + + if (action == HDA_FIXUP_ACT_INIT) + alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids)); +} + +/* Set VREF on speaker pins on mba21 */ +static void alc889_fixup_mba21_vref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + static const hda_nid_t nids[] = { 0x18, 0x19 }; + + if (action == HDA_FIXUP_ACT_INIT) + alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids)); +} + +/* Don't take HP output as primary + * Strangely, the speaker output doesn't work on Vaio Z and some Vaio + * all-in-one desktop PCs (for example VGC-LN51JGB) through DAC 0x05 + */ +static void alc882_fixup_no_primary_hp(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.no_primary_hp = 1; + spec->gen.no_multi_io = 1; + } +} + +static void alc1220_fixup_gb_x570(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + static const hda_nid_t conn1[] = { 0x0c }; + static const struct coef_fw gb_x570_coefs[] = { + WRITE_COEF(0x07, 0x03c0), + WRITE_COEF(0x1a, 0x01c1), + WRITE_COEF(0x1b, 0x0202), + WRITE_COEF(0x43, 0x3005), + {} + }; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1); + snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1); + break; + case HDA_FIXUP_ACT_INIT: + alc_process_coef_fw(codec, gb_x570_coefs); + break; + } +} + +static void alc1220_fixup_clevo_p950(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + static const hda_nid_t conn1[] = { 0x0c }; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + alc_update_coef_idx(codec, 0x7, 0, 0x3c3); + /* We therefore want to make sure 0x14 (front headphone) and + * 0x1b (speakers) use the stereo DAC 0x02 + */ + snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1); + snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1); +} + +static void alc1220_fixup_clevo_pb51ed(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + alc1220_fixup_clevo_p950(codec, fix, action); + alc_fixup_headset_mode_no_hp_mic(codec, fix, action); +} + +static void alc887_asus_hp_automute_hook(struct hda_codec *codec, + struct hda_jack_callback *jack) +{ + struct alc_spec *spec = codec->spec; + unsigned int vref; + + snd_hda_gen_hp_automute(codec, jack); + + if (spec->gen.hp_jack_present) + vref = AC_PINCTL_VREF_80; + else + vref = AC_PINCTL_VREF_HIZ; + snd_hda_set_pin_ctl(codec, 0x19, PIN_HP | vref); +} + +static void alc887_fixup_asus_jack(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + if (action != HDA_FIXUP_ACT_PROBE) + return; + snd_hda_set_pin_ctl_cache(codec, 0x1b, PIN_HP); + spec->gen.hp_automute_hook = alc887_asus_hp_automute_hook; +} + +static const struct hda_fixup alc882_fixups[] = { + [ALC882_FIXUP_ABIT_AW9D_MAX] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x15, 0x01080104 }, /* side */ + { 0x16, 0x01011012 }, /* rear */ + { 0x17, 0x01016011 }, /* clfe */ + { } + } + }, + [ALC882_FIXUP_LENOVO_Y530] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x15, 0x99130112 }, /* rear int speakers */ + { 0x16, 0x99130111 }, /* subwoofer */ + { } + } + }, + [ALC882_FIXUP_PB_M5210] = { + .type = HDA_FIXUP_PINCTLS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, PIN_VREF50 }, + {} + } + }, + [ALC882_FIXUP_ACER_ASPIRE_7736] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_sku_ignore, + }, + [ALC882_FIXUP_ASUS_W90V] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x16, 0x99130110 }, /* fix sequence for CLFE */ + { } + } + }, + [ALC889_FIXUP_CD] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1c, 0x993301f0 }, /* CD */ + { } + } + }, + [ALC889_FIXUP_FRONT_HP_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1b, 0x02214120 }, /* Front HP jack is flaky, disable jack detect */ + { } + }, + .chained = true, + .chain_id = ALC889_FIXUP_CD, + }, + [ALC889_FIXUP_VAIO_TT] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x17, 0x90170111 }, /* hidden surround speaker */ + { } + } + }, + [ALC888_FIXUP_EEE1601] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x0838 }, + { } + } + }, + [ALC886_FIXUP_EAPD] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* change to EAPD mode */ + { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x0068 }, + { } + } + }, + [ALC882_FIXUP_EAPD] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* change to EAPD mode */ + { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 }, + { } + } + }, + [ALC883_FIXUP_EAPD] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* change to EAPD mode */ + { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 }, + { } + } + }, + [ALC883_FIXUP_ACER_EAPD] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* eanable EAPD on Acer laptops */ + { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 }, + { } + } + }, + [ALC882_FIXUP_GPIO1] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_gpio1, + }, + [ALC882_FIXUP_GPIO2] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_gpio2, + }, + [ALC882_FIXUP_GPIO3] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_gpio3, + }, + [ALC882_FIXUP_ASUS_W2JC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_gpio1, + .chained = true, + .chain_id = ALC882_FIXUP_EAPD, + }, + [ALC889_FIXUP_COEF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc889_fixup_coef, + }, + [ALC882_FIXUP_ACER_ASPIRE_4930G] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x16, 0x99130111 }, /* CLFE speaker */ + { 0x17, 0x99130112 }, /* surround speaker */ + { } + }, + .chained = true, + .chain_id = ALC882_FIXUP_GPIO1, + }, + [ALC882_FIXUP_ACER_ASPIRE_8930G] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x16, 0x99130111 }, /* CLFE speaker */ + { 0x1b, 0x99130112 }, /* surround speaker */ + { } + }, + .chained = true, + .chain_id = ALC882_FIXUP_ASPIRE_8930G_VERBS, + }, + [ALC882_FIXUP_ASPIRE_8930G_VERBS] = { + /* additional init verbs for Acer Aspire 8930G */ + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* Enable all DACs */ + /* DAC DISABLE/MUTE 1? */ + /* setting bits 1-5 disables DAC nids 0x02-0x06 + * apparently. Init=0x38 */ + { 0x20, AC_VERB_SET_COEF_INDEX, 0x03 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, + /* DAC DISABLE/MUTE 2? */ + /* some bit here disables the other DACs. + * Init=0x4900 */ + { 0x20, AC_VERB_SET_COEF_INDEX, 0x08 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, + /* DMIC fix + * This laptop has a stereo digital microphone. + * The mics are only 1cm apart which makes the stereo + * useless. However, either the mic or the ALC889 + * makes the signal become a difference/sum signal + * instead of standard stereo, which is annoying. + * So instead we flip this bit which makes the + * codec replicate the sum signal to both channels, + * turning it into a normal mono mic. + */ + /* DMIC_CONTROL? Init value = 0x0001 */ + { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x0003 }, + { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 }, + { } + }, + .chained = true, + .chain_id = ALC882_FIXUP_GPIO1, + }, + [ALC885_FIXUP_MACPRO_GPIO] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc885_fixup_macpro_gpio, + }, + [ALC889_FIXUP_DAC_ROUTE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc889_fixup_dac_route, + }, + [ALC889_FIXUP_MBP_VREF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc889_fixup_mbp_vref, + .chained = true, + .chain_id = ALC882_FIXUP_GPIO1, + }, + [ALC889_FIXUP_IMAC91_VREF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc889_fixup_imac91_vref, + .chained = true, + .chain_id = ALC882_FIXUP_GPIO1, + }, + [ALC889_FIXUP_MBA11_VREF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc889_fixup_mba11_vref, + .chained = true, + .chain_id = ALC889_FIXUP_MBP_VREF, + }, + [ALC889_FIXUP_MBA21_VREF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc889_fixup_mba21_vref, + .chained = true, + .chain_id = ALC889_FIXUP_MBP_VREF, + }, + [ALC889_FIXUP_MP11_VREF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc889_fixup_mba11_vref, + .chained = true, + .chain_id = ALC885_FIXUP_MACPRO_GPIO, + }, + [ALC889_FIXUP_MP41_VREF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc889_fixup_mbp_vref, + .chained = true, + .chain_id = ALC885_FIXUP_MACPRO_GPIO, + }, + [ALC882_FIXUP_INV_DMIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_inv_dmic, + }, + [ALC882_FIXUP_NO_PRIMARY_HP] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc882_fixup_no_primary_hp, + }, + [ALC887_FIXUP_ASUS_BASS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + {0x16, 0x99130130}, /* bass speaker */ + {} + }, + .chained = true, + .chain_id = ALC887_FIXUP_BASS_CHMAP, + }, + [ALC887_FIXUP_BASS_CHMAP] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_bass_chmap, + }, + [ALC1220_FIXUP_GB_DUAL_CODECS] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc1220_fixup_gb_dual_codecs, + }, + [ALC1220_FIXUP_GB_X570] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc1220_fixup_gb_x570, + }, + [ALC1220_FIXUP_CLEVO_P950] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc1220_fixup_clevo_p950, + }, + [ALC1220_FIXUP_CLEVO_PB51ED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc1220_fixup_clevo_pb51ed, + }, + [ALC1220_FIXUP_CLEVO_PB51ED_PINS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */ + {} + }, + .chained = true, + .chain_id = ALC1220_FIXUP_CLEVO_PB51ED, + }, + [ALC887_FIXUP_ASUS_AUDIO] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x15, 0x02a14150 }, /* use as headset mic, without its own jack detect */ + { 0x19, 0x22219420 }, + {} + }, + }, + [ALC887_FIXUP_ASUS_HMIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc887_fixup_asus_jack, + .chained = true, + .chain_id = ALC887_FIXUP_ASUS_AUDIO, + }, + [ALCS1200A_FIXUP_MIC_VREF] = { + .type = HDA_FIXUP_PINCTLS, + .v.pins = (const struct hda_pintbl[]) { + { 0x18, PIN_VREF50 }, /* rear mic */ + { 0x19, PIN_VREF50 }, /* front mic */ + {} + } + }, + [ALC888VD_FIXUP_MIC_100VREF] = { + .type = HDA_FIXUP_PINCTLS, + .v.pins = (const struct hda_pintbl[]) { + { 0x18, PIN_VREF100 }, /* headset mic */ + {} + } + }, +}; + +static const struct hda_quirk alc882_fixup_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD), + SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), + SND_PCI_QUIRK(0x1025, 0x0107, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), + SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_FIXUP_ACER_EAPD), + SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), + SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_FIXUP_ACER_EAPD), + SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_FIXUP_ACER_EAPD), + SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G", + ALC882_FIXUP_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G", + ALC882_FIXUP_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G", + ALC882_FIXUP_ACER_ASPIRE_8930G), + SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G", + ALC882_FIXUP_ACER_ASPIRE_8930G), + SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G", + ALC882_FIXUP_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210), + SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", + ALC882_FIXUP_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G", + ALC882_FIXUP_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x021e, "Acer Aspire 5739G", + ALC882_FIXUP_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x0259, "Acer Aspire 5935", ALC889_FIXUP_DAC_ROUTE), + SND_PCI_QUIRK(0x1025, 0x026b, "Acer Aspire 8940G", ALC882_FIXUP_ACER_ASPIRE_8930G), + SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", ALC882_FIXUP_ACER_ASPIRE_7736), + SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_FIXUP_EAPD), + SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V), + SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC), + SND_PCI_QUIRK(0x1043, 0x2390, "Asus D700SA", ALC887_FIXUP_ASUS_HMIC), + SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601), + SND_PCI_QUIRK(0x1043, 0x84bc, "ASUS ET2700", ALC887_FIXUP_ASUS_BASS), + SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3), + SND_PCI_QUIRK(0x1043, 0x8797, "ASUS TUF B550M-PLUS", ALCS1200A_FIXUP_MIC_VREF), + SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP), + SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP), + SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT), + SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP), + SND_PCI_QUIRK(0x104d, 0x9060, "Sony Vaio VPCL14M1R", ALC882_FIXUP_NO_PRIMARY_HP), + + /* All Apple entries are in codec SSIDs */ + SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF), + SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF), + SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF), + SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC889_FIXUP_MP11_VREF), + SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO), + SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO), + SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF), + SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF), + SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD), + SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBA11_VREF), + SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBA21_VREF), + SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF), + SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF), + SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO), + SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF), + SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF), + SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF), + SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 4,1/5,1", ALC889_FIXUP_MP41_VREF), + SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF), + SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF), + SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF), + SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_MBA11_VREF), + + SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD), + SND_PCI_QUIRK(0x10ec, 0x12d8, "iBase Elo Touch", ALC888VD_FIXUP_MIC_100VREF), + SND_PCI_QUIRK(0x13fe, 0x1009, "Advantech MIT-W101", ALC886_FIXUP_EAPD), + SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE), + SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS), + SND_PCI_QUIRK(0x1458, 0xa0cd, "Gigabyte X570 Aorus Master", ALC1220_FIXUP_GB_X570), + SND_PCI_QUIRK(0x1458, 0xa0ce, "Gigabyte X570 Aorus Xtreme", ALC1220_FIXUP_GB_X570), + SND_PCI_QUIRK(0x1458, 0xa0d5, "Gigabyte X570S Aorus Master", ALC1220_FIXUP_GB_X570), + SND_PCI_QUIRK(0x1462, 0x11f7, "MSI-GE63", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1462, 0x1228, "MSI-GP63", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1462, 0x1229, "MSI-GP73", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1462, 0x1275, "MSI-GL63", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1462, 0x1276, "MSI-GL73", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1462, 0x1293, "MSI-GP65", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD), + SND_PCI_QUIRK(0x1462, 0xcc34, "MSI Godlike X570", ALC1220_FIXUP_GB_DUAL_CODECS), + SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS), + SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), + SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX), + SND_PCI_QUIRK(0x1558, 0x3702, "Clevo X370SN[VW]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x50d3, "Clevo PC50[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x5802, "Clevo X58[05]WN[RST]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x65e1, "Clevo PB51[ED][DF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x65e5, "Clevo PC50D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x65f1, "Clevo PC50HS", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x65f5, "Clevo PD50PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x66a2, "Clevo PE60RNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x66a6, "Clevo PE60SN[CDE]-[GS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x67f1, "Clevo PC70H[PRS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x67f5, "Clevo PD70PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x70d1, "Clevo PC70[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x7714, "Clevo X170SM", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x7715, "Clevo X170KM-G", ALC1220_FIXUP_CLEVO_PB51ED), + SND_PCI_QUIRK(0x1558, 0x9501, "Clevo P950HR", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x9506, "Clevo P955HQ", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x950a, "Clevo P955H[PR]", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x95e1, "Clevo P95xER", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x95e2, "Clevo P950ER", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x95e3, "Clevo P955[ER]T", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x95e4, "Clevo P955ER", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x95e5, "Clevo P955EE6", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x95e6, "Clevo P950R[CDF]", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x96e1, "Clevo P960[ER][CDFN]-K", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x97e1, "Clevo P970[ER][CDFN]", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x97e2, "Clevo P970RC-M", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0xd502, "Clevo PD50SNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + 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), + SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_FIXUP_COEF), + {} +}; + +static const struct hda_model_fixup alc882_fixup_models[] = { + {.id = ALC882_FIXUP_ABIT_AW9D_MAX, .name = "abit-aw9d"}, + {.id = ALC882_FIXUP_LENOVO_Y530, .name = "lenovo-y530"}, + {.id = ALC882_FIXUP_ACER_ASPIRE_7736, .name = "acer-aspire-7736"}, + {.id = ALC882_FIXUP_ASUS_W90V, .name = "asus-w90v"}, + {.id = ALC889_FIXUP_CD, .name = "cd"}, + {.id = ALC889_FIXUP_FRONT_HP_NO_PRESENCE, .name = "no-front-hp"}, + {.id = ALC889_FIXUP_VAIO_TT, .name = "vaio-tt"}, + {.id = ALC888_FIXUP_EEE1601, .name = "eee1601"}, + {.id = ALC882_FIXUP_EAPD, .name = "alc882-eapd"}, + {.id = ALC883_FIXUP_EAPD, .name = "alc883-eapd"}, + {.id = ALC882_FIXUP_GPIO1, .name = "gpio1"}, + {.id = ALC882_FIXUP_GPIO2, .name = "gpio2"}, + {.id = ALC882_FIXUP_GPIO3, .name = "gpio3"}, + {.id = ALC889_FIXUP_COEF, .name = "alc889-coef"}, + {.id = ALC882_FIXUP_ASUS_W2JC, .name = "asus-w2jc"}, + {.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"}, + {.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"}, + {.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"}, + {.id = ALC885_FIXUP_MACPRO_GPIO, .name = "macpro-gpio"}, + {.id = ALC889_FIXUP_DAC_ROUTE, .name = "dac-route"}, + {.id = ALC889_FIXUP_MBP_VREF, .name = "mbp-vref"}, + {.id = ALC889_FIXUP_IMAC91_VREF, .name = "imac91-vref"}, + {.id = ALC889_FIXUP_MBA11_VREF, .name = "mba11-vref"}, + {.id = ALC889_FIXUP_MBA21_VREF, .name = "mba21-vref"}, + {.id = ALC889_FIXUP_MP11_VREF, .name = "mp11-vref"}, + {.id = ALC889_FIXUP_MP41_VREF, .name = "mp41-vref"}, + {.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"}, + {.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"}, + {.id = ALC887_FIXUP_ASUS_BASS, .name = "asus-bass"}, + {.id = ALC1220_FIXUP_GB_DUAL_CODECS, .name = "dual-codecs"}, + {.id = ALC1220_FIXUP_GB_X570, .name = "gb-x570"}, + {.id = ALC1220_FIXUP_CLEVO_P950, .name = "clevo-p950"}, + {} +}; + +static const struct snd_hda_pin_quirk alc882_pin_fixup_tbl[] = { + SND_HDA_PIN_QUIRK(0x10ec1220, 0x1043, "ASUS", ALC1220_FIXUP_CLEVO_P950, + {0x14, 0x01014010}, + {0x15, 0x01011012}, + {0x16, 0x01016011}, + {0x18, 0x01a19040}, + {0x19, 0x02a19050}, + {0x1a, 0x0181304f}, + {0x1b, 0x0221401f}, + {0x1e, 0x01456130}), + SND_HDA_PIN_QUIRK(0x10ec1220, 0x1462, "MS-7C35", ALC1220_FIXUP_CLEVO_P950, + {0x14, 0x01015010}, + {0x15, 0x01011012}, + {0x16, 0x01011011}, + {0x18, 0x01a11040}, + {0x19, 0x02a19050}, + {0x1a, 0x0181104f}, + {0x1b, 0x0221401f}, + {0x1e, 0x01451130}), + {} +}; + +/* + * BIOS auto configuration + */ +/* almost identical with ALC880 parser... */ +static int alc882_parse_auto_config(struct hda_codec *codec) +{ + static const hda_nid_t alc882_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 }; + return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids); +} + +/* + */ +static int patch_alc882(struct hda_codec *codec) +{ + struct alc_spec *spec; + int err; + + err = alc_alloc_spec(codec, 0x0b); + if (err < 0) + return err; + + spec = codec->spec; + + switch (codec->core.vendor_id) { + case 0x10ec0882: + case 0x10ec0885: + case 0x10ec0900: + case 0x10ec0b00: + case 0x10ec1220: + break; + default: + /* ALC883 and variants */ + alc_fix_pll_init(codec, 0x20, 0x0a, 10); + break; + } + + alc_pre_init(codec); + + snd_hda_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl, + alc882_fixups); + snd_hda_pick_pin_fixup(codec, alc882_pin_fixup_tbl, alc882_fixups, true); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + alc_auto_parse_customize_define(codec); + + if (has_cdefine_beep(codec)) + spec->gen.beep_nid = 0x01; + + /* automatic parse from the BIOS config */ + err = alc882_parse_auto_config(codec); + if (err < 0) + goto error; + + if (!spec->gen.no_analog && spec->gen.beep_nid) { + err = set_beep_amp(spec, 0x0b, 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_alc882[] = { + HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100002, "ALC662 rev2", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0882, "ALC882", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0883, "ALC883", patch_alc882), + HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100101, "ALC889A", patch_alc882), + HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100103, "ALC889A", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0885, "ALC885", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0887, "ALC887", patch_alc882), + HDA_CODEC_REV_ENTRY(0x10ec0888, 0x100101, "ALC1200", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0888, "ALC888", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0889, "ALC889", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0b00, "ALCS1200A", patch_alc882), + HDA_CODEC_ENTRY(0x10ec1168, "ALC1220", patch_alc882), + HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882), + {} /* terminator */ +}; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc882); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek ALC882 and compatible HD-audio codecs"); +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); + +static struct hda_codec_driver alc882_driver = { + .id = snd_hda_id_alc882, +}; + +module_hda_codec_driver(alc882_driver); diff --git a/sound/hda/codecs/realtek/realtek.c b/sound/hda/codecs/realtek/realtek.c new file mode 100644 index 000000000000..4ab49e76c304 --- /dev/null +++ b/sound/hda/codecs/realtek/realtek.c @@ -0,0 +1,2314 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Realtek HD-audio codec support code +// + +#include +#include +#include "realtek.h" + +/* + * COEF access helper functions + */ + +static void coef_mutex_lock(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + snd_hda_power_up_pm(codec); + mutex_lock(&spec->coef_mutex); +} + +static void coef_mutex_unlock(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + mutex_unlock(&spec->coef_mutex); + snd_hda_power_down_pm(codec); +} + +static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid, + unsigned int coef_idx) +{ + unsigned int val; + + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx); + val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0); + return val; +} + +int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid, + unsigned int coef_idx) +{ + unsigned int val; + + coef_mutex_lock(codec); + val = __alc_read_coefex_idx(codec, nid, coef_idx); + coef_mutex_unlock(codec); + return val; +} +EXPORT_SYMBOL_NS_GPL(alc_read_coefex_idx, "SND_HDA_CODEC_REALTEK"); + +static void __alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid, + unsigned int coef_idx, unsigned int coef_val) +{ + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coef_val); +} + +void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid, + unsigned int coef_idx, unsigned int coef_val) +{ + coef_mutex_lock(codec); + __alc_write_coefex_idx(codec, nid, coef_idx, coef_val); + coef_mutex_unlock(codec); +} +EXPORT_SYMBOL_NS_GPL(alc_write_coefex_idx, "SND_HDA_CODEC_REALTEK"); + +static void __alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid, + unsigned int coef_idx, unsigned int mask, + unsigned int bits_set) +{ + unsigned int val = __alc_read_coefex_idx(codec, nid, coef_idx); + + if (val != -1) + __alc_write_coefex_idx(codec, nid, coef_idx, + (val & ~mask) | bits_set); +} + +void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid, + unsigned int coef_idx, unsigned int mask, + unsigned int bits_set) +{ + coef_mutex_lock(codec); + __alc_update_coefex_idx(codec, nid, coef_idx, mask, bits_set); + coef_mutex_unlock(codec); +} +EXPORT_SYMBOL_NS_GPL(alc_update_coefex_idx, "SND_HDA_CODEC_REALTEK"); + +/* a special bypass for COEF 0; read the cached value at the second time */ +unsigned int alc_get_coef0(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (!spec->coef0) + spec->coef0 = alc_read_coef_idx(codec, 0); + return spec->coef0; +} +EXPORT_SYMBOL_NS_GPL(alc_get_coef0, "SND_HDA_CODEC_REALTEK"); + +void alc_process_coef_fw(struct hda_codec *codec, const struct coef_fw *fw) +{ + coef_mutex_lock(codec); + for (; fw->nid; fw++) { + if (fw->mask == (unsigned short)-1) + __alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val); + else + __alc_update_coefex_idx(codec, fw->nid, fw->idx, + fw->mask, fw->val); + } + coef_mutex_unlock(codec); +} +EXPORT_SYMBOL_NS_GPL(alc_process_coef_fw, "SND_HDA_CODEC_REALTEK"); + +/* + * GPIO setup tables, used in initialization + */ + +/* Enable GPIO mask and set output */ +void alc_setup_gpio(struct hda_codec *codec, unsigned int mask) +{ + struct alc_spec *spec = codec->spec; + + spec->gpio_mask |= mask; + spec->gpio_dir |= mask; + spec->gpio_data |= mask; +} +EXPORT_SYMBOL_NS_GPL(alc_setup_gpio, "SND_HDA_CODEC_REALTEK"); + +void alc_write_gpio_data(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, + spec->gpio_data); +} +EXPORT_SYMBOL_NS_GPL(alc_write_gpio_data, "SND_HDA_CODEC_REALTEK"); + +void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask, + bool on) +{ + struct alc_spec *spec = codec->spec; + unsigned int oldval = spec->gpio_data; + + if (on) + spec->gpio_data |= mask; + else + spec->gpio_data &= ~mask; + if (oldval != spec->gpio_data) + alc_write_gpio_data(codec); +} +EXPORT_SYMBOL_NS_GPL(alc_update_gpio_data, "SND_HDA_CODEC_REALTEK"); + +void alc_write_gpio(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (!spec->gpio_mask) + return; + + snd_hda_codec_write(codec, codec->core.afg, 0, + AC_VERB_SET_GPIO_MASK, spec->gpio_mask); + snd_hda_codec_write(codec, codec->core.afg, 0, + AC_VERB_SET_GPIO_DIRECTION, spec->gpio_dir); + if (spec->gpio_write_delay) + msleep(1); + alc_write_gpio_data(codec); +} +EXPORT_SYMBOL_NS_GPL(alc_write_gpio, "SND_HDA_CODEC_REALTEK"); + +void alc_fixup_gpio(struct hda_codec *codec, int action, unsigned int mask) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) + alc_setup_gpio(codec, mask); +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio, "SND_HDA_CODEC_REALTEK"); + +void alc_fixup_gpio1(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + alc_fixup_gpio(codec, action, 0x01); +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio1, "SND_HDA_CODEC_REALTEK"); + +void alc_fixup_gpio2(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + alc_fixup_gpio(codec, action, 0x02); +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio2, "SND_HDA_CODEC_REALTEK"); + +void alc_fixup_gpio3(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + alc_fixup_gpio(codec, action, 0x03); +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio3, "SND_HDA_CODEC_REALTEK"); + +void alc_fixup_gpio4(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + alc_fixup_gpio(codec, action, 0x04); +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio4, "SND_HDA_CODEC_REALTEK"); + +void alc_fixup_micmute_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) + snd_hda_gen_add_micmute_led_cdev(codec, NULL); +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_micmute_led, "SND_HDA_CODEC_REALTEK"); + +/* + * Fix hardware PLL issue + * On some codecs, the analog PLL gating control must be off while + * the default value is 1. + */ +void alc_fix_pll(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (spec->pll_nid) + alc_update_coefex_idx(codec, spec->pll_nid, spec->pll_coef_idx, + 1 << spec->pll_coef_bit, 0); +} +EXPORT_SYMBOL_NS_GPL(alc_fix_pll, "SND_HDA_CODEC_REALTEK"); + +void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, + unsigned int coef_idx, unsigned int coef_bit) +{ + struct alc_spec *spec = codec->spec; + spec->pll_nid = nid; + spec->pll_coef_idx = coef_idx; + spec->pll_coef_bit = coef_bit; + alc_fix_pll(codec); +} +EXPORT_SYMBOL_NS_GPL(alc_fix_pll_init, "SND_HDA_CODEC_REALTEK"); + +/* update the master volume per volume-knob's unsol event */ +void alc_update_knob_master(struct hda_codec *codec, + struct hda_jack_callback *jack) +{ + unsigned int val; + struct snd_kcontrol *kctl; + struct snd_ctl_elem_value *uctl; + + kctl = snd_hda_find_mixer_ctl(codec, "Master Playback Volume"); + if (!kctl) + return; + uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); + if (!uctl) + return; + val = snd_hda_codec_read(codec, jack->nid, 0, + AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); + val &= HDA_AMP_VOLMASK; + uctl->value.integer.value[0] = val; + uctl->value.integer.value[1] = val; + kctl->put(kctl, uctl); + kfree(uctl); +} +EXPORT_SYMBOL_NS_GPL(alc_update_knob_master, "SND_HDA_CODEC_REALTEK"); + +/* Change EAPD to verb control */ +void alc_fill_eapd_coef(struct hda_codec *codec) +{ + int coef; + + coef = alc_get_coef0(codec); + + switch (codec->core.vendor_id) { + case 0x10ec0262: + alc_update_coef_idx(codec, 0x7, 0, 1<<5); + break; + case 0x10ec0267: + case 0x10ec0268: + alc_update_coef_idx(codec, 0x7, 0, 1<<13); + break; + case 0x10ec0269: + if ((coef & 0x00f0) == 0x0010) + alc_update_coef_idx(codec, 0xd, 0, 1<<14); + if ((coef & 0x00f0) == 0x0020) + alc_update_coef_idx(codec, 0x4, 1<<15, 0); + if ((coef & 0x00f0) == 0x0030) + alc_update_coef_idx(codec, 0x10, 1<<9, 0); + break; + case 0x10ec0280: + case 0x10ec0284: + case 0x10ec0290: + case 0x10ec0292: + alc_update_coef_idx(codec, 0x4, 1<<15, 0); + break; + case 0x10ec0225: + case 0x10ec0295: + case 0x10ec0299: + alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000); + fallthrough; + case 0x10ec0215: + case 0x10ec0236: + case 0x10ec0245: + case 0x10ec0256: + case 0x10ec0257: + case 0x10ec0285: + case 0x10ec0289: + alc_update_coef_idx(codec, 0x36, 1<<13, 0); + fallthrough; + case 0x10ec0230: + case 0x10ec0233: + case 0x10ec0235: + case 0x10ec0255: + case 0x19e58326: + case 0x10ec0282: + case 0x10ec0283: + case 0x10ec0286: + case 0x10ec0288: + case 0x10ec0298: + case 0x10ec0300: + alc_update_coef_idx(codec, 0x10, 1<<9, 0); + break; + case 0x10ec0275: + alc_update_coef_idx(codec, 0xe, 0, 1<<0); + break; + case 0x10ec0287: + alc_update_coef_idx(codec, 0x10, 1<<9, 0); + alc_write_coef_idx(codec, 0x8, 0x4ab7); + break; + case 0x10ec0293: + alc_update_coef_idx(codec, 0xa, 1<<13, 0); + break; + case 0x10ec0234: + case 0x10ec0274: + alc_write_coef_idx(codec, 0x6e, 0x0c25); + fallthrough; + case 0x10ec0294: + case 0x10ec0700: + case 0x10ec0701: + case 0x10ec0703: + case 0x10ec0711: + alc_update_coef_idx(codec, 0x10, 1<<15, 0); + break; + case 0x10ec0662: + if ((coef & 0x00f0) == 0x0030) + alc_update_coef_idx(codec, 0x4, 1<<10, 0); /* EAPD Ctrl */ + break; + case 0x10ec0272: + case 0x10ec0273: + case 0x10ec0663: + case 0x10ec0665: + case 0x10ec0670: + case 0x10ec0671: + case 0x10ec0672: + alc_update_coef_idx(codec, 0xd, 0, 1<<14); /* EAPD Ctrl */ + break; + case 0x10ec0222: + case 0x10ec0623: + alc_update_coef_idx(codec, 0x19, 1<<13, 0); + break; + case 0x10ec0668: + alc_update_coef_idx(codec, 0x7, 3<<13, 0); + break; + case 0x10ec0867: + alc_update_coef_idx(codec, 0x4, 1<<10, 0); + break; + case 0x10ec0888: + if ((coef & 0x00f0) == 0x0020 || (coef & 0x00f0) == 0x0030) + alc_update_coef_idx(codec, 0x7, 1<<5, 0); + break; + case 0x10ec0892: + case 0x10ec0897: + alc_update_coef_idx(codec, 0x7, 1<<5, 0); + break; + case 0x10ec0899: + case 0x10ec0900: + case 0x10ec0b00: + case 0x10ec1168: + case 0x10ec1220: + alc_update_coef_idx(codec, 0x7, 1<<1, 0); + break; + } +} +EXPORT_SYMBOL_NS_GPL(alc_fill_eapd_coef, "SND_HDA_CODEC_REALTEK"); + +/* turn on/off EAPD control (only if available) */ +static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on) +{ + if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) + return; + if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD) + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, + on ? 2 : 0); +} + +/* turn on/off EAPD controls of the codec */ +void alc_auto_setup_eapd(struct hda_codec *codec, bool on) +{ + /* We currently only handle front, HP */ + static const hda_nid_t pins[] = { + 0x0f, 0x10, 0x14, 0x15, 0x17, 0 + }; + const hda_nid_t *p; + for (p = pins; *p; p++) + set_eapd(codec, *p, on); +} +EXPORT_SYMBOL_NS_GPL(alc_auto_setup_eapd, "SND_HDA_CODEC_REALTEK"); + +/* Returns the nid of the external mic input pin, or 0 if it cannot be found. */ +int alc_find_ext_mic_pin(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + hda_nid_t nid; + unsigned int defcfg; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + if (cfg->inputs[i].type != AUTO_PIN_MIC) + continue; + nid = cfg->inputs[i].pin; + defcfg = snd_hda_codec_get_pincfg(codec, nid); + if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT) + continue; + return nid; + } + + return 0; +} +EXPORT_SYMBOL_NS_GPL(alc_find_ext_mic_pin, "SND_HDA_CODEC_REALTEK"); + +void alc_headset_mic_no_shutup(struct hda_codec *codec) +{ + const struct hda_pincfg *pin; + int mic_pin = alc_find_ext_mic_pin(codec); + int i; + + /* don't shut up pins when unloading the driver; otherwise it breaks + * the default pin setup at the next load of the driver + */ + if (codec->bus->shutdown) + return; + + snd_array_for_each(&codec->init_pins, i, pin) { + /* use read here for syncing after issuing each verb */ + if (pin->nid != mic_pin) + snd_hda_codec_read(codec, pin->nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0); + } + + codec->pins_shutup = 1; +} +EXPORT_SYMBOL_NS_GPL(alc_headset_mic_no_shutup, "SND_HDA_CODEC_REALTEK"); + +void alc_shutup_pins(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (spec->no_shutup_pins) + return; + + switch (codec->core.vendor_id) { + case 0x10ec0236: + case 0x10ec0256: + case 0x10ec0257: + case 0x19e58326: + case 0x10ec0283: + case 0x10ec0285: + case 0x10ec0286: + case 0x10ec0287: + case 0x10ec0288: + case 0x10ec0295: + case 0x10ec0298: + alc_headset_mic_no_shutup(codec); + break; + default: + snd_hda_shutup_pins(codec); + break; + } +} +EXPORT_SYMBOL_NS_GPL(alc_shutup_pins, "SND_HDA_CODEC_REALTEK"); + +/* generic shutup callback; + * just turning off EAPD and a little pause for avoiding pop-noise + */ +void alc_eapd_shutup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + alc_auto_setup_eapd(codec, false); + if (!spec->no_depop_delay) + msleep(200); + alc_shutup_pins(codec); +} +EXPORT_SYMBOL_NS_GPL(alc_eapd_shutup, "SND_HDA_CODEC_REALTEK"); + +/* additional initialization for ALC888 variants */ +static void alc888_coef_init(struct hda_codec *codec) +{ + switch (alc_get_coef0(codec) & 0x00f0) { + /* alc888-VA */ + case 0x00: + /* alc888-VB */ + case 0x10: + alc_update_coef_idx(codec, 7, 0, 0x2030); /* Turn EAPD to High */ + break; + } +} + +/* generic EAPD initialization */ +void alc_auto_init_amp(struct hda_codec *codec, int type) +{ + alc_auto_setup_eapd(codec, true); + alc_write_gpio(codec); + switch (type) { + case ALC_INIT_DEFAULT: + switch (codec->core.vendor_id) { + case 0x10ec0260: + alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x2010); + break; + case 0x10ec0880: + case 0x10ec0882: + case 0x10ec0883: + case 0x10ec0885: + alc_update_coef_idx(codec, 7, 0, 0x2030); + break; + case 0x10ec0888: + alc888_coef_init(codec); + break; + } + break; + } +} +EXPORT_SYMBOL_NS_GPL(alc_auto_init_amp, "SND_HDA_CODEC_REALTEK"); + +/* get a primary headphone pin if available */ +hda_nid_t alc_get_hp_pin(struct alc_spec *spec) +{ + if (spec->gen.autocfg.hp_pins[0]) + return spec->gen.autocfg.hp_pins[0]; + if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT) + return spec->gen.autocfg.line_out_pins[0]; + return 0; +} +EXPORT_SYMBOL_NS_GPL(alc_get_hp_pin, "SND_HDA_CODEC_REALTEK"); + +/* + * Realtek SSID verification + */ + +/* Could be any non-zero and even value. When used as fixup, tells + * the driver to ignore any present sku defines. + */ +#define ALC_FIXUP_SKU_IGNORE (2) + +void alc_fixup_sku_ignore(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->cdefine.fixup = 1; + spec->cdefine.sku_cfg = ALC_FIXUP_SKU_IGNORE; + } +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_sku_ignore, "SND_HDA_CODEC_REALTEK"); + +void alc_fixup_no_depop_delay(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PROBE) { + spec->no_depop_delay = 1; + codec->depop_delay = 0; + } +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_no_depop_delay, "SND_HDA_CODEC_REALTEK"); + +int alc_auto_parse_customize_define(struct hda_codec *codec) +{ + unsigned int ass, tmp, i; + unsigned nid = 0; + struct alc_spec *spec = codec->spec; + + spec->cdefine.enable_pcbeep = 1; /* assume always enabled */ + + if (spec->cdefine.fixup) { + ass = spec->cdefine.sku_cfg; + if (ass == ALC_FIXUP_SKU_IGNORE) + return -1; + goto do_sku; + } + + if (!codec->bus->pci) + return -1; + ass = codec->core.subsystem_id & 0xffff; + if (ass != codec->bus->pci->subsystem_device && (ass & 1)) + goto do_sku; + + nid = 0x1d; + if (codec->core.vendor_id == 0x10ec0260) + nid = 0x17; + ass = snd_hda_codec_get_pincfg(codec, nid); + + if (!(ass & 1)) { + codec_info(codec, "%s: SKU not ready 0x%08x\n", + codec->core.chip_name, ass); + return -1; + } + + /* check sum */ + tmp = 0; + for (i = 1; i < 16; i++) { + if ((ass >> i) & 1) + tmp++; + } + if (((ass >> 16) & 0xf) != tmp) + return -1; + + spec->cdefine.port_connectivity = ass >> 30; + spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20; + spec->cdefine.check_sum = (ass >> 16) & 0xf; + spec->cdefine.customization = ass >> 8; +do_sku: + spec->cdefine.sku_cfg = ass; + spec->cdefine.external_amp = (ass & 0x38) >> 3; + spec->cdefine.platform_type = (ass & 0x4) >> 2; + spec->cdefine.swap = (ass & 0x2) >> 1; + spec->cdefine.override = ass & 0x1; + + codec_dbg(codec, "SKU: Nid=0x%x sku_cfg=0x%08x\n", + nid, spec->cdefine.sku_cfg); + codec_dbg(codec, "SKU: port_connectivity=0x%x\n", + spec->cdefine.port_connectivity); + codec_dbg(codec, "SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep); + codec_dbg(codec, "SKU: check_sum=0x%08x\n", spec->cdefine.check_sum); + codec_dbg(codec, "SKU: customization=0x%08x\n", spec->cdefine.customization); + codec_dbg(codec, "SKU: external_amp=0x%x\n", spec->cdefine.external_amp); + codec_dbg(codec, "SKU: platform_type=0x%x\n", spec->cdefine.platform_type); + codec_dbg(codec, "SKU: swap=0x%x\n", spec->cdefine.swap); + codec_dbg(codec, "SKU: override=0x%x\n", spec->cdefine.override); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(alc_auto_parse_customize_define, "SND_HDA_CODEC_REALTEK"); + +/* return the position of NID in the list, or -1 if not found */ +static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) +{ + int i; + for (i = 0; i < nums; i++) + if (list[i] == nid) + return i; + return -1; +} +/* return true if the given NID is found in the list */ +static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) +{ + return find_idx_in_nid_list(nid, list, nums) >= 0; +} + +/* check subsystem ID and set up device-specific initialization; + * return 1 if initialized, 0 if invalid SSID + */ +/* 32-bit subsystem ID for BIOS loading in HD Audio codec. + * 31 ~ 16 : Manufacture ID + * 15 ~ 8 : SKU ID + * 7 ~ 0 : Assembly ID + * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36 + */ +int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports) +{ + unsigned int ass, tmp, i; + unsigned nid; + struct alc_spec *spec = codec->spec; + + if (spec->cdefine.fixup) { + ass = spec->cdefine.sku_cfg; + if (ass == ALC_FIXUP_SKU_IGNORE) + return 0; + goto do_sku; + } + + ass = codec->core.subsystem_id & 0xffff; + if (codec->bus->pci && + ass != codec->bus->pci->subsystem_device && (ass & 1)) + goto do_sku; + + /* invalid SSID, check the special NID pin defcfg instead */ + /* + * 31~30 : port connectivity + * 29~21 : reserve + * 20 : PCBEEP input + * 19~16 : Check sum (15:1) + * 15~1 : Custom + * 0 : override + */ + nid = 0x1d; + if (codec->core.vendor_id == 0x10ec0260) + nid = 0x17; + ass = snd_hda_codec_get_pincfg(codec, nid); + codec_dbg(codec, + "realtek: No valid SSID, checking pincfg 0x%08x for NID 0x%x\n", + ass, nid); + if (!(ass & 1)) + return 0; + if ((ass >> 30) != 1) /* no physical connection */ + return 0; + + /* check sum */ + tmp = 0; + for (i = 1; i < 16; i++) { + if ((ass >> i) & 1) + tmp++; + } + if (((ass >> 16) & 0xf) != tmp) + return 0; +do_sku: + codec_dbg(codec, "realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n", + ass & 0xffff, codec->core.vendor_id); + /* + * 0 : override + * 1 : Swap Jack + * 2 : 0 --> Desktop, 1 --> Laptop + * 3~5 : External Amplifier control + * 7~6 : Reserved + */ + tmp = (ass & 0x38) >> 3; /* external Amp control */ + if (spec->init_amp == ALC_INIT_UNDEFINED) { + switch (tmp) { + case 1: + alc_setup_gpio(codec, 0x01); + break; + case 3: + alc_setup_gpio(codec, 0x02); + break; + case 7: + alc_setup_gpio(codec, 0x04); + break; + case 5: + default: + spec->init_amp = ALC_INIT_DEFAULT; + break; + } + } + + /* is laptop or Desktop and enable the function "Mute internal speaker + * when the external headphone out jack is plugged" + */ + if (!(ass & 0x8000)) + return 1; + /* + * 10~8 : Jack location + * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered + * 14~13: Resvered + * 15 : 1 --> enable the function "Mute internal speaker + * when the external headphone out jack is plugged" + */ + if (!alc_get_hp_pin(spec)) { + hda_nid_t nid; + tmp = (ass >> 11) & 0x3; /* HP to chassis */ + nid = ports[tmp]; + if (found_in_nid_list(nid, spec->gen.autocfg.line_out_pins, + spec->gen.autocfg.line_outs)) + return 1; + spec->gen.autocfg.hp_pins[0] = nid; + } + return 1; +} +EXPORT_SYMBOL_NS_GPL(alc_subsystem_id, "SND_HDA_CODEC_REALTEK"); + +/* Check the validity of ALC subsystem-id + * ports contains an array of 4 pin NIDs for port-A, E, D and I */ +void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports) +{ + if (!alc_subsystem_id(codec, ports)) { + struct alc_spec *spec = codec->spec; + if (spec->init_amp == ALC_INIT_UNDEFINED) { + codec_dbg(codec, + "realtek: Enable default setup for auto mode as fallback\n"); + spec->init_amp = ALC_INIT_DEFAULT; + } + } +} +EXPORT_SYMBOL_NS_GPL(alc_ssid_check, "SND_HDA_CODEC_REALTEK"); + +/* inverted digital-mic */ +void alc_fixup_inv_dmic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + spec->gen.inv_dmic_split = 1; +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_inv_dmic, "SND_HDA_CODEC_REALTEK"); + +int alc_build_controls(struct hda_codec *codec) +{ + int err; + + err = snd_hda_gen_build_controls(codec); + if (err < 0) + return err; + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD); + return 0; +} +EXPORT_SYMBOL_NS_GPL(alc_build_controls, "SND_HDA_CODEC_REALTEK"); + +int alc_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + /* hibernation resume needs the full chip initialization */ + if (is_s4_resume(codec)) + alc_pre_init(codec); + + if (spec->init_hook) + spec->init_hook(codec); + + spec->gen.skip_verbs = 1; /* applied in below */ + snd_hda_gen_init(codec); + alc_fix_pll(codec); + alc_auto_init_amp(codec, spec->init_amp); + snd_hda_apply_verbs(codec); /* apply verbs here after own init */ + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(alc_init, "SND_HDA_CODEC_REALTEK"); + +void alc_shutup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (!snd_hda_get_bool_hint(codec, "shutup")) + return; /* disabled explicitly by hints */ + + if (spec && spec->shutup) + spec->shutup(codec); + else + alc_shutup_pins(codec); +} +EXPORT_SYMBOL_NS_GPL(alc_shutup, "SND_HDA_CODEC_REALTEK"); + +void alc_power_eapd(struct hda_codec *codec) +{ + alc_auto_setup_eapd(codec, false); +} +EXPORT_SYMBOL_NS_GPL(alc_power_eapd, "SND_HDA_CODEC_REALTEK"); + +int alc_suspend(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc_shutup(codec); + if (spec && spec->power_hook) + spec->power_hook(codec); + return 0; +} +EXPORT_SYMBOL_NS_GPL(alc_suspend, "SND_HDA_CODEC_REALTEK"); + +int alc_resume(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (!spec->no_depop_delay) + msleep(150); /* to avoid pop noise */ + codec->patch_ops.init(codec); + snd_hda_regmap_sync(codec); + hda_call_check_power_status(codec, 0x01); + return 0; +} +EXPORT_SYMBOL_NS_GPL(alc_resume, "SND_HDA_CODEC_REALTEK"); + +/* + */ +const struct hda_codec_ops alc_patch_ops = { + .build_controls = alc_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = alc_init, + .free = alc_free, + .unsol_event = snd_hda_jack_unsol_event, + .resume = alc_resume, + .suspend = alc_suspend, + .check_power_status = snd_hda_gen_check_power_status, +}; +EXPORT_SYMBOL_NS_GPL(alc_patch_ops, "SND_HDA_CODEC_REALTEK"); + +/* + * Rename codecs appropriately from COEF value or subvendor id + */ +struct alc_codec_rename_table { + unsigned int vendor_id; + unsigned short coef_mask; + unsigned short coef_bits; + const char *name; +}; + +struct alc_codec_rename_pci_table { + unsigned int codec_vendor_id; + unsigned short pci_subvendor; + unsigned short pci_subdevice; + const char *name; +}; + +static const struct alc_codec_rename_table rename_tbl[] = { + { 0x10ec0221, 0xf00f, 0x1003, "ALC231" }, + { 0x10ec0269, 0xfff0, 0x3010, "ALC277" }, + { 0x10ec0269, 0xf0f0, 0x2010, "ALC259" }, + { 0x10ec0269, 0xf0f0, 0x3010, "ALC258" }, + { 0x10ec0269, 0x00f0, 0x0010, "ALC269VB" }, + { 0x10ec0269, 0xffff, 0xa023, "ALC259" }, + { 0x10ec0269, 0xffff, 0x6023, "ALC281X" }, + { 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" }, + { 0x10ec0269, 0x00f0, 0x0030, "ALC269VD" }, + { 0x10ec0662, 0xffff, 0x4020, "ALC656" }, + { 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" }, + { 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" }, + { 0x10ec0888, 0xf0f0, 0x3020, "ALC886" }, + { 0x10ec0899, 0x2000, 0x2000, "ALC899" }, + { 0x10ec0892, 0xffff, 0x8020, "ALC661" }, + { 0x10ec0892, 0xffff, 0x8011, "ALC661" }, + { 0x10ec0892, 0xffff, 0x4011, "ALC656" }, + { } /* terminator */ +}; + +static const struct alc_codec_rename_pci_table rename_pci_tbl[] = { + { 0x10ec0280, 0x1028, 0, "ALC3220" }, + { 0x10ec0282, 0x1028, 0, "ALC3221" }, + { 0x10ec0283, 0x1028, 0, "ALC3223" }, + { 0x10ec0288, 0x1028, 0, "ALC3263" }, + { 0x10ec0292, 0x1028, 0, "ALC3226" }, + { 0x10ec0293, 0x1028, 0, "ALC3235" }, + { 0x10ec0255, 0x1028, 0, "ALC3234" }, + { 0x10ec0668, 0x1028, 0, "ALC3661" }, + { 0x10ec0275, 0x1028, 0, "ALC3260" }, + { 0x10ec0899, 0x1028, 0, "ALC3861" }, + { 0x10ec0298, 0x1028, 0, "ALC3266" }, + { 0x10ec0236, 0x1028, 0, "ALC3204" }, + { 0x10ec0256, 0x1028, 0, "ALC3246" }, + { 0x10ec0225, 0x1028, 0, "ALC3253" }, + { 0x10ec0295, 0x1028, 0, "ALC3254" }, + { 0x10ec0299, 0x1028, 0, "ALC3271" }, + { 0x10ec0670, 0x1025, 0, "ALC669X" }, + { 0x10ec0676, 0x1025, 0, "ALC679X" }, + { 0x10ec0282, 0x1043, 0, "ALC3229" }, + { 0x10ec0233, 0x1043, 0, "ALC3236" }, + { 0x10ec0280, 0x103c, 0, "ALC3228" }, + { 0x10ec0282, 0x103c, 0, "ALC3227" }, + { 0x10ec0286, 0x103c, 0, "ALC3242" }, + { 0x10ec0290, 0x103c, 0, "ALC3241" }, + { 0x10ec0668, 0x103c, 0, "ALC3662" }, + { 0x10ec0283, 0x17aa, 0, "ALC3239" }, + { 0x10ec0292, 0x17aa, 0, "ALC3232" }, + { 0x10ec0257, 0x12f0, 0, "ALC3328" }, + { } /* terminator */ +}; + +static int alc_codec_rename_from_preset(struct hda_codec *codec) +{ + const struct alc_codec_rename_table *p; + const struct alc_codec_rename_pci_table *q; + + for (p = rename_tbl; p->vendor_id; p++) { + if (p->vendor_id != codec->core.vendor_id) + continue; + if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits) + return alc_codec_rename(codec, p->name); + } + + if (!codec->bus->pci) + return 0; + for (q = rename_pci_tbl; q->codec_vendor_id; q++) { + if (q->codec_vendor_id != codec->core.vendor_id) + continue; + if (q->pci_subvendor != codec->bus->pci->subsystem_vendor) + continue; + if (!q->pci_subdevice || + q->pci_subdevice == codec->bus->pci->subsystem_device) + return alc_codec_rename(codec, q->name); + } + + return 0; +} + +/* + * Digital-beep handlers + */ +#ifdef CONFIG_SND_HDA_INPUT_BEEP + +/* additional beep mixers; private_value will be overwritten */ +static const struct snd_kcontrol_new alc_beep_mixer[] = { + HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT), + HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT), +}; + +/* set up and create beep controls */ +int alc_set_beep_amp(struct alc_spec *spec, hda_nid_t nid, int idx, int dir) +{ + struct snd_kcontrol_new *knew; + unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir); + int i; + + for (i = 0; i < ARRAY_SIZE(alc_beep_mixer); i++) { + knew = snd_hda_gen_add_kctl(&spec->gen, NULL, + &alc_beep_mixer[i]); + if (!knew) + return -ENOMEM; + knew->private_value = beep_amp; + } + return 0; +} +EXPORT_SYMBOL_NS_GPL(alc_set_beep_amp, "SND_HDA_CODEC_REALTEK"); + +static const struct snd_pci_quirk beep_allow_list[] = { + SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1), + SND_PCI_QUIRK(0x1043, 0x115d, "ASUS", 1), + SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), + SND_PCI_QUIRK(0x1043, 0x8376, "EeePC", 1), + SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1), + SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1), + SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1), + SND_PCI_QUIRK(0x1458, 0xa002, "GA-MA790X", 1), + SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1), + /* denylist -- no beep available */ + SND_PCI_QUIRK(0x17aa, 0x309e, "Lenovo ThinkCentre M73", 0), + SND_PCI_QUIRK(0x17aa, 0x30a3, "Lenovo ThinkCentre M93", 0), + {} +}; + +int alc_has_cdefine_beep(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + const struct snd_pci_quirk *q; + q = snd_pci_quirk_lookup(codec->bus->pci, beep_allow_list); + if (q) + return q->value; + return spec->cdefine.enable_pcbeep; +} +EXPORT_SYMBOL_NS_GPL(alc_has_cdefine_beep, "SND_HDA_CODEC_REALTEK"); + +#endif /* CONFIG_SND_HDA_INPUT_BEEP */ + +/* parse the BIOS configuration and set up the alc_spec */ +/* return 1 if successful, 0 if the proper config is not found, + * or a negative error code + */ +int alc_parse_auto_config(struct hda_codec *codec, + const hda_nid_t *ignore_nids, + const hda_nid_t *ssid_nids) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + int err; + + err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids, + spec->parse_flags); + if (err < 0) + return err; + + if (ssid_nids) + alc_ssid_check(codec, ssid_nids); + + err = snd_hda_gen_parse_auto_config(codec, cfg); + if (err < 0) + return err; + + return 1; +} +EXPORT_SYMBOL_NS_GPL(alc_parse_auto_config, "SND_HDA_CODEC_REALTEK"); + +/* common preparation job for alc_spec */ +int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid) +{ + struct alc_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL); + int err; + + if (!spec) + return -ENOMEM; + codec->spec = spec; + snd_hda_gen_spec_init(&spec->gen); + spec->gen.mixer_nid = mixer_nid; + spec->gen.own_eapd_ctl = 1; + codec->single_adc_amp = 1; + /* FIXME: do we need this for all Realtek codec models? */ + codec->spdif_status_reset = 1; + codec->forced_resume = 1; + codec->patch_ops = alc_patch_ops; + mutex_init(&spec->coef_mutex); + + err = alc_codec_rename_from_preset(codec); + if (err < 0) { + kfree(spec); + return err; + } + return 0; +} +EXPORT_SYMBOL_NS_GPL(alc_alloc_spec, "SND_HDA_CODEC_REALTEK"); + +/* For dual-codec configuration, we need to disable some features to avoid + * conflicts of kctls and PCM streams + */ +void alc_fixup_dual_codecs(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + /* disable vmaster */ + spec->gen.suppress_vmaster = 1; + /* auto-mute and auto-mic switch don't work with multiple codecs */ + spec->gen.suppress_auto_mute = 1; + spec->gen.suppress_auto_mic = 1; + /* disable aamix as well */ + spec->gen.mixer_nid = 0; + /* add location prefix to avoid conflicts */ + codec->force_pin_prefix = 1; +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_dual_codecs, "SND_HDA_CODEC_REALTEK"); + +static const struct snd_pcm_chmap_elem asus_pcm_2_1_chmaps[] = { + { .channels = 2, + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, + { .channels = 4, + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, + SNDRV_CHMAP_NA, SNDRV_CHMAP_LFE } }, /* LFE only on right */ + { } +}; + +/* override the 2.1 chmap */ +void alc_fixup_bass_chmap(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_BUILD) { + struct alc_spec *spec = codec->spec; + spec->gen.pcm_rec[0]->stream[0].chmap = asus_pcm_2_1_chmaps; + } +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_bass_chmap, "SND_HDA_CODEC_REALTEK"); + +/* exported as it's used by multiple codecs */ +void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + alc_fixup_dual_codecs(codec, fix, action); + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + /* override card longname to provide a unique UCM profile */ + strcpy(codec->card->longname, "HDAudio-Gigabyte-ALC1220DualCodecs"); + break; + case HDA_FIXUP_ACT_BUILD: + /* rename Capture controls depending on the codec */ + rename_ctl(codec, "Capture Volume", + codec->addr == 0 ? + "Rear-Panel Capture Volume" : + "Front-Panel Capture Volume"); + rename_ctl(codec, "Capture Switch", + codec->addr == 0 ? + "Rear-Panel Capture Switch" : + "Front-Panel Capture Switch"); + break; + } +} +EXPORT_SYMBOL_NS_GPL(alc1220_fixup_gb_dual_codecs, "SND_HDA_CODEC_REALTEK"); + +void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + alc_fixup_dual_codecs(codec, fix, action); + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + /* override card longname to provide a unique UCM profile */ + strcpy(codec->card->longname, "HDAudio-Lenovo-DualCodecs"); + break; + case HDA_FIXUP_ACT_BUILD: + /* rename Capture controls depending on the codec */ + rename_ctl(codec, "Capture Volume", + codec->addr == 0 ? + "Rear-Panel Capture Volume" : + "Front-Panel Capture Volume"); + rename_ctl(codec, "Capture Switch", + codec->addr == 0 ? + "Rear-Panel Capture Switch" : + "Front-Panel Capture Switch"); + break; + } +} +EXPORT_SYMBOL_NS_GPL(alc233_alc662_fixup_lenovo_dual_codecs, "SND_HDA_CODEC_REALTEK"); + +static void alc_shutup_dell_xps13(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int hp_pin = alc_get_hp_pin(spec); + + /* Prevent pop noises when headphones are plugged in */ + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + msleep(20); +} + +void alc_fixup_dell_xps13(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->gen.input_mux; + int i; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + /* mic pin 0x19 must be initialized with Vref Hi-Z, otherwise + * it causes a click noise at start up + */ + snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ); + spec->shutup = alc_shutup_dell_xps13; + break; + case HDA_FIXUP_ACT_PROBE: + /* Make the internal mic the default input source. */ + for (i = 0; i < imux->num_items; i++) { + if (spec->gen.imux_pins[i] == 0x12) { + spec->gen.cur_mux[0] = i; + break; + } + } + break; + } +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_dell_xps13, "SND_HDA_CODEC_REALTEK"); + +/* + * headset handling + */ + +static void alc_hp_mute_disable(struct hda_codec *codec, unsigned int delay) +{ + if (delay <= 0) + delay = 75; + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + msleep(delay); + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + msleep(delay); +} + +static void alc_hp_enable_unmute(struct hda_codec *codec, unsigned int delay) +{ + if (delay <= 0) + delay = 75; + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + msleep(delay); + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + msleep(delay); +} + +static const struct coef_fw alc225_pre_hsmode[] = { + UPDATE_COEF(0x4a, 1<<8, 0), + UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), + UPDATE_COEF(0x63, 3<<14, 3<<14), + UPDATE_COEF(0x4a, 3<<4, 2<<4), + UPDATE_COEF(0x4a, 3<<10, 3<<10), + UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10), + UPDATE_COEF(0x4a, 3<<10, 0), + {} +}; + +static void alc_headset_mode_unplugged(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + static const struct coef_fw coef0255[] = { + WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */ + WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */ + UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/ + WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */ + WRITE_COEFEX(0x57, 0x03, 0x8aa6), /* Direct Drive HP Amp control */ + {} + }; + static const struct coef_fw coef0256[] = { + WRITE_COEF(0x1b, 0x0c4b), /* LDO and MISC control */ + WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */ + WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */ + WRITE_COEFEX(0x57, 0x03, 0x09a3), /* Direct Drive HP Amp control */ + UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/ + {} + }; + static const struct coef_fw coef0233[] = { + WRITE_COEF(0x1b, 0x0c0b), + WRITE_COEF(0x45, 0xc429), + UPDATE_COEF(0x35, 0x4000, 0), + WRITE_COEF(0x06, 0x2104), + WRITE_COEF(0x1a, 0x0001), + WRITE_COEF(0x26, 0x0004), + WRITE_COEF(0x32, 0x42a3), + {} + }; + static const struct coef_fw coef0288[] = { + UPDATE_COEF(0x4f, 0xfcc0, 0xc400), + UPDATE_COEF(0x50, 0x2000, 0x2000), + UPDATE_COEF(0x56, 0x0006, 0x0006), + UPDATE_COEF(0x66, 0x0008, 0), + UPDATE_COEF(0x67, 0x2000, 0), + {} + }; + static const struct coef_fw coef0298[] = { + UPDATE_COEF(0x19, 0x1300, 0x0300), + {} + }; + static const struct coef_fw coef0292[] = { + WRITE_COEF(0x76, 0x000e), + WRITE_COEF(0x6c, 0x2400), + WRITE_COEF(0x18, 0x7308), + WRITE_COEF(0x6b, 0xc429), + {} + }; + static const struct coef_fw coef0293[] = { + UPDATE_COEF(0x10, 7<<8, 6<<8), /* SET Line1 JD to 0 */ + UPDATE_COEFEX(0x57, 0x05, 1<<15|1<<13, 0x0), /* SET charge pump by verb */ + UPDATE_COEFEX(0x57, 0x03, 1<<10, 1<<10), /* SET EN_OSW to 1 */ + UPDATE_COEF(0x1a, 1<<3, 1<<3), /* Combo JD gating with LINE1-VREFO */ + WRITE_COEF(0x45, 0xc429), /* Set to TRS type */ + UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */ + {} + }; + static const struct coef_fw coef0668[] = { + WRITE_COEF(0x15, 0x0d40), + WRITE_COEF(0xb7, 0x802b), + {} + }; + static const struct coef_fw coef0225[] = { + UPDATE_COEF(0x63, 3<<14, 0), + {} + }; + static const struct coef_fw coef0274[] = { + UPDATE_COEF(0x4a, 0x0100, 0), + UPDATE_COEFEX(0x57, 0x05, 0x4000, 0), + UPDATE_COEF(0x6b, 0xf000, 0x5000), + UPDATE_COEF(0x4a, 0x0010, 0), + UPDATE_COEF(0x4a, 0x0c00, 0x0c00), + WRITE_COEF(0x45, 0x5289), + UPDATE_COEF(0x4a, 0x0c00, 0), + {} + }; + + if (spec->no_internal_mic_pin) { + alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12); + return; + } + + switch (codec->core.vendor_id) { + case 0x10ec0255: + alc_process_coef_fw(codec, coef0255); + break; + case 0x10ec0230: + case 0x10ec0236: + case 0x10ec0256: + case 0x19e58326: + alc_hp_mute_disable(codec, 75); + alc_process_coef_fw(codec, coef0256); + break; + case 0x10ec0234: + case 0x10ec0274: + case 0x10ec0294: + alc_process_coef_fw(codec, coef0274); + break; + case 0x10ec0233: + case 0x10ec0283: + alc_process_coef_fw(codec, coef0233); + break; + case 0x10ec0286: + case 0x10ec0288: + alc_process_coef_fw(codec, coef0288); + break; + case 0x10ec0298: + alc_process_coef_fw(codec, coef0298); + alc_process_coef_fw(codec, coef0288); + break; + case 0x10ec0292: + alc_process_coef_fw(codec, coef0292); + break; + case 0x10ec0293: + alc_process_coef_fw(codec, coef0293); + break; + case 0x10ec0668: + alc_process_coef_fw(codec, coef0668); + break; + case 0x10ec0215: + case 0x10ec0225: + case 0x10ec0285: + case 0x10ec0295: + case 0x10ec0289: + case 0x10ec0299: + alc_hp_mute_disable(codec, 75); + alc_process_coef_fw(codec, alc225_pre_hsmode); + alc_process_coef_fw(codec, coef0225); + break; + case 0x10ec0867: + alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0); + break; + } + codec_dbg(codec, "Headset jack set to unplugged mode.\n"); +} + + +static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, + hda_nid_t mic_pin) +{ + static const struct coef_fw coef0255[] = { + WRITE_COEFEX(0x57, 0x03, 0x8aa6), + WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */ + {} + }; + static const struct coef_fw coef0256[] = { + UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14), /* Direct Drive HP Amp control(Set to verb control)*/ + WRITE_COEFEX(0x57, 0x03, 0x09a3), + WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */ + {} + }; + static const struct coef_fw coef0233[] = { + UPDATE_COEF(0x35, 0, 1<<14), + WRITE_COEF(0x06, 0x2100), + WRITE_COEF(0x1a, 0x0021), + WRITE_COEF(0x26, 0x008c), + {} + }; + static const struct coef_fw coef0288[] = { + UPDATE_COEF(0x4f, 0x00c0, 0), + UPDATE_COEF(0x50, 0x2000, 0), + UPDATE_COEF(0x56, 0x0006, 0), + UPDATE_COEF(0x4f, 0xfcc0, 0xc400), + UPDATE_COEF(0x66, 0x0008, 0x0008), + UPDATE_COEF(0x67, 0x2000, 0x2000), + {} + }; + static const struct coef_fw coef0292[] = { + WRITE_COEF(0x19, 0xa208), + WRITE_COEF(0x2e, 0xacf0), + {} + }; + static const struct coef_fw coef0293[] = { + UPDATE_COEFEX(0x57, 0x05, 0, 1<<15|1<<13), /* SET charge pump by verb */ + UPDATE_COEFEX(0x57, 0x03, 1<<10, 0), /* SET EN_OSW to 0 */ + UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */ + {} + }; + static const struct coef_fw coef0688[] = { + WRITE_COEF(0xb7, 0x802b), + WRITE_COEF(0xb5, 0x1040), + UPDATE_COEF(0xc3, 0, 1<<12), + {} + }; + static const struct coef_fw coef0225[] = { + UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14), + UPDATE_COEF(0x4a, 3<<4, 2<<4), + UPDATE_COEF(0x63, 3<<14, 0), + {} + }; + static const struct coef_fw coef0274[] = { + UPDATE_COEFEX(0x57, 0x05, 0x4000, 0x4000), + UPDATE_COEF(0x4a, 0x0010, 0), + UPDATE_COEF(0x6b, 0xf000, 0), + {} + }; + + switch (codec->core.vendor_id) { + case 0x10ec0255: + alc_write_coef_idx(codec, 0x45, 0xc489); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + alc_process_coef_fw(codec, coef0255); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; + case 0x10ec0230: + case 0x10ec0236: + case 0x10ec0256: + case 0x19e58326: + alc_write_coef_idx(codec, 0x45, 0xc489); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + alc_process_coef_fw(codec, coef0256); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; + case 0x10ec0234: + case 0x10ec0274: + case 0x10ec0294: + alc_write_coef_idx(codec, 0x45, 0x4689); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + alc_process_coef_fw(codec, coef0274); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; + case 0x10ec0233: + case 0x10ec0283: + alc_write_coef_idx(codec, 0x45, 0xc429); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + alc_process_coef_fw(codec, coef0233); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; + case 0x10ec0286: + case 0x10ec0288: + case 0x10ec0298: + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + alc_process_coef_fw(codec, coef0288); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; + case 0x10ec0292: + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + alc_process_coef_fw(codec, coef0292); + break; + case 0x10ec0293: + /* Set to TRS mode */ + alc_write_coef_idx(codec, 0x45, 0xc429); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + alc_process_coef_fw(codec, coef0293); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; + case 0x10ec0867: + alc_update_coefex_idx(codec, 0x57, 0x5, 0, 1<<14); + fallthrough; + case 0x10ec0221: + case 0x10ec0662: + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; + case 0x10ec0668: + alc_write_coef_idx(codec, 0x11, 0x0001); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + alc_process_coef_fw(codec, coef0688); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; + case 0x10ec0215: + case 0x10ec0225: + case 0x10ec0285: + case 0x10ec0295: + case 0x10ec0289: + case 0x10ec0299: + alc_process_coef_fw(codec, alc225_pre_hsmode); + alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + alc_process_coef_fw(codec, coef0225); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; + } + codec_dbg(codec, "Headset jack set to mic-in mode.\n"); +} + +static void alc_headset_mode_default(struct hda_codec *codec) +{ + static const struct coef_fw coef0225[] = { + UPDATE_COEF(0x45, 0x3f<<10, 0x30<<10), + UPDATE_COEF(0x45, 0x3f<<10, 0x31<<10), + UPDATE_COEF(0x49, 3<<8, 0<<8), + UPDATE_COEF(0x4a, 3<<4, 3<<4), + UPDATE_COEF(0x63, 3<<14, 0), + UPDATE_COEF(0x67, 0xf000, 0x3000), + {} + }; + static const struct coef_fw coef0255[] = { + WRITE_COEF(0x45, 0xc089), + WRITE_COEF(0x45, 0xc489), + WRITE_COEFEX(0x57, 0x03, 0x8ea6), + WRITE_COEF(0x49, 0x0049), + {} + }; + static const struct coef_fw coef0256[] = { + WRITE_COEF(0x45, 0xc489), + WRITE_COEFEX(0x57, 0x03, 0x0da3), + WRITE_COEF(0x49, 0x0049), + UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/ + WRITE_COEF(0x06, 0x6100), + {} + }; + static const struct coef_fw coef0233[] = { + WRITE_COEF(0x06, 0x2100), + WRITE_COEF(0x32, 0x4ea3), + {} + }; + static const struct coef_fw coef0288[] = { + UPDATE_COEF(0x4f, 0xfcc0, 0xc400), /* Set to TRS type */ + UPDATE_COEF(0x50, 0x2000, 0x2000), + UPDATE_COEF(0x56, 0x0006, 0x0006), + UPDATE_COEF(0x66, 0x0008, 0), + UPDATE_COEF(0x67, 0x2000, 0), + {} + }; + static const struct coef_fw coef0292[] = { + WRITE_COEF(0x76, 0x000e), + WRITE_COEF(0x6c, 0x2400), + WRITE_COEF(0x6b, 0xc429), + WRITE_COEF(0x18, 0x7308), + {} + }; + static const struct coef_fw coef0293[] = { + UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */ + WRITE_COEF(0x45, 0xC429), /* Set to TRS type */ + UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */ + {} + }; + static const struct coef_fw coef0688[] = { + WRITE_COEF(0x11, 0x0041), + WRITE_COEF(0x15, 0x0d40), + WRITE_COEF(0xb7, 0x802b), + {} + }; + static const struct coef_fw coef0274[] = { + WRITE_COEF(0x45, 0x4289), + UPDATE_COEF(0x4a, 0x0010, 0x0010), + UPDATE_COEF(0x6b, 0x0f00, 0), + UPDATE_COEF(0x49, 0x0300, 0x0300), + {} + }; + + switch (codec->core.vendor_id) { + case 0x10ec0215: + case 0x10ec0225: + case 0x10ec0285: + case 0x10ec0295: + case 0x10ec0289: + case 0x10ec0299: + alc_process_coef_fw(codec, alc225_pre_hsmode); + alc_process_coef_fw(codec, coef0225); + alc_hp_enable_unmute(codec, 75); + break; + case 0x10ec0255: + alc_process_coef_fw(codec, coef0255); + break; + case 0x10ec0230: + case 0x10ec0236: + case 0x10ec0256: + case 0x19e58326: + alc_write_coef_idx(codec, 0x1b, 0x0e4b); + alc_write_coef_idx(codec, 0x45, 0xc089); + msleep(50); + alc_process_coef_fw(codec, coef0256); + alc_hp_enable_unmute(codec, 75); + break; + case 0x10ec0234: + case 0x10ec0274: + case 0x10ec0294: + alc_process_coef_fw(codec, coef0274); + break; + case 0x10ec0233: + case 0x10ec0283: + alc_process_coef_fw(codec, coef0233); + break; + case 0x10ec0286: + case 0x10ec0288: + case 0x10ec0298: + alc_process_coef_fw(codec, coef0288); + break; + case 0x10ec0292: + alc_process_coef_fw(codec, coef0292); + break; + case 0x10ec0293: + alc_process_coef_fw(codec, coef0293); + break; + case 0x10ec0668: + alc_process_coef_fw(codec, coef0688); + break; + case 0x10ec0867: + alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0); + break; + } + codec_dbg(codec, "Headset jack set to headphone (default) mode.\n"); +} + +/* Iphone type */ +static void alc_headset_mode_ctia(struct hda_codec *codec) +{ + int val; + + static const struct coef_fw coef0255[] = { + WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */ + WRITE_COEF(0x1b, 0x0c2b), + WRITE_COEFEX(0x57, 0x03, 0x8ea6), + {} + }; + static const struct coef_fw coef0256[] = { + WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */ + WRITE_COEF(0x1b, 0x0e6b), + {} + }; + static const struct coef_fw coef0233[] = { + WRITE_COEF(0x45, 0xd429), + WRITE_COEF(0x1b, 0x0c2b), + WRITE_COEF(0x32, 0x4ea3), + {} + }; + static const struct coef_fw coef0288[] = { + UPDATE_COEF(0x50, 0x2000, 0x2000), + UPDATE_COEF(0x56, 0x0006, 0x0006), + UPDATE_COEF(0x66, 0x0008, 0), + UPDATE_COEF(0x67, 0x2000, 0), + {} + }; + static const struct coef_fw coef0292[] = { + WRITE_COEF(0x6b, 0xd429), + WRITE_COEF(0x76, 0x0008), + WRITE_COEF(0x18, 0x7388), + {} + }; + static const struct coef_fw coef0293[] = { + WRITE_COEF(0x45, 0xd429), /* Set to ctia type */ + UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */ + {} + }; + static const struct coef_fw coef0688[] = { + WRITE_COEF(0x11, 0x0001), + WRITE_COEF(0x15, 0x0d60), + WRITE_COEF(0xc3, 0x0000), + {} + }; + static const struct coef_fw coef0225_1[] = { + UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10), + UPDATE_COEF(0x63, 3<<14, 2<<14), + {} + }; + static const struct coef_fw coef0225_2[] = { + UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10), + UPDATE_COEF(0x63, 3<<14, 1<<14), + {} + }; + + switch (codec->core.vendor_id) { + case 0x10ec0255: + alc_process_coef_fw(codec, coef0255); + break; + case 0x10ec0230: + case 0x10ec0236: + case 0x10ec0256: + case 0x19e58326: + alc_process_coef_fw(codec, coef0256); + alc_hp_enable_unmute(codec, 75); + break; + case 0x10ec0234: + case 0x10ec0274: + case 0x10ec0294: + alc_write_coef_idx(codec, 0x45, 0xd689); + break; + case 0x10ec0233: + case 0x10ec0283: + alc_process_coef_fw(codec, coef0233); + break; + case 0x10ec0298: + val = alc_read_coef_idx(codec, 0x50); + if (val & (1 << 12)) { + alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020); + alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400); + msleep(300); + } else { + alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010); + alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400); + msleep(300); + } + break; + case 0x10ec0286: + case 0x10ec0288: + alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400); + msleep(300); + alc_process_coef_fw(codec, coef0288); + break; + case 0x10ec0292: + alc_process_coef_fw(codec, coef0292); + break; + case 0x10ec0293: + alc_process_coef_fw(codec, coef0293); + break; + case 0x10ec0668: + alc_process_coef_fw(codec, coef0688); + break; + case 0x10ec0215: + case 0x10ec0225: + case 0x10ec0285: + case 0x10ec0295: + case 0x10ec0289: + case 0x10ec0299: + val = alc_read_coef_idx(codec, 0x45); + if (val & (1 << 9)) + alc_process_coef_fw(codec, coef0225_2); + else + alc_process_coef_fw(codec, coef0225_1); + alc_hp_enable_unmute(codec, 75); + break; + case 0x10ec0867: + alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0); + break; + } + codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n"); +} + +/* Nokia type */ +static void alc_headset_mode_omtp(struct hda_codec *codec) +{ + static const struct coef_fw coef0255[] = { + WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */ + WRITE_COEF(0x1b, 0x0c2b), + WRITE_COEFEX(0x57, 0x03, 0x8ea6), + {} + }; + static const struct coef_fw coef0256[] = { + WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */ + WRITE_COEF(0x1b, 0x0e6b), + {} + }; + static const struct coef_fw coef0233[] = { + WRITE_COEF(0x45, 0xe429), + WRITE_COEF(0x1b, 0x0c2b), + WRITE_COEF(0x32, 0x4ea3), + {} + }; + static const struct coef_fw coef0288[] = { + UPDATE_COEF(0x50, 0x2000, 0x2000), + UPDATE_COEF(0x56, 0x0006, 0x0006), + UPDATE_COEF(0x66, 0x0008, 0), + UPDATE_COEF(0x67, 0x2000, 0), + {} + }; + static const struct coef_fw coef0292[] = { + WRITE_COEF(0x6b, 0xe429), + WRITE_COEF(0x76, 0x0008), + WRITE_COEF(0x18, 0x7388), + {} + }; + static const struct coef_fw coef0293[] = { + WRITE_COEF(0x45, 0xe429), /* Set to omtp type */ + UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */ + {} + }; + static const struct coef_fw coef0688[] = { + WRITE_COEF(0x11, 0x0001), + WRITE_COEF(0x15, 0x0d50), + WRITE_COEF(0xc3, 0x0000), + {} + }; + static const struct coef_fw coef0225[] = { + UPDATE_COEF(0x45, 0x3f<<10, 0x39<<10), + UPDATE_COEF(0x63, 3<<14, 2<<14), + {} + }; + + switch (codec->core.vendor_id) { + case 0x10ec0255: + alc_process_coef_fw(codec, coef0255); + break; + case 0x10ec0230: + case 0x10ec0236: + case 0x10ec0256: + case 0x19e58326: + alc_process_coef_fw(codec, coef0256); + alc_hp_enable_unmute(codec, 75); + break; + case 0x10ec0234: + case 0x10ec0274: + case 0x10ec0294: + alc_write_coef_idx(codec, 0x45, 0xe689); + break; + case 0x10ec0233: + case 0x10ec0283: + alc_process_coef_fw(codec, coef0233); + break; + case 0x10ec0298: + alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);/* Headset output enable */ + alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400); + msleep(300); + break; + case 0x10ec0286: + case 0x10ec0288: + alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400); + msleep(300); + alc_process_coef_fw(codec, coef0288); + break; + case 0x10ec0292: + alc_process_coef_fw(codec, coef0292); + break; + case 0x10ec0293: + alc_process_coef_fw(codec, coef0293); + break; + case 0x10ec0668: + alc_process_coef_fw(codec, coef0688); + break; + case 0x10ec0215: + case 0x10ec0225: + case 0x10ec0285: + case 0x10ec0295: + case 0x10ec0289: + case 0x10ec0299: + alc_process_coef_fw(codec, coef0225); + alc_hp_enable_unmute(codec, 75); + break; + } + codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n"); +} + +static void alc_determine_headset_type(struct hda_codec *codec) +{ + int val; + bool is_ctia = false; + struct alc_spec *spec = codec->spec; + static const struct coef_fw coef0255[] = { + WRITE_COEF(0x45, 0xd089), /* combo jack auto switch control(Check type)*/ + WRITE_COEF(0x49, 0x0149), /* combo jack auto switch control(Vref + conteol) */ + {} + }; + static const struct coef_fw coef0288[] = { + UPDATE_COEF(0x4f, 0xfcc0, 0xd400), /* Check Type */ + {} + }; + static const struct coef_fw coef0298[] = { + UPDATE_COEF(0x50, 0x2000, 0x2000), + UPDATE_COEF(0x56, 0x0006, 0x0006), + UPDATE_COEF(0x66, 0x0008, 0), + UPDATE_COEF(0x67, 0x2000, 0), + UPDATE_COEF(0x19, 0x1300, 0x1300), + {} + }; + static const struct coef_fw coef0293[] = { + UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */ + WRITE_COEF(0x45, 0xD429), /* Set to ctia type */ + {} + }; + static const struct coef_fw coef0688[] = { + WRITE_COEF(0x11, 0x0001), + WRITE_COEF(0xb7, 0x802b), + WRITE_COEF(0x15, 0x0d60), + WRITE_COEF(0xc3, 0x0c00), + {} + }; + static const struct coef_fw coef0274[] = { + UPDATE_COEF(0x4a, 0x0010, 0), + UPDATE_COEF(0x4a, 0x8000, 0), + WRITE_COEF(0x45, 0xd289), + UPDATE_COEF(0x49, 0x0300, 0x0300), + {} + }; + + if (spec->no_internal_mic_pin) { + alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12); + return; + } + + switch (codec->core.vendor_id) { + case 0x10ec0255: + alc_process_coef_fw(codec, coef0255); + msleep(300); + val = alc_read_coef_idx(codec, 0x46); + is_ctia = (val & 0x0070) == 0x0070; + break; + case 0x10ec0230: + case 0x10ec0236: + case 0x10ec0256: + case 0x19e58326: + alc_write_coef_idx(codec, 0x1b, 0x0e4b); + alc_write_coef_idx(codec, 0x06, 0x6104); + alc_write_coefex_idx(codec, 0x57, 0x3, 0x09a3); + + alc_process_coef_fw(codec, coef0255); + msleep(300); + val = alc_read_coef_idx(codec, 0x46); + is_ctia = (val & 0x0070) == 0x0070; + if (!is_ctia) { + alc_write_coef_idx(codec, 0x45, 0xe089); + msleep(100); + val = alc_read_coef_idx(codec, 0x46); + if ((val & 0x0070) == 0x0070) + is_ctia = false; + else + is_ctia = true; + } + alc_write_coefex_idx(codec, 0x57, 0x3, 0x0da3); + alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0); + break; + case 0x10ec0234: + case 0x10ec0274: + case 0x10ec0294: + alc_process_coef_fw(codec, coef0274); + msleep(850); + val = alc_read_coef_idx(codec, 0x46); + is_ctia = (val & 0x00f0) == 0x00f0; + break; + case 0x10ec0233: + case 0x10ec0283: + alc_write_coef_idx(codec, 0x45, 0xd029); + msleep(300); + val = alc_read_coef_idx(codec, 0x46); + is_ctia = (val & 0x0070) == 0x0070; + break; + case 0x10ec0298: + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + msleep(100); + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + msleep(200); + + val = alc_read_coef_idx(codec, 0x50); + if (val & (1 << 12)) { + alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020); + alc_process_coef_fw(codec, coef0288); + msleep(350); + val = alc_read_coef_idx(codec, 0x50); + is_ctia = (val & 0x0070) == 0x0070; + } else { + alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010); + alc_process_coef_fw(codec, coef0288); + msleep(350); + val = alc_read_coef_idx(codec, 0x50); + is_ctia = (val & 0x0070) == 0x0070; + } + alc_process_coef_fw(codec, coef0298); + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); + msleep(75); + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + break; + case 0x10ec0286: + case 0x10ec0288: + alc_process_coef_fw(codec, coef0288); + msleep(350); + val = alc_read_coef_idx(codec, 0x50); + is_ctia = (val & 0x0070) == 0x0070; + break; + case 0x10ec0292: + alc_write_coef_idx(codec, 0x6b, 0xd429); + msleep(300); + val = alc_read_coef_idx(codec, 0x6c); + is_ctia = (val & 0x001c) == 0x001c; + break; + case 0x10ec0293: + alc_process_coef_fw(codec, coef0293); + msleep(300); + val = alc_read_coef_idx(codec, 0x46); + is_ctia = (val & 0x0070) == 0x0070; + break; + case 0x10ec0668: + alc_process_coef_fw(codec, coef0688); + msleep(300); + val = alc_read_coef_idx(codec, 0xbe); + is_ctia = (val & 0x1c02) == 0x1c02; + break; + case 0x10ec0215: + case 0x10ec0225: + case 0x10ec0285: + case 0x10ec0295: + case 0x10ec0289: + case 0x10ec0299: + alc_process_coef_fw(codec, alc225_pre_hsmode); + alc_update_coef_idx(codec, 0x67, 0xf000, 0x1000); + val = alc_read_coef_idx(codec, 0x45); + if (val & (1 << 9)) { + alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10); + alc_update_coef_idx(codec, 0x49, 3<<8, 2<<8); + msleep(800); + val = alc_read_coef_idx(codec, 0x46); + is_ctia = (val & 0x00f0) == 0x00f0; + } else { + alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10); + alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8); + msleep(800); + val = alc_read_coef_idx(codec, 0x46); + is_ctia = (val & 0x00f0) == 0x00f0; + } + if (!is_ctia) { + alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x38<<10); + alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8); + msleep(100); + val = alc_read_coef_idx(codec, 0x46); + if ((val & 0x00f0) == 0x00f0) + is_ctia = false; + else + is_ctia = true; + } + alc_update_coef_idx(codec, 0x4a, 7<<6, 7<<6); + alc_update_coef_idx(codec, 0x4a, 3<<4, 3<<4); + alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000); + break; + case 0x10ec0867: + is_ctia = true; + break; + } + + codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n", + str_yes_no(is_ctia)); + spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP; +} + +static void alc_update_headset_mode(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]]; + hda_nid_t hp_pin = alc_get_hp_pin(spec); + + int new_headset_mode; + + if (!snd_hda_jack_detect(codec, hp_pin)) + new_headset_mode = ALC_HEADSET_MODE_UNPLUGGED; + else if (mux_pin == spec->headset_mic_pin) + new_headset_mode = ALC_HEADSET_MODE_HEADSET; + else if (mux_pin == spec->headphone_mic_pin) + new_headset_mode = ALC_HEADSET_MODE_MIC; + else + new_headset_mode = ALC_HEADSET_MODE_HEADPHONE; + + if (new_headset_mode == spec->current_headset_mode) { + snd_hda_gen_update_outputs(codec); + return; + } + + switch (new_headset_mode) { + case ALC_HEADSET_MODE_UNPLUGGED: + alc_headset_mode_unplugged(codec); + spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN; + spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN; + spec->gen.hp_jack_present = false; + break; + case ALC_HEADSET_MODE_HEADSET: + if (spec->current_headset_type == ALC_HEADSET_TYPE_UNKNOWN) + alc_determine_headset_type(codec); + if (spec->current_headset_type == ALC_HEADSET_TYPE_CTIA) + alc_headset_mode_ctia(codec); + else if (spec->current_headset_type == ALC_HEADSET_TYPE_OMTP) + alc_headset_mode_omtp(codec); + spec->gen.hp_jack_present = true; + break; + case ALC_HEADSET_MODE_MIC: + alc_headset_mode_mic_in(codec, hp_pin, spec->headphone_mic_pin); + spec->gen.hp_jack_present = false; + break; + case ALC_HEADSET_MODE_HEADPHONE: + alc_headset_mode_default(codec); + spec->gen.hp_jack_present = true; + break; + } + if (new_headset_mode != ALC_HEADSET_MODE_MIC) { + snd_hda_set_pin_ctl_cache(codec, hp_pin, + AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); + if (spec->headphone_mic_pin && spec->headphone_mic_pin != hp_pin) + snd_hda_set_pin_ctl_cache(codec, spec->headphone_mic_pin, + PIN_VREFHIZ); + } + spec->current_headset_mode = new_headset_mode; + + snd_hda_gen_update_outputs(codec); +} + +static void alc_update_headset_mode_hook(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + alc_update_headset_mode(codec); +} + +void alc_update_headset_jack_cb(struct hda_codec *codec, + struct hda_jack_callback *jack) +{ + snd_hda_gen_hp_automute(codec, jack); + alc_update_headset_mode(codec); +} +EXPORT_SYMBOL_NS_GPL(alc_update_headset_jack_cb, "SND_HDA_CODEC_REALTEK"); + +static void alc_probe_headset_mode(struct hda_codec *codec) +{ + int i; + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + + /* Find mic pins */ + for (i = 0; i < cfg->num_inputs; i++) { + if (cfg->inputs[i].is_headset_mic && !spec->headset_mic_pin) + spec->headset_mic_pin = cfg->inputs[i].pin; + if (cfg->inputs[i].is_headphone_mic && !spec->headphone_mic_pin) + spec->headphone_mic_pin = cfg->inputs[i].pin; + } + + WARN_ON(spec->gen.cap_sync_hook); + spec->gen.cap_sync_hook = alc_update_headset_mode_hook; + spec->gen.automute_hook = alc_update_headset_mode; + spec->gen.hp_automute_hook = alc_update_headset_jack_cb; +} + +void alc_fixup_headset_mode(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC | HDA_PINCFG_HEADPHONE_MIC; + break; + case HDA_FIXUP_ACT_PROBE: + alc_probe_headset_mode(codec); + break; + case HDA_FIXUP_ACT_INIT: + if (is_s3_resume(codec) || is_s4_resume(codec)) { + spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN; + spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN; + } + alc_update_headset_mode(codec); + break; + } +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_headset_mode, "SND_HDA_CODEC_REALTEK"); + +void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + struct alc_spec *spec = codec->spec; + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + } + else + alc_fixup_headset_mode(codec, fix, action); +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_headset_mode_no_hp_mic, "SND_HDA_CODEC_REALTEK"); + +void alc_fixup_headset_mic(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->parse_flags |= HDA_PINCFG_HEADSET_MIC; +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_headset_mic, "SND_HDA_CODEC_REALTEK"); + +/* update LED status via GPIO */ +void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask, + int polarity, bool enabled) +{ + if (polarity) + enabled = !enabled; + alc_update_gpio_data(codec, mask, !enabled); /* muted -> LED on */ +} +EXPORT_SYMBOL_NS_GPL(alc_update_gpio_led, "SND_HDA_CODEC_REALTEK"); + +/* turn on/off mic-mute LED via GPIO per capture hook */ +static int micmute_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent); + struct alc_spec *spec = codec->spec; + + alc_update_gpio_led(codec, spec->gpio_mic_led_mask, + spec->micmute_led_polarity, !brightness); + return 0; +} + +/* turn on/off mute LED via GPIO per vmaster hook */ +static int gpio_mute_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent); + struct alc_spec *spec = codec->spec; + + alc_update_gpio_led(codec, spec->gpio_mute_led_mask, + spec->mute_led_polarity, !brightness); + return 0; +} + +/* setup mute and mic-mute GPIO bits, add hooks appropriately */ +void alc_fixup_hp_gpio_led(struct hda_codec *codec, + int action, + unsigned int mute_mask, + unsigned int micmute_mask) +{ + struct alc_spec *spec = codec->spec; + + alc_fixup_gpio(codec, action, mute_mask | micmute_mask); + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + if (mute_mask) { + spec->gpio_mute_led_mask = mute_mask; + snd_hda_gen_add_mute_led_cdev(codec, gpio_mute_led_set); + } + if (micmute_mask) { + spec->gpio_mic_led_mask = micmute_mask; + snd_hda_gen_add_micmute_led_cdev(codec, micmute_led_set); + } +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_hp_gpio_led, "SND_HDA_CODEC_REALTEK"); + +/* suppress the jack-detection */ +void alc_fixup_no_jack_detect(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) + codec->no_jack_detect = 1; +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_no_jack_detect, "SND_HDA_CODEC_REALTEK"); + +void alc_fixup_disable_aamix(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + struct alc_spec *spec = codec->spec; + /* Disable AA-loopback as it causes white noise */ + spec->gen.mixer_nid = 0; + } +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_disable_aamix, "SND_HDA_CODEC_REALTEK"); + +void alc_fixup_auto_mute_via_amp(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + struct alc_spec *spec = codec->spec; + spec->gen.auto_mute_via_amp = 1; + } +} +EXPORT_SYMBOL_NS_GPL(alc_fixup_auto_mute_via_amp, "SND_HDA_CODEC_REALTEK"); + +MODULE_IMPORT_NS("SND_HDA_SCODEC_COMPONENT"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek HD-audio codec helper"); diff --git a/sound/hda/codecs/realtek/realtek.h b/sound/hda/codecs/realtek/realtek.h new file mode 100644 index 000000000000..ac142f2540e3 --- /dev/null +++ b/sound/hda/codecs/realtek/realtek.h @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Realtek HD-audio codec support code +// + +#ifndef __HDA_REALTEK_H +#define __HDA_REALTEK_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hda_local.h" +#include "hda_auto_parser.h" +#include "hda_beep.h" +#include "hda_jack.h" +#include "../generic.h" +#include "../side-codecs/hda_component.h" + +/* extra amp-initialization sequence types */ +enum { + ALC_INIT_UNDEFINED, + ALC_INIT_NONE, + ALC_INIT_DEFAULT, +}; + +enum { + ALC_HEADSET_MODE_UNKNOWN, + ALC_HEADSET_MODE_UNPLUGGED, + ALC_HEADSET_MODE_HEADSET, + ALC_HEADSET_MODE_MIC, + ALC_HEADSET_MODE_HEADPHONE, +}; + +enum { + ALC_HEADSET_TYPE_UNKNOWN, + ALC_HEADSET_TYPE_CTIA, + ALC_HEADSET_TYPE_OMTP, +}; + +enum { + ALC_KEY_MICMUTE_INDEX, +}; + +struct alc_customize_define { + unsigned int sku_cfg; + unsigned char port_connectivity; + unsigned char check_sum; + unsigned char customization; + unsigned char external_amp; + unsigned int enable_pcbeep:1; + unsigned int platform_type:1; + unsigned int swap:1; + unsigned int override:1; + unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */ +}; + +struct alc_coef_led { + unsigned int idx; + unsigned int mask; + unsigned int on; + unsigned int off; +}; + +struct alc_spec { + struct hda_gen_spec gen; /* must be at head */ + + /* codec parameterization */ + struct alc_customize_define cdefine; + unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ + + /* GPIO bits */ + unsigned int gpio_mask; + unsigned int gpio_dir; + unsigned int gpio_data; + bool gpio_write_delay; /* add a delay before writing gpio_data */ + + /* mute LED for HP laptops, see vref_mute_led_set() */ + int mute_led_polarity; + int micmute_led_polarity; + hda_nid_t mute_led_nid; + hda_nid_t cap_mute_led_nid; + + unsigned int gpio_mute_led_mask; + unsigned int gpio_mic_led_mask; + struct alc_coef_led mute_led_coef; + struct alc_coef_led mic_led_coef; + struct mutex coef_mutex; + + hda_nid_t headset_mic_pin; + hda_nid_t headphone_mic_pin; + int current_headset_mode; + int current_headset_type; + + /* hooks */ + void (*init_hook)(struct hda_codec *codec); + void (*power_hook)(struct hda_codec *codec); + void (*shutup)(struct hda_codec *codec); + + int init_amp; + int codec_variant; /* flag for other variants */ + unsigned int has_alc5505_dsp:1; + unsigned int no_depop_delay:1; + unsigned int done_hp_init:1; + unsigned int no_shutup_pins:1; + unsigned int ultra_low_power:1; + unsigned int has_hs_key:1; + unsigned int no_internal_mic_pin:1; + unsigned int en_3kpull_low:1; + int num_speaker_amps; + + /* for PLL fix */ + hda_nid_t pll_nid; + unsigned int pll_coef_idx, pll_coef_bit; + unsigned int coef0; + struct input_dev *kb_dev; + u8 alc_mute_keycode_map[1]; + + /* component binding */ + struct hda_component_parent comps; +}; + +int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid, + unsigned int coef_idx); +void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid, + unsigned int coef_idx, unsigned int coef_val); +void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid, + unsigned int coef_idx, unsigned int mask, + unsigned int bits_set); +#define alc_read_coef_idx(codec, coef_idx) \ + alc_read_coefex_idx(codec, 0x20, coef_idx) +#define alc_write_coef_idx(codec, coef_idx, coef_val) \ + alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val) +#define alc_update_coef_idx(codec, coef_idx, mask, bits_set) \ + alc_update_coefex_idx(codec, 0x20, coef_idx, mask, bits_set) + +unsigned int alc_get_coef0(struct hda_codec *codec); + +/* coef writes/updates batch */ +struct coef_fw { + unsigned char nid; + unsigned char idx; + unsigned short mask; + unsigned short val; +}; + +#define UPDATE_COEFEX(_nid, _idx, _mask, _val) \ + { .nid = (_nid), .idx = (_idx), .mask = (_mask), .val = (_val) } +#define WRITE_COEFEX(_nid, _idx, _val) UPDATE_COEFEX(_nid, _idx, -1, _val) +#define WRITE_COEF(_idx, _val) WRITE_COEFEX(0x20, _idx, _val) +#define UPDATE_COEF(_idx, _mask, _val) UPDATE_COEFEX(0x20, _idx, _mask, _val) + +void alc_process_coef_fw(struct hda_codec *codec, const struct coef_fw *fw); + +/* + * GPIO helpers + */ +void alc_setup_gpio(struct hda_codec *codec, unsigned int mask); +void alc_write_gpio_data(struct hda_codec *codec); +void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask, + bool on); +void alc_write_gpio(struct hda_codec *codec); + +/* common GPIO fixups */ +void alc_fixup_gpio(struct hda_codec *codec, int action, unsigned int mask); +void alc_fixup_gpio1(struct hda_codec *codec, + const struct hda_fixup *fix, int action); +void alc_fixup_gpio2(struct hda_codec *codec, + const struct hda_fixup *fix, int action); +void alc_fixup_gpio3(struct hda_codec *codec, + const struct hda_fixup *fix, int action); +void alc_fixup_gpio4(struct hda_codec *codec, + const struct hda_fixup *fix, int action); +void alc_fixup_micmute_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action); + +/* + * Common init code, callbacks and helpers + */ +void alc_fix_pll(struct hda_codec *codec); +void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, + unsigned int coef_idx, unsigned int coef_bit); +void alc_fill_eapd_coef(struct hda_codec *codec); +void alc_auto_setup_eapd(struct hda_codec *codec, bool on); + +int alc_find_ext_mic_pin(struct hda_codec *codec); +void alc_headset_mic_no_shutup(struct hda_codec *codec); +void alc_shutup_pins(struct hda_codec *codec); +void alc_eapd_shutup(struct hda_codec *codec); +void alc_auto_init_amp(struct hda_codec *codec, int type); +hda_nid_t alc_get_hp_pin(struct alc_spec *spec); +int alc_auto_parse_customize_define(struct hda_codec *codec); +int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports); +void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports); +int alc_build_controls(struct hda_codec *codec); +void alc_update_knob_master(struct hda_codec *codec, + struct hda_jack_callback *jack); + +static inline void alc_pre_init(struct hda_codec *codec) +{ + alc_fill_eapd_coef(codec); +} + +#define is_s3_resume(codec) \ + ((codec)->core.dev.power.power_state.event == PM_EVENT_RESUME) +#define is_s4_resume(codec) \ + ((codec)->core.dev.power.power_state.event == PM_EVENT_RESTORE) +#define is_s4_suspend(codec) \ + ((codec)->core.dev.power.power_state.event == PM_EVENT_FREEZE) + +int alc_init(struct hda_codec *codec); +void alc_shutup(struct hda_codec *codec); +void alc_power_eapd(struct hda_codec *codec); +int alc_suspend(struct hda_codec *codec); +int alc_resume(struct hda_codec *codec); + +#define alc_free snd_hda_gen_free + +int alc_parse_auto_config(struct hda_codec *codec, + const hda_nid_t *ignore_nids, + const hda_nid_t *ssid_nids); +int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid); + +extern const struct hda_codec_ops alc_patch_ops; + +#define alc_codec_rename(codec, name) snd_hda_codec_set_name(codec, name) + +#ifdef CONFIG_SND_HDA_INPUT_BEEP +int alc_set_beep_amp(struct alc_spec *spec, hda_nid_t nid, int idx, int dir); +int alc_has_cdefine_beep(struct hda_codec *codec); +#define set_beep_amp alc_set_beep_amp +#define has_cdefine_beep alc_has_cdefine_beep +#else +#define set_beep_amp(spec, nid, idx, dir) 0 +#define has_cdefine_beep(codec) 0 +#endif + +static inline void rename_ctl(struct hda_codec *codec, const char *oldname, + const char *newname) +{ + struct snd_kcontrol *kctl; + + kctl = snd_hda_find_mixer_ctl(codec, oldname); + if (kctl) + snd_ctl_rename(codec->card, kctl, newname); +} + +/* Common fixups */ +void alc_fixup_sku_ignore(struct hda_codec *codec, + const struct hda_fixup *fix, int action); +void alc_fixup_no_depop_delay(struct hda_codec *codec, + const struct hda_fixup *fix, int action); +void alc_fixup_inv_dmic(struct hda_codec *codec, + const struct hda_fixup *fix, int action); +void alc_fixup_dual_codecs(struct hda_codec *codec, + const struct hda_fixup *fix, int action); +void alc_fixup_bass_chmap(struct hda_codec *codec, + const struct hda_fixup *fix, int action); +void alc_fixup_headset_mode(struct hda_codec *codec, + const struct hda_fixup *fix, int action); +void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec, + const struct hda_fixup *fix, int action); +void alc_fixup_headset_mic(struct hda_codec *codec, + const struct hda_fixup *fix, int action); +void alc_update_headset_jack_cb(struct hda_codec *codec, + struct hda_jack_callback *jack); +void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask, + int polarity, bool enabled); +void alc_fixup_hp_gpio_led(struct hda_codec *codec, + int action, + unsigned int mute_mask, + unsigned int micmute_mask); +void alc_fixup_no_jack_detect(struct hda_codec *codec, + const struct hda_fixup *fix, int action); +void alc_fixup_disable_aamix(struct hda_codec *codec, + const struct hda_fixup *fix, int action); +void alc_fixup_auto_mute_via_amp(struct hda_codec *codec, + const struct hda_fixup *fix, int action); + +/* device-specific, but used by multiple codec drivers */ +void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec, + const struct hda_fixup *fix, + int action); +void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec, + const struct hda_fixup *fix, + int action); +void alc_fixup_dell_xps13(struct hda_codec *codec, + const struct hda_fixup *fix, int action); + +#endif /* __HDA_REALTEK_H */ From 73cd0490819d2a693928c5977280dd31b756cb42 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:11 +0200 Subject: [PATCH 324/385] ALSA: hda/hdmi: Split vendor codec drivers In the past, we unified HD-audio HDMI codec driver once with a slight hope that more vendors will follow the standard, but in reality, the driver received more and more vendor-specific code. In order to make the messy code a bit more understandable, this patch splits the HDMI codec driver into multiple drivers again. Namely, the vendor-specific code for Intel, AMD and Nvidia are moved into the own drivers, while we split the common HDMI code to two drivers, the generic HDMI driver and the simple HDMI driver. So, now we have: - The generic HDMI driver (snd-hda-codec-hdmi): providing the common helpers, also supports Glenfly HDMI codecs and some other codecs that don't need vendor-specific stuff - The simple HDMI driver (snd-hda-codec-simplehdmi): devices with no dynamic PCM assignment and with fixed channels, mostly used by some other drivers, but this driver alone suffices for VIA HDMI codec support, too - Intel HDMI driver (snd-hda-codec-intelhdmi): bound with i915 / Xe DRM, based on the generic HDMI driver - AMD/ATI HDMI driver (snd-hda-codec-atihdmi): optionally bound with radeon / amdgpu DRM, based on the generic HDMI driver - Nvidia HDMI driver (snd-hda-codec-nvhdmi); optionally bound with nouveau DRM, based on the generic HDMI driver - Legacy Nvidia HDMI driver (snd-hda-codec-nvhdmi-mcp): for 2ch or 8ch outputs, based on the simple HDMI driver - Nvidia Tegra HDMI driver (snd-hda-codec-tegrahdmi): based on the generic HDMI driver Along with the driver split, the enable_silent_stream module option is moved to snd-hda-codec-intelhdmi, too, as it's an Intel-specific feature. Most of the changes here are just to split and move the code to different files, as well as to rename/expose the functions that are commonly used by drivers. The silent stream handling code is slightly modified for putting the stuff into Intel driver; now a new callback "silent_stream" is defined in hdmi_ops, and it's called in silent_stream_enable() and *_disable() functions. The runtime-PM handling in silent_stream_enable() was cleaned up, and rather taking the runtime PM refcount in the silent_stream() callback appropriately, instead. Other than that, there should be no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-9-tiwai@suse.de --- sound/hda/codecs/Kconfig | 31 +- sound/hda/codecs/hdmi/Kconfig | 68 + sound/hda/codecs/hdmi/Makefile | 12 + sound/hda/codecs/hdmi/atihdmi.c | 606 +++++++ sound/hda/codecs/hdmi/eld.c | 172 -- sound/hda/codecs/hdmi/hdmi.c | 2465 +--------------------------- sound/hda/codecs/hdmi/hdmi_local.h | 302 ++++ sound/hda/codecs/hdmi/intelhdmi.c | 760 +++++++++ sound/hda/codecs/hdmi/nvhdmi-mcp.c | 382 +++++ sound/hda/codecs/hdmi/nvhdmi.c | 218 +++ sound/hda/codecs/hdmi/simplehdmi.c | 241 +++ sound/hda/codecs/hdmi/tegrahdmi.c | 313 ++++ sound/hda/common/hda_local.h | 4 - 13 files changed, 2993 insertions(+), 2581 deletions(-) create mode 100644 sound/hda/codecs/hdmi/Kconfig create mode 100644 sound/hda/codecs/hdmi/atihdmi.c create mode 100644 sound/hda/codecs/hdmi/hdmi_local.h create mode 100644 sound/hda/codecs/hdmi/intelhdmi.c create mode 100644 sound/hda/codecs/hdmi/nvhdmi-mcp.c create mode 100644 sound/hda/codecs/hdmi/nvhdmi.c create mode 100644 sound/hda/codecs/hdmi/simplehdmi.c create mode 100644 sound/hda/codecs/hdmi/tegrahdmi.c diff --git a/sound/hda/codecs/Kconfig b/sound/hda/codecs/Kconfig index 0bb675ab84fe..e8c2efd2efb6 100644 --- a/sound/hda/codecs/Kconfig +++ b/sound/hda/codecs/Kconfig @@ -35,21 +35,6 @@ config SND_HDA_CODEC_VIA comment "Set to Y if you want auto-loading the codec driver" depends on SND_HDA=y && SND_HDA_CODEC_VIA=m -config SND_HDA_CODEC_HDMI - tristate "Build HDMI/DisplayPort HD-audio codec support" - select SND_DYNAMIC_MINORS - select SND_PCM_ELD - help - Say Y or M here to include HDMI and DisplayPort HD-audio codec - support in snd-hda-intel driver. This includes all AMD/ATI, - Intel and Nvidia HDMI/DisplayPort codecs. - - Note that this option mandatorily enables CONFIG_SND_DYNAMIC_MINORS - to assure the multiple streams for DP-MST support. - -comment "Set to Y if you want auto-loading the codec driver" - depends on SND_HDA=y && SND_HDA_CODEC_HDMI=m - config SND_HDA_CODEC_CONEXANT tristate "Build Conexant HD-audio codec support" select SND_HDA_GENERIC @@ -134,23 +119,9 @@ config SND_HDA_GENERIC comment "Set to Y if you want auto-loading the codec driver" depends on SND_HDA=y && SND_HDA_GENERIC=m -config SND_HDA_INTEL_HDMI_SILENT_STREAM - bool "Enable Silent Stream always for HDMI" - depends on SND_HDA_INTEL - help - Say Y to enable HD-Audio Keep Alive (KAE) aka Silent Stream - for HDMI on hardware that supports the feature. - - When enabled, the HDMI/DisplayPort codec will continue to provide - a continuous clock and a valid but silent data stream to - any connected external receiver. This allows to avoid gaps - at start of playback. Many receivers require multiple seconds - to start playing audio after the clock has been stopped. - 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/hdmi/Kconfig" source "sound/hda/codecs/side-codecs/Kconfig" endif # SND_HDA diff --git a/sound/hda/codecs/hdmi/Kconfig b/sound/hda/codecs/hdmi/Kconfig new file mode 100644 index 000000000000..498000d2c6ae --- /dev/null +++ b/sound/hda/codecs/hdmi/Kconfig @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config SND_HDA_CODEC_HDMI + tristate "Generic HDMI/DisplayPort HD-audio codec support" + select SND_DYNAMIC_MINORS + select SND_PCM_ELD + help + Say Y or M here to include Generic HDMI and DisplayPort HD-audio + codec support. + + Note that this option mandatorily enables CONFIG_SND_DYNAMIC_MINORS + to assure the multiple streams for DP-MST support. + +config SND_HDA_CODEC_HDMI_SIMPLE + tristate "Simple HDMI/DisplayPort HD-audio codec support" + help + Say Y or M here to include Simple HDMI and DisplayPort HD-audio + codec support for VIA and other codecs. + +config SND_HDA_CODEC_HDMI_INTEL + tristate "Intel HDMI/DisplayPort HD-audio codec support" + select SND_HDA_CODEC_HDMI + help + Say Y or M here to include Intel graphics HDMI and DisplayPort + HD-audio codec support. + +config SND_HDA_INTEL_HDMI_SILENT_STREAM + bool "Enable Silent Stream always for HDMI" + depends on SND_HDA_CODEC_HDMI_INTEL + help + Say Y to enable HD-Audio Keep Alive (KAE) aka Silent Stream + for HDMI on hardware that supports the feature. + + When enabled, the HDMI/DisplayPort codec will continue to provide + a continuous clock and a valid but silent data stream to + any connected external receiver. This allows to avoid gaps + at start of playback. Many receivers require multiple seconds + to start playing audio after the clock has been stopped. + This feature can impact power consumption as resources + are kept reserved both at transmitter and receiver. + +config SND_HDA_CODEC_HDMI_ATI + tristate "AMD/ATI HDMI/DisplayPort HD-audio codec support" + select SND_HDA_CODEC_HDMI + help + Say Y or M here to include AMD/ATI graphics HDMI and DisplayPort + HD-audio codec support. + +config SND_HDA_CODEC_HDMI_NVIDIA + tristate "Nvidia HDMI/DisplayPort HD-audio codec support" + select SND_HDA_CODEC_HDMI + help + Say Y or M here to include HDMI and DisplayPort HD-audio codec + support for the recent Nvidia graphics cards. + +config SND_HDA_CODEC_HDMI_NVIDIA_MCP + tristate "Legacy Nvidia HDMI/DisplayPort HD-audio codec support" + select SND_HDA_CODEC_HDMI_SIMPLE + help + Say Y or M here to include HDMI and DisplayPort HD-audio codec + support for the legacy Nvidia graphics like MCP73, MCP67, MCP77/78. + +config SND_HDA_CODEC_HDMI_TEGRA + tristate "Nvidia Tegra HDMI/DisplayPort HD-audio codec support" + select SND_HDA_CODEC_HDMI + help + Say Y or M here to include HDMI and DisplayPort HD-audio codec + support for Nvidia Tegra. diff --git a/sound/hda/codecs/hdmi/Makefile b/sound/hda/codecs/hdmi/Makefile index 371818d4e9b2..c07a0a71b64f 100644 --- a/sound/hda/codecs/hdmi/Makefile +++ b/sound/hda/codecs/hdmi/Makefile @@ -2,5 +2,17 @@ subdir-ccflags-y += -I$(src)/../../common snd-hda-codec-hdmi-y := hdmi.o eld.o +snd-hda-codec-simplehdmi-y := simplehdmi.o +snd-hda-codec-intelhdmi-y := intelhdmi.o +snd-hda-codec-atihdmi-y := atihdmi.o +snd-hda-codec-nvhdmi-y := nvhdmi.o +snd-hda-codec-nvhdmi-mcp-y := nvhdmi-mcp.o +snd-hda-codec-tegrahdmi-y := tegrahdmi.o obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o +obj-$(CONFIG_SND_HDA_CODEC_HDMI_SIMPLE) += snd-hda-codec-simplehdmi.o +obj-$(CONFIG_SND_HDA_CODEC_HDMI_INTEL) += snd-hda-codec-intelhdmi.o +obj-$(CONFIG_SND_HDA_CODEC_HDMI_ATI) += snd-hda-codec-atihdmi.o +obj-$(CONFIG_SND_HDA_CODEC_HDMI_NVIDIA) += snd-hda-codec-nvhdmi.o +obj-$(CONFIG_SND_HDA_CODEC_HDMI_NVIDIA_MCP) += snd-hda-codec-nvhdmi-mcp.o +obj-$(CONFIG_SND_HDA_CODEC_HDMI_TEGRA) += snd-hda-codec-tegrahdmi.o diff --git a/sound/hda/codecs/hdmi/atihdmi.c b/sound/hda/codecs/hdmi/atihdmi.c new file mode 100644 index 000000000000..e23995cc1b8c --- /dev/null +++ b/sound/hda/codecs/hdmi/atihdmi.c @@ -0,0 +1,606 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * ATI/AMD codec support + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "hda_local.h" +#include "hdmi_local.h" + +#define is_amdhdmi_rev3_or_later(codec) \ + ((codec)->core.vendor_id == 0x1002aa01 && \ + ((codec)->core.revision_id & 0xff00) >= 0x0300) +#define has_amd_full_remap_support(codec) is_amdhdmi_rev3_or_later(codec) + +/* ATI/AMD specific HDA pin verbs, see the AMD HDA Verbs specification */ +#define ATI_VERB_SET_CHANNEL_ALLOCATION 0x771 +#define ATI_VERB_SET_DOWNMIX_INFO 0x772 +#define ATI_VERB_SET_MULTICHANNEL_01 0x777 +#define ATI_VERB_SET_MULTICHANNEL_23 0x778 +#define ATI_VERB_SET_MULTICHANNEL_45 0x779 +#define ATI_VERB_SET_MULTICHANNEL_67 0x77a +#define ATI_VERB_SET_HBR_CONTROL 0x77c +#define ATI_VERB_SET_MULTICHANNEL_1 0x785 +#define ATI_VERB_SET_MULTICHANNEL_3 0x786 +#define ATI_VERB_SET_MULTICHANNEL_5 0x787 +#define ATI_VERB_SET_MULTICHANNEL_7 0x788 +#define ATI_VERB_SET_MULTICHANNEL_MODE 0x789 +#define ATI_VERB_GET_CHANNEL_ALLOCATION 0xf71 +#define ATI_VERB_GET_DOWNMIX_INFO 0xf72 +#define ATI_VERB_GET_MULTICHANNEL_01 0xf77 +#define ATI_VERB_GET_MULTICHANNEL_23 0xf78 +#define ATI_VERB_GET_MULTICHANNEL_45 0xf79 +#define ATI_VERB_GET_MULTICHANNEL_67 0xf7a +#define ATI_VERB_GET_HBR_CONTROL 0xf7c +#define ATI_VERB_GET_MULTICHANNEL_1 0xf85 +#define ATI_VERB_GET_MULTICHANNEL_3 0xf86 +#define ATI_VERB_GET_MULTICHANNEL_5 0xf87 +#define ATI_VERB_GET_MULTICHANNEL_7 0xf88 +#define ATI_VERB_GET_MULTICHANNEL_MODE 0xf89 + +/* AMD specific HDA cvt verbs */ +#define ATI_VERB_SET_RAMP_RATE 0x770 +#define ATI_VERB_GET_RAMP_RATE 0xf70 + +#define ATI_OUT_ENABLE 0x1 + +#define ATI_MULTICHANNEL_MODE_PAIRED 0 +#define ATI_MULTICHANNEL_MODE_SINGLE 1 + +#define ATI_HBR_CAPABLE 0x01 +#define ATI_HBR_ENABLE 0x10 + +/* ATI/AMD specific ELD emulation */ + +#define ATI_VERB_SET_AUDIO_DESCRIPTOR 0x776 +#define ATI_VERB_SET_SINK_INFO_INDEX 0x780 +#define ATI_VERB_GET_SPEAKER_ALLOCATION 0xf70 +#define ATI_VERB_GET_AUDIO_DESCRIPTOR 0xf76 +#define ATI_VERB_GET_AUDIO_VIDEO_DELAY 0xf7b +#define ATI_VERB_GET_SINK_INFO_INDEX 0xf80 +#define ATI_VERB_GET_SINK_INFO_DATA 0xf81 + +#define ATI_SPKALLOC_SPKALLOC 0x007f +#define ATI_SPKALLOC_TYPE_HDMI 0x0100 +#define ATI_SPKALLOC_TYPE_DISPLAYPORT 0x0200 + +/* first three bytes are just standard SAD */ +#define ATI_AUDIODESC_CHANNELS 0x00000007 +#define ATI_AUDIODESC_RATES 0x0000ff00 +#define ATI_AUDIODESC_LPCM_STEREO_RATES 0xff000000 + +/* in standard HDMI VSDB format */ +#define ATI_DELAY_VIDEO_LATENCY 0x000000ff +#define ATI_DELAY_AUDIO_LATENCY 0x0000ff00 + +enum ati_sink_info_idx { + ATI_INFO_IDX_MANUFACTURER_ID = 0, + ATI_INFO_IDX_PRODUCT_ID = 1, + ATI_INFO_IDX_SINK_DESC_LEN = 2, + ATI_INFO_IDX_PORT_ID_LOW = 3, + ATI_INFO_IDX_PORT_ID_HIGH = 4, + ATI_INFO_IDX_SINK_DESC_FIRST = 5, + ATI_INFO_IDX_SINK_DESC_LAST = 22, /* max len 18 bytes */ +}; + +static int get_eld_ati(struct hda_codec *codec, hda_nid_t nid, + unsigned char *buf, int *eld_size, bool rev3_or_later) +{ + int spkalloc, ati_sad, aud_synch; + int sink_desc_len = 0; + int pos, i; + + /* ATI/AMD does not have ELD, emulate it */ + + spkalloc = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SPEAKER_ALLOCATION, 0); + + if (spkalloc <= 0) { + codec_info(codec, "HDMI ATI/AMD: no speaker allocation for ELD\n"); + return -EINVAL; + } + + memset(buf, 0, ELD_FIXED_BYTES + ELD_MAX_MNL + ELD_MAX_SAD * 3); + + /* version */ + buf[0] = ELD_VER_CEA_861D << 3; + + /* speaker allocation from EDID */ + buf[7] = spkalloc & ATI_SPKALLOC_SPKALLOC; + + /* is DisplayPort? */ + if (spkalloc & ATI_SPKALLOC_TYPE_DISPLAYPORT) + buf[5] |= 0x04; + + pos = ELD_FIXED_BYTES; + + if (rev3_or_later) { + int sink_info; + + snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_LOW); + sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); + put_unaligned_le32(sink_info, buf + 8); + + snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_HIGH); + sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); + put_unaligned_le32(sink_info, buf + 12); + + snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_MANUFACTURER_ID); + sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); + put_unaligned_le16(sink_info, buf + 16); + + snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PRODUCT_ID); + sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); + put_unaligned_le16(sink_info, buf + 18); + + snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_LEN); + sink_desc_len = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); + + if (sink_desc_len > ELD_MAX_MNL) { + codec_info(codec, "HDMI ATI/AMD: Truncating HDMI sink description with length %d\n", + sink_desc_len); + sink_desc_len = ELD_MAX_MNL; + } + + buf[4] |= sink_desc_len; + + for (i = 0; i < sink_desc_len; i++) { + snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_FIRST + i); + buf[pos++] = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); + } + } + + for (i = AUDIO_CODING_TYPE_LPCM; i <= AUDIO_CODING_TYPE_WMAPRO; i++) { + if (i == AUDIO_CODING_TYPE_SACD || i == AUDIO_CODING_TYPE_DST) + continue; /* not handled by ATI/AMD */ + + snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_AUDIO_DESCRIPTOR, i << 3); + ati_sad = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_DESCRIPTOR, 0); + + if (ati_sad <= 0) + continue; + + if (ati_sad & ATI_AUDIODESC_RATES) { + /* format is supported, copy SAD as-is */ + buf[pos++] = (ati_sad & 0x0000ff) >> 0; + buf[pos++] = (ati_sad & 0x00ff00) >> 8; + buf[pos++] = (ati_sad & 0xff0000) >> 16; + } + + if (i == AUDIO_CODING_TYPE_LPCM + && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) + && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) >> 16 != (ati_sad & ATI_AUDIODESC_RATES)) { + /* for PCM there is a separate stereo rate mask */ + buf[pos++] = ((ati_sad & 0x000000ff) & ~ATI_AUDIODESC_CHANNELS) | 0x1; + /* rates from the extra byte */ + buf[pos++] = (ati_sad & 0xff000000) >> 24; + buf[pos++] = (ati_sad & 0x00ff0000) >> 16; + } + } + + if (pos == ELD_FIXED_BYTES + sink_desc_len) { + codec_info(codec, "HDMI ATI/AMD: no audio descriptors for ELD\n"); + return -EINVAL; + } + + /* + * HDMI VSDB latency format: + * separately for both audio and video: + * 0 field not valid or unknown latency + * [1..251] msecs = (x-1)*2 (max 500ms with x = 251 = 0xfb) + * 255 audio/video not supported + * + * HDA latency format: + * single value indicating video latency relative to audio: + * 0 unknown or 0ms + * [1..250] msecs = x*2 (max 500ms with x = 250 = 0xfa) + * [251..255] reserved + */ + aud_synch = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_VIDEO_DELAY, 0); + if ((aud_synch & ATI_DELAY_VIDEO_LATENCY) && (aud_synch & ATI_DELAY_AUDIO_LATENCY)) { + int video_latency_hdmi = (aud_synch & ATI_DELAY_VIDEO_LATENCY); + int audio_latency_hdmi = (aud_synch & ATI_DELAY_AUDIO_LATENCY) >> 8; + + if (video_latency_hdmi <= 0xfb && audio_latency_hdmi <= 0xfb && + video_latency_hdmi > audio_latency_hdmi) + buf[6] = video_latency_hdmi - audio_latency_hdmi; + /* else unknown/invalid or 0ms or video ahead of audio, so use zero */ + } + + /* SAD count */ + buf[5] |= ((pos - ELD_FIXED_BYTES - sink_desc_len) / 3) << 4; + + /* Baseline ELD block length is 4-byte aligned */ + pos = round_up(pos, 4); + + /* Baseline ELD length (4-byte header is not counted in) */ + buf[2] = (pos - 4) / 4; + + *eld_size = pos; + + return 0; +} + +static int atihdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid, + int dev_id, unsigned char *buf, int *eld_size) +{ + WARN_ON(dev_id != 0); + /* call hda_eld.c ATI/AMD-specific function */ + return get_eld_ati(codec, nid, buf, eld_size, + is_amdhdmi_rev3_or_later(codec)); +} + +static void atihdmi_pin_setup_infoframe(struct hda_codec *codec, + hda_nid_t pin_nid, int dev_id, int ca, + int active_channels, int conn_type) +{ + WARN_ON(dev_id != 0); + snd_hda_codec_write(codec, pin_nid, 0, ATI_VERB_SET_CHANNEL_ALLOCATION, ca); +} + +static int atihdmi_paired_swap_fc_lfe(int pos) +{ + /* + * ATI/AMD have automatic FC/LFE swap built-in + * when in pairwise mapping mode. + */ + + switch (pos) { + /* see channel_allocations[].speakers[] */ + case 2: return 3; + case 3: return 2; + default: return pos; + } +} + +static int atihdmi_paired_chmap_validate(struct hdac_chmap *chmap, + int ca, int chs, unsigned char *map) +{ + struct hdac_cea_channel_speaker_allocation *cap; + int i, j; + + /* check that only channel pairs need to be remapped on old pre-rev3 ATI/AMD */ + + cap = snd_hdac_get_ch_alloc_from_ca(ca); + for (i = 0; i < chs; ++i) { + int mask = snd_hdac_chmap_to_spk_mask(map[i]); + bool ok = false; + bool companion_ok = false; + + if (!mask) + continue; + + for (j = 0 + i % 2; j < 8; j += 2) { + int chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j); + + if (cap->speakers[chan_idx] == mask) { + /* channel is in a supported position */ + ok = true; + + if (i % 2 == 0 && i + 1 < chs) { + /* even channel, check the odd companion */ + int comp_chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j + 1); + int comp_mask_req = snd_hdac_chmap_to_spk_mask(map[i+1]); + int comp_mask_act = cap->speakers[comp_chan_idx]; + + if (comp_mask_req == comp_mask_act) + companion_ok = true; + else + return -EINVAL; + } + break; + } + } + + if (!ok) + return -EINVAL; + + if (companion_ok) + i++; /* companion channel already checked */ + } + + return 0; +} + +static int atihdmi_pin_set_slot_channel(struct hdac_device *hdac, + hda_nid_t pin_nid, int hdmi_slot, int stream_channel) +{ + struct hda_codec *codec = hdac_to_hda_codec(hdac); + int verb; + int ati_channel_setup = 0; + + if (hdmi_slot > 7) + return -EINVAL; + + if (!has_amd_full_remap_support(codec)) { + hdmi_slot = atihdmi_paired_swap_fc_lfe(hdmi_slot); + + /* In case this is an odd slot but without stream channel, do not + * disable the slot since the corresponding even slot could have a + * channel. In case neither have a channel, the slot pair will be + * disabled when this function is called for the even slot. + */ + if (hdmi_slot % 2 != 0 && stream_channel == 0xf) + return 0; + + hdmi_slot -= hdmi_slot % 2; + + if (stream_channel != 0xf) + stream_channel -= stream_channel % 2; + } + + verb = ATI_VERB_SET_MULTICHANNEL_01 + hdmi_slot/2 + (hdmi_slot % 2) * 0x00e; + + /* ati_channel_setup format: [7..4] = stream_channel_id, [1] = mute, [0] = enable */ + + if (stream_channel != 0xf) + ati_channel_setup = (stream_channel << 4) | ATI_OUT_ENABLE; + + return snd_hda_codec_write(codec, pin_nid, 0, verb, ati_channel_setup); +} + +static int atihdmi_pin_get_slot_channel(struct hdac_device *hdac, + hda_nid_t pin_nid, int asp_slot) +{ + struct hda_codec *codec = hdac_to_hda_codec(hdac); + bool was_odd = false; + int ati_asp_slot = asp_slot; + int verb; + int ati_channel_setup; + + if (asp_slot > 7) + return -EINVAL; + + if (!has_amd_full_remap_support(codec)) { + ati_asp_slot = atihdmi_paired_swap_fc_lfe(asp_slot); + if (ati_asp_slot % 2 != 0) { + ati_asp_slot -= 1; + was_odd = true; + } + } + + verb = ATI_VERB_GET_MULTICHANNEL_01 + ati_asp_slot/2 + (ati_asp_slot % 2) * 0x00e; + + ati_channel_setup = snd_hda_codec_read(codec, pin_nid, 0, verb, 0); + + if (!(ati_channel_setup & ATI_OUT_ENABLE)) + return 0xf; + + return ((ati_channel_setup & 0xf0) >> 4) + !!was_odd; +} + +static int atihdmi_paired_chmap_cea_alloc_validate_get_type( + struct hdac_chmap *chmap, + struct hdac_cea_channel_speaker_allocation *cap, + int channels) +{ + int c; + + /* + * Pre-rev3 ATI/AMD codecs operate in a paired channel mode, so + * we need to take that into account (a single channel may take 2 + * channel slots if we need to carry a silent channel next to it). + * On Rev3+ AMD codecs this function is not used. + */ + int chanpairs = 0; + + /* We only produce even-numbered channel count TLVs */ + if ((channels % 2) != 0) + return -1; + + for (c = 0; c < 7; c += 2) { + if (cap->speakers[c] || cap->speakers[c+1]) + chanpairs++; + } + + if (chanpairs * 2 != channels) + return -1; + + return SNDRV_CTL_TLVT_CHMAP_PAIRED; +} + +static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap, + struct hdac_cea_channel_speaker_allocation *cap, + unsigned int *chmap, int channels) +{ + /* produce paired maps for pre-rev3 ATI/AMD codecs */ + int count = 0; + int c; + + for (c = 7; c >= 0; c--) { + int chan = 7 - atihdmi_paired_swap_fc_lfe(7 - c); + int spk = cap->speakers[chan]; + + if (!spk) { + /* add N/A channel if the companion channel is occupied */ + if (cap->speakers[chan + (chan % 2 ? -1 : 1)]) + chmap[count++] = SNDRV_CHMAP_NA; + + continue; + } + + chmap[count++] = snd_hdac_spk_to_chmap(spk); + } + + WARN_ON(count != channels); +} + +static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid, + int dev_id, bool hbr) +{ + int hbr_ctl, hbr_ctl_new; + + WARN_ON(dev_id != 0); + + hbr_ctl = snd_hda_codec_read(codec, pin_nid, 0, ATI_VERB_GET_HBR_CONTROL, 0); + if (hbr_ctl >= 0 && (hbr_ctl & ATI_HBR_CAPABLE)) { + if (hbr) + hbr_ctl_new = hbr_ctl | ATI_HBR_ENABLE; + else + hbr_ctl_new = hbr_ctl & ~ATI_HBR_ENABLE; + + codec_dbg(codec, + "%s: NID=0x%x, %shbr-ctl=0x%x\n", + __func__, + pin_nid, + hbr_ctl == hbr_ctl_new ? "" : "new-", + hbr_ctl_new); + + if (hbr_ctl != hbr_ctl_new) + snd_hda_codec_write(codec, pin_nid, 0, + ATI_VERB_SET_HBR_CONTROL, + hbr_ctl_new); + + } else if (hbr) + return -EINVAL; + + return 0; +} + +static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, + hda_nid_t pin_nid, int dev_id, + u32 stream_tag, int format) +{ + if (is_amdhdmi_rev3_or_later(codec)) { + int ramp_rate = 180; /* default as per AMD spec */ + /* disable ramp-up/down for non-pcm as per AMD spec */ + if (format & AC_FMT_TYPE_NON_PCM) + ramp_rate = 0; + + snd_hda_codec_write(codec, cvt_nid, 0, ATI_VERB_SET_RAMP_RATE, ramp_rate); + } + + return snd_hda_hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id, + stream_tag, format); +} + + +static int atihdmi_init(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + int pin_idx, err; + + err = snd_hda_hdmi_generic_init(codec); + + if (err) + return err; + + for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); + + /* make sure downmix information in infoframe is zero */ + snd_hda_codec_write(codec, per_pin->pin_nid, 0, ATI_VERB_SET_DOWNMIX_INFO, 0); + + /* enable channel-wise remap mode if supported */ + if (has_amd_full_remap_support(codec)) + snd_hda_codec_write(codec, per_pin->pin_nid, 0, + ATI_VERB_SET_MULTICHANNEL_MODE, + ATI_MULTICHANNEL_MODE_SINGLE); + } + codec->auto_runtime_pm = 1; + + return 0; +} + +/* map from pin NID to port; port is 0-based */ +/* for AMD: assume widget NID starting from 3, with step 2 (3, 5, 7, ...) */ +static int atihdmi_pin2port(void *audio_ptr, int pin_nid) +{ + return pin_nid / 2 - 1; +} + +/* reverse-map from port to pin NID: see above */ +static int atihdmi_port2pin(struct hda_codec *codec, int port) +{ + return port * 2 + 3; +} + +static const struct drm_audio_component_audio_ops atihdmi_audio_ops = { + .pin2port = atihdmi_pin2port, + .pin_eld_notify = snd_hda_hdmi_acomp_pin_eld_notify, + .master_bind = snd_hda_hdmi_acomp_master_bind, + .master_unbind = snd_hda_hdmi_acomp_master_unbind, +}; + +static int patch_atihdmi(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + struct hdmi_spec_per_cvt *per_cvt; + int err, cvt_idx; + + err = patch_generic_hdmi(codec); + + if (err) + return err; + + codec->patch_ops.init = atihdmi_init; + + spec = codec->spec; + + spec->static_pcm_mapping = true; + + spec->ops.pin_get_eld = atihdmi_pin_get_eld; + spec->ops.pin_setup_infoframe = atihdmi_pin_setup_infoframe; + spec->ops.pin_hbr_setup = atihdmi_pin_hbr_setup; + spec->ops.setup_stream = atihdmi_setup_stream; + + spec->chmap.ops.pin_get_slot_channel = atihdmi_pin_get_slot_channel; + spec->chmap.ops.pin_set_slot_channel = atihdmi_pin_set_slot_channel; + + if (!has_amd_full_remap_support(codec)) { + /* override to ATI/AMD-specific versions with pairwise mapping */ + spec->chmap.ops.chmap_cea_alloc_validate_get_type = + atihdmi_paired_chmap_cea_alloc_validate_get_type; + spec->chmap.ops.cea_alloc_to_tlv_chmap = + atihdmi_paired_cea_alloc_to_tlv_chmap; + spec->chmap.ops.chmap_validate = atihdmi_paired_chmap_validate; + } + + /* ATI/AMD converters do not advertise all of their capabilities */ + for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { + per_cvt = get_cvt(spec, cvt_idx); + per_cvt->channels_max = max(per_cvt->channels_max, 8u); + per_cvt->rates |= SUPPORTED_RATES; + per_cvt->formats |= SUPPORTED_FORMATS; + per_cvt->maxbps = max(per_cvt->maxbps, 24u); + } + + spec->chmap.channels_max = max(spec->chmap.channels_max, 8u); + + /* AMD GPUs have neither EPSS nor CLKSTOP bits, hence preventing + * the link-down as is. Tell the core to allow it. + */ + codec->link_down_at_suspend = 1; + + snd_hda_hdmi_acomp_init(codec, &atihdmi_audio_ops, atihdmi_port2pin); + + return 0; +} + +/* + * patch entries + */ +static const struct hda_device_id snd_hda_id_atihdmi[] = { +HDA_CODEC_ENTRY(0x1002793c, "RS600 HDMI", patch_atihdmi), +HDA_CODEC_ENTRY(0x10027919, "RS600 HDMI", patch_atihdmi), +HDA_CODEC_ENTRY(0x1002791a, "RS690/780 HDMI", patch_atihdmi), +HDA_CODEC_ENTRY(0x1002aa01, "R6xx HDMI", patch_atihdmi), +{} /* terminator */ +}; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_atihdmi); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AMD/ATI HDMI HD-audio codec"); +MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI"); + +static struct hda_codec_driver atihdmi_driver = { + .id = snd_hda_id_atihdmi, +}; + +module_hda_codec_driver(atihdmi_driver); diff --git a/sound/hda/codecs/hdmi/eld.c b/sound/hda/codecs/hdmi/eld.c index d3e87b9c1a4f..1464fd1c675b 100644 --- a/sound/hda/codecs/hdmi/eld.c +++ b/sound/hda/codecs/hdmi/eld.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include "hda_local.h" @@ -229,174 +228,3 @@ void snd_hdmi_eld_update_pcm_info(struct snd_parsed_hdmi_eld *e, hinfo->maxbps = min(hinfo->maxbps, maxbps); hinfo->channels_max = min(hinfo->channels_max, channels_max); } - - -/* ATI/AMD specific stuff (ELD emulation) */ - -#define ATI_VERB_SET_AUDIO_DESCRIPTOR 0x776 -#define ATI_VERB_SET_SINK_INFO_INDEX 0x780 -#define ATI_VERB_GET_SPEAKER_ALLOCATION 0xf70 -#define ATI_VERB_GET_AUDIO_DESCRIPTOR 0xf76 -#define ATI_VERB_GET_AUDIO_VIDEO_DELAY 0xf7b -#define ATI_VERB_GET_SINK_INFO_INDEX 0xf80 -#define ATI_VERB_GET_SINK_INFO_DATA 0xf81 - -#define ATI_SPKALLOC_SPKALLOC 0x007f -#define ATI_SPKALLOC_TYPE_HDMI 0x0100 -#define ATI_SPKALLOC_TYPE_DISPLAYPORT 0x0200 - -/* first three bytes are just standard SAD */ -#define ATI_AUDIODESC_CHANNELS 0x00000007 -#define ATI_AUDIODESC_RATES 0x0000ff00 -#define ATI_AUDIODESC_LPCM_STEREO_RATES 0xff000000 - -/* in standard HDMI VSDB format */ -#define ATI_DELAY_VIDEO_LATENCY 0x000000ff -#define ATI_DELAY_AUDIO_LATENCY 0x0000ff00 - -enum ati_sink_info_idx { - ATI_INFO_IDX_MANUFACTURER_ID = 0, - ATI_INFO_IDX_PRODUCT_ID = 1, - ATI_INFO_IDX_SINK_DESC_LEN = 2, - ATI_INFO_IDX_PORT_ID_LOW = 3, - ATI_INFO_IDX_PORT_ID_HIGH = 4, - ATI_INFO_IDX_SINK_DESC_FIRST = 5, - ATI_INFO_IDX_SINK_DESC_LAST = 22, /* max len 18 bytes */ -}; - -int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid, - unsigned char *buf, int *eld_size, bool rev3_or_later) -{ - int spkalloc, ati_sad, aud_synch; - int sink_desc_len = 0; - int pos, i; - - /* ATI/AMD does not have ELD, emulate it */ - - spkalloc = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SPEAKER_ALLOCATION, 0); - - if (spkalloc <= 0) { - codec_info(codec, "HDMI ATI/AMD: no speaker allocation for ELD\n"); - return -EINVAL; - } - - memset(buf, 0, ELD_FIXED_BYTES + ELD_MAX_MNL + ELD_MAX_SAD * 3); - - /* version */ - buf[0] = ELD_VER_CEA_861D << 3; - - /* speaker allocation from EDID */ - buf[7] = spkalloc & ATI_SPKALLOC_SPKALLOC; - - /* is DisplayPort? */ - if (spkalloc & ATI_SPKALLOC_TYPE_DISPLAYPORT) - buf[5] |= 0x04; - - pos = ELD_FIXED_BYTES; - - if (rev3_or_later) { - int sink_info; - - snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_LOW); - sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); - put_unaligned_le32(sink_info, buf + 8); - - snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_HIGH); - sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); - put_unaligned_le32(sink_info, buf + 12); - - snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_MANUFACTURER_ID); - sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); - put_unaligned_le16(sink_info, buf + 16); - - snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PRODUCT_ID); - sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); - put_unaligned_le16(sink_info, buf + 18); - - snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_LEN); - sink_desc_len = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); - - if (sink_desc_len > ELD_MAX_MNL) { - codec_info(codec, "HDMI ATI/AMD: Truncating HDMI sink description with length %d\n", - sink_desc_len); - sink_desc_len = ELD_MAX_MNL; - } - - buf[4] |= sink_desc_len; - - for (i = 0; i < sink_desc_len; i++) { - snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_FIRST + i); - buf[pos++] = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); - } - } - - for (i = AUDIO_CODING_TYPE_LPCM; i <= AUDIO_CODING_TYPE_WMAPRO; i++) { - if (i == AUDIO_CODING_TYPE_SACD || i == AUDIO_CODING_TYPE_DST) - continue; /* not handled by ATI/AMD */ - - snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_AUDIO_DESCRIPTOR, i << 3); - ati_sad = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_DESCRIPTOR, 0); - - if (ati_sad <= 0) - continue; - - if (ati_sad & ATI_AUDIODESC_RATES) { - /* format is supported, copy SAD as-is */ - buf[pos++] = (ati_sad & 0x0000ff) >> 0; - buf[pos++] = (ati_sad & 0x00ff00) >> 8; - buf[pos++] = (ati_sad & 0xff0000) >> 16; - } - - if (i == AUDIO_CODING_TYPE_LPCM - && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) - && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) >> 16 != (ati_sad & ATI_AUDIODESC_RATES)) { - /* for PCM there is a separate stereo rate mask */ - buf[pos++] = ((ati_sad & 0x000000ff) & ~ATI_AUDIODESC_CHANNELS) | 0x1; - /* rates from the extra byte */ - buf[pos++] = (ati_sad & 0xff000000) >> 24; - buf[pos++] = (ati_sad & 0x00ff0000) >> 16; - } - } - - if (pos == ELD_FIXED_BYTES + sink_desc_len) { - codec_info(codec, "HDMI ATI/AMD: no audio descriptors for ELD\n"); - return -EINVAL; - } - - /* - * HDMI VSDB latency format: - * separately for both audio and video: - * 0 field not valid or unknown latency - * [1..251] msecs = (x-1)*2 (max 500ms with x = 251 = 0xfb) - * 255 audio/video not supported - * - * HDA latency format: - * single value indicating video latency relative to audio: - * 0 unknown or 0ms - * [1..250] msecs = x*2 (max 500ms with x = 250 = 0xfa) - * [251..255] reserved - */ - aud_synch = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_VIDEO_DELAY, 0); - if ((aud_synch & ATI_DELAY_VIDEO_LATENCY) && (aud_synch & ATI_DELAY_AUDIO_LATENCY)) { - int video_latency_hdmi = (aud_synch & ATI_DELAY_VIDEO_LATENCY); - int audio_latency_hdmi = (aud_synch & ATI_DELAY_AUDIO_LATENCY) >> 8; - - if (video_latency_hdmi <= 0xfb && audio_latency_hdmi <= 0xfb && - video_latency_hdmi > audio_latency_hdmi) - buf[6] = video_latency_hdmi - audio_latency_hdmi; - /* else unknown/invalid or 0ms or video ahead of audio, so use zero */ - } - - /* SAD count */ - buf[5] |= ((pos - ELD_FIXED_BYTES - sink_desc_len) / 3) << 4; - - /* Baseline ELD block length is 4-byte aligned */ - pos = round_up(pos, 4); - - /* Baseline ELD length (4-byte header is not counted in) */ - buf[2] = (pos - 4) / 4; - - *eld_size = pos; - - return 0; -} diff --git a/sound/hda/codecs/hdmi/hdmi.c b/sound/hda/codecs/hdmi/hdmi.c index 3811eb1dc998..85aaa454072f 100644 --- a/sound/hda/codecs/hdmi/hdmi.c +++ b/sound/hda/codecs/hdmi/hdmi.c @@ -33,6 +33,7 @@ #include "hda_local.h" #include "hda_jack.h" #include "hda_controller.h" +#include "hdmi_local.h" static bool static_hdmi_pcm; module_param(static_hdmi_pcm, bool, 0644); @@ -42,214 +43,12 @@ static bool enable_acomp = true; module_param(enable_acomp, bool, 0444); MODULE_PARM_DESC(enable_acomp, "Enable audio component binding (default=yes)"); -static bool enable_silent_stream = -IS_ENABLED(CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM); -module_param(enable_silent_stream, bool, 0644); -MODULE_PARM_DESC(enable_silent_stream, "Enable Silent Stream for HDMI devices"); - static bool enable_all_pins; module_param(enable_all_pins, bool, 0444); MODULE_PARM_DESC(enable_all_pins, "Forcibly enable all pins"); -struct hdmi_spec_per_cvt { - hda_nid_t cvt_nid; - bool assigned; /* the stream has been assigned */ - bool silent_stream; /* silent stream activated */ - unsigned int channels_min; - unsigned int channels_max; - u32 rates; - u64 formats; - unsigned int maxbps; -}; - -/* max. connections to a widget */ -#define HDA_MAX_CONNECTIONS 32 - -struct hdmi_spec_per_pin { - hda_nid_t pin_nid; - int dev_id; - /* pin idx, different device entries on the same pin use the same idx */ - int pin_nid_idx; - int num_mux_nids; - hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; - int mux_idx; - hda_nid_t cvt_nid; - - struct hda_codec *codec; - struct hdmi_eld sink_eld; - struct mutex lock; - struct delayed_work work; - struct hdmi_pcm *pcm; /* pointer to spec->pcm_rec[n] dynamically*/ - int pcm_idx; /* which pcm is attached. -1 means no pcm is attached */ - int prev_pcm_idx; /* previously assigned pcm index */ - int repoll_count; - bool setup; /* the stream has been set up by prepare callback */ - bool silent_stream; - int channels; /* current number of channels */ - bool non_pcm; - bool chmap_set; /* channel-map override by ALSA API? */ - unsigned char chmap[8]; /* ALSA API channel-map */ -#ifdef CONFIG_SND_PROC_FS - struct snd_info_entry *proc_entry; -#endif -}; - -/* operations used by generic code that can be overridden by patches */ -struct hdmi_ops { - int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid, - int dev_id, unsigned char *buf, int *eld_size); - - void (*pin_setup_infoframe)(struct hda_codec *codec, hda_nid_t pin_nid, - int dev_id, - int ca, int active_channels, int conn_type); - - /* enable/disable HBR (HD passthrough) */ - int (*pin_hbr_setup)(struct hda_codec *codec, hda_nid_t pin_nid, - int dev_id, bool hbr); - - int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid, - hda_nid_t pin_nid, int dev_id, u32 stream_tag, - int format); - - void (*pin_cvt_fixup)(struct hda_codec *codec, - struct hdmi_spec_per_pin *per_pin, - hda_nid_t cvt_nid); -}; - -struct hdmi_pcm { - struct hda_pcm *pcm; - struct snd_jack *jack; - struct snd_kcontrol *eld_ctl; -}; - -enum { - SILENT_STREAM_OFF = 0, - SILENT_STREAM_KAE, /* use standard HDA Keep-Alive */ - SILENT_STREAM_I915, /* Intel i915 extension */ -}; - -struct hdmi_spec { - struct hda_codec *codec; - int num_cvts; - struct snd_array cvts; /* struct hdmi_spec_per_cvt */ - hda_nid_t cvt_nids[4]; /* only for haswell fix */ - - /* - * num_pins is the number of virtual pins - * for example, there are 3 pins, and each pin - * has 4 device entries, then the num_pins is 12 - */ - int num_pins; - /* - * num_nids is the number of real pins - * In the above example, num_nids is 3 - */ - int num_nids; - /* - * dev_num is the number of device entries - * on each pin. - * In the above example, dev_num is 4 - */ - int dev_num; - struct snd_array pins; /* struct hdmi_spec_per_pin */ - struct hdmi_pcm pcm_rec[8]; - struct mutex pcm_lock; - struct mutex bind_lock; /* for audio component binding */ - /* pcm_bitmap means which pcms have been assigned to pins*/ - unsigned long pcm_bitmap; - int pcm_used; /* counter of pcm_rec[] */ - /* bitmap shows whether the pcm is opened in user space - * bit 0 means the first playback PCM (PCM3); - * bit 1 means the second playback PCM, and so on. - */ - unsigned long pcm_in_use; - - struct hdmi_eld temp_eld; - struct hdmi_ops ops; - - bool dyn_pin_out; - bool static_pcm_mapping; - /* hdmi interrupt trigger control flag for Nvidia codec */ - bool hdmi_intr_trig_ctrl; - bool nv_dp_workaround; /* workaround DP audio infoframe for Nvidia */ - - bool intel_hsw_fixup; /* apply Intel platform-specific fixups */ - /* - * Non-generic VIA/NVIDIA specific - */ - struct hda_multi_out multiout; - struct hda_pcm_stream pcm_playback; - - bool use_acomp_notifier; /* use eld_notify callback for hotplug */ - bool acomp_registered; /* audio component registered in this driver */ - bool force_connect; /* force connectivity */ - struct drm_audio_component_audio_ops drm_audio_ops; - int (*port2pin)(struct hda_codec *, int); /* reverse port/pin mapping */ - - struct hdac_chmap chmap; - hda_nid_t vendor_nid; - const int *port_map; - int port_num; - int silent_stream_type; -}; - -#ifdef CONFIG_SND_HDA_COMPONENT -static inline bool codec_has_acomp(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - return spec->use_acomp_notifier; -} -#else -#define codec_has_acomp(codec) false -#endif - -struct hdmi_audio_infoframe { - u8 type; /* 0x84 */ - u8 ver; /* 0x01 */ - u8 len; /* 0x0a */ - - u8 checksum; - - u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */ - u8 SS01_SF24; - u8 CXT04; - u8 CA; - u8 LFEPBL01_LSV36_DM_INH7; -}; - -struct dp_audio_infoframe { - u8 type; /* 0x84 */ - u8 len; /* 0x1b */ - u8 ver; /* 0x11 << 2 */ - - u8 CC02_CT47; /* match with HDMI infoframe from this on */ - u8 SS01_SF24; - u8 CXT04; - u8 CA; - u8 LFEPBL01_LSV36_DM_INH7; -}; - -union audio_infoframe { - struct hdmi_audio_infoframe hdmi; - struct dp_audio_infoframe dp; - DECLARE_FLEX_ARRAY(u8, bytes); -}; - -/* - * HDMI routines - */ - -#define get_pin(spec, idx) \ - ((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx)) -#define get_cvt(spec, idx) \ - ((struct hdmi_spec_per_cvt *)snd_array_elem(&spec->cvts, idx)) -/* obtain hdmi_pcm object assigned to idx */ -#define get_hdmi_pcm(spec, idx) (&(spec)->pcm_rec[idx]) -/* obtain hda_pcm object assigned to idx */ -#define get_pcm_rec(spec, idx) (get_hdmi_pcm(spec, idx)->pcm) - -static int pin_id_to_pin_index(struct hda_codec *codec, - hda_nid_t pin_nid, int dev_id) +int snd_hda_hdmi_pin_id_to_pin_index(struct hda_codec *codec, + hda_nid_t pin_nid, int dev_id) { struct hdmi_spec *spec = codec->spec; int pin_idx; @@ -272,6 +71,7 @@ static int pin_id_to_pin_index(struct hda_codec *codec, codec_warn(codec, "HDMI: pin NID 0x%x not registered\n", pin_nid); return -EINVAL; } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_pin_id_to_pin_index, "SND_HDA_CODEC_HDMI"); static int hinfo_to_pcm_index(struct hda_codec *codec, struct hda_pcm_stream *hinfo) @@ -735,9 +535,9 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec, } } -static void hdmi_setup_audio_infoframe(struct hda_codec *codec, - struct hdmi_spec_per_pin *per_pin, - bool non_pcm) +void snd_hda_hdmi_setup_audio_infoframe(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin, + bool non_pcm) { struct hdmi_spec *spec = codec->spec; struct hdac_chmap *chmap = &spec->chmap; @@ -783,6 +583,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, per_pin->non_pcm = non_pcm; } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_setup_audio_infoframe, "SND_HDA_CODEC_HDMI"); /* * Unsolicited events @@ -790,8 +591,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll); -static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid, - int dev_id) +void snd_hda_hdmi_check_presence_and_report(struct hda_codec *codec, + hda_nid_t nid, int dev_id) { struct hdmi_spec *spec = codec->spec; int pin_idx = pin_id_to_pin_index(codec, nid, dev_id); @@ -802,6 +603,8 @@ static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid, hdmi_present_sense(get_pin(spec, pin_idx), 1); mutex_unlock(&spec->pcm_lock); } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_check_presence_and_report, + "SND_HDA_CODEC_HDMI"); static void jack_callback(struct hda_codec *codec, struct hda_jack_callback *jack) @@ -810,7 +613,7 @@ static void jack_callback(struct hda_codec *codec, if (codec_has_acomp(codec)) return; - check_presence_and_report(codec, jack->nid, jack->dev_id); + snd_hda_hdmi_check_presence_and_report(codec, jack->nid, jack->dev_id); } static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res, @@ -823,7 +626,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res, codec->addr, jack->nid, jack->dev_id, !!(res & AC_UNSOL_RES_IA), !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV)); - check_presence_and_report(codec, jack->nid, jack->dev_id); + snd_hda_hdmi_check_presence_and_report(codec, jack->nid, jack->dev_id); } static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) @@ -850,8 +653,7 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) } } - -static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) +void snd_hda_hdmi_generic_unsol_event(struct hda_codec *codec, unsigned int res) { int tag = res >> AC_UNSOL_RES_TAG_SHIFT; int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; @@ -879,27 +681,7 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) else hdmi_non_intrinsic_event(codec, res); } - -static void haswell_verify_D0(struct hda_codec *codec, - hda_nid_t cvt_nid, hda_nid_t nid) -{ - int pwr; - - /* For Haswell, the converter 1/2 may keep in D3 state after bootup, - * thus pins could only choose converter 0 for use. Make sure the - * converters are in correct power state */ - if (!snd_hda_check_power_state(codec, cvt_nid, AC_PWRST_D0)) - snd_hda_codec_write(codec, cvt_nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - - if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0)) { - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - msleep(40); - pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0); - pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT; - codec_dbg(codec, "Haswell HDMI audio: Power for NID 0x%x is now D%d\n", nid, pwr); - } -} +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_unsol_event, "SND_HDA_CODEC_HDMI"); /* * Callbacks @@ -944,7 +726,8 @@ static int hdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid, return 0; } -static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, +int snd_hda_hdmi_setup_stream(struct hda_codec *codec, + hda_nid_t cvt_nid, hda_nid_t pin_nid, int dev_id, u32 stream_tag, int format) { @@ -983,6 +766,7 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, snd_hda_codec_setup_stream(codec, cvt_nid, stream_tag, 0, format); return 0; } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_setup_stream, "SND_HDA_CODEC_HDMI"); /* Try to find an available converter * If pin_idx is less then zero, just try to find an available converter. @@ -1046,137 +830,6 @@ static int hdmi_choose_cvt(struct hda_codec *codec, return 0; } -/* Assure the pin select the right convetor */ -static void intel_verify_pin_cvt_connect(struct hda_codec *codec, - struct hdmi_spec_per_pin *per_pin) -{ - hda_nid_t pin_nid = per_pin->pin_nid; - int mux_idx, curr; - - mux_idx = per_pin->mux_idx; - curr = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_CONNECT_SEL, 0); - if (curr != mux_idx) - snd_hda_codec_write_cache(codec, pin_nid, 0, - AC_VERB_SET_CONNECT_SEL, - mux_idx); -} - -/* get the mux index for the converter of the pins - * converter's mux index is the same for all pins on Intel platform - */ -static int intel_cvt_id_to_mux_idx(struct hdmi_spec *spec, - hda_nid_t cvt_nid) -{ - int i; - - for (i = 0; i < spec->num_cvts; i++) - if (spec->cvt_nids[i] == cvt_nid) - return i; - return -EINVAL; -} - -/* Intel HDMI workaround to fix audio routing issue: - * For some Intel display codecs, pins share the same connection list. - * So a conveter can be selected by multiple pins and playback on any of these - * pins will generate sound on the external display, because audio flows from - * the same converter to the display pipeline. Also muting one pin may make - * other pins have no sound output. - * So this function assures that an assigned converter for a pin is not selected - * by any other pins. - */ -static void intel_not_share_assigned_cvt(struct hda_codec *codec, - hda_nid_t pin_nid, - int dev_id, int mux_idx) -{ - struct hdmi_spec *spec = codec->spec; - hda_nid_t nid; - int cvt_idx, curr; - struct hdmi_spec_per_cvt *per_cvt; - struct hdmi_spec_per_pin *per_pin; - int pin_idx; - - /* configure the pins connections */ - for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - int dev_id_saved; - int dev_num; - - per_pin = get_pin(spec, pin_idx); - /* - * pin not connected to monitor - * no need to operate on it - */ - if (!per_pin->pcm) - continue; - - if ((per_pin->pin_nid == pin_nid) && - (per_pin->dev_id == dev_id)) - continue; - - /* - * if per_pin->dev_id >= dev_num, - * snd_hda_get_dev_select() will fail, - * and the following operation is unpredictable. - * So skip this situation. - */ - dev_num = snd_hda_get_num_devices(codec, per_pin->pin_nid) + 1; - if (per_pin->dev_id >= dev_num) - continue; - - nid = per_pin->pin_nid; - - /* - * Calling this function should not impact - * on the device entry selection - * So let's save the dev id for each pin, - * and restore it when return - */ - dev_id_saved = snd_hda_get_dev_select(codec, nid); - snd_hda_set_dev_select(codec, nid, per_pin->dev_id); - curr = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONNECT_SEL, 0); - if (curr != mux_idx) { - snd_hda_set_dev_select(codec, nid, dev_id_saved); - continue; - } - - - /* choose an unassigned converter. The conveters in the - * connection list are in the same order as in the codec. - */ - for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { - per_cvt = get_cvt(spec, cvt_idx); - if (!per_cvt->assigned) { - codec_dbg(codec, - "choose cvt %d for pin NID 0x%x\n", - cvt_idx, nid); - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_CONNECT_SEL, - cvt_idx); - break; - } - } - snd_hda_set_dev_select(codec, nid, dev_id_saved); - } -} - -/* A wrapper of intel_not_share_asigned_cvt() */ -static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec, - hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid) -{ - int mux_idx; - struct hdmi_spec *spec = codec->spec; - - /* On Intel platform, the mapping of converter nid to - * mux index of the pins are always the same. - * The pin nid may be 0, this means all pins will not - * share the converter. - */ - mux_idx = intel_cvt_id_to_mux_idx(spec, cvt_nid); - if (mux_idx >= 0) - intel_not_share_assigned_cvt(codec, pin_nid, dev_id, mux_idx); -} - /* skeleton caller of pin_cvt_fixup ops */ static void pin_cvt_fixup(struct hda_codec *codec, struct hdmi_spec_per_pin *per_pin, @@ -1466,7 +1119,7 @@ static void hdmi_pcm_setup_pin(struct hdmi_spec *spec, per_pin->setup = true; per_pin->mux_idx = mux_idx; - hdmi_setup_audio_infoframe(codec, per_pin, non_pcm); + snd_hda_hdmi_setup_audio_infoframe(codec, per_pin, non_pcm); } static void hdmi_pcm_reset_pin(struct hdmi_spec *spec, @@ -1583,7 +1236,7 @@ static void update_eld(struct hda_codec *codec, */ if (eld->eld_valid && !old_eld_valid && per_pin->setup) { pin_cvt_fixup(codec, per_pin, 0); - hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); + snd_hda_hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); } if (eld_changed && pcm_idx >= 0) @@ -1653,57 +1306,12 @@ static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, snd_hda_power_down_pm(codec); } -#define I915_SILENT_RATE 48000 -#define I915_SILENT_CHANNELS 2 -#define I915_SILENT_FORMAT_BITS 16 -#define I915_SILENT_FMT_MASK 0xf - -static void silent_stream_enable_i915(struct hda_codec *codec, - struct hdmi_spec_per_pin *per_pin) -{ - unsigned int format; - - snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid, - per_pin->dev_id, I915_SILENT_RATE); - - /* trigger silent stream generation in hw */ - format = snd_hdac_stream_format(I915_SILENT_CHANNELS, I915_SILENT_FORMAT_BITS, - I915_SILENT_RATE); - snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, - I915_SILENT_FMT_MASK, I915_SILENT_FMT_MASK, format); - usleep_range(100, 200); - snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, I915_SILENT_FMT_MASK, 0, format); - - per_pin->channels = I915_SILENT_CHANNELS; - hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); -} - -static void silent_stream_set_kae(struct hda_codec *codec, - struct hdmi_spec_per_pin *per_pin, - bool enable) -{ - unsigned int param; - - codec_dbg(codec, "HDMI: KAE %d cvt-NID=0x%x\n", enable, per_pin->cvt_nid); - - param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0); - param = (param >> 16) & 0xff; - - if (enable) - param |= AC_DIG3_KAE; - else - param &= ~AC_DIG3_KAE; - - snd_hda_codec_write(codec, per_pin->cvt_nid, 0, AC_VERB_SET_DIGI_CONVERT_3, param); -} - static void silent_stream_enable(struct hda_codec *codec, struct hdmi_spec_per_pin *per_pin) { struct hdmi_spec *spec = codec->spec; struct hdmi_spec_per_cvt *per_cvt; int cvt_idx, pin_idx, err; - int keep_power = 0; /* * Power-up will call hdmi_present_sense, so the PM calls @@ -1749,24 +1357,12 @@ static void silent_stream_enable(struct hda_codec *codec, /* configure unused pins to choose other converters */ pin_cvt_fixup(codec, per_pin, 0); - switch (spec->silent_stream_type) { - case SILENT_STREAM_KAE: - silent_stream_enable_i915(codec, per_pin); - silent_stream_set_kae(codec, per_pin, true); - break; - case SILENT_STREAM_I915: - silent_stream_enable_i915(codec, per_pin); - keep_power = 1; - break; - default: - break; - } + spec->ops.silent_stream(codec, per_pin, true); unlock_out: mutex_unlock(&per_pin->lock); - if (err || !keep_power) - snd_hda_power_down_pm(codec); + snd_hda_power_down_pm(codec); } static void silent_stream_disable(struct hda_codec *codec, @@ -1798,12 +1394,7 @@ static void silent_stream_disable(struct hda_codec *codec, per_cvt->silent_stream = false; } - if (spec->silent_stream_type == SILENT_STREAM_I915) { - /* release ref taken in silent_stream_enable() */ - snd_hda_power_down_pm(codec); - } else if (spec->silent_stream_type == SILENT_STREAM_KAE) { - silent_stream_set_kae(codec, per_pin, false); - } + spec->ops.silent_stream(codec, per_pin, false); per_pin->cvt_nid = 0; per_pin->silent_stream = false; @@ -2003,7 +1594,7 @@ static const struct snd_pci_quirk force_connect_list[] = { {} }; -static int hdmi_parse_codec(struct hda_codec *codec) +int snd_hda_hdmi_parse_codec(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; hda_nid_t start_nid; @@ -2056,6 +1647,7 @@ static int hdmi_parse_codec(struct hda_codec *codec) return 0; } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_parse_codec, "SND_HDA_CODEC_HDMI"); /* */ @@ -2082,11 +1674,11 @@ static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) * HDMI callbacks */ -static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) +int snd_hda_hdmi_generic_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) { hda_nid_t cvt_nid = hinfo->nid; struct hdmi_spec *spec = codec->spec; @@ -2140,7 +1732,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, stripe); } - hdmi_setup_audio_infoframe(codec, per_pin, non_pcm); + snd_hda_hdmi_setup_audio_infoframe(codec, per_pin, non_pcm); mutex_unlock(&per_pin->lock); if (spec->dyn_pin_out) { snd_hda_set_dev_select(codec, per_pin->pin_nid, @@ -2159,14 +1751,16 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, mutex_unlock(&spec->pcm_lock); return err; } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_pcm_prepare, "SND_HDA_CODEC_HDMI"); -static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) +int snd_hda_hdmi_generic_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) { snd_hda_codec_cleanup_stream(codec, hinfo->nid); return 0; } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_pcm_cleanup, "SND_HDA_CODEC_HDMI"); static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, struct hda_codec *codec, @@ -2237,8 +1831,8 @@ unlock: static const struct hda_pcm_ops generic_ops = { .open = hdmi_pcm_open, .close = hdmi_pcm_close, - .prepare = generic_hdmi_playback_pcm_prepare, - .cleanup = generic_hdmi_playback_pcm_cleanup, + .prepare = snd_hda_hdmi_generic_pcm_prepare, + .cleanup = snd_hda_hdmi_generic_pcm_cleanup, }; static int hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) @@ -2280,7 +1874,7 @@ static void hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, per_pin->chmap_set = true; memcpy(per_pin->chmap, chmap, ARRAY_SIZE(per_pin->chmap)); if (prepared) - hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); + snd_hda_hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); mutex_unlock(&per_pin->lock); } @@ -2293,7 +1887,7 @@ static bool is_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) return per_pin ? true:false; } -static int generic_hdmi_build_pcms(struct hda_codec *codec) +int snd_hda_hdmi_generic_build_pcms(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; int idx, pcm_num; @@ -2332,6 +1926,7 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) return 0; } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_build_pcms, "SND_HDA_CODEC_HDMI"); static void free_hdmi_jack_priv(struct snd_jack *jack) { @@ -2362,7 +1957,7 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pcm_idx) return 0; } -static int generic_hdmi_build_controls(struct hda_codec *codec) +int snd_hda_hdmi_generic_build_controls(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; int dev, err; @@ -2425,8 +2020,9 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) return 0; } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_build_controls, "SND_HDA_CODEC_HDMI"); -static int generic_hdmi_init_per_pins(struct hda_codec *codec) +int snd_hda_hdmi_generic_init_per_pins(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; int pin_idx; @@ -2441,8 +2037,9 @@ static int generic_hdmi_init_per_pins(struct hda_codec *codec) } return 0; } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_init_per_pins, "SND_HDA_CODEC_HDMI"); -static int generic_hdmi_init(struct hda_codec *codec) +int snd_hda_hdmi_generic_init(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; int pin_idx; @@ -2463,6 +2060,7 @@ static int generic_hdmi_init(struct hda_codec *codec) mutex_unlock(&spec->bind_lock); return 0; } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_init, "SND_HDA_CODEC_HDMI"); static void hdmi_array_init(struct hdmi_spec *spec, int nums) { @@ -2476,7 +2074,7 @@ static void hdmi_array_free(struct hdmi_spec *spec) snd_array_free(&spec->cvts); } -static void generic_spec_free(struct hda_codec *codec) +void snd_hda_hdmi_generic_spec_free(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; @@ -2487,8 +2085,9 @@ static void generic_spec_free(struct hda_codec *codec) } codec->dp_mst = false; } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_spec_free, "SND_HDA_CODEC_HDMI"); -static void generic_hdmi_free(struct hda_codec *codec) +void snd_hda_hdmi_generic_free(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; int pin_idx, pcm_idx; @@ -2512,10 +2111,11 @@ static void generic_hdmi_free(struct hda_codec *codec) snd_device_free(codec->card, spec->pcm_rec[pcm_idx].jack); } - generic_spec_free(codec); + snd_hda_hdmi_generic_spec_free(codec); } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_free, "SND_HDA_CODEC_HDMI"); -static int generic_hdmi_suspend(struct hda_codec *codec) +int snd_hda_hdmi_generic_suspend(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; int pin_idx; @@ -2526,8 +2126,9 @@ static int generic_hdmi_suspend(struct hda_codec *codec) } return 0; } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_suspend, "SND_HDA_CODEC_HDMI"); -static int generic_hdmi_resume(struct hda_codec *codec) +int snd_hda_hdmi_generic_resume(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; int pin_idx; @@ -2541,26 +2142,27 @@ static int generic_hdmi_resume(struct hda_codec *codec) } return 0; } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_resume, "SND_HDA_CODEC_HDMI"); static const struct hda_codec_ops generic_hdmi_patch_ops = { - .init = generic_hdmi_init, - .free = generic_hdmi_free, - .build_pcms = generic_hdmi_build_pcms, - .build_controls = generic_hdmi_build_controls, - .unsol_event = hdmi_unsol_event, - .suspend = generic_hdmi_suspend, - .resume = generic_hdmi_resume, + .init = snd_hda_hdmi_generic_init, + .free = snd_hda_hdmi_generic_free, + .build_pcms = snd_hda_hdmi_generic_build_pcms, + .build_controls = snd_hda_hdmi_generic_build_controls, + .unsol_event = snd_hda_hdmi_generic_unsol_event, + .suspend = snd_hda_hdmi_generic_suspend, + .resume = snd_hda_hdmi_generic_resume, }; static const struct hdmi_ops generic_standard_hdmi_ops = { .pin_get_eld = hdmi_pin_get_eld, .pin_setup_infoframe = hdmi_pin_setup_infoframe, .pin_hbr_setup = hdmi_pin_hbr_setup, - .setup_stream = hdmi_setup_stream, + .setup_stream = snd_hda_hdmi_setup_stream, }; /* allocate codec->spec and assign/initialize generic parser ops */ -static int alloc_generic_hdmi(struct hda_codec *codec) +int snd_hda_hdmi_generic_alloc(struct hda_codec *codec) { struct hdmi_spec *spec; @@ -2587,25 +2189,27 @@ static int alloc_generic_hdmi(struct hda_codec *codec) return 0; } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_alloc, "SND_HDA_CODEC_HDMI"); /* generic HDMI parser */ -static int patch_generic_hdmi(struct hda_codec *codec) +int patch_generic_hdmi(struct hda_codec *codec) { int err; - err = alloc_generic_hdmi(codec); + err = snd_hda_hdmi_generic_alloc(codec); if (err < 0) return err; - err = hdmi_parse_codec(codec); + err = snd_hda_hdmi_parse_codec(codec); if (err < 0) { - generic_spec_free(codec); + snd_hda_hdmi_generic_spec_free(codec); return err; } - generic_hdmi_init_per_pins(codec); + snd_hda_hdmi_generic_init_per_pins(codec); return 0; } +EXPORT_SYMBOL_NS_GPL(patch_generic_hdmi, "SND_HDA_CODEC_HDMI"); /* * generic audio component binding @@ -2650,18 +2254,20 @@ static void generic_acomp_notifier_set(struct drm_audio_component *acomp, } /* enable / disable the notifier via master bind / unbind */ -static int generic_acomp_master_bind(struct device *dev, - struct drm_audio_component *acomp) +int snd_hda_hdmi_acomp_master_bind(struct device *dev, + struct drm_audio_component *acomp) { generic_acomp_notifier_set(acomp, true); return 0; } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_acomp_master_bind, "SND_HDA_CODEC_HDMI"); -static void generic_acomp_master_unbind(struct device *dev, - struct drm_audio_component *acomp) +void snd_hda_hdmi_acomp_master_unbind(struct device *dev, + struct drm_audio_component *acomp) { generic_acomp_notifier_set(acomp, false); } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_acomp_master_unbind, "SND_HDA_CODEC_HDMI"); /* check whether both HD-audio and DRM PCI devices belong to the same bus */ static int match_bound_vga(struct device *dev, int subtype, void *data) @@ -2677,7 +2283,7 @@ static int match_bound_vga(struct device *dev, int subtype, void *data) } /* audio component notifier for AMD/Nvidia HDMI codecs */ -static void generic_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id) +void snd_hda_hdmi_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id) { struct hda_codec *codec = audio_ptr; struct hdmi_spec *spec = codec->spec; @@ -2693,12 +2299,13 @@ static void generic_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id) if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND) return; - check_presence_and_report(codec, pin_nid, dev_id); + snd_hda_hdmi_check_presence_and_report(codec, pin_nid, dev_id); } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_acomp_pin_eld_notify, "SND_HDA_CODEC_HDMI"); /* set up the private drm_audio_ops from the template */ -static void setup_drm_audio_ops(struct hda_codec *codec, - const struct drm_audio_component_audio_ops *ops) +void snd_hda_hdmi_setup_drm_audio_ops(struct hda_codec *codec, + const struct drm_audio_component_audio_ops *ops) { struct hdmi_spec *spec = codec->spec; @@ -2713,11 +2320,12 @@ static void setup_drm_audio_ops(struct hda_codec *codec, spec->drm_audio_ops.master_bind = ops->master_bind; spec->drm_audio_ops.master_unbind = ops->master_unbind; } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_setup_drm_audio_ops, "SND_HDA_CODEC_HDMI"); /* initialize the generic HDMI audio component */ -static void generic_acomp_init(struct hda_codec *codec, - const struct drm_audio_component_audio_ops *ops, - int (*port2pin)(struct hda_codec *, int)) +void snd_hda_hdmi_acomp_init(struct hda_codec *codec, + const struct drm_audio_component_audio_ops *ops, + int (*port2pin)(struct hda_codec *, int)) { struct hdmi_spec *spec = codec->spec; @@ -2727,1767 +2335,17 @@ static void generic_acomp_init(struct hda_codec *codec, } spec->port2pin = port2pin; - setup_drm_audio_ops(codec, ops); + snd_hda_hdmi_setup_drm_audio_ops(codec, ops); if (!snd_hdac_acomp_init(&codec->bus->core, &spec->drm_audio_ops, match_bound_vga, 0)) { spec->acomp_registered = true; } } +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_acomp_init, "SND_HDA_CODEC_HDMI"); /* - * Intel codec parsers and helpers */ -#define INTEL_GET_VENDOR_VERB 0xf81 -#define INTEL_SET_VENDOR_VERB 0x781 -#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ -#define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */ - -static void intel_haswell_enable_all_pins(struct hda_codec *codec, - bool update_tree) -{ - unsigned int vendor_param; - struct hdmi_spec *spec = codec->spec; - - vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0, - INTEL_GET_VENDOR_VERB, 0); - if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS) - return; - - vendor_param |= INTEL_EN_ALL_PIN_CVTS; - vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0, - INTEL_SET_VENDOR_VERB, vendor_param); - if (vendor_param == -1) - return; - - if (update_tree) - snd_hda_codec_update_widgets(codec); -} - -static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec) -{ - unsigned int vendor_param; - struct hdmi_spec *spec = codec->spec; - - vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0, - INTEL_GET_VENDOR_VERB, 0); - if (vendor_param == -1 || vendor_param & INTEL_EN_DP12) - return; - - /* enable DP1.2 mode */ - vendor_param |= INTEL_EN_DP12; - snd_hdac_regmap_add_vendor_verb(&codec->core, INTEL_SET_VENDOR_VERB); - snd_hda_codec_write_cache(codec, spec->vendor_nid, 0, - INTEL_SET_VENDOR_VERB, vendor_param); -} - -/* Haswell needs to re-issue the vendor-specific verbs before turning to D0. - * Otherwise you may get severe h/w communication errors. - */ -static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg, - unsigned int power_state) -{ - if (power_state == AC_PWRST_D0) { - intel_haswell_enable_all_pins(codec, false); - intel_haswell_fixup_enable_dp12(codec); - } - - snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state); - snd_hda_codec_set_power_to_all(codec, fg, power_state); -} - -/* There is a fixed mapping between audio pin node and display port. - * on SNB, IVY, HSW, BSW, SKL, BXT, KBL: - * Pin Widget 5 - PORT B (port = 1 in i915 driver) - * Pin Widget 6 - PORT C (port = 2 in i915 driver) - * Pin Widget 7 - PORT D (port = 3 in i915 driver) - * - * on VLV, ILK: - * Pin Widget 4 - PORT B (port = 1 in i915 driver) - * Pin Widget 5 - PORT C (port = 2 in i915 driver) - * Pin Widget 6 - PORT D (port = 3 in i915 driver) - */ -static int intel_base_nid(struct hda_codec *codec) -{ - switch (codec->core.vendor_id) { - case 0x80860054: /* ILK */ - case 0x80862804: /* ILK */ - case 0x80862882: /* VLV */ - return 4; - default: - return 5; - } -} - -static int intel_pin2port(void *audio_ptr, int pin_nid) -{ - struct hda_codec *codec = audio_ptr; - struct hdmi_spec *spec = codec->spec; - int base_nid, i; - - if (!spec->port_num) { - base_nid = intel_base_nid(codec); - if (WARN_ON(pin_nid < base_nid || pin_nid >= base_nid + 3)) - return -1; - return pin_nid - base_nid + 1; - } - - /* - * looking for the pin number in the mapping table and return - * the index which indicate the port number - */ - for (i = 0; i < spec->port_num; i++) { - if (pin_nid == spec->port_map[i]) - return i; - } - - codec_info(codec, "Can't find the HDMI/DP port for pin NID 0x%x\n", pin_nid); - return -1; -} - -static int intel_port2pin(struct hda_codec *codec, int port) -{ - struct hdmi_spec *spec = codec->spec; - - if (!spec->port_num) { - /* we assume only from port-B to port-D */ - if (port < 1 || port > 3) - return 0; - return port + intel_base_nid(codec) - 1; - } - - if (port < 0 || port >= spec->port_num) - return 0; - return spec->port_map[port]; -} - -static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe) -{ - struct hda_codec *codec = audio_ptr; - int pin_nid; - int dev_id = pipe; - - pin_nid = intel_port2pin(codec, port); - if (!pin_nid) - return; - /* skip notification during system suspend (but not in runtime PM); - * the state will be updated at resume - */ - if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND) - return; - - snd_hdac_i915_set_bclk(&codec->bus->core); - check_presence_and_report(codec, pin_nid, dev_id); -} - -static const struct drm_audio_component_audio_ops intel_audio_ops = { - .pin2port = intel_pin2port, - .pin_eld_notify = intel_pin_eld_notify, -}; - -/* register i915 component pin_eld_notify callback */ -static void register_i915_notifier(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - - spec->use_acomp_notifier = true; - spec->port2pin = intel_port2pin; - setup_drm_audio_ops(codec, &intel_audio_ops); - snd_hdac_acomp_register_notifier(&codec->bus->core, - &spec->drm_audio_ops); - /* no need for forcible resume for jack check thanks to notifier */ - codec->relaxed_resume = 1; -} - -/* setup_stream ops override for HSW+ */ -static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, - hda_nid_t pin_nid, int dev_id, u32 stream_tag, - int format) -{ - struct hdmi_spec *spec = codec->spec; - int pin_idx = pin_id_to_pin_index(codec, pin_nid, dev_id); - struct hdmi_spec_per_pin *per_pin; - int res; - - if (pin_idx < 0) - per_pin = NULL; - else - per_pin = get_pin(spec, pin_idx); - - haswell_verify_D0(codec, cvt_nid, pin_nid); - - if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) { - silent_stream_set_kae(codec, per_pin, false); - /* wait for pending transfers in codec to clear */ - usleep_range(100, 200); - } - - res = hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id, - stream_tag, format); - - if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) { - usleep_range(100, 200); - silent_stream_set_kae(codec, per_pin, true); - } - - return res; -} - -/* pin_cvt_fixup ops override for HSW+ and VLV+ */ -static void i915_pin_cvt_fixup(struct hda_codec *codec, - struct hdmi_spec_per_pin *per_pin, - hda_nid_t cvt_nid) -{ - if (per_pin) { - haswell_verify_D0(codec, per_pin->cvt_nid, per_pin->pin_nid); - snd_hda_set_dev_select(codec, per_pin->pin_nid, - per_pin->dev_id); - intel_verify_pin_cvt_connect(codec, per_pin); - intel_not_share_assigned_cvt(codec, per_pin->pin_nid, - per_pin->dev_id, per_pin->mux_idx); - } else { - intel_not_share_assigned_cvt_nid(codec, 0, 0, cvt_nid); - } -} - -static int i915_adlp_hdmi_suspend(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - bool silent_streams = false; - int pin_idx, res; - - res = generic_hdmi_suspend(codec); - - for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); - - if (per_pin->silent_stream) { - silent_streams = true; - break; - } - } - - if (silent_streams && spec->silent_stream_type == SILENT_STREAM_KAE) { - /* - * stream-id should remain programmed when codec goes - * to runtime suspend - */ - codec->no_stream_clean_at_suspend = 1; - - /* - * the system might go to S3, in which case keep-alive - * must be reprogrammed upon resume - */ - codec->forced_resume = 1; - - codec_dbg(codec, "HDMI: KAE active at suspend\n"); - } else { - codec->no_stream_clean_at_suspend = 0; - codec->forced_resume = 0; - } - - return res; -} - -static int i915_adlp_hdmi_resume(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - int pin_idx, res; - - res = generic_hdmi_resume(codec); - - /* KAE not programmed at suspend, nothing to do here */ - if (!codec->no_stream_clean_at_suspend) - return res; - - for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); - - /* - * If system was in suspend with monitor connected, - * the codec setting may have been lost. Re-enable - * keep-alive. - */ - if (per_pin->silent_stream) { - unsigned int param; - - param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0, - AC_VERB_GET_CONV, 0); - if (!param) { - codec_dbg(codec, "HDMI: KAE: restore stream id\n"); - silent_stream_enable_i915(codec, per_pin); - } - - param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0, - AC_VERB_GET_DIGI_CONVERT_1, 0); - if (!(param & (AC_DIG3_KAE << 16))) { - codec_dbg(codec, "HDMI: KAE: restore DIG3_KAE\n"); - silent_stream_set_kae(codec, per_pin, true); - } - } - } - - return res; -} - -/* precondition and allocation for Intel codecs */ -static int alloc_intel_hdmi(struct hda_codec *codec) -{ - int err; - - /* requires i915 binding */ - if (!codec->bus->core.audio_component) { - codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n"); - /* set probe_id here to prevent generic fallback binding */ - codec->probe_id = HDA_CODEC_ID_SKIP_PROBE; - return -ENODEV; - } - - err = alloc_generic_hdmi(codec); - if (err < 0) - return err; - /* no need to handle unsol events */ - codec->patch_ops.unsol_event = NULL; - return 0; -} - -/* parse and post-process for Intel codecs */ -static int parse_intel_hdmi(struct hda_codec *codec) -{ - int err, retries = 3; - - do { - err = hdmi_parse_codec(codec); - } while (err < 0 && retries--); - - if (err < 0) { - generic_spec_free(codec); - return err; - } - - generic_hdmi_init_per_pins(codec); - register_i915_notifier(codec); - return 0; -} - -/* Intel Haswell and onwards; audio component with eld notifier */ -static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid, - const int *port_map, int port_num, int dev_num, - bool send_silent_stream) -{ - struct hdmi_spec *spec; - int err; - - err = alloc_intel_hdmi(codec); - if (err < 0) - return err; - spec = codec->spec; - codec->dp_mst = true; - spec->vendor_nid = vendor_nid; - spec->port_map = port_map; - spec->port_num = port_num; - spec->intel_hsw_fixup = true; - spec->dev_num = dev_num; - - intel_haswell_enable_all_pins(codec, true); - intel_haswell_fixup_enable_dp12(codec); - - codec->display_power_control = 1; - - codec->patch_ops.set_power_state = haswell_set_power_state; - codec->depop_delay = 0; - codec->auto_runtime_pm = 1; - - spec->ops.setup_stream = i915_hsw_setup_stream; - spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup; - - /* - * Enable silent stream feature, if it is enabled via - * module param or Kconfig option - */ - if (send_silent_stream) - spec->silent_stream_type = SILENT_STREAM_I915; - - return parse_intel_hdmi(codec); -} - -static int patch_i915_hsw_hdmi(struct hda_codec *codec) -{ - return intel_hsw_common_init(codec, 0x08, NULL, 0, 3, - enable_silent_stream); -} - -static int patch_i915_glk_hdmi(struct hda_codec *codec) -{ - /* - * Silent stream calls audio component .get_power() from - * .pin_eld_notify(). On GLK this will deadlock in i915 due - * to the audio vs. CDCLK workaround. - */ - return intel_hsw_common_init(codec, 0x0b, NULL, 0, 3, false); -} - -static int patch_i915_icl_hdmi(struct hda_codec *codec) -{ - /* - * pin to port mapping table where the value indicate the pin number and - * the index indicate the port number. - */ - static const int map[] = {0x0, 0x4, 0x6, 0x8, 0xa, 0xb}; - - return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 3, - enable_silent_stream); -} - -static int patch_i915_tgl_hdmi(struct hda_codec *codec) -{ - /* - * pin to port mapping table where the value indicate the pin number and - * the index indicate the port number. - */ - static const int map[] = {0x4, 0x6, 0x8, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; - - return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 4, - enable_silent_stream); -} - -static int patch_i915_adlp_hdmi(struct hda_codec *codec) -{ - struct hdmi_spec *spec; - int res; - - res = patch_i915_tgl_hdmi(codec); - if (!res) { - spec = codec->spec; - - if (spec->silent_stream_type) { - spec->silent_stream_type = SILENT_STREAM_KAE; - - codec->patch_ops.resume = i915_adlp_hdmi_resume; - codec->patch_ops.suspend = i915_adlp_hdmi_suspend; - } - } - - return res; -} - -/* Intel Baytrail and Braswell; with eld notifier */ -static int patch_i915_byt_hdmi(struct hda_codec *codec) -{ - struct hdmi_spec *spec; - int err; - - err = alloc_intel_hdmi(codec); - if (err < 0) - return err; - spec = codec->spec; - - /* For Valleyview/Cherryview, only the display codec is in the display - * power well and can use link_power ops to request/release the power. - */ - codec->display_power_control = 1; - - codec->depop_delay = 0; - codec->auto_runtime_pm = 1; - - spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup; - - return parse_intel_hdmi(codec); -} - -/* Intel IronLake, SandyBridge and IvyBridge; with eld notifier */ -static int patch_i915_cpt_hdmi(struct hda_codec *codec) -{ - int err; - - err = alloc_intel_hdmi(codec); - if (err < 0) - return err; - return parse_intel_hdmi(codec); -} - -/* - * Shared non-generic implementations - */ - -static int simple_playback_build_pcms(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - struct hda_pcm *info; - unsigned int chans; - struct hda_pcm_stream *pstr; - struct hdmi_spec_per_cvt *per_cvt; - - per_cvt = get_cvt(spec, 0); - chans = get_wcaps(codec, per_cvt->cvt_nid); - chans = get_wcaps_channels(chans); - - info = snd_hda_codec_pcm_new(codec, "HDMI 0"); - if (!info) - return -ENOMEM; - spec->pcm_rec[0].pcm = info; - info->pcm_type = HDA_PCM_TYPE_HDMI; - pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK]; - *pstr = spec->pcm_playback; - pstr->nid = per_cvt->cvt_nid; - if (pstr->channels_max <= 2 && chans && chans <= 16) - pstr->channels_max = chans; - - return 0; -} - -/* unsolicited event for jack sensing */ -static void simple_hdmi_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - snd_hda_jack_set_dirty_all(codec); - snd_hda_jack_report_sync(codec); -} - -/* generic_hdmi_build_jack can be used for simple_hdmi, too, - * as long as spec->pins[] is set correctly - */ -#define simple_hdmi_build_jack generic_hdmi_build_jack - -static int simple_playback_build_controls(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - struct hdmi_spec_per_cvt *per_cvt; - int err; - - per_cvt = get_cvt(spec, 0); - err = snd_hda_create_dig_out_ctls(codec, per_cvt->cvt_nid, - per_cvt->cvt_nid, - HDA_PCM_TYPE_HDMI); - if (err < 0) - return err; - return simple_hdmi_build_jack(codec, 0); -} - -static int simple_playback_init(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - struct hdmi_spec_per_pin *per_pin = get_pin(spec, 0); - hda_nid_t pin = per_pin->pin_nid; - - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - /* some codecs require to unmute the pin */ - if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); - snd_hda_jack_detect_enable(codec, pin, per_pin->dev_id); - return 0; -} - -static void simple_playback_free(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - - hdmi_array_free(spec); - kfree(spec); -} - -/* - * Nvidia specific implementations - */ - -#define Nv_VERB_SET_Channel_Allocation 0xF79 -#define Nv_VERB_SET_Info_Frame_Checksum 0xF7A -#define Nv_VERB_SET_Audio_Protection_On 0xF98 -#define Nv_VERB_SET_Audio_Protection_Off 0xF99 - -#define nvhdmi_master_con_nid_7x 0x04 -#define nvhdmi_master_pin_nid_7x 0x05 - -static const hda_nid_t nvhdmi_con_nids_7x[4] = { - /*front, rear, clfe, rear_surr */ - 0x6, 0x8, 0xa, 0xc, -}; - -static const struct hda_verb nvhdmi_basic_init_7x_2ch[] = { - /* set audio protect on */ - { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1}, - /* enable digital output on pin widget */ - { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, - {} /* terminator */ -}; - -static const struct hda_verb nvhdmi_basic_init_7x_8ch[] = { - /* set audio protect on */ - { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1}, - /* enable digital output on pin widget */ - { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, - { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, - { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, - { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, - { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, - {} /* terminator */ -}; - -#ifdef LIMITED_RATE_FMT_SUPPORT -/* support only the safe format and rate */ -#define SUPPORTED_RATES SNDRV_PCM_RATE_48000 -#define SUPPORTED_MAXBPS 16 -#define SUPPORTED_FORMATS SNDRV_PCM_FMTBIT_S16_LE -#else -/* support all rates and formats */ -#define SUPPORTED_RATES \ - (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\ - SNDRV_PCM_RATE_192000) -#define SUPPORTED_MAXBPS 24 -#define SUPPORTED_FORMATS \ - (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) -#endif - -static int nvhdmi_7x_init_2ch(struct hda_codec *codec) -{ - snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_2ch); - return 0; -} - -static int nvhdmi_7x_init_8ch(struct hda_codec *codec) -{ - snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_8ch); - return 0; -} - -static const unsigned int channels_2_6_8[] = { - 2, 6, 8 -}; - -static const unsigned int channels_2_8[] = { - 2, 8 -}; - -static const struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = { - .count = ARRAY_SIZE(channels_2_6_8), - .list = channels_2_6_8, - .mask = 0, -}; - -static const struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = { - .count = ARRAY_SIZE(channels_2_8), - .list = channels_2_8, - .mask = 0, -}; - -static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct hdmi_spec *spec = codec->spec; - const struct snd_pcm_hw_constraint_list *hw_constraints_channels = NULL; - - switch (codec->preset->vendor_id) { - case 0x10de0002: - case 0x10de0003: - case 0x10de0005: - case 0x10de0006: - hw_constraints_channels = &hw_constraints_2_8_channels; - break; - case 0x10de0007: - hw_constraints_channels = &hw_constraints_2_6_8_channels; - break; - default: - break; - } - - if (hw_constraints_channels != NULL) { - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - hw_constraints_channels); - } else { - snd_pcm_hw_constraint_step(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, 2); - } - - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int simple_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct hdmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int simple_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct hdmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static const struct hda_pcm_stream simple_pcm_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .open = simple_playback_pcm_open, - .close = simple_playback_pcm_close, - .prepare = simple_playback_pcm_prepare - }, -}; - -static const struct hda_codec_ops simple_hdmi_patch_ops = { - .build_controls = simple_playback_build_controls, - .build_pcms = simple_playback_build_pcms, - .init = simple_playback_init, - .free = simple_playback_free, - .unsol_event = simple_hdmi_unsol_event, -}; - -static int patch_simple_hdmi(struct hda_codec *codec, - hda_nid_t cvt_nid, hda_nid_t pin_nid) -{ - struct hdmi_spec *spec; - struct hdmi_spec_per_cvt *per_cvt; - struct hdmi_spec_per_pin *per_pin; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - - spec->codec = codec; - codec->spec = spec; - hdmi_array_init(spec, 1); - - spec->multiout.num_dacs = 0; /* no analog */ - spec->multiout.max_channels = 2; - spec->multiout.dig_out_nid = cvt_nid; - spec->num_cvts = 1; - spec->num_pins = 1; - per_pin = snd_array_new(&spec->pins); - per_cvt = snd_array_new(&spec->cvts); - if (!per_pin || !per_cvt) { - simple_playback_free(codec); - return -ENOMEM; - } - per_cvt->cvt_nid = cvt_nid; - per_pin->pin_nid = pin_nid; - spec->pcm_playback = simple_pcm_playback; - - codec->patch_ops = simple_hdmi_patch_ops; - - return 0; -} - -static void nvhdmi_8ch_7x_set_info_frame_parameters(struct hda_codec *codec, - int channels) -{ - unsigned int chanmask; - int chan = channels ? (channels - 1) : 1; - - switch (channels) { - default: - case 0: - case 2: - chanmask = 0x00; - break; - case 4: - chanmask = 0x08; - break; - case 6: - chanmask = 0x0b; - break; - case 8: - chanmask = 0x13; - break; - } - - /* Set the audio infoframe channel allocation and checksum fields. The - * channel count is computed implicitly by the hardware. */ - snd_hda_codec_write(codec, 0x1, 0, - Nv_VERB_SET_Channel_Allocation, chanmask); - - snd_hda_codec_write(codec, 0x1, 0, - Nv_VERB_SET_Info_Frame_Checksum, - (0x71 - chan - chanmask)); -} - -static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct hdmi_spec *spec = codec->spec; - int i; - - snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, - 0, AC_VERB_SET_CHANNEL_STREAMID, 0); - for (i = 0; i < 4; i++) { - /* set the stream id */ - snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, - AC_VERB_SET_CHANNEL_STREAMID, 0); - /* set the stream format */ - snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, - AC_VERB_SET_STREAM_FORMAT, 0); - } - - /* The audio hardware sends a channel count of 0x7 (8ch) when all the - * streams are disabled. */ - nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8); - - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - int chs; - unsigned int dataDCC2, channel_id; - int i; - struct hdmi_spec *spec = codec->spec; - struct hda_spdif_out *spdif; - struct hdmi_spec_per_cvt *per_cvt; - - mutex_lock(&codec->spdif_mutex); - per_cvt = get_cvt(spec, 0); - spdif = snd_hda_spdif_out_of_nid(codec, per_cvt->cvt_nid); - - chs = substream->runtime->channels; - - dataDCC2 = 0x2; - - /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ - if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) - snd_hda_codec_write(codec, - nvhdmi_master_con_nid_7x, - 0, - AC_VERB_SET_DIGI_CONVERT_1, - spdif->ctls & ~AC_DIG1_ENABLE & 0xff); - - /* set the stream id */ - snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, - AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0); - - /* set the stream format */ - snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, - AC_VERB_SET_STREAM_FORMAT, format); - - /* turn on again (if needed) */ - /* enable and set the channel status audio/data flag */ - if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) { - snd_hda_codec_write(codec, - nvhdmi_master_con_nid_7x, - 0, - AC_VERB_SET_DIGI_CONVERT_1, - spdif->ctls & 0xff); - snd_hda_codec_write(codec, - nvhdmi_master_con_nid_7x, - 0, - AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); - } - - for (i = 0; i < 4; i++) { - if (chs == 2) - channel_id = 0; - else - channel_id = i * 2; - - /* turn off SPDIF once; - *otherwise the IEC958 bits won't be updated - */ - if (codec->spdif_status_reset && - (spdif->ctls & AC_DIG1_ENABLE)) - snd_hda_codec_write(codec, - nvhdmi_con_nids_7x[i], - 0, - AC_VERB_SET_DIGI_CONVERT_1, - spdif->ctls & ~AC_DIG1_ENABLE & 0xff); - /* set the stream id */ - snd_hda_codec_write(codec, - nvhdmi_con_nids_7x[i], - 0, - AC_VERB_SET_CHANNEL_STREAMID, - (stream_tag << 4) | channel_id); - /* set the stream format */ - snd_hda_codec_write(codec, - nvhdmi_con_nids_7x[i], - 0, - AC_VERB_SET_STREAM_FORMAT, - format); - /* turn on again (if needed) */ - /* enable and set the channel status audio/data flag */ - if (codec->spdif_status_reset && - (spdif->ctls & AC_DIG1_ENABLE)) { - snd_hda_codec_write(codec, - nvhdmi_con_nids_7x[i], - 0, - AC_VERB_SET_DIGI_CONVERT_1, - spdif->ctls & 0xff); - snd_hda_codec_write(codec, - nvhdmi_con_nids_7x[i], - 0, - AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); - } - } - - nvhdmi_8ch_7x_set_info_frame_parameters(codec, chs); - - mutex_unlock(&codec->spdif_mutex); - return 0; -} - -static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - .nid = nvhdmi_master_con_nid_7x, - .rates = SUPPORTED_RATES, - .maxbps = SUPPORTED_MAXBPS, - .formats = SUPPORTED_FORMATS, - .ops = { - .open = simple_playback_pcm_open, - .close = nvhdmi_8ch_7x_pcm_close, - .prepare = nvhdmi_8ch_7x_pcm_prepare - }, -}; - -static int patch_nvhdmi_2ch(struct hda_codec *codec) -{ - struct hdmi_spec *spec; - int err = patch_simple_hdmi(codec, nvhdmi_master_con_nid_7x, - nvhdmi_master_pin_nid_7x); - if (err < 0) - return err; - - codec->patch_ops.init = nvhdmi_7x_init_2ch; - /* override the PCM rates, etc, as the codec doesn't give full list */ - spec = codec->spec; - spec->pcm_playback.rates = SUPPORTED_RATES; - spec->pcm_playback.maxbps = SUPPORTED_MAXBPS; - spec->pcm_playback.formats = SUPPORTED_FORMATS; - spec->nv_dp_workaround = true; - return 0; -} - -static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - int err = simple_playback_build_pcms(codec); - if (!err) { - struct hda_pcm *info = get_pcm_rec(spec, 0); - info->own_chmap = true; - } - return err; -} - -static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - struct hda_pcm *info; - struct snd_pcm_chmap *chmap; - int err; - - err = simple_playback_build_controls(codec); - if (err < 0) - return err; - - /* add channel maps */ - info = get_pcm_rec(spec, 0); - err = snd_pcm_add_chmap_ctls(info->pcm, - SNDRV_PCM_STREAM_PLAYBACK, - snd_pcm_alt_chmaps, 8, 0, &chmap); - if (err < 0) - return err; - switch (codec->preset->vendor_id) { - case 0x10de0002: - case 0x10de0003: - case 0x10de0005: - case 0x10de0006: - chmap->channel_mask = (1U << 2) | (1U << 8); - break; - case 0x10de0007: - chmap->channel_mask = (1U << 2) | (1U << 6) | (1U << 8); - } - return 0; -} - -static int patch_nvhdmi_8ch_7x(struct hda_codec *codec) -{ - struct hdmi_spec *spec; - int err = patch_nvhdmi_2ch(codec); - if (err < 0) - return err; - spec = codec->spec; - spec->multiout.max_channels = 8; - spec->pcm_playback = nvhdmi_pcm_playback_8ch_7x; - codec->patch_ops.init = nvhdmi_7x_init_8ch; - codec->patch_ops.build_pcms = nvhdmi_7x_8ch_build_pcms; - codec->patch_ops.build_controls = nvhdmi_7x_8ch_build_controls; - - /* Initialize the audio infoframe channel mask and checksum to something - * valid */ - nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8); - - return 0; -} - -/* - * NVIDIA codecs ignore ASP mapping for 2ch - confirmed on: - * - 0x10de0015 - * - 0x10de0040 - */ -static int nvhdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap, - struct hdac_cea_channel_speaker_allocation *cap, int channels) -{ - if (cap->ca_index == 0x00 && channels == 2) - return SNDRV_CTL_TLVT_CHMAP_FIXED; - - /* If the speaker allocation matches the channel count, it is OK. */ - if (cap->channels != channels) - return -1; - - /* all channels are remappable freely */ - return SNDRV_CTL_TLVT_CHMAP_VAR; -} - -static int nvhdmi_chmap_validate(struct hdac_chmap *chmap, - int ca, int chs, unsigned char *map) -{ - if (ca == 0x00 && (map[0] != SNDRV_CHMAP_FL || map[1] != SNDRV_CHMAP_FR)) - return -EINVAL; - - return 0; -} - -/* map from pin NID to port; port is 0-based */ -/* for Nvidia: assume widget NID starting from 4, with step 1 (4, 5, 6, ...) */ -static int nvhdmi_pin2port(void *audio_ptr, int pin_nid) -{ - return pin_nid - 4; -} - -/* reverse-map from port to pin NID: see above */ -static int nvhdmi_port2pin(struct hda_codec *codec, int port) -{ - return port + 4; -} - -static const struct drm_audio_component_audio_ops nvhdmi_audio_ops = { - .pin2port = nvhdmi_pin2port, - .pin_eld_notify = generic_acomp_pin_eld_notify, - .master_bind = generic_acomp_master_bind, - .master_unbind = generic_acomp_master_unbind, -}; - -static int patch_nvhdmi(struct hda_codec *codec) -{ - struct hdmi_spec *spec; - int err; - - err = alloc_generic_hdmi(codec); - if (err < 0) - return err; - codec->dp_mst = true; - - spec = codec->spec; - - err = hdmi_parse_codec(codec); - if (err < 0) { - generic_spec_free(codec); - return err; - } - - generic_hdmi_init_per_pins(codec); - - spec->dyn_pin_out = true; - - spec->chmap.ops.chmap_cea_alloc_validate_get_type = - nvhdmi_chmap_cea_alloc_validate_get_type; - spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate; - spec->nv_dp_workaround = true; - - codec->link_down_at_suspend = 1; - - generic_acomp_init(codec, &nvhdmi_audio_ops, nvhdmi_port2pin); - - return 0; -} - -static int patch_nvhdmi_legacy(struct hda_codec *codec) -{ - struct hdmi_spec *spec; - int err; - - err = patch_generic_hdmi(codec); - if (err) - return err; - - spec = codec->spec; - spec->dyn_pin_out = true; - - spec->chmap.ops.chmap_cea_alloc_validate_get_type = - nvhdmi_chmap_cea_alloc_validate_get_type; - spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate; - spec->nv_dp_workaround = true; - - codec->link_down_at_suspend = 1; - - return 0; -} - -/* - * The HDA codec on NVIDIA Tegra contains two scratch registers that are - * accessed using vendor-defined verbs. These registers can be used for - * interoperability between the HDA and HDMI drivers. - */ - -/* Audio Function Group node */ -#define NVIDIA_AFG_NID 0x01 - -/* - * The SCRATCH0 register is used to notify the HDMI codec of changes in audio - * format. On Tegra, bit 31 is used as a trigger that causes an interrupt to - * be raised in the HDMI codec. The remainder of the bits is arbitrary. This - * implementation stores the HDA format (see AC_FMT_*) in bits [15:0] and an - * additional bit (at position 30) to signal the validity of the format. - * - * | 31 | 30 | 29 16 | 15 0 | - * +---------+-------+--------+--------+ - * | TRIGGER | VALID | UNUSED | FORMAT | - * +-----------------------------------| - * - * Note that for the trigger bit to take effect it needs to change value - * (i.e. it needs to be toggled). The trigger bit is not applicable from - * TEGRA234 chip onwards, as new verb id 0xf80 will be used for interrupt - * trigger to hdmi. - */ -#define NVIDIA_SET_HOST_INTR 0xf80 -#define NVIDIA_GET_SCRATCH0 0xfa6 -#define NVIDIA_SET_SCRATCH0_BYTE0 0xfa7 -#define NVIDIA_SET_SCRATCH0_BYTE1 0xfa8 -#define NVIDIA_SET_SCRATCH0_BYTE2 0xfa9 -#define NVIDIA_SET_SCRATCH0_BYTE3 0xfaa -#define NVIDIA_SCRATCH_TRIGGER (1 << 7) -#define NVIDIA_SCRATCH_VALID (1 << 6) - -#define NVIDIA_GET_SCRATCH1 0xfab -#define NVIDIA_SET_SCRATCH1_BYTE0 0xfac -#define NVIDIA_SET_SCRATCH1_BYTE1 0xfad -#define NVIDIA_SET_SCRATCH1_BYTE2 0xfae -#define NVIDIA_SET_SCRATCH1_BYTE3 0xfaf - -/* - * The format parameter is the HDA audio format (see AC_FMT_*). If set to 0, - * the format is invalidated so that the HDMI codec can be disabled. - */ -static void tegra_hdmi_set_format(struct hda_codec *codec, - hda_nid_t cvt_nid, - unsigned int format) -{ - unsigned int value; - unsigned int nid = NVIDIA_AFG_NID; - struct hdmi_spec *spec = codec->spec; - - /* - * Tegra HDA codec design from TEGRA234 chip onwards support DP MST. - * This resulted in moving scratch registers from audio function - * group to converter widget context. So CVT NID should be used for - * scratch register read/write for DP MST supported Tegra HDA codec. - */ - if (codec->dp_mst) - nid = cvt_nid; - - /* bits [31:30] contain the trigger and valid bits */ - value = snd_hda_codec_read(codec, nid, 0, - NVIDIA_GET_SCRATCH0, 0); - value = (value >> 24) & 0xff; - - /* bits [15:0] are used to store the HDA format */ - snd_hda_codec_write(codec, nid, 0, - NVIDIA_SET_SCRATCH0_BYTE0, - (format >> 0) & 0xff); - snd_hda_codec_write(codec, nid, 0, - NVIDIA_SET_SCRATCH0_BYTE1, - (format >> 8) & 0xff); - - /* bits [16:24] are unused */ - snd_hda_codec_write(codec, nid, 0, - NVIDIA_SET_SCRATCH0_BYTE2, 0); - - /* - * Bit 30 signals that the data is valid and hence that HDMI audio can - * be enabled. - */ - if (format == 0) - value &= ~NVIDIA_SCRATCH_VALID; - else - value |= NVIDIA_SCRATCH_VALID; - - if (spec->hdmi_intr_trig_ctrl) { - /* - * For Tegra HDA Codec design from TEGRA234 onwards, the - * Interrupt to hdmi driver is triggered by writing - * non-zero values to verb 0xF80 instead of 31st bit of - * scratch register. - */ - snd_hda_codec_write(codec, nid, 0, - NVIDIA_SET_SCRATCH0_BYTE3, value); - snd_hda_codec_write(codec, nid, 0, - NVIDIA_SET_HOST_INTR, 0x1); - } else { - /* - * Whenever the 31st trigger bit is toggled, an interrupt is raised - * in the HDMI codec. The HDMI driver will use that as trigger - * to update its configuration. - */ - value ^= NVIDIA_SCRATCH_TRIGGER; - - snd_hda_codec_write(codec, nid, 0, - NVIDIA_SET_SCRATCH0_BYTE3, value); - } -} - -static int tegra_hdmi_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - int err; - - err = generic_hdmi_playback_pcm_prepare(hinfo, codec, stream_tag, - format, substream); - if (err < 0) - return err; - - /* notify the HDMI codec of the format change */ - tegra_hdmi_set_format(codec, hinfo->nid, format); - - return 0; -} - -static int tegra_hdmi_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - /* invalidate the format in the HDMI codec */ - tegra_hdmi_set_format(codec, hinfo->nid, 0); - - return generic_hdmi_playback_pcm_cleanup(hinfo, codec, substream); -} - -static struct hda_pcm *hda_find_pcm_by_type(struct hda_codec *codec, int type) -{ - struct hdmi_spec *spec = codec->spec; - unsigned int i; - - for (i = 0; i < spec->num_pins; i++) { - struct hda_pcm *pcm = get_pcm_rec(spec, i); - - if (pcm->pcm_type == type) - return pcm; - } - - return NULL; -} - -static int tegra_hdmi_build_pcms(struct hda_codec *codec) -{ - struct hda_pcm_stream *stream; - struct hda_pcm *pcm; - int err; - - err = generic_hdmi_build_pcms(codec); - if (err < 0) - return err; - - pcm = hda_find_pcm_by_type(codec, HDA_PCM_TYPE_HDMI); - if (!pcm) - return -ENODEV; - - /* - * Override ->prepare() and ->cleanup() operations to notify the HDMI - * codec about format changes. - */ - stream = &pcm->stream[SNDRV_PCM_STREAM_PLAYBACK]; - stream->ops.prepare = tegra_hdmi_pcm_prepare; - stream->ops.cleanup = tegra_hdmi_pcm_cleanup; - - return 0; -} - -static int tegra_hdmi_init(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - int i, err; - - err = hdmi_parse_codec(codec); - if (err < 0) { - generic_spec_free(codec); - return err; - } - - for (i = 0; i < spec->num_cvts; i++) - snd_hda_codec_write(codec, spec->cvt_nids[i], 0, - AC_VERB_SET_DIGI_CONVERT_1, - AC_DIG1_ENABLE); - - generic_hdmi_init_per_pins(codec); - - codec->depop_delay = 10; - codec->patch_ops.build_pcms = tegra_hdmi_build_pcms; - spec->chmap.ops.chmap_cea_alloc_validate_get_type = - nvhdmi_chmap_cea_alloc_validate_get_type; - spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate; - - spec->chmap.ops.chmap_cea_alloc_validate_get_type = - nvhdmi_chmap_cea_alloc_validate_get_type; - spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate; - spec->nv_dp_workaround = true; - - return 0; -} - -static int patch_tegra_hdmi(struct hda_codec *codec) -{ - int err; - - err = alloc_generic_hdmi(codec); - if (err < 0) - return err; - - return tegra_hdmi_init(codec); -} - -static int patch_tegra234_hdmi(struct hda_codec *codec) -{ - struct hdmi_spec *spec; - int err; - - err = alloc_generic_hdmi(codec); - if (err < 0) - return err; - - codec->dp_mst = true; - spec = codec->spec; - spec->dyn_pin_out = true; - spec->hdmi_intr_trig_ctrl = true; - - return tegra_hdmi_init(codec); -} - -/* - * ATI/AMD-specific implementations - */ - -#define is_amdhdmi_rev3_or_later(codec) \ - ((codec)->core.vendor_id == 0x1002aa01 && \ - ((codec)->core.revision_id & 0xff00) >= 0x0300) -#define has_amd_full_remap_support(codec) is_amdhdmi_rev3_or_later(codec) - -/* ATI/AMD specific HDA pin verbs, see the AMD HDA Verbs specification */ -#define ATI_VERB_SET_CHANNEL_ALLOCATION 0x771 -#define ATI_VERB_SET_DOWNMIX_INFO 0x772 -#define ATI_VERB_SET_MULTICHANNEL_01 0x777 -#define ATI_VERB_SET_MULTICHANNEL_23 0x778 -#define ATI_VERB_SET_MULTICHANNEL_45 0x779 -#define ATI_VERB_SET_MULTICHANNEL_67 0x77a -#define ATI_VERB_SET_HBR_CONTROL 0x77c -#define ATI_VERB_SET_MULTICHANNEL_1 0x785 -#define ATI_VERB_SET_MULTICHANNEL_3 0x786 -#define ATI_VERB_SET_MULTICHANNEL_5 0x787 -#define ATI_VERB_SET_MULTICHANNEL_7 0x788 -#define ATI_VERB_SET_MULTICHANNEL_MODE 0x789 -#define ATI_VERB_GET_CHANNEL_ALLOCATION 0xf71 -#define ATI_VERB_GET_DOWNMIX_INFO 0xf72 -#define ATI_VERB_GET_MULTICHANNEL_01 0xf77 -#define ATI_VERB_GET_MULTICHANNEL_23 0xf78 -#define ATI_VERB_GET_MULTICHANNEL_45 0xf79 -#define ATI_VERB_GET_MULTICHANNEL_67 0xf7a -#define ATI_VERB_GET_HBR_CONTROL 0xf7c -#define ATI_VERB_GET_MULTICHANNEL_1 0xf85 -#define ATI_VERB_GET_MULTICHANNEL_3 0xf86 -#define ATI_VERB_GET_MULTICHANNEL_5 0xf87 -#define ATI_VERB_GET_MULTICHANNEL_7 0xf88 -#define ATI_VERB_GET_MULTICHANNEL_MODE 0xf89 - -/* AMD specific HDA cvt verbs */ -#define ATI_VERB_SET_RAMP_RATE 0x770 -#define ATI_VERB_GET_RAMP_RATE 0xf70 - -#define ATI_OUT_ENABLE 0x1 - -#define ATI_MULTICHANNEL_MODE_PAIRED 0 -#define ATI_MULTICHANNEL_MODE_SINGLE 1 - -#define ATI_HBR_CAPABLE 0x01 -#define ATI_HBR_ENABLE 0x10 - -static int atihdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid, - int dev_id, unsigned char *buf, int *eld_size) -{ - WARN_ON(dev_id != 0); - /* call hda_eld.c ATI/AMD-specific function */ - return snd_hdmi_get_eld_ati(codec, nid, buf, eld_size, - is_amdhdmi_rev3_or_later(codec)); -} - -static void atihdmi_pin_setup_infoframe(struct hda_codec *codec, - hda_nid_t pin_nid, int dev_id, int ca, - int active_channels, int conn_type) -{ - WARN_ON(dev_id != 0); - snd_hda_codec_write(codec, pin_nid, 0, ATI_VERB_SET_CHANNEL_ALLOCATION, ca); -} - -static int atihdmi_paired_swap_fc_lfe(int pos) -{ - /* - * ATI/AMD have automatic FC/LFE swap built-in - * when in pairwise mapping mode. - */ - - switch (pos) { - /* see channel_allocations[].speakers[] */ - case 2: return 3; - case 3: return 2; - default: break; - } - - return pos; -} - -static int atihdmi_paired_chmap_validate(struct hdac_chmap *chmap, - int ca, int chs, unsigned char *map) -{ - struct hdac_cea_channel_speaker_allocation *cap; - int i, j; - - /* check that only channel pairs need to be remapped on old pre-rev3 ATI/AMD */ - - cap = snd_hdac_get_ch_alloc_from_ca(ca); - for (i = 0; i < chs; ++i) { - int mask = snd_hdac_chmap_to_spk_mask(map[i]); - bool ok = false; - bool companion_ok = false; - - if (!mask) - continue; - - for (j = 0 + i % 2; j < 8; j += 2) { - int chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j); - if (cap->speakers[chan_idx] == mask) { - /* channel is in a supported position */ - ok = true; - - if (i % 2 == 0 && i + 1 < chs) { - /* even channel, check the odd companion */ - int comp_chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j + 1); - int comp_mask_req = snd_hdac_chmap_to_spk_mask(map[i+1]); - int comp_mask_act = cap->speakers[comp_chan_idx]; - - if (comp_mask_req == comp_mask_act) - companion_ok = true; - else - return -EINVAL; - } - break; - } - } - - if (!ok) - return -EINVAL; - - if (companion_ok) - i++; /* companion channel already checked */ - } - - return 0; -} - -static int atihdmi_pin_set_slot_channel(struct hdac_device *hdac, - hda_nid_t pin_nid, int hdmi_slot, int stream_channel) -{ - struct hda_codec *codec = hdac_to_hda_codec(hdac); - int verb; - int ati_channel_setup = 0; - - if (hdmi_slot > 7) - return -EINVAL; - - if (!has_amd_full_remap_support(codec)) { - hdmi_slot = atihdmi_paired_swap_fc_lfe(hdmi_slot); - - /* In case this is an odd slot but without stream channel, do not - * disable the slot since the corresponding even slot could have a - * channel. In case neither have a channel, the slot pair will be - * disabled when this function is called for the even slot. */ - if (hdmi_slot % 2 != 0 && stream_channel == 0xf) - return 0; - - hdmi_slot -= hdmi_slot % 2; - - if (stream_channel != 0xf) - stream_channel -= stream_channel % 2; - } - - verb = ATI_VERB_SET_MULTICHANNEL_01 + hdmi_slot/2 + (hdmi_slot % 2) * 0x00e; - - /* ati_channel_setup format: [7..4] = stream_channel_id, [1] = mute, [0] = enable */ - - if (stream_channel != 0xf) - ati_channel_setup = (stream_channel << 4) | ATI_OUT_ENABLE; - - return snd_hda_codec_write(codec, pin_nid, 0, verb, ati_channel_setup); -} - -static int atihdmi_pin_get_slot_channel(struct hdac_device *hdac, - hda_nid_t pin_nid, int asp_slot) -{ - struct hda_codec *codec = hdac_to_hda_codec(hdac); - bool was_odd = false; - int ati_asp_slot = asp_slot; - int verb; - int ati_channel_setup; - - if (asp_slot > 7) - return -EINVAL; - - if (!has_amd_full_remap_support(codec)) { - ati_asp_slot = atihdmi_paired_swap_fc_lfe(asp_slot); - if (ati_asp_slot % 2 != 0) { - ati_asp_slot -= 1; - was_odd = true; - } - } - - verb = ATI_VERB_GET_MULTICHANNEL_01 + ati_asp_slot/2 + (ati_asp_slot % 2) * 0x00e; - - ati_channel_setup = snd_hda_codec_read(codec, pin_nid, 0, verb, 0); - - if (!(ati_channel_setup & ATI_OUT_ENABLE)) - return 0xf; - - return ((ati_channel_setup & 0xf0) >> 4) + !!was_odd; -} - -static int atihdmi_paired_chmap_cea_alloc_validate_get_type( - struct hdac_chmap *chmap, - struct hdac_cea_channel_speaker_allocation *cap, - int channels) -{ - int c; - - /* - * Pre-rev3 ATI/AMD codecs operate in a paired channel mode, so - * we need to take that into account (a single channel may take 2 - * channel slots if we need to carry a silent channel next to it). - * On Rev3+ AMD codecs this function is not used. - */ - int chanpairs = 0; - - /* We only produce even-numbered channel count TLVs */ - if ((channels % 2) != 0) - return -1; - - for (c = 0; c < 7; c += 2) { - if (cap->speakers[c] || cap->speakers[c+1]) - chanpairs++; - } - - if (chanpairs * 2 != channels) - return -1; - - return SNDRV_CTL_TLVT_CHMAP_PAIRED; -} - -static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap, - struct hdac_cea_channel_speaker_allocation *cap, - unsigned int *chmap, int channels) -{ - /* produce paired maps for pre-rev3 ATI/AMD codecs */ - int count = 0; - int c; - - for (c = 7; c >= 0; c--) { - int chan = 7 - atihdmi_paired_swap_fc_lfe(7 - c); - int spk = cap->speakers[chan]; - if (!spk) { - /* add N/A channel if the companion channel is occupied */ - if (cap->speakers[chan + (chan % 2 ? -1 : 1)]) - chmap[count++] = SNDRV_CHMAP_NA; - - continue; - } - - chmap[count++] = snd_hdac_spk_to_chmap(spk); - } - - WARN_ON(count != channels); -} - -static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid, - int dev_id, bool hbr) -{ - int hbr_ctl, hbr_ctl_new; - - WARN_ON(dev_id != 0); - - hbr_ctl = snd_hda_codec_read(codec, pin_nid, 0, ATI_VERB_GET_HBR_CONTROL, 0); - if (hbr_ctl >= 0 && (hbr_ctl & ATI_HBR_CAPABLE)) { - if (hbr) - hbr_ctl_new = hbr_ctl | ATI_HBR_ENABLE; - else - hbr_ctl_new = hbr_ctl & ~ATI_HBR_ENABLE; - - codec_dbg(codec, - "atihdmi_pin_hbr_setup: NID=0x%x, %shbr-ctl=0x%x\n", - pin_nid, - hbr_ctl == hbr_ctl_new ? "" : "new-", - hbr_ctl_new); - - if (hbr_ctl != hbr_ctl_new) - snd_hda_codec_write(codec, pin_nid, 0, - ATI_VERB_SET_HBR_CONTROL, - hbr_ctl_new); - - } else if (hbr) - return -EINVAL; - - return 0; -} - -static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, - hda_nid_t pin_nid, int dev_id, - u32 stream_tag, int format) -{ - if (is_amdhdmi_rev3_or_later(codec)) { - int ramp_rate = 180; /* default as per AMD spec */ - /* disable ramp-up/down for non-pcm as per AMD spec */ - if (format & AC_FMT_TYPE_NON_PCM) - ramp_rate = 0; - - snd_hda_codec_write(codec, cvt_nid, 0, ATI_VERB_SET_RAMP_RATE, ramp_rate); - } - - return hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id, - stream_tag, format); -} - - -static int atihdmi_init(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - int pin_idx, err; - - err = generic_hdmi_init(codec); - - if (err) - return err; - - for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); - - /* make sure downmix information in infoframe is zero */ - snd_hda_codec_write(codec, per_pin->pin_nid, 0, ATI_VERB_SET_DOWNMIX_INFO, 0); - - /* enable channel-wise remap mode if supported */ - if (has_amd_full_remap_support(codec)) - snd_hda_codec_write(codec, per_pin->pin_nid, 0, - ATI_VERB_SET_MULTICHANNEL_MODE, - ATI_MULTICHANNEL_MODE_SINGLE); - } - codec->auto_runtime_pm = 1; - - return 0; -} - -/* map from pin NID to port; port is 0-based */ -/* for AMD: assume widget NID starting from 3, with step 2 (3, 5, 7, ...) */ -static int atihdmi_pin2port(void *audio_ptr, int pin_nid) -{ - return pin_nid / 2 - 1; -} - -/* reverse-map from port to pin NID: see above */ -static int atihdmi_port2pin(struct hda_codec *codec, int port) -{ - return port * 2 + 3; -} - -static const struct drm_audio_component_audio_ops atihdmi_audio_ops = { - .pin2port = atihdmi_pin2port, - .pin_eld_notify = generic_acomp_pin_eld_notify, - .master_bind = generic_acomp_master_bind, - .master_unbind = generic_acomp_master_unbind, -}; - -static int patch_atihdmi(struct hda_codec *codec) -{ - struct hdmi_spec *spec; - struct hdmi_spec_per_cvt *per_cvt; - int err, cvt_idx; - - err = patch_generic_hdmi(codec); - - if (err) - return err; - - codec->patch_ops.init = atihdmi_init; - - spec = codec->spec; - - spec->static_pcm_mapping = true; - - spec->ops.pin_get_eld = atihdmi_pin_get_eld; - spec->ops.pin_setup_infoframe = atihdmi_pin_setup_infoframe; - spec->ops.pin_hbr_setup = atihdmi_pin_hbr_setup; - spec->ops.setup_stream = atihdmi_setup_stream; - - spec->chmap.ops.pin_get_slot_channel = atihdmi_pin_get_slot_channel; - spec->chmap.ops.pin_set_slot_channel = atihdmi_pin_set_slot_channel; - - if (!has_amd_full_remap_support(codec)) { - /* override to ATI/AMD-specific versions with pairwise mapping */ - spec->chmap.ops.chmap_cea_alloc_validate_get_type = - atihdmi_paired_chmap_cea_alloc_validate_get_type; - spec->chmap.ops.cea_alloc_to_tlv_chmap = - atihdmi_paired_cea_alloc_to_tlv_chmap; - spec->chmap.ops.chmap_validate = atihdmi_paired_chmap_validate; - } - - /* ATI/AMD converters do not advertise all of their capabilities */ - for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { - per_cvt = get_cvt(spec, cvt_idx); - per_cvt->channels_max = max(per_cvt->channels_max, 8u); - per_cvt->rates |= SUPPORTED_RATES; - per_cvt->formats |= SUPPORTED_FORMATS; - per_cvt->maxbps = max(per_cvt->maxbps, 24u); - } - - spec->chmap.channels_max = max(spec->chmap.channels_max, 8u); - - /* AMD GPUs have neither EPSS nor CLKSTOP bits, hence preventing - * the link-down as is. Tell the core to allow it. - */ - codec->link_down_at_suspend = 1; - - generic_acomp_init(codec, &atihdmi_audio_ops, atihdmi_port2pin); - - return 0; -} - -/* VIA HDMI Implementation */ -#define VIAHDMI_CVT_NID 0x02 /* audio converter1 */ -#define VIAHDMI_PIN_NID 0x03 /* HDMI output pin1 */ - -static int patch_via_hdmi(struct hda_codec *codec) -{ - return patch_simple_hdmi(codec, VIAHDMI_CVT_NID, VIAHDMI_PIN_NID); -} - static int patch_gf_hdmi(struct hda_codec *codec) { int err; @@ -4509,125 +2367,15 @@ static int patch_gf_hdmi(struct hda_codec *codec) */ static const struct hda_device_id snd_hda_id_hdmi[] = { HDA_CODEC_ENTRY(0x00147a47, "Loongson HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x1002793c, "RS600 HDMI", patch_atihdmi), -HDA_CODEC_ENTRY(0x10027919, "RS600 HDMI", patch_atihdmi), -HDA_CODEC_ENTRY(0x1002791a, "RS690/780 HDMI", patch_atihdmi), -HDA_CODEC_ENTRY(0x1002aa01, "R6xx HDMI", patch_atihdmi), HDA_CODEC_ENTRY(0x10951390, "SiI1390 HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x10951392, "SiI1392 HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x17e80047, "Chrontel HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x10de0001, "MCP73 HDMI", patch_nvhdmi_2ch), -HDA_CODEC_ENTRY(0x10de0002, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), -HDA_CODEC_ENTRY(0x10de0003, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), -HDA_CODEC_ENTRY(0x10de0004, "GPU 04 HDMI", patch_nvhdmi_8ch_7x), -HDA_CODEC_ENTRY(0x10de0005, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), -HDA_CODEC_ENTRY(0x10de0006, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), -HDA_CODEC_ENTRY(0x10de0007, "MCP79/7A HDMI", patch_nvhdmi_8ch_7x), -HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de000d, "GPU 0d HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0010, "GPU 10 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0011, "GPU 11 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0012, "GPU 12 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0013, "GPU 13 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0014, "GPU 14 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0015, "GPU 15 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0016, "GPU 16 HDMI/DP", patch_nvhdmi_legacy), -/* 17 is known to be absent */ -HDA_CODEC_ENTRY(0x10de0018, "GPU 18 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0019, "GPU 19 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de001a, "GPU 1a HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de001b, "GPU 1b HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de001c, "GPU 1c HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0020, "Tegra30 HDMI", patch_tegra_hdmi), -HDA_CODEC_ENTRY(0x10de0022, "Tegra114 HDMI", patch_tegra_hdmi), -HDA_CODEC_ENTRY(0x10de0028, "Tegra124 HDMI", patch_tegra_hdmi), -HDA_CODEC_ENTRY(0x10de0029, "Tegra210 HDMI/DP", patch_tegra_hdmi), -HDA_CODEC_ENTRY(0x10de002d, "Tegra186 HDMI/DP0", patch_tegra_hdmi), -HDA_CODEC_ENTRY(0x10de002e, "Tegra186 HDMI/DP1", patch_tegra_hdmi), -HDA_CODEC_ENTRY(0x10de002f, "Tegra194 HDMI/DP2", patch_tegra_hdmi), -HDA_CODEC_ENTRY(0x10de0030, "Tegra194 HDMI/DP3", patch_tegra_hdmi), -HDA_CODEC_ENTRY(0x10de0031, "Tegra234 HDMI/DP", patch_tegra234_hdmi), -HDA_CODEC_ENTRY(0x10de0033, "SoC 33 HDMI/DP", patch_tegra234_hdmi), -HDA_CODEC_ENTRY(0x10de0034, "Tegra264 HDMI/DP", patch_tegra234_hdmi), -HDA_CODEC_ENTRY(0x10de0035, "SoC 35 HDMI/DP", patch_tegra234_hdmi), -HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0043, "GPU 43 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0044, "GPU 44 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0045, "GPU 45 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0050, "GPU 50 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0051, "GPU 51 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0052, "GPU 52 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0060, "GPU 60 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0061, "GPU 61 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0062, "GPU 62 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0067, "MCP67 HDMI", patch_nvhdmi_2ch), -HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0073, "GPU 73 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0074, "GPU 74 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0076, "GPU 76 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de007b, "GPU 7b HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de007c, "GPU 7c HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de007e, "GPU 7e HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0081, "GPU 81 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0084, "GPU 84 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0090, "GPU 90 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0091, "GPU 91 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0092, "GPU 92 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0093, "GPU 93 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0094, "GPU 94 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0095, "GPU 95 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0097, "GPU 97 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0098, "GPU 98 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0099, "GPU 99 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de009a, "GPU 9a HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de009b, "GPU 9b HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de009c, "GPU 9c HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de009d, "GPU 9d HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de009e, "GPU 9e HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de009f, "GPU 9f HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00a0, "GPU a0 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00a1, "GPU a1 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00a3, "GPU a3 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00a4, "GPU a4 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00a5, "GPU a5 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00a6, "GPU a6 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00a7, "GPU a7 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00a8, "GPU a8 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00a9, "GPU a9 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00aa, "GPU aa HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00ab, "GPU ab HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00ad, "GPU ad HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00ae, "GPU ae HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00af, "GPU af HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00b0, "GPU b0 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00b1, "GPU b1 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00c0, "GPU c0 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00c1, "GPU c1 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00c3, "GPU c3 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00c4, "GPU c4 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00c5, "GPU c5 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI", patch_nvhdmi_2ch), -HDA_CODEC_ENTRY(0x10de8067, "MCP67/68 HDMI", patch_nvhdmi_2ch), HDA_CODEC_ENTRY(0x67663d82, "Arise 82 HDMI/DP", patch_gf_hdmi), HDA_CODEC_ENTRY(0x67663d83, "Arise 83 HDMI/DP", patch_gf_hdmi), HDA_CODEC_ENTRY(0x67663d84, "Arise 84 HDMI/DP", patch_gf_hdmi), HDA_CODEC_ENTRY(0x67663d85, "Arise 85 HDMI/DP", patch_gf_hdmi), HDA_CODEC_ENTRY(0x67663d86, "Arise 86 HDMI/DP", patch_gf_hdmi), HDA_CODEC_ENTRY(0x67663d87, "Arise 87 HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP", patch_via_hdmi), -HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP", patch_via_hdmi), HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP", patch_generic_hdmi), HDA_CODEC_ENTRY(0x11069f85, "VX11 HDMI/DP", patch_generic_hdmi), HDA_CODEC_ENTRY(0x1d179f86, "ZX-100S HDMI/DP", patch_gf_hdmi), @@ -4641,40 +2389,10 @@ HDA_CODEC_ENTRY(0x1d179f8d, "KX-6000G HDMI/DP", patch_gf_hdmi), HDA_CODEC_ENTRY(0x1d179f8e, "KX-7000 HDMI/DP", patch_gf_hdmi), HDA_CODEC_ENTRY(0x1d179f8f, "KX-7000 HDMI/DP", patch_gf_hdmi), HDA_CODEC_ENTRY(0x1d179f90, "KX-7000 HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x80860054, "IbexPeak HDMI", patch_i915_cpt_hdmi), -HDA_CODEC_ENTRY(0x80862800, "Geminilake HDMI", patch_i915_glk_hdmi), HDA_CODEC_ENTRY(0x80862801, "Bearlake HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862802, "Cantiga HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862803, "Eaglelake HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x80862804, "IbexPeak HDMI", patch_i915_cpt_hdmi), -HDA_CODEC_ENTRY(0x80862805, "CougarPoint HDMI", patch_i915_cpt_hdmi), -HDA_CODEC_ENTRY(0x80862806, "PantherPoint HDMI", patch_i915_cpt_hdmi), -HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI", patch_i915_hsw_hdmi), -HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_i915_hsw_hdmi), -HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_i915_hsw_hdmi), -HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_i915_hsw_hdmi), -HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_i915_hsw_hdmi), -HDA_CODEC_ENTRY(0x8086280c, "Cannonlake HDMI", patch_i915_glk_hdmi), -HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_glk_hdmi), -HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI", patch_i915_icl_hdmi), -HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI", patch_i915_tgl_hdmi), -HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI", patch_i915_tgl_hdmi), -HDA_CODEC_ENTRY(0x80862815, "Alderlake HDMI", patch_i915_tgl_hdmi), -HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI", patch_i915_tgl_hdmi), -HDA_CODEC_ENTRY(0x80862818, "Raptorlake HDMI", patch_i915_tgl_hdmi), -HDA_CODEC_ENTRY(0x80862819, "DG2 HDMI", patch_i915_tgl_hdmi), -HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi), -HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI", patch_i915_icl_hdmi), -HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_adlp_hdmi), -HDA_CODEC_ENTRY(0x8086281d, "Meteor Lake HDMI", patch_i915_adlp_hdmi), -HDA_CODEC_ENTRY(0x8086281e, "Battlemage HDMI", patch_i915_adlp_hdmi), -HDA_CODEC_ENTRY(0x8086281f, "Raptor Lake P HDMI", patch_i915_adlp_hdmi), -HDA_CODEC_ENTRY(0x80862820, "Lunar Lake HDMI", patch_i915_adlp_hdmi), -HDA_CODEC_ENTRY(0x80862822, "Panther Lake HDMI", patch_i915_adlp_hdmi), -HDA_CODEC_ENTRY(0x80862823, "Wildcat Lake HDMI", patch_i915_adlp_hdmi), HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi), -HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi), HDA_CODEC_ENTRY(0x808629fb, "Crestline HDMI", patch_generic_hdmi), /* special ID for generic HDMI */ HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC_HDMI, "Generic HDMI", patch_generic_hdmi), @@ -4684,9 +2402,6 @@ MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_hdmi); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("HDMI HD-audio codec"); -MODULE_ALIAS("snd-hda-codec-intelhdmi"); -MODULE_ALIAS("snd-hda-codec-nvhdmi"); -MODULE_ALIAS("snd-hda-codec-atihdmi"); static struct hda_codec_driver hdmi_driver = { .id = snd_hda_id_hdmi, diff --git a/sound/hda/codecs/hdmi/hdmi_local.h b/sound/hda/codecs/hdmi/hdmi_local.h new file mode 100644 index 000000000000..96351bebbc1b --- /dev/null +++ b/sound/hda/codecs/hdmi/hdmi_local.h @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * HD-audio HDMI codec driver + */ + +#ifndef __HDA_HDMI_LOCAL_H +#define __HDA_HDMI_LOCAL_H + +#include +#include +#include +#include +#include +#include +#include "hda_local.h" + +struct hdmi_spec_per_cvt { + hda_nid_t cvt_nid; + bool assigned; /* the stream has been assigned */ + bool silent_stream; /* silent stream activated */ + unsigned int channels_min; + unsigned int channels_max; + u32 rates; + u64 formats; + unsigned int maxbps; +}; + +/* max. connections to a widget */ +#define HDA_MAX_CONNECTIONS 32 + +struct hdmi_spec_per_pin { + hda_nid_t pin_nid; + int dev_id; + /* pin idx, different device entries on the same pin use the same idx */ + int pin_nid_idx; + int num_mux_nids; + hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; + int mux_idx; + hda_nid_t cvt_nid; + + struct hda_codec *codec; + struct hdmi_eld sink_eld; + struct mutex lock; + struct delayed_work work; + struct hdmi_pcm *pcm; /* pointer to spec->pcm_rec[n] dynamically*/ + int pcm_idx; /* which pcm is attached. -1 means no pcm is attached */ + int prev_pcm_idx; /* previously assigned pcm index */ + int repoll_count; + bool setup; /* the stream has been set up by prepare callback */ + bool silent_stream; + int channels; /* current number of channels */ + bool non_pcm; + bool chmap_set; /* channel-map override by ALSA API? */ + unsigned char chmap[8]; /* ALSA API channel-map */ +#ifdef CONFIG_SND_PROC_FS + struct snd_info_entry *proc_entry; +#endif +}; + +/* operations used by generic code that can be overridden by patches */ +struct hdmi_ops { + int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid, + int dev_id, unsigned char *buf, int *eld_size); + + void (*pin_setup_infoframe)(struct hda_codec *codec, hda_nid_t pin_nid, + int dev_id, + int ca, int active_channels, int conn_type); + + /* enable/disable HBR (HD passthrough) */ + int (*pin_hbr_setup)(struct hda_codec *codec, hda_nid_t pin_nid, + int dev_id, bool hbr); + + int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid, + hda_nid_t pin_nid, int dev_id, u32 stream_tag, + int format); + + void (*pin_cvt_fixup)(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin, + hda_nid_t cvt_nid); + + void (*silent_stream)(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin, + bool enable); +}; + +struct hdmi_pcm { + struct hda_pcm *pcm; + struct snd_jack *jack; + struct snd_kcontrol *eld_ctl; +}; + +enum { + SILENT_STREAM_OFF = 0, + SILENT_STREAM_KAE, /* use standard HDA Keep-Alive */ + SILENT_STREAM_I915, /* Intel i915 extension */ +}; + +struct hdmi_spec { + struct hda_codec *codec; + int num_cvts; + struct snd_array cvts; /* struct hdmi_spec_per_cvt */ + hda_nid_t cvt_nids[4]; /* only for haswell fix */ + + /* + * num_pins is the number of virtual pins + * for example, there are 3 pins, and each pin + * has 4 device entries, then the num_pins is 12 + */ + int num_pins; + /* + * num_nids is the number of real pins + * In the above example, num_nids is 3 + */ + int num_nids; + /* + * dev_num is the number of device entries + * on each pin. + * In the above example, dev_num is 4 + */ + int dev_num; + struct snd_array pins; /* struct hdmi_spec_per_pin */ + struct hdmi_pcm pcm_rec[8]; + struct mutex pcm_lock; + struct mutex bind_lock; /* for audio component binding */ + /* pcm_bitmap means which pcms have been assigned to pins*/ + unsigned long pcm_bitmap; + int pcm_used; /* counter of pcm_rec[] */ + /* bitmap shows whether the pcm is opened in user space + * bit 0 means the first playback PCM (PCM3); + * bit 1 means the second playback PCM, and so on. + */ + unsigned long pcm_in_use; + + struct hdmi_eld temp_eld; + struct hdmi_ops ops; + + bool dyn_pin_out; + bool static_pcm_mapping; + /* hdmi interrupt trigger control flag for Nvidia codec */ + bool hdmi_intr_trig_ctrl; + bool nv_dp_workaround; /* workaround DP audio infoframe for Nvidia */ + + bool intel_hsw_fixup; /* apply Intel platform-specific fixups */ + /* + * Non-generic VIA/NVIDIA specific + */ + struct hda_multi_out multiout; + struct hda_pcm_stream pcm_playback; + + bool use_acomp_notifier; /* use eld_notify callback for hotplug */ + bool acomp_registered; /* audio component registered in this driver */ + bool force_connect; /* force connectivity */ + struct drm_audio_component_audio_ops drm_audio_ops; + int (*port2pin)(struct hda_codec *codec, int port); /* reverse port/pin mapping */ + + struct hdac_chmap chmap; + hda_nid_t vendor_nid; + const int *port_map; + int port_num; + int silent_stream_type; + + const struct snd_pcm_hw_constraint_list *hw_constraints_channels; +}; + +#ifdef CONFIG_SND_HDA_COMPONENT +static inline bool codec_has_acomp(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + + return spec->use_acomp_notifier; +} +#else +#define codec_has_acomp(codec) false +#endif + +struct hdmi_audio_infoframe { + u8 type; /* 0x84 */ + u8 ver; /* 0x01 */ + u8 len; /* 0x0a */ + + u8 checksum; + + u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */ + u8 SS01_SF24; + u8 CXT04; + u8 CA; + u8 LFEPBL01_LSV36_DM_INH7; +}; + +struct dp_audio_infoframe { + u8 type; /* 0x84 */ + u8 len; /* 0x1b */ + u8 ver; /* 0x11 << 2 */ + + u8 CC02_CT47; /* match with HDMI infoframe from this on */ + u8 SS01_SF24; + u8 CXT04; + u8 CA; + u8 LFEPBL01_LSV36_DM_INH7; +}; + +union audio_infoframe { + struct hdmi_audio_infoframe hdmi; + struct dp_audio_infoframe dp; + DECLARE_FLEX_ARRAY(u8, bytes); +}; + +#ifdef LIMITED_RATE_FMT_SUPPORT +/* support only the safe format and rate */ +#define SUPPORTED_RATES SNDRV_PCM_RATE_48000 +#define SUPPORTED_MAXBPS 16 +#define SUPPORTED_FORMATS SNDRV_PCM_FMTBIT_S16_LE +#else +/* support all rates and formats */ +#define SUPPORTED_RATES \ + (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) +#define SUPPORTED_MAXBPS 24 +#define SUPPORTED_FORMATS \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) +#endif + +/* + * HDMI routines + */ + +#define get_pin(spec, idx) \ + ((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx)) +#define get_cvt(spec, idx) \ + ((struct hdmi_spec_per_cvt *)snd_array_elem(&spec->cvts, idx)) +/* obtain hdmi_pcm object assigned to idx */ +#define get_hdmi_pcm(spec, idx) (&(spec)->pcm_rec[idx]) +/* obtain hda_pcm object assigned to idx */ +#define get_pcm_rec(spec, idx) (get_hdmi_pcm(spec, idx)->pcm) + +/* Generic HDMI codec support */ +int snd_hda_hdmi_generic_alloc(struct hda_codec *codec); +int snd_hda_hdmi_parse_codec(struct hda_codec *codec); +int patch_generic_hdmi(struct hda_codec *codec); +void snd_hda_hdmi_generic_free(struct hda_codec *codec); + +int snd_hda_hdmi_generic_build_pcms(struct hda_codec *codec); +int snd_hda_hdmi_generic_build_controls(struct hda_codec *codec); +int snd_hda_hdmi_generic_init(struct hda_codec *codec); +int snd_hda_hdmi_generic_suspend(struct hda_codec *codec); +int snd_hda_hdmi_generic_resume(struct hda_codec *codec); +void snd_hda_hdmi_generic_unsol_event(struct hda_codec *codec, unsigned int res); + +int snd_hda_hdmi_pin_id_to_pin_index(struct hda_codec *codec, + hda_nid_t pin_nid, int dev_id); +#define pin_id_to_pin_index(codec, pin, dev) \ + snd_hda_hdmi_pin_id_to_pin_index(codec, pin, dev) +int snd_hda_hdmi_generic_init_per_pins(struct hda_codec *codec); +void snd_hda_hdmi_generic_spec_free(struct hda_codec *codec); +int snd_hda_hdmi_setup_stream(struct hda_codec *codec, + hda_nid_t cvt_nid, + hda_nid_t pin_nid, int dev_id, + u32 stream_tag, int format); + +int snd_hda_hdmi_generic_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream); +int snd_hda_hdmi_generic_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream); + +void snd_hda_hdmi_check_presence_and_report(struct hda_codec *codec, + hda_nid_t nid, int dev_id); +void snd_hda_hdmi_setup_audio_infoframe(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin, + bool non_pcm); + +/* Audio component support */ +void snd_hda_hdmi_setup_drm_audio_ops(struct hda_codec *codec, + const struct drm_audio_component_audio_ops *ops); +void snd_hda_hdmi_acomp_init(struct hda_codec *codec, + const struct drm_audio_component_audio_ops *ops, + int (*port2pin)(struct hda_codec *, int)); +void snd_hda_hdmi_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id); +int snd_hda_hdmi_acomp_master_bind(struct device *dev, + struct drm_audio_component *acomp); +void snd_hda_hdmi_acomp_master_unbind(struct device *dev, + struct drm_audio_component *acomp); + +/* Simple / legacy HDMI codec support */ +int patch_simple_hdmi(struct hda_codec *codec, + hda_nid_t cvt_nid, hda_nid_t pin_nid); +void snd_hda_hdmi_simple_free(struct hda_codec *codec); + +int snd_hda_hdmi_simple_build_pcms(struct hda_codec *codec); +int snd_hda_hdmi_simple_build_controls(struct hda_codec *codec); +int snd_hda_hdmi_simple_init(struct hda_codec *codec); +void snd_hda_hdmi_simple_unsol_event(struct hda_codec *codec, + unsigned int res); +int snd_hda_hdmi_simple_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream); + +#endif /* __HDA_HDMI_LOCAL_H */ diff --git a/sound/hda/codecs/hdmi/intelhdmi.c b/sound/hda/codecs/hdmi/intelhdmi.c new file mode 100644 index 000000000000..a88ac1f80db6 --- /dev/null +++ b/sound/hda/codecs/hdmi/intelhdmi.c @@ -0,0 +1,760 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Intel HDMI codec support + */ + +#include +#include +#include +#include +#include +#include +#include +#include "hda_local.h" +#include "hdmi_local.h" + +static bool enable_silent_stream = +IS_ENABLED(CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM); +module_param(enable_silent_stream, bool, 0644); +MODULE_PARM_DESC(enable_silent_stream, "Enable Silent Stream for HDMI devices"); + +#define INTEL_GET_VENDOR_VERB 0xf81 +#define INTEL_SET_VENDOR_VERB 0x781 +#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ +#define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */ + +static void intel_haswell_enable_all_pins(struct hda_codec *codec, + bool update_tree) +{ + unsigned int vendor_param; + struct hdmi_spec *spec = codec->spec; + + vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0, + INTEL_GET_VENDOR_VERB, 0); + if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS) + return; + + vendor_param |= INTEL_EN_ALL_PIN_CVTS; + vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0, + INTEL_SET_VENDOR_VERB, vendor_param); + if (vendor_param == -1) + return; + + if (update_tree) + snd_hda_codec_update_widgets(codec); +} + +static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec) +{ + unsigned int vendor_param; + struct hdmi_spec *spec = codec->spec; + + vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0, + INTEL_GET_VENDOR_VERB, 0); + if (vendor_param == -1 || vendor_param & INTEL_EN_DP12) + return; + + /* enable DP1.2 mode */ + vendor_param |= INTEL_EN_DP12; + snd_hdac_regmap_add_vendor_verb(&codec->core, INTEL_SET_VENDOR_VERB); + snd_hda_codec_write_cache(codec, spec->vendor_nid, 0, + INTEL_SET_VENDOR_VERB, vendor_param); +} + +/* Haswell needs to re-issue the vendor-specific verbs before turning to D0. + * Otherwise you may get severe h/w communication errors. + */ +static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg, + unsigned int power_state) +{ + if (power_state == AC_PWRST_D0) { + intel_haswell_enable_all_pins(codec, false); + intel_haswell_fixup_enable_dp12(codec); + } + + snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state); + snd_hda_codec_set_power_to_all(codec, fg, power_state); +} + +/* There is a fixed mapping between audio pin node and display port. + * on SNB, IVY, HSW, BSW, SKL, BXT, KBL: + * Pin Widget 5 - PORT B (port = 1 in i915 driver) + * Pin Widget 6 - PORT C (port = 2 in i915 driver) + * Pin Widget 7 - PORT D (port = 3 in i915 driver) + * + * on VLV, ILK: + * Pin Widget 4 - PORT B (port = 1 in i915 driver) + * Pin Widget 5 - PORT C (port = 2 in i915 driver) + * Pin Widget 6 - PORT D (port = 3 in i915 driver) + */ +static int intel_base_nid(struct hda_codec *codec) +{ + switch (codec->core.vendor_id) { + case 0x80860054: /* ILK */ + case 0x80862804: /* ILK */ + case 0x80862882: /* VLV */ + return 4; + default: + return 5; + } +} + +static int intel_pin2port(void *audio_ptr, int pin_nid) +{ + struct hda_codec *codec = audio_ptr; + struct hdmi_spec *spec = codec->spec; + int base_nid, i; + + if (!spec->port_num) { + base_nid = intel_base_nid(codec); + if (WARN_ON(pin_nid < base_nid || pin_nid >= base_nid + 3)) + return -1; + return pin_nid - base_nid + 1; + } + + /* + * looking for the pin number in the mapping table and return + * the index which indicate the port number + */ + for (i = 0; i < spec->port_num; i++) { + if (pin_nid == spec->port_map[i]) + return i; + } + + codec_info(codec, "Can't find the HDMI/DP port for pin NID 0x%x\n", pin_nid); + return -1; +} + +static int intel_port2pin(struct hda_codec *codec, int port) +{ + struct hdmi_spec *spec = codec->spec; + + if (!spec->port_num) { + /* we assume only from port-B to port-D */ + if (port < 1 || port > 3) + return 0; + return port + intel_base_nid(codec) - 1; + } + + if (port < 0 || port >= spec->port_num) + return 0; + return spec->port_map[port]; +} + +static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe) +{ + struct hda_codec *codec = audio_ptr; + int pin_nid; + int dev_id = pipe; + + pin_nid = intel_port2pin(codec, port); + if (!pin_nid) + return; + /* skip notification during system suspend (but not in runtime PM); + * the state will be updated at resume + */ + if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND) + return; + + snd_hdac_i915_set_bclk(&codec->bus->core); + snd_hda_hdmi_check_presence_and_report(codec, pin_nid, dev_id); +} + +static const struct drm_audio_component_audio_ops intel_audio_ops = { + .pin2port = intel_pin2port, + .pin_eld_notify = intel_pin_eld_notify, +}; + +/* register i915 component pin_eld_notify callback */ +static void register_i915_notifier(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + + spec->use_acomp_notifier = true; + spec->port2pin = intel_port2pin; + snd_hda_hdmi_setup_drm_audio_ops(codec, &intel_audio_ops); + snd_hdac_acomp_register_notifier(&codec->bus->core, + &spec->drm_audio_ops); + /* no need for forcible resume for jack check thanks to notifier */ + codec->relaxed_resume = 1; +} + +#define I915_SILENT_RATE 48000 +#define I915_SILENT_CHANNELS 2 +#define I915_SILENT_FORMAT_BITS 16 +#define I915_SILENT_FMT_MASK 0xf + +static void silent_stream_enable_i915(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin) +{ + unsigned int format; + + snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid, + per_pin->dev_id, I915_SILENT_RATE); + + /* trigger silent stream generation in hw */ + format = snd_hdac_stream_format(I915_SILENT_CHANNELS, I915_SILENT_FORMAT_BITS, + I915_SILENT_RATE); + snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, + I915_SILENT_FMT_MASK, I915_SILENT_FMT_MASK, format); + usleep_range(100, 200); + snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, I915_SILENT_FMT_MASK, 0, format); + + per_pin->channels = I915_SILENT_CHANNELS; + snd_hda_hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); +} + +static void silent_stream_set_kae(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin, + bool enable) +{ + unsigned int param; + + codec_dbg(codec, "HDMI: KAE %d cvt-NID=0x%x\n", enable, per_pin->cvt_nid); + + param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0); + param = (param >> 16) & 0xff; + + if (enable) + param |= AC_DIG3_KAE; + else + param &= ~AC_DIG3_KAE; + + snd_hda_codec_write(codec, per_pin->cvt_nid, 0, AC_VERB_SET_DIGI_CONVERT_3, param); +} + +static void i915_set_silent_stream(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin, + bool enable) +{ + struct hdmi_spec *spec = codec->spec; + + switch (spec->silent_stream_type) { + case SILENT_STREAM_KAE: + if (enable) { + silent_stream_enable_i915(codec, per_pin); + silent_stream_set_kae(codec, per_pin, true); + } else { + silent_stream_set_kae(codec, per_pin, false); + } + break; + case SILENT_STREAM_I915: + if (enable) { + silent_stream_enable_i915(codec, per_pin); + snd_hda_power_up_pm(codec); + } else { + /* release ref taken in silent_stream_enable() */ + snd_hda_power_down_pm(codec); + } + break; + default: + break; + } +} + +static void haswell_verify_D0(struct hda_codec *codec, + hda_nid_t cvt_nid, hda_nid_t nid) +{ + int pwr; + + /* For Haswell, the converter 1/2 may keep in D3 state after bootup, + * thus pins could only choose converter 0 for use. Make sure the + * converters are in correct power state + */ + if (!snd_hda_check_power_state(codec, cvt_nid, AC_PWRST_D0)) + snd_hda_codec_write(codec, cvt_nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + + if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0)) { + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, + AC_PWRST_D0); + msleep(40); + pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0); + pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT; + codec_dbg(codec, "Haswell HDMI audio: Power for NID 0x%x is now D%d\n", nid, pwr); + } +} + +/* Assure the pin select the right convetor */ +static void intel_verify_pin_cvt_connect(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin) +{ + hda_nid_t pin_nid = per_pin->pin_nid; + int mux_idx, curr; + + mux_idx = per_pin->mux_idx; + curr = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_CONNECT_SEL, 0); + if (curr != mux_idx) + snd_hda_codec_write_cache(codec, pin_nid, 0, + AC_VERB_SET_CONNECT_SEL, + mux_idx); +} + +/* get the mux index for the converter of the pins + * converter's mux index is the same for all pins on Intel platform + */ +static int intel_cvt_id_to_mux_idx(struct hdmi_spec *spec, + hda_nid_t cvt_nid) +{ + int i; + + for (i = 0; i < spec->num_cvts; i++) + if (spec->cvt_nids[i] == cvt_nid) + return i; + return -EINVAL; +} + +/* Intel HDMI workaround to fix audio routing issue: + * For some Intel display codecs, pins share the same connection list. + * So a conveter can be selected by multiple pins and playback on any of these + * pins will generate sound on the external display, because audio flows from + * the same converter to the display pipeline. Also muting one pin may make + * other pins have no sound output. + * So this function assures that an assigned converter for a pin is not selected + * by any other pins. + */ +static void intel_not_share_assigned_cvt(struct hda_codec *codec, + hda_nid_t pin_nid, + int dev_id, int mux_idx) +{ + struct hdmi_spec *spec = codec->spec; + hda_nid_t nid; + int cvt_idx, curr; + struct hdmi_spec_per_cvt *per_cvt; + struct hdmi_spec_per_pin *per_pin; + int pin_idx; + + /* configure the pins connections */ + for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { + int dev_id_saved; + int dev_num; + + per_pin = get_pin(spec, pin_idx); + /* + * pin not connected to monitor + * no need to operate on it + */ + if (!per_pin->pcm) + continue; + + if ((per_pin->pin_nid == pin_nid) && + (per_pin->dev_id == dev_id)) + continue; + + /* + * if per_pin->dev_id >= dev_num, + * snd_hda_get_dev_select() will fail, + * and the following operation is unpredictable. + * So skip this situation. + */ + dev_num = snd_hda_get_num_devices(codec, per_pin->pin_nid) + 1; + if (per_pin->dev_id >= dev_num) + continue; + + nid = per_pin->pin_nid; + + /* + * Calling this function should not impact + * on the device entry selection + * So let's save the dev id for each pin, + * and restore it when return + */ + dev_id_saved = snd_hda_get_dev_select(codec, nid); + snd_hda_set_dev_select(codec, nid, per_pin->dev_id); + curr = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONNECT_SEL, 0); + if (curr != mux_idx) { + snd_hda_set_dev_select(codec, nid, dev_id_saved); + continue; + } + + + /* choose an unassigned converter. The conveters in the + * connection list are in the same order as in the codec. + */ + for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { + per_cvt = get_cvt(spec, cvt_idx); + if (!per_cvt->assigned) { + codec_dbg(codec, + "choose cvt %d for pin NID 0x%x\n", + cvt_idx, nid); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, + cvt_idx); + break; + } + } + snd_hda_set_dev_select(codec, nid, dev_id_saved); + } +} + +/* A wrapper of intel_not_share_asigned_cvt() */ +static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec, + hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid) +{ + int mux_idx; + struct hdmi_spec *spec = codec->spec; + + /* On Intel platform, the mapping of converter nid to + * mux index of the pins are always the same. + * The pin nid may be 0, this means all pins will not + * share the converter. + */ + mux_idx = intel_cvt_id_to_mux_idx(spec, cvt_nid); + if (mux_idx >= 0) + intel_not_share_assigned_cvt(codec, pin_nid, dev_id, mux_idx); +} + +/* setup_stream ops override for HSW+ */ +static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, + hda_nid_t pin_nid, int dev_id, u32 stream_tag, + int format) +{ + struct hdmi_spec *spec = codec->spec; + int pin_idx = pin_id_to_pin_index(codec, pin_nid, dev_id); + struct hdmi_spec_per_pin *per_pin; + int res; + + if (pin_idx < 0) + per_pin = NULL; + else + per_pin = get_pin(spec, pin_idx); + + haswell_verify_D0(codec, cvt_nid, pin_nid); + + if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) { + silent_stream_set_kae(codec, per_pin, false); + /* wait for pending transfers in codec to clear */ + usleep_range(100, 200); + } + + res = snd_hda_hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id, + stream_tag, format); + + if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) { + usleep_range(100, 200); + silent_stream_set_kae(codec, per_pin, true); + } + + return res; +} + +/* pin_cvt_fixup ops override for HSW+ and VLV+ */ +static void i915_pin_cvt_fixup(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin, + hda_nid_t cvt_nid) +{ + if (per_pin) { + haswell_verify_D0(codec, per_pin->cvt_nid, per_pin->pin_nid); + snd_hda_set_dev_select(codec, per_pin->pin_nid, + per_pin->dev_id); + intel_verify_pin_cvt_connect(codec, per_pin); + intel_not_share_assigned_cvt(codec, per_pin->pin_nid, + per_pin->dev_id, per_pin->mux_idx); + } else { + intel_not_share_assigned_cvt_nid(codec, 0, 0, cvt_nid); + } +} + +static int i915_adlp_hdmi_suspend(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + bool silent_streams = false; + int pin_idx, res; + + res = snd_hda_hdmi_generic_suspend(codec); + + for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); + + if (per_pin->silent_stream) { + silent_streams = true; + break; + } + } + + if (silent_streams) { + /* + * stream-id should remain programmed when codec goes + * to runtime suspend + */ + codec->no_stream_clean_at_suspend = 1; + + /* + * the system might go to S3, in which case keep-alive + * must be reprogrammed upon resume + */ + codec->forced_resume = 1; + + codec_dbg(codec, "HDMI: KAE active at suspend\n"); + } else { + codec->no_stream_clean_at_suspend = 0; + codec->forced_resume = 0; + } + + return res; +} + +static int i915_adlp_hdmi_resume(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + int pin_idx, res; + + res = snd_hda_hdmi_generic_resume(codec); + + /* KAE not programmed at suspend, nothing to do here */ + if (!codec->no_stream_clean_at_suspend) + return res; + + for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); + + /* + * If system was in suspend with monitor connected, + * the codec setting may have been lost. Re-enable + * keep-alive. + */ + if (per_pin->silent_stream) { + unsigned int param; + + param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0, + AC_VERB_GET_CONV, 0); + if (!param) { + codec_dbg(codec, "HDMI: KAE: restore stream id\n"); + silent_stream_enable_i915(codec, per_pin); + } + + param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0, + AC_VERB_GET_DIGI_CONVERT_1, 0); + if (!(param & (AC_DIG3_KAE << 16))) { + codec_dbg(codec, "HDMI: KAE: restore DIG3_KAE\n"); + silent_stream_set_kae(codec, per_pin, true); + } + } + } + + return res; +} + +/* precondition and allocation for Intel codecs */ +static int alloc_intel_hdmi(struct hda_codec *codec) +{ + int err; + + /* requires i915 binding */ + if (!codec->bus->core.audio_component) { + codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n"); + /* set probe_id here to prevent generic fallback binding */ + codec->probe_id = HDA_CODEC_ID_SKIP_PROBE; + return -ENODEV; + } + + err = snd_hda_hdmi_generic_alloc(codec); + if (err < 0) + return err; + /* no need to handle unsol events */ + codec->patch_ops.unsol_event = NULL; + return 0; +} + +/* parse and post-process for Intel codecs */ +static int parse_intel_hdmi(struct hda_codec *codec) +{ + int err, retries = 3; + + do { + err = snd_hda_hdmi_parse_codec(codec); + } while (err < 0 && retries--); + + if (err < 0) + return err; + + snd_hda_hdmi_generic_init_per_pins(codec); + register_i915_notifier(codec); + return 0; +} + +/* Intel Haswell and onwards; audio component with eld notifier */ +static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid, + const int *port_map, int port_num, int dev_num, + bool send_silent_stream) +{ + struct hdmi_spec *spec; + int err; + + err = alloc_intel_hdmi(codec); + if (err < 0) + return err; + spec = codec->spec; + codec->dp_mst = true; + spec->vendor_nid = vendor_nid; + spec->port_map = port_map; + spec->port_num = port_num; + spec->intel_hsw_fixup = true; + spec->dev_num = dev_num; + + intel_haswell_enable_all_pins(codec, true); + intel_haswell_fixup_enable_dp12(codec); + + codec->display_power_control = 1; + + codec->patch_ops.set_power_state = haswell_set_power_state; + codec->depop_delay = 0; + codec->auto_runtime_pm = 1; + + spec->ops.setup_stream = i915_hsw_setup_stream; + spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup; + spec->ops.silent_stream = i915_set_silent_stream; + + /* + * Enable silent stream feature, if it is enabled via + * module param or Kconfig option + */ + if (send_silent_stream) + spec->silent_stream_type = SILENT_STREAM_I915; + + return parse_intel_hdmi(codec); +} + +static int patch_i915_hsw_hdmi(struct hda_codec *codec) +{ + return intel_hsw_common_init(codec, 0x08, NULL, 0, 3, + enable_silent_stream); +} + +static int patch_i915_glk_hdmi(struct hda_codec *codec) +{ + /* + * Silent stream calls audio component .get_power() from + * .pin_eld_notify(). On GLK this will deadlock in i915 due + * to the audio vs. CDCLK workaround. + */ + return intel_hsw_common_init(codec, 0x0b, NULL, 0, 3, false); +} + +static int patch_i915_icl_hdmi(struct hda_codec *codec) +{ + /* + * pin to port mapping table where the value indicate the pin number and + * the index indicate the port number. + */ + static const int map[] = {0x0, 0x4, 0x6, 0x8, 0xa, 0xb}; + + return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 3, + enable_silent_stream); +} + +static int patch_i915_tgl_hdmi(struct hda_codec *codec) +{ + /* + * pin to port mapping table where the value indicate the pin number and + * the index indicate the port number. + */ + static const int map[] = {0x4, 0x6, 0x8, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; + + return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 4, + enable_silent_stream); +} + +static int patch_i915_adlp_hdmi(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int res; + + res = patch_i915_tgl_hdmi(codec); + if (!res) { + spec = codec->spec; + + if (spec->silent_stream_type) { + spec->silent_stream_type = SILENT_STREAM_KAE; + + codec->patch_ops.resume = i915_adlp_hdmi_resume; + codec->patch_ops.suspend = i915_adlp_hdmi_suspend; + } + } + + return res; +} + +/* Intel Baytrail and Braswell; with eld notifier */ +static int patch_i915_byt_hdmi(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int err; + + err = alloc_intel_hdmi(codec); + if (err < 0) + return err; + spec = codec->spec; + + /* For Valleyview/Cherryview, only the display codec is in the display + * power well and can use link_power ops to request/release the power. + */ + codec->display_power_control = 1; + + codec->depop_delay = 0; + codec->auto_runtime_pm = 1; + + spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup; + + return parse_intel_hdmi(codec); +} + +/* Intel IronLake, SandyBridge and IvyBridge; with eld notifier */ +static int patch_i915_cpt_hdmi(struct hda_codec *codec) +{ + int err; + + err = alloc_intel_hdmi(codec); + if (err < 0) + return err; + return parse_intel_hdmi(codec); +} + +/* + * driver entries + */ +static const struct hda_device_id snd_hda_id_intelhdmi[] = { +HDA_CODEC_ENTRY(0x80860054, "IbexPeak HDMI", patch_i915_cpt_hdmi), +HDA_CODEC_ENTRY(0x80862800, "Geminilake HDMI", patch_i915_glk_hdmi), +HDA_CODEC_ENTRY(0x80862804, "IbexPeak HDMI", patch_i915_cpt_hdmi), +HDA_CODEC_ENTRY(0x80862805, "CougarPoint HDMI", patch_i915_cpt_hdmi), +HDA_CODEC_ENTRY(0x80862806, "PantherPoint HDMI", patch_i915_cpt_hdmi), +HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI", patch_i915_hsw_hdmi), +HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_i915_hsw_hdmi), +HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_i915_hsw_hdmi), +HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_i915_hsw_hdmi), +HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_i915_hsw_hdmi), +HDA_CODEC_ENTRY(0x8086280c, "Cannonlake HDMI", patch_i915_glk_hdmi), +HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_glk_hdmi), +HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI", patch_i915_icl_hdmi), +HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI", patch_i915_tgl_hdmi), +HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI", patch_i915_tgl_hdmi), +HDA_CODEC_ENTRY(0x80862815, "Alderlake HDMI", patch_i915_tgl_hdmi), +HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI", patch_i915_tgl_hdmi), +HDA_CODEC_ENTRY(0x80862818, "Raptorlake HDMI", patch_i915_tgl_hdmi), +HDA_CODEC_ENTRY(0x80862819, "DG2 HDMI", patch_i915_tgl_hdmi), +HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi), +HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI", patch_i915_icl_hdmi), +HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_adlp_hdmi), +HDA_CODEC_ENTRY(0x8086281d, "Meteor Lake HDMI", patch_i915_adlp_hdmi), +HDA_CODEC_ENTRY(0x8086281e, "Battlemage HDMI", patch_i915_adlp_hdmi), +HDA_CODEC_ENTRY(0x8086281f, "Raptor Lake P HDMI", patch_i915_adlp_hdmi), +HDA_CODEC_ENTRY(0x80862820, "Lunar Lake HDMI", patch_i915_adlp_hdmi), +HDA_CODEC_ENTRY(0x80862822, "Panther Lake HDMI", patch_i915_adlp_hdmi), +HDA_CODEC_ENTRY(0x80862823, "Wildcat Lake HDMI", patch_i915_adlp_hdmi), +HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi), +HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi), +{} /* terminator */ +}; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_intelhdmi); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Intel HDMI HD-audio codec"); +MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI"); + +static struct hda_codec_driver intelhdmi_driver = { + .id = snd_hda_id_intelhdmi, +}; + +module_hda_codec_driver(intelhdmi_driver); diff --git a/sound/hda/codecs/hdmi/nvhdmi-mcp.c b/sound/hda/codecs/hdmi/nvhdmi-mcp.c new file mode 100644 index 000000000000..67e187a351d7 --- /dev/null +++ b/sound/hda/codecs/hdmi/nvhdmi-mcp.c @@ -0,0 +1,382 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Legacy Nvidia HDMI codec support + */ + +#include +#include +#include +#include +#include +#include +#include "hda_local.h" +#include "hdmi_local.h" + +#define Nv_VERB_SET_Channel_Allocation 0xF79 +#define Nv_VERB_SET_Info_Frame_Checksum 0xF7A +#define Nv_VERB_SET_Audio_Protection_On 0xF98 +#define Nv_VERB_SET_Audio_Protection_Off 0xF99 + +#define nvhdmi_master_con_nid_7x 0x04 +#define nvhdmi_master_pin_nid_7x 0x05 + +static const hda_nid_t nvhdmi_con_nids_7x[4] = { + /*front, rear, clfe, rear_surr */ + 0x6, 0x8, 0xa, 0xc, +}; + +static const struct hda_verb nvhdmi_basic_init_7x_2ch[] = { + /* set audio protect on */ + { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1}, + /* enable digital output on pin widget */ + { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, + {} /* terminator */ +}; + +static const struct hda_verb nvhdmi_basic_init_7x_8ch[] = { + /* set audio protect on */ + { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1}, + /* enable digital output on pin widget */ + { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, + { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, + { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, + { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, + { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, + {} /* terminator */ +}; + +static int nvhdmi_7x_init_2ch(struct hda_codec *codec) +{ + snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_2ch); + return 0; +} + +static int nvhdmi_7x_init_8ch(struct hda_codec *codec) +{ + snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_8ch); + return 0; +} + +static void nvhdmi_8ch_7x_set_info_frame_parameters(struct hda_codec *codec, + int channels) +{ + unsigned int chanmask; + int chan = channels ? (channels - 1) : 1; + + switch (channels) { + default: + case 0: + case 2: + chanmask = 0x00; + break; + case 4: + chanmask = 0x08; + break; + case 6: + chanmask = 0x0b; + break; + case 8: + chanmask = 0x13; + break; + } + + /* Set the audio infoframe channel allocation and checksum fields. The + * channel count is computed implicitly by the hardware. + */ + snd_hda_codec_write(codec, 0x1, 0, + Nv_VERB_SET_Channel_Allocation, chanmask); + + snd_hda_codec_write(codec, 0x1, 0, + Nv_VERB_SET_Info_Frame_Checksum, + (0x71 - chan - chanmask)); +} + +static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hdmi_spec *spec = codec->spec; + int i; + + snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, + 0, AC_VERB_SET_CHANNEL_STREAMID, 0); + for (i = 0; i < 4; i++) { + /* set the stream id */ + snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, + AC_VERB_SET_CHANNEL_STREAMID, 0); + /* set the stream format */ + snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, + AC_VERB_SET_STREAM_FORMAT, 0); + } + + /* The audio hardware sends a channel count of 0x7 (8ch) when all the + * streams are disabled. + */ + nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8); + + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + +static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + int chs; + unsigned int dataDCC2, channel_id; + int i; + struct hdmi_spec *spec = codec->spec; + struct hda_spdif_out *spdif; + struct hdmi_spec_per_cvt *per_cvt; + + mutex_lock(&codec->spdif_mutex); + per_cvt = get_cvt(spec, 0); + spdif = snd_hda_spdif_out_of_nid(codec, per_cvt->cvt_nid); + + chs = substream->runtime->channels; + + dataDCC2 = 0x2; + + /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ + if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) + snd_hda_codec_write(codec, + nvhdmi_master_con_nid_7x, + 0, + AC_VERB_SET_DIGI_CONVERT_1, + spdif->ctls & ~AC_DIG1_ENABLE & 0xff); + + /* set the stream id */ + snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, + AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0); + + /* set the stream format */ + snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, + AC_VERB_SET_STREAM_FORMAT, format); + + /* turn on again (if needed) */ + /* enable and set the channel status audio/data flag */ + if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) { + snd_hda_codec_write(codec, + nvhdmi_master_con_nid_7x, + 0, + AC_VERB_SET_DIGI_CONVERT_1, + spdif->ctls & 0xff); + snd_hda_codec_write(codec, + nvhdmi_master_con_nid_7x, + 0, + AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); + } + + for (i = 0; i < 4; i++) { + if (chs == 2) + channel_id = 0; + else + channel_id = i * 2; + + /* turn off SPDIF once; + *otherwise the IEC958 bits won't be updated + */ + if (codec->spdif_status_reset && + (spdif->ctls & AC_DIG1_ENABLE)) + snd_hda_codec_write(codec, + nvhdmi_con_nids_7x[i], + 0, + AC_VERB_SET_DIGI_CONVERT_1, + spdif->ctls & ~AC_DIG1_ENABLE & 0xff); + /* set the stream id */ + snd_hda_codec_write(codec, + nvhdmi_con_nids_7x[i], + 0, + AC_VERB_SET_CHANNEL_STREAMID, + (stream_tag << 4) | channel_id); + /* set the stream format */ + snd_hda_codec_write(codec, + nvhdmi_con_nids_7x[i], + 0, + AC_VERB_SET_STREAM_FORMAT, + format); + /* turn on again (if needed) */ + /* enable and set the channel status audio/data flag */ + if (codec->spdif_status_reset && + (spdif->ctls & AC_DIG1_ENABLE)) { + snd_hda_codec_write(codec, + nvhdmi_con_nids_7x[i], + 0, + AC_VERB_SET_DIGI_CONVERT_1, + spdif->ctls & 0xff); + snd_hda_codec_write(codec, + nvhdmi_con_nids_7x[i], + 0, + AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); + } + } + + nvhdmi_8ch_7x_set_info_frame_parameters(codec, chs); + + mutex_unlock(&codec->spdif_mutex); + return 0; +} + +static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = { + .substreams = 1, + .channels_min = 2, + .channels_max = 8, + .nid = nvhdmi_master_con_nid_7x, + .rates = SUPPORTED_RATES, + .maxbps = SUPPORTED_MAXBPS, + .formats = SUPPORTED_FORMATS, + .ops = { + .open = snd_hda_hdmi_simple_pcm_open, + .close = nvhdmi_8ch_7x_pcm_close, + .prepare = nvhdmi_8ch_7x_pcm_prepare + }, +}; + +static int patch_nvhdmi_2ch(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int err = patch_simple_hdmi(codec, nvhdmi_master_con_nid_7x, + nvhdmi_master_pin_nid_7x); + if (err < 0) + return err; + + codec->patch_ops.init = nvhdmi_7x_init_2ch; + /* override the PCM rates, etc, as the codec doesn't give full list */ + spec = codec->spec; + spec->pcm_playback.rates = SUPPORTED_RATES; + spec->pcm_playback.maxbps = SUPPORTED_MAXBPS; + spec->pcm_playback.formats = SUPPORTED_FORMATS; + spec->nv_dp_workaround = true; + return 0; +} + +static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + int err; + + err = snd_hda_hdmi_simple_build_pcms(codec); + if (!err) { + struct hda_pcm *info = get_pcm_rec(spec, 0); + + info->own_chmap = true; + } + return err; +} + +static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + struct hda_pcm *info; + struct snd_pcm_chmap *chmap; + int err; + + err = snd_hda_hdmi_simple_build_controls(codec); + if (err < 0) + return err; + + /* add channel maps */ + info = get_pcm_rec(spec, 0); + err = snd_pcm_add_chmap_ctls(info->pcm, + SNDRV_PCM_STREAM_PLAYBACK, + snd_pcm_alt_chmaps, 8, 0, &chmap); + if (err < 0) + return err; + switch (codec->preset->vendor_id) { + case 0x10de0002: + case 0x10de0003: + case 0x10de0005: + case 0x10de0006: + chmap->channel_mask = (1U << 2) | (1U << 8); + break; + case 0x10de0007: + chmap->channel_mask = (1U << 2) | (1U << 6) | (1U << 8); + } + return 0; +} + +static const unsigned int channels_2_6_8[] = { + 2, 6, 8 +}; + +static const unsigned int channels_2_8[] = { + 2, 8 +}; + +static const struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = { + .count = ARRAY_SIZE(channels_2_6_8), + .list = channels_2_6_8, + .mask = 0, +}; + +static const struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = { + .count = ARRAY_SIZE(channels_2_8), + .list = channels_2_8, + .mask = 0, +}; + +static int patch_nvhdmi_8ch_7x(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int err; + + err = patch_nvhdmi_2ch(codec); + if (err < 0) + return err; + spec = codec->spec; + spec->multiout.max_channels = 8; + spec->pcm_playback = nvhdmi_pcm_playback_8ch_7x; + codec->patch_ops.init = nvhdmi_7x_init_8ch; + codec->patch_ops.build_pcms = nvhdmi_7x_8ch_build_pcms; + codec->patch_ops.build_controls = nvhdmi_7x_8ch_build_controls; + + switch (codec->preset->vendor_id) { + case 0x10de0002: + case 0x10de0003: + case 0x10de0005: + case 0x10de0006: + spec->hw_constraints_channels = &hw_constraints_2_8_channels; + break; + case 0x10de0007: + spec->hw_constraints_channels = &hw_constraints_2_6_8_channels; + break; + default: + break; + } + + /* Initialize the audio infoframe channel mask and checksum to something + * valid + */ + nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8); + + return 0; +} + +/* + * patch entries + */ +static const struct hda_device_id snd_hda_id_nvhdmi_mcp[] = { +HDA_CODEC_ENTRY(0x10de0001, "MCP73 HDMI", patch_nvhdmi_2ch), +HDA_CODEC_ENTRY(0x10de0002, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), +HDA_CODEC_ENTRY(0x10de0003, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), +HDA_CODEC_ENTRY(0x10de0004, "GPU 04 HDMI", patch_nvhdmi_8ch_7x), +HDA_CODEC_ENTRY(0x10de0005, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), +HDA_CODEC_ENTRY(0x10de0006, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), +HDA_CODEC_ENTRY(0x10de0007, "MCP79/7A HDMI", patch_nvhdmi_8ch_7x), +HDA_CODEC_ENTRY(0x10de0067, "MCP67 HDMI", patch_nvhdmi_2ch), +HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI", patch_nvhdmi_2ch), +HDA_CODEC_ENTRY(0x10de8067, "MCP67/68 HDMI", patch_nvhdmi_2ch), +{} /* terminator */ +}; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_nvhdmi_mcp); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Legacy Nvidia HDMI HD-audio codec"); +MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI"); + +static struct hda_codec_driver nvhdmi_mcp_driver = { + .id = snd_hda_id_nvhdmi_mcp, +}; + +module_hda_codec_driver(nvhdmi_mcp_driver); diff --git a/sound/hda/codecs/hdmi/nvhdmi.c b/sound/hda/codecs/hdmi/nvhdmi.c new file mode 100644 index 000000000000..2add5f59daf5 --- /dev/null +++ b/sound/hda/codecs/hdmi/nvhdmi.c @@ -0,0 +1,218 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Nvidia HDMI codec support + */ + +#include +#include +#include +#include +#include +#include +#include +#include "hda_local.h" +#include "hdmi_local.h" + +/* + * NVIDIA codecs ignore ASP mapping for 2ch - confirmed on: + * - 0x10de0015 + * - 0x10de0040 + */ +static int nvhdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap, + struct hdac_cea_channel_speaker_allocation *cap, int channels) +{ + if (cap->ca_index == 0x00 && channels == 2) + return SNDRV_CTL_TLVT_CHMAP_FIXED; + + /* If the speaker allocation matches the channel count, it is OK. */ + if (cap->channels != channels) + return -1; + + /* all channels are remappable freely */ + return SNDRV_CTL_TLVT_CHMAP_VAR; +} + +static int nvhdmi_chmap_validate(struct hdac_chmap *chmap, + int ca, int chs, unsigned char *map) +{ + if (ca == 0x00 && (map[0] != SNDRV_CHMAP_FL || map[1] != SNDRV_CHMAP_FR)) + return -EINVAL; + + return 0; +} + +/* map from pin NID to port; port is 0-based */ +/* for Nvidia: assume widget NID starting from 4, with step 1 (4, 5, 6, ...) */ +static int nvhdmi_pin2port(void *audio_ptr, int pin_nid) +{ + return pin_nid - 4; +} + +/* reverse-map from port to pin NID: see above */ +static int nvhdmi_port2pin(struct hda_codec *codec, int port) +{ + return port + 4; +} + +static const struct drm_audio_component_audio_ops nvhdmi_audio_ops = { + .pin2port = nvhdmi_pin2port, + .pin_eld_notify = snd_hda_hdmi_acomp_pin_eld_notify, + .master_bind = snd_hda_hdmi_acomp_master_bind, + .master_unbind = snd_hda_hdmi_acomp_master_unbind, +}; + +static int patch_nvhdmi(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int err; + + err = snd_hda_hdmi_generic_alloc(codec); + if (err < 0) + return err; + codec->dp_mst = true; + + spec = codec->spec; + + err = snd_hda_hdmi_parse_codec(codec); + if (err < 0) { + snd_hda_hdmi_generic_spec_free(codec); + return err; + } + + snd_hda_hdmi_generic_init_per_pins(codec); + + spec->dyn_pin_out = true; + + spec->chmap.ops.chmap_cea_alloc_validate_get_type = + nvhdmi_chmap_cea_alloc_validate_get_type; + spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate; + spec->nv_dp_workaround = true; + + codec->link_down_at_suspend = 1; + + snd_hda_hdmi_acomp_init(codec, &nvhdmi_audio_ops, nvhdmi_port2pin); + + return 0; +} + +static int patch_nvhdmi_legacy(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int err; + + err = patch_generic_hdmi(codec); + if (err) + return err; + + spec = codec->spec; + spec->dyn_pin_out = true; + + spec->chmap.ops.chmap_cea_alloc_validate_get_type = + nvhdmi_chmap_cea_alloc_validate_get_type; + spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate; + spec->nv_dp_workaround = true; + + codec->link_down_at_suspend = 1; + + return 0; +} + +/* + * patch entries + */ +static const struct hda_device_id snd_hda_id_nvhdmi[] = { +HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de000d, "GPU 0d HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0010, "GPU 10 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0011, "GPU 11 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0012, "GPU 12 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0013, "GPU 13 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0014, "GPU 14 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0015, "GPU 15 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0016, "GPU 16 HDMI/DP", patch_nvhdmi_legacy), +/* 17 is known to be absent */ +HDA_CODEC_ENTRY(0x10de0018, "GPU 18 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0019, "GPU 19 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de001a, "GPU 1a HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de001b, "GPU 1b HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de001c, "GPU 1c HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0043, "GPU 43 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0044, "GPU 44 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0045, "GPU 45 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0050, "GPU 50 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0051, "GPU 51 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0052, "GPU 52 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0060, "GPU 60 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0061, "GPU 61 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0062, "GPU 62 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0073, "GPU 73 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0074, "GPU 74 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0076, "GPU 76 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de007b, "GPU 7b HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de007c, "GPU 7c HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de007e, "GPU 7e HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0081, "GPU 81 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0084, "GPU 84 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0090, "GPU 90 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0091, "GPU 91 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0092, "GPU 92 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0093, "GPU 93 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0094, "GPU 94 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0095, "GPU 95 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0097, "GPU 97 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0098, "GPU 98 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0099, "GPU 99 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de009a, "GPU 9a HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de009b, "GPU 9b HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de009c, "GPU 9c HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de009d, "GPU 9d HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de009e, "GPU 9e HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de009f, "GPU 9f HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00a0, "GPU a0 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00a1, "GPU a1 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00a3, "GPU a3 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00a4, "GPU a4 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00a5, "GPU a5 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00a6, "GPU a6 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00a7, "GPU a7 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00a8, "GPU a8 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00a9, "GPU a9 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00aa, "GPU aa HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00ab, "GPU ab HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00ad, "GPU ad HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00ae, "GPU ae HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00af, "GPU af HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00b0, "GPU b0 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00b1, "GPU b1 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00c0, "GPU c0 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00c1, "GPU c1 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00c3, "GPU c3 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00c4, "GPU c4 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00c5, "GPU c5 HDMI/DP", patch_nvhdmi), +{} /* terminator */ +}; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_nvhdmi); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Nvidia HDMI HD-audio codec"); +MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI"); + +static struct hda_codec_driver nvhdmi_driver = { + .id = snd_hda_id_nvhdmi, +}; + +module_hda_codec_driver(nvhdmi_driver); diff --git a/sound/hda/codecs/hdmi/simplehdmi.c b/sound/hda/codecs/hdmi/simplehdmi.c new file mode 100644 index 000000000000..87ea997a6d3b --- /dev/null +++ b/sound/hda/codecs/hdmi/simplehdmi.c @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Non-generic simple HDMI codec support + */ + +#include +#include +#include "hdmi_local.h" +#include "hda_jack.h" + +int snd_hda_hdmi_simple_build_pcms(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + struct hda_pcm *info; + unsigned int chans; + struct hda_pcm_stream *pstr; + struct hdmi_spec_per_cvt *per_cvt; + + per_cvt = get_cvt(spec, 0); + chans = get_wcaps(codec, per_cvt->cvt_nid); + chans = get_wcaps_channels(chans); + + info = snd_hda_codec_pcm_new(codec, "HDMI 0"); + if (!info) + return -ENOMEM; + spec->pcm_rec[0].pcm = info; + info->pcm_type = HDA_PCM_TYPE_HDMI; + pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK]; + *pstr = spec->pcm_playback; + pstr->nid = per_cvt->cvt_nid; + if (pstr->channels_max <= 2 && chans && chans <= 16) + pstr->channels_max = chans; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_build_pcms, "SND_HDA_CODEC_HDMI"); + +/* unsolicited event for jack sensing */ +void snd_hda_hdmi_simple_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + snd_hda_jack_set_dirty_all(codec); + snd_hda_jack_report_sync(codec); +} +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_unsol_event, "SND_HDA_CODEC_HDMI"); + +static void free_hdmi_jack_priv(struct snd_jack *jack) +{ + struct hdmi_pcm *pcm = jack->private_data; + + pcm->jack = NULL; +} + +static int simple_hdmi_build_jack(struct hda_codec *codec) +{ + char hdmi_str[32] = "HDMI/DP"; + struct hdmi_spec *spec = codec->spec; + struct snd_jack *jack; + struct hdmi_pcm *pcmp = get_hdmi_pcm(spec, 0); + int pcmdev = pcmp->pcm->device; + int err; + + if (pcmdev > 0) + sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev); + + err = snd_jack_new(codec->card, hdmi_str, SND_JACK_AVOUT, &jack, + true, false); + if (err < 0) + return err; + + pcmp->jack = jack; + jack->private_data = pcmp; + jack->private_free = free_hdmi_jack_priv; + return 0; +} + +int snd_hda_hdmi_simple_build_controls(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + struct hdmi_spec_per_cvt *per_cvt; + int err; + + per_cvt = get_cvt(spec, 0); + err = snd_hda_create_dig_out_ctls(codec, per_cvt->cvt_nid, + per_cvt->cvt_nid, + HDA_PCM_TYPE_HDMI); + if (err < 0) + return err; + return simple_hdmi_build_jack(codec); +} +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_build_controls, "SND_HDA_CODEC_HDMI"); + +int snd_hda_hdmi_simple_init(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, 0); + hda_nid_t pin = per_pin->pin_nid; + + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + /* some codecs require to unmute the pin */ + if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) + snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_UNMUTE); + snd_hda_jack_detect_enable(codec, pin, per_pin->dev_id); + return 0; +} +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_init, "SND_HDA_CODEC_HDMI"); + +void snd_hda_hdmi_simple_free(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + + snd_array_free(&spec->pins); + snd_array_free(&spec->cvts); + kfree(spec); +} +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_free, "SND_HDA_CODEC_HDMI"); + +int snd_hda_hdmi_simple_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hdmi_spec *spec = codec->spec; + + if (spec->hw_constraints_channels) { + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + spec->hw_constraints_channels); + } else { + snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, 2); + } + + return snd_hda_multi_out_dig_open(codec, &spec->multiout); +} +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_pcm_open, "SND_HDA_CODEC_HDMI"); + +static int simple_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hdmi_spec *spec = codec->spec; + + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + +static int simple_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct hdmi_spec *spec = codec->spec; + + return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, + stream_tag, format, substream); +} + +static const struct hda_pcm_stream simple_pcm_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .ops = { + .open = snd_hda_hdmi_simple_pcm_open, + .close = simple_playback_pcm_close, + .prepare = simple_playback_pcm_prepare + }, +}; + +static const struct hda_codec_ops simple_hdmi_patch_ops = { + .build_controls = snd_hda_hdmi_simple_build_controls, + .build_pcms = snd_hda_hdmi_simple_build_pcms, + .init = snd_hda_hdmi_simple_init, + .free = snd_hda_hdmi_simple_free, + .unsol_event = snd_hda_hdmi_simple_unsol_event, +}; + +int patch_simple_hdmi(struct hda_codec *codec, + hda_nid_t cvt_nid, hda_nid_t pin_nid) +{ + struct hdmi_spec *spec; + struct hdmi_spec_per_cvt *per_cvt; + struct hdmi_spec_per_pin *per_pin; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + + spec->codec = codec; + codec->spec = spec; + snd_array_init(&spec->pins, sizeof(struct hdmi_spec_per_pin), 1); + snd_array_init(&spec->cvts, sizeof(struct hdmi_spec_per_cvt), 1); + + spec->multiout.num_dacs = 0; /* no analog */ + spec->multiout.max_channels = 2; + spec->multiout.dig_out_nid = cvt_nid; + spec->num_cvts = 1; + spec->num_pins = 1; + per_pin = snd_array_new(&spec->pins); + per_cvt = snd_array_new(&spec->cvts); + if (!per_pin || !per_cvt) { + snd_hda_hdmi_simple_free(codec); + return -ENOMEM; + } + per_cvt->cvt_nid = cvt_nid; + per_pin->pin_nid = pin_nid; + spec->pcm_playback = simple_pcm_playback; + + codec->patch_ops = simple_hdmi_patch_ops; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(patch_simple_hdmi, "SND_HDA_CODEC_HDMI"); + +/* VIA HDMI Implementation */ +#define VIAHDMI_CVT_NID 0x02 /* audio converter1 */ +#define VIAHDMI_PIN_NID 0x03 /* HDMI output pin1 */ + +static int patch_via_hdmi(struct hda_codec *codec) +{ + return patch_simple_hdmi(codec, VIAHDMI_CVT_NID, VIAHDMI_PIN_NID); +} + +/* + * patch entries + */ +static const struct hda_device_id snd_hda_id_simplehdmi[] = { +HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP", patch_via_hdmi), +HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP", patch_via_hdmi), +{} /* terminator */ +}; + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Simple HDMI HD-audio codec support"); + +static struct hda_codec_driver simplehdmi_driver = { + .id = snd_hda_id_simplehdmi, +}; + +module_hda_codec_driver(simplehdmi_driver); diff --git a/sound/hda/codecs/hdmi/tegrahdmi.c b/sound/hda/codecs/hdmi/tegrahdmi.c new file mode 100644 index 000000000000..c13a63788799 --- /dev/null +++ b/sound/hda/codecs/hdmi/tegrahdmi.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Nvidia Tegra HDMI codec support + */ + +#include +#include +#include +#include +#include +#include +#include +#include "hda_local.h" +#include "hdmi_local.h" + +/* + * The HDA codec on NVIDIA Tegra contains two scratch registers that are + * accessed using vendor-defined verbs. These registers can be used for + * interoperability between the HDA and HDMI drivers. + */ + +/* Audio Function Group node */ +#define NVIDIA_AFG_NID 0x01 + +/* + * The SCRATCH0 register is used to notify the HDMI codec of changes in audio + * format. On Tegra, bit 31 is used as a trigger that causes an interrupt to + * be raised in the HDMI codec. The remainder of the bits is arbitrary. This + * implementation stores the HDA format (see AC_FMT_*) in bits [15:0] and an + * additional bit (at position 30) to signal the validity of the format. + * + * | 31 | 30 | 29 16 | 15 0 | + * +---------+-------+--------+--------+ + * | TRIGGER | VALID | UNUSED | FORMAT | + * +-----------------------------------| + * + * Note that for the trigger bit to take effect it needs to change value + * (i.e. it needs to be toggled). The trigger bit is not applicable from + * TEGRA234 chip onwards, as new verb id 0xf80 will be used for interrupt + * trigger to hdmi. + */ +#define NVIDIA_SET_HOST_INTR 0xf80 +#define NVIDIA_GET_SCRATCH0 0xfa6 +#define NVIDIA_SET_SCRATCH0_BYTE0 0xfa7 +#define NVIDIA_SET_SCRATCH0_BYTE1 0xfa8 +#define NVIDIA_SET_SCRATCH0_BYTE2 0xfa9 +#define NVIDIA_SET_SCRATCH0_BYTE3 0xfaa +#define NVIDIA_SCRATCH_TRIGGER (1 << 7) +#define NVIDIA_SCRATCH_VALID (1 << 6) + +#define NVIDIA_GET_SCRATCH1 0xfab +#define NVIDIA_SET_SCRATCH1_BYTE0 0xfac +#define NVIDIA_SET_SCRATCH1_BYTE1 0xfad +#define NVIDIA_SET_SCRATCH1_BYTE2 0xfae +#define NVIDIA_SET_SCRATCH1_BYTE3 0xfaf + +/* + * The format parameter is the HDA audio format (see AC_FMT_*). If set to 0, + * the format is invalidated so that the HDMI codec can be disabled. + */ +static void tegra_hdmi_set_format(struct hda_codec *codec, + hda_nid_t cvt_nid, + unsigned int format) +{ + unsigned int value; + unsigned int nid = NVIDIA_AFG_NID; + struct hdmi_spec *spec = codec->spec; + + /* + * Tegra HDA codec design from TEGRA234 chip onwards support DP MST. + * This resulted in moving scratch registers from audio function + * group to converter widget context. So CVT NID should be used for + * scratch register read/write for DP MST supported Tegra HDA codec. + */ + if (codec->dp_mst) + nid = cvt_nid; + + /* bits [31:30] contain the trigger and valid bits */ + value = snd_hda_codec_read(codec, nid, 0, + NVIDIA_GET_SCRATCH0, 0); + value = (value >> 24) & 0xff; + + /* bits [15:0] are used to store the HDA format */ + snd_hda_codec_write(codec, nid, 0, + NVIDIA_SET_SCRATCH0_BYTE0, + (format >> 0) & 0xff); + snd_hda_codec_write(codec, nid, 0, + NVIDIA_SET_SCRATCH0_BYTE1, + (format >> 8) & 0xff); + + /* bits [16:24] are unused */ + snd_hda_codec_write(codec, nid, 0, + NVIDIA_SET_SCRATCH0_BYTE2, 0); + + /* + * Bit 30 signals that the data is valid and hence that HDMI audio can + * be enabled. + */ + if (format == 0) + value &= ~NVIDIA_SCRATCH_VALID; + else + value |= NVIDIA_SCRATCH_VALID; + + if (spec->hdmi_intr_trig_ctrl) { + /* + * For Tegra HDA Codec design from TEGRA234 onwards, the + * Interrupt to hdmi driver is triggered by writing + * non-zero values to verb 0xF80 instead of 31st bit of + * scratch register. + */ + snd_hda_codec_write(codec, nid, 0, + NVIDIA_SET_SCRATCH0_BYTE3, value); + snd_hda_codec_write(codec, nid, 0, + NVIDIA_SET_HOST_INTR, 0x1); + } else { + /* + * Whenever the 31st trigger bit is toggled, an interrupt is raised + * in the HDMI codec. The HDMI driver will use that as trigger + * to update its configuration. + */ + value ^= NVIDIA_SCRATCH_TRIGGER; + + snd_hda_codec_write(codec, nid, 0, + NVIDIA_SET_SCRATCH0_BYTE3, value); + } +} + +static int tegra_hdmi_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + int err; + + err = snd_hda_hdmi_generic_pcm_prepare(hinfo, codec, stream_tag, + format, substream); + if (err < 0) + return err; + + /* notify the HDMI codec of the format change */ + tegra_hdmi_set_format(codec, hinfo->nid, format); + + return 0; +} + +static int tegra_hdmi_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + /* invalidate the format in the HDMI codec */ + tegra_hdmi_set_format(codec, hinfo->nid, 0); + + return snd_hda_hdmi_generic_pcm_cleanup(hinfo, codec, substream); +} + +static struct hda_pcm *hda_find_pcm_by_type(struct hda_codec *codec, int type) +{ + struct hdmi_spec *spec = codec->spec; + unsigned int i; + + for (i = 0; i < spec->num_pins; i++) { + struct hda_pcm *pcm = get_pcm_rec(spec, i); + + if (pcm->pcm_type == type) + return pcm; + } + + return NULL; +} + +static int tegra_hdmi_build_pcms(struct hda_codec *codec) +{ + struct hda_pcm_stream *stream; + struct hda_pcm *pcm; + int err; + + err = snd_hda_hdmi_generic_build_pcms(codec); + if (err < 0) + return err; + + pcm = hda_find_pcm_by_type(codec, HDA_PCM_TYPE_HDMI); + if (!pcm) + return -ENODEV; + + /* + * Override ->prepare() and ->cleanup() operations to notify the HDMI + * codec about format changes. + */ + stream = &pcm->stream[SNDRV_PCM_STREAM_PLAYBACK]; + stream->ops.prepare = tegra_hdmi_pcm_prepare; + stream->ops.cleanup = tegra_hdmi_pcm_cleanup; + + return 0; +} + +/* + * NVIDIA codecs ignore ASP mapping for 2ch - confirmed on: + * - 0x10de0015 + * - 0x10de0040 + */ +static int nvhdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap, + struct hdac_cea_channel_speaker_allocation *cap, int channels) +{ + if (cap->ca_index == 0x00 && channels == 2) + return SNDRV_CTL_TLVT_CHMAP_FIXED; + + /* If the speaker allocation matches the channel count, it is OK. */ + if (cap->channels != channels) + return -1; + + /* all channels are remappable freely */ + return SNDRV_CTL_TLVT_CHMAP_VAR; +} + +static int nvhdmi_chmap_validate(struct hdac_chmap *chmap, + int ca, int chs, unsigned char *map) +{ + if (ca == 0x00 && (map[0] != SNDRV_CHMAP_FL || map[1] != SNDRV_CHMAP_FR)) + return -EINVAL; + + return 0; +} + +static int tegra_hdmi_init(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + int i, err; + + err = snd_hda_hdmi_parse_codec(codec); + if (err < 0) { + snd_hda_hdmi_generic_spec_free(codec); + return err; + } + + for (i = 0; i < spec->num_cvts; i++) + snd_hda_codec_write(codec, spec->cvt_nids[i], 0, + AC_VERB_SET_DIGI_CONVERT_1, + AC_DIG1_ENABLE); + + snd_hda_hdmi_generic_init_per_pins(codec); + + codec->depop_delay = 10; + codec->patch_ops.build_pcms = tegra_hdmi_build_pcms; + spec->chmap.ops.chmap_cea_alloc_validate_get_type = + nvhdmi_chmap_cea_alloc_validate_get_type; + spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate; + + spec->chmap.ops.chmap_cea_alloc_validate_get_type = + nvhdmi_chmap_cea_alloc_validate_get_type; + spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate; + spec->nv_dp_workaround = true; + + return 0; +} + +static int patch_tegra_hdmi(struct hda_codec *codec) +{ + int err; + + err = snd_hda_hdmi_generic_alloc(codec); + if (err < 0) + return err; + + return tegra_hdmi_init(codec); +} + +static int patch_tegra234_hdmi(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int err; + + err = snd_hda_hdmi_generic_alloc(codec); + if (err < 0) + return err; + + codec->dp_mst = true; + spec = codec->spec; + spec->dyn_pin_out = true; + spec->hdmi_intr_trig_ctrl = true; + + return tegra_hdmi_init(codec); +} + +/* + * patch entries + */ +static const struct hda_device_id snd_hda_id_tegrahdmi[] = { +HDA_CODEC_ENTRY(0x10de0020, "Tegra30 HDMI", patch_tegra_hdmi), +HDA_CODEC_ENTRY(0x10de0022, "Tegra114 HDMI", patch_tegra_hdmi), +HDA_CODEC_ENTRY(0x10de0028, "Tegra124 HDMI", patch_tegra_hdmi), +HDA_CODEC_ENTRY(0x10de0029, "Tegra210 HDMI/DP", patch_tegra_hdmi), +HDA_CODEC_ENTRY(0x10de002d, "Tegra186 HDMI/DP0", patch_tegra_hdmi), +HDA_CODEC_ENTRY(0x10de002e, "Tegra186 HDMI/DP1", patch_tegra_hdmi), +HDA_CODEC_ENTRY(0x10de002f, "Tegra194 HDMI/DP2", patch_tegra_hdmi), +HDA_CODEC_ENTRY(0x10de0030, "Tegra194 HDMI/DP3", patch_tegra_hdmi), +HDA_CODEC_ENTRY(0x10de0031, "Tegra234 HDMI/DP", patch_tegra234_hdmi), +HDA_CODEC_ENTRY(0x10de0033, "SoC 33 HDMI/DP", patch_tegra234_hdmi), +HDA_CODEC_ENTRY(0x10de0034, "Tegra264 HDMI/DP", patch_tegra234_hdmi), +HDA_CODEC_ENTRY(0x10de0035, "SoC 35 HDMI/DP", patch_tegra234_hdmi), +{} /* terminator */ +}; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_tegrahdmi); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Nvidia Tegra HDMI HD-audio codec"); +MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI"); + +static struct hda_codec_driver tegrahdmi_driver = { + .id = snd_hda_id_tegrahdmi, +}; + +module_hda_codec_driver(tegrahdmi_driver); diff --git a/sound/hda/common/hda_local.h b/sound/hda/common/hda_local.h index 68c31f5354b7..428aa5a06ead 100644 --- a/sound/hda/common/hda_local.h +++ b/sound/hda/common/hda_local.h @@ -689,10 +689,6 @@ int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid, void snd_hdmi_eld_update_pcm_info(struct snd_parsed_hdmi_eld *e, struct hda_pcm_stream *hinfo); -int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid, - unsigned char *buf, int *eld_size, - bool rev3_or_later); - #ifdef CONFIG_SND_PROC_FS void snd_hdmi_print_eld_info(struct hdmi_eld *eld, struct snd_info_buffer *buffer, From 6bf917e9aacc360e76b74249209a4290f2e8404b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:12 +0200 Subject: [PATCH 325/385] ALSA: hda: Introduce hda_codec_driver ops Until now, we use "patch_ops" embedded in hda_codec object for defining the callbacks that are used in various places to manage HD-audio codec. But from the device driver POV, this should have been rather the driver ops, instead of the callbacks in the codec object. This patch defines the driver ops for HD-audio codec driver as the replacement. We reuse the same struct hda_codec_ops, and this is put as hda_codec_driver.ops. When the driver->ops callbacks are defined, they are called primarily instead of codec->patch_ops callbacks. With converting to the driver ops, there is no need to pass the ugly patch_ops handling in hda_device_id tables. That is, driver_data field of hda_device_id becomes really optional and it can be used for passing the codec-specific data (e.g. specifying a model). The codec entries after the conversion should be with HDA_CODEC_ID() and co, instead of the former HDA_CODEC_ENTRY(). Once after converting all codec drivers to use driver ops, we can get rid of codec patch_ops. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-10-tiwai@suse.de --- include/sound/hda_codec.h | 26 +++++++++++++++-- sound/hda/common/bind.c | 27 +++++++++++++---- sound/hda/common/codec.c | 56 ++++++++++++++++++++++++++---------- sound/hda/common/hda_local.h | 11 +++++++ sound/soc/codecs/hda.c | 27 +++++++++++------ sound/soc/codecs/hdac_hda.c | 28 +++++++++++++----- 6 files changed, 137 insertions(+), 38 deletions(-) diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index c1fe6290d04d..a725ac48c20c 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -27,6 +27,7 @@ struct hda_beep; struct hda_codec; struct hda_pcm; struct hda_pcm_stream; +struct hda_codec_ops; /* * codec bus @@ -79,6 +80,17 @@ typedef int (*hda_codec_patch_t)(struct hda_codec *); #define HDA_CODEC_ID_GENERIC_HDMI 0x00000101 #define HDA_CODEC_ID_GENERIC 0x00000201 +#define HDA_CODEC_ID_REV_MODEL(_vid, _rev, _name, _model) \ + { .vendor_id = (_vid), .rev_id = (_rev), .name = (_name), \ + .api_version = HDA_DEV_LEGACY, .driver_data = (_model) } +#define HDA_CODEC_ID_MODEL(_vid, _name, _model) \ + HDA_CODEC_ID_REV_MODEL(_vid, 0, _name, _model) +#define HDA_CODEC_ID_REV(_vid, _rev, _name) \ + HDA_CODEC_ID_REV_MODEL(_vid, _rev, _name, 0) +#define HDA_CODEC_ID(_vid, _name) \ + HDA_CODEC_ID_REV(_vid, 0, _name) + +/* old macros for patch_ops -- to be deprecated */ #define HDA_CODEC_REV_ENTRY(_vid, _rev, _name, _patch) \ { .vendor_id = (_vid), .rev_id = (_rev), .name = (_name), \ .api_version = HDA_DEV_LEGACY, \ @@ -89,8 +101,12 @@ typedef int (*hda_codec_patch_t)(struct hda_codec *); struct hda_codec_driver { struct hdac_driver core; const struct hda_device_id *id; + const struct hda_codec_ops *ops; }; +#define hda_codec_to_driver(codec) \ + container_of((codec)->core.dev.driver, struct hda_codec_driver, core.driver) + int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name, struct module *owner); #define hda_codec_driver_register(drv) \ @@ -102,6 +118,8 @@ void hda_codec_driver_unregister(struct hda_codec_driver *drv); /* ops set by the preset patch */ struct hda_codec_ops { + int (*probe)(struct hda_codec *codec, const struct hda_device_id *id); + void (*remove)(struct hda_codec *codec); int (*build_controls)(struct hda_codec *codec); int (*build_pcms)(struct hda_codec *codec); int (*init)(struct hda_codec *codec); @@ -184,7 +202,7 @@ struct hda_codec { /* set by patch */ struct hda_codec_ops patch_ops; - /* PCM to create, set by patch_ops.build_pcms callback */ + /* PCM to create, set by hda_codec_ops.build_pcms callback */ struct list_head pcm_list_head; refcount_t pcm_ref; wait_queue_head_t remove_sleep; @@ -478,7 +496,11 @@ extern const struct dev_pm_ops hda_codec_driver_pm; static inline int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid) { - if (codec->patch_ops.check_power_status) + struct hda_codec_driver *driver = hda_codec_to_driver(codec); + + if (driver->ops && driver->ops->check_power_status) + return driver->ops->check_power_status(codec, nid); + else if (codec->patch_ops.check_power_status) return codec->patch_ops.check_power_status(codec, nid); return 0; } diff --git a/sound/hda/common/bind.c b/sound/hda/common/bind.c index df8f88beddd0..56975178f533 100644 --- a/sound/hda/common/bind.c +++ b/sound/hda/common/bind.c @@ -42,6 +42,7 @@ static int hda_codec_match(struct hdac_device *dev, const struct hdac_driver *dr static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev) { struct hda_codec *codec = container_of(dev, struct hda_codec, core); + struct hda_codec_driver *driver = hda_codec_to_driver(codec); /* ignore unsol events during shutdown */ if (codec->card->shutdown || codec->bus->shutdown) @@ -51,7 +52,9 @@ static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev) if (codec->core.dev.power.power_state.event != PM_EVENT_ON) return; - if (codec->patch_ops.unsol_event) + if (driver->ops && driver->ops->unsol_event) + driver->ops->unsol_event(codec, ev); + else if (codec->patch_ops.unsol_event) codec->patch_ops.unsol_event(codec, ev); } @@ -87,6 +90,7 @@ static int hda_codec_driver_probe(struct device *dev) { struct hda_codec *codec = dev_to_hda_codec(dev); struct module *owner = dev->driver->owner; + struct hda_codec_driver *driver = hda_codec_to_driver(codec); hda_codec_patch_t patch; int err; @@ -111,11 +115,17 @@ static int hda_codec_driver_probe(struct device *dev) goto error; } - patch = (hda_codec_patch_t)codec->preset->driver_data; - if (patch) { - err = patch(codec); + if (driver->ops && driver->ops->probe) { + err = driver->ops->probe(codec, codec->preset); if (err < 0) goto error_module_put; + } else { + patch = (hda_codec_patch_t)codec->preset->driver_data; + if (patch) { + err = patch(codec); + if (err < 0) + goto error_module_put; + } } err = snd_hda_codec_build_pcms(codec); @@ -136,7 +146,9 @@ static int hda_codec_driver_probe(struct device *dev) return 0; error_module: - if (codec->patch_ops.free) + if (driver->ops && driver->ops->remove) + driver->ops->remove(codec); + else if (codec->patch_ops.free) codec->patch_ops.free(codec); error_module_put: module_put(owner); @@ -150,6 +162,7 @@ static int hda_codec_driver_probe(struct device *dev) static int hda_codec_driver_remove(struct device *dev) { struct hda_codec *codec = dev_to_hda_codec(dev); + struct hda_codec_driver *driver = hda_codec_to_driver(codec); if (codec->bus->core.ext_ops) { if (WARN_ON(!codec->bus->core.ext_ops->hdev_detach)) @@ -163,7 +176,9 @@ static int hda_codec_driver_remove(struct device *dev) wait_event(codec->remove_sleep, !refcount_read(&codec->pcm_ref)); snd_power_sync_ref(codec->bus->card); - if (codec->patch_ops.free) + if (driver->ops && driver->ops->remove) + driver->ops->remove(codec); + else if (codec->patch_ops.free) codec->patch_ops.free(codec); snd_hda_codec_cleanup_for_unbind(codec); codec->preset = NULL; diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c index cb72e9655c8a..8899be764d68 100644 --- a/sound/hda/common/codec.c +++ b/sound/hda/common/codec.c @@ -1114,6 +1114,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, int channel_id, int format) { + struct hda_codec_driver *driver = hda_codec_to_driver(codec); struct hda_codec *c; struct hda_cvt_setup *p; int type; @@ -1129,7 +1130,9 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, if (!p) return; - if (codec->patch_ops.stream_pm) + if (driver->ops && driver->ops->stream_pm) + driver->ops->stream_pm(codec, nid, true); + else if (codec->patch_ops.stream_pm) codec->patch_ops.stream_pm(codec, nid, true); if (codec->pcm_format_first) update_pcm_format(codec, p, nid, format); @@ -1190,7 +1193,9 @@ EXPORT_SYMBOL_GPL(__snd_hda_codec_cleanup_stream); static void really_cleanup_stream(struct hda_codec *codec, struct hda_cvt_setup *q) { + struct hda_codec_driver *driver = hda_codec_to_driver(codec); hda_nid_t nid = q->nid; + if (q->stream_tag || q->channel_id) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); if (q->format_id) @@ -1198,7 +1203,9 @@ static void really_cleanup_stream(struct hda_codec *codec, ); memset(q, 0, sizeof(*q)); q->nid = nid; - if (codec->patch_ops.stream_pm) + if (driver->ops && driver->ops->stream_pm) + driver->ops->stream_pm(codec, nid, false); + else if (codec->patch_ops.stream_pm) codec->patch_ops.stream_pm(codec, nid, false); } @@ -2746,6 +2753,7 @@ EXPORT_SYMBOL_GPL(snd_hda_codec_eapd_power_filter); static unsigned int hda_set_power_state(struct hda_codec *codec, unsigned int power_state) { + struct hda_codec_driver *driver = hda_codec_to_driver(codec); hda_nid_t fg = codec->core.afg ? codec->core.afg : codec->core.mfg; int count; unsigned int state; @@ -2762,7 +2770,10 @@ static unsigned int hda_set_power_state(struct hda_codec *codec, /* repeat power states setting at most 10 times*/ for (count = 0; count < 10; count++) { - if (codec->patch_ops.set_power_state) + /* might be called before binding to driver, too */ + if (driver && driver->ops && driver->ops->set_power_state) + driver->ops->set_power_state(codec, fg, power_state); + else if (codec->patch_ops.set_power_state) codec->patch_ops.set_power_state(codec, fg, power_state); else { @@ -2842,10 +2853,13 @@ void snd_hda_update_power_acct(struct hda_codec *codec) */ static unsigned int hda_call_codec_suspend(struct hda_codec *codec) { + struct hda_codec_driver *driver = hda_codec_to_driver(codec); unsigned int state; snd_hdac_enter_pm(&codec->core); - if (codec->patch_ops.suspend) + if (driver->ops && driver->ops->suspend) + driver->ops->suspend(codec); + else if (codec->patch_ops.suspend) codec->patch_ops.suspend(codec); if (!codec->no_stream_clean_at_suspend) hda_cleanup_all_streams(codec); @@ -2860,6 +2874,8 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec) */ static void hda_call_codec_resume(struct hda_codec *codec) { + struct hda_codec_driver *driver = hda_codec_to_driver(codec); + snd_hdac_enter_pm(&codec->core); if (codec->core.regmap) regcache_mark_dirty(codec->core.regmap); @@ -2870,11 +2886,12 @@ static void hda_call_codec_resume(struct hda_codec *codec) restore_shutup_pins(codec); hda_exec_init_verbs(codec); snd_hda_jack_set_dirty_all(codec); - if (codec->patch_ops.resume) + if (driver->ops && driver->ops->resume) + driver->ops->resume(codec); + else if (codec->patch_ops.resume) codec->patch_ops.resume(codec); else { - if (codec->patch_ops.init) - codec->patch_ops.init(codec); + snd_hda_codec_init(codec); snd_hda_regmap_sync(codec); } @@ -3059,15 +3076,20 @@ EXPORT_SYMBOL_GPL(snd_pcm_2_1_chmaps); int snd_hda_codec_build_controls(struct hda_codec *codec) { + struct hda_codec_driver *driver = hda_codec_to_driver(codec); int err = 0; + hda_exec_init_verbs(codec); /* continue to initialize... */ - if (codec->patch_ops.init) - err = codec->patch_ops.init(codec); - if (!err && codec->patch_ops.build_controls) - err = codec->patch_ops.build_controls(codec); - if (err < 0) - return err; + err = snd_hda_codec_init(codec); + if (!err) { + if (driver->ops && driver->ops->build_controls) + err = driver->ops->build_controls(codec); + else if (codec->patch_ops.build_controls) + err = codec->patch_ops.build_controls(codec); + if (err < 0) + return err; + } /* we create chmaps here instead of build_pcms */ err = add_std_chmaps(codec); @@ -3253,16 +3275,20 @@ static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type) /* call build_pcms ops of the given codec and set up the default parameters */ int snd_hda_codec_parse_pcms(struct hda_codec *codec) { + struct hda_codec_driver *driver = hda_codec_to_driver(codec); struct hda_pcm *cpcm; int err; if (!list_empty(&codec->pcm_list_head)) return 0; /* already parsed */ - if (!codec->patch_ops.build_pcms) + if (driver->ops && driver->ops->build_pcms) + err = driver->ops->build_pcms(codec); + else if (codec->patch_ops.build_pcms) + err = codec->patch_ops.build_pcms(codec); + else return 0; - err = codec->patch_ops.build_pcms(codec); if (err < 0) { codec_err(codec, "cannot build PCMs for #%d (error %d)\n", codec->core.addr, err); diff --git a/sound/hda/common/hda_local.h b/sound/hda/common/hda_local.h index 428aa5a06ead..654fe1156d56 100644 --- a/sound/hda/common/hda_local.h +++ b/sound/hda/common/hda_local.h @@ -652,6 +652,17 @@ unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec, void snd_hda_codec_shutdown(struct hda_codec *codec); +static inline int snd_hda_codec_init(struct hda_codec *codec) +{ + struct hda_codec_driver *driver = hda_codec_to_driver(codec); + + if (driver->ops && driver->ops->init) + return driver->ops->init(codec); + else if (codec->patch_ops.init) + return codec->patch_ops.init(codec); + return 0; +} + /* * AMP control callbacks */ diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c index dc7794c9ac44..ddb31001657e 100644 --- a/sound/soc/codecs/hda.c +++ b/sound/soc/codecs/hda.c @@ -173,6 +173,7 @@ EXPORT_SYMBOL_GPL(hda_codec_probe_complete); static int hda_codec_probe(struct snd_soc_component *component) { struct hda_codec *codec = dev_to_hda_codec(component->dev); + struct hda_codec_driver *driver = hda_codec_to_driver(codec); struct hdac_device *hdev = &codec->core; struct hdac_bus *bus = hdev->bus; struct hdac_ext_link *hlink; @@ -214,14 +215,19 @@ static int hda_codec_probe(struct snd_soc_component *component) goto err; } - patch = (hda_codec_patch_t)codec->preset->driver_data; - if (!patch) { - dev_err(&hdev->dev, "no patch specified\n"); - ret = -EINVAL; - goto err; + if (driver->ops && driver->ops->probe) { + ret = driver->ops->probe(codec, codec->preset); + } else { + patch = (hda_codec_patch_t)codec->preset->driver_data; + if (!patch) { + dev_err(&hdev->dev, "no patch specified\n"); + ret = -EINVAL; + goto err; + } + + ret = patch(codec); } - ret = patch(codec); if (ret < 0) { dev_err(&hdev->dev, "codec init failed: %d\n", ret); goto err; @@ -252,7 +258,9 @@ static int hda_codec_probe(struct snd_soc_component *component) complete_err: hda_codec_unregister_dais(codec, component); parse_pcms_err: - if (codec->patch_ops.free) + if (driver->ops && driver->ops->remove) + driver->ops->remove(codec); + else if (codec->patch_ops.free) codec->patch_ops.free(codec); err: snd_hda_codec_cleanup_for_unbind(codec); @@ -271,6 +279,7 @@ device_new_err: static void hda_codec_remove(struct snd_soc_component *component) { struct hda_codec *codec = dev_to_hda_codec(component->dev); + struct hda_codec_driver *driver = hda_codec_to_driver(codec); struct hdac_device *hdev = &codec->core; struct hdac_bus *bus = hdev->bus; struct hdac_ext_link *hlink; @@ -281,7 +290,9 @@ static void hda_codec_remove(struct snd_soc_component *component) hda_codec_unregister_dais(codec, component); - if (codec->patch_ops.free) + if (driver->ops && driver->ops->remove) + driver->ops->remove(codec); + else if (codec->patch_ops.free) codec->patch_ops.free(codec); snd_hda_codec_cleanup_for_unbind(codec); diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 29c88de5508b..7bb7845d5e43 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -409,6 +409,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) snd_soc_component_get_dapm(component); struct hdac_device *hdev = &hda_pvt->codec->core; struct hda_codec *hcodec = hda_pvt->codec; + struct hda_codec_driver *driver = hda_codec_to_driver(hcodec); struct hdac_ext_link *hlink; hda_codec_patch_t patch; int ret; @@ -484,15 +485,23 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) goto error_pm; } - patch = (hda_codec_patch_t)hcodec->preset->driver_data; - if (patch) { - ret = patch(hcodec); + if (driver->ops && driver->ops->probe) { + ret = driver->ops->probe(hcodec, hcodec->preset); if (ret < 0) { - dev_err(&hdev->dev, "%s: patch failed %d\n", __func__, ret); + dev_err(&hdev->dev, "%s: probe failed %d\n", __func__, ret); goto error_regmap; } } else { - dev_dbg(&hdev->dev, "%s: no patch file found\n", __func__); + patch = (hda_codec_patch_t)hcodec->preset->driver_data; + if (patch) { + ret = patch(hcodec); + if (ret < 0) { + dev_err(&hdev->dev, "%s: patch failed %d\n", __func__, ret); + goto error_regmap; + } + } else { + dev_dbg(&hdev->dev, "%s: no patch file found\n", __func__); + } } ret = snd_hda_codec_parse_pcms(hcodec); @@ -531,7 +540,9 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) return 0; error_patch: - if (hcodec->patch_ops.free) + if (driver->ops && driver->ops->remove) + driver->ops->remove(hcodec); + else if (hcodec->patch_ops.free) hcodec->patch_ops.free(hcodec); error_regmap: snd_hdac_regmap_exit(hdev); @@ -548,6 +559,7 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component) snd_soc_component_get_drvdata(component); struct hdac_device *hdev = &hda_pvt->codec->core; struct hda_codec *codec = hda_pvt->codec; + struct hda_codec_driver *driver = hda_codec_to_driver(codec); struct hdac_ext_link *hlink = NULL; hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev)); @@ -559,7 +571,9 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component) pm_runtime_disable(&hdev->dev); snd_hdac_ext_bus_link_put(hdev->bus, hlink); - if (codec->patch_ops.free) + if (driver->ops && driver->ops->remove) + driver->ops->remove(codec); + else if (codec->patch_ops.free) codec->patch_ops.free(codec); snd_hda_codec_cleanup_for_unbind(codec); From 1d0e6926ef8755d7a520c566d57eec1e4083ac8b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:13 +0200 Subject: [PATCH 326/385] ALSA: hda/generic: Rewrite to new probe method Convert the generic HD-audio codec driver to use the new hda_codec_ops probe. No functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-11-tiwai@suse.de --- sound/hda/codecs/generic.c | 43 +++++++++++++++++++++++--------------- sound/hda/codecs/generic.h | 3 ++- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/sound/hda/codecs/generic.c b/sound/hda/codecs/generic.c index 873fd4b7f451..82c31b93424c 100644 --- a/sound/hda/codecs/generic.c +++ b/sound/hda/codecs/generic.c @@ -4946,7 +4946,7 @@ static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix) * @nid: audio widget * @on: power on/off flag * - * Set this in patch_ops.stream_pm. Only valid with power_save_node flag. + * Set this in hda_codec_ops.stream_pm. Only valid with power_save_node flag. */ void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on) { @@ -5230,7 +5230,7 @@ static const char * const follower_pfxs[] = { * snd_hda_gen_build_controls - Build controls from the parsed results * @codec: the HDA codec * - * Pass this to build_controls patch_ops. + * Pass this to build_controls hda_codec_ops. */ int snd_hda_gen_build_controls(struct hda_codec *codec) { @@ -5743,7 +5743,7 @@ static void setup_pcm_stream(struct hda_pcm_stream *str, * snd_hda_gen_build_pcms - build PCM streams based on the parsed results * @codec: the HDA codec * - * Pass this to build_pcms patch_ops. + * Pass this to build_pcms hda_codec_ops. */ int snd_hda_gen_build_pcms(struct hda_codec *codec) { @@ -6032,7 +6032,7 @@ static void clear_unsol_on_unused_pins(struct hda_codec *codec) * snd_hda_gen_init - initialize the generic spec * @codec: the HDA codec * - * This can be put as patch_ops init function. + * This can be put as hda_codec_ops init function. */ int snd_hda_gen_init(struct hda_codec *codec) { @@ -6070,26 +6070,26 @@ int snd_hda_gen_init(struct hda_codec *codec) EXPORT_SYMBOL_GPL(snd_hda_gen_init); /** - * snd_hda_gen_free - free the generic spec + * snd_hda_gen_remove - free the generic spec * @codec: the HDA codec * - * This can be put as patch_ops free function. + * This can be put as hda_codec_ops remove function. */ -void snd_hda_gen_free(struct hda_codec *codec) +void snd_hda_gen_remove(struct hda_codec *codec) { snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE); snd_hda_gen_spec_free(codec->spec); kfree(codec->spec); codec->spec = NULL; } -EXPORT_SYMBOL_GPL(snd_hda_gen_free); +EXPORT_SYMBOL_GPL(snd_hda_gen_remove); /** * snd_hda_gen_check_power_status - check the loopback power save state * @codec: the HDA codec * @nid: NID to inspect * - * This can be put as patch_ops check_power_status function. + * This can be put as hda_codec_ops check_power_status function. */ int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid) { @@ -6112,11 +6112,8 @@ static const struct hda_codec_ops generic_patch_ops = { .check_power_status = snd_hda_gen_check_power_status, }; -/* - * snd_hda_parse_generic_codec - Generic codec parser - * @codec: the HDA codec - */ -static int snd_hda_parse_generic_codec(struct hda_codec *codec) +static int snd_hda_gen_probe(struct hda_codec *codec, + const struct hda_device_id *id) { struct hda_gen_spec *spec; int err; @@ -6139,19 +6136,31 @@ static int snd_hda_parse_generic_codec(struct hda_codec *codec) return 0; error: - snd_hda_gen_free(codec); + snd_hda_gen_remove(codec); return err; } +static const struct hda_codec_ops generic_codec_ops = { + .probe = snd_hda_gen_probe, + .remove = snd_hda_gen_remove, + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = snd_hda_gen_init, + .unsol_event = snd_hda_jack_unsol_event, + .check_power_status = snd_hda_gen_check_power_status, + .stream_pm = snd_hda_gen_stream_pm, +}; + static const struct hda_device_id snd_hda_id_generic[] = { - HDA_CODEC_ENTRY(0x1af40021, "Generic", snd_hda_parse_generic_codec), /* QEMU */ - HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC, "Generic", snd_hda_parse_generic_codec), + HDA_CODEC_ID(0x1af40021, "Generic"), /* QEMU */ + HDA_CODEC_ID(HDA_CODEC_ID_GENERIC, "Generic"), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_generic); static struct hda_codec_driver generic_driver = { .id = snd_hda_id_generic, + .ops = &generic_codec_ops, }; module_hda_codec_driver(generic_driver); diff --git a/sound/hda/codecs/generic.h b/sound/hda/codecs/generic.h index 9612afaa61c2..00a92fc55846 100644 --- a/sound/hda/codecs/generic.h +++ b/sound/hda/codecs/generic.h @@ -311,7 +311,8 @@ enum { int snd_hda_gen_spec_init(struct hda_gen_spec *spec); int snd_hda_gen_init(struct hda_codec *codec); -void snd_hda_gen_free(struct hda_codec *codec); +void snd_hda_gen_remove(struct hda_codec *codec); +#define snd_hda_gen_free snd_hda_gen_remove int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path); struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx); From e1d695b45fd112810b4621f7e1bb48d197f5ef6a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:14 +0200 Subject: [PATCH 327/385] ALSA: hda/realtek: Rewrite to new probe method Convert the Realtek codec drivers to use the new hda_codec_ops probe. No functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-12-tiwai@suse.de --- sound/hda/codecs/realtek/alc260.c | 20 ++++- sound/hda/codecs/realtek/alc262.c | 20 ++++- sound/hda/codecs/realtek/alc268.c | 22 +++++- sound/hda/codecs/realtek/alc269.c | 111 +++++++++++++++------------- sound/hda/codecs/realtek/alc662.c | 42 +++++++---- sound/hda/codecs/realtek/alc680.c | 20 ++++- sound/hda/codecs/realtek/alc861.c | 22 +++++- sound/hda/codecs/realtek/alc861vd.c | 22 +++++- sound/hda/codecs/realtek/alc880.c | 24 ++++-- sound/hda/codecs/realtek/alc882.c | 48 +++++++----- sound/hda/codecs/realtek/realtek.c | 17 +---- sound/hda/codecs/realtek/realtek.h | 4 - 12 files changed, 244 insertions(+), 128 deletions(-) diff --git a/sound/hda/codecs/realtek/alc260.c b/sound/hda/codecs/realtek/alc260.c index ebe20eaec58a..8bd47079dccb 100644 --- a/sound/hda/codecs/realtek/alc260.c +++ b/sound/hda/codecs/realtek/alc260.c @@ -211,7 +211,7 @@ static const struct hda_model_fixup alc260_fixup_models[] = { /* */ -static int patch_alc260(struct hda_codec *codec) +static int alc260_probe(struct hda_codec *codec, const struct hda_device_id *id) { struct alc_spec *spec; int err; @@ -252,15 +252,28 @@ static int patch_alc260(struct hda_codec *codec) return 0; error: - alc_free(codec); + snd_hda_gen_remove(codec); return err; } +static const struct hda_codec_ops alc260_codec_ops = { + .probe = alc260_probe, + .remove = snd_hda_gen_remove, + .build_controls = alc_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = alc_init, + .unsol_event = snd_hda_jack_unsol_event, + .resume = alc_resume, + .suspend = alc_suspend, + .check_power_status = snd_hda_gen_check_power_status, + .stream_pm = snd_hda_gen_stream_pm, +}; + /* * driver entries */ static const struct hda_device_id snd_hda_id_alc260[] = { - HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260), + HDA_CODEC_ID(0x10ec0260, "ALC260"), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc260); @@ -271,6 +284,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); static struct hda_codec_driver alc260_driver = { .id = snd_hda_id_alc260, + .ops = &alc260_codec_ops, }; module_hda_codec_driver(alc260_driver); diff --git a/sound/hda/codecs/realtek/alc262.c b/sound/hda/codecs/realtek/alc262.c index ffe61f447667..3ec06cf5d2a6 100644 --- a/sound/hda/codecs/realtek/alc262.c +++ b/sound/hda/codecs/realtek/alc262.c @@ -126,7 +126,7 @@ static const struct hda_model_fixup alc262_fixup_models[] = { /* */ -static int patch_alc262(struct hda_codec *codec) +static int alc262_probe(struct hda_codec *codec, const struct hda_device_id *id) { struct alc_spec *spec; int err; @@ -175,15 +175,28 @@ static int patch_alc262(struct hda_codec *codec) return 0; error: - alc_free(codec); + snd_hda_gen_remove(codec); return err; } +static const struct hda_codec_ops alc262_codec_ops = { + .probe = alc262_probe, + .remove = snd_hda_gen_remove, + .build_controls = alc_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = alc_init, + .unsol_event = snd_hda_jack_unsol_event, + .resume = alc_resume, + .suspend = alc_suspend, + .check_power_status = snd_hda_gen_check_power_status, + .stream_pm = snd_hda_gen_stream_pm, +}; + /* * driver entries */ static const struct hda_device_id snd_hda_id_alc262[] = { - HDA_CODEC_ENTRY(0x10ec0262, "ALC262", patch_alc262), + HDA_CODEC_ID(0x10ec0262, "ALC262"), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc262); @@ -194,6 +207,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); static struct hda_codec_driver alc262_driver = { .id = snd_hda_id_alc262, + .ops = &alc262_codec_ops, }; module_hda_codec_driver(alc262_driver); diff --git a/sound/hda/codecs/realtek/alc268.c b/sound/hda/codecs/realtek/alc268.c index d018f9982feb..e489cdc98eb8 100644 --- a/sound/hda/codecs/realtek/alc268.c +++ b/sound/hda/codecs/realtek/alc268.c @@ -101,7 +101,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec) /* */ -static int patch_alc268(struct hda_codec *codec) +static int alc268_probe(struct hda_codec *codec, const struct hda_device_id *id) { struct alc_spec *spec; int i, err; @@ -151,16 +151,29 @@ static int patch_alc268(struct hda_codec *codec) return 0; error: - alc_free(codec); + snd_hda_gen_remove(codec); return err; } +static const struct hda_codec_ops alc268_codec_ops = { + .probe = alc268_probe, + .remove = snd_hda_gen_remove, + .build_controls = alc_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = alc_init, + .unsol_event = snd_hda_jack_unsol_event, + .resume = alc_resume, + .suspend = alc_suspend, + .check_power_status = snd_hda_gen_check_power_status, + .stream_pm = snd_hda_gen_stream_pm, +}; + /* * driver entries */ static const struct hda_device_id snd_hda_id_alc268[] = { - HDA_CODEC_ENTRY(0x10ec0267, "ALC267", patch_alc268), - HDA_CODEC_ENTRY(0x10ec0268, "ALC268", patch_alc268), + HDA_CODEC_ID(0x10ec0267, "ALC267"), + HDA_CODEC_ID(0x10ec0268, "ALC268"), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc268); @@ -171,6 +184,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); static struct hda_codec_driver alc268_driver = { .id = snd_hda_id_alc268, + .ops = &alc268_codec_ops, }; module_hda_codec_driver(alc268_driver); diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index 13549b5b9c42..03daa58a88de 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -992,7 +992,7 @@ static int alc269_resume(struct hda_codec *codec) msleep(150); } - codec->patch_ops.init(codec); + snd_hda_codec_init(codec); if (spec->codec_variant == ALC269_TYPE_ALC269VB) alc269vb_toggle_power_output(codec, 1); @@ -7842,19 +7842,19 @@ static void alc269_fill_coef(struct hda_codec *codec) alc_update_coef_idx(codec, 0x4, 0, 1<<11); } -static void alc269_free(struct hda_codec *codec) +static void alc269_remove(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; if (spec) hda_component_manager_free(&spec->comps, &comp_master_ops); - alc_free(codec); + snd_hda_gen_remove(codec); } /* */ -static int patch_alc269(struct hda_codec *codec) +static int alc269_probe(struct hda_codec *codec, const struct hda_device_id *id) { struct alc_spec *spec; int err; @@ -7868,9 +7868,6 @@ static int patch_alc269(struct hda_codec *codec) codec->power_save_node = 0; spec->en_3kpull_low = true; - codec->patch_ops.suspend = alc269_suspend; - codec->patch_ops.resume = alc269_resume; - codec->patch_ops.free = alc269_free; spec->shutup = alc_default_shutup; spec->init_hook = alc_default_init; @@ -8068,56 +8065,69 @@ static int patch_alc269(struct hda_codec *codec) return 0; error: - alc_free(codec); + alc269_remove(codec); return err; } +static const struct hda_codec_ops alc269_codec_ops = { + .probe = alc269_probe, + .remove = alc269_remove, + .build_controls = alc_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = alc_init, + .unsol_event = snd_hda_jack_unsol_event, + .suspend = alc269_suspend, + .resume = alc269_resume, + .check_power_status = snd_hda_gen_check_power_status, + .stream_pm = snd_hda_gen_stream_pm, +}; + /* * driver entries */ static const struct hda_device_id snd_hda_id_alc269[] = { - HDA_CODEC_ENTRY(0x10ec0215, "ALC215", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0221, "ALC221", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0222, "ALC222", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0225, "ALC225", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0230, "ALC236", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0231, "ALC231", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0233, "ALC233", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0234, "ALC234", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0235, "ALC233", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0236, "ALC236", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0245, "ALC245", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0255, "ALC255", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0256, "ALC256", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0257, "ALC257", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0269, "ALC269", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0270, "ALC270", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0274, "ALC274", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0275, "ALC275", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0276, "ALC276", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0280, "ALC280", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0282, "ALC282", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0283, "ALC283", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0284, "ALC284", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0285, "ALC285", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0286, "ALC286", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0287, "ALC287", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0288, "ALC288", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0289, "ALC289", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0290, "ALC290", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0292, "ALC292", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0293, "ALC293", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0294, "ALC294", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0295, "ALC295", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0298, "ALC298", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0299, "ALC299", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0300, "ALC300", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0623, "ALC623", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0700, "ALC700", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0701, "ALC701", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0703, "ALC703", patch_alc269), - HDA_CODEC_ENTRY(0x10ec0711, "ALC711", patch_alc269), - HDA_CODEC_ENTRY(0x19e58326, "HW8326", patch_alc269), + HDA_CODEC_ID(0x10ec0215, "ALC215"), + HDA_CODEC_ID(0x10ec0221, "ALC221"), + HDA_CODEC_ID(0x10ec0222, "ALC222"), + HDA_CODEC_ID(0x10ec0225, "ALC225"), + HDA_CODEC_ID(0x10ec0230, "ALC236"), + HDA_CODEC_ID(0x10ec0231, "ALC231"), + HDA_CODEC_ID(0x10ec0233, "ALC233"), + HDA_CODEC_ID(0x10ec0234, "ALC234"), + HDA_CODEC_ID(0x10ec0235, "ALC233"), + HDA_CODEC_ID(0x10ec0236, "ALC236"), + HDA_CODEC_ID(0x10ec0245, "ALC245"), + HDA_CODEC_ID(0x10ec0255, "ALC255"), + HDA_CODEC_ID(0x10ec0256, "ALC256"), + HDA_CODEC_ID(0x10ec0257, "ALC257"), + HDA_CODEC_ID(0x10ec0269, "ALC269"), + HDA_CODEC_ID(0x10ec0270, "ALC270"), + HDA_CODEC_ID(0x10ec0274, "ALC274"), + HDA_CODEC_ID(0x10ec0275, "ALC275"), + HDA_CODEC_ID(0x10ec0276, "ALC276"), + HDA_CODEC_ID(0x10ec0280, "ALC280"), + HDA_CODEC_ID(0x10ec0282, "ALC282"), + HDA_CODEC_ID(0x10ec0283, "ALC283"), + HDA_CODEC_ID(0x10ec0284, "ALC284"), + HDA_CODEC_ID(0x10ec0285, "ALC285"), + HDA_CODEC_ID(0x10ec0286, "ALC286"), + HDA_CODEC_ID(0x10ec0287, "ALC287"), + HDA_CODEC_ID(0x10ec0288, "ALC288"), + HDA_CODEC_ID(0x10ec0289, "ALC289"), + HDA_CODEC_ID(0x10ec0290, "ALC290"), + HDA_CODEC_ID(0x10ec0292, "ALC292"), + HDA_CODEC_ID(0x10ec0293, "ALC293"), + HDA_CODEC_ID(0x10ec0294, "ALC294"), + HDA_CODEC_ID(0x10ec0295, "ALC295"), + HDA_CODEC_ID(0x10ec0298, "ALC298"), + HDA_CODEC_ID(0x10ec0299, "ALC299"), + HDA_CODEC_ID(0x10ec0300, "ALC300"), + HDA_CODEC_ID(0x10ec0623, "ALC623"), + HDA_CODEC_ID(0x10ec0700, "ALC700"), + HDA_CODEC_ID(0x10ec0701, "ALC701"), + HDA_CODEC_ID(0x10ec0703, "ALC703"), + HDA_CODEC_ID(0x10ec0711, "ALC711"), + HDA_CODEC_ID(0x19e58326, "HW8326"), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc269); @@ -8129,6 +8139,7 @@ MODULE_IMPORT_NS("SND_HDA_SCODEC_COMPONENT"); static struct hda_codec_driver alc269_driver = { .id = snd_hda_id_alc269, + .ops = &alc269_codec_ops, }; module_hda_codec_driver(alc269_driver); diff --git a/sound/hda/codecs/realtek/alc662.c b/sound/hda/codecs/realtek/alc662.c index 94e4a313e5e2..5073165d1f3c 100644 --- a/sound/hda/codecs/realtek/alc662.c +++ b/sound/hda/codecs/realtek/alc662.c @@ -994,7 +994,7 @@ static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = { /* */ -static int patch_alc662(struct hda_codec *codec) +static int alc662_probe(struct hda_codec *codec, const struct hda_device_id *id) { struct alc_spec *spec; int err; @@ -1067,26 +1067,39 @@ static int patch_alc662(struct hda_codec *codec) return 0; error: - alc_free(codec); + snd_hda_gen_remove(codec); return err; } +static const struct hda_codec_ops alc662_codec_ops = { + .probe = alc662_probe, + .remove = snd_hda_gen_remove, + .build_controls = alc_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = alc_init, + .unsol_event = snd_hda_jack_unsol_event, + .resume = alc_resume, + .suspend = alc_suspend, + .check_power_status = snd_hda_gen_check_power_status, + .stream_pm = snd_hda_gen_stream_pm, +}; + /* * driver entries */ static const struct hda_device_id snd_hda_id_alc662[] = { - HDA_CODEC_ENTRY(0x10ec0272, "ALC272", patch_alc662), - HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100101, "ALC662 rev1", patch_alc662), - HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100300, "ALC662 rev3", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0663, "ALC663", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0665, "ALC665", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0667, "ALC667", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0668, "ALC668", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0670, "ALC670", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0671, "ALC671", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0867, "ALC891", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662), - HDA_CODEC_ENTRY(0x10ec0897, "ALC897", patch_alc662), + HDA_CODEC_ID(0x10ec0272, "ALC272"), + HDA_CODEC_ID_REV(0x10ec0662, 0x100101, "ALC662 rev1"), + HDA_CODEC_ID_REV(0x10ec0662, 0x100300, "ALC662 rev3"), + HDA_CODEC_ID(0x10ec0663, "ALC663"), + HDA_CODEC_ID(0x10ec0665, "ALC665"), + HDA_CODEC_ID(0x10ec0667, "ALC667"), + HDA_CODEC_ID(0x10ec0668, "ALC668"), + HDA_CODEC_ID(0x10ec0670, "ALC670"), + HDA_CODEC_ID(0x10ec0671, "ALC671"), + HDA_CODEC_ID(0x10ec0867, "ALC891"), + HDA_CODEC_ID(0x10ec0892, "ALC892"), + HDA_CODEC_ID(0x10ec0897, "ALC897"), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc662); @@ -1097,6 +1110,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); static struct hda_codec_driver alc662_driver = { .id = snd_hda_id_alc662, + .ops = &alc662_codec_ops, }; module_hda_codec_driver(alc662_driver); diff --git a/sound/hda/codecs/realtek/alc680.c b/sound/hda/codecs/realtek/alc680.c index baf19ee3bc2f..8aab1026243c 100644 --- a/sound/hda/codecs/realtek/alc680.c +++ b/sound/hda/codecs/realtek/alc680.c @@ -14,7 +14,7 @@ static int alc680_parse_auto_config(struct hda_codec *codec) /* */ -static int patch_alc680(struct hda_codec *codec) +static int alc680_probe(struct hda_codec *codec, const struct hda_device_id *id) { int err; @@ -26,18 +26,31 @@ static int patch_alc680(struct hda_codec *codec) /* automatic parse from the BIOS config */ err = alc680_parse_auto_config(codec); if (err < 0) { - alc_free(codec); + snd_hda_gen_remove(codec); return err; } return 0; } +static const struct hda_codec_ops alc680_codec_ops = { + .probe = alc680_probe, + .remove = snd_hda_gen_remove, + .build_controls = alc_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = alc_init, + .unsol_event = snd_hda_jack_unsol_event, + .resume = alc_resume, + .suspend = alc_suspend, + .check_power_status = snd_hda_gen_check_power_status, + .stream_pm = snd_hda_gen_stream_pm, +}; + /* * driver entries */ static const struct hda_device_id snd_hda_id_alc680[] = { - HDA_CODEC_ENTRY(0x10ec0680, "ALC680", patch_alc680), + HDA_CODEC_ID(0x10ec0680, "ALC680"), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc680); @@ -48,6 +61,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); static struct hda_codec_driver alc680_driver = { .id = snd_hda_id_alc680, + .ops = &alc680_codec_ops, }; module_hda_codec_driver(alc680_driver); diff --git a/sound/hda/codecs/realtek/alc861.c b/sound/hda/codecs/realtek/alc861.c index 0eb70b44dc05..270037c6504a 100644 --- a/sound/hda/codecs/realtek/alc861.c +++ b/sound/hda/codecs/realtek/alc861.c @@ -88,7 +88,7 @@ static const struct hda_quirk alc861_fixup_tbl[] = { /* */ -static int patch_alc861(struct hda_codec *codec) +static int alc861_probe(struct hda_codec *codec, const struct hda_device_id *id) { struct alc_spec *spec; int err; @@ -124,16 +124,29 @@ static int patch_alc861(struct hda_codec *codec) return 0; error: - alc_free(codec); + snd_hda_gen_remove(codec); return err; } +static const struct hda_codec_ops alc861_codec_ops = { + .probe = alc861_probe, + .remove = snd_hda_gen_remove, + .build_controls = alc_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = alc_init, + .unsol_event = snd_hda_jack_unsol_event, + .resume = alc_resume, + .suspend = alc_suspend, + .check_power_status = snd_hda_gen_check_power_status, + .stream_pm = snd_hda_gen_stream_pm, +}; + /* * driver entries */ static const struct hda_device_id snd_hda_id_alc861[] = { - HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861), - HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861), + HDA_CODEC_ID_REV(0x10ec0861, 0x100340, "ALC660"), + HDA_CODEC_ID(0x10ec0861, "ALC861"), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc861); @@ -144,6 +157,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); static struct hda_codec_driver alc861_driver = { .id = snd_hda_id_alc861, + .ops = &alc861_codec_ops, }; module_hda_codec_driver(alc861_driver); diff --git a/sound/hda/codecs/realtek/alc861vd.c b/sound/hda/codecs/realtek/alc861vd.c index ebf274ad730b..44264e0d6e56 100644 --- a/sound/hda/codecs/realtek/alc861vd.c +++ b/sound/hda/codecs/realtek/alc861vd.c @@ -62,7 +62,7 @@ static const struct hda_quirk alc861vd_fixup_tbl[] = { /* */ -static int patch_alc861vd(struct hda_codec *codec) +static int alc861vd_probe(struct hda_codec *codec, const struct hda_device_id *id) { struct alc_spec *spec; int err; @@ -98,16 +98,29 @@ static int patch_alc861vd(struct hda_codec *codec) return 0; error: - alc_free(codec); + snd_hda_gen_remove(codec); return err; } +static const struct hda_codec_ops alc861vd_codec_ops = { + .probe = alc861vd_probe, + .remove = snd_hda_gen_remove, + .build_controls = alc_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = alc_init, + .unsol_event = snd_hda_jack_unsol_event, + .resume = alc_resume, + .suspend = alc_suspend, + .check_power_status = snd_hda_gen_check_power_status, + .stream_pm = snd_hda_gen_stream_pm, +}; + /* * driver entries */ static const struct hda_device_id snd_hda_id_alc861vd[] = { - HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd), - HDA_CODEC_ENTRY(0x10ec0862, "ALC861-VD", patch_alc861vd), + HDA_CODEC_ID(0x10ec0660, "ALC660-VD"), + HDA_CODEC_ID(0x10ec0862, "ALC861-VD"), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc861vd); @@ -118,6 +131,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); static struct hda_codec_driver alc861vd_driver = { .id = snd_hda_id_alc861vd, + .ops = &alc861vd_codec_ops, }; module_hda_codec_driver(alc861vd_driver); diff --git a/sound/hda/codecs/realtek/alc880.c b/sound/hda/codecs/realtek/alc880.c index 2e828ab96dc5..bf1bdf11ec2d 100644 --- a/sound/hda/codecs/realtek/alc880.c +++ b/sound/hda/codecs/realtek/alc880.c @@ -434,9 +434,9 @@ static const struct hda_model_fixup alc880_fixup_models[] = { /* - * OK, here we have finally the patch for ALC880 + * OK, here we have finally the probe for ALC880 */ -static int patch_alc880(struct hda_codec *codec) +static int alc880_probe(struct hda_codec *codec, const struct hda_device_id *id) { struct alc_spec *spec; int err; @@ -449,8 +449,6 @@ static int patch_alc880(struct hda_codec *codec) spec->gen.need_dac_fix = 1; spec->gen.beep_nid = 0x01; - codec->patch_ops.unsol_event = alc880_unsol_event; - alc_pre_init(codec); snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl, @@ -473,15 +471,28 @@ static int patch_alc880(struct hda_codec *codec) return 0; error: - alc_free(codec); + snd_hda_gen_remove(codec); return err; } +static const struct hda_codec_ops alc880_codec_ops = { + .probe = alc880_probe, + .remove = snd_hda_gen_remove, + .build_controls = alc_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = alc_init, + .unsol_event = alc880_unsol_event, + .resume = alc_resume, + .suspend = alc_suspend, + .check_power_status = snd_hda_gen_check_power_status, + .stream_pm = snd_hda_gen_stream_pm, +}; + /* * driver entries */ static const struct hda_device_id snd_hda_id_alc880[] = { - HDA_CODEC_ENTRY(0x10ec0880, "ALC880", patch_alc880), + HDA_CODEC_ID(0x10ec0880, "ALC880"), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc880); @@ -492,6 +503,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); static struct hda_codec_driver alc880_driver = { .id = snd_hda_id_alc880, + .ops = &alc880_codec_ops, }; module_hda_codec_driver(alc880_driver); diff --git a/sound/hda/codecs/realtek/alc882.c b/sound/hda/codecs/realtek/alc882.c index 6af2f7fcc6bb..529fecd5baa0 100644 --- a/sound/hda/codecs/realtek/alc882.c +++ b/sound/hda/codecs/realtek/alc882.c @@ -757,7 +757,7 @@ static int alc882_parse_auto_config(struct hda_codec *codec) /* */ -static int patch_alc882(struct hda_codec *codec) +static int alc882_probe(struct hda_codec *codec, const struct hda_device_id *id) { struct alc_spec *spec; int err; @@ -809,29 +809,42 @@ static int patch_alc882(struct hda_codec *codec) return 0; error: - alc_free(codec); + snd_hda_gen_remove(codec); return err; } +static const struct hda_codec_ops alc882_codec_ops = { + .probe = alc882_probe, + .remove = snd_hda_gen_remove, + .build_controls = alc_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = alc_init, + .unsol_event = snd_hda_jack_unsol_event, + .resume = alc_resume, + .suspend = alc_suspend, + .check_power_status = snd_hda_gen_check_power_status, + .stream_pm = snd_hda_gen_stream_pm, +}; + /* * driver entries */ static const struct hda_device_id snd_hda_id_alc882[] = { - HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100002, "ALC662 rev2", patch_alc882), - HDA_CODEC_ENTRY(0x10ec0882, "ALC882", patch_alc882), - HDA_CODEC_ENTRY(0x10ec0883, "ALC883", patch_alc882), - HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100101, "ALC889A", patch_alc882), - HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100103, "ALC889A", patch_alc882), - HDA_CODEC_ENTRY(0x10ec0885, "ALC885", patch_alc882), - HDA_CODEC_ENTRY(0x10ec0887, "ALC887", patch_alc882), - HDA_CODEC_REV_ENTRY(0x10ec0888, 0x100101, "ALC1200", patch_alc882), - HDA_CODEC_ENTRY(0x10ec0888, "ALC888", patch_alc882), - HDA_CODEC_ENTRY(0x10ec0889, "ALC889", patch_alc882), - HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882), - HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882), - HDA_CODEC_ENTRY(0x10ec0b00, "ALCS1200A", patch_alc882), - HDA_CODEC_ENTRY(0x10ec1168, "ALC1220", patch_alc882), - HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882), + HDA_CODEC_ID_REV(0x10ec0662, 0x100002, "ALC662 rev2"), + HDA_CODEC_ID(0x10ec0882, "ALC882"), + HDA_CODEC_ID(0x10ec0883, "ALC883"), + HDA_CODEC_ID_REV(0x10ec0885, 0x100101, "ALC889A"), + HDA_CODEC_ID_REV(0x10ec0885, 0x100103, "ALC889A"), + HDA_CODEC_ID(0x10ec0885, "ALC885"), + HDA_CODEC_ID(0x10ec0887, "ALC887"), + HDA_CODEC_ID_REV(0x10ec0888, 0x100101, "ALC1200"), + HDA_CODEC_ID(0x10ec0888, "ALC888"), + HDA_CODEC_ID(0x10ec0889, "ALC889"), + HDA_CODEC_ID(0x10ec0899, "ALC898"), + HDA_CODEC_ID(0x10ec0900, "ALC1150"), + HDA_CODEC_ID(0x10ec0b00, "ALCS1200A"), + HDA_CODEC_ID(0x10ec1168, "ALC1220"), + HDA_CODEC_ID(0x10ec1220, "ALC1220"), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc882); @@ -842,6 +855,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); static struct hda_codec_driver alc882_driver = { .id = snd_hda_id_alc882, + .ops = &alc882_codec_ops, }; module_hda_codec_driver(alc882_driver); diff --git a/sound/hda/codecs/realtek/realtek.c b/sound/hda/codecs/realtek/realtek.c index 4ab49e76c304..66b2efb9acb3 100644 --- a/sound/hda/codecs/realtek/realtek.c +++ b/sound/hda/codecs/realtek/realtek.c @@ -862,27 +862,13 @@ int alc_resume(struct hda_codec *codec) if (!spec->no_depop_delay) msleep(150); /* to avoid pop noise */ - codec->patch_ops.init(codec); + snd_hda_codec_init(codec); snd_hda_regmap_sync(codec); hda_call_check_power_status(codec, 0x01); return 0; } EXPORT_SYMBOL_NS_GPL(alc_resume, "SND_HDA_CODEC_REALTEK"); -/* - */ -const struct hda_codec_ops alc_patch_ops = { - .build_controls = alc_build_controls, - .build_pcms = snd_hda_gen_build_pcms, - .init = alc_init, - .free = alc_free, - .unsol_event = snd_hda_jack_unsol_event, - .resume = alc_resume, - .suspend = alc_suspend, - .check_power_status = snd_hda_gen_check_power_status, -}; -EXPORT_SYMBOL_NS_GPL(alc_patch_ops, "SND_HDA_CODEC_REALTEK"); - /* * Rename codecs appropriately from COEF value or subvendor id */ @@ -1082,7 +1068,6 @@ int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid) /* FIXME: do we need this for all Realtek codec models? */ codec->spdif_status_reset = 1; codec->forced_resume = 1; - codec->patch_ops = alc_patch_ops; mutex_init(&spec->coef_mutex); err = alc_codec_rename_from_preset(codec); diff --git a/sound/hda/codecs/realtek/realtek.h b/sound/hda/codecs/realtek/realtek.h index ac142f2540e3..ee893da0c486 100644 --- a/sound/hda/codecs/realtek/realtek.h +++ b/sound/hda/codecs/realtek/realtek.h @@ -226,15 +226,11 @@ void alc_power_eapd(struct hda_codec *codec); int alc_suspend(struct hda_codec *codec); int alc_resume(struct hda_codec *codec); -#define alc_free snd_hda_gen_free - int alc_parse_auto_config(struct hda_codec *codec, const hda_nid_t *ignore_nids, const hda_nid_t *ssid_nids); int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid); -extern const struct hda_codec_ops alc_patch_ops; - #define alc_codec_rename(codec, name) snd_hda_codec_set_name(codec, name) #ifdef CONFIG_SND_HDA_INPUT_BEEP From 0f1e8306dcbef54f64368aefaff175d5a135671b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:15 +0200 Subject: [PATCH 328/385] ALSA: hda/cmedia: Rewrite to new probe method Convert the C-Media codec driver to use the new hda_codec_ops probe. Since the CM9825 uses a completely different probe and codec ops, factor out to an individual codec driver, snd-hda-codec-cm9825. Other than that, no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-13-tiwai@suse.de --- sound/hda/codecs/Kconfig | 10 + sound/hda/codecs/Makefile | 2 + sound/hda/codecs/cm9825.c | 312 ++++++++++++++++++++++++++++++++ sound/hda/codecs/cmedia.c | 372 +++++--------------------------------- 4 files changed, 365 insertions(+), 331 deletions(-) create mode 100644 sound/hda/codecs/cm9825.c diff --git a/sound/hda/codecs/Kconfig b/sound/hda/codecs/Kconfig index e8c2efd2efb6..addbc9424336 100644 --- a/sound/hda/codecs/Kconfig +++ b/sound/hda/codecs/Kconfig @@ -99,6 +99,16 @@ config SND_HDA_CODEC_CMEDIA comment "Set to Y if you want auto-loading the codec driver" depends on SND_HDA=y && SND_HDA_CODEC_CMEDIA=m +config SND_HDA_CODEC_CM9825 + tristate "Build C-Media CM9825 HD-audio codec support" + select SND_HDA_GENERIC + help + Say Y or M here to include C-Media CM9825 HD-audio codec support in + snd-hda-intel driver + +comment "Set to Y if you want auto-loading the codec driver" + depends on SND_HDA=y && SND_HDA_CODEC_CM9825=m + config SND_HDA_CODEC_SI3054 tristate "Build Silicon Labs 3054 HD-modem codec support" help diff --git a/sound/hda/codecs/Makefile b/sound/hda/codecs/Makefile index 14e5041aa4f0..e7f03e281999 100644 --- a/sound/hda/codecs/Makefile +++ b/sound/hda/codecs/Makefile @@ -3,6 +3,7 @@ subdir-ccflags-y += -I$(src)/../common snd-hda-codec-generic-y := generic.o snd-hda-codec-cmedia-y := cmedia.o +snd-hda-codec-cm9825-y := cm9825.o snd-hda-codec-analog-y := analog.o snd-hda-codec-ca0110-y := ca0110.o snd-hda-codec-ca0132-y := ca0132.o @@ -21,6 +22,7 @@ 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_CM9825) += snd-hda-codec-cm9825.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 diff --git a/sound/hda/codecs/cm9825.c b/sound/hda/codecs/cm9825.c new file mode 100644 index 000000000000..5c474ce44348 --- /dev/null +++ b/sound/hda/codecs/cm9825.c @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * CM9825 HD-audio codec + */ + +#include +#include +#include +#include +#include +#include "hda_local.h" +#include "hda_auto_parser.h" +#include "hda_jack.h" +#include "generic.h" + +/* CM9825 Offset Definitions */ + +#define CM9825_VERB_SET_HPF_1 0x781 +#define CM9825_VERB_SET_HPF_2 0x785 +#define CM9825_VERB_SET_PLL 0x7a0 +#define CM9825_VERB_SET_NEG 0x7a1 +#define CM9825_VERB_SET_ADCL 0x7a2 +#define CM9825_VERB_SET_DACL 0x7a3 +#define CM9825_VERB_SET_MBIAS 0x7a4 +#define CM9825_VERB_SET_VNEG 0x7a8 +#define CM9825_VERB_SET_D2S 0x7a9 +#define CM9825_VERB_SET_DACTRL 0x7aa +#define CM9825_VERB_SET_PDNEG 0x7ac +#define CM9825_VERB_SET_VDO 0x7ad +#define CM9825_VERB_SET_CDALR 0x7b0 +#define CM9825_VERB_SET_MTCBA 0x7b1 +#define CM9825_VERB_SET_OTP 0x7b2 +#define CM9825_VERB_SET_OCP 0x7b3 +#define CM9825_VERB_SET_GAD 0x7b4 +#define CM9825_VERB_SET_TMOD 0x7b5 +#define CM9825_VERB_SET_SNR 0x7b6 + +struct cmi_spec { + struct hda_gen_spec gen; + const struct hda_verb *chip_d0_verbs; + const struct hda_verb *chip_d3_verbs; + const struct hda_verb *chip_hp_present_verbs; + const struct hda_verb *chip_hp_remove_verbs; + struct hda_codec *codec; + struct delayed_work unsol_hp_work; + int quirk; +}; + +static const struct hda_verb cm9825_std_d3_verbs[] = { + /* chip sleep verbs */ + {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */ + {0x43, CM9825_VERB_SET_PLL, 0x01}, /* PLL set */ + {0x43, CM9825_VERB_SET_NEG, 0xc2}, /* NEG set */ + {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */ + {0x43, CM9825_VERB_SET_DACL, 0x02}, /* DACL */ + {0x43, CM9825_VERB_SET_VNEG, 0x50}, /* VOL NEG */ + {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */ + {0x43, CM9825_VERB_SET_PDNEG, 0x04}, /* SEL OSC */ + {0x43, CM9825_VERB_SET_CDALR, 0xf6}, /* Class D */ + {0x43, CM9825_VERB_SET_OTP, 0xcd}, /* OTP set */ + {} +}; + +static const struct hda_verb cm9825_std_d0_verbs[] = { + /* chip init verbs */ + {0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, /* EAPD set */ + {0x43, CM9825_VERB_SET_SNR, 0x30}, /* SNR set */ + {0x43, CM9825_VERB_SET_PLL, 0x00}, /* PLL set */ + {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */ + {0x43, CM9825_VERB_SET_DACL, 0x02}, /* DACL */ + {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */ + {0x43, CM9825_VERB_SET_VNEG, 0x56}, /* VOL NEG */ + {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */ + {0x43, CM9825_VERB_SET_DACTRL, 0x00}, /* DACTRL set */ + {0x43, CM9825_VERB_SET_PDNEG, 0x0c}, /* SEL OSC */ + {0x43, CM9825_VERB_SET_VDO, 0x80}, /* VDO set */ + {0x43, CM9825_VERB_SET_CDALR, 0xf4}, /* Class D */ + {0x43, CM9825_VERB_SET_OTP, 0xcd}, /* OTP set */ + {0x43, CM9825_VERB_SET_MTCBA, 0x61}, /* SR set */ + {0x43, CM9825_VERB_SET_OCP, 0x33}, /* OTP set */ + {0x43, CM9825_VERB_SET_GAD, 0x07}, /* ADC -3db */ + {0x43, CM9825_VERB_SET_TMOD, 0x26}, /* Class D clk */ + {0x3C, AC_VERB_SET_AMP_GAIN_MUTE | + AC_AMP_SET_OUTPUT | AC_AMP_SET_RIGHT, 0x2d}, /* Gain set */ + {0x3C, AC_VERB_SET_AMP_GAIN_MUTE | + AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT, 0x2d}, /* Gain set */ + {0x43, CM9825_VERB_SET_HPF_1, 0x40}, /* HPF set */ + {0x43, CM9825_VERB_SET_HPF_2, 0x40}, /* HPF set */ + {} +}; + +static const struct hda_verb cm9825_hp_present_verbs[] = { + {0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00}, /* PIN off */ + {0x43, CM9825_VERB_SET_ADCL, 0x88}, /* ADC */ + {0x43, CM9825_VERB_SET_DACL, 0xaa}, /* DACL */ + {0x43, CM9825_VERB_SET_MBIAS, 0x10}, /* MBIAS */ + {0x43, CM9825_VERB_SET_D2S, 0xf2}, /* depop */ + {0x43, CM9825_VERB_SET_DACTRL, 0x00}, /* DACTRL set */ + {0x43, CM9825_VERB_SET_VDO, 0xc4}, /* VDO set */ + {} +}; + +static const struct hda_verb cm9825_hp_remove_verbs[] = { + {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */ + {0x43, CM9825_VERB_SET_DACL, 0x56}, /* DACL */ + {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */ + {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */ + {0x43, CM9825_VERB_SET_DACTRL, 0xe0}, /* DACTRL set */ + {0x43, CM9825_VERB_SET_VDO, 0x80}, /* VDO set */ + {0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, /* PIN on */ + {} +}; + +static void cm9825_unsol_hp_delayed(struct work_struct *work) +{ + struct cmi_spec *spec = + container_of(to_delayed_work(work), struct cmi_spec, unsol_hp_work); + struct hda_jack_tbl *jack; + hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; + bool hp_jack_plugin = false; + int err = 0; + + hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin); + + codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n", + (int)hp_jack_plugin, hp_pin); + + if (!hp_jack_plugin) { + err = + snd_hda_codec_write(spec->codec, 0x42, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40); + if (err) + codec_dbg(spec->codec, "codec_write err %d\n", err); + + snd_hda_sequence_write(spec->codec, spec->chip_hp_remove_verbs); + } else { + snd_hda_sequence_write(spec->codec, + spec->chip_hp_present_verbs); + } + + jack = snd_hda_jack_tbl_get(spec->codec, hp_pin); + if (jack) { + jack->block_report = 0; + snd_hda_jack_report_sync(spec->codec); + } +} + +static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb) +{ + struct cmi_spec *spec = codec->spec; + struct hda_jack_tbl *tbl; + + /* Delay enabling the HP amp, to let the mic-detection + * state machine run. + */ + + codec_dbg(spec->codec, "cb->nid 0x%X\n", cb->nid); + + tbl = snd_hda_jack_tbl_get(codec, cb->nid); + if (tbl) + tbl->block_report = 1; + schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(200)); +} + +static void cm9825_setup_unsol(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + + hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; + + snd_hda_jack_detect_enable_callback(codec, hp_pin, hp_callback); +} + +static int cm9825_init(struct hda_codec *codec) +{ + snd_hda_gen_init(codec); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); + + return 0; +} + +static void cm9825_remove(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + + cancel_delayed_work_sync(&spec->unsol_hp_work); + snd_hda_gen_remove(codec); +} + +static int cm9825_suspend(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + + cancel_delayed_work_sync(&spec->unsol_hp_work); + + snd_hda_sequence_write(codec, spec->chip_d3_verbs); + + return 0; +} + +static int cm9825_resume(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + hda_nid_t hp_pin = 0; + bool hp_jack_plugin = false; + int err; + + err = + snd_hda_codec_write(spec->codec, 0x42, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00); + if (err) + codec_dbg(codec, "codec_write err %d\n", err); + + msleep(150); /* for depop noise */ + + snd_hda_codec_init(codec); + + hp_pin = spec->gen.autocfg.hp_pins[0]; + hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin); + + codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n", + (int)hp_jack_plugin, hp_pin); + + if (!hp_jack_plugin) { + err = + snd_hda_codec_write(spec->codec, 0x42, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40); + + if (err) + codec_dbg(codec, "codec_write err %d\n", err); + + snd_hda_sequence_write(codec, cm9825_hp_remove_verbs); + } + + snd_hda_regmap_sync(codec); + hda_call_check_power_status(codec, 0x01); + + return 0; +} + +static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id) +{ + struct cmi_spec *spec; + struct auto_pin_cfg *cfg; + int err; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + INIT_DELAYED_WORK(&spec->unsol_hp_work, cm9825_unsol_hp_delayed); + codec->spec = spec; + spec->codec = codec; + cfg = &spec->gen.autocfg; + snd_hda_gen_spec_init(&spec->gen); + spec->chip_d0_verbs = cm9825_std_d0_verbs; + spec->chip_d3_verbs = cm9825_std_d3_verbs; + spec->chip_hp_present_verbs = cm9825_hp_present_verbs; + spec->chip_hp_remove_verbs = cm9825_hp_remove_verbs; + + snd_hda_sequence_write(codec, spec->chip_d0_verbs); + + err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); + if (err < 0) + goto error; + err = snd_hda_gen_parse_auto_config(codec, cfg); + if (err < 0) + goto error; + + cm9825_setup_unsol(codec); + + return 0; + + error: + cm9825_remove(codec); + + codec_info(codec, "Enter err %d\n", err); + + return err; +} + +static const struct hda_codec_ops cm9825_codec_ops = { + .probe = cm9825_probe, + .remove = cm9825_remove, + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = cm9825_init, + .unsol_event = snd_hda_jack_unsol_event, + .suspend = cm9825_suspend, + .resume = cm9825_resume, + .check_power_status = snd_hda_gen_check_power_status, + .stream_pm = snd_hda_gen_stream_pm, +}; + +/* + * driver entries + */ +static const struct hda_device_id snd_hda_id_cm9825[] = { + HDA_CODEC_ID(0x13f69825, "CM9825"), + {} /* terminator */ +}; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cm9825); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("CM9825 HD-audio codec"); + +static struct hda_codec_driver cm9825_driver = { + .id = snd_hda_id_cm9825, + .ops = &cm9825_codec_ops, +}; + +module_hda_codec_driver(cm9825_driver); diff --git a/sound/hda/codecs/cmedia.c b/sound/hda/codecs/cmedia.c index c88da2f8233e..15e5a1118a6e 100644 --- a/sound/hda/codecs/cmedia.c +++ b/sound/hda/codecs/cmedia.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Universal Interface for Intel High Definition Audio Codec + * Universal codec driver for Intel High Definition Audio Codec * - * HD audio interface patch for C-Media CMI9880 + * HD audio codec driver for C-Media CMI9880 * * Copyright (c) 2004 Takashi Iwai */ @@ -17,293 +17,11 @@ #include "hda_jack.h" #include "generic.h" -/* CM9825 Offset Definitions */ - -#define CM9825_VERB_SET_HPF_1 0x781 -#define CM9825_VERB_SET_HPF_2 0x785 -#define CM9825_VERB_SET_PLL 0x7a0 -#define CM9825_VERB_SET_NEG 0x7a1 -#define CM9825_VERB_SET_ADCL 0x7a2 -#define CM9825_VERB_SET_DACL 0x7a3 -#define CM9825_VERB_SET_MBIAS 0x7a4 -#define CM9825_VERB_SET_VNEG 0x7a8 -#define CM9825_VERB_SET_D2S 0x7a9 -#define CM9825_VERB_SET_DACTRL 0x7aa -#define CM9825_VERB_SET_PDNEG 0x7ac -#define CM9825_VERB_SET_VDO 0x7ad -#define CM9825_VERB_SET_CDALR 0x7b0 -#define CM9825_VERB_SET_MTCBA 0x7b1 -#define CM9825_VERB_SET_OTP 0x7b2 -#define CM9825_VERB_SET_OCP 0x7b3 -#define CM9825_VERB_SET_GAD 0x7b4 -#define CM9825_VERB_SET_TMOD 0x7b5 -#define CM9825_VERB_SET_SNR 0x7b6 - -struct cmi_spec { - struct hda_gen_spec gen; - const struct hda_verb *chip_d0_verbs; - const struct hda_verb *chip_d3_verbs; - const struct hda_verb *chip_hp_present_verbs; - const struct hda_verb *chip_hp_remove_verbs; - struct hda_codec *codec; - struct delayed_work unsol_hp_work; - int quirk; -}; - -static const struct hda_verb cm9825_std_d3_verbs[] = { - /* chip sleep verbs */ - {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */ - {0x43, CM9825_VERB_SET_PLL, 0x01}, /* PLL set */ - {0x43, CM9825_VERB_SET_NEG, 0xc2}, /* NEG set */ - {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */ - {0x43, CM9825_VERB_SET_DACL, 0x02}, /* DACL */ - {0x43, CM9825_VERB_SET_VNEG, 0x50}, /* VOL NEG */ - {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */ - {0x43, CM9825_VERB_SET_PDNEG, 0x04}, /* SEL OSC */ - {0x43, CM9825_VERB_SET_CDALR, 0xf6}, /* Class D */ - {0x43, CM9825_VERB_SET_OTP, 0xcd}, /* OTP set */ - {} -}; - -static const struct hda_verb cm9825_std_d0_verbs[] = { - /* chip init verbs */ - {0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, /* EAPD set */ - {0x43, CM9825_VERB_SET_SNR, 0x30}, /* SNR set */ - {0x43, CM9825_VERB_SET_PLL, 0x00}, /* PLL set */ - {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */ - {0x43, CM9825_VERB_SET_DACL, 0x02}, /* DACL */ - {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */ - {0x43, CM9825_VERB_SET_VNEG, 0x56}, /* VOL NEG */ - {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */ - {0x43, CM9825_VERB_SET_DACTRL, 0x00}, /* DACTRL set */ - {0x43, CM9825_VERB_SET_PDNEG, 0x0c}, /* SEL OSC */ - {0x43, CM9825_VERB_SET_VDO, 0x80}, /* VDO set */ - {0x43, CM9825_VERB_SET_CDALR, 0xf4}, /* Class D */ - {0x43, CM9825_VERB_SET_OTP, 0xcd}, /* OTP set */ - {0x43, CM9825_VERB_SET_MTCBA, 0x61}, /* SR set */ - {0x43, CM9825_VERB_SET_OCP, 0x33}, /* OTP set */ - {0x43, CM9825_VERB_SET_GAD, 0x07}, /* ADC -3db */ - {0x43, CM9825_VERB_SET_TMOD, 0x26}, /* Class D clk */ - {0x3C, AC_VERB_SET_AMP_GAIN_MUTE | - AC_AMP_SET_OUTPUT | AC_AMP_SET_RIGHT, 0x2d}, /* Gain set */ - {0x3C, AC_VERB_SET_AMP_GAIN_MUTE | - AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT, 0x2d}, /* Gain set */ - {0x43, CM9825_VERB_SET_HPF_1, 0x40}, /* HPF set */ - {0x43, CM9825_VERB_SET_HPF_2, 0x40}, /* HPF set */ - {} -}; - -static const struct hda_verb cm9825_hp_present_verbs[] = { - {0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00}, /* PIN off */ - {0x43, CM9825_VERB_SET_ADCL, 0x88}, /* ADC */ - {0x43, CM9825_VERB_SET_DACL, 0xaa}, /* DACL */ - {0x43, CM9825_VERB_SET_MBIAS, 0x10}, /* MBIAS */ - {0x43, CM9825_VERB_SET_D2S, 0xf2}, /* depop */ - {0x43, CM9825_VERB_SET_DACTRL, 0x00}, /* DACTRL set */ - {0x43, CM9825_VERB_SET_VDO, 0xc4}, /* VDO set */ - {} -}; - -static const struct hda_verb cm9825_hp_remove_verbs[] = { - {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */ - {0x43, CM9825_VERB_SET_DACL, 0x56}, /* DACL */ - {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */ - {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */ - {0x43, CM9825_VERB_SET_DACTRL, 0xe0}, /* DACTRL set */ - {0x43, CM9825_VERB_SET_VDO, 0x80}, /* VDO set */ - {0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, /* PIN on */ - {} -}; - -static void cm9825_unsol_hp_delayed(struct work_struct *work) +static int cmedia_probe(struct hda_codec *codec, const struct hda_device_id *id) { - struct cmi_spec *spec = - container_of(to_delayed_work(work), struct cmi_spec, unsol_hp_work); - struct hda_jack_tbl *jack; - hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; - bool hp_jack_plugin = false; - int err = 0; - - hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin); - - codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n", - (int)hp_jack_plugin, hp_pin); - - if (!hp_jack_plugin) { - err = - snd_hda_codec_write(spec->codec, 0x42, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40); - if (err) - codec_dbg(spec->codec, "codec_write err %d\n", err); - - snd_hda_sequence_write(spec->codec, spec->chip_hp_remove_verbs); - } else { - snd_hda_sequence_write(spec->codec, - spec->chip_hp_present_verbs); - } - - jack = snd_hda_jack_tbl_get(spec->codec, hp_pin); - if (jack) { - jack->block_report = 0; - snd_hda_jack_report_sync(spec->codec); - } -} - -static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb) -{ - struct cmi_spec *spec = codec->spec; - struct hda_jack_tbl *tbl; - - /* Delay enabling the HP amp, to let the mic-detection - * state machine run. - */ - - codec_dbg(spec->codec, "cb->nid 0x%X\n", cb->nid); - - tbl = snd_hda_jack_tbl_get(codec, cb->nid); - if (tbl) - tbl->block_report = 1; - schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(200)); -} - -static void cm9825_setup_unsol(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - - hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; - - snd_hda_jack_detect_enable_callback(codec, hp_pin, hp_callback); -} - -static int cm9825_init(struct hda_codec *codec) -{ - snd_hda_gen_init(codec); - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); - - return 0; -} - -static void cm9825_free(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - - cancel_delayed_work_sync(&spec->unsol_hp_work); - snd_hda_gen_free(codec); -} - -static int cm9825_suspend(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - - cancel_delayed_work_sync(&spec->unsol_hp_work); - - snd_hda_sequence_write(codec, spec->chip_d3_verbs); - - return 0; -} - -static int cm9825_resume(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - hda_nid_t hp_pin = 0; - bool hp_jack_plugin = false; - int err; - - err = - snd_hda_codec_write(spec->codec, 0x42, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00); - if (err) - codec_dbg(codec, "codec_write err %d\n", err); - - msleep(150); /* for depop noise */ - - codec->patch_ops.init(codec); - - hp_pin = spec->gen.autocfg.hp_pins[0]; - hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin); - - codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n", - (int)hp_jack_plugin, hp_pin); - - if (!hp_jack_plugin) { - err = - snd_hda_codec_write(spec->codec, 0x42, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40); - - if (err) - codec_dbg(codec, "codec_write err %d\n", err); - - snd_hda_sequence_write(codec, cm9825_hp_remove_verbs); - } - - snd_hda_regmap_sync(codec); - hda_call_check_power_status(codec, 0x01); - - return 0; -} - -/* - * stuff for auto-parser - */ -static const struct hda_codec_ops cmi_auto_patch_ops = { - .build_controls = snd_hda_gen_build_controls, - .build_pcms = snd_hda_gen_build_pcms, - .init = snd_hda_gen_init, - .free = snd_hda_gen_free, - .unsol_event = snd_hda_jack_unsol_event, -}; - -static int patch_cm9825(struct hda_codec *codec) -{ - struct cmi_spec *spec; - struct auto_pin_cfg *cfg; - int err; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - INIT_DELAYED_WORK(&spec->unsol_hp_work, cm9825_unsol_hp_delayed); - codec->spec = spec; - spec->codec = codec; - codec->patch_ops = cmi_auto_patch_ops; - codec->patch_ops.init = cm9825_init; - codec->patch_ops.suspend = cm9825_suspend; - codec->patch_ops.resume = cm9825_resume; - codec->patch_ops.free = cm9825_free; - codec->patch_ops.check_power_status = snd_hda_gen_check_power_status; - cfg = &spec->gen.autocfg; - snd_hda_gen_spec_init(&spec->gen); - spec->chip_d0_verbs = cm9825_std_d0_verbs; - spec->chip_d3_verbs = cm9825_std_d3_verbs; - spec->chip_hp_present_verbs = cm9825_hp_present_verbs; - spec->chip_hp_remove_verbs = cm9825_hp_remove_verbs; - - snd_hda_sequence_write(codec, spec->chip_d0_verbs); - - err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); - if (err < 0) - goto error; - err = snd_hda_gen_parse_auto_config(codec, cfg); - if (err < 0) - goto error; - - cm9825_setup_unsol(codec); - - return 0; - - error: - cm9825_free(codec); - - codec_info(codec, "Enter err %d\n", err); - - return err; -} - -static int patch_cmi9880(struct hda_codec *codec) -{ - struct cmi_spec *spec; + struct hda_gen_spec *spec; struct auto_pin_cfg *cfg; + bool is_cmi8888 = id->vendor_id == 0x13f68888; int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); @@ -311,9 +29,15 @@ static int patch_cmi9880(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; - codec->patch_ops = cmi_auto_patch_ops; - cfg = &spec->gen.autocfg; - snd_hda_gen_spec_init(&spec->gen); + cfg = &spec->autocfg; + snd_hda_gen_spec_init(spec); + + if (is_cmi8888) { + /* mask NID 0x10 from the playback volume selection; + * it's a headphone boost volume handled manually below + */ + spec->out_vol_mask = (1ULL << 0x10); + } err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); if (err < 0) @@ -322,33 +46,6 @@ static int patch_cmi9880(struct hda_codec *codec) if (err < 0) goto error; - return 0; - - error: - snd_hda_gen_free(codec); - return err; -} - -static int patch_cmi8888(struct hda_codec *codec) -{ - struct cmi_spec *spec; - struct auto_pin_cfg *cfg; - int err; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - - codec->spec = spec; - codec->patch_ops = cmi_auto_patch_ops; - cfg = &spec->gen.autocfg; - snd_hda_gen_spec_init(&spec->gen); - - /* mask NID 0x10 from the playback volume selection; - * it's a headphone boost volume handled manually below - */ - spec->gen.out_vol_mask = (1ULL << 0x10); - err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); if (err < 0) goto error; @@ -356,32 +53,44 @@ static int patch_cmi8888(struct hda_codec *codec) if (err < 0) goto error; - if (get_defcfg_device(snd_hda_codec_get_pincfg(codec, 0x10)) == - AC_JACK_HP_OUT) { - static const struct snd_kcontrol_new amp_kctl = - HDA_CODEC_VOLUME("Headphone Amp Playback Volume", - 0x10, 0, HDA_OUTPUT); - if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &_kctl)) { - err = -ENOMEM; - goto error; + if (is_cmi8888) { + if (get_defcfg_device(snd_hda_codec_get_pincfg(codec, 0x10)) == + AC_JACK_HP_OUT) { + static const struct snd_kcontrol_new amp_kctl = + HDA_CODEC_VOLUME("Headphone Amp Playback Volume", + 0x10, 0, HDA_OUTPUT); + if (!snd_hda_gen_add_kctl(spec, NULL, &_kctl)) { + err = -ENOMEM; + goto error; + } } } return 0; error: - snd_hda_gen_free(codec); + snd_hda_gen_remove(codec); return err; } +static const struct hda_codec_ops cmedia_codec_ops = { + .probe = cmedia_probe, + .remove = snd_hda_gen_remove, + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = snd_hda_gen_init, + .unsol_event = snd_hda_jack_unsol_event, + .check_power_status = snd_hda_gen_check_power_status, + .stream_pm = snd_hda_gen_stream_pm, +}; + /* - * patch entries + * driver entries */ static const struct hda_device_id snd_hda_id_cmedia[] = { - HDA_CODEC_ENTRY(0x13f68888, "CMI8888", patch_cmi8888), - HDA_CODEC_ENTRY(0x13f69880, "CMI9880", patch_cmi9880), - HDA_CODEC_ENTRY(0x434d4980, "CMI9880", patch_cmi9880), - HDA_CODEC_ENTRY(0x13f69825, "CM9825", patch_cm9825), + HDA_CODEC_ID(0x13f68888, "CMI8888"), + HDA_CODEC_ID(0x13f69880, "CMI9880"), + HDA_CODEC_ID(0x434d4980, "CMI9880"), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cmedia); @@ -391,6 +100,7 @@ MODULE_DESCRIPTION("C-Media HD-audio codec"); static struct hda_codec_driver cmedia_driver = { .id = snd_hda_id_cmedia, + .ops = &cmedia_codec_ops, }; module_hda_codec_driver(cmedia_driver); From f025ef0316ce3650e8f4dc9de2709869c9217dac Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:16 +0200 Subject: [PATCH 329/385] ALSA: hda/analog: Rewrite to new probe method Convert the Analog Device codec driver to use the new hda_codec_ops probe. The probe function had to be unified and branched with the model type specified via driver_data instead. Other than that, no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-14-tiwai@suse.de --- sound/hda/codecs/analog.c | 221 +++++++++++++++++++------------------- 1 file changed, 111 insertions(+), 110 deletions(-) diff --git a/sound/hda/codecs/analog.c b/sound/hda/codecs/analog.c index 3557e06c6d2b..33aaeb44c4dc 100644 --- a/sound/hda/codecs/analog.c +++ b/sound/hda/codecs/analog.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984, + * HD audio codec driver for AD1882, AD1884, AD1981HD, AD1983, AD1984, * AD1986A, AD1988 * * Copyright (c) 2005-2007 Takashi Iwai @@ -18,9 +18,18 @@ #include "hda_jack.h" #include "generic.h" +enum { + MODEL_AD1882, + MODEL_AD1884, + MODEL_AD1981, + MODEL_AD1983, + MODEL_AD1986A, + MODEL_AD1988, +}; struct ad198x_spec { struct hda_gen_spec gen; + int model; /* for auto parser */ int smux_paths[4]; @@ -111,7 +120,7 @@ static void ad198x_power_eapd(struct hda_codec *codec) } } -static int ad198x_suspend(struct hda_codec *codec) +static int ad_codec_suspend(struct hda_codec *codec) { snd_hda_shutup_pins(codec); ad198x_power_eapd(codec); @@ -137,7 +146,7 @@ static void ad_vmaster_eapd_hook(void *private_data, int enabled) * Automatic parse of I/O pins from the BIOS configuration */ -static int ad198x_auto_build_controls(struct hda_codec *codec) +static int ad_codec_build_controls(struct hda_codec *codec) { int err; @@ -150,17 +159,6 @@ static int ad198x_auto_build_controls(struct hda_codec *codec) return 0; } -static const struct hda_codec_ops ad198x_auto_patch_ops = { - .build_controls = ad198x_auto_build_controls, - .build_pcms = snd_hda_gen_build_pcms, - .init = snd_hda_gen_init, - .free = snd_hda_gen_free, - .unsol_event = snd_hda_jack_unsol_event, - .check_power_status = snd_hda_gen_check_power_status, - .suspend = ad198x_suspend, -}; - - static int ad198x_parse_auto_config(struct hda_codec *codec, bool indep_hp) { struct ad198x_spec *spec = codec->spec; @@ -198,7 +196,6 @@ static int alloc_ad_spec(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; snd_hda_gen_spec_init(&spec->gen); - codec->patch_ops = ad198x_auto_patch_ops; return 0; } @@ -375,10 +372,10 @@ static const struct hda_model_fixup ad1986a_fixup_models[] = { /* */ -static int patch_ad1986a(struct hda_codec *codec) +static int ad1986a_probe(struct hda_codec *codec) { int err; - struct ad198x_spec *spec; + struct ad198x_spec *spec = codec->spec; static const hda_nid_t preferred_pairs[] = { 0x1a, 0x03, 0x1b, 0x03, @@ -388,11 +385,6 @@ static int patch_ad1986a(struct hda_codec *codec) 0 }; - err = alloc_ad_spec(codec); - if (err < 0) - return err; - spec = codec->spec; - /* AD1986A has the inverted EAPD implementation */ codec->inv_eapd = 1; @@ -418,10 +410,8 @@ static int patch_ad1986a(struct hda_codec *codec) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); err = ad198x_parse_auto_config(codec, false); - if (err < 0) { - snd_hda_gen_free(codec); + if (err < 0) return err; - } snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); @@ -507,18 +497,13 @@ static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec) return 0; } -static int patch_ad1983(struct hda_codec *codec) +static int ad1983_probe(struct hda_codec *codec) { static const hda_nid_t conn_0c[] = { 0x08 }; static const hda_nid_t conn_0d[] = { 0x09 }; - struct ad198x_spec *spec; + struct ad198x_spec *spec = codec->spec; int err; - err = alloc_ad_spec(codec); - if (err < 0) - return err; - spec = codec->spec; - spec->gen.mixer_nid = 0x0e; spec->gen.beep_nid = 0x10; set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); @@ -529,15 +514,11 @@ static int patch_ad1983(struct hda_codec *codec) err = ad198x_parse_auto_config(codec, false); if (err < 0) - goto error; + return err; err = ad1983_add_spdif_mux_ctl(codec); if (err < 0) - goto error; + return err; return 0; - - error: - snd_hda_gen_free(codec); - return err; } @@ -597,16 +578,11 @@ static const struct hda_quirk ad1981_fixup_tbl[] = { {} }; -static int patch_ad1981(struct hda_codec *codec) +static int ad1981_probe(struct hda_codec *codec) { - struct ad198x_spec *spec; + struct ad198x_spec *spec = codec->spec; int err; - err = alloc_ad_spec(codec); - if (err < 0) - return -ENOMEM; - spec = codec->spec; - spec->gen.mixer_nid = 0x0e; spec->gen.beep_nid = 0x10; set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT); @@ -616,18 +592,14 @@ static int patch_ad1981(struct hda_codec *codec) err = ad198x_parse_auto_config(codec, false); if (err < 0) - goto error; + return err; err = ad1983_add_spdif_mux_ctl(codec); if (err < 0) - goto error; + return err; snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; - - error: - snd_hda_gen_free(codec); - return err; } @@ -776,7 +748,7 @@ static const struct snd_kcontrol_new ad1988_auto_smux_mixer = { .put = ad1988_auto_smux_enum_put, }; -static int ad1988_auto_init(struct hda_codec *codec) +static int ad_codec_init(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; int i, err; @@ -784,6 +756,8 @@ static int ad1988_auto_init(struct hda_codec *codec) err = snd_hda_gen_init(codec); if (err < 0) return err; + if (spec->model != MODEL_AD1988) + return 0; if (!spec->gen.autocfg.dig_outs) return 0; @@ -854,8 +828,6 @@ static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec) if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1988_auto_smux_mixer)) return -ENOMEM; - codec->patch_ops.init = ad1988_auto_init; - return 0; } @@ -889,16 +861,11 @@ static const struct hda_model_fixup ad1988_fixup_models[] = { {} }; -static int patch_ad1988(struct hda_codec *codec) +static int ad1988_probe(struct hda_codec *codec) { - struct ad198x_spec *spec; + struct ad198x_spec *spec = codec->spec; int err; - err = alloc_ad_spec(codec); - if (err < 0) - return err; - spec = codec->spec; - spec->gen.mixer_nid = 0x20; spec->gen.mixer_merge_nid = 0x21; spec->gen.beep_nid = 0x10; @@ -909,18 +876,14 @@ static int patch_ad1988(struct hda_codec *codec) err = ad198x_parse_auto_config(codec, true); if (err < 0) - goto error; + return err; err = ad1988_add_spdif_mux_ctl(codec); if (err < 0) - goto error; + return err; snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; - - error: - snd_hda_gen_free(codec); - return err; } @@ -1069,16 +1032,11 @@ static const struct hda_quirk ad1884_fixup_tbl[] = { }; -static int patch_ad1884(struct hda_codec *codec) +static int ad1884_probe(struct hda_codec *codec) { - struct ad198x_spec *spec; + struct ad198x_spec *spec = codec->spec; int err; - err = alloc_ad_spec(codec); - if (err < 0) - return err; - spec = codec->spec; - spec->gen.mixer_nid = 0x20; spec->gen.mixer_merge_nid = 0x21; spec->gen.beep_nid = 0x10; @@ -1089,18 +1047,14 @@ static int patch_ad1884(struct hda_codec *codec) err = ad198x_parse_auto_config(codec, true); if (err < 0) - goto error; + return err; err = ad1983_add_spdif_mux_ctl(codec); if (err < 0) - goto error; + return err; snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; - - error: - snd_hda_gen_free(codec); - return err; } /* @@ -1115,53 +1069,99 @@ static int patch_ad1884(struct hda_codec *codec) * port-G - rear clfe-out (6stack) */ -static int patch_ad1882(struct hda_codec *codec) +static int ad1882_probe(struct hda_codec *codec) { - struct ad198x_spec *spec; + struct ad198x_spec *spec = codec->spec; int err; - err = alloc_ad_spec(codec); - if (err < 0) - return err; - spec = codec->spec; - spec->gen.mixer_nid = 0x20; spec->gen.mixer_merge_nid = 0x21; spec->gen.beep_nid = 0x10; set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); err = ad198x_parse_auto_config(codec, true); if (err < 0) - goto error; + return err; err = ad1988_add_spdif_mux_ctl(codec); if (err < 0) - goto error; + return err; return 0; - - error: - snd_hda_gen_free(codec); - return err; } - /* - * patch entries + * driver entries */ +static int ad_codec_probe(struct hda_codec *codec, + const struct hda_device_id *id) +{ + struct ad198x_spec *spec; + int err; + + err = alloc_ad_spec(codec); + if (err < 0) + return -ENOMEM; + spec = codec->spec; + spec->model = id->driver_data; + + switch (spec->model) { + case MODEL_AD1882: + err = ad1882_probe(codec); + break; + case MODEL_AD1884: + err = ad1884_probe(codec); + break; + case MODEL_AD1981: + err = ad1981_probe(codec); + break; + case MODEL_AD1983: + err = ad1983_probe(codec); + break; + case MODEL_AD1986A: + err = ad1986a_probe(codec); + break; + case MODEL_AD1988: + err = ad1988_probe(codec); + break; + default: + err = -EINVAL; + break; + } + + if (err < 0) { + snd_hda_gen_remove(codec); + return err; + } + + return 0; +} + +static const struct hda_codec_ops ad_codec_ops = { + .probe = ad_codec_probe, + .remove = snd_hda_gen_remove, + .build_controls = ad_codec_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = ad_codec_init, + .unsol_event = snd_hda_jack_unsol_event, + .suspend = ad_codec_suspend, + .check_power_status = snd_hda_gen_check_power_status, + .stream_pm = snd_hda_gen_stream_pm, +}; + static const struct hda_device_id snd_hda_id_analog[] = { - HDA_CODEC_ENTRY(0x11d4184a, "AD1884A", patch_ad1884), - HDA_CODEC_ENTRY(0x11d41882, "AD1882", patch_ad1882), - HDA_CODEC_ENTRY(0x11d41883, "AD1883", patch_ad1884), - HDA_CODEC_ENTRY(0x11d41884, "AD1884", patch_ad1884), - HDA_CODEC_ENTRY(0x11d4194a, "AD1984A", patch_ad1884), - HDA_CODEC_ENTRY(0x11d4194b, "AD1984B", patch_ad1884), - HDA_CODEC_ENTRY(0x11d41981, "AD1981", patch_ad1981), - HDA_CODEC_ENTRY(0x11d41983, "AD1983", patch_ad1983), - HDA_CODEC_ENTRY(0x11d41984, "AD1984", patch_ad1884), - HDA_CODEC_ENTRY(0x11d41986, "AD1986A", patch_ad1986a), - HDA_CODEC_ENTRY(0x11d41988, "AD1988", patch_ad1988), - HDA_CODEC_ENTRY(0x11d4198b, "AD1988B", patch_ad1988), - HDA_CODEC_ENTRY(0x11d4882a, "AD1882A", patch_ad1882), - HDA_CODEC_ENTRY(0x11d4989a, "AD1989A", patch_ad1988), - HDA_CODEC_ENTRY(0x11d4989b, "AD1989B", patch_ad1988), + HDA_CODEC_ID_MODEL(0x11d4184a, "AD1884A", MODEL_AD1884), + HDA_CODEC_ID_MODEL(0x11d41882, "AD1882", MODEL_AD1882), + HDA_CODEC_ID_MODEL(0x11d41883, "AD1883", MODEL_AD1884), + HDA_CODEC_ID_MODEL(0x11d41884, "AD1884", MODEL_AD1884), + HDA_CODEC_ID_MODEL(0x11d4194a, "AD1984A", MODEL_AD1884), + HDA_CODEC_ID_MODEL(0x11d4194b, "AD1984B", MODEL_AD1884), + HDA_CODEC_ID_MODEL(0x11d41981, "AD1981", MODEL_AD1981), + HDA_CODEC_ID_MODEL(0x11d41983, "AD1983", MODEL_AD1983), + HDA_CODEC_ID_MODEL(0x11d41984, "AD1984", MODEL_AD1884), + HDA_CODEC_ID_MODEL(0x11d41986, "AD1986A", MODEL_AD1986A), + HDA_CODEC_ID_MODEL(0x11d41988, "AD1988", MODEL_AD1988), + HDA_CODEC_ID_MODEL(0x11d4198b, "AD1988B", MODEL_AD1988), + HDA_CODEC_ID_MODEL(0x11d4882a, "AD1882A", MODEL_AD1882), + HDA_CODEC_ID_MODEL(0x11d4989a, "AD1989A", MODEL_AD1988), + HDA_CODEC_ID_MODEL(0x11d4989b, "AD1989B", MODEL_AD1988), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_analog); @@ -1171,6 +1171,7 @@ MODULE_DESCRIPTION("Analog Devices HD-audio codec"); static struct hda_codec_driver analog_driver = { .id = snd_hda_id_analog, + .ops = &ad_codec_ops, }; module_hda_codec_driver(analog_driver); From dbe3e4ab57dd92b1f6bd9ba39aff43aa7a53749a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:17 +0200 Subject: [PATCH 330/385] ALSA: hda/ca0110: Rewrite to new probe method Convert the CA0110 codec driver to use the new hda_codec_ops probe. No functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-15-tiwai@suse.de --- sound/hda/codecs/ca0110.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/sound/hda/codecs/ca0110.c b/sound/hda/codecs/ca0110.c index 0353544435b9..c75a9ff9460d 100644 --- a/sound/hda/codecs/ca0110.c +++ b/sound/hda/codecs/ca0110.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * HD audio interface patch for Creative X-Fi CA0110-IBG chip + * HD audio codec driver for Creative X-Fi CA0110-IBG chip * * Copyright (c) 2008 Takashi Iwai */ @@ -15,15 +15,6 @@ #include "hda_jack.h" #include "generic.h" - -static const struct hda_codec_ops ca0110_patch_ops = { - .build_controls = snd_hda_gen_build_controls, - .build_pcms = snd_hda_gen_build_pcms, - .init = snd_hda_gen_init, - .free = snd_hda_gen_free, - .unsol_event = snd_hda_jack_unsol_event, -}; - static int ca0110_parse_auto_config(struct hda_codec *codec) { struct hda_gen_spec *spec = codec->spec; @@ -39,8 +30,7 @@ static int ca0110_parse_auto_config(struct hda_codec *codec) return 0; } - -static int patch_ca0110(struct hda_codec *codec) +static int ca0110_probe(struct hda_codec *codec, const struct hda_device_id *id) { struct hda_gen_spec *spec; int err; @@ -50,7 +40,6 @@ static int patch_ca0110(struct hda_codec *codec) return -ENOMEM; snd_hda_gen_spec_init(spec); codec->spec = spec; - codec->patch_ops = ca0110_patch_ops; spec->multi_cap_vol = 1; codec->bus->core.needs_damn_long_delay = 1; @@ -62,18 +51,27 @@ static int patch_ca0110(struct hda_codec *codec) return 0; error: - snd_hda_gen_free(codec); + snd_hda_gen_remove(codec); return err; } +static const struct hda_codec_ops ca0110_codec_ops = { + .probe = ca0110_probe, + .remove = snd_hda_gen_remove, + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = snd_hda_gen_init, + .unsol_event = snd_hda_jack_unsol_event, +}; + /* - * patch entries + * driver entries */ static const struct hda_device_id snd_hda_id_ca0110[] = { - HDA_CODEC_ENTRY(0x1102000a, "CA0110-IBG", patch_ca0110), - HDA_CODEC_ENTRY(0x1102000b, "CA0110-IBG", patch_ca0110), - HDA_CODEC_ENTRY(0x1102000d, "SB0880 X-Fi", patch_ca0110), + HDA_CODEC_ID(0x1102000a, "CA0110-IBG"), + HDA_CODEC_ID(0x1102000b, "CA0110-IBG"), + HDA_CODEC_ID(0x1102000d, "SB0880 X-Fi"), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_ca0110); @@ -83,6 +81,7 @@ MODULE_DESCRIPTION("Creative CA0110-IBG HD-audio codec"); static struct hda_codec_driver ca0110_driver = { .id = snd_hda_id_ca0110, + .ops = &ca0110_codec_ops, }; module_hda_codec_driver(ca0110_driver); From 1cb8744a36c7e8faa7098207f835af22a65717b5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:18 +0200 Subject: [PATCH 331/385] ALSA: hda/cirrus: Split to cs420x and cs421x drivers Since the codec ops for CS420x and CS421x are fairly independent, split the cirrus codec driver into two drivers, snd-hda-codec-cs420x and snd-hda-code-cs421x. Together with the split, convert to the new hda_codec_ops probe. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-16-tiwai@suse.de --- sound/hda/codecs/cirrus/Kconfig | 20 +- sound/hda/codecs/cirrus/Makefile | 6 +- .../hda/codecs/cirrus/{cirrus.c => cs420x.c} | 526 +--------------- sound/hda/codecs/cirrus/cs421x.c | 590 ++++++++++++++++++ 4 files changed, 643 insertions(+), 499 deletions(-) rename sound/hda/codecs/cirrus/{cirrus.c => cs420x.c} (61%) create mode 100644 sound/hda/codecs/cirrus/cs421x.c diff --git a/sound/hda/codecs/cirrus/Kconfig b/sound/hda/codecs/cirrus/Kconfig index f6cefb65c5f8..b3a5968e9a02 100644 --- a/sound/hda/codecs/cirrus/Kconfig +++ b/sound/hda/codecs/cirrus/Kconfig @@ -1,14 +1,24 @@ # SPDX-License-Identifier: GPL-2.0-only -config SND_HDA_CODEC_CIRRUS - tristate "Build Cirrus Logic codec support" +config SND_HDA_CODEC_CS420X + tristate "Build Cirrus Logic CS420x codec support" select SND_HDA_GENERIC help - Say Y or M here to include Cirrus Logic codec support in - snd-hda-intel driver, such as CS4206. + Say Y or M here to include Cirrus Logic CS420x codec support in + snd-hda-intel driver comment "Set to Y if you want auto-loading the codec driver" - depends on SND_HDA=y && SND_HDA_CODEC_CIRRUS=m + depends on SND_HDA=y && SND_HDA_CODEC_CS420X=m + +config SND_HDA_CODEC_CS421X + tristate "Build Cirrus Logic CS421x codec support" + select SND_HDA_GENERIC + help + Say Y or M here to include Cirrus Logic CS421x codec support in + snd-hda-intel driver + +comment "Set to Y if you want auto-loading the codec driver" + depends on SND_HDA=y && SND_HDA_CODEC_CS421X=m config SND_HDA_CODEC_CS8409 tristate "Build Cirrus Logic HDA bridge support" diff --git a/sound/hda/codecs/cirrus/Makefile b/sound/hda/codecs/cirrus/Makefile index fa40c893fb09..dda1873ebcf5 100644 --- a/sound/hda/codecs/cirrus/Makefile +++ b/sound/hda/codecs/cirrus/Makefile @@ -1,8 +1,10 @@ # SPDX-License-Identifier: GPL-2.0 subdir-ccflags-y += -I$(src)/../../common -snd-hda-codec-cirrus-y := cirrus.o +snd-hda-codec-cs420x-y := cs420x.o +snd-hda-codec-cs421x-y := cs421x.o snd-hda-codec-cs8409-y := cs8409.o cs8409-tables.o -obj-$(CONFIG_SND_HDA_CODEC_CIRRUS) += snd-hda-codec-cirrus.o +obj-$(CONFIG_SND_HDA_CODEC_CS420X) += snd-hda-codec-cs420x.o +obj-$(CONFIG_SND_HDA_CODEC_CS421X) += snd-hda-codec-cs421x.o obj-$(CONFIG_SND_HDA_CODEC_CS8409) += snd-hda-codec-cs8409.o diff --git a/sound/hda/codecs/cirrus/cirrus.c b/sound/hda/codecs/cirrus/cs420x.c similarity index 61% rename from sound/hda/codecs/cirrus/cirrus.c rename to sound/hda/codecs/cirrus/cs420x.c index 81ea66c4e9d3..823220d5cada 100644 --- a/sound/hda/codecs/cirrus/cirrus.c +++ b/sound/hda/codecs/cirrus/cs420x.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * HD audio interface patch for Cirrus Logic CS420x chip + * Cirrus Logic CS420x HD-audio codec * * Copyright (c) 2009 Takashi Iwai */ @@ -17,9 +17,6 @@ #include "hda_jack.h" #include "../generic.h" -/* - */ - struct cs_spec { struct hda_gen_spec gen; @@ -29,10 +26,6 @@ struct cs_spec { unsigned int gpio_eapd_hp; /* EAPD GPIO bit for headphones */ unsigned int gpio_eapd_speaker; /* EAPD GPIO bit for speakers */ - /* CS421x */ - unsigned int spdif_detect:1; - unsigned int spdif_present:1; - unsigned int sense_b:1; hda_nid_t vendor_nid; /* for MBP SPDIF control */ @@ -56,13 +49,6 @@ enum { CS420X_APPLE = CS420X_GPIO_13, }; -/* CS421x boards */ -enum { - CS421X_CDB4210, - CS421X_SENSE_B, - CS421X_STUMPY, -}; - /* Vendor-specific processing widget */ #define CS420X_VENDOR_NID 0x11 #define CS_DIG_OUT1_PIN_NID 0x10 @@ -105,28 +91,6 @@ enum { /* Cirrus Logic CS4208 */ #define CS4208_VENDOR_NID 0x24 -/* - * Cirrus Logic CS4210 - * - * 1 DAC => HP(sense) / Speakers, - * 1 ADC <= LineIn(sense) / MicIn / DMicIn, - * 1 SPDIF OUT => SPDIF Trasmitter(sense) - */ -#define CS4210_DAC_NID 0x02 -#define CS4210_ADC_NID 0x03 -#define CS4210_VENDOR_NID 0x0B -#define CS421X_DMIC_PIN_NID 0x09 /* Port E */ -#define CS421X_SPDIF_PIN_NID 0x0A /* Port H */ - -#define CS421X_IDX_DEV_CFG 0x01 -#define CS421X_IDX_ADC_CFG 0x02 -#define CS421X_IDX_DAC_CFG 0x03 -#define CS421X_IDX_SPK_CTL 0x04 - -/* Cirrus Logic CS4213 is like CS4210 but does not have SPDIF input/output */ -#define CS4213_VENDOR_NID 0x09 - - static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) { struct cs_spec *spec = codec->spec; @@ -158,9 +122,6 @@ static void cs_automute(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; - /* mute HPs if spdif jack (SENSE_B) is present */ - spec->gen.master_mute = !!(spec->spdif_present && spec->sense_b); - snd_hda_gen_update_outputs(codec); if (spec->gpio_eapd_hp || spec->gpio_eapd_speaker) { @@ -331,16 +292,6 @@ static int cs_build_controls(struct hda_codec *codec) return 0; } -#define cs_free snd_hda_gen_free - -static const struct hda_codec_ops cs_patch_ops = { - .build_controls = cs_build_controls, - .build_pcms = snd_hda_gen_build_pcms, - .init = cs_init, - .free = cs_free, - .unsol_event = snd_hda_jack_unsol_event, -}; - static int cs_parse_auto_config(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; @@ -584,17 +535,10 @@ static struct cs_spec *cs_alloc_spec(struct hda_codec *codec, int vendor_nid) return spec; } -static int patch_cs420x(struct hda_codec *codec) +static int cs420x_probe(struct hda_codec *codec) { - struct cs_spec *spec; int err; - spec = cs_alloc_spec(codec, CS420X_VENDOR_NID); - if (!spec) - return -ENOMEM; - - codec->patch_ops = cs_patch_ops; - spec->gen.automute_hook = cs_automute; codec->single_adc_amp = 1; snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl, @@ -603,15 +547,11 @@ static int patch_cs420x(struct hda_codec *codec) err = cs_parse_auto_config(codec); if (err < 0) - goto error; + return err; snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; - - error: - cs_free(codec); - return err; } /* @@ -766,17 +706,11 @@ static void cs4208_fix_amp_caps(struct hda_codec *codec, hda_nid_t adc) snd_hda_override_amp_caps(codec, adc, HDA_INPUT, caps); } -static int patch_cs4208(struct hda_codec *codec) +static int cs4208_probe(struct hda_codec *codec) { - struct cs_spec *spec; + struct cs_spec *spec = codec->spec; int err; - spec = cs_alloc_spec(codec, CS4208_VENDOR_NID); - if (!spec) - return -ENOMEM; - - codec->patch_ops = cs_patch_ops; - spec->gen.automute_hook = cs_automute; /* exclude NID 0x10 (HP) from output volumes due to different steps */ spec->gen.out_vol_mask = 1ULL << 0x10; @@ -792,452 +726,60 @@ static int patch_cs4208(struct hda_codec *codec) err = cs_parse_auto_config(codec); if (err < 0) - goto error; + return err; snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; - - error: - cs_free(codec); - return err; } -/* - * Cirrus Logic CS4210 - * - * 1 DAC => HP(sense) / Speakers, - * 1 ADC <= LineIn(sense) / MicIn / DMicIn, - * 1 SPDIF OUT => SPDIF Trasmitter(sense) - */ - -/* CS4210 board names */ -static const struct hda_model_fixup cs421x_models[] = { - { .id = CS421X_CDB4210, .name = "cdb4210" }, - { .id = CS421X_STUMPY, .name = "stumpy" }, - {} -}; - -static const struct hda_quirk cs421x_fixup_tbl[] = { - /* Test Intel board + CDB2410 */ - SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210), - {} /* terminator */ -}; - -/* CS4210 board pinconfigs */ -/* Default CS4210 (CDB4210)*/ -static const struct hda_pintbl cdb4210_pincfgs[] = { - { 0x05, 0x0321401f }, - { 0x06, 0x90170010 }, - { 0x07, 0x03813031 }, - { 0x08, 0xb7a70037 }, - { 0x09, 0xb7a6003e }, - { 0x0a, 0x034510f0 }, - {} /* terminator */ -}; - -/* Stumpy ChromeBox */ -static const struct hda_pintbl stumpy_pincfgs[] = { - { 0x05, 0x022120f0 }, - { 0x06, 0x901700f0 }, - { 0x07, 0x02a120f0 }, - { 0x08, 0x77a70037 }, - { 0x09, 0x77a6003e }, - { 0x0a, 0x434510f0 }, - {} /* terminator */ -}; - -/* Setup GPIO/SENSE for each board (if used) */ -static void cs421x_fixup_sense_b(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - struct cs_spec *spec = codec->spec; - - if (action == HDA_FIXUP_ACT_PRE_PROBE) - spec->sense_b = 1; -} - -static const struct hda_fixup cs421x_fixups[] = { - [CS421X_CDB4210] = { - .type = HDA_FIXUP_PINS, - .v.pins = cdb4210_pincfgs, - .chained = true, - .chain_id = CS421X_SENSE_B, - }, - [CS421X_SENSE_B] = { - .type = HDA_FIXUP_FUNC, - .v.func = cs421x_fixup_sense_b, - }, - [CS421X_STUMPY] = { - .type = HDA_FIXUP_PINS, - .v.pins = stumpy_pincfgs, - }, -}; - -static const struct hda_verb cs421x_coef_init_verbs[] = { - {0x0B, AC_VERB_SET_PROC_STATE, 1}, - {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DEV_CFG}, - /* - * Disable Coefficient Index Auto-Increment(DAI)=1, - * PDREF=0 - */ - {0x0B, AC_VERB_SET_PROC_COEF, 0x0001 }, - - {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_ADC_CFG}, - /* ADC SZCMode = Digital Soft Ramp */ - {0x0B, AC_VERB_SET_PROC_COEF, 0x0002 }, - - {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DAC_CFG}, - {0x0B, AC_VERB_SET_PROC_COEF, - (0x0002 /* DAC SZCMode = Digital Soft Ramp */ - | 0x0004 /* Mute DAC on FIFO error */ - | 0x0008 /* Enable DAC High Pass Filter */ - )}, - {} /* terminator */ -}; - -/* Errata: CS4210 rev A1 Silicon - * - * http://www.cirrus.com/en/pubs/errata/ - * - * Description: - * 1. Performance degredation is present in the ADC. - * 2. Speaker output is not completely muted upon HP detect. - * 3. Noise is present when clipping occurs on the amplified - * speaker outputs. - * - * Workaround: - * The following verb sequence written to the registers during - * initialization will correct the issues listed above. - */ - -static const struct hda_verb cs421x_coef_init_verbs_A1_silicon_fixes[] = { - {0x0B, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */ - - {0x0B, AC_VERB_SET_COEF_INDEX, 0x0006}, - {0x0B, AC_VERB_SET_PROC_COEF, 0x9999}, /* Test mode: on */ - - {0x0B, AC_VERB_SET_COEF_INDEX, 0x000A}, - {0x0B, AC_VERB_SET_PROC_COEF, 0x14CB}, /* Chop double */ - - {0x0B, AC_VERB_SET_COEF_INDEX, 0x0011}, - {0x0B, AC_VERB_SET_PROC_COEF, 0xA2D0}, /* Increase ADC current */ - - {0x0B, AC_VERB_SET_COEF_INDEX, 0x001A}, - {0x0B, AC_VERB_SET_PROC_COEF, 0x02A9}, /* Mute speaker */ - - {0x0B, AC_VERB_SET_COEF_INDEX, 0x001B}, - {0x0B, AC_VERB_SET_PROC_COEF, 0X1006}, /* Remove noise */ - - {} /* terminator */ -}; - -/* Speaker Amp Gain is controlled by the vendor widget's coef 4 */ -static const DECLARE_TLV_DB_SCALE(cs421x_speaker_boost_db_scale, 900, 300, 0); - -static int cs421x_boost_vol_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 3; - return 0; -} - -static int cs421x_boost_vol_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - - ucontrol->value.integer.value[0] = - cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL) & 0x0003; - return 0; -} - -static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - - unsigned int vol = ucontrol->value.integer.value[0]; - unsigned int coef = - cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL); - unsigned int original_coef = coef; - - coef &= ~0x0003; - coef |= (vol & 0x0003); - if (original_coef != coef) { - cs_vendor_coef_set(codec, CS421X_IDX_SPK_CTL, coef); - return 1; - } - - return 0; -} - -static const struct snd_kcontrol_new cs421x_speaker_boost_ctl = { - - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ), - .name = "Speaker Boost Playback Volume", - .info = cs421x_boost_vol_info, - .get = cs421x_boost_vol_get, - .put = cs421x_boost_vol_put, - .tlv = { .p = cs421x_speaker_boost_db_scale }, -}; - -static void cs4210_pinmux_init(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - unsigned int def_conf, coef; - - /* GPIO, DMIC_SCL, DMIC_SDA and SENSE_B are multiplexed */ - coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG); - - if (spec->gpio_mask) - coef |= 0x0008; /* B1,B2 are GPIOs */ - else - coef &= ~0x0008; - - if (spec->sense_b) - coef |= 0x0010; /* B2 is SENSE_B, not inverted */ - else - coef &= ~0x0010; - - cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef); - - if ((spec->gpio_mask || spec->sense_b) && - is_active_pin(codec, CS421X_DMIC_PIN_NID)) { - - /* - * GPIO or SENSE_B forced - disconnect the DMIC pin. - */ - def_conf = snd_hda_codec_get_pincfg(codec, CS421X_DMIC_PIN_NID); - def_conf &= ~AC_DEFCFG_PORT_CONN; - def_conf |= (AC_JACK_PORT_NONE << AC_DEFCFG_PORT_CONN_SHIFT); - snd_hda_codec_set_pincfg(codec, CS421X_DMIC_PIN_NID, def_conf); - } -} - -static void cs4210_spdif_automute(struct hda_codec *codec, - struct hda_jack_callback *tbl) -{ - struct cs_spec *spec = codec->spec; - bool spdif_present = false; - hda_nid_t spdif_pin = spec->gen.autocfg.dig_out_pins[0]; - - /* detect on spdif is specific to CS4210 */ - if (!spec->spdif_detect || - spec->vendor_nid != CS4210_VENDOR_NID) - return; - - spdif_present = snd_hda_jack_detect(codec, spdif_pin); - if (spdif_present == spec->spdif_present) - return; - - spec->spdif_present = spdif_present; - /* SPDIF TX on/off */ - snd_hda_set_pin_ctl(codec, spdif_pin, spdif_present ? PIN_OUT : 0); - - cs_automute(codec); -} - -static void parse_cs421x_digital(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->gen.autocfg; - int i; - - for (i = 0; i < cfg->dig_outs; i++) { - hda_nid_t nid = cfg->dig_out_pins[i]; - - if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { - spec->spdif_detect = 1; - snd_hda_jack_detect_enable_callback(codec, nid, - cs4210_spdif_automute); - } - } -} - -static int cs421x_init(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - - if (spec->vendor_nid == CS4210_VENDOR_NID) { - snd_hda_sequence_write(codec, cs421x_coef_init_verbs); - snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes); - cs4210_pinmux_init(codec); - } - - snd_hda_gen_init(codec); - - if (spec->gpio_mask) { - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, - spec->gpio_mask); - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, - spec->gpio_dir); - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, - spec->gpio_data); - } - - init_input_coef(codec); - - cs4210_spdif_automute(codec, NULL); - - return 0; -} - -static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac) -{ - unsigned int caps; - - /* set the upper-limit for mixer amp to 0dB */ - caps = query_amp_caps(codec, dac, HDA_OUTPUT); - caps &= ~(0x7f << AC_AMPCAP_NUM_STEPS_SHIFT); - caps |= ((caps >> AC_AMPCAP_OFFSET_SHIFT) & 0x7f) - << AC_AMPCAP_NUM_STEPS_SHIFT; - snd_hda_override_amp_caps(codec, dac, HDA_OUTPUT, caps); -} - -static int cs421x_parse_auto_config(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - hda_nid_t dac = CS4210_DAC_NID; - int err; - - fix_volume_caps(codec, dac); - - err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); - if (err < 0) - return err; - - err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); - if (err < 0) - return err; - - parse_cs421x_digital(codec); - - if (spec->gen.autocfg.speaker_outs && - spec->vendor_nid == CS4210_VENDOR_NID) { - if (!snd_hda_gen_add_kctl(&spec->gen, NULL, - &cs421x_speaker_boost_ctl)) - return -ENOMEM; - } - - return 0; -} - -/* - * Manage PDREF, when transitioning to D3hot - * (DAC,ADC) -> D3, PDREF=1, AFG->D3 - */ -static int cs421x_suspend(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - unsigned int coef; - - snd_hda_shutup_pins(codec); - - snd_hda_codec_write(codec, CS4210_DAC_NID, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - snd_hda_codec_write(codec, CS4210_ADC_NID, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - - if (spec->vendor_nid == CS4210_VENDOR_NID) { - coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG); - coef |= 0x0004; /* PDREF */ - cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef); - } - - return 0; -} - -static const struct hda_codec_ops cs421x_patch_ops = { - .build_controls = snd_hda_gen_build_controls, - .build_pcms = snd_hda_gen_build_pcms, - .init = cs421x_init, - .free = cs_free, - .unsol_event = snd_hda_jack_unsol_event, - .suspend = cs421x_suspend, -}; - -static int patch_cs4210(struct hda_codec *codec) +static int cs_codec_probe(struct hda_codec *codec, + const struct hda_device_id *id) { struct cs_spec *spec; int err; - spec = cs_alloc_spec(codec, CS4210_VENDOR_NID); + spec = cs_alloc_spec(codec, id->driver_data); if (!spec) return -ENOMEM; - - codec->patch_ops = cs421x_patch_ops; spec->gen.automute_hook = cs_automute; - snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl, - cs421x_fixups); - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - - /* - * Update the GPIO/DMIC/SENSE_B pinmux before the configuration - * is auto-parsed. If GPIO or SENSE_B is forced, DMIC input - * is disabled. - */ - cs4210_pinmux_init(codec); - - err = cs421x_parse_auto_config(codec); + if (spec->vendor_nid == CS4208_VENDOR_NID) + err = cs4208_probe(codec); + else + err = cs420x_probe(codec); if (err < 0) - goto error; - - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); - - return 0; - - error: - cs_free(codec); + snd_hda_gen_remove(codec); return err; } -static int patch_cs4213(struct hda_codec *codec) -{ - struct cs_spec *spec; - int err; - - spec = cs_alloc_spec(codec, CS4213_VENDOR_NID); - if (!spec) - return -ENOMEM; - - codec->patch_ops = cs421x_patch_ops; - - err = cs421x_parse_auto_config(codec); - if (err < 0) - goto error; - - return 0; - - error: - cs_free(codec); - return err; -} +static const struct hda_codec_ops cs_codec_ops = { + .probe = cs_codec_probe, + .remove = snd_hda_gen_remove, + .build_controls = cs_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = cs_init, + .unsol_event = snd_hda_jack_unsol_event, + .stream_pm = snd_hda_gen_stream_pm, +}; /* - * patch entries + * driver entries */ -static const struct hda_device_id snd_hda_id_cirrus[] = { - HDA_CODEC_ENTRY(0x10134206, "CS4206", patch_cs420x), - HDA_CODEC_ENTRY(0x10134207, "CS4207", patch_cs420x), - HDA_CODEC_ENTRY(0x10134208, "CS4208", patch_cs4208), - HDA_CODEC_ENTRY(0x10134210, "CS4210", patch_cs4210), - HDA_CODEC_ENTRY(0x10134213, "CS4213", patch_cs4213), +static const struct hda_device_id snd_hda_id_cs420x[] = { + HDA_CODEC_ID_MODEL(0x10134206, "CS4206", CS420X_VENDOR_NID), + HDA_CODEC_ID_MODEL(0x10134207, "CS4207", CS420X_VENDOR_NID), + HDA_CODEC_ID_MODEL(0x10134208, "CS4208", CS4208_VENDOR_NID), {} /* terminator */ }; -MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cirrus); +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cs420x); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Cirrus Logic HD-audio codec"); +MODULE_DESCRIPTION("Cirrus Logic CS420x HD-audio codec"); -static struct hda_codec_driver cirrus_driver = { - .id = snd_hda_id_cirrus, +static struct hda_codec_driver cs420x_driver = { + .id = snd_hda_id_cs420x, + .ops = &cs_codec_ops, }; -module_hda_codec_driver(cirrus_driver); +module_hda_codec_driver(cs420x_driver); diff --git a/sound/hda/codecs/cirrus/cs421x.c b/sound/hda/codecs/cirrus/cs421x.c new file mode 100644 index 000000000000..a93e2e0bb391 --- /dev/null +++ b/sound/hda/codecs/cirrus/cs421x.c @@ -0,0 +1,590 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Cirrus Logic CS421x HD-audio codec + */ + +#include +#include +#include +#include +#include +#include +#include +#include "hda_local.h" +#include "hda_auto_parser.h" +#include "hda_jack.h" +#include "../generic.h" + +struct cs_spec { + struct hda_gen_spec gen; + + unsigned int gpio_mask; + unsigned int gpio_dir; + unsigned int gpio_data; + unsigned int gpio_eapd_hp; /* EAPD GPIO bit for headphones */ + unsigned int gpio_eapd_speaker; /* EAPD GPIO bit for speakers */ + + /* CS421x */ + unsigned int spdif_detect:1; + unsigned int spdif_present:1; + unsigned int sense_b:1; + hda_nid_t vendor_nid; + + /* for MBP SPDIF control */ + int (*spdif_sw_put)(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +}; + +/* CS421x boards */ +enum { + CS421X_CDB4210, + CS421X_SENSE_B, + CS421X_STUMPY, +}; + +/* Vendor-specific processing widget */ +#define CS_DIG_OUT1_PIN_NID 0x10 +#define CS_DIG_OUT2_PIN_NID 0x15 +#define CS_DMIC1_PIN_NID 0x0e +#define CS_DMIC2_PIN_NID 0x12 + +/* coef indices */ +#define IDX_SPDIF_STAT 0x0000 +#define IDX_SPDIF_CTL 0x0001 +#define IDX_ADC_CFG 0x0002 +/* SZC bitmask, 4 modes below: + * 0 = immediate, + * 1 = digital immediate, analog zero-cross + * 2 = digtail & analog soft-ramp + * 3 = digital soft-ramp, analog zero-cross + */ +#define CS_COEF_ADC_SZC_MASK (3 << 0) +#define CS_COEF_ADC_MIC_SZC_MODE (3 << 0) /* SZC setup for mic */ +#define CS_COEF_ADC_LI_SZC_MODE (3 << 0) /* SZC setup for line-in */ +/* PGA mode: 0 = differential, 1 = signle-ended */ +#define CS_COEF_ADC_MIC_PGA_MODE (1 << 5) /* PGA setup for mic */ +#define CS_COEF_ADC_LI_PGA_MODE (1 << 6) /* PGA setup for line-in */ +#define IDX_DAC_CFG 0x0003 +/* SZC bitmask, 4 modes below: + * 0 = Immediate + * 1 = zero-cross + * 2 = soft-ramp + * 3 = soft-ramp on zero-cross + */ +#define CS_COEF_DAC_HP_SZC_MODE (3 << 0) /* nid 0x02 */ +#define CS_COEF_DAC_LO_SZC_MODE (3 << 2) /* nid 0x03 */ +#define CS_COEF_DAC_SPK_SZC_MODE (3 << 4) /* nid 0x04 */ + +#define IDX_BEEP_CFG 0x0004 +/* 0x0008 - test reg key */ +/* 0x0009 - 0x0014 -> 12 test regs */ +/* 0x0015 - visibility reg */ + +/* + * Cirrus Logic CS4210 + * + * 1 DAC => HP(sense) / Speakers, + * 1 ADC <= LineIn(sense) / MicIn / DMicIn, + * 1 SPDIF OUT => SPDIF Transmitter(sense) + */ +#define CS4210_DAC_NID 0x02 +#define CS4210_ADC_NID 0x03 +#define CS4210_VENDOR_NID 0x0B +#define CS421X_DMIC_PIN_NID 0x09 /* Port E */ +#define CS421X_SPDIF_PIN_NID 0x0A /* Port H */ + +#define CS421X_IDX_DEV_CFG 0x01 +#define CS421X_IDX_ADC_CFG 0x02 +#define CS421X_IDX_DAC_CFG 0x03 +#define CS421X_IDX_SPK_CTL 0x04 + +/* Cirrus Logic CS4213 is like CS4210 but does not have SPDIF input/output */ +#define CS4213_VENDOR_NID 0x09 + + +static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) +{ + struct cs_spec *spec = codec->spec; + + snd_hda_codec_write(codec, spec->vendor_nid, 0, + AC_VERB_SET_COEF_INDEX, idx); + return snd_hda_codec_read(codec, spec->vendor_nid, 0, + AC_VERB_GET_PROC_COEF, 0); +} + +static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx, + unsigned int coef) +{ + struct cs_spec *spec = codec->spec; + + snd_hda_codec_write(codec, spec->vendor_nid, 0, + AC_VERB_SET_COEF_INDEX, idx); + snd_hda_codec_write(codec, spec->vendor_nid, 0, + AC_VERB_SET_PROC_COEF, coef); +} + +/* + * auto-mute and auto-mic switching + * CS421x auto-output redirecting + * HP/SPK/SPDIF + */ + +static void cs_automute(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + + /* mute HPs if spdif jack (SENSE_B) is present */ + spec->gen.master_mute = !!(spec->spdif_present && spec->sense_b); + + snd_hda_gen_update_outputs(codec); + + if (spec->gpio_eapd_hp || spec->gpio_eapd_speaker) { + if (spec->gen.automute_speaker) + spec->gpio_data = spec->gen.hp_jack_present ? + spec->gpio_eapd_hp : spec->gpio_eapd_speaker; + else + spec->gpio_data = + spec->gpio_eapd_hp | spec->gpio_eapd_speaker; + snd_hda_codec_write(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, spec->gpio_data); + } +} + +static bool is_active_pin(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int val; + + val = snd_hda_codec_get_pincfg(codec, nid); + return (get_defcfg_connect(val) != AC_JACK_PORT_NONE); +} + +static struct cs_spec *cs_alloc_spec(struct hda_codec *codec, int vendor_nid) +{ + struct cs_spec *spec; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return NULL; + codec->spec = spec; + spec->vendor_nid = vendor_nid; + codec->power_save_node = 1; + snd_hda_gen_spec_init(&spec->gen); + + return spec; +} + +/* + * Cirrus Logic CS4210 + * + * 1 DAC => HP(sense) / Speakers, + * 1 ADC <= LineIn(sense) / MicIn / DMicIn, + * 1 SPDIF OUT => SPDIF Transmitter(sense) + */ + +/* CS4210 board names */ +static const struct hda_model_fixup cs421x_models[] = { + { .id = CS421X_CDB4210, .name = "cdb4210" }, + { .id = CS421X_STUMPY, .name = "stumpy" }, + {} +}; + +static const struct hda_quirk cs421x_fixup_tbl[] = { + /* Test Intel board + CDB2410 */ + SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210), + {} /* terminator */ +}; + +/* CS4210 board pinconfigs */ +/* Default CS4210 (CDB4210)*/ +static const struct hda_pintbl cdb4210_pincfgs[] = { + { 0x05, 0x0321401f }, + { 0x06, 0x90170010 }, + { 0x07, 0x03813031 }, + { 0x08, 0xb7a70037 }, + { 0x09, 0xb7a6003e }, + { 0x0a, 0x034510f0 }, + {} /* terminator */ +}; + +/* Stumpy ChromeBox */ +static const struct hda_pintbl stumpy_pincfgs[] = { + { 0x05, 0x022120f0 }, + { 0x06, 0x901700f0 }, + { 0x07, 0x02a120f0 }, + { 0x08, 0x77a70037 }, + { 0x09, 0x77a6003e }, + { 0x0a, 0x434510f0 }, + {} /* terminator */ +}; + +/* Setup GPIO/SENSE for each board (if used) */ +static void cs421x_fixup_sense_b(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct cs_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) + spec->sense_b = 1; +} + +static const struct hda_fixup cs421x_fixups[] = { + [CS421X_CDB4210] = { + .type = HDA_FIXUP_PINS, + .v.pins = cdb4210_pincfgs, + .chained = true, + .chain_id = CS421X_SENSE_B, + }, + [CS421X_SENSE_B] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs421x_fixup_sense_b, + }, + [CS421X_STUMPY] = { + .type = HDA_FIXUP_PINS, + .v.pins = stumpy_pincfgs, + }, +}; + +static const struct hda_verb cs421x_coef_init_verbs[] = { + {0x0B, AC_VERB_SET_PROC_STATE, 1}, + {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DEV_CFG}, + /* + * Disable Coefficient Index Auto-Increment(DAI)=1, + * PDREF=0 + */ + {0x0B, AC_VERB_SET_PROC_COEF, 0x0001 }, + + {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_ADC_CFG}, + /* ADC SZCMode = Digital Soft Ramp */ + {0x0B, AC_VERB_SET_PROC_COEF, 0x0002 }, + + {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DAC_CFG}, + {0x0B, AC_VERB_SET_PROC_COEF, + (0x0002 /* DAC SZCMode = Digital Soft Ramp */ + | 0x0004 /* Mute DAC on FIFO error */ + | 0x0008 /* Enable DAC High Pass Filter */ + )}, + {} /* terminator */ +}; + +/* Errata: CS4210 rev A1 Silicon + * + * http://www.cirrus.com/en/pubs/errata/ + * + * Description: + * 1. Performance degredation is present in the ADC. + * 2. Speaker output is not completely muted upon HP detect. + * 3. Noise is present when clipping occurs on the amplified + * speaker outputs. + * + * Workaround: + * The following verb sequence written to the registers during + * initialization will correct the issues listed above. + */ + +static const struct hda_verb cs421x_coef_init_verbs_A1_silicon_fixes[] = { + {0x0B, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */ + + {0x0B, AC_VERB_SET_COEF_INDEX, 0x0006}, + {0x0B, AC_VERB_SET_PROC_COEF, 0x9999}, /* Test mode: on */ + + {0x0B, AC_VERB_SET_COEF_INDEX, 0x000A}, + {0x0B, AC_VERB_SET_PROC_COEF, 0x14CB}, /* Chop double */ + + {0x0B, AC_VERB_SET_COEF_INDEX, 0x0011}, + {0x0B, AC_VERB_SET_PROC_COEF, 0xA2D0}, /* Increase ADC current */ + + {0x0B, AC_VERB_SET_COEF_INDEX, 0x001A}, + {0x0B, AC_VERB_SET_PROC_COEF, 0x02A9}, /* Mute speaker */ + + {0x0B, AC_VERB_SET_COEF_INDEX, 0x001B}, + {0x0B, AC_VERB_SET_PROC_COEF, 0X1006}, /* Remove noise */ + + {} /* terminator */ +}; + +/* Speaker Amp Gain is controlled by the vendor widget's coef 4 */ +static const DECLARE_TLV_DB_SCALE(cs421x_speaker_boost_db_scale, 900, 300, 0); + +static int cs421x_boost_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 3; + return 0; +} + +static int cs421x_boost_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = + cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL) & 0x0003; + return 0; +} + +static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + + unsigned int vol = ucontrol->value.integer.value[0]; + unsigned int coef = + cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL); + unsigned int original_coef = coef; + + coef &= ~0x0003; + coef |= (vol & 0x0003); + if (original_coef != coef) { + cs_vendor_coef_set(codec, CS421X_IDX_SPK_CTL, coef); + return 1; + } + + return 0; +} + +static const struct snd_kcontrol_new cs421x_speaker_boost_ctl = { + + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ), + .name = "Speaker Boost Playback Volume", + .info = cs421x_boost_vol_info, + .get = cs421x_boost_vol_get, + .put = cs421x_boost_vol_put, + .tlv = { .p = cs421x_speaker_boost_db_scale }, +}; + +static void cs4210_pinmux_init(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + unsigned int def_conf, coef; + + /* GPIO, DMIC_SCL, DMIC_SDA and SENSE_B are multiplexed */ + coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG); + + if (spec->gpio_mask) + coef |= 0x0008; /* B1,B2 are GPIOs */ + else + coef &= ~0x0008; + + if (spec->sense_b) + coef |= 0x0010; /* B2 is SENSE_B, not inverted */ + else + coef &= ~0x0010; + + cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef); + + if ((spec->gpio_mask || spec->sense_b) && + is_active_pin(codec, CS421X_DMIC_PIN_NID)) { + + /* + * GPIO or SENSE_B forced - disconnect the DMIC pin. + */ + def_conf = snd_hda_codec_get_pincfg(codec, CS421X_DMIC_PIN_NID); + def_conf &= ~AC_DEFCFG_PORT_CONN; + def_conf |= (AC_JACK_PORT_NONE << AC_DEFCFG_PORT_CONN_SHIFT); + snd_hda_codec_set_pincfg(codec, CS421X_DMIC_PIN_NID, def_conf); + } +} + +static void cs4210_spdif_automute(struct hda_codec *codec, + struct hda_jack_callback *tbl) +{ + struct cs_spec *spec = codec->spec; + bool spdif_present = false; + hda_nid_t spdif_pin = spec->gen.autocfg.dig_out_pins[0]; + + /* detect on spdif is specific to CS4210 */ + if (!spec->spdif_detect || + spec->vendor_nid != CS4210_VENDOR_NID) + return; + + spdif_present = snd_hda_jack_detect(codec, spdif_pin); + if (spdif_present == spec->spdif_present) + return; + + spec->spdif_present = spdif_present; + /* SPDIF TX on/off */ + snd_hda_set_pin_ctl(codec, spdif_pin, spdif_present ? PIN_OUT : 0); + + cs_automute(codec); +} + +static void parse_cs421x_digital(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + int i; + + for (i = 0; i < cfg->dig_outs; i++) { + hda_nid_t nid = cfg->dig_out_pins[i]; + + if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { + spec->spdif_detect = 1; + snd_hda_jack_detect_enable_callback(codec, nid, + cs4210_spdif_automute); + } + } +} + +static int cs421x_init(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + + if (spec->vendor_nid == CS4210_VENDOR_NID) { + snd_hda_sequence_write(codec, cs421x_coef_init_verbs); + snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes); + cs4210_pinmux_init(codec); + } + + snd_hda_gen_init(codec); + + if (spec->gpio_mask) { + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, + spec->gpio_mask); + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, + spec->gpio_dir); + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, + spec->gpio_data); + } + + cs4210_spdif_automute(codec, NULL); + + return 0; +} + +static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac) +{ + unsigned int caps; + + /* set the upper-limit for mixer amp to 0dB */ + caps = query_amp_caps(codec, dac, HDA_OUTPUT); + caps &= ~(0x7f << AC_AMPCAP_NUM_STEPS_SHIFT); + caps |= ((caps >> AC_AMPCAP_OFFSET_SHIFT) & 0x7f) + << AC_AMPCAP_NUM_STEPS_SHIFT; + snd_hda_override_amp_caps(codec, dac, HDA_OUTPUT, caps); +} + +static int cs421x_parse_auto_config(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + hda_nid_t dac = CS4210_DAC_NID; + int err; + + fix_volume_caps(codec, dac); + + err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); + if (err < 0) + return err; + + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); + if (err < 0) + return err; + + parse_cs421x_digital(codec); + + if (spec->gen.autocfg.speaker_outs && + spec->vendor_nid == CS4210_VENDOR_NID) { + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, + &cs421x_speaker_boost_ctl)) + return -ENOMEM; + } + + return 0; +} + +/* + * Manage PDREF, when transitioning to D3hot + * (DAC,ADC) -> D3, PDREF=1, AFG->D3 + */ +static int cs421x_suspend(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + unsigned int coef; + + snd_hda_shutup_pins(codec); + + snd_hda_codec_write(codec, CS4210_DAC_NID, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + snd_hda_codec_write(codec, CS4210_ADC_NID, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + + if (spec->vendor_nid == CS4210_VENDOR_NID) { + coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG); + coef |= 0x0004; /* PDREF */ + cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef); + } + + return 0; +} + +static int cs421x_probe(struct hda_codec *codec, const struct hda_device_id *id) +{ + struct cs_spec *spec; + int err; + + spec = cs_alloc_spec(codec, id->driver_data); + if (!spec) + return -ENOMEM; + + spec->gen.automute_hook = cs_automute; + + if (spec->vendor_nid == CS4210_VENDOR_NID) { + snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl, + cs421x_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + /* + * Update the GPIO/DMIC/SENSE_B pinmux before the configuration + * is auto-parsed. If GPIO or SENSE_B is forced, DMIC input + * is disabled. + */ + cs4210_pinmux_init(codec); + } + + err = cs421x_parse_auto_config(codec); + if (err < 0) + goto error; + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + + return 0; + + error: + snd_hda_gen_remove(codec); + return err; +} + +static const struct hda_codec_ops cs421x_codec_ops = { + .probe = cs421x_probe, + .remove = snd_hda_gen_remove, + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = cs421x_init, + .unsol_event = snd_hda_jack_unsol_event, + .suspend = cs421x_suspend, + .stream_pm = snd_hda_gen_stream_pm, +}; + +/* + * driver entries + */ +static const struct hda_device_id snd_hda_id_cs421x[] = { + HDA_CODEC_ID_MODEL(0x10134210, "CS4210", CS4210_VENDOR_NID), + HDA_CODEC_ID_MODEL(0x10134213, "CS4213", CS4213_VENDOR_NID), + {} /* terminator */ +}; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cs421x); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Cirrus Logic CS421x HD-audio codec"); + +static struct hda_codec_driver cs421x_driver = { + .id = snd_hda_id_cs421x, + .ops = &cs421x_codec_ops, +}; + +module_hda_codec_driver(cs421x_driver); From e4c9f524a12c2e5fbd3dc1fb4c0bdadbe4d89f6f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:19 +0200 Subject: [PATCH 332/385] ALSA: hda/cs8409: Rewrite to new probe method Convert the CS8409 codec driver to use the new hda_codec_ops probe. The Dolphin support needs an override of unsol_event callback, and redirect via spec->unsol_event function pointer for now. Other than that, no functional changes. Reviewed-by: Richard Fitzgerald Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-17-tiwai@suse.de --- sound/hda/codecs/cirrus/cs8409-tables.c | 2 +- sound/hda/codecs/cirrus/cs8409.c | 55 +++++++++++++------------ sound/hda/codecs/cirrus/cs8409.h | 4 +- 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/sound/hda/codecs/cirrus/cs8409-tables.c b/sound/hda/codecs/cirrus/cs8409-tables.c index 5fe49f13c0da..8c703b714a71 100644 --- a/sound/hda/codecs/cirrus/cs8409-tables.c +++ b/sound/hda/codecs/cirrus/cs8409-tables.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * cs8409-tables.c -- HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip + * cs8409-tables.c -- HD audio codec driver for Cirrus Logic CS8409 HDA bridge chip * * Copyright (C) 2021 Cirrus Logic, Inc. and * Cirrus Logic International Semiconductor Ltd. diff --git a/sound/hda/codecs/cirrus/cs8409.c b/sound/hda/codecs/cirrus/cs8409.c index 5ec1126b2a55..e32b462cdc5e 100644 --- a/sound/hda/codecs/cirrus/cs8409.c +++ b/sound/hda/codecs/cirrus/cs8409.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip + * HD audio codec driver for Cirrus Logic CS8409 HDA bridge chip * * Copyright (C) 2021 Cirrus Logic, Inc. and * Cirrus Logic International Semiconductor Ltd. @@ -954,7 +954,7 @@ static void cs42l42_suspend(struct sub_codec *cs42l42) snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, spec->gpio_data); } -static void cs8409_free(struct hda_codec *codec) +static void cs8409_remove(struct hda_codec *codec) { struct cs8409_spec *spec = codec->spec; @@ -962,7 +962,7 @@ static void cs8409_free(struct hda_codec *codec) cancel_delayed_work_sync(&spec->i2c_clk_work); cs8409_disable_i2c_clock(codec); - snd_hda_gen_free(codec); + snd_hda_gen_remove(codec); } /****************************************************************************** @@ -1007,6 +1007,16 @@ static void cs8409_cs42l42_jack_unsol_event(struct hda_codec *codec, unsigned in } } +static void cs8409_unsol_event(struct hda_codec *codec, unsigned int res) +{ + struct cs8409_spec *spec = codec->spec; + + if (spec->unsol_event) + spec->unsol_event(codec, res); + else + cs8409_cs42l42_jack_unsol_event(codec, res); +} + /* Manage PDREF, when transition to D3hot */ static int cs8409_cs42l42_suspend(struct hda_codec *codec) { @@ -1076,15 +1086,6 @@ static void cs8409_cs42l42_hw_init(struct hda_codec *codec) cs8409_enable_ur(codec, 1); } -static const struct hda_codec_ops cs8409_cs42l42_patch_ops = { - .build_controls = cs8409_build_controls, - .build_pcms = snd_hda_gen_build_pcms, - .init = cs8409_init, - .free = cs8409_free, - .unsol_event = cs8409_cs42l42_jack_unsol_event, - .suspend = cs8409_cs42l42_suspend, -}; - static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, unsigned int cmd, unsigned int flags, unsigned int *res) { @@ -1134,7 +1135,6 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix, spec->scodecs[CS8409_CODEC0] = &cs8409_cs42l42_codec; spec->num_scodecs = 1; spec->scodecs[CS8409_CODEC0]->codec = codec; - codec->patch_ops = cs8409_cs42l42_patch_ops; spec->gen.suppress_auto_mute = 1; spec->gen.no_primary_hp = 1; @@ -1304,15 +1304,6 @@ static void dolphin_hw_init(struct hda_codec *codec) cs8409_enable_ur(codec, 1); } -static const struct hda_codec_ops cs8409_dolphin_patch_ops = { - .build_controls = cs8409_build_controls, - .build_pcms = snd_hda_gen_build_pcms, - .init = cs8409_init, - .free = cs8409_free, - .unsol_event = dolphin_jack_unsol_event, - .suspend = cs8409_cs42l42_suspend, -}; - static int dolphin_exec_verb(struct hdac_device *dev, unsigned int cmd, unsigned int flags, unsigned int *res) { @@ -1371,7 +1362,7 @@ void dolphin_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int ac spec->num_scodecs = 2; spec->gen.suppress_vmaster = 1; - codec->patch_ops = cs8409_dolphin_patch_ops; + spec->unsol_event = dolphin_jack_unsol_event; /* GPIO 1,5 out, 0,4 in */ spec->gpio_dir = spec->scodecs[CS8409_CODEC0]->reset_gpio | @@ -1444,7 +1435,7 @@ void dolphin_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int ac } } -static int patch_cs8409(struct hda_codec *codec) +static int cs8409_probe(struct hda_codec *codec, const struct hda_device_id *id) { int err; @@ -1461,7 +1452,7 @@ static int patch_cs8409(struct hda_codec *codec) err = cs8409_parse_auto_config(codec); if (err < 0) { - cs8409_free(codec); + cs8409_remove(codec); return err; } @@ -1469,14 +1460,26 @@ static int patch_cs8409(struct hda_codec *codec) return 0; } +static const struct hda_codec_ops cs8409_codec_ops = { + .probe = cs8409_probe, + .remove = cs8409_remove, + .build_controls = cs8409_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = cs8409_init, + .unsol_event = cs8409_unsol_event, + .suspend = cs8409_cs42l42_suspend, + .stream_pm = snd_hda_gen_stream_pm, +}; + static const struct hda_device_id snd_hda_id_cs8409[] = { - HDA_CODEC_ENTRY(0x10138409, "CS8409", patch_cs8409), + HDA_CODEC_ID(0x10138409, "CS8409"), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cs8409); static struct hda_codec_driver cs8409_driver = { .id = snd_hda_id_cs8409, + .ops = &cs8409_codec_ops, }; module_hda_codec_driver(cs8409_driver); diff --git a/sound/hda/codecs/cirrus/cs8409.h b/sound/hda/codecs/cirrus/cs8409.h index 35072cd009dc..7fe56f4a73bc 100644 --- a/sound/hda/codecs/cirrus/cs8409.h +++ b/sound/hda/codecs/cirrus/cs8409.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip + * HD audio codec driver for Cirrus Logic CS8409 HDA bridge chip * * Copyright (C) 2021 Cirrus Logic, Inc. and * Cirrus Logic International Semiconductor Ltd. @@ -345,6 +345,8 @@ struct cs8409_spec { /* verb exec op override */ int (*exec_verb)(struct hdac_device *dev, unsigned int cmd, unsigned int flags, unsigned int *res); + /* unsol_event op override */ + void (*unsol_event)(struct hda_codec *codec, unsigned int res); }; extern const struct snd_kcontrol_new cs42l42_dac_volume_mixer; From dec96130eae338fc04756df52d8492713755610d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:20 +0200 Subject: [PATCH 333/385] ALSA: hda/conexant: Rewrite to new probe method Convert the Conexant codec driver to use the new hda_codec_ops probe. No functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-18-tiwai@suse.de --- sound/hda/codecs/conexant.c | 104 ++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 51 deletions(-) diff --git a/sound/hda/codecs/conexant.c b/sound/hda/codecs/conexant.c index b7710a81fd87..c881bf213ebe 100644 --- a/sound/hda/codecs/conexant.c +++ b/sound/hda/codecs/conexant.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * HD audio interface patch for Conexant HDA audio codec + * HD audio codec driver for Conexant HDA audio codec * * Copyright (c) 2006 Pototskiy Akex * Takashi Iwai @@ -185,7 +185,7 @@ static void cx_fixup_headset_recog(struct hda_codec *codec) snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20); } -static int cx_auto_init(struct hda_codec *codec) +static int cx_init(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; snd_hda_gen_init(codec); @@ -210,10 +210,10 @@ static void cx_auto_shutdown(struct hda_codec *codec) cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false); } -static void cx_auto_free(struct hda_codec *codec) +static void cx_remove(struct hda_codec *codec) { cx_auto_shutdown(codec); - snd_hda_gen_free(codec); + snd_hda_gen_remove(codec); } static void cx_process_headset_plugin(struct hda_codec *codec) @@ -258,22 +258,12 @@ static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_ cx_process_headset_plugin(codec); } -static int cx_auto_suspend(struct hda_codec *codec) +static int cx_suspend(struct hda_codec *codec) { cx_auto_shutdown(codec); return 0; } -static const struct hda_codec_ops cx_auto_patch_ops = { - .build_controls = snd_hda_gen_build_controls, - .build_pcms = snd_hda_gen_build_pcms, - .init = cx_auto_init, - .free = cx_auto_free, - .unsol_event = snd_hda_jack_unsol_event, - .suspend = cx_auto_suspend, - .check_power_status = snd_hda_gen_check_power_status, -}; - /* * pin fix-up */ @@ -1178,7 +1168,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec) spec->gen.dac_min_mute = true; } -static int patch_conexant_auto(struct hda_codec *codec) +static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id) { struct conexant_spec *spec; int err; @@ -1190,7 +1180,6 @@ static int patch_conexant_auto(struct hda_codec *codec) return -ENOMEM; snd_hda_gen_spec_init(&spec->gen); codec->spec = spec; - codec->patch_ops = cx_auto_patch_ops; /* init cx11880/sn6140 flag and reset headset_present_flag */ switch (codec->core.vendor_id) { @@ -1276,47 +1265,59 @@ static int patch_conexant_auto(struct hda_codec *codec) return 0; error: - cx_auto_free(codec); + cx_remove(codec); return err; } +static const struct hda_codec_ops cx_codec_ops = { + .probe = cx_probe, + .remove = cx_remove, + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = cx_init, + .unsol_event = snd_hda_jack_unsol_event, + .suspend = cx_suspend, + .check_power_status = snd_hda_gen_check_power_status, + .stream_pm = snd_hda_gen_stream_pm, +}; + /* */ static const struct hda_device_id snd_hda_id_conexant[] = { - HDA_CODEC_ENTRY(0x14f11f86, "CX11880", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f11f87, "SN6140", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f120d0, "CX11970", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f120d1, "SN6180", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f15051, "CX20561 (Hermosa)", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f15066, "CX20582 (Pebble)", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f15067, "CX20583 (Pebble HSF)", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f15068, "CX20584", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f15069, "CX20585", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f1506c, "CX20588", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f1506e, "CX20590", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f15097, "CX20631", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f15098, "CX20632", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f150a1, "CX20641", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f150a2, "CX20642", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f150ab, "CX20651", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f150ac, "CX20652", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f150b8, "CX20664", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f150b9, "CX20665", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f150f1, "CX21722", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f150f2, "CX20722", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f150f3, "CX21724", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f150f4, "CX20724", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f1510f, "CX20751/2", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f15110, "CX20751/2", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f15111, "CX20753/4", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f15113, "CX20755", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f15114, "CX20756", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f15115, "CX20757", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f151d7, "CX20952", patch_conexant_auto), + HDA_CODEC_ID(0x14f11f86, "CX11880"), + HDA_CODEC_ID(0x14f11f87, "SN6140"), + HDA_CODEC_ID(0x14f12008, "CX8200"), + HDA_CODEC_ID(0x14f120d0, "CX11970"), + HDA_CODEC_ID(0x14f120d1, "SN6180"), + HDA_CODEC_ID(0x14f15045, "CX20549 (Venice)"), + HDA_CODEC_ID(0x14f15047, "CX20551 (Waikiki)"), + HDA_CODEC_ID(0x14f15051, "CX20561 (Hermosa)"), + HDA_CODEC_ID(0x14f15066, "CX20582 (Pebble)"), + HDA_CODEC_ID(0x14f15067, "CX20583 (Pebble HSF)"), + HDA_CODEC_ID(0x14f15068, "CX20584"), + HDA_CODEC_ID(0x14f15069, "CX20585"), + HDA_CODEC_ID(0x14f1506c, "CX20588"), + HDA_CODEC_ID(0x14f1506e, "CX20590"), + HDA_CODEC_ID(0x14f15097, "CX20631"), + HDA_CODEC_ID(0x14f15098, "CX20632"), + HDA_CODEC_ID(0x14f150a1, "CX20641"), + HDA_CODEC_ID(0x14f150a2, "CX20642"), + HDA_CODEC_ID(0x14f150ab, "CX20651"), + HDA_CODEC_ID(0x14f150ac, "CX20652"), + HDA_CODEC_ID(0x14f150b8, "CX20664"), + HDA_CODEC_ID(0x14f150b9, "CX20665"), + HDA_CODEC_ID(0x14f150f1, "CX21722"), + HDA_CODEC_ID(0x14f150f2, "CX20722"), + HDA_CODEC_ID(0x14f150f3, "CX21724"), + HDA_CODEC_ID(0x14f150f4, "CX20724"), + HDA_CODEC_ID(0x14f1510f, "CX20751/2"), + HDA_CODEC_ID(0x14f15110, "CX20751/2"), + HDA_CODEC_ID(0x14f15111, "CX20753/4"), + HDA_CODEC_ID(0x14f15113, "CX20755"), + HDA_CODEC_ID(0x14f15114, "CX20756"), + HDA_CODEC_ID(0x14f15115, "CX20757"), + HDA_CODEC_ID(0x14f151d7, "CX20952"), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_conexant); @@ -1326,6 +1327,7 @@ MODULE_DESCRIPTION("Conexant HD-audio codec"); static struct hda_codec_driver conexant_driver = { .id = snd_hda_id_conexant, + .ops = &cx_codec_ops, }; module_hda_codec_driver(conexant_driver); From 3cea41383450319d0e130c6339f023f307723d6d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:21 +0200 Subject: [PATCH 334/385] ALSA: hda/senary: Rewrite to new probe method Convert the Senary codec driver to use the new hda_codec_ops probe. No functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-19-tiwai@suse.de --- sound/hda/codecs/senarytech.c | 46 ++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/sound/hda/codecs/senarytech.c b/sound/hda/codecs/senarytech.c index 9a253ad19f4d..9aa1e9bcd9ec 100644 --- a/sound/hda/codecs/senarytech.c +++ b/sound/hda/codecs/senarytech.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * HD audio interface patch for Senary HDA audio codec + * HD audio codec driver for Senary HDA audio codec * * Initially based on conexant.c */ @@ -129,7 +129,7 @@ static void senary_init_gpio_led(struct hda_codec *codec) } } -static int senary_auto_init(struct hda_codec *codec) +static int senary_init(struct hda_codec *codec) { snd_hda_gen_init(codec); senary_init_gpio_led(codec); @@ -138,7 +138,7 @@ static int senary_auto_init(struct hda_codec *codec) return 0; } -static void senary_auto_shutdown(struct hda_codec *codec) +static void senary_shutdown(struct hda_codec *codec) { struct senary_spec *spec = codec->spec; @@ -148,29 +148,19 @@ static void senary_auto_shutdown(struct hda_codec *codec) senary_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false); } -static void senary_auto_free(struct hda_codec *codec) +static void senary_remove(struct hda_codec *codec) { - senary_auto_shutdown(codec); - snd_hda_gen_free(codec); + senary_shutdown(codec); + snd_hda_gen_remove(codec); } -static int senary_auto_suspend(struct hda_codec *codec) +static int senary_suspend(struct hda_codec *codec) { - senary_auto_shutdown(codec); + senary_shutdown(codec); return 0; } -static const struct hda_codec_ops senary_auto_patch_ops = { - .build_controls = snd_hda_gen_build_controls, - .build_pcms = snd_hda_gen_build_pcms, - .init = senary_auto_init, - .free = senary_auto_free, - .unsol_event = snd_hda_jack_unsol_event, - .suspend = senary_auto_suspend, - .check_power_status = snd_hda_gen_check_power_status, -}; - -static int patch_senary_auto(struct hda_codec *codec) +static int senary_probe(struct hda_codec *codec, const struct hda_device_id *id) { struct senary_spec *spec; int err; @@ -182,7 +172,6 @@ static int patch_senary_auto(struct hda_codec *codec) return -ENOMEM; snd_hda_gen_spec_init(&spec->gen); codec->spec = spec; - codec->patch_ops = senary_auto_patch_ops; senary_auto_parse_eapd(codec); spec->gen.own_eapd_ctl = 1; @@ -221,15 +210,27 @@ static int patch_senary_auto(struct hda_codec *codec) return 0; error: - senary_auto_free(codec); + senary_remove(codec); return err; } +static const struct hda_codec_ops senary_codec_ops = { + .probe = senary_probe, + .remove = senary_remove, + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = senary_init, + .unsol_event = snd_hda_jack_unsol_event, + .suspend = senary_suspend, + .check_power_status = snd_hda_gen_check_power_status, + .stream_pm = snd_hda_gen_stream_pm, +}; + /* */ static const struct hda_device_id snd_hda_id_senary[] = { - HDA_CODEC_ENTRY(0x1fa86186, "SN6186", patch_senary_auto), + HDA_CODEC_ID(0x1fa86186, "SN6186"), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_senary); @@ -239,6 +240,7 @@ MODULE_DESCRIPTION("Senarytech HD-audio codec"); static struct hda_codec_driver senary_driver = { .id = snd_hda_id_senary, + .ops = &senary_codec_ops, }; module_hda_codec_driver(senary_driver); From 51a1e7f4131ad150039d8b99088d1f7fdf1bc369 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:22 +0200 Subject: [PATCH 335/385] ALSA: hda/si3054: Rewrite to new probe method Convert the SI3054 codec driver to use the new hda_codec_ops probe. No functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-20-tiwai@suse.de --- sound/hda/codecs/si3054.c | 53 +++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/sound/hda/codecs/si3054.c b/sound/hda/codecs/si3054.c index 763eae80a148..87cf9da9f3bf 100644 --- a/sound/hda/codecs/si3054.c +++ b/sound/hda/codecs/si3054.c @@ -2,7 +2,7 @@ /* * Universal Interface for Intel High Definition Audio Codec * - * HD audio interface patch for Silicon Labs 3054/5 modem codec + * HD audio codec driver for Silicon Labs 3054/5 modem codec * * Copyright (c) 2005 Sasha Khapyorsky * Takashi Iwai @@ -246,50 +246,48 @@ static int si3054_init(struct hda_codec *codec) return 0; } -static void si3054_free(struct hda_codec *codec) +static void si3054_remove(struct hda_codec *codec) { kfree(codec->spec); } - /* */ -static const struct hda_codec_ops si3054_patch_ops = { - .build_controls = si3054_build_controls, - .build_pcms = si3054_build_pcms, - .init = si3054_init, - .free = si3054_free, -}; - -static int patch_si3054(struct hda_codec *codec) +static int si3054_probe(struct hda_codec *codec, const struct hda_device_id *id) { - struct si3054_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) + codec->spec = kzalloc(sizeof(struct si3054_spec), GFP_KERNEL); + if (!codec->spec) return -ENOMEM; - codec->spec = spec; - codec->patch_ops = si3054_patch_ops; return 0; } +static const struct hda_codec_ops si3054_codec_ops = { + .probe = si3054_probe, + .remove = si3054_remove, + .build_controls = si3054_build_controls, + .build_pcms = si3054_build_pcms, + .init = si3054_init, +}; + /* - * patch entries + * driver entries */ static const struct hda_device_id snd_hda_id_si3054[] = { - HDA_CODEC_ENTRY(0x163c3055, "Si3054", patch_si3054), - HDA_CODEC_ENTRY(0x163c3155, "Si3054", patch_si3054), - HDA_CODEC_ENTRY(0x11c13026, "Si3054", patch_si3054), - HDA_CODEC_ENTRY(0x11c13055, "Si3054", patch_si3054), - HDA_CODEC_ENTRY(0x11c13155, "Si3054", patch_si3054), - HDA_CODEC_ENTRY(0x10573055, "Si3054", patch_si3054), - HDA_CODEC_ENTRY(0x10573057, "Si3054", patch_si3054), - HDA_CODEC_ENTRY(0x10573155, "Si3054", patch_si3054), + HDA_CODEC_ID(0x163c3055, "Si3054"), + HDA_CODEC_ID(0x163c3155, "Si3054"), + HDA_CODEC_ID(0x11c13026, "Si3054"), + HDA_CODEC_ID(0x11c13055, "Si3054"), + HDA_CODEC_ID(0x11c13155, "Si3054"), + HDA_CODEC_ID(0x10573055, "Si3054"), + HDA_CODEC_ID(0x10573057, "Si3054"), + HDA_CODEC_ID(0x10573155, "Si3054"), /* VIA HDA on Clevo m540 */ - HDA_CODEC_ENTRY(0x11063288, "Si3054", patch_si3054), + HDA_CODEC_ID(0x11063288, "Si3054"), /* Asus A8J Modem (SM56) */ - HDA_CODEC_ENTRY(0x15433155, "Si3054", patch_si3054), + HDA_CODEC_ID(0x15433155, "Si3054"), /* LG LW20 modem */ - HDA_CODEC_ENTRY(0x18540018, "Si3054", patch_si3054), + HDA_CODEC_ID(0x18540018, "Si3054"), {} }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_si3054); @@ -299,6 +297,7 @@ MODULE_DESCRIPTION("Si3054 HD-audio modem codec"); static struct hda_codec_driver si3054_driver = { .id = snd_hda_id_si3054, + .ops = &si3054_codec_ops, }; module_hda_codec_driver(si3054_driver); From be60c1290967d410597a6bc6a0982dfb8b3392e3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:23 +0200 Subject: [PATCH 336/385] ALSA: hda/via: Rewrite to new probe method Convert the VIA codec driver to use the new hda_codec_ops probe. No functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-21-tiwai@suse.de --- sound/hda/codecs/via.c | 445 +++++++++++++++++------------------------ 1 file changed, 186 insertions(+), 259 deletions(-) diff --git a/sound/hda/codecs/via.c b/sound/hda/codecs/via.c index e3ce563f866b..6becea9bb810 100644 --- a/sound/hda/codecs/via.c +++ b/sound/hda/codecs/via.c @@ -2,7 +2,7 @@ /* * Universal Interface for Intel High Definition Audio Codec * - * HD audio interface patch for VIA VT17xx/VT18xx/VT20xx codec + * HD audio codec driver for VIA VT17xx/VT18xx/VT20xx codec * * (C) 2006-2009 VIA Technology, Inc. * (C) 2006-2008 Takashi Iwai @@ -52,8 +52,10 @@ enum VIA_HDA_CODEC { UNKNOWN = -1, VT1708, + VT1709, VT1709_10CH, VT1709_6CH, + VT1708B, VT1708B_8CH, VT1708B_4CH, VT1708S, @@ -66,6 +68,7 @@ enum VIA_HDA_CODEC { VT1802, VT1705CF, VT1808, + VT3476, CODEC_TYPES, }; @@ -95,8 +98,6 @@ static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream, int action); -static const struct hda_codec_ops via_patch_ops; /* defined below */ - static struct via_spec *via_new_spec(struct hda_codec *codec) { struct via_spec *spec; @@ -118,7 +119,6 @@ static struct via_spec *via_new_spec(struct hda_codec *codec) spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO; codec->power_save_node = 1; spec->gen.power_down_unused = 1; - codec->patch_ops = via_patch_ops; return spec; } @@ -373,10 +373,10 @@ static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo, vt1708_update_hp_work(codec); } -static void via_free(struct hda_codec *codec) +static void via_remove(struct hda_codec *codec) { vt1708_stop_hp_work(codec); - snd_hda_gen_free(codec); + snd_hda_gen_remove(codec); } static int via_suspend(struct hda_codec *codec) @@ -395,7 +395,7 @@ static int via_resume(struct hda_codec *codec) { /* some delay here to make jack detection working (bko#98921) */ msleep(10); - codec->patch_ops.init(codec); + snd_hda_codec_init(codec); snd_hda_regmap_sync(codec); return 0; } @@ -411,20 +411,6 @@ static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid) /* */ -static int via_init(struct hda_codec *codec); - -static const struct hda_codec_ops via_patch_ops = { - .build_controls = snd_hda_gen_build_controls, - .build_pcms = snd_hda_gen_build_pcms, - .init = via_init, - .free = via_free, - .unsol_event = snd_hda_jack_unsol_event, - .suspend = via_suspend, - .resume = via_resume, - .check_power_status = via_check_power_status, -}; - - static const struct hda_verb vt1708_init_verbs[] = { /* power down jack detect function */ {0x1, 0xf81, 0x1}, @@ -541,19 +527,21 @@ static int via_init(struct hda_codec *codec) return 0; } -static int vt1708_build_controls(struct hda_codec *codec) +static int via_build_controls(struct hda_codec *codec) { /* In order not to create "Phantom Jack" controls, temporary enable jackpoll */ int err; int old_interval = codec->jackpoll_interval; - codec->jackpoll_interval = msecs_to_jiffies(100); + if (old_interval) + codec->jackpoll_interval = msecs_to_jiffies(100); err = snd_hda_gen_build_controls(codec); - codec->jackpoll_interval = old_interval; + if (old_interval) + codec->jackpoll_interval = old_interval; return err; } -static int vt1708_build_pcms(struct hda_codec *codec) +static int via_build_pcms(struct hda_codec *codec) { struct via_spec *spec = codec->spec; int i, err; @@ -580,19 +568,11 @@ static int vt1708_build_pcms(struct hda_codec *codec) return 0; } -static int patch_vt1708(struct hda_codec *codec) +static int probe_vt1708(struct hda_codec *codec) { - struct via_spec *spec; + struct via_spec *spec = codec->spec; int err; - /* create a codec specific record */ - spec = via_new_spec(codec); - if (spec == NULL) - return -ENOMEM; - - /* override some patch_ops */ - codec->patch_ops.build_controls = vt1708_build_controls; - codec->patch_ops.build_pcms = vt1708_build_pcms; spec->gen.mixer_nid = 0x17; /* set jackpoll_interval while parsing the codec */ @@ -611,81 +591,47 @@ static int patch_vt1708(struct hda_codec *codec) err = snd_hda_add_verbs(codec, vt1708_init_verbs); if (err < 0) - goto error; + return err; /* automatic parse from the BIOS config */ err = via_parse_auto_config(codec); if (err < 0) - goto error; + return err; /* add jack detect on/off control */ - if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1708_jack_detect_ctl)) { - err = -ENOMEM; - goto error; - } + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1708_jack_detect_ctl)) + return -ENOMEM; /* clear jackpoll_interval again; it's set dynamically */ codec->jackpoll_interval = 0; return 0; - - error: - via_free(codec); - return err; } -static int patch_vt1709(struct hda_codec *codec) +static int probe_vt1709(struct hda_codec *codec) { - struct via_spec *spec; - int err; - - /* create a codec specific record */ - spec = via_new_spec(codec); - if (spec == NULL) - return -ENOMEM; + struct via_spec *spec = codec->spec; spec->gen.mixer_nid = 0x18; - err = via_parse_auto_config(codec); - if (err < 0) - goto error; - - return 0; - - error: - via_free(codec); - return err; + return via_parse_auto_config(codec); } -static int patch_vt1708S(struct hda_codec *codec); -static int patch_vt1708B(struct hda_codec *codec) +static int probe_vt1708S(struct hda_codec *codec); +static int probe_vt1708B(struct hda_codec *codec) { - struct via_spec *spec; - int err; + struct via_spec *spec = codec->spec; if (get_codec_type(codec) == VT1708BCE) - return patch_vt1708S(codec); - - /* create a codec specific record */ - spec = via_new_spec(codec); - if (spec == NULL) - return -ENOMEM; + return probe_vt1708S(codec); spec->gen.mixer_nid = 0x16; /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); - if (err < 0) - goto error; - - return 0; - - error: - via_free(codec); - return err; + return via_parse_auto_config(codec); } -/* Patch for VT1708S */ +/* Support for VT1708S */ static const struct hda_verb vt1708S_init_verbs[] = { /* Enable Mic Boost Volume backdoor */ {0x1, 0xf98, 0x1}, @@ -706,16 +652,11 @@ static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin, (0 << AC_AMPCAP_MUTE_SHIFT)); } -static int patch_vt1708S(struct hda_codec *codec) +static int probe_vt1708S(struct hda_codec *codec) { - struct via_spec *spec; + struct via_spec *spec = codec->spec; int err; - /* create a codec specific record */ - spec = via_new_spec(codec); - if (spec == NULL) - return -ENOMEM; - spec->gen.mixer_nid = 0x16; override_mic_boost(codec, 0x1a, 0, 3, 40); override_mic_boost(codec, 0x1e, 0, 3, 40); @@ -729,21 +670,12 @@ static int patch_vt1708S(struct hda_codec *codec) err = snd_hda_add_verbs(codec, vt1708S_init_verbs); if (err < 0) - goto error; + return err; - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); - if (err < 0) - goto error; - - return 0; - - error: - via_free(codec); - return err; + return via_parse_auto_config(codec); } -/* Patch for VT1702 */ +/* Support for VT1702 */ static const struct hda_verb vt1702_init_verbs[] = { /* mixer enable */ @@ -753,16 +685,11 @@ static const struct hda_verb vt1702_init_verbs[] = { { } }; -static int patch_vt1702(struct hda_codec *codec) +static int probe_vt1702(struct hda_codec *codec) { - struct via_spec *spec; + struct via_spec *spec = codec->spec; int err; - /* create a codec specific record */ - spec = via_new_spec(codec); - if (spec == NULL) - return -ENOMEM; - spec->gen.mixer_nid = 0x1a; /* limit AA path volume to 0 dB */ @@ -774,21 +701,13 @@ static int patch_vt1702(struct hda_codec *codec) err = snd_hda_add_verbs(codec, vt1702_init_verbs); if (err < 0) - goto error; + return err; /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); - if (err < 0) - goto error; - - return 0; - - error: - via_free(codec); - return err; + return via_parse_auto_config(codec); } -/* Patch for VT1718S */ +/* Support for VT1718S */ static const struct hda_verb vt1718S_init_verbs[] = { /* Enable MW0 adjust Gain 5 */ @@ -836,16 +755,11 @@ static int add_secret_dac_path(struct hda_codec *codec) } -static int patch_vt1718S(struct hda_codec *codec) +static int probe_vt1718S(struct hda_codec *codec) { - struct via_spec *spec; + struct via_spec *spec = codec->spec; int err; - /* create a codec specific record */ - spec = via_new_spec(codec); - if (spec == NULL) - return -ENOMEM; - spec->gen.mixer_nid = 0x21; override_mic_boost(codec, 0x2b, 0, 3, 40); override_mic_boost(codec, 0x29, 0, 3, 40); @@ -853,21 +767,13 @@ static int patch_vt1718S(struct hda_codec *codec) err = snd_hda_add_verbs(codec, vt1718S_init_verbs); if (err < 0) - goto error; + return err; /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); - if (err < 0) - goto error; - - return 0; - - error: - via_free(codec); - return err; + return via_parse_auto_config(codec); } -/* Patch for VT1716S */ +/* Support for VT1716S */ static int vt1716s_dmic_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -933,41 +839,30 @@ static const struct hda_verb vt1716S_init_verbs[] = { { } }; -static int patch_vt1716S(struct hda_codec *codec) +static int probe_vt1716S(struct hda_codec *codec) { - struct via_spec *spec; + struct via_spec *spec = codec->spec; int err; - /* create a codec specific record */ - spec = via_new_spec(codec); - if (spec == NULL) - return -ENOMEM; - spec->gen.mixer_nid = 0x16; override_mic_boost(codec, 0x1a, 0, 3, 40); override_mic_boost(codec, 0x1e, 0, 3, 40); err = snd_hda_add_verbs(codec, vt1716S_init_verbs); if (err < 0) - goto error; + return err; /* automatic parse from the BIOS config */ err = via_parse_auto_config(codec); if (err < 0) - goto error; + return err; if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716s_dmic_mixer_vol) || !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716s_dmic_mixer_sw) || - !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716S_mono_out_mixer)) { - err = -ENOMEM; - goto error; - } + !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716S_mono_out_mixer)) + return -ENOMEM; return 0; - - error: - via_free(codec); - return err; } /* for vt2002P */ @@ -1055,17 +950,12 @@ static void fix_vt1802_connections(struct hda_codec *codec) snd_hda_override_conn_list(codec, 0x33, ARRAY_SIZE(conn_33), conn_33); } -/* patch for vt2002P */ -static int patch_vt2002P(struct hda_codec *codec) +/* Support for vt2002P */ +static int probe_vt2002P(struct hda_codec *codec) { - struct via_spec *spec; + struct via_spec *spec = codec->spec; int err; - /* create a codec specific record */ - spec = via_new_spec(codec); - if (spec == NULL) - return -ENOMEM; - spec->gen.mixer_nid = 0x21; override_mic_boost(codec, 0x2b, 0, 3, 40); override_mic_boost(codec, 0x29, 0, 3, 40); @@ -1081,18 +971,10 @@ static int patch_vt2002P(struct hda_codec *codec) else err = snd_hda_add_verbs(codec, vt2002P_init_verbs); if (err < 0) - goto error; + return err; /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); - if (err < 0) - goto error; - - return 0; - - error: - via_free(codec); - return err; + return via_parse_auto_config(codec); } /* for vt1812 */ @@ -1105,17 +987,11 @@ static const struct hda_verb vt1812_init_verbs[] = { { } }; -/* patch for vt1812 */ -static int patch_vt1812(struct hda_codec *codec) +static int probe_vt1812(struct hda_codec *codec) { - struct via_spec *spec; + struct via_spec *spec = codec->spec; int err; - /* create a codec specific record */ - spec = via_new_spec(codec); - if (spec == NULL) - return -ENOMEM; - spec->gen.mixer_nid = 0x21; override_mic_boost(codec, 0x2b, 0, 3, 40); override_mic_boost(codec, 0x29, 0, 3, 40); @@ -1123,21 +999,13 @@ static int patch_vt1812(struct hda_codec *codec) err = snd_hda_add_verbs(codec, vt1812_init_verbs); if (err < 0) - goto error; + return err; /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); - if (err < 0) - goto error; - - return 0; - - error: - via_free(codec); - return err; + return via_parse_auto_config(codec); } -/* patch for vt3476 */ +/* Support for vt3476 */ static const struct hda_verb vt3476_init_verbs[] = { /* Enable DMic 8/16/32K */ @@ -1149,96 +1017,155 @@ static const struct hda_verb vt3476_init_verbs[] = { { } }; -static int patch_vt3476(struct hda_codec *codec) +static int probe_vt3476(struct hda_codec *codec) { - struct via_spec *spec; + struct via_spec *spec = codec->spec; int err; - /* create a codec specific record */ - spec = via_new_spec(codec); - if (spec == NULL) - return -ENOMEM; - spec->gen.mixer_nid = 0x3f; add_secret_dac_path(codec); err = snd_hda_add_verbs(codec, vt3476_init_verbs); if (err < 0) - goto error; + return err; /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); - if (err < 0) - goto error; + return via_parse_auto_config(codec); - return 0; - - error: - via_free(codec); - return err; } /* - * patch entries + * common driver probe + */ +static int via_probe(struct hda_codec *codec, const struct hda_device_id *id) +{ + struct via_spec *spec; + int err; + + /* create a codec specific record */ + spec = via_new_spec(codec); + if (!spec) + return -ENOMEM; + + switch (id->driver_data) { + case VT1708: + err = probe_vt1708(codec); + break; + case VT1709: + err = probe_vt1709(codec); + break; + case VT1708B: + err = probe_vt1708B(codec); + break; + case VT1708S: + err = probe_vt1708S(codec); + break; + case VT1702: + err = probe_vt1702(codec); + break; + case VT1718S: + err = probe_vt1718S(codec); + break; + case VT1716S: + err = probe_vt1716S(codec); + break; + case VT2002P: + err = probe_vt2002P(codec); + break; + case VT1812: + err = probe_vt1812(codec); + break; + case VT3476: + err = probe_vt3476(codec); + break; + default: + err = -EINVAL; + break; + } + + if (err < 0) { + via_remove(codec); + return err; + } + + return 0; +} + +static const struct hda_codec_ops via_codec_ops = { + .probe = via_probe, + .remove = via_remove, + .build_controls = via_build_controls, + .build_pcms = via_build_pcms, + .init = via_init, + .unsol_event = snd_hda_jack_unsol_event, + .suspend = via_suspend, + .resume = via_resume, + .check_power_status = via_check_power_status, + .stream_pm = snd_hda_gen_stream_pm, +}; + +/* + * driver entries */ static const struct hda_device_id snd_hda_id_via[] = { - HDA_CODEC_ENTRY(0x11061708, "VT1708", patch_vt1708), - HDA_CODEC_ENTRY(0x11061709, "VT1708", patch_vt1708), - HDA_CODEC_ENTRY(0x1106170a, "VT1708", patch_vt1708), - HDA_CODEC_ENTRY(0x1106170b, "VT1708", patch_vt1708), - HDA_CODEC_ENTRY(0x1106e710, "VT1709 10-Ch", patch_vt1709), - HDA_CODEC_ENTRY(0x1106e711, "VT1709 10-Ch", patch_vt1709), - HDA_CODEC_ENTRY(0x1106e712, "VT1709 10-Ch", patch_vt1709), - HDA_CODEC_ENTRY(0x1106e713, "VT1709 10-Ch", patch_vt1709), - HDA_CODEC_ENTRY(0x1106e714, "VT1709 6-Ch", patch_vt1709), - HDA_CODEC_ENTRY(0x1106e715, "VT1709 6-Ch", patch_vt1709), - HDA_CODEC_ENTRY(0x1106e716, "VT1709 6-Ch", patch_vt1709), - HDA_CODEC_ENTRY(0x1106e717, "VT1709 6-Ch", patch_vt1709), - HDA_CODEC_ENTRY(0x1106e720, "VT1708B 8-Ch", patch_vt1708B), - HDA_CODEC_ENTRY(0x1106e721, "VT1708B 8-Ch", patch_vt1708B), - HDA_CODEC_ENTRY(0x1106e722, "VT1708B 8-Ch", patch_vt1708B), - HDA_CODEC_ENTRY(0x1106e723, "VT1708B 8-Ch", patch_vt1708B), - HDA_CODEC_ENTRY(0x1106e724, "VT1708B 4-Ch", patch_vt1708B), - HDA_CODEC_ENTRY(0x1106e725, "VT1708B 4-Ch", patch_vt1708B), - HDA_CODEC_ENTRY(0x1106e726, "VT1708B 4-Ch", patch_vt1708B), - HDA_CODEC_ENTRY(0x1106e727, "VT1708B 4-Ch", patch_vt1708B), - HDA_CODEC_ENTRY(0x11060397, "VT1708S", patch_vt1708S), - HDA_CODEC_ENTRY(0x11061397, "VT1708S", patch_vt1708S), - HDA_CODEC_ENTRY(0x11062397, "VT1708S", patch_vt1708S), - HDA_CODEC_ENTRY(0x11063397, "VT1708S", patch_vt1708S), - HDA_CODEC_ENTRY(0x11064397, "VT1705", patch_vt1708S), - HDA_CODEC_ENTRY(0x11065397, "VT1708S", patch_vt1708S), - HDA_CODEC_ENTRY(0x11066397, "VT1708S", patch_vt1708S), - HDA_CODEC_ENTRY(0x11067397, "VT1708S", patch_vt1708S), - HDA_CODEC_ENTRY(0x11060398, "VT1702", patch_vt1702), - HDA_CODEC_ENTRY(0x11061398, "VT1702", patch_vt1702), - HDA_CODEC_ENTRY(0x11062398, "VT1702", patch_vt1702), - HDA_CODEC_ENTRY(0x11063398, "VT1702", patch_vt1702), - HDA_CODEC_ENTRY(0x11064398, "VT1702", patch_vt1702), - HDA_CODEC_ENTRY(0x11065398, "VT1702", patch_vt1702), - HDA_CODEC_ENTRY(0x11066398, "VT1702", patch_vt1702), - HDA_CODEC_ENTRY(0x11067398, "VT1702", patch_vt1702), - HDA_CODEC_ENTRY(0x11060428, "VT1718S", patch_vt1718S), - HDA_CODEC_ENTRY(0x11064428, "VT1718S", patch_vt1718S), - HDA_CODEC_ENTRY(0x11060441, "VT2020", patch_vt1718S), - HDA_CODEC_ENTRY(0x11064441, "VT1828S", patch_vt1718S), - HDA_CODEC_ENTRY(0x11060433, "VT1716S", patch_vt1716S), - HDA_CODEC_ENTRY(0x1106a721, "VT1716S", patch_vt1716S), - HDA_CODEC_ENTRY(0x11060438, "VT2002P", patch_vt2002P), - HDA_CODEC_ENTRY(0x11064438, "VT2002P", patch_vt2002P), - HDA_CODEC_ENTRY(0x11060448, "VT1812", patch_vt1812), - HDA_CODEC_ENTRY(0x11060440, "VT1818S", patch_vt1708S), - HDA_CODEC_ENTRY(0x11060446, "VT1802", patch_vt2002P), - HDA_CODEC_ENTRY(0x11068446, "VT1802", patch_vt2002P), - HDA_CODEC_ENTRY(0x11064760, "VT1705CF", patch_vt3476), - HDA_CODEC_ENTRY(0x11064761, "VT1708SCE", patch_vt3476), - HDA_CODEC_ENTRY(0x11064762, "VT1808", patch_vt3476), + HDA_CODEC_ID_MODEL(0x11061708, "VT1708", VT1708), + HDA_CODEC_ID_MODEL(0x11061709, "VT1708", VT1708), + HDA_CODEC_ID_MODEL(0x1106170a, "VT1708", VT1708), + HDA_CODEC_ID_MODEL(0x1106170b, "VT1708", VT1708), + HDA_CODEC_ID_MODEL(0x1106e710, "VT1709 10-Ch", VT1709), + HDA_CODEC_ID_MODEL(0x1106e711, "VT1709 10-Ch", VT1709), + HDA_CODEC_ID_MODEL(0x1106e712, "VT1709 10-Ch", VT1709), + HDA_CODEC_ID_MODEL(0x1106e713, "VT1709 10-Ch", VT1709), + HDA_CODEC_ID_MODEL(0x1106e714, "VT1709 6-Ch", VT1709), + HDA_CODEC_ID_MODEL(0x1106e715, "VT1709 6-Ch", VT1709), + HDA_CODEC_ID_MODEL(0x1106e716, "VT1709 6-Ch", VT1709), + HDA_CODEC_ID_MODEL(0x1106e717, "VT1709 6-Ch", VT1709), + HDA_CODEC_ID_MODEL(0x1106e720, "VT1708B 8-Ch", VT1708B), + HDA_CODEC_ID_MODEL(0x1106e721, "VT1708B 8-Ch", VT1708B), + HDA_CODEC_ID_MODEL(0x1106e722, "VT1708B 8-Ch", VT1708B), + HDA_CODEC_ID_MODEL(0x1106e723, "VT1708B 8-Ch", VT1708B), + HDA_CODEC_ID_MODEL(0x1106e724, "VT1708B 4-Ch", VT1708B), + HDA_CODEC_ID_MODEL(0x1106e725, "VT1708B 4-Ch", VT1708B), + HDA_CODEC_ID_MODEL(0x1106e726, "VT1708B 4-Ch", VT1708B), + HDA_CODEC_ID_MODEL(0x1106e727, "VT1708B 4-Ch", VT1708B), + HDA_CODEC_ID_MODEL(0x11060397, "VT1708S", VT1708S), + HDA_CODEC_ID_MODEL(0x11061397, "VT1708S", VT1708S), + HDA_CODEC_ID_MODEL(0x11062397, "VT1708S", VT1708S), + HDA_CODEC_ID_MODEL(0x11063397, "VT1708S", VT1708S), + HDA_CODEC_ID_MODEL(0x11064397, "VT1705", VT1708S), + HDA_CODEC_ID_MODEL(0x11065397, "VT1708S", VT1708S), + HDA_CODEC_ID_MODEL(0x11066397, "VT1708S", VT1708S), + HDA_CODEC_ID_MODEL(0x11067397, "VT1708S", VT1708S), + HDA_CODEC_ID_MODEL(0x11060398, "VT1702", VT1702), + HDA_CODEC_ID_MODEL(0x11061398, "VT1702", VT1702), + HDA_CODEC_ID_MODEL(0x11062398, "VT1702", VT1702), + HDA_CODEC_ID_MODEL(0x11063398, "VT1702", VT1702), + HDA_CODEC_ID_MODEL(0x11064398, "VT1702", VT1702), + HDA_CODEC_ID_MODEL(0x11065398, "VT1702", VT1702), + HDA_CODEC_ID_MODEL(0x11066398, "VT1702", VT1702), + HDA_CODEC_ID_MODEL(0x11067398, "VT1702", VT1702), + HDA_CODEC_ID_MODEL(0x11060428, "VT1718S", VT1718S), + HDA_CODEC_ID_MODEL(0x11064428, "VT1718S", VT1718S), + HDA_CODEC_ID_MODEL(0x11060441, "VT2020", VT1718S), + HDA_CODEC_ID_MODEL(0x11064441, "VT1828S", VT1718S), + HDA_CODEC_ID_MODEL(0x11060433, "VT1716S", VT1716S), + HDA_CODEC_ID_MODEL(0x1106a721, "VT1716S", VT1716S), + HDA_CODEC_ID_MODEL(0x11060438, "VT2002P", VT2002P), + HDA_CODEC_ID_MODEL(0x11064438, "VT2002P", VT2002P), + HDA_CODEC_ID_MODEL(0x11060448, "VT1812", VT1812), + HDA_CODEC_ID_MODEL(0x11060440, "VT1818S", VT1708S), + HDA_CODEC_ID_MODEL(0x11060446, "VT1802", VT2002P), + HDA_CODEC_ID_MODEL(0x11068446, "VT1802", VT2002P), + HDA_CODEC_ID_MODEL(0x11064760, "VT1705CF", VT3476), + HDA_CODEC_ID_MODEL(0x11064761, "VT1708SCE", VT3476), + HDA_CODEC_ID_MODEL(0x11064762, "VT1808", VT3476), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_via); static struct hda_codec_driver via_driver = { .id = snd_hda_id_via, + .ops = &via_codec_ops, }; MODULE_LICENSE("GPL"); From eb2f0844140fdb569e05b5521087dff6892c27cd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:24 +0200 Subject: [PATCH 337/385] ALSA: hda/sigmatel: Rewrite to new probe method Convert the Sigmatel/IDT codec driver to use the new hda_codec_ops probe. No functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-22-tiwai@suse.de --- sound/hda/codecs/sigmatel.c | 398 ++++++++++++++++++------------------ 1 file changed, 203 insertions(+), 195 deletions(-) diff --git a/sound/hda/codecs/sigmatel.c b/sound/hda/codecs/sigmatel.c index 56274ff49b0b..ecbee408d771 100644 --- a/sound/hda/codecs/sigmatel.c +++ b/sound/hda/codecs/sigmatel.c @@ -2,7 +2,7 @@ /* * Universal Interface for Intel High Definition Audio Codec * - * HD audio interface patch for SigmaTel STAC92xx + * HD audio codec driver for SigmaTel STAC92xx * * Copyright (c) 2005 Embedded Alley Solutions, Inc. * Matt Porter @@ -4391,8 +4391,6 @@ static int stac_init(struct hda_codec *codec) return 0; } -#define stac_free snd_hda_gen_free - #ifdef CONFIG_SND_PROC_FS static void stac92hd_proc_hook(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid) @@ -4454,15 +4452,6 @@ static int stac_suspend(struct hda_codec *codec) return 0; } -static const struct hda_codec_ops stac_patch_ops = { - .build_controls = snd_hda_gen_build_controls, - .build_pcms = snd_hda_gen_build_pcms, - .init = stac_init, - .free = stac_free, - .unsol_event = snd_hda_jack_unsol_event, - .suspend = stac_suspend, -}; - static int alloc_stac_spec(struct hda_codec *codec) { struct sigmatel_spec *spec; @@ -4474,19 +4463,14 @@ static int alloc_stac_spec(struct hda_codec *codec) codec->spec = spec; codec->no_trigger_sense = 1; /* seems common with STAC/IDT codecs */ spec->gen.dac_min_mute = true; - codec->patch_ops = stac_patch_ops; return 0; } -static int patch_stac9200(struct hda_codec *codec) +static int probe_stac9200(struct hda_codec *codec) { struct sigmatel_spec *spec; int err; - err = alloc_stac_spec(codec); - if (err < 0) - return err; - spec = codec->spec; spec->linear_tone_beep = 1; spec->gen.own_eapd_ctl = 1; @@ -4500,25 +4484,19 @@ static int patch_stac9200(struct hda_codec *codec) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); err = stac_parse_auto_config(codec); - if (err < 0) { - stac_free(codec); + if (err < 0) return err; - } snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; } -static int patch_stac925x(struct hda_codec *codec) +static int probe_stac925x(struct hda_codec *codec) { struct sigmatel_spec *spec; int err; - err = alloc_stac_spec(codec); - if (err < 0) - return err; - spec = codec->spec; spec->linear_tone_beep = 1; spec->gen.own_eapd_ctl = 1; @@ -4530,26 +4508,20 @@ static int patch_stac925x(struct hda_codec *codec) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); err = stac_parse_auto_config(codec); - if (err < 0) { - stac_free(codec); + if (err < 0) return err; - } snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; } -static int patch_stac92hd73xx(struct hda_codec *codec) +static int probe_stac92hd73xx(struct hda_codec *codec) { struct sigmatel_spec *spec; int err; int num_dacs; - err = alloc_stac_spec(codec); - if (err < 0) - return err; - spec = codec->spec; /* enable power_save_node only for new 92HD89xx chips, as it causes * click noises on old 92HD73xx chips. @@ -4604,10 +4576,8 @@ static int patch_stac92hd73xx(struct hda_codec *codec) snd_hda_add_verbs(codec, stac92hd73xx_core_init); err = stac_parse_auto_config(codec); - if (err < 0) { - stac_free(codec); + if (err < 0) return err; - } /* Don't GPIO-mute speakers if there are no internal speakers, because * the GPIO might be necessary for Headphone @@ -4646,15 +4616,11 @@ static void stac_setup_gpio(struct hda_codec *codec) } } -static int patch_stac92hd83xxx(struct hda_codec *codec) +static int probe_stac92hd83xxx(struct hda_codec *codec) { struct sigmatel_spec *spec; int err; - err = alloc_stac_spec(codec); - if (err < 0) - return err; - /* longer delay needed for D3 */ codec->core.power_caps &= ~AC_PWRST_EPSS; @@ -4679,10 +4645,8 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) stac_setup_gpio(codec); err = stac_parse_auto_config(codec); - if (err < 0) { - stac_free(codec); + if (err < 0) return err; - } codec->proc_widget_hook = stac92hd_proc_hook; @@ -4695,15 +4659,11 @@ static const hda_nid_t stac92hd95_pwr_nids[] = { 0x0a, 0x0b, 0x0c, 0x0d }; -static int patch_stac92hd95(struct hda_codec *codec) +static int probe_stac92hd95(struct hda_codec *codec) { struct sigmatel_spec *spec; int err; - err = alloc_stac_spec(codec); - if (err < 0) - return err; - /* longer delay needed for D3 */ codec->core.power_caps &= ~AC_PWRST_EPSS; @@ -4725,10 +4685,8 @@ static int patch_stac92hd95(struct hda_codec *codec) stac_setup_gpio(codec); err = stac_parse_auto_config(codec); - if (err < 0) { - stac_free(codec); + if (err < 0) return err; - } codec->proc_widget_hook = stac92hd_proc_hook; @@ -4737,16 +4695,12 @@ static int patch_stac92hd95(struct hda_codec *codec) return 0; } -static int patch_stac92hd71bxx(struct hda_codec *codec) +static int probe_stac92hd71bxx(struct hda_codec *codec) { struct sigmatel_spec *spec; const hda_nid_t *unmute_nids = stac92hd71bxx_unmute_nids; int err; - err = alloc_stac_spec(codec); - if (err < 0) - return err; - spec = codec->spec; /* disabled power_save_node since it causes noises on a Dell machine */ /* codec->power_save_node = 1; */ @@ -4809,10 +4763,8 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) stac_setup_gpio(codec); err = stac_parse_auto_config(codec); - if (err < 0) { - stac_free(codec); + if (err < 0) return err; - } codec->proc_widget_hook = stac92hd7x_proc_hook; @@ -4821,15 +4773,11 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) return 0; } -static int patch_stac922x(struct hda_codec *codec) +static int probe_stac922x(struct hda_codec *codec) { struct sigmatel_spec *spec; int err; - err = alloc_stac_spec(codec); - if (err < 0) - return err; - spec = codec->spec; spec->linear_tone_beep = 1; spec->gen.own_eapd_ctl = 1; @@ -4848,10 +4796,8 @@ static int patch_stac922x(struct hda_codec *codec) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); err = stac_parse_auto_config(codec); - if (err < 0) { - stac_free(codec); + if (err < 0) return err; - } snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); @@ -4863,15 +4809,11 @@ static const char * const stac927x_spdif_labels[] = { "Analog Mux 2", "Analog Mux 3", NULL }; -static int patch_stac927x(struct hda_codec *codec) +static int probe_stac927x(struct hda_codec *codec) { struct sigmatel_spec *spec; int err; - err = alloc_stac_spec(codec); - if (err < 0) - return err; - spec = codec->spec; spec->linear_tone_beep = 1; spec->gen.own_eapd_ctl = 1; @@ -4897,10 +4839,8 @@ static int patch_stac927x(struct hda_codec *codec) snd_hda_add_verbs(codec, stac927x_core_init); err = stac_parse_auto_config(codec); - if (err < 0) { - stac_free(codec); + if (err < 0) return err; - } codec->proc_widget_hook = stac927x_proc_hook; @@ -4921,15 +4861,11 @@ static int patch_stac927x(struct hda_codec *codec) return 0; } -static int patch_stac9205(struct hda_codec *codec) +static int probe_stac9205(struct hda_codec *codec) { struct sigmatel_spec *spec; int err; - err = alloc_stac_spec(codec); - if (err < 0) - return err; - spec = codec->spec; spec->linear_tone_beep = 1; spec->gen.own_eapd_ctl = 1; @@ -4955,10 +4891,8 @@ static int patch_stac9205(struct hda_codec *codec) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); err = stac_parse_auto_config(codec); - if (err < 0) { - stac_free(codec); + if (err < 0) return err; - } codec->proc_widget_hook = stac9205_proc_hook; @@ -5008,15 +4942,11 @@ static const struct hda_quirk stac9872_fixup_tbl[] = { {} /* terminator */ }; -static int patch_stac9872(struct hda_codec *codec) +static int probe_stac9872(struct hda_codec *codec) { struct sigmatel_spec *spec; int err; - err = alloc_stac_spec(codec); - if (err < 0) - return err; - spec = codec->spec; spec->linear_tone_beep = 1; spec->gen.own_eapd_ctl = 1; @@ -5028,125 +4958,202 @@ static int patch_stac9872(struct hda_codec *codec) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); err = stac_parse_auto_config(codec); - if (err < 0) { - stac_free(codec); - return -EINVAL; - } + if (err < 0) + return err; snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; } +/* + * common driver probe + */ + +enum { + MODEL_STAC9200, + MODEL_STAC9205, + MODEL_STAC922X, + MODEL_STAC925X, + MODEL_STAC927X, + MODEL_STAC9872, + MODEL_STAC92HD71BXX, + MODEL_STAC92HD73XX, + MODEL_STAC92HD83XXX, + MODEL_STAC92HD95, +}; + +static int stac_probe(struct hda_codec *codec, const struct hda_device_id *id) +{ + int err; + + err = alloc_stac_spec(codec); + if (err < 0) + return err; + + switch (id->driver_data) { + case MODEL_STAC9200: + err = probe_stac9200(codec); + break; + case MODEL_STAC9205: + err = probe_stac9205(codec); + break; + case MODEL_STAC922X: + err = probe_stac922x(codec); + break; + case MODEL_STAC925X: + err = probe_stac925x(codec); + break; + case MODEL_STAC927X: + err = probe_stac927x(codec); + break; + case MODEL_STAC9872: + err = probe_stac9872(codec); + break; + case MODEL_STAC92HD71BXX: + err = probe_stac92hd71bxx(codec); + break; + case MODEL_STAC92HD73XX: + err = probe_stac92hd73xx(codec); + break; + case MODEL_STAC92HD83XXX: + err = probe_stac92hd83xxx(codec); + break; + case MODEL_STAC92HD95: + err = probe_stac92hd95(codec); + break; + default: + err = -EINVAL; + break; + } + + if (err < 0) { + snd_hda_gen_remove(codec); + return err; + } + + return 0; +} + +static const struct hda_codec_ops stac_codec_ops = { + .probe = stac_probe, + .remove = snd_hda_gen_remove, + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = stac_init, + .unsol_event = snd_hda_jack_unsol_event, + .suspend = stac_suspend, + .stream_pm = snd_hda_gen_stream_pm, +}; /* - * patch entries + * driver entries */ static const struct hda_device_id snd_hda_id_sigmatel[] = { - HDA_CODEC_ENTRY(0x83847690, "STAC9200", patch_stac9200), - HDA_CODEC_ENTRY(0x83847882, "STAC9220 A1", patch_stac922x), - HDA_CODEC_ENTRY(0x83847680, "STAC9221 A1", patch_stac922x), - HDA_CODEC_ENTRY(0x83847880, "STAC9220 A2", patch_stac922x), - HDA_CODEC_ENTRY(0x83847681, "STAC9220D/9223D A2", patch_stac922x), - HDA_CODEC_ENTRY(0x83847682, "STAC9221 A2", patch_stac922x), - HDA_CODEC_ENTRY(0x83847683, "STAC9221D A2", patch_stac922x), - HDA_CODEC_ENTRY(0x83847618, "STAC9227", patch_stac927x), - HDA_CODEC_ENTRY(0x83847619, "STAC9227", patch_stac927x), - HDA_CODEC_ENTRY(0x83847638, "STAC92HD700", patch_stac927x), - HDA_CODEC_ENTRY(0x83847616, "STAC9228", patch_stac927x), - HDA_CODEC_ENTRY(0x83847617, "STAC9228", patch_stac927x), - HDA_CODEC_ENTRY(0x83847614, "STAC9229", patch_stac927x), - HDA_CODEC_ENTRY(0x83847615, "STAC9229", patch_stac927x), - HDA_CODEC_ENTRY(0x83847620, "STAC9274", patch_stac927x), - HDA_CODEC_ENTRY(0x83847621, "STAC9274D", patch_stac927x), - HDA_CODEC_ENTRY(0x83847622, "STAC9273X", patch_stac927x), - HDA_CODEC_ENTRY(0x83847623, "STAC9273D", patch_stac927x), - HDA_CODEC_ENTRY(0x83847624, "STAC9272X", patch_stac927x), - HDA_CODEC_ENTRY(0x83847625, "STAC9272D", patch_stac927x), - HDA_CODEC_ENTRY(0x83847626, "STAC9271X", patch_stac927x), - HDA_CODEC_ENTRY(0x83847627, "STAC9271D", patch_stac927x), - HDA_CODEC_ENTRY(0x83847628, "STAC9274X5NH", patch_stac927x), - HDA_CODEC_ENTRY(0x83847629, "STAC9274D5NH", patch_stac927x), - HDA_CODEC_ENTRY(0x83847632, "STAC9202", patch_stac925x), - HDA_CODEC_ENTRY(0x83847633, "STAC9202D", patch_stac925x), - HDA_CODEC_ENTRY(0x83847634, "STAC9250", patch_stac925x), - HDA_CODEC_ENTRY(0x83847635, "STAC9250D", patch_stac925x), - HDA_CODEC_ENTRY(0x83847636, "STAC9251", patch_stac925x), - HDA_CODEC_ENTRY(0x83847637, "STAC9250D", patch_stac925x), - HDA_CODEC_ENTRY(0x83847645, "92HD206X", patch_stac927x), - HDA_CODEC_ENTRY(0x83847646, "92HD206D", patch_stac927x), + HDA_CODEC_ID_MODEL(0x83847690, "STAC9200", MODEL_STAC9200), + HDA_CODEC_ID_MODEL(0x83847882, "STAC9220 A1", MODEL_STAC922X), + HDA_CODEC_ID_MODEL(0x83847680, "STAC9221 A1", MODEL_STAC922X), + HDA_CODEC_ID_MODEL(0x83847880, "STAC9220 A2", MODEL_STAC922X), + HDA_CODEC_ID_MODEL(0x83847681, "STAC9220D/9223D A2", MODEL_STAC922X), + HDA_CODEC_ID_MODEL(0x83847682, "STAC9221 A2", MODEL_STAC922X), + HDA_CODEC_ID_MODEL(0x83847683, "STAC9221D A2", MODEL_STAC922X), + HDA_CODEC_ID_MODEL(0x83847618, "STAC9227", MODEL_STAC927X), + HDA_CODEC_ID_MODEL(0x83847619, "STAC9227", MODEL_STAC927X), + HDA_CODEC_ID_MODEL(0x83847638, "STAC92HD700", MODEL_STAC927X), + HDA_CODEC_ID_MODEL(0x83847616, "STAC9228", MODEL_STAC927X), + HDA_CODEC_ID_MODEL(0x83847617, "STAC9228", MODEL_STAC927X), + HDA_CODEC_ID_MODEL(0x83847614, "STAC9229", MODEL_STAC927X), + HDA_CODEC_ID_MODEL(0x83847615, "STAC9229", MODEL_STAC927X), + HDA_CODEC_ID_MODEL(0x83847620, "STAC9274", MODEL_STAC927X), + HDA_CODEC_ID_MODEL(0x83847621, "STAC9274D", MODEL_STAC927X), + HDA_CODEC_ID_MODEL(0x83847622, "STAC9273X", MODEL_STAC927X), + HDA_CODEC_ID_MODEL(0x83847623, "STAC9273D", MODEL_STAC927X), + HDA_CODEC_ID_MODEL(0x83847624, "STAC9272X", MODEL_STAC927X), + HDA_CODEC_ID_MODEL(0x83847625, "STAC9272D", MODEL_STAC927X), + HDA_CODEC_ID_MODEL(0x83847626, "STAC9271X", MODEL_STAC927X), + HDA_CODEC_ID_MODEL(0x83847627, "STAC9271D", MODEL_STAC927X), + HDA_CODEC_ID_MODEL(0x83847628, "STAC9274X5NH", MODEL_STAC927X), + HDA_CODEC_ID_MODEL(0x83847629, "STAC9274D5NH", MODEL_STAC927X), + HDA_CODEC_ID_MODEL(0x83847632, "STAC9202", MODEL_STAC925X), + HDA_CODEC_ID_MODEL(0x83847633, "STAC9202D", MODEL_STAC925X), + HDA_CODEC_ID_MODEL(0x83847634, "STAC9250", MODEL_STAC925X), + HDA_CODEC_ID_MODEL(0x83847635, "STAC9250D", MODEL_STAC925X), + HDA_CODEC_ID_MODEL(0x83847636, "STAC9251", MODEL_STAC925X), + HDA_CODEC_ID_MODEL(0x83847637, "STAC9250D", MODEL_STAC925X), + HDA_CODEC_ID_MODEL(0x83847645, "92HD206X", MODEL_STAC927X), + HDA_CODEC_ID_MODEL(0x83847646, "92HD206D", MODEL_STAC927X), /* The following does not take into account .id=0x83847661 when subsys = * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are * currently not fully supported. */ - HDA_CODEC_ENTRY(0x83847661, "CXD9872RD/K", patch_stac9872), - HDA_CODEC_ENTRY(0x83847662, "STAC9872AK", patch_stac9872), - HDA_CODEC_ENTRY(0x83847664, "CXD9872AKD", patch_stac9872), - HDA_CODEC_ENTRY(0x83847698, "STAC9205", patch_stac9205), - HDA_CODEC_ENTRY(0x838476a0, "STAC9205", patch_stac9205), - HDA_CODEC_ENTRY(0x838476a1, "STAC9205D", patch_stac9205), - HDA_CODEC_ENTRY(0x838476a2, "STAC9204", patch_stac9205), - HDA_CODEC_ENTRY(0x838476a3, "STAC9204D", patch_stac9205), - HDA_CODEC_ENTRY(0x838476a4, "STAC9255", patch_stac9205), - HDA_CODEC_ENTRY(0x838476a5, "STAC9255D", patch_stac9205), - HDA_CODEC_ENTRY(0x838476a6, "STAC9254", patch_stac9205), - HDA_CODEC_ENTRY(0x838476a7, "STAC9254D", patch_stac9205), - HDA_CODEC_ENTRY(0x111d7603, "92HD75B3X5", patch_stac92hd71bxx), - HDA_CODEC_ENTRY(0x111d7604, "92HD83C1X5", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76d4, "92HD83C1C5", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d7605, "92HD81B1X5", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76d5, "92HD81B1C5", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76d1, "92HD87B1/3", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76d9, "92HD87B2/4", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d7666, "92HD88B3", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d7667, "92HD88B1", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d7668, "92HD88B2", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d7669, "92HD88B4", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d7608, "92HD75B2X5", patch_stac92hd71bxx), - HDA_CODEC_ENTRY(0x111d7674, "92HD73D1X5", patch_stac92hd73xx), - HDA_CODEC_ENTRY(0x111d7675, "92HD73C1X5", patch_stac92hd73xx), - HDA_CODEC_ENTRY(0x111d7676, "92HD73E1X5", patch_stac92hd73xx), - HDA_CODEC_ENTRY(0x111d7695, "92HD95", patch_stac92hd95), - HDA_CODEC_ENTRY(0x111d76b0, "92HD71B8X", patch_stac92hd71bxx), - HDA_CODEC_ENTRY(0x111d76b1, "92HD71B8X", patch_stac92hd71bxx), - HDA_CODEC_ENTRY(0x111d76b2, "92HD71B7X", patch_stac92hd71bxx), - HDA_CODEC_ENTRY(0x111d76b3, "92HD71B7X", patch_stac92hd71bxx), - HDA_CODEC_ENTRY(0x111d76b4, "92HD71B6X", patch_stac92hd71bxx), - HDA_CODEC_ENTRY(0x111d76b5, "92HD71B6X", patch_stac92hd71bxx), - HDA_CODEC_ENTRY(0x111d76b6, "92HD71B5X", patch_stac92hd71bxx), - HDA_CODEC_ENTRY(0x111d76b7, "92HD71B5X", patch_stac92hd71bxx), - HDA_CODEC_ENTRY(0x111d76c0, "92HD89C3", patch_stac92hd73xx), - HDA_CODEC_ENTRY(0x111d76c1, "92HD89C2", patch_stac92hd73xx), - HDA_CODEC_ENTRY(0x111d76c2, "92HD89C1", patch_stac92hd73xx), - HDA_CODEC_ENTRY(0x111d76c3, "92HD89B3", patch_stac92hd73xx), - HDA_CODEC_ENTRY(0x111d76c4, "92HD89B2", patch_stac92hd73xx), - HDA_CODEC_ENTRY(0x111d76c5, "92HD89B1", patch_stac92hd73xx), - HDA_CODEC_ENTRY(0x111d76c6, "92HD89E3", patch_stac92hd73xx), - HDA_CODEC_ENTRY(0x111d76c7, "92HD89E2", patch_stac92hd73xx), - HDA_CODEC_ENTRY(0x111d76c8, "92HD89E1", patch_stac92hd73xx), - HDA_CODEC_ENTRY(0x111d76c9, "92HD89D3", patch_stac92hd73xx), - HDA_CODEC_ENTRY(0x111d76ca, "92HD89D2", patch_stac92hd73xx), - HDA_CODEC_ENTRY(0x111d76cb, "92HD89D1", patch_stac92hd73xx), - HDA_CODEC_ENTRY(0x111d76cc, "92HD89F3", patch_stac92hd73xx), - HDA_CODEC_ENTRY(0x111d76cd, "92HD89F2", patch_stac92hd73xx), - HDA_CODEC_ENTRY(0x111d76ce, "92HD89F1", patch_stac92hd73xx), - HDA_CODEC_ENTRY(0x111d76df, "92HD93BXX", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76e0, "92HD91BXX", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76e3, "92HD98BXX", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76e5, "92HD99BXX", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76e7, "92HD90BXX", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76e8, "92HD66B1X5", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76e9, "92HD66B2X5", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76ea, "92HD66B3X5", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76eb, "92HD66C1X5", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76ec, "92HD66C2X5", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76ed, "92HD66C3X5", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76ee, "92HD66B1X3", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76ef, "92HD66B2X3", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76f0, "92HD66B3X3", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76f1, "92HD66C1X3", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76f2, "92HD66C2X3", patch_stac92hd83xxx), - HDA_CODEC_ENTRY(0x111d76f3, "92HD66C3/65", patch_stac92hd83xxx), + HDA_CODEC_ID_MODEL(0x83847661, "CXD9872RD/K", MODEL_STAC9872), + HDA_CODEC_ID_MODEL(0x83847662, "STAC9872AK", MODEL_STAC9872), + HDA_CODEC_ID_MODEL(0x83847664, "CXD9872AKD", MODEL_STAC9872), + HDA_CODEC_ID_MODEL(0x83847698, "STAC9205", MODEL_STAC9205), + HDA_CODEC_ID_MODEL(0x838476a0, "STAC9205", MODEL_STAC9205), + HDA_CODEC_ID_MODEL(0x838476a1, "STAC9205D", MODEL_STAC9205), + HDA_CODEC_ID_MODEL(0x838476a2, "STAC9204", MODEL_STAC9205), + HDA_CODEC_ID_MODEL(0x838476a3, "STAC9204D", MODEL_STAC9205), + HDA_CODEC_ID_MODEL(0x838476a4, "STAC9255", MODEL_STAC9205), + HDA_CODEC_ID_MODEL(0x838476a5, "STAC9255D", MODEL_STAC9205), + HDA_CODEC_ID_MODEL(0x838476a6, "STAC9254", MODEL_STAC9205), + HDA_CODEC_ID_MODEL(0x838476a7, "STAC9254D", MODEL_STAC9205), + HDA_CODEC_ID_MODEL(0x111d7603, "92HD75B3X5", MODEL_STAC92HD71BXX), + HDA_CODEC_ID_MODEL(0x111d7604, "92HD83C1X5", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76d4, "92HD83C1C5", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d7605, "92HD81B1X5", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76d5, "92HD81B1C5", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76d1, "92HD87B1/3", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76d9, "92HD87B2/4", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d7666, "92HD88B3", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d7667, "92HD88B1", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d7668, "92HD88B2", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d7669, "92HD88B4", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d7608, "92HD75B2X5", MODEL_STAC92HD71BXX), + HDA_CODEC_ID_MODEL(0x111d7674, "92HD73D1X5", MODEL_STAC92HD73XX), + HDA_CODEC_ID_MODEL(0x111d7675, "92HD73C1X5", MODEL_STAC92HD73XX), + HDA_CODEC_ID_MODEL(0x111d7676, "92HD73E1X5", MODEL_STAC92HD73XX), + HDA_CODEC_ID_MODEL(0x111d7695, "92HD95", MODEL_STAC92HD95), + HDA_CODEC_ID_MODEL(0x111d76b0, "92HD71B8X", MODEL_STAC92HD71BXX), + HDA_CODEC_ID_MODEL(0x111d76b1, "92HD71B8X", MODEL_STAC92HD71BXX), + HDA_CODEC_ID_MODEL(0x111d76b2, "92HD71B7X", MODEL_STAC92HD71BXX), + HDA_CODEC_ID_MODEL(0x111d76b3, "92HD71B7X", MODEL_STAC92HD71BXX), + HDA_CODEC_ID_MODEL(0x111d76b4, "92HD71B6X", MODEL_STAC92HD71BXX), + HDA_CODEC_ID_MODEL(0x111d76b5, "92HD71B6X", MODEL_STAC92HD71BXX), + HDA_CODEC_ID_MODEL(0x111d76b6, "92HD71B5X", MODEL_STAC92HD71BXX), + HDA_CODEC_ID_MODEL(0x111d76b7, "92HD71B5X", MODEL_STAC92HD71BXX), + HDA_CODEC_ID_MODEL(0x111d76c0, "92HD89C3", MODEL_STAC92HD73XX), + HDA_CODEC_ID_MODEL(0x111d76c1, "92HD89C2", MODEL_STAC92HD73XX), + HDA_CODEC_ID_MODEL(0x111d76c2, "92HD89C1", MODEL_STAC92HD73XX), + HDA_CODEC_ID_MODEL(0x111d76c3, "92HD89B3", MODEL_STAC92HD73XX), + HDA_CODEC_ID_MODEL(0x111d76c4, "92HD89B2", MODEL_STAC92HD73XX), + HDA_CODEC_ID_MODEL(0x111d76c5, "92HD89B1", MODEL_STAC92HD73XX), + HDA_CODEC_ID_MODEL(0x111d76c6, "92HD89E3", MODEL_STAC92HD73XX), + HDA_CODEC_ID_MODEL(0x111d76c7, "92HD89E2", MODEL_STAC92HD73XX), + HDA_CODEC_ID_MODEL(0x111d76c8, "92HD89E1", MODEL_STAC92HD73XX), + HDA_CODEC_ID_MODEL(0x111d76c9, "92HD89D3", MODEL_STAC92HD73XX), + HDA_CODEC_ID_MODEL(0x111d76ca, "92HD89D2", MODEL_STAC92HD73XX), + HDA_CODEC_ID_MODEL(0x111d76cb, "92HD89D1", MODEL_STAC92HD73XX), + HDA_CODEC_ID_MODEL(0x111d76cc, "92HD89F3", MODEL_STAC92HD73XX), + HDA_CODEC_ID_MODEL(0x111d76cd, "92HD89F2", MODEL_STAC92HD73XX), + HDA_CODEC_ID_MODEL(0x111d76ce, "92HD89F1", MODEL_STAC92HD73XX), + HDA_CODEC_ID_MODEL(0x111d76df, "92HD93BXX", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76e0, "92HD91BXX", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76e3, "92HD98BXX", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76e5, "92HD99BXX", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76e7, "92HD90BXX", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76e8, "92HD66B1X5", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76e9, "92HD66B2X5", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76ea, "92HD66B3X5", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76eb, "92HD66C1X5", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76ec, "92HD66C2X5", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76ed, "92HD66C3X5", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76ee, "92HD66B1X3", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76ef, "92HD66B2X3", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76f0, "92HD66B3X3", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76f1, "92HD66C1X3", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76f2, "92HD66C2X3", MODEL_STAC92HD83XXX), + HDA_CODEC_ID_MODEL(0x111d76f3, "92HD66C3/65", MODEL_STAC92HD83XXX), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_sigmatel); @@ -5156,6 +5163,7 @@ MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec"); static struct hda_codec_driver sigmatel_driver = { .id = snd_hda_id_sigmatel, + .ops = &stac_codec_ops, }; module_hda_codec_driver(sigmatel_driver); From 6cce08122f7096c045ed72b734e2e00ab46fd111 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:25 +0200 Subject: [PATCH 338/385] ALSA: hda/ca0132: Rewrite to new probe method Convert the CA0132 codec driver to use the new hda_codec_ops probe. No functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-23-tiwai@suse.de --- sound/hda/codecs/ca0132.c | 103 +++++++++++++++++++++------------ sound/hda/codecs/ca0132_regs.h | 2 +- 2 files changed, 68 insertions(+), 37 deletions(-) diff --git a/sound/hda/codecs/ca0132.c b/sound/hda/codecs/ca0132.c index 35a979465c75..6ab59c336ed4 100644 --- a/sound/hda/codecs/ca0132.c +++ b/sound/hda/codecs/ca0132.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * HD audio interface patch for Creative CA0132 chip + * HD audio codec driver for Creative CA0132 chip * * Copyright (c) 2011, Creative Technology Ltd. * @@ -9118,7 +9118,7 @@ static void sbz_dsp_startup_check(struct hda_codec *codec) codec_info(codec, "Reloading... Tries left: %d", reload); sbz_exit_chip(codec); spec->dsp_state = DSP_DOWNLOAD_INIT; - codec->patch_ops.init(codec); + snd_hda_codec_init(codec); failure = 0; for (i = 0; i < 4; i++) { chipio_read(codec, cur_address, &dsp_data_check[i]); @@ -9694,30 +9694,6 @@ static void dbpro_free(struct hda_codec *codec) kfree(codec->spec); } -static int ca0132_suspend(struct hda_codec *codec) -{ - struct ca0132_spec *spec = codec->spec; - - cancel_delayed_work_sync(&spec->unsol_hp_work); - return 0; -} - -static const struct hda_codec_ops ca0132_patch_ops = { - .build_controls = ca0132_build_controls, - .build_pcms = ca0132_build_pcms, - .init = ca0132_init, - .free = ca0132_free, - .unsol_event = snd_hda_jack_unsol_event, - .suspend = ca0132_suspend, -}; - -static const struct hda_codec_ops dbpro_patch_ops = { - .build_controls = dbpro_build_controls, - .build_pcms = dbpro_build_pcms, - .init = dbpro_init, - .free = dbpro_free, -}; - static void ca0132_config(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; @@ -9982,12 +9958,23 @@ static void sbz_detect_quirk(struct hda_codec *codec) } } -static int patch_ca0132(struct hda_codec *codec) +static void ca0132_codec_remove(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO) + return dbpro_free(codec); + else + return ca0132_free(codec); +} + +static int ca0132_codec_probe(struct hda_codec *codec, + const struct hda_device_id *id) { struct ca0132_spec *spec; int err; - codec_dbg(codec, "patch_ca0132\n"); + codec_dbg(codec, "%s\n", __func__); spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) @@ -10000,11 +9987,6 @@ static int patch_ca0132(struct hda_codec *codec) if (ca0132_quirk(spec) == QUIRK_SBZ) sbz_detect_quirk(codec); - if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO) - codec->patch_ops = dbpro_patch_ops; - else - codec->patch_ops = ca0132_patch_ops; - codec->pcm_format_first = 1; codec->no_sticky_stream = 1; @@ -10100,15 +10082,63 @@ static int patch_ca0132(struct hda_codec *codec) return 0; error: - ca0132_free(codec); + ca0132_codec_remove(codec); return err; } +static int ca0132_codec_build_controls(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO) + return dbpro_build_controls(codec); + else + return ca0132_build_controls(codec); +} + +static int ca0132_codec_build_pcms(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO) + return dbpro_build_pcms(codec); + else + return ca0132_build_pcms(codec); +} + +static int ca0132_codec_init(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO) + return dbpro_init(codec); + else + return ca0132_init(codec); +} + +static int ca0132_codec_suspend(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + cancel_delayed_work_sync(&spec->unsol_hp_work); + return 0; +} + +static const struct hda_codec_ops ca0132_codec_ops = { + .probe = ca0132_codec_probe, + .remove = ca0132_codec_remove, + .build_controls = ca0132_codec_build_controls, + .build_pcms = ca0132_codec_build_pcms, + .init = ca0132_codec_init, + .unsol_event = snd_hda_jack_unsol_event, + .suspend = ca0132_codec_suspend, +}; + /* - * patch entries + * driver entries */ static const struct hda_device_id snd_hda_id_ca0132[] = { - HDA_CODEC_ENTRY(0x11020011, "CA0132", patch_ca0132), + HDA_CODEC_ID(0x11020011, "CA0132"), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_ca0132); @@ -10118,6 +10148,7 @@ MODULE_DESCRIPTION("Creative Sound Core3D codec"); static struct hda_codec_driver ca0132_driver = { .id = snd_hda_id_ca0132, + .ops = &ca0132_codec_ops, }; module_hda_codec_driver(ca0132_driver); diff --git a/sound/hda/codecs/ca0132_regs.h b/sound/hda/codecs/ca0132_regs.h index 0ead571fb447..dc0153df3d5c 100644 --- a/sound/hda/codecs/ca0132_regs.h +++ b/sound/hda/codecs/ca0132_regs.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * HD audio interface patch for Creative CA0132 chip. + * HD audio codec driver for Creative CA0132 chip. * CA0132 registers defines. * * Copyright (c) 2011, Creative Technology Ltd. From ad781b550f9a8829e3dae4bd3d18c4a126a53d04 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:26 +0200 Subject: [PATCH 339/385] ALSA: hda/hdmi: Rewrite to new probe method Convert the HDMI codec drivers to use the new hda_codec_ops probe. The Intel and Nvidia-MCP HDMI drivers needed slightly more changes to deal with the unified callbacks among all models. Also another non-trivial change is Intel driver's set_power_state callback. An additional NULL check of codec->spec is needed there since the set_power_state() may be called before the probe gets called (e.g. in ASoC hda codec hda_codec_probe()). Other than that, no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-24-tiwai@suse.de --- sound/hda/codecs/hdmi/atihdmi.c | 31 +++-- sound/hda/codecs/hdmi/hdmi.c | 130 ++++++++++---------- sound/hda/codecs/hdmi/hdmi_local.h | 10 +- sound/hda/codecs/hdmi/intelhdmi.c | 185 ++++++++++++++++++----------- sound/hda/codecs/hdmi/nvhdmi-mcp.c | 96 +++++++-------- sound/hda/codecs/hdmi/nvhdmi.c | 183 ++++++++++++++-------------- sound/hda/codecs/hdmi/simplehdmi.c | 58 +++++---- sound/hda/codecs/hdmi/tegrahdmi.c | 69 ++++++----- 8 files changed, 424 insertions(+), 338 deletions(-) diff --git a/sound/hda/codecs/hdmi/atihdmi.c b/sound/hda/codecs/hdmi/atihdmi.c index e23995cc1b8c..44366f75de33 100644 --- a/sound/hda/codecs/hdmi/atihdmi.c +++ b/sound/hda/codecs/hdmi/atihdmi.c @@ -528,19 +528,16 @@ static const struct drm_audio_component_audio_ops atihdmi_audio_ops = { .master_unbind = snd_hda_hdmi_acomp_master_unbind, }; -static int patch_atihdmi(struct hda_codec *codec) +static int atihdmi_probe(struct hda_codec *codec, const struct hda_device_id *id) { struct hdmi_spec *spec; struct hdmi_spec_per_cvt *per_cvt; int err, cvt_idx; - err = patch_generic_hdmi(codec); - + err = snd_hda_hdmi_generic_probe(codec); if (err) return err; - codec->patch_ops.init = atihdmi_init; - spec = codec->spec; spec->static_pcm_mapping = true; @@ -583,15 +580,26 @@ static int patch_atihdmi(struct hda_codec *codec) return 0; } +static const struct hda_codec_ops atihdmi_codec_ops = { + .probe = atihdmi_probe, + .remove = snd_hda_hdmi_generic_remove, + .init = atihdmi_init, + .build_pcms = snd_hda_hdmi_generic_build_pcms, + .build_controls = snd_hda_hdmi_generic_build_controls, + .unsol_event = snd_hda_hdmi_generic_unsol_event, + .suspend = snd_hda_hdmi_generic_suspend, + .resume = snd_hda_hdmi_generic_resume, +}; + /* - * patch entries + * driver entries */ static const struct hda_device_id snd_hda_id_atihdmi[] = { -HDA_CODEC_ENTRY(0x1002793c, "RS600 HDMI", patch_atihdmi), -HDA_CODEC_ENTRY(0x10027919, "RS600 HDMI", patch_atihdmi), -HDA_CODEC_ENTRY(0x1002791a, "RS690/780 HDMI", patch_atihdmi), -HDA_CODEC_ENTRY(0x1002aa01, "R6xx HDMI", patch_atihdmi), -{} /* terminator */ + HDA_CODEC_ID(0x1002793c, "RS600 HDMI"), + HDA_CODEC_ID(0x10027919, "RS600 HDMI"), + HDA_CODEC_ID(0x1002791a, "RS690/780 HDMI"), + HDA_CODEC_ID(0x1002aa01, "R6xx HDMI"), + {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_atihdmi); @@ -601,6 +609,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI"); static struct hda_codec_driver atihdmi_driver = { .id = snd_hda_id_atihdmi, + .ops = &atihdmi_codec_ops, }; module_hda_codec_driver(atihdmi_driver); diff --git a/sound/hda/codecs/hdmi/hdmi.c b/sound/hda/codecs/hdmi/hdmi.c index 85aaa454072f..b5d840d9892b 100644 --- a/sound/hda/codecs/hdmi/hdmi.c +++ b/sound/hda/codecs/hdmi/hdmi.c @@ -2087,7 +2087,7 @@ void snd_hda_hdmi_generic_spec_free(struct hda_codec *codec) } EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_spec_free, "SND_HDA_CODEC_HDMI"); -void snd_hda_hdmi_generic_free(struct hda_codec *codec) +void snd_hda_hdmi_generic_remove(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; int pin_idx, pcm_idx; @@ -2113,7 +2113,7 @@ void snd_hda_hdmi_generic_free(struct hda_codec *codec) snd_hda_hdmi_generic_spec_free(codec); } -EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_free, "SND_HDA_CODEC_HDMI"); +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_remove, "SND_HDA_CODEC_HDMI"); int snd_hda_hdmi_generic_suspend(struct hda_codec *codec) { @@ -2133,7 +2133,7 @@ int snd_hda_hdmi_generic_resume(struct hda_codec *codec) struct hdmi_spec *spec = codec->spec; int pin_idx; - codec->patch_ops.init(codec); + snd_hda_codec_init(codec); snd_hda_regmap_sync(codec); for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { @@ -2144,16 +2144,6 @@ int snd_hda_hdmi_generic_resume(struct hda_codec *codec) } EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_resume, "SND_HDA_CODEC_HDMI"); -static const struct hda_codec_ops generic_hdmi_patch_ops = { - .init = snd_hda_hdmi_generic_init, - .free = snd_hda_hdmi_generic_free, - .build_pcms = snd_hda_hdmi_generic_build_pcms, - .build_controls = snd_hda_hdmi_generic_build_controls, - .unsol_event = snd_hda_hdmi_generic_unsol_event, - .suspend = snd_hda_hdmi_generic_suspend, - .resume = snd_hda_hdmi_generic_resume, -}; - static const struct hdmi_ops generic_standard_hdmi_ops = { .pin_get_eld = hdmi_pin_get_eld, .pin_setup_infoframe = hdmi_pin_setup_infoframe, @@ -2185,14 +2175,12 @@ int snd_hda_hdmi_generic_alloc(struct hda_codec *codec) codec->spec = spec; hdmi_array_init(spec, 4); - codec->patch_ops = generic_hdmi_patch_ops; - return 0; } EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_alloc, "SND_HDA_CODEC_HDMI"); /* generic HDMI parser */ -int patch_generic_hdmi(struct hda_codec *codec) +int snd_hda_hdmi_generic_probe(struct hda_codec *codec) { int err; @@ -2209,7 +2197,7 @@ int patch_generic_hdmi(struct hda_codec *codec) snd_hda_hdmi_generic_init_per_pins(codec); return 0; } -EXPORT_SYMBOL_NS_GPL(patch_generic_hdmi, "SND_HDA_CODEC_HDMI"); +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_probe, "SND_HDA_CODEC_HDMI"); /* * generic audio component binding @@ -2346,65 +2334,83 @@ EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_acomp_init, "SND_HDA_CODEC_HDMI"); /* */ -static int patch_gf_hdmi(struct hda_codec *codec) +enum { + MODEL_GENERIC, + MODEL_GF, +}; + +static int generichdmi_probe(struct hda_codec *codec, + const struct hda_device_id *id) { int err; - err = patch_generic_hdmi(codec); - if (err) + err = snd_hda_hdmi_generic_probe(codec); + if (err < 0) return err; - /* * Glenfly GPUs have two codecs, stream switches from one codec to * another, need to do actual clean-ups in codec_cleanup_stream */ - codec->no_sticky_stream = 1; + if (id->driver_data == MODEL_GF) + codec->no_sticky_stream = 1; + return 0; } -/* - * patch entries - */ -static const struct hda_device_id snd_hda_id_hdmi[] = { -HDA_CODEC_ENTRY(0x00147a47, "Loongson HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x10951390, "SiI1390 HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x10951392, "SiI1392 HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x17e80047, "Chrontel HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x67663d82, "Arise 82 HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x67663d83, "Arise 83 HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x67663d84, "Arise 84 HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x67663d85, "Arise 85 HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x67663d86, "Arise 86 HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x67663d87, "Arise 87 HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x11069f85, "VX11 HDMI/DP", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x1d179f86, "ZX-100S HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x1d179f87, "ZX-100S HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x1d179f88, "KX-5000 HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x1d179f89, "KX-5000 HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x1d179f8a, "KX-6000 HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x1d179f8b, "KX-6000 HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x1d179f8c, "KX-6000G HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x1d179f8d, "KX-6000G HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x1d179f8e, "KX-7000 HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x1d179f8f, "KX-7000 HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x1d179f90, "KX-7000 HDMI/DP", patch_gf_hdmi), -HDA_CODEC_ENTRY(0x80862801, "Bearlake HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x80862802, "Cantiga HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x80862803, "Eaglelake HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x808629fb, "Crestline HDMI", patch_generic_hdmi), -/* special ID for generic HDMI */ -HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC_HDMI, "Generic HDMI", patch_generic_hdmi), -{} /* terminator */ +static const struct hda_codec_ops generichdmi_codec_ops = { + .probe = generichdmi_probe, + .remove = snd_hda_hdmi_generic_remove, + .init = snd_hda_hdmi_generic_init, + .build_pcms = snd_hda_hdmi_generic_build_pcms, + .build_controls = snd_hda_hdmi_generic_build_controls, + .unsol_event = snd_hda_hdmi_generic_unsol_event, + .suspend = snd_hda_hdmi_generic_suspend, + .resume = snd_hda_hdmi_generic_resume, }; -MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_hdmi); + +/* + */ +static const struct hda_device_id snd_hda_id_generichdmi[] = { + HDA_CODEC_ID_MODEL(0x00147a47, "Loongson HDMI", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10951390, "SiI1390 HDMI", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10951392, "SiI1392 HDMI", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x11069f84, "VX11 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x11069f85, "VX11 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x17e80047, "Chrontel HDMI", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x1d179f86, "ZX-100S HDMI/DP", MODEL_GF), + HDA_CODEC_ID_MODEL(0x1d179f87, "ZX-100S HDMI/DP", MODEL_GF), + HDA_CODEC_ID_MODEL(0x1d179f88, "KX-5000 HDMI/DP", MODEL_GF), + HDA_CODEC_ID_MODEL(0x1d179f89, "KX-5000 HDMI/DP", MODEL_GF), + HDA_CODEC_ID_MODEL(0x1d179f8a, "KX-6000 HDMI/DP", MODEL_GF), + HDA_CODEC_ID_MODEL(0x1d179f8b, "KX-6000 HDMI/DP", MODEL_GF), + HDA_CODEC_ID_MODEL(0x1d179f8c, "KX-6000G HDMI/DP", MODEL_GF), + HDA_CODEC_ID_MODEL(0x1d179f8d, "KX-6000G HDMI/DP", MODEL_GF), + HDA_CODEC_ID_MODEL(0x1d179f8e, "KX-7000 HDMI/DP", MODEL_GF), + HDA_CODEC_ID_MODEL(0x1d179f8f, "KX-7000 HDMI/DP", MODEL_GF), + HDA_CODEC_ID_MODEL(0x1d179f90, "KX-7000 HDMI/DP", MODEL_GF), + HDA_CODEC_ID_MODEL(0x67663d82, "Arise 82 HDMI/DP", MODEL_GF), + HDA_CODEC_ID_MODEL(0x67663d83, "Arise 83 HDMI/DP", MODEL_GF), + HDA_CODEC_ID_MODEL(0x67663d84, "Arise 84 HDMI/DP", MODEL_GF), + HDA_CODEC_ID_MODEL(0x67663d85, "Arise 85 HDMI/DP", MODEL_GF), + HDA_CODEC_ID_MODEL(0x67663d86, "Arise 86 HDMI/DP", MODEL_GF), + HDA_CODEC_ID_MODEL(0x67663d87, "Arise 87 HDMI/DP", MODEL_GF), + HDA_CODEC_ID_MODEL(0x80862801, "Bearlake HDMI", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x80862802, "Cantiga HDMI", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x80862803, "Eaglelake HDMI", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x80862880, "CedarTrail HDMI", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x808629fb, "Crestline HDMI", MODEL_GENERIC), + /* special ID for generic HDMI */ + HDA_CODEC_ID_MODEL(HDA_CODEC_ID_GENERIC_HDMI, "Generic HDMI", MODEL_GENERIC), + {} /* terminator */ +}; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_generichdmi); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("HDMI HD-audio codec"); +MODULE_DESCRIPTION("Generic HDMI HD-audio codec"); -static struct hda_codec_driver hdmi_driver = { - .id = snd_hda_id_hdmi, +static struct hda_codec_driver generichdmi_driver = { + .id = snd_hda_id_generichdmi, + .ops = &generichdmi_codec_ops, }; -module_hda_codec_driver(hdmi_driver); +module_hda_codec_driver(generichdmi_driver); diff --git a/sound/hda/codecs/hdmi/hdmi_local.h b/sound/hda/codecs/hdmi/hdmi_local.h index 96351bebbc1b..0654013f1fda 100644 --- a/sound/hda/codecs/hdmi/hdmi_local.h +++ b/sound/hda/codecs/hdmi/hdmi_local.h @@ -237,8 +237,8 @@ union audio_infoframe { /* Generic HDMI codec support */ int snd_hda_hdmi_generic_alloc(struct hda_codec *codec); int snd_hda_hdmi_parse_codec(struct hda_codec *codec); -int patch_generic_hdmi(struct hda_codec *codec); -void snd_hda_hdmi_generic_free(struct hda_codec *codec); +int snd_hda_hdmi_generic_probe(struct hda_codec *codec); +void snd_hda_hdmi_generic_remove(struct hda_codec *codec); int snd_hda_hdmi_generic_build_pcms(struct hda_codec *codec); int snd_hda_hdmi_generic_build_controls(struct hda_codec *codec); @@ -286,9 +286,9 @@ void snd_hda_hdmi_acomp_master_unbind(struct device *dev, struct drm_audio_component *acomp); /* Simple / legacy HDMI codec support */ -int patch_simple_hdmi(struct hda_codec *codec, - hda_nid_t cvt_nid, hda_nid_t pin_nid); -void snd_hda_hdmi_simple_free(struct hda_codec *codec); +int snd_hda_hdmi_simple_probe(struct hda_codec *codec, + hda_nid_t cvt_nid, hda_nid_t pin_nid); +void snd_hda_hdmi_simple_remove(struct hda_codec *codec); int snd_hda_hdmi_simple_build_pcms(struct hda_codec *codec); int snd_hda_hdmi_simple_build_controls(struct hda_codec *codec); diff --git a/sound/hda/codecs/hdmi/intelhdmi.c b/sound/hda/codecs/hdmi/intelhdmi.c index a88ac1f80db6..23237d527430 100644 --- a/sound/hda/codecs/hdmi/intelhdmi.c +++ b/sound/hda/codecs/hdmi/intelhdmi.c @@ -18,6 +18,16 @@ IS_ENABLED(CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM); module_param(enable_silent_stream, bool, 0644); MODULE_PARM_DESC(enable_silent_stream, "Enable Silent Stream for HDMI devices"); +enum { + MODEL_HSW, + MODEL_GLK, + MODEL_ICL, + MODEL_TGL, + MODEL_ADLP, + MODEL_BYT, + MODEL_CPT, +}; + #define INTEL_GET_VENDOR_VERB 0xf81 #define INTEL_SET_VENDOR_VERB 0x781 #define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ @@ -67,9 +77,12 @@ static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec) static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg, unsigned int power_state) { - if (power_state == AC_PWRST_D0) { - intel_haswell_enable_all_pins(codec, false); - intel_haswell_fixup_enable_dp12(codec); + /* check codec->spec: it can be called before the probe gets called */ + if (codec->spec) { + if (power_state == AC_PWRST_D0) { + intel_haswell_enable_all_pins(codec, false); + intel_haswell_fixup_enable_dp12(codec); + } } snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state); @@ -456,13 +469,15 @@ static void i915_pin_cvt_fixup(struct hda_codec *codec, } } -static int i915_adlp_hdmi_suspend(struct hda_codec *codec) +static int i915_hdmi_suspend(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; bool silent_streams = false; int pin_idx, res; res = snd_hda_hdmi_generic_suspend(codec); + if (spec->silent_stream_type != SILENT_STREAM_KAE) + return res; for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); @@ -495,12 +510,14 @@ static int i915_adlp_hdmi_suspend(struct hda_codec *codec) return res; } -static int i915_adlp_hdmi_resume(struct hda_codec *codec) +static int i915_hdmi_resume(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; int pin_idx, res; res = snd_hda_hdmi_generic_resume(codec); + if (spec->silent_stream_type != SILENT_STREAM_KAE) + return res; /* KAE not programmed at suspend, nothing to do here */ if (!codec->no_stream_clean_at_suspend) @@ -539,8 +556,6 @@ static int i915_adlp_hdmi_resume(struct hda_codec *codec) /* precondition and allocation for Intel codecs */ static int alloc_intel_hdmi(struct hda_codec *codec) { - int err; - /* requires i915 binding */ if (!codec->bus->core.audio_component) { codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n"); @@ -549,12 +564,7 @@ static int alloc_intel_hdmi(struct hda_codec *codec) return -ENODEV; } - err = snd_hda_hdmi_generic_alloc(codec); - if (err < 0) - return err; - /* no need to handle unsol events */ - codec->patch_ops.unsol_event = NULL; - return 0; + return snd_hda_hdmi_generic_alloc(codec); } /* parse and post-process for Intel codecs */ @@ -580,11 +590,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid, bool send_silent_stream) { struct hdmi_spec *spec; - int err; - err = alloc_intel_hdmi(codec); - if (err < 0) - return err; spec = codec->spec; codec->dp_mst = true; spec->vendor_nid = vendor_nid; @@ -598,7 +604,6 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid, codec->display_power_control = 1; - codec->patch_ops.set_power_state = haswell_set_power_state; codec->depop_delay = 0; codec->auto_runtime_pm = 1; @@ -616,13 +621,13 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid, return parse_intel_hdmi(codec); } -static int patch_i915_hsw_hdmi(struct hda_codec *codec) +static int probe_i915_hsw_hdmi(struct hda_codec *codec) { return intel_hsw_common_init(codec, 0x08, NULL, 0, 3, enable_silent_stream); } -static int patch_i915_glk_hdmi(struct hda_codec *codec) +static int probe_i915_glk_hdmi(struct hda_codec *codec) { /* * Silent stream calls audio component .get_power() from @@ -632,7 +637,7 @@ static int patch_i915_glk_hdmi(struct hda_codec *codec) return intel_hsw_common_init(codec, 0x0b, NULL, 0, 3, false); } -static int patch_i915_icl_hdmi(struct hda_codec *codec) +static int probe_i915_icl_hdmi(struct hda_codec *codec) { /* * pin to port mapping table where the value indicate the pin number and @@ -644,7 +649,7 @@ static int patch_i915_icl_hdmi(struct hda_codec *codec) enable_silent_stream); } -static int patch_i915_tgl_hdmi(struct hda_codec *codec) +static int probe_i915_tgl_hdmi(struct hda_codec *codec) { /* * pin to port mapping table where the value indicate the pin number and @@ -656,35 +661,27 @@ static int patch_i915_tgl_hdmi(struct hda_codec *codec) enable_silent_stream); } -static int patch_i915_adlp_hdmi(struct hda_codec *codec) +static int probe_i915_adlp_hdmi(struct hda_codec *codec) { struct hdmi_spec *spec; int res; - res = patch_i915_tgl_hdmi(codec); + res = probe_i915_tgl_hdmi(codec); if (!res) { spec = codec->spec; - if (spec->silent_stream_type) { + if (spec->silent_stream_type) spec->silent_stream_type = SILENT_STREAM_KAE; - - codec->patch_ops.resume = i915_adlp_hdmi_resume; - codec->patch_ops.suspend = i915_adlp_hdmi_suspend; - } } return res; } /* Intel Baytrail and Braswell; with eld notifier */ -static int patch_i915_byt_hdmi(struct hda_codec *codec) +static int probe_i915_byt_hdmi(struct hda_codec *codec) { struct hdmi_spec *spec; - int err; - err = alloc_intel_hdmi(codec); - if (err < 0) - return err; spec = codec->spec; /* For Valleyview/Cherryview, only the display codec is in the display @@ -701,51 +698,104 @@ static int patch_i915_byt_hdmi(struct hda_codec *codec) } /* Intel IronLake, SandyBridge and IvyBridge; with eld notifier */ -static int patch_i915_cpt_hdmi(struct hda_codec *codec) +static int probe_i915_cpt_hdmi(struct hda_codec *codec) +{ + return parse_intel_hdmi(codec); +} + +/* + * common driver probe + */ +static int intelhdmi_probe(struct hda_codec *codec, const struct hda_device_id *id) { int err; err = alloc_intel_hdmi(codec); if (err < 0) return err; - return parse_intel_hdmi(codec); + + switch (id->driver_data) { + case MODEL_HSW: + err = probe_i915_hsw_hdmi(codec); + break; + case MODEL_GLK: + err = probe_i915_glk_hdmi(codec); + break; + case MODEL_ICL: + err = probe_i915_icl_hdmi(codec); + break; + case MODEL_TGL: + err = probe_i915_tgl_hdmi(codec); + break; + case MODEL_ADLP: + err = probe_i915_adlp_hdmi(codec); + break; + case MODEL_BYT: + err = probe_i915_byt_hdmi(codec); + break; + case MODEL_CPT: + err = probe_i915_cpt_hdmi(codec); + break; + default: + err = -EINVAL; + break; + } + + if (err < 0) { + snd_hda_hdmi_generic_spec_free(codec); + return err; + } + + return 0; } +static const struct hda_codec_ops intelhdmi_codec_ops = { + .probe = intelhdmi_probe, + .remove = snd_hda_hdmi_generic_remove, + .init = snd_hda_hdmi_generic_init, + .build_pcms = snd_hda_hdmi_generic_build_pcms, + .build_controls = snd_hda_hdmi_generic_build_controls, + .unsol_event = snd_hda_hdmi_generic_unsol_event, + .suspend = i915_hdmi_suspend, + .resume = i915_hdmi_resume, + .set_power_state = haswell_set_power_state, +}; + /* * driver entries */ static const struct hda_device_id snd_hda_id_intelhdmi[] = { -HDA_CODEC_ENTRY(0x80860054, "IbexPeak HDMI", patch_i915_cpt_hdmi), -HDA_CODEC_ENTRY(0x80862800, "Geminilake HDMI", patch_i915_glk_hdmi), -HDA_CODEC_ENTRY(0x80862804, "IbexPeak HDMI", patch_i915_cpt_hdmi), -HDA_CODEC_ENTRY(0x80862805, "CougarPoint HDMI", patch_i915_cpt_hdmi), -HDA_CODEC_ENTRY(0x80862806, "PantherPoint HDMI", patch_i915_cpt_hdmi), -HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI", patch_i915_hsw_hdmi), -HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_i915_hsw_hdmi), -HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_i915_hsw_hdmi), -HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_i915_hsw_hdmi), -HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_i915_hsw_hdmi), -HDA_CODEC_ENTRY(0x8086280c, "Cannonlake HDMI", patch_i915_glk_hdmi), -HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_glk_hdmi), -HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI", patch_i915_icl_hdmi), -HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI", patch_i915_tgl_hdmi), -HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI", patch_i915_tgl_hdmi), -HDA_CODEC_ENTRY(0x80862815, "Alderlake HDMI", patch_i915_tgl_hdmi), -HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI", patch_i915_tgl_hdmi), -HDA_CODEC_ENTRY(0x80862818, "Raptorlake HDMI", patch_i915_tgl_hdmi), -HDA_CODEC_ENTRY(0x80862819, "DG2 HDMI", patch_i915_tgl_hdmi), -HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi), -HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI", patch_i915_icl_hdmi), -HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_adlp_hdmi), -HDA_CODEC_ENTRY(0x8086281d, "Meteor Lake HDMI", patch_i915_adlp_hdmi), -HDA_CODEC_ENTRY(0x8086281e, "Battlemage HDMI", patch_i915_adlp_hdmi), -HDA_CODEC_ENTRY(0x8086281f, "Raptor Lake P HDMI", patch_i915_adlp_hdmi), -HDA_CODEC_ENTRY(0x80862820, "Lunar Lake HDMI", patch_i915_adlp_hdmi), -HDA_CODEC_ENTRY(0x80862822, "Panther Lake HDMI", patch_i915_adlp_hdmi), -HDA_CODEC_ENTRY(0x80862823, "Wildcat Lake HDMI", patch_i915_adlp_hdmi), -HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi), -HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi), -{} /* terminator */ + HDA_CODEC_ID_MODEL(0x80860054, "IbexPeak HDMI", MODEL_CPT), + HDA_CODEC_ID_MODEL(0x80862800, "Geminilake HDMI", MODEL_GLK), + HDA_CODEC_ID_MODEL(0x80862804, "IbexPeak HDMI", MODEL_CPT), + HDA_CODEC_ID_MODEL(0x80862805, "CougarPoint HDMI", MODEL_CPT), + HDA_CODEC_ID_MODEL(0x80862806, "PantherPoint HDMI", MODEL_CPT), + HDA_CODEC_ID_MODEL(0x80862807, "Haswell HDMI", MODEL_HSW), + HDA_CODEC_ID_MODEL(0x80862808, "Broadwell HDMI", MODEL_HSW), + HDA_CODEC_ID_MODEL(0x80862809, "Skylake HDMI", MODEL_HSW), + HDA_CODEC_ID_MODEL(0x8086280a, "Broxton HDMI", MODEL_HSW), + HDA_CODEC_ID_MODEL(0x8086280b, "Kabylake HDMI", MODEL_HSW), + HDA_CODEC_ID_MODEL(0x8086280c, "Cannonlake HDMI", MODEL_GLK), + HDA_CODEC_ID_MODEL(0x8086280d, "Geminilake HDMI", MODEL_GLK), + HDA_CODEC_ID_MODEL(0x8086280f, "Icelake HDMI", MODEL_ICL), + HDA_CODEC_ID_MODEL(0x80862812, "Tigerlake HDMI", MODEL_TGL), + HDA_CODEC_ID_MODEL(0x80862814, "DG1 HDMI", MODEL_TGL), + HDA_CODEC_ID_MODEL(0x80862815, "Alderlake HDMI", MODEL_TGL), + HDA_CODEC_ID_MODEL(0x80862816, "Rocketlake HDMI", MODEL_TGL), + HDA_CODEC_ID_MODEL(0x80862818, "Raptorlake HDMI", MODEL_TGL), + HDA_CODEC_ID_MODEL(0x80862819, "DG2 HDMI", MODEL_TGL), + HDA_CODEC_ID_MODEL(0x8086281a, "Jasperlake HDMI", MODEL_ICL), + HDA_CODEC_ID_MODEL(0x8086281b, "Elkhartlake HDMI", MODEL_ICL), + HDA_CODEC_ID_MODEL(0x8086281c, "Alderlake-P HDMI", MODEL_ADLP), + HDA_CODEC_ID_MODEL(0x8086281d, "Meteor Lake HDMI", MODEL_ADLP), + HDA_CODEC_ID_MODEL(0x8086281e, "Battlemage HDMI", MODEL_ADLP), + HDA_CODEC_ID_MODEL(0x8086281f, "Raptor Lake P HDMI", MODEL_ADLP), + HDA_CODEC_ID_MODEL(0x80862820, "Lunar Lake HDMI", MODEL_ADLP), + HDA_CODEC_ID_MODEL(0x80862822, "Panther Lake HDMI", MODEL_ADLP), + HDA_CODEC_ID_MODEL(0x80862823, "Wildcat Lake HDMI", MODEL_ADLP), + HDA_CODEC_ID_MODEL(0x80862882, "Valleyview2 HDMI", MODEL_BYT), + HDA_CODEC_ID_MODEL(0x80862883, "Braswell HDMI", MODEL_BYT), + {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_intelhdmi); @@ -755,6 +805,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI"); static struct hda_codec_driver intelhdmi_driver = { .id = snd_hda_id_intelhdmi, + .ops = &intelhdmi_codec_ops, }; module_hda_codec_driver(intelhdmi_driver); diff --git a/sound/hda/codecs/hdmi/nvhdmi-mcp.c b/sound/hda/codecs/hdmi/nvhdmi-mcp.c index 67e187a351d7..fbcea6d1850e 100644 --- a/sound/hda/codecs/hdmi/nvhdmi-mcp.c +++ b/sound/hda/codecs/hdmi/nvhdmi-mcp.c @@ -12,6 +12,8 @@ #include "hda_local.h" #include "hdmi_local.h" +enum { MODEL_2CH, MODEL_8CH }; + #define Nv_VERB_SET_Channel_Allocation 0xF79 #define Nv_VERB_SET_Info_Frame_Checksum 0xF7A #define Nv_VERB_SET_Audio_Protection_On 0xF98 @@ -45,15 +47,14 @@ static const struct hda_verb nvhdmi_basic_init_7x_8ch[] = { {} /* terminator */ }; -static int nvhdmi_7x_init_2ch(struct hda_codec *codec) +static int nvhdmi_mcp_init(struct hda_codec *codec) { - snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_2ch); - return 0; -} + struct hdmi_spec *spec = codec->spec; -static int nvhdmi_7x_init_8ch(struct hda_codec *codec) -{ - snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_8ch); + if (spec->multiout.max_channels == 2) + snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_2ch); + else + snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_8ch); return 0; } @@ -233,31 +234,13 @@ static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = { }, }; -static int patch_nvhdmi_2ch(struct hda_codec *codec) -{ - struct hdmi_spec *spec; - int err = patch_simple_hdmi(codec, nvhdmi_master_con_nid_7x, - nvhdmi_master_pin_nid_7x); - if (err < 0) - return err; - - codec->patch_ops.init = nvhdmi_7x_init_2ch; - /* override the PCM rates, etc, as the codec doesn't give full list */ - spec = codec->spec; - spec->pcm_playback.rates = SUPPORTED_RATES; - spec->pcm_playback.maxbps = SUPPORTED_MAXBPS; - spec->pcm_playback.formats = SUPPORTED_FORMATS; - spec->nv_dp_workaround = true; - return 0; -} - -static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec) +static int nvhdmi_mcp_build_pcms(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; int err; err = snd_hda_hdmi_simple_build_pcms(codec); - if (!err) { + if (!err && spec->multiout.max_channels == 8) { struct hda_pcm *info = get_pcm_rec(spec, 0); info->own_chmap = true; @@ -265,7 +248,7 @@ static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec) return err; } -static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec) +static int nvhdmi_mcp_build_controls(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; struct hda_pcm *info; @@ -276,6 +259,9 @@ static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec) if (err < 0) return err; + if (spec->multiout.max_channels != 8) + return 0; + /* add channel maps */ info = get_pcm_rec(spec, 0); err = snd_pcm_add_chmap_ctls(info->pcm, @@ -316,20 +302,29 @@ static const struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = { .mask = 0, }; -static int patch_nvhdmi_8ch_7x(struct hda_codec *codec) +static int nvhdmi_mcp_probe(struct hda_codec *codec, + const struct hda_device_id *id) { struct hdmi_spec *spec; int err; - err = patch_nvhdmi_2ch(codec); + err = snd_hda_hdmi_simple_probe(codec, nvhdmi_master_con_nid_7x, + nvhdmi_master_pin_nid_7x); if (err < 0) return err; + + /* override the PCM rates, etc, as the codec doesn't give full list */ spec = codec->spec; + spec->pcm_playback.rates = SUPPORTED_RATES; + spec->pcm_playback.maxbps = SUPPORTED_MAXBPS; + spec->pcm_playback.formats = SUPPORTED_FORMATS; + spec->nv_dp_workaround = true; + + if (id->driver_data == MODEL_2CH) + return 0; + spec->multiout.max_channels = 8; spec->pcm_playback = nvhdmi_pcm_playback_8ch_7x; - codec->patch_ops.init = nvhdmi_7x_init_8ch; - codec->patch_ops.build_pcms = nvhdmi_7x_8ch_build_pcms; - codec->patch_ops.build_controls = nvhdmi_7x_8ch_build_controls; switch (codec->preset->vendor_id) { case 0x10de0002: @@ -353,21 +348,27 @@ static int patch_nvhdmi_8ch_7x(struct hda_codec *codec) return 0; } -/* - * patch entries - */ +static const struct hda_codec_ops nvhdmi_mcp_codec_ops = { + .probe = nvhdmi_mcp_probe, + .remove = snd_hda_hdmi_simple_remove, + .build_controls = nvhdmi_mcp_build_pcms, + .build_pcms = nvhdmi_mcp_build_controls, + .init = nvhdmi_mcp_init, + .unsol_event = snd_hda_hdmi_simple_unsol_event, +}; + static const struct hda_device_id snd_hda_id_nvhdmi_mcp[] = { -HDA_CODEC_ENTRY(0x10de0001, "MCP73 HDMI", patch_nvhdmi_2ch), -HDA_CODEC_ENTRY(0x10de0002, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), -HDA_CODEC_ENTRY(0x10de0003, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), -HDA_CODEC_ENTRY(0x10de0004, "GPU 04 HDMI", patch_nvhdmi_8ch_7x), -HDA_CODEC_ENTRY(0x10de0005, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), -HDA_CODEC_ENTRY(0x10de0006, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), -HDA_CODEC_ENTRY(0x10de0007, "MCP79/7A HDMI", patch_nvhdmi_8ch_7x), -HDA_CODEC_ENTRY(0x10de0067, "MCP67 HDMI", patch_nvhdmi_2ch), -HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI", patch_nvhdmi_2ch), -HDA_CODEC_ENTRY(0x10de8067, "MCP67/68 HDMI", patch_nvhdmi_2ch), -{} /* terminator */ + HDA_CODEC_ID_MODEL(0x10de0001, "MCP73 HDMI", MODEL_2CH), + HDA_CODEC_ID_MODEL(0x10de0002, "MCP77/78 HDMI", MODEL_8CH), + HDA_CODEC_ID_MODEL(0x10de0003, "MCP77/78 HDMI", MODEL_8CH), + HDA_CODEC_ID_MODEL(0x10de0004, "GPU 04 HDMI", MODEL_8CH), + HDA_CODEC_ID_MODEL(0x10de0005, "MCP77/78 HDMI", MODEL_8CH), + HDA_CODEC_ID_MODEL(0x10de0006, "MCP77/78 HDMI", MODEL_8CH), + HDA_CODEC_ID_MODEL(0x10de0007, "MCP79/7A HDMI", MODEL_8CH), + HDA_CODEC_ID_MODEL(0x10de0067, "MCP67 HDMI", MODEL_2CH), + HDA_CODEC_ID_MODEL(0x10de8001, "MCP73 HDMI", MODEL_2CH), + HDA_CODEC_ID_MODEL(0x10de8067, "MCP67/68 HDMI", MODEL_2CH), + {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_nvhdmi_mcp); @@ -377,6 +378,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI"); static struct hda_codec_driver nvhdmi_mcp_driver = { .id = snd_hda_id_nvhdmi_mcp, + .ops = &nvhdmi_mcp_codec_ops, }; module_hda_codec_driver(nvhdmi_mcp_driver); diff --git a/sound/hda/codecs/hdmi/nvhdmi.c b/sound/hda/codecs/hdmi/nvhdmi.c index 2add5f59daf5..b513253b1101 100644 --- a/sound/hda/codecs/hdmi/nvhdmi.c +++ b/sound/hda/codecs/hdmi/nvhdmi.c @@ -13,6 +13,11 @@ #include "hda_local.h" #include "hdmi_local.h" +enum { + MODEL_GENERIC, + MODEL_LEGACY, +}; + /* * NVIDIA codecs ignore ASP mapping for 2ch - confirmed on: * - 0x10de0015 @@ -61,7 +66,7 @@ static const struct drm_audio_component_audio_ops nvhdmi_audio_ops = { .master_unbind = snd_hda_hdmi_acomp_master_unbind, }; -static int patch_nvhdmi(struct hda_codec *codec) +static int probe_generic(struct hda_codec *codec) { struct hdmi_spec *spec; int err; @@ -95,12 +100,12 @@ static int patch_nvhdmi(struct hda_codec *codec) return 0; } -static int patch_nvhdmi_legacy(struct hda_codec *codec) +static int probe_legacy(struct hda_codec *codec) { struct hdmi_spec *spec; int err; - err = patch_generic_hdmi(codec); + err = snd_hda_hdmi_generic_probe(codec); if (err) return err; @@ -117,93 +122,92 @@ static int patch_nvhdmi_legacy(struct hda_codec *codec) return 0; } -/* - * patch entries - */ +static int nvhdmi_probe(struct hda_codec *codec, const struct hda_device_id *id) +{ + if (id->driver_data == MODEL_LEGACY) + return probe_legacy(codec); + else + return probe_generic(codec); +} + +static const struct hda_codec_ops nvhdmi_codec_ops = { + .probe = nvhdmi_probe, + .remove = snd_hda_hdmi_generic_remove, + .init = snd_hda_hdmi_generic_init, + .build_pcms = snd_hda_hdmi_generic_build_pcms, + .build_controls = snd_hda_hdmi_generic_build_controls, + .unsol_event = snd_hda_hdmi_generic_unsol_event, + .suspend = snd_hda_hdmi_generic_suspend, + .resume = snd_hda_hdmi_generic_resume, +}; + static const struct hda_device_id snd_hda_id_nvhdmi[] = { -HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de000d, "GPU 0d HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0010, "GPU 10 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0011, "GPU 11 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0012, "GPU 12 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0013, "GPU 13 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0014, "GPU 14 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0015, "GPU 15 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0016, "GPU 16 HDMI/DP", patch_nvhdmi_legacy), -/* 17 is known to be absent */ -HDA_CODEC_ENTRY(0x10de0018, "GPU 18 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0019, "GPU 19 HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de001a, "GPU 1a HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de001b, "GPU 1b HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de001c, "GPU 1c HDMI/DP", patch_nvhdmi_legacy), -HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0043, "GPU 43 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0044, "GPU 44 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0045, "GPU 45 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0050, "GPU 50 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0051, "GPU 51 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0052, "GPU 52 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0060, "GPU 60 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0061, "GPU 61 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0062, "GPU 62 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0073, "GPU 73 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0074, "GPU 74 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0076, "GPU 76 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de007b, "GPU 7b HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de007c, "GPU 7c HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de007e, "GPU 7e HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0081, "GPU 81 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0084, "GPU 84 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0090, "GPU 90 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0091, "GPU 91 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0092, "GPU 92 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0093, "GPU 93 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0094, "GPU 94 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0095, "GPU 95 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0097, "GPU 97 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0098, "GPU 98 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0099, "GPU 99 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de009a, "GPU 9a HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de009b, "GPU 9b HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de009c, "GPU 9c HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de009d, "GPU 9d HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de009e, "GPU 9e HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de009f, "GPU 9f HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00a0, "GPU a0 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00a1, "GPU a1 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00a3, "GPU a3 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00a4, "GPU a4 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00a5, "GPU a5 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00a6, "GPU a6 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00a7, "GPU a7 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00a8, "GPU a8 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00a9, "GPU a9 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00aa, "GPU aa HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00ab, "GPU ab HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00ad, "GPU ad HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00ae, "GPU ae HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00af, "GPU af HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00b0, "GPU b0 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00b1, "GPU b1 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00c0, "GPU c0 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00c1, "GPU c1 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00c3, "GPU c3 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00c4, "GPU c4 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de00c5, "GPU c5 HDMI/DP", patch_nvhdmi), -{} /* terminator */ + HDA_CODEC_ID_MODEL(0x10de0008, "GPU 08 HDMI/DP", MODEL_LEGACY), + HDA_CODEC_ID_MODEL(0x10de0009, "GPU 09 HDMI/DP", MODEL_LEGACY), + HDA_CODEC_ID_MODEL(0x10de000a, "GPU 0a HDMI/DP", MODEL_LEGACY), + HDA_CODEC_ID_MODEL(0x10de000b, "GPU 0b HDMI/DP", MODEL_LEGACY), + HDA_CODEC_ID_MODEL(0x10de000c, "MCP89 HDMI", MODEL_LEGACY), + HDA_CODEC_ID_MODEL(0x10de000d, "GPU 0d HDMI/DP", MODEL_LEGACY), + HDA_CODEC_ID_MODEL(0x10de0010, "GPU 10 HDMI/DP", MODEL_LEGACY), + HDA_CODEC_ID_MODEL(0x10de0011, "GPU 11 HDMI/DP", MODEL_LEGACY), + HDA_CODEC_ID_MODEL(0x10de0012, "GPU 12 HDMI/DP", MODEL_LEGACY), + HDA_CODEC_ID_MODEL(0x10de0013, "GPU 13 HDMI/DP", MODEL_LEGACY), + HDA_CODEC_ID_MODEL(0x10de0014, "GPU 14 HDMI/DP", MODEL_LEGACY), + HDA_CODEC_ID_MODEL(0x10de0015, "GPU 15 HDMI/DP", MODEL_LEGACY), + HDA_CODEC_ID_MODEL(0x10de0016, "GPU 16 HDMI/DP", MODEL_LEGACY), + /* 17 is known to be absent */ + HDA_CODEC_ID_MODEL(0x10de0018, "GPU 18 HDMI/DP", MODEL_LEGACY), + HDA_CODEC_ID_MODEL(0x10de0019, "GPU 19 HDMI/DP", MODEL_LEGACY), + HDA_CODEC_ID_MODEL(0x10de001a, "GPU 1a HDMI/DP", MODEL_LEGACY), + HDA_CODEC_ID_MODEL(0x10de001b, "GPU 1b HDMI/DP", MODEL_LEGACY), + HDA_CODEC_ID_MODEL(0x10de001c, "GPU 1c HDMI/DP", MODEL_LEGACY), + HDA_CODEC_ID_MODEL(0x10de0040, "GPU 40 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0041, "GPU 41 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0042, "GPU 42 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0043, "GPU 43 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0044, "GPU 44 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0045, "GPU 45 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0050, "GPU 50 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0051, "GPU 51 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0052, "GPU 52 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0060, "GPU 60 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0061, "GPU 61 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0062, "GPU 62 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0070, "GPU 70 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0071, "GPU 71 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0072, "GPU 72 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0073, "GPU 73 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0074, "GPU 74 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0076, "GPU 76 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de007b, "GPU 7b HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de007c, "GPU 7c HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de007d, "GPU 7d HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de007e, "GPU 7e HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0080, "GPU 80 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0081, "GPU 81 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0082, "GPU 82 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0083, "GPU 83 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0084, "GPU 84 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0090, "GPU 90 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0091, "GPU 91 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0092, "GPU 92 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0093, "GPU 93 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0094, "GPU 94 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0095, "GPU 95 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0097, "GPU 97 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0098, "GPU 98 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de0099, "GPU 99 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de009a, "GPU 9a HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de009d, "GPU 9d HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de009e, "GPU 9e HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de009f, "GPU 9f HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00a0, "GPU a0 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00a3, "GPU a3 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00a4, "GPU a4 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00a5, "GPU a5 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00a6, "GPU a6 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00a7, "GPU a7 HDMI/DP", MODEL_GENERIC), + {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_nvhdmi); @@ -213,6 +217,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI"); static struct hda_codec_driver nvhdmi_driver = { .id = snd_hda_id_nvhdmi, + .ops = &nvhdmi_codec_ops, }; module_hda_codec_driver(nvhdmi_driver); diff --git a/sound/hda/codecs/hdmi/simplehdmi.c b/sound/hda/codecs/hdmi/simplehdmi.c index 87ea997a6d3b..193c8dc882af 100644 --- a/sound/hda/codecs/hdmi/simplehdmi.c +++ b/sound/hda/codecs/hdmi/simplehdmi.c @@ -107,7 +107,7 @@ int snd_hda_hdmi_simple_init(struct hda_codec *codec) } EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_init, "SND_HDA_CODEC_HDMI"); -void snd_hda_hdmi_simple_free(struct hda_codec *codec) +void snd_hda_hdmi_simple_remove(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; @@ -115,7 +115,7 @@ void snd_hda_hdmi_simple_free(struct hda_codec *codec) snd_array_free(&spec->cvts); kfree(spec); } -EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_free, "SND_HDA_CODEC_HDMI"); +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_remove, "SND_HDA_CODEC_HDMI"); int snd_hda_hdmi_simple_pcm_open(struct hda_pcm_stream *hinfo, struct hda_codec *codec, @@ -168,16 +168,8 @@ static const struct hda_pcm_stream simple_pcm_playback = { }, }; -static const struct hda_codec_ops simple_hdmi_patch_ops = { - .build_controls = snd_hda_hdmi_simple_build_controls, - .build_pcms = snd_hda_hdmi_simple_build_pcms, - .init = snd_hda_hdmi_simple_init, - .free = snd_hda_hdmi_simple_free, - .unsol_event = snd_hda_hdmi_simple_unsol_event, -}; - -int patch_simple_hdmi(struct hda_codec *codec, - hda_nid_t cvt_nid, hda_nid_t pin_nid) +int snd_hda_hdmi_simple_probe(struct hda_codec *codec, + hda_nid_t cvt_nid, hda_nid_t pin_nid) { struct hdmi_spec *spec; struct hdmi_spec_per_cvt *per_cvt; @@ -200,35 +192,52 @@ int patch_simple_hdmi(struct hda_codec *codec, per_pin = snd_array_new(&spec->pins); per_cvt = snd_array_new(&spec->cvts); if (!per_pin || !per_cvt) { - snd_hda_hdmi_simple_free(codec); + snd_hda_hdmi_simple_remove(codec); return -ENOMEM; } per_cvt->cvt_nid = cvt_nid; per_pin->pin_nid = pin_nid; spec->pcm_playback = simple_pcm_playback; - codec->patch_ops = simple_hdmi_patch_ops; - return 0; } -EXPORT_SYMBOL_NS_GPL(patch_simple_hdmi, "SND_HDA_CODEC_HDMI"); +EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_probe, "SND_HDA_CODEC_HDMI"); + +/* + * driver entries + */ + +enum { MODEL_VIA }; /* VIA HDMI Implementation */ #define VIAHDMI_CVT_NID 0x02 /* audio converter1 */ #define VIAHDMI_PIN_NID 0x03 /* HDMI output pin1 */ -static int patch_via_hdmi(struct hda_codec *codec) +static int simplehdmi_probe(struct hda_codec *codec, + const struct hda_device_id *id) { - return patch_simple_hdmi(codec, VIAHDMI_CVT_NID, VIAHDMI_PIN_NID); + switch (id->driver_data) { + case MODEL_VIA: + return snd_hda_hdmi_simple_probe(codec, VIAHDMI_CVT_NID, + VIAHDMI_PIN_NID); + default: + return -EINVAL; + } } -/* - * patch entries - */ +static const struct hda_codec_ops simplehdmi_codec_ops = { + .probe = simplehdmi_probe, + .remove = snd_hda_hdmi_simple_remove, + .build_controls = snd_hda_hdmi_simple_build_controls, + .build_pcms = snd_hda_hdmi_simple_build_pcms, + .init = snd_hda_hdmi_simple_init, + .unsol_event = snd_hda_hdmi_simple_unsol_event, +}; + static const struct hda_device_id snd_hda_id_simplehdmi[] = { -HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP", patch_via_hdmi), -HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP", patch_via_hdmi), -{} /* terminator */ + HDA_CODEC_ID_MODEL(0x11069f80, "VX900 HDMI/DP", MODEL_VIA), + HDA_CODEC_ID_MODEL(0x11069f81, "VX900 HDMI/DP", MODEL_VIA), + {} /* terminator */ }; MODULE_LICENSE("GPL"); @@ -236,6 +245,7 @@ MODULE_DESCRIPTION("Simple HDMI HD-audio codec support"); static struct hda_codec_driver simplehdmi_driver = { .id = snd_hda_id_simplehdmi, + .ops = &simplehdmi_codec_ops, }; module_hda_codec_driver(simplehdmi_driver); diff --git a/sound/hda/codecs/hdmi/tegrahdmi.c b/sound/hda/codecs/hdmi/tegrahdmi.c index c13a63788799..f1f745187f68 100644 --- a/sound/hda/codecs/hdmi/tegrahdmi.c +++ b/sound/hda/codecs/hdmi/tegrahdmi.c @@ -13,6 +13,11 @@ #include "hda_local.h" #include "hdmi_local.h" +enum { + MODEL_TEGRA, + MODEL_TEGRA234, +}; + /* * The HDA codec on NVIDIA Tegra contains two scratch registers that are * accessed using vendor-defined verbs. These registers can be used for @@ -241,7 +246,6 @@ static int tegra_hdmi_init(struct hda_codec *codec) snd_hda_hdmi_generic_init_per_pins(codec); codec->depop_delay = 10; - codec->patch_ops.build_pcms = tegra_hdmi_build_pcms; spec->chmap.ops.chmap_cea_alloc_validate_get_type = nvhdmi_chmap_cea_alloc_validate_get_type; spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate; @@ -254,18 +258,8 @@ static int tegra_hdmi_init(struct hda_codec *codec) return 0; } -static int patch_tegra_hdmi(struct hda_codec *codec) -{ - int err; - - err = snd_hda_hdmi_generic_alloc(codec); - if (err < 0) - return err; - - return tegra_hdmi_init(codec); -} - -static int patch_tegra234_hdmi(struct hda_codec *codec) +static int tegrahdmi_probe(struct hda_codec *codec, + const struct hda_device_id *id) { struct hdmi_spec *spec; int err; @@ -274,31 +268,39 @@ static int patch_tegra234_hdmi(struct hda_codec *codec) if (err < 0) return err; - codec->dp_mst = true; - spec = codec->spec; - spec->dyn_pin_out = true; - spec->hdmi_intr_trig_ctrl = true; + if (id->driver_data == MODEL_TEGRA234) { + codec->dp_mst = true; + spec = codec->spec; + spec->dyn_pin_out = true; + spec->hdmi_intr_trig_ctrl = true; + } return tegra_hdmi_init(codec); } -/* - * patch entries - */ +static const struct hda_codec_ops tegrahdmi_codec_ops = { + .probe = tegrahdmi_probe, + .remove = snd_hda_hdmi_generic_remove, + .init = snd_hda_hdmi_generic_init, + .build_pcms = tegra_hdmi_build_pcms, + .build_controls = snd_hda_hdmi_generic_build_controls, + .unsol_event = snd_hda_hdmi_generic_unsol_event, + .suspend = snd_hda_hdmi_generic_suspend, + .resume = snd_hda_hdmi_generic_resume, +}; + static const struct hda_device_id snd_hda_id_tegrahdmi[] = { -HDA_CODEC_ENTRY(0x10de0020, "Tegra30 HDMI", patch_tegra_hdmi), -HDA_CODEC_ENTRY(0x10de0022, "Tegra114 HDMI", patch_tegra_hdmi), -HDA_CODEC_ENTRY(0x10de0028, "Tegra124 HDMI", patch_tegra_hdmi), -HDA_CODEC_ENTRY(0x10de0029, "Tegra210 HDMI/DP", patch_tegra_hdmi), -HDA_CODEC_ENTRY(0x10de002d, "Tegra186 HDMI/DP0", patch_tegra_hdmi), -HDA_CODEC_ENTRY(0x10de002e, "Tegra186 HDMI/DP1", patch_tegra_hdmi), -HDA_CODEC_ENTRY(0x10de002f, "Tegra194 HDMI/DP2", patch_tegra_hdmi), -HDA_CODEC_ENTRY(0x10de0030, "Tegra194 HDMI/DP3", patch_tegra_hdmi), -HDA_CODEC_ENTRY(0x10de0031, "Tegra234 HDMI/DP", patch_tegra234_hdmi), -HDA_CODEC_ENTRY(0x10de0033, "SoC 33 HDMI/DP", patch_tegra234_hdmi), -HDA_CODEC_ENTRY(0x10de0034, "Tegra264 HDMI/DP", patch_tegra234_hdmi), -HDA_CODEC_ENTRY(0x10de0035, "SoC 35 HDMI/DP", patch_tegra234_hdmi), -{} /* terminator */ + HDA_CODEC_ID_MODEL(0x10de0020, "Tegra30 HDMI", MODEL_TEGRA), + HDA_CODEC_ID_MODEL(0x10de0022, "Tegra114 HDMI", MODEL_TEGRA), + HDA_CODEC_ID_MODEL(0x10de0028, "Tegra124 HDMI", MODEL_TEGRA), + HDA_CODEC_ID_MODEL(0x10de0029, "Tegra210 HDMI/DP", MODEL_TEGRA), + HDA_CODEC_ID_MODEL(0x10de002d, "Tegra186 HDMI/DP0", MODEL_TEGRA), + HDA_CODEC_ID_MODEL(0x10de002e, "Tegra186 HDMI/DP1", MODEL_TEGRA), + HDA_CODEC_ID_MODEL(0x10de002f, "Tegra194 HDMI/DP2", MODEL_TEGRA), + HDA_CODEC_ID_MODEL(0x10de0030, "Tegra194 HDMI/DP3", MODEL_TEGRA), + HDA_CODEC_ID_MODEL(0x10de0031, "Tegra234 HDMI/DP", MODEL_TEGRA234), + HDA_CODEC_ID_MODEL(0x10de0034, "Tegra264 HDMI/DP", MODEL_TEGRA234), + {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_tegrahdmi); @@ -308,6 +310,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI"); static struct hda_codec_driver tegrahdmi_driver = { .id = snd_hda_id_tegrahdmi, + .ops = &tegrahdmi_codec_ops, }; module_hda_codec_driver(tegrahdmi_driver); From cabaf5908e586156d1d59f3fb8c51d2b169bc636 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:27 +0200 Subject: [PATCH 340/385] ALSA: hda: Drop old codec binding method Now that all patch_ops usage have been converted to the new hda_codec_ops probe, we can drop patch_ops from the hda_codec, together with the calls of patch_ops callbacks. The hda_codec_ops.free callback is removed as all have been replaced with the new remove callback. Also, correct comments mentioning "patch"; it's replaced with "codec driver". Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-25-tiwai@suse.de --- include/sound/hda_codec.h | 22 ++------------------- sound/hda/Makefile | 2 +- sound/hda/codecs/generic.c | 12 ------------ sound/hda/codecs/generic.h | 1 - sound/hda/codecs/hdmi/hdmi_local.h | 2 +- sound/hda/common/bind.c | 26 +++++++------------------ sound/hda/common/codec.c | 20 ++----------------- sound/hda/common/hda_local.h | 2 -- sound/soc/codecs/hda.c | 20 ++++--------------- sound/soc/codecs/hdac_hda.c | 31 +++++++++--------------------- 10 files changed, 26 insertions(+), 112 deletions(-) diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index a725ac48c20c..ddc9c392f93f 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -70,12 +70,8 @@ struct hda_bus { /* * codec preset - * - * Known codecs have the patch to build and set up the controls/PCMs - * better than the generic parser. */ -typedef int (*hda_codec_patch_t)(struct hda_codec *); - + #define HDA_CODEC_ID_SKIP_PROBE 0x00000001 #define HDA_CODEC_ID_GENERIC_HDMI 0x00000101 #define HDA_CODEC_ID_GENERIC 0x00000201 @@ -90,14 +86,6 @@ typedef int (*hda_codec_patch_t)(struct hda_codec *); #define HDA_CODEC_ID(_vid, _name) \ HDA_CODEC_ID_REV(_vid, 0, _name) -/* old macros for patch_ops -- to be deprecated */ -#define HDA_CODEC_REV_ENTRY(_vid, _rev, _name, _patch) \ - { .vendor_id = (_vid), .rev_id = (_rev), .name = (_name), \ - .api_version = HDA_DEV_LEGACY, \ - .driver_data = (unsigned long)(_patch) } -#define HDA_CODEC_ENTRY(_vid, _name, _patch) \ - HDA_CODEC_REV_ENTRY(_vid, 0, _name, _patch) - struct hda_codec_driver { struct hdac_driver core; const struct hda_device_id *id; @@ -116,14 +104,13 @@ void hda_codec_driver_unregister(struct hda_codec_driver *drv); module_driver(drv, hda_codec_driver_register, \ hda_codec_driver_unregister) -/* ops set by the preset patch */ +/* ops for hda codec driver */ struct hda_codec_ops { int (*probe)(struct hda_codec *codec, const struct hda_device_id *id); void (*remove)(struct hda_codec *codec); int (*build_controls)(struct hda_codec *codec); int (*build_pcms)(struct hda_codec *codec); int (*init)(struct hda_codec *codec); - void (*free)(struct hda_codec *codec); void (*unsol_event)(struct hda_codec *codec, unsigned int res); void (*set_power_state)(struct hda_codec *codec, hda_nid_t fg, unsigned int power_state); @@ -199,9 +186,6 @@ struct hda_codec { const struct hda_device_id *preset; const char *modelname; /* model name for preset */ - /* set by patch */ - struct hda_codec_ops patch_ops; - /* PCM to create, set by hda_codec_ops.build_pcms callback */ struct list_head pcm_list_head; refcount_t pcm_ref; @@ -500,8 +484,6 @@ int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid) if (driver->ops && driver->ops->check_power_status) return driver->ops->check_power_status(codec, nid); - else if (codec->patch_ops.check_power_status) - return codec->patch_ops.check_power_status(codec, nid); return 0; } diff --git a/sound/hda/Makefile b/sound/hda/Makefile index 31b9fbedaa77..d9a6def582ef 100644 --- a/sound/hda/Makefile +++ b/sound/hda/Makefile @@ -3,6 +3,6 @@ obj-y += core/ obj-$(CONFIG_SND_HDA) += common/ obj-$(CONFIG_SND_HDA) += codecs/ # this must be the last entry after codec drivers; -# otherwise the codec patches won't be hooked before the PCI probe +# otherwise the codec drivers won't be hooked before the PCI probe # when built in kernel obj-$(CONFIG_SND_HDA) += controllers/ diff --git a/sound/hda/codecs/generic.c b/sound/hda/codecs/generic.c index 82c31b93424c..044f1d0aeaea 100644 --- a/sound/hda/codecs/generic.c +++ b/sound/hda/codecs/generic.c @@ -5190,8 +5190,6 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, if (spec->power_down_unused || codec->power_save_node) { if (!codec->power_filter) codec->power_filter = snd_hda_gen_path_power_filter; - if (!codec->patch_ops.stream_pm) - codec->patch_ops.stream_pm = snd_hda_gen_stream_pm; } if (!spec->no_analog && spec->beep_nid) { @@ -6103,15 +6101,6 @@ EXPORT_SYMBOL_GPL(snd_hda_gen_check_power_status); * the generic codec support */ -static const struct hda_codec_ops generic_patch_ops = { - .build_controls = snd_hda_gen_build_controls, - .build_pcms = snd_hda_gen_build_pcms, - .init = snd_hda_gen_init, - .free = snd_hda_gen_free, - .unsol_event = snd_hda_jack_unsol_event, - .check_power_status = snd_hda_gen_check_power_status, -}; - static int snd_hda_gen_probe(struct hda_codec *codec, const struct hda_device_id *id) { @@ -6132,7 +6121,6 @@ static int snd_hda_gen_probe(struct hda_codec *codec, if (err < 0) goto error; - codec->patch_ops = generic_patch_ops; return 0; error: diff --git a/sound/hda/codecs/generic.h b/sound/hda/codecs/generic.h index 00a92fc55846..524591821f8c 100644 --- a/sound/hda/codecs/generic.h +++ b/sound/hda/codecs/generic.h @@ -312,7 +312,6 @@ int snd_hda_gen_spec_init(struct hda_gen_spec *spec); int snd_hda_gen_init(struct hda_codec *codec); void snd_hda_gen_remove(struct hda_codec *codec); -#define snd_hda_gen_free snd_hda_gen_remove int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path); struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx); diff --git a/sound/hda/codecs/hdmi/hdmi_local.h b/sound/hda/codecs/hdmi/hdmi_local.h index 0654013f1fda..548241ad3fa9 100644 --- a/sound/hda/codecs/hdmi/hdmi_local.h +++ b/sound/hda/codecs/hdmi/hdmi_local.h @@ -57,7 +57,7 @@ struct hdmi_spec_per_pin { #endif }; -/* operations used by generic code that can be overridden by patches */ +/* operations used by generic code that can be overridden by codec drivers */ struct hdmi_ops { int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid, int dev_id, unsigned char *buf, int *eld_size); diff --git a/sound/hda/common/bind.c b/sound/hda/common/bind.c index 56975178f533..f85c640dd54f 100644 --- a/sound/hda/common/bind.c +++ b/sound/hda/common/bind.c @@ -54,8 +54,6 @@ static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev) if (driver->ops && driver->ops->unsol_event) driver->ops->unsol_event(codec, ev); - else if (codec->patch_ops.unsol_event) - codec->patch_ops.unsol_event(codec, ev); } /** @@ -91,7 +89,6 @@ static int hda_codec_driver_probe(struct device *dev) struct hda_codec *codec = dev_to_hda_codec(dev); struct module *owner = dev->driver->owner; struct hda_codec_driver *driver = hda_codec_to_driver(codec); - hda_codec_patch_t patch; int err; if (codec->bus->core.ext_ops) { @@ -115,19 +112,14 @@ static int hda_codec_driver_probe(struct device *dev) goto error; } - if (driver->ops && driver->ops->probe) { - err = driver->ops->probe(codec, codec->preset); - if (err < 0) - goto error_module_put; - } else { - patch = (hda_codec_patch_t)codec->preset->driver_data; - if (patch) { - err = patch(codec); - if (err < 0) - goto error_module_put; - } + if (WARN_ON(!(driver->ops && driver->ops->probe))) { + err = -EINVAL; + goto error_module_put; } + err = driver->ops->probe(codec, codec->preset); + if (err < 0) + goto error_module_put; err = snd_hda_codec_build_pcms(codec); if (err < 0) goto error_module; @@ -148,8 +140,6 @@ static int hda_codec_driver_probe(struct device *dev) error_module: if (driver->ops && driver->ops->remove) driver->ops->remove(codec); - else if (codec->patch_ops.free) - codec->patch_ops.free(codec); error_module_put: module_put(owner); @@ -178,8 +168,6 @@ static int hda_codec_driver_remove(struct device *dev) if (driver->ops && driver->ops->remove) driver->ops->remove(codec); - else if (codec->patch_ops.free) - codec->patch_ops.free(codec); snd_hda_codec_cleanup_for_unbind(codec); codec->preset = NULL; module_put(dev->driver->owner); @@ -320,7 +308,7 @@ static int codec_bind_generic(struct hda_codec *codec) * @codec: the HDA codec * * Start parsing of the given codec tree and (re-)initialize the whole - * patch instance. + * codec driver binding. * * Returns 0 if successful or a negative error code. */ diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c index 8899be764d68..33121d002087 100644 --- a/sound/hda/common/codec.c +++ b/sound/hda/common/codec.c @@ -766,7 +766,6 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec) snd_hda_ctls_clear(codec); codec_release_pcms(codec); snd_hda_detach_beep_device(codec); - memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); snd_hda_jack_tbl_clear(codec); codec->proc_widget_hook = NULL; codec->spec = NULL; @@ -1132,8 +1131,6 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, if (driver->ops && driver->ops->stream_pm) driver->ops->stream_pm(codec, nid, true); - else if (codec->patch_ops.stream_pm) - codec->patch_ops.stream_pm(codec, nid, true); if (codec->pcm_format_first) update_pcm_format(codec, p, nid, format); update_pcm_stream_id(codec, p, nid, stream_tag, channel_id); @@ -1205,8 +1202,6 @@ static void really_cleanup_stream(struct hda_codec *codec, q->nid = nid; if (driver->ops && driver->ops->stream_pm) driver->ops->stream_pm(codec, nid, false); - else if (codec->patch_ops.stream_pm) - codec->patch_ops.stream_pm(codec, nid, false); } /* clean up the all conflicting obsolete streams */ @@ -2397,7 +2392,7 @@ static const struct snd_kcontrol_new dig_mixes[] = { * @cvt_nid: converter NID * @type: HDA_PCM_TYPE_* * Creates controls related with the digital output. - * Called from each patch supporting the digital out. + * Called from each codec driver supporting the digital out. * * Returns 0 if successful, or a negative error code. */ @@ -2656,7 +2651,7 @@ static const struct snd_kcontrol_new dig_in_ctls[] = { * @nid: audio in widget NID * * Creates controls related with the SPDIF input. - * Called from each patch supporting the SPDIF in. + * Called from each codec driver supporting the SPDIF in. * * Returns 0 if successful, or a negative error code. */ @@ -2773,9 +2768,6 @@ static unsigned int hda_set_power_state(struct hda_codec *codec, /* might be called before binding to driver, too */ if (driver && driver->ops && driver->ops->set_power_state) driver->ops->set_power_state(codec, fg, power_state); - else if (codec->patch_ops.set_power_state) - codec->patch_ops.set_power_state(codec, fg, - power_state); else { state = power_state; if (codec->power_filter) @@ -2859,8 +2851,6 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec) snd_hdac_enter_pm(&codec->core); if (driver->ops && driver->ops->suspend) driver->ops->suspend(codec); - else if (codec->patch_ops.suspend) - codec->patch_ops.suspend(codec); if (!codec->no_stream_clean_at_suspend) hda_cleanup_all_streams(codec); state = hda_set_power_state(codec, AC_PWRST_D3); @@ -2888,8 +2878,6 @@ static void hda_call_codec_resume(struct hda_codec *codec) snd_hda_jack_set_dirty_all(codec); if (driver->ops && driver->ops->resume) driver->ops->resume(codec); - else if (codec->patch_ops.resume) - codec->patch_ops.resume(codec); else { snd_hda_codec_init(codec); snd_hda_regmap_sync(codec); @@ -3085,8 +3073,6 @@ int snd_hda_codec_build_controls(struct hda_codec *codec) if (!err) { if (driver->ops && driver->ops->build_controls) err = driver->ops->build_controls(codec); - else if (codec->patch_ops.build_controls) - err = codec->patch_ops.build_controls(codec); if (err < 0) return err; } @@ -3284,8 +3270,6 @@ int snd_hda_codec_parse_pcms(struct hda_codec *codec) if (driver->ops && driver->ops->build_pcms) err = driver->ops->build_pcms(codec); - else if (codec->patch_ops.build_pcms) - err = codec->patch_ops.build_pcms(codec); else return 0; diff --git a/sound/hda/common/hda_local.h b/sound/hda/common/hda_local.h index 654fe1156d56..e56bea4c9357 100644 --- a/sound/hda/common/hda_local.h +++ b/sound/hda/common/hda_local.h @@ -658,8 +658,6 @@ static inline int snd_hda_codec_init(struct hda_codec *codec) if (driver->ops && driver->ops->init) return driver->ops->init(codec); - else if (codec->patch_ops.init) - return codec->patch_ops.init(codec); return 0; } diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c index ddb31001657e..126270ffd418 100644 --- a/sound/soc/codecs/hda.c +++ b/sound/soc/codecs/hda.c @@ -177,7 +177,6 @@ static int hda_codec_probe(struct snd_soc_component *component) struct hdac_device *hdev = &codec->core; struct hdac_bus *bus = hdev->bus; struct hdac_ext_link *hlink; - hda_codec_patch_t patch; int ret; #ifdef CONFIG_PM @@ -215,19 +214,12 @@ static int hda_codec_probe(struct snd_soc_component *component) goto err; } - if (driver->ops && driver->ops->probe) { - ret = driver->ops->probe(codec, codec->preset); - } else { - patch = (hda_codec_patch_t)codec->preset->driver_data; - if (!patch) { - dev_err(&hdev->dev, "no patch specified\n"); - ret = -EINVAL; - goto err; - } - - ret = patch(codec); + if (WARN_ON(!(driver->ops && driver->ops->probe))) { + ret = -EINVAL; + goto err; } + ret = driver->ops->probe(codec, codec->preset); if (ret < 0) { dev_err(&hdev->dev, "codec init failed: %d\n", ret); goto err; @@ -260,8 +252,6 @@ complete_err: parse_pcms_err: if (driver->ops && driver->ops->remove) driver->ops->remove(codec); - else if (codec->patch_ops.free) - codec->patch_ops.free(codec); err: snd_hda_codec_cleanup_for_unbind(codec); device_new_err: @@ -292,8 +282,6 @@ static void hda_codec_remove(struct snd_soc_component *component) if (driver->ops && driver->ops->remove) driver->ops->remove(codec); - else if (codec->patch_ops.free) - codec->patch_ops.free(codec); snd_hda_codec_cleanup_for_unbind(codec); pm_runtime_put_noidle(&hdev->dev); diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 7bb7845d5e43..191cb8427664 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -411,7 +411,6 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) struct hda_codec *hcodec = hda_pvt->codec; struct hda_codec_driver *driver = hda_codec_to_driver(hcodec); struct hdac_ext_link *hlink; - hda_codec_patch_t patch; int ret; hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev)); @@ -485,23 +484,15 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) goto error_pm; } - if (driver->ops && driver->ops->probe) { - ret = driver->ops->probe(hcodec, hcodec->preset); - if (ret < 0) { - dev_err(&hdev->dev, "%s: probe failed %d\n", __func__, ret); - goto error_regmap; - } - } else { - patch = (hda_codec_patch_t)hcodec->preset->driver_data; - if (patch) { - ret = patch(hcodec); - if (ret < 0) { - dev_err(&hdev->dev, "%s: patch failed %d\n", __func__, ret); - goto error_regmap; - } - } else { - dev_dbg(&hdev->dev, "%s: no patch file found\n", __func__); - } + if (WARN_ON(!(driver->ops && driver->ops->probe))) { + ret = -EINVAL; + goto error_regmap; + } + + ret = driver->ops->probe(hcodec, hcodec->preset); + if (ret < 0) { + dev_err(&hdev->dev, "%s: probe failed %d\n", __func__, ret); + goto error_regmap; } ret = snd_hda_codec_parse_pcms(hcodec); @@ -542,8 +533,6 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) error_patch: if (driver->ops && driver->ops->remove) driver->ops->remove(hcodec); - else if (hcodec->patch_ops.free) - hcodec->patch_ops.free(hcodec); error_regmap: snd_hdac_regmap_exit(hdev); error_pm: @@ -573,8 +562,6 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component) if (driver->ops && driver->ops->remove) driver->ops->remove(codec); - else if (codec->patch_ops.free) - codec->patch_ops.free(codec); snd_hda_codec_cleanup_for_unbind(codec); } From 691351de31684b98a7366b08cd278bb057b51fce Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:28 +0200 Subject: [PATCH 341/385] ALSA: hda: Drop superfluous driver->ops NULL checks After all conversions, driver->ops became a must in most places (except for the codec power setup which might be called before binding to the codec driver), hence we can get rid of the superfluous driver->ops NULL checks, too. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-26-tiwai@suse.de --- sound/hda/common/bind.c | 6 +++--- sound/hda/common/codec.c | 15 +++++++-------- sound/hda/common/hda_local.h | 2 +- sound/soc/codecs/hda.c | 4 ++-- sound/soc/codecs/hdac_hda.c | 4 ++-- 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/sound/hda/common/bind.c b/sound/hda/common/bind.c index f85c640dd54f..bb1090b65699 100644 --- a/sound/hda/common/bind.c +++ b/sound/hda/common/bind.c @@ -52,7 +52,7 @@ static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev) if (codec->core.dev.power.power_state.event != PM_EVENT_ON) return; - if (driver->ops && driver->ops->unsol_event) + if (driver->ops->unsol_event) driver->ops->unsol_event(codec, ev); } @@ -138,7 +138,7 @@ static int hda_codec_driver_probe(struct device *dev) return 0; error_module: - if (driver->ops && driver->ops->remove) + if (driver->ops->remove) driver->ops->remove(codec); error_module_put: module_put(owner); @@ -166,7 +166,7 @@ static int hda_codec_driver_remove(struct device *dev) wait_event(codec->remove_sleep, !refcount_read(&codec->pcm_ref)); snd_power_sync_ref(codec->bus->card); - if (driver->ops && driver->ops->remove) + if (driver->ops->remove) driver->ops->remove(codec); snd_hda_codec_cleanup_for_unbind(codec); codec->preset = NULL; diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c index 33121d002087..fa07a296abe8 100644 --- a/sound/hda/common/codec.c +++ b/sound/hda/common/codec.c @@ -1129,7 +1129,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, if (!p) return; - if (driver->ops && driver->ops->stream_pm) + if (driver->ops->stream_pm) driver->ops->stream_pm(codec, nid, true); if (codec->pcm_format_first) update_pcm_format(codec, p, nid, format); @@ -1200,7 +1200,7 @@ static void really_cleanup_stream(struct hda_codec *codec, ); memset(q, 0, sizeof(*q)); q->nid = nid; - if (driver->ops && driver->ops->stream_pm) + if (driver->ops->stream_pm) driver->ops->stream_pm(codec, nid, false); } @@ -2849,7 +2849,7 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec) unsigned int state; snd_hdac_enter_pm(&codec->core); - if (driver->ops && driver->ops->suspend) + if (driver->ops->suspend) driver->ops->suspend(codec); if (!codec->no_stream_clean_at_suspend) hda_cleanup_all_streams(codec); @@ -2876,7 +2876,7 @@ static void hda_call_codec_resume(struct hda_codec *codec) restore_shutup_pins(codec); hda_exec_init_verbs(codec); snd_hda_jack_set_dirty_all(codec); - if (driver->ops && driver->ops->resume) + if (driver->ops->resume) driver->ops->resume(codec); else { snd_hda_codec_init(codec); @@ -3071,7 +3071,7 @@ int snd_hda_codec_build_controls(struct hda_codec *codec) /* continue to initialize... */ err = snd_hda_codec_init(codec); if (!err) { - if (driver->ops && driver->ops->build_controls) + if (driver->ops->build_controls) err = driver->ops->build_controls(codec); if (err < 0) return err; @@ -3268,11 +3268,10 @@ int snd_hda_codec_parse_pcms(struct hda_codec *codec) if (!list_empty(&codec->pcm_list_head)) return 0; /* already parsed */ - if (driver->ops && driver->ops->build_pcms) - err = driver->ops->build_pcms(codec); - else + if (!driver->ops->build_pcms) return 0; + err = driver->ops->build_pcms(codec); if (err < 0) { codec_err(codec, "cannot build PCMs for #%d (error %d)\n", codec->core.addr, err); diff --git a/sound/hda/common/hda_local.h b/sound/hda/common/hda_local.h index e56bea4c9357..a7e53277a0fe 100644 --- a/sound/hda/common/hda_local.h +++ b/sound/hda/common/hda_local.h @@ -656,7 +656,7 @@ static inline int snd_hda_codec_init(struct hda_codec *codec) { struct hda_codec_driver *driver = hda_codec_to_driver(codec); - if (driver->ops && driver->ops->init) + if (driver->ops->init) return driver->ops->init(codec); return 0; } diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c index 126270ffd418..c8344e28df3d 100644 --- a/sound/soc/codecs/hda.c +++ b/sound/soc/codecs/hda.c @@ -250,7 +250,7 @@ static int hda_codec_probe(struct snd_soc_component *component) complete_err: hda_codec_unregister_dais(codec, component); parse_pcms_err: - if (driver->ops && driver->ops->remove) + if (driver->ops->remove) driver->ops->remove(codec); err: snd_hda_codec_cleanup_for_unbind(codec); @@ -280,7 +280,7 @@ static void hda_codec_remove(struct snd_soc_component *component) hda_codec_unregister_dais(codec, component); - if (driver->ops && driver->ops->remove) + if (driver->ops->remove) driver->ops->remove(codec); snd_hda_codec_cleanup_for_unbind(codec); diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 191cb8427664..afd8edf10fdc 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -531,7 +531,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) return 0; error_patch: - if (driver->ops && driver->ops->remove) + if (driver->ops->remove) driver->ops->remove(hcodec); error_regmap: snd_hdac_regmap_exit(hdev); @@ -560,7 +560,7 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component) pm_runtime_disable(&hdev->dev); snd_hdac_ext_bus_link_put(hdev->bus, hlink); - if (driver->ops && driver->ops->remove) + if (driver->ops->remove) driver->ops->remove(codec); snd_hda_codec_cleanup_for_unbind(codec); From 0c4eebafea5fefef264f2f8f1c88bbe1e53efedf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:29 +0200 Subject: [PATCH 342/385] MAINTAINERS: Adjust to the new HD-audio driver paths The HD-audio drivers are moved under sound/hda now. Correct the locations. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-27-tiwai@suse.de --- MAINTAINERS | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 5bfcaf0732ed..bd86f2ad65b9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5741,9 +5741,9 @@ F: drivers/spi/spi-cs42l43* F: include/dt-bindings/sound/cs* F: include/linux/mfd/cs42l43* F: include/sound/cs* -F: sound/pci/hda/cirrus* -F: sound/pci/hda/cs* -F: sound/pci/hda/hda_component* +F: sound/hda/codecs/cirrus* +F: sound/hda/codecs/side-codecs/cs* +F: sound/hda/codecs/side-codecs/hda_component* F: sound/soc/codecs/cs* CIRRUS LOGIC HAPTIC DRIVERS @@ -24533,7 +24533,7 @@ F: Documentation/devicetree/bindings/sound/ti,tlv320*.yaml F: Documentation/devicetree/bindings/sound/ti,tlv320adcx140.yaml F: include/sound/tas2*.h F: include/sound/tlv320*.h -F: sound/pci/hda/tas2781_hda_i2c.c +F: sound/hda/codecs/side-codecs/tas2781_hda_i2c.c F: sound/soc/codecs/pcm1681.c F: sound/soc/codecs/pcm1789*.* F: sound/soc/codecs/pcm179x*.* @@ -27473,7 +27473,7 @@ SENARYTECH AUDIO CODEC DRIVER M: bo liu S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git -F: sound/pci/hda/patch_senarytech.c +F: sound/hda/codecs/senarytech.c THE REST M: Linus Torvalds From 0c8e393941d25ea13a659f184c6dc76194a473b5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Jul 2025 18:04:30 +0200 Subject: [PATCH 343/385] ALSA: hda: Return the codec init error properly at snd_hda_codec_build_controls() The error from snd_hda_codec_init() was ignored in snd_hda_codec_build_controls(), which should have been taken account and abort the flow. Fix it now. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250709160434.1859-28-tiwai@suse.de --- sound/hda/common/codec.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c index fa07a296abe8..8e47769ef0ce 100644 --- a/sound/hda/common/codec.c +++ b/sound/hda/common/codec.c @@ -3065,14 +3065,16 @@ EXPORT_SYMBOL_GPL(snd_pcm_2_1_chmaps); int snd_hda_codec_build_controls(struct hda_codec *codec) { struct hda_codec_driver *driver = hda_codec_to_driver(codec); - int err = 0; + int err; hda_exec_init_verbs(codec); /* continue to initialize... */ err = snd_hda_codec_init(codec); - if (!err) { - if (driver->ops->build_controls) - err = driver->ops->build_controls(codec); + if (err < 0) + return err; + + if (driver->ops->build_controls) { + err = driver->ops->build_controls(codec); if (err < 0) return err; } From 0bdbce25855f021187d16d4ffbb92102b9f13788 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 11 Jul 2025 10:30:50 +0200 Subject: [PATCH 344/385] ALSA: hda: Use safer strscpy() instead of strcpy() Use a safer function strscpy() instead of strcpy() for copying to arrays. Only idiomatic code replacement, and no functional changes. Link: https://patch.msgid.link/20250711083051.18759-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/hda/codecs/ca0132.c | 18 +++++++++--------- sound/hda/codecs/generic.c | 4 ++-- sound/hda/codecs/realtek/realtek.c | 4 ++-- sound/hda/common/codec.c | 4 ++-- sound/hda/controllers/intel.c | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/sound/hda/codecs/ca0132.c b/sound/hda/codecs/ca0132.c index 6ab59c336ed4..b716f721f25d 100644 --- a/sound/hda/codecs/ca0132.c +++ b/sound/hda/codecs/ca0132.c @@ -5796,7 +5796,7 @@ static int ca0132_alt_mic_boost_info(struct snd_kcontrol *kcontrol, if (uinfo->value.enumerated.item >= MIC_BOOST_NUM_OF_STEPS) uinfo->value.enumerated.item = MIC_BOOST_NUM_OF_STEPS - 1; sprintf(namestr, "%d %s", (uinfo->value.enumerated.item * 10), sfx); - strcpy(uinfo->value.enumerated.name, namestr); + strscpy(uinfo->value.enumerated.name, namestr); return 0; } @@ -5850,7 +5850,7 @@ static int ae5_headphone_gain_info(struct snd_kcontrol *kcontrol, sprintf(namestr, "%s %s", ae5_headphone_gain_presets[uinfo->value.enumerated.item].name, sfx); - strcpy(uinfo->value.enumerated.name, namestr); + strscpy(uinfo->value.enumerated.name, namestr); return 0; } @@ -5903,7 +5903,7 @@ static int ae5_sound_filter_info(struct snd_kcontrol *kcontrol, uinfo->value.enumerated.item = AE5_SOUND_FILTER_MAX - 1; sprintf(namestr, "%s", ae5_filter_presets[uinfo->value.enumerated.item].name); - strcpy(uinfo->value.enumerated.name, namestr); + strscpy(uinfo->value.enumerated.name, namestr); return 0; } @@ -5952,7 +5952,7 @@ static int ca0132_alt_input_source_info(struct snd_kcontrol *kcontrol, uinfo->value.enumerated.items = IN_SRC_NUM_OF_INPUTS; if (uinfo->value.enumerated.item >= IN_SRC_NUM_OF_INPUTS) uinfo->value.enumerated.item = IN_SRC_NUM_OF_INPUTS - 1; - strcpy(uinfo->value.enumerated.name, + strscpy(uinfo->value.enumerated.name, in_src_str[uinfo->value.enumerated.item]); return 0; } @@ -6004,7 +6004,7 @@ static int ca0132_alt_output_select_get_info(struct snd_kcontrol *kcontrol, uinfo->value.enumerated.items = NUM_OF_OUTPUTS; if (uinfo->value.enumerated.item >= NUM_OF_OUTPUTS) uinfo->value.enumerated.item = NUM_OF_OUTPUTS - 1; - strcpy(uinfo->value.enumerated.name, + strscpy(uinfo->value.enumerated.name, out_type_str[uinfo->value.enumerated.item]); return 0; } @@ -6055,7 +6055,7 @@ static int ca0132_alt_speaker_channel_cfg_get_info(struct snd_kcontrol *kcontrol uinfo->value.enumerated.items = items; if (uinfo->value.enumerated.item >= items) uinfo->value.enumerated.item = items - 1; - strcpy(uinfo->value.enumerated.name, + strscpy(uinfo->value.enumerated.name, speaker_channel_cfgs[uinfo->value.enumerated.item].name); return 0; } @@ -6108,7 +6108,7 @@ static int ca0132_alt_svm_setting_info(struct snd_kcontrol *kcontrol, uinfo->value.enumerated.items = NUM_OF_SVM_SETTINGS; if (uinfo->value.enumerated.item >= NUM_OF_SVM_SETTINGS) uinfo->value.enumerated.item = NUM_OF_SVM_SETTINGS - 1; - strcpy(uinfo->value.enumerated.name, + strscpy(uinfo->value.enumerated.name, out_svm_set_enum_str[uinfo->value.enumerated.item]); return 0; } @@ -6172,7 +6172,7 @@ static int ca0132_alt_eq_preset_info(struct snd_kcontrol *kcontrol, uinfo->value.enumerated.items = items; if (uinfo->value.enumerated.item >= items) uinfo->value.enumerated.item = items - 1; - strcpy(uinfo->value.enumerated.name, + strscpy(uinfo->value.enumerated.name, ca0132_alt_eq_presets[uinfo->value.enumerated.item].name); return 0; } @@ -6229,7 +6229,7 @@ static int ca0132_voicefx_info(struct snd_kcontrol *kcontrol, uinfo->value.enumerated.items = items; if (uinfo->value.enumerated.item >= items) uinfo->value.enumerated.item = items - 1; - strcpy(uinfo->value.enumerated.name, + strscpy(uinfo->value.enumerated.name, ca0132_voicefx_presets[uinfo->value.enumerated.item].name); return 0; } diff --git a/sound/hda/codecs/generic.c b/sound/hda/codecs/generic.c index 044f1d0aeaea..a44beefe3e97 100644 --- a/sound/hda/codecs/generic.c +++ b/sound/hda/codecs/generic.c @@ -2828,7 +2828,7 @@ static int in_jack_mode_info(struct snd_kcontrol *kcontrol, snd_hda_enum_helper_info(kcontrol, uinfo, hweight32(vref_caps), vref_texts); /* set the right text */ - strcpy(uinfo->value.enumerated.name, + strscpy(uinfo->value.enumerated.name, vref_texts[get_vref_idx(vref_caps, uinfo->value.enumerated.item)]); return 0; } @@ -2941,7 +2941,7 @@ static int hp_mic_jack_mode_info(struct snd_kcontrol *kcontrol, text = "Mic In"; } - strcpy(uinfo->value.enumerated.name, text); + strscpy(uinfo->value.enumerated.name, text); return 0; } diff --git a/sound/hda/codecs/realtek/realtek.c b/sound/hda/codecs/realtek/realtek.c index 66b2efb9acb3..b6feccfd45a9 100644 --- a/sound/hda/codecs/realtek/realtek.c +++ b/sound/hda/codecs/realtek/realtek.c @@ -1130,7 +1130,7 @@ void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec, switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: /* override card longname to provide a unique UCM profile */ - strcpy(codec->card->longname, "HDAudio-Gigabyte-ALC1220DualCodecs"); + strscpy(codec->card->longname, "HDAudio-Gigabyte-ALC1220DualCodecs"); break; case HDA_FIXUP_ACT_BUILD: /* rename Capture controls depending on the codec */ @@ -1155,7 +1155,7 @@ void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec, switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: /* override card longname to provide a unique UCM profile */ - strcpy(codec->card->longname, "HDAudio-Lenovo-DualCodecs"); + strscpy(codec->card->longname, "HDAudio-Lenovo-DualCodecs"); break; case HDA_FIXUP_ACT_BUILD: /* rename Capture controls depending on the codec */ diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c index 8e47769ef0ce..eb268d442201 100644 --- a/sound/hda/common/codec.c +++ b/sound/hda/common/codec.c @@ -1638,7 +1638,7 @@ find_mixer_ctl(struct hda_codec *codec, const char *name, int dev, int idx) id.index = idx; if (snd_BUG_ON(strlen(name) >= sizeof(id.name))) return NULL; - strcpy(id.name, name); + strscpy(id.name, name); return snd_ctl_find_id(codec->card, &id); } @@ -3508,7 +3508,7 @@ int snd_hda_input_mux_info(const struct hda_input_mux *imux, index = uinfo->value.enumerated.item; if (index >= imux->num_items) index = imux->num_items - 1; - strcpy(uinfo->value.enumerated.name, imux->items[index].label); + strscpy(uinfo->value.enumerated.name, imux->items[index].label); return 0; } EXPORT_SYMBOL_GPL(snd_hda_input_mux_info); diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c index ebfc999156f4..32bfd92d817f 100644 --- a/sound/hda/controllers/intel.c +++ b/sound/hda/controllers/intel.c @@ -2024,7 +2024,7 @@ static int azx_first_init(struct azx *chip) if (azx_acquire_irq(chip, 0) < 0) return -EBUSY; - strcpy(card->driver, "HDA-Intel"); + strscpy(card->driver, "HDA-Intel"); strscpy(card->shortname, driver_short_names[chip->driver_type], sizeof(card->shortname)); snprintf(card->longname, sizeof(card->longname), From 6894e49b7b62cdb0edbcaaa23ea0218edb3b02dd Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 11 Jul 2025 11:06:15 +0100 Subject: [PATCH 345/385] ASoC: SDCA: Kconfig/Makefile fixups Tidy up a few bits of the SDCA Kconfig. Default both HID and IRQ to enabled, since typically if one wants SDCA all the functionality will be expected. Finally, update the IRQ support to match the changes made to the HID support. Signed-off-by: Charles Keepax Reviewed-by: Arnd Bergmann Link: https://patch.msgid.link/20250711100616.296329-2-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/sdca/Kconfig | 13 +++++++++---- sound/soc/sdca/Makefile | 10 ++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/sound/soc/sdca/Kconfig b/sound/soc/sdca/Kconfig index 2253a300dcc3..6a3ba43f26bd 100644 --- a/sound/soc/sdca/Kconfig +++ b/sound/soc/sdca/Kconfig @@ -8,19 +8,24 @@ config SND_SOC_SDCA This option enables support for the MIPI SoundWire Device Class for Audio (SDCA). -config SND_SOC_SDCA_OPTIONAL - def_tristate SND_SOC_SDCA || !SND_SOC_SDCA - config SND_SOC_SDCA_HID bool "SDCA HID support" depends on SND_SOC_SDCA depends on HID=y || HID=SND_SOC_SDCA + default y + help + This option enables support for audio jack button reporting using HID. config SND_SOC_SDCA_IRQ - tristate + bool "SDCA IRQ support" select REGMAP select REGMAP_IRQ + depends on SND_SOC_SDCA + default y help This option enables support for SDCA IRQs. +config SND_SOC_SDCA_OPTIONAL + def_tristate SND_SOC_SDCA || !SND_SOC_SDCA + endmenu diff --git a/sound/soc/sdca/Makefile b/sound/soc/sdca/Makefile index 1efc869c6cbc..58a8f3ef3feb 100644 --- a/sound/soc/sdca/Makefile +++ b/sound/soc/sdca/Makefile @@ -1,11 +1,13 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-soc-sdca-y := sdca_functions.o sdca_device.o sdca_regmap.o sdca_asoc.o +snd-soc-sdca-y := sdca_functions.o sdca_device.o sdca_regmap.o sdca_asoc.o snd-soc-sdca-hid-y := sdca_hid.o snd-soc-sdca-irq-y := sdca_interrupts.o -obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca.o +obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca.o ifdef CONFIG_SND_SOC_SDCA_HID -obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca-hid.o +obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca-hid.o +endif +ifdef CONFIG_SND_SOC_SDCA_IRQ +obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca-irq.o endif -obj-$(CONFIG_SND_SOC_SDCA_IRQ) += snd-soc-sdca-irq.o From 5030abcb0aa3304bf91497844ffa9607a2d4ad5d Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 11 Jul 2025 11:06:16 +0100 Subject: [PATCH 346/385] ASoC: SDCA: Pull HID and IRQ into the primary SDCA module If the HID or the IRQ are selected as options they will always require loading alongside the main SDCA module. Since it will never be possible to run without them the value of keeping them as separate modules is fairly limited. Pull them into the main SDCA module to simplify things still further. Signed-off-by: Charles Keepax Reviewed-by: Arnd Bergmann Link: https://patch.msgid.link/20250711100616.296329-3-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/sdca/Makefile | 10 ++-------- sound/soc/sdca/sdca_functions.c | 1 - sound/soc/sdca/sdca_hid.c | 2 +- sound/soc/sdca/sdca_interrupts.c | 8 ++++---- 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/sound/soc/sdca/Makefile b/sound/soc/sdca/Makefile index 58a8f3ef3feb..5e51760cb651 100644 --- a/sound/soc/sdca/Makefile +++ b/sound/soc/sdca/Makefile @@ -1,13 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only snd-soc-sdca-y := sdca_functions.o sdca_device.o sdca_regmap.o sdca_asoc.o -snd-soc-sdca-hid-y := sdca_hid.o -snd-soc-sdca-irq-y := sdca_interrupts.o +snd-soc-sdca-$(CONFIG_SND_SOC_SDCA_HID) += sdca_hid.o +snd-soc-sdca-$(CONFIG_SND_SOC_SDCA_IRQ) += sdca_interrupts.o obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca.o -ifdef CONFIG_SND_SOC_SDCA_HID -obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca-hid.o -endif -ifdef CONFIG_SND_SOC_SDCA_IRQ -obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca-irq.o -endif diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index c34f3bf62983..be09b7a34102 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -1943,4 +1943,3 @@ EXPORT_SYMBOL_NS(sdca_parse_function, "SND_SOC_SDCA"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SDCA library"); -MODULE_IMPORT_NS("SND_SOC_SDCA_HID"); diff --git a/sound/soc/sdca/sdca_hid.c b/sound/soc/sdca/sdca_hid.c index b227ad94d08f..2224ade59aff 100644 --- a/sound/soc/sdca/sdca_hid.c +++ b/sound/soc/sdca/sdca_hid.c @@ -121,7 +121,7 @@ int sdca_add_hid_device(struct device *dev, struct sdca_entity *entity) return 0; } -EXPORT_SYMBOL_NS(sdca_add_hid_device, "SND_SOC_SDCA_HID"); +EXPORT_SYMBOL_NS(sdca_add_hid_device, "SND_SOC_SDCA"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SDCA HID library"); diff --git a/sound/soc/sdca/sdca_interrupts.c b/sound/soc/sdca/sdca_interrupts.c index edb045c7ebb0..2f85fcc6e544 100644 --- a/sound/soc/sdca/sdca_interrupts.c +++ b/sound/soc/sdca/sdca_interrupts.c @@ -279,7 +279,7 @@ int sdca_irq_request(struct device *dev, struct sdca_interrupt_info *info, return 0; } -EXPORT_SYMBOL_NS_GPL(sdca_irq_request, "SND_SOC_SDCA_IRQ"); +EXPORT_SYMBOL_NS_GPL(sdca_irq_request, "SND_SOC_SDCA"); /** * sdca_irq_data_populate - Populate common interrupt data @@ -313,7 +313,7 @@ int sdca_irq_data_populate(struct snd_soc_component *component, return 0; } -EXPORT_SYMBOL_NS_GPL(sdca_irq_data_populate, "SND_SOC_SDCA_IRQ"); +EXPORT_SYMBOL_NS_GPL(sdca_irq_data_populate, "SND_SOC_SDCA"); /** * sdca_irq_populate - Request all the individual IRQs for an SDCA Function @@ -393,7 +393,7 @@ int sdca_irq_populate(struct sdca_function_data *function, return 0; } -EXPORT_SYMBOL_NS_GPL(sdca_irq_populate, "SND_SOC_SDCA_IRQ"); +EXPORT_SYMBOL_NS_GPL(sdca_irq_populate, "SND_SOC_SDCA"); /** * sdca_irq_allocate - allocate an SDCA interrupt structure for a device @@ -433,7 +433,7 @@ struct sdca_interrupt_info *sdca_irq_allocate(struct device *dev, return info; } -EXPORT_SYMBOL_NS_GPL(sdca_irq_allocate, "SND_SOC_SDCA_IRQ"); +EXPORT_SYMBOL_NS_GPL(sdca_irq_allocate, "SND_SOC_SDCA"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SDCA IRQ library"); From f40ecc2743652c0b0f19935f81baf57c601eb7f0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 11 Jul 2025 02:26:39 +0000 Subject: [PATCH 347/385] ASoC: soc-dapm: set bias_level if snd_soc_dapm_set_bias_level() was successed ASoC has 2 functions to set bias level. (A) snd_soc_dapm_force_bias_level() (B) snd_soc_dapm_set_bias_level() snd_soc_dapm_force_bias_level() (A) will set dapm->bias_level (a) if successed. (A) int snd_soc_dapm_force_bias_level(...) { ... if (ret == 0) (a) dapm->bias_level = level; ... } snd_soc_dapm_set_bias_level() (B) is also a function that sets bias_level. It will call snd_soc_dapm_force_bias_level() (A) inside, but doesn't set dapm->bias_level by itself. One note is that (A) might not be called. (B) static int snd_soc_dapm_set_bias_level(...) { ... ret = snd_soc_card_set_bias_level(...); ... if (dapm != &card->dapm) (A) ret = snd_soc_dapm_force_bias_level(...); ... ret = snd_soc_card_set_bias_level_post(...); ... } dapm->bias_level will be set if (A) was called, but might not be set if (B) was called, even though it calles set_bias_level() function. We should set dapm->bias_level if we calls snd_soc_dapm_set_bias_level() (B), too. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87qzyn4g4h.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index b8a5875378c8..a37d44cd04c6 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1030,6 +1030,10 @@ static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm, out: trace_snd_soc_bias_level_done(dapm, level); + /* success */ + if (ret == 0) + snd_soc_dapm_init_bias_level(dapm, level); + return ret; } From 88f60cb4b8c96241d86a68da57dc5b52488240cf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 11 Jul 2025 02:26:54 +0000 Subject: [PATCH 348/385] ASoC: samsung: bell: don't set dapm->bias_level directly snd_soc_dapm_set_bias_level() (A) will set dapm->bias_level (a) inside. No need to set it by each callback function. Remove it. (A) static int snd_soc_dapm_set_bias_level(...) { ... /* success */ if (ret == 0) (a) snd_soc_dapm_init_bias_level(dapm, level); ... } Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87ple74g47.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/samsung/bells.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c index 8dc3b2da4c8f..61ed5e69391a 100644 --- a/sound/soc/samsung/bells.c +++ b/sound/soc/samsung/bells.c @@ -133,8 +133,6 @@ static int bells_set_bias_level_post(struct snd_soc_card *card, break; } - dapm->bias_level = level; - return 0; } From d2f423a4f4ecabd852c5ee5076596399488d4b75 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 11 Jul 2025 02:27:04 +0000 Subject: [PATCH 349/385] ASoC: samsung: speyside: don't set dapm->bias_level directly snd_soc_dapm_set_bias_level() (A) will set dapm->bias_level (a) inside. No need to set it by each callback function. Remove it. (A) static int snd_soc_dapm_set_bias_level(...) { ... /* success */ if (ret == 0) (a) snd_soc_dapm_init_bias_level(dapm, level); ... } Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87o6tr4g3r.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/samsung/speyside.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index 9262e5626584..f4cc5684ef0a 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c @@ -90,8 +90,6 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card, break; } - card->dapm.bias_level = level; - return 0; } From 4421e455d2c33a86cdb19f3a0854a59de1542321 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 11 Jul 2025 02:27:12 +0000 Subject: [PATCH 350/385] ASoC: samsung: tobermory: don't set dapm->bias_level directly snd_soc_dapm_set_bias_level() (A) will set dapm->bias_level (a) inside. No need to set it by each callback function. Remove it. (A) static int snd_soc_dapm_set_bias_level(...) { ... /* success */ if (ret == 0) (a) snd_soc_dapm_init_bias_level(dapm, level); ... } Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87ms9b4g3j.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/samsung/tobermory.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c index d0f0c01365aa..1d0a782402f0 100644 --- a/sound/soc/samsung/tobermory.c +++ b/sound/soc/samsung/tobermory.c @@ -91,8 +91,6 @@ static int tobermory_set_bias_level_post(struct snd_soc_card *card, break; } - dapm->bias_level = level; - return 0; } From f00e06296ba3f0d8440030afe8cc2258758b7af7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 11 Jul 2025 02:27:19 +0000 Subject: [PATCH 351/385] ASoC: samsung: littlemill: don't set dapm->bias_level directly snd_soc_dapm_set_bias_level() (A) will set dapm->bias_level (a) inside. No need to set it by each callback function. Remove it. (A) static int snd_soc_dapm_set_bias_level(...) { ... /* success */ if (ret == 0) (a) snd_soc_dapm_init_bias_level(dapm, level); ... } Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87ldov4g3c.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/samsung/littlemill.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c index 5a02aac9b423..c8b06894ac88 100644 --- a/sound/soc/samsung/littlemill.c +++ b/sound/soc/samsung/littlemill.c @@ -95,8 +95,6 @@ static int littlemill_set_bias_level_post(struct snd_soc_card *card, break; } - dapm->bias_level = level; - return 0; } From 69d5b62c4bded309332add0fac6760239ff47a68 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 10 Jul 2025 20:40:01 +0800 Subject: [PATCH 352/385] ASoC: codec: tlv320aic32x4: Drop aic32x4_pdata usage There is no machine is using aic32x4_pdata as platform_data, so remove the dead code. Cc: Markus Niebel Cc: Alexander Stein Reviewed-by: Alexander Stein Signed-off-by: Peng Fan Reviewed-by: Linus Walleij Link: https://patch.msgid.link/20250710-asoc-gpio-1-v2-1-2233b272a1a6@nxp.com Signed-off-by: Mark Brown --- include/sound/tlv320aic32x4.h | 9 --------- sound/soc/codecs/tlv320aic32x4.c | 9 +-------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/include/sound/tlv320aic32x4.h b/include/sound/tlv320aic32x4.h index 0abf74d7edbd..b779d671a995 100644 --- a/include/sound/tlv320aic32x4.h +++ b/include/sound/tlv320aic32x4.h @@ -40,13 +40,4 @@ struct aic32x4_setup_data { unsigned int gpio_func[5]; }; - -struct aic32x4_pdata { - struct aic32x4_setup_data *setup; - u32 power_cfg; - u32 micpga_routing; - bool swapdacs; - int rstn_gpio; -}; - #endif diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 54ea4bc58c27..7dbcf7f7130b 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -1346,7 +1346,6 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap, enum aic32x4_type type) { struct aic32x4_priv *aic32x4; - struct aic32x4_pdata *pdata = dev->platform_data; struct device_node *np = dev->of_node; int ret; @@ -1363,13 +1362,7 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap, dev_set_drvdata(dev, aic32x4); - if (pdata) { - aic32x4->power_cfg = pdata->power_cfg; - aic32x4->swapdacs = pdata->swapdacs; - aic32x4->micpga_routing = pdata->micpga_routing; - aic32x4->rstn_gpio = pdata->rstn_gpio; - aic32x4->mclk_name = "mclk"; - } else if (np) { + if (np) { ret = aic32x4_parse_dt(aic32x4, np); if (ret) { dev_err(dev, "Failed to parse DT node\n"); From b709c1aef5e15db3aff5749fc7ed9c61b8d0a322 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 10 Jul 2025 20:40:02 +0800 Subject: [PATCH 353/385] ASoC: codec: tlv320aic32x4: Sort headers alphabetically Sort headers alphabetically to easily insert new ones and drop unused ones. Signed-off-by: Peng Fan Reviewed-by: Alexander Stein Link: https://patch.msgid.link/20250710-asoc-gpio-1-v2-2-2233b272a1a6@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 7dbcf7f7130b..2f4147387c4f 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -9,27 +9,27 @@ * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27. */ +#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include #include +#include -#include #include +#include #include #include #include #include -#include #include +#include #include "tlv320aic32x4.h" From 790d5f8ee6f2a27686d042abbce16b4e03ac1608 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 10 Jul 2025 20:40:03 +0800 Subject: [PATCH 354/385] ASoC: codec: tlv320aic32x4: Convert to GPIO descriptors of_gpio.h is deprecated, update the driver to use GPIO descriptors. - Use devm_gpiod_get_optional to get GPIO descriptor, and set consumer name. - Use gpiod_set_value to configure output value. While at here, reorder the included headers. Checking the DTS that use the device, all are using GPIOD_ACTIVE_LOW polarity for reset-gpios, so all should work as expected with this patch. Cc: Markus Niebel Cc: Alexander Stein Reviewed-by: Linus Walleij Tested-by: Alexander Stein Signed-off-by: Peng Fan Link: https://patch.msgid.link/20250710-asoc-gpio-1-v2-3-2233b272a1a6@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 2f4147387c4f..3b89980e9bcf 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -12,12 +12,11 @@ #include #include #include -#include +#include #include #include #include #include -#include #include #include #include @@ -38,7 +37,7 @@ struct aic32x4_priv { u32 power_cfg; u32 micpga_routing; bool swapdacs; - int rstn_gpio; + struct gpio_desc *rstn_gpio; const char *mclk_name; struct regulator *supply_ldo; @@ -1236,7 +1235,14 @@ static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, aic32x4->swapdacs = false; aic32x4->micpga_routing = 0; - aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0); + /* Assert reset using GPIOD_OUT_HIGH, because reset is GPIO_ACTIVE_LOW */ + aic32x4->rstn_gpio = devm_gpiod_get_optional(aic32x4->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(aic32x4->rstn_gpio)) { + return dev_err_probe(aic32x4->dev, PTR_ERR(aic32x4->rstn_gpio), + "Failed to get reset gpio\n"); + } else { + gpiod_set_consumer_name(aic32x4->rstn_gpio, "tlv320aic32x4_rstn"); + } if (of_property_read_u32_array(np, "aic32x4-gpio-func", aic32x4_setup->gpio_func, 5) >= 0) @@ -1372,26 +1378,20 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap, aic32x4->power_cfg = 0; aic32x4->swapdacs = false; aic32x4->micpga_routing = 0; - aic32x4->rstn_gpio = -1; + aic32x4->rstn_gpio = NULL; aic32x4->mclk_name = "mclk"; } - if (gpio_is_valid(aic32x4->rstn_gpio)) { - ret = devm_gpio_request_one(dev, aic32x4->rstn_gpio, - GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn"); - if (ret != 0) - return ret; - } - ret = aic32x4_setup_regulators(dev, aic32x4); if (ret) { dev_err(dev, "Failed to setup regulators\n"); return ret; } - if (gpio_is_valid(aic32x4->rstn_gpio)) { + if (!aic32x4->rstn_gpio) { ndelay(10); - gpio_set_value_cansleep(aic32x4->rstn_gpio, 1); + /* deassert reset */ + gpiod_set_value_cansleep(aic32x4->rstn_gpio, 0); mdelay(1); } From af241e3fa4d823f8af899c92fd50d020816a1860 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 8 Jul 2025 16:53:17 +0800 Subject: [PATCH 355/385] ASoC: fsl-asoc-card: add sysclk_ratio for calculate sysclk frequency The sysclk frequency can be calculated from sample rate multiply ratio. When sysclk_freq is not configured, but sysclk_ratio is configured, then calculate sysclk frequency according to sysclk_ratio. Apply this change for wm8524 codec. Signed-off-by: Shengjiu Wang Link: https://patch.msgid.link/20250708085318.2563521-1-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl-asoc-card.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index ab583b432c60..71113886e494 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -63,6 +63,7 @@ struct codec_priv { * @sysclk_freq: SYSCLK rates for set_sysclk() * @sysclk_dir: SYSCLK directions for set_sysclk() * @sysclk_id: SYSCLK ids for set_sysclk() + * @sysclk_ratio: SYSCLK ratio on sample rate * @slot_width: Slot width of each frame * @slot_num: Number of slots of each frame * @@ -72,6 +73,7 @@ struct cpu_priv { unsigned long sysclk_freq[2]; u32 sysclk_dir[2]; u32 sysclk_id[2]; + u32 sysclk_ratio[2]; u32 slot_width; u32 slot_num; }; @@ -176,7 +178,7 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai; struct cpu_priv *cpu_priv = &priv->cpu_priv; struct device *dev = rtd->card->dev; - unsigned int pll_out; + unsigned int pll_out, sysclk_freq; int codec_idx; int ret; @@ -187,9 +189,14 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream, if (fsl_asoc_card_is_ac97(priv)) return 0; + if (!cpu_priv->sysclk_freq[tx] && cpu_priv->sysclk_ratio[tx]) + sysclk_freq = priv->sample_rate * cpu_priv->sysclk_ratio[tx]; + else + sysclk_freq = cpu_priv->sysclk_freq[tx]; + /* Specific configurations of DAIs starts from here */ ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), cpu_priv->sysclk_id[tx], - cpu_priv->sysclk_freq[tx], + sysclk_freq, cpu_priv->sysclk_dir[tx]); if (ret && ret != -ENOTSUPP) { dev_err(dev, "failed to set sysclk for cpu dai\n"); @@ -799,6 +806,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->cpu_priv.slot_width = 32; priv->card.dapm_routes = audio_map_tx; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); + priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT; + priv->cpu_priv.sysclk_ratio[TX] = 256; } else if (of_device_is_compatible(np, "fsl,imx-audio-si476x")) { codec_dai_name[0] = "si476x-codec"; priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC; From 8a4d73121d6bd9a70895e65d6d1014ed6b0a6c8e Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 10 Jul 2025 11:51:07 -0400 Subject: [PATCH 356/385] ASoC: codecs: da7219: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney Link: https://patch.msgid.link/20250710-sound-clk-round-rate-v1-1-4a9c3bb6ff3a@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 64 +++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 3958e88a2445..05e4cc89df22 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1982,8 +1982,8 @@ static unsigned long da7219_wclk_recalc_rate(struct clk_hw *hw, } } -static long da7219_wclk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int da7219_wclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct da7219_priv *da7219 = container_of(hw, struct da7219_priv, @@ -1992,28 +1992,30 @@ static long da7219_wclk_round_rate(struct clk_hw *hw, unsigned long rate, if (!da7219->master) return -EINVAL; - if (rate < 11025) - return 8000; - else if (rate < 12000) - return 11025; - else if (rate < 16000) - return 12000; - else if (rate < 22050) - return 16000; - else if (rate < 24000) - return 22050; - else if (rate < 32000) - return 24000; - else if (rate < 44100) - return 32000; - else if (rate < 48000) - return 44100; - else if (rate < 88200) - return 48000; - else if (rate < 96000) - return 88200; + if (req->rate < 11025) + req->rate = 8000; + else if (req->rate < 12000) + req->rate = 11025; + else if (req->rate < 16000) + req->rate = 12000; + else if (req->rate < 22050) + req->rate = 16000; + else if (req->rate < 24000) + req->rate = 22050; + else if (req->rate < 32000) + req->rate = 24000; + else if (req->rate < 44100) + req->rate = 32000; + else if (req->rate < 48000) + req->rate = 44100; + else if (req->rate < 88200) + req->rate = 48000; + else if (req->rate < 96000) + req->rate = 88200; else - return 96000; + req->rate = 96000; + + return 0; } static int da7219_wclk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -2070,15 +2072,15 @@ static unsigned long da7219_bclk_get_factor(unsigned long rate, return 256; } -static long da7219_bclk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int da7219_bclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct da7219_priv *da7219 = container_of(hw, struct da7219_priv, dai_clks_hw[DA7219_DAI_BCLK_IDX]); unsigned long factor; - if (!*parent_rate || !da7219->master) + if (!req->best_parent_rate || !da7219->master) return -EINVAL; /* @@ -2088,9 +2090,11 @@ static long da7219_bclk_round_rate(struct clk_hw *hw, unsigned long rate, * parent WCLK rate set and find the appropriate multiplier of BCLK to * get the rounded down BCLK value. */ - factor = da7219_bclk_get_factor(rate, *parent_rate); + factor = da7219_bclk_get_factor(req->rate, req->best_parent_rate); - return *parent_rate * factor; + req->rate = req->best_parent_rate * factor; + + return 0; } static int da7219_bclk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -2116,12 +2120,12 @@ static const struct clk_ops da7219_dai_clk_ops[DA7219_DAI_NUM_CLKS] = { .unprepare = da7219_wclk_unprepare, .is_prepared = da7219_wclk_is_prepared, .recalc_rate = da7219_wclk_recalc_rate, - .round_rate = da7219_wclk_round_rate, + .determine_rate = da7219_wclk_determine_rate, .set_rate = da7219_wclk_set_rate, }, [DA7219_DAI_BCLK_IDX] = { .recalc_rate = da7219_bclk_recalc_rate, - .round_rate = da7219_bclk_round_rate, + .determine_rate = da7219_bclk_determine_rate, .set_rate = da7219_bclk_set_rate, }, }; From 4e15a10f6fb254e33d73a6da3c4d00e3e64d2eb8 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 10 Jul 2025 11:51:08 -0400 Subject: [PATCH 357/385] ASoC: codecs: rt5682: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney Link: https://patch.msgid.link/20250710-sound-clk-round-rate-v1-2-4a9c3bb6ff3a@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 7c88370e2dee..a0abd2ce0c1e 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2675,8 +2675,8 @@ static unsigned long rt5682_wclk_recalc_rate(struct clk_hw *hw, return rt5682->lrck[RT5682_AIF1]; } -static long rt5682_wclk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int rt5682_wclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct rt5682_priv *rt5682 = container_of(hw, struct rt5682_priv, @@ -2689,13 +2689,13 @@ static long rt5682_wclk_round_rate(struct clk_hw *hw, unsigned long rate, * Only accept to set wclk rate to 44.1k or 48kHz. * It will force to 48kHz if not both. */ - if (rate != CLK_48 && rate != CLK_44) { + if (req->rate != CLK_48 && req->rate != CLK_44) { dev_warn(rt5682->i2c_dev, "%s: clk %s only support %d or %d Hz output\n", __func__, clk_name, CLK_44, CLK_48); - rate = CLK_48; + req->rate = CLK_48; } - return rate; + return 0; } static int rt5682_wclk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -2795,15 +2795,15 @@ static unsigned long rt5682_bclk_get_factor(unsigned long rate, return 256; } -static long rt5682_bclk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int rt5682_bclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct rt5682_priv *rt5682 = container_of(hw, struct rt5682_priv, dai_clks_hw[RT5682_DAI_BCLK_IDX]); unsigned long factor; - if (!*parent_rate || !rt5682_clk_check(rt5682)) + if (!req->best_parent_rate || !rt5682_clk_check(rt5682)) return -EINVAL; /* @@ -2813,9 +2813,11 @@ static long rt5682_bclk_round_rate(struct clk_hw *hw, unsigned long rate, * and find the appropriate multiplier of BCLK to * get the rounded down BCLK value. */ - factor = rt5682_bclk_get_factor(rate, *parent_rate); + factor = rt5682_bclk_get_factor(req->rate, req->best_parent_rate); - return *parent_rate * factor; + req->rate = req->best_parent_rate * factor; + + return 0; } static int rt5682_bclk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -2849,12 +2851,12 @@ static const struct clk_ops rt5682_dai_clk_ops[RT5682_DAI_NUM_CLKS] = { .prepare = rt5682_wclk_prepare, .unprepare = rt5682_wclk_unprepare, .recalc_rate = rt5682_wclk_recalc_rate, - .round_rate = rt5682_wclk_round_rate, + .determine_rate = rt5682_wclk_determine_rate, .set_rate = rt5682_wclk_set_rate, }, [RT5682_DAI_BCLK_IDX] = { .recalc_rate = rt5682_bclk_recalc_rate, - .round_rate = rt5682_bclk_round_rate, + .determine_rate = rt5682_bclk_determine_rate, .set_rate = rt5682_bclk_set_rate, }, }; From a37d9c8aef1c78876eff0bc8980a889c083de89d Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 10 Jul 2025 11:51:09 -0400 Subject: [PATCH 358/385] ASoC: codecs: rt5682s: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney Link: https://patch.msgid.link/20250710-sound-clk-round-rate-v1-3-4a9c3bb6ff3a@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682s.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index 73c4b3c31f8c..80b921695e7d 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -2610,8 +2610,8 @@ static unsigned long rt5682s_wclk_recalc_rate(struct clk_hw *hw, return rt5682s->lrck[RT5682S_AIF1]; } -static long rt5682s_wclk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int rt5682s_wclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct rt5682s_priv *rt5682s = container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]); @@ -2624,13 +2624,13 @@ static long rt5682s_wclk_round_rate(struct clk_hw *hw, unsigned long rate, * Only accept to set wclk rate to 44.1k or 48kHz. * It will force to 48kHz if not both. */ - if (rate != CLK_48 && rate != CLK_44) { + if (req->rate != CLK_48 && req->rate != CLK_44) { dev_warn(component->dev, "%s: clk %s only support %d or %d Hz output\n", __func__, clk_name, CLK_44, CLK_48); - rate = CLK_48; + req->rate = CLK_48; } - return rate; + return 0; } static int rt5682s_wclk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -2719,14 +2719,14 @@ static unsigned long rt5682s_bclk_get_factor(unsigned long rate, return 256; } -static long rt5682s_bclk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int rt5682s_bclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct rt5682s_priv *rt5682s = container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_BCLK_IDX]); unsigned long factor; - if (!*parent_rate || !rt5682s_clk_check(rt5682s)) + if (!req->best_parent_rate || !rt5682s_clk_check(rt5682s)) return -EINVAL; /* @@ -2736,9 +2736,11 @@ static long rt5682s_bclk_round_rate(struct clk_hw *hw, unsigned long rate, * and find the appropriate multiplier of BCLK to * get the rounded down BCLK value. */ - factor = rt5682s_bclk_get_factor(rate, *parent_rate); + factor = rt5682s_bclk_get_factor(req->rate, req->best_parent_rate); - return *parent_rate * factor; + req->rate = req->best_parent_rate * factor; + + return 0; } static int rt5682s_bclk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -2769,12 +2771,12 @@ static const struct clk_ops rt5682s_dai_clk_ops[RT5682S_DAI_NUM_CLKS] = { .prepare = rt5682s_wclk_prepare, .unprepare = rt5682s_wclk_unprepare, .recalc_rate = rt5682s_wclk_recalc_rate, - .round_rate = rt5682s_wclk_round_rate, + .determine_rate = rt5682s_wclk_determine_rate, .set_rate = rt5682s_wclk_set_rate, }, [RT5682S_DAI_BCLK_IDX] = { .recalc_rate = rt5682s_bclk_recalc_rate, - .round_rate = rt5682s_bclk_round_rate, + .determine_rate = rt5682s_bclk_determine_rate, .set_rate = rt5682s_bclk_set_rate, }, }; From fc62ed665eb2e8fb0f1e12ab9cdb578666704a76 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 10 Jul 2025 11:51:10 -0400 Subject: [PATCH 359/385] ASoC: qcom: qdsp6: q6dsp-lpass-clocks: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney Reviewed-by: Konrad Dybcio Link: https://patch.msgid.link/20250710-sound-clk-round-rate-v1-4-4a9c3bb6ff3a@redhat.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c index e758411603be..03838582aead 100644 --- a/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c +++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c @@ -69,17 +69,17 @@ static unsigned long clk_q6dsp_recalc_rate(struct clk_hw *hw, return clk->rate; } -static long clk_q6dsp_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int clk_q6dsp_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - return rate; + return 0; } static const struct clk_ops clk_q6dsp_ops = { .prepare = clk_q6dsp_prepare, .unprepare = clk_q6dsp_unprepare, .set_rate = clk_q6dsp_set_rate, - .round_rate = clk_q6dsp_round_rate, + .determine_rate = clk_q6dsp_determine_rate, .recalc_rate = clk_q6dsp_recalc_rate, }; From afd529d740028a41fa750d4491b106cecbccba3e Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 10 Jul 2025 11:51:11 -0400 Subject: [PATCH 360/385] ASoC: stm: stm32_i2s: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney Link: https://patch.msgid.link/20250710-sound-clk-round-rate-v1-5-4a9c3bb6ff3a@redhat.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 6037b7a9c97b..0e489097d9c1 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -461,20 +461,25 @@ err: return -EINVAL; } -static long stm32_i2smclk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int stm32_i2smclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct stm32_i2smclk_data *mclk = to_mclk_data(hw); struct stm32_i2s_data *i2s = mclk->i2s_data; int ret; - ret = stm32_i2s_calc_clk_div(i2s, *prate, rate); - if (ret) - return ret; + ret = stm32_i2s_calc_clk_div(i2s, req->best_parent_rate, req->rate); + if (ret) { + req->rate = ret; - mclk->freq = *prate / i2s->divider; + return 0; + } - return mclk->freq; + mclk->freq = req->best_parent_rate / i2s->divider; + + req->rate = mclk->freq; + + return 0; } static unsigned long stm32_i2smclk_recalc_rate(struct clk_hw *hw, @@ -530,7 +535,7 @@ static const struct clk_ops mclk_ops = { .enable = stm32_i2smclk_enable, .disable = stm32_i2smclk_disable, .recalc_rate = stm32_i2smclk_recalc_rate, - .round_rate = stm32_i2smclk_round_rate, + .determine_rate = stm32_i2smclk_determine_rate, .set_rate = stm32_i2smclk_set_rate, }; From d5f317fd5cd9dfdf5bbe11384001817760c12b75 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 10 Jul 2025 11:51:12 -0400 Subject: [PATCH 361/385] ASoC: stm: stm32_sai_sub: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney Link: https://patch.msgid.link/20250710-sound-clk-round-rate-v1-6-4a9c3bb6ff3a@redhat.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai_sub.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index bf5299ba11c3..463a2b7d023b 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -489,20 +489,22 @@ err: return -EINVAL; } -static long stm32_sai_mclk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int stm32_sai_mclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct stm32_sai_mclk_data *mclk = to_mclk_data(hw); struct stm32_sai_sub_data *sai = mclk->sai_data; int div; - div = stm32_sai_get_clk_div(sai, *prate, rate); + div = stm32_sai_get_clk_div(sai, req->best_parent_rate, req->rate); if (div <= 0) return -EINVAL; - mclk->freq = *prate / div; + mclk->freq = req->best_parent_rate / div; - return mclk->freq; + req->rate = mclk->freq; + + return 0; } static unsigned long stm32_sai_mclk_recalc_rate(struct clk_hw *hw, @@ -558,7 +560,7 @@ static const struct clk_ops mclk_ops = { .enable = stm32_sai_mclk_enable, .disable = stm32_sai_mclk_disable, .recalc_rate = stm32_sai_mclk_recalc_rate, - .round_rate = stm32_sai_mclk_round_rate, + .determine_rate = stm32_sai_mclk_determine_rate, .set_rate = stm32_sai_mclk_set_rate, }; From 859d97606f032d10d4633e17541f07f1f355e282 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Jul 2025 09:51:21 +0200 Subject: [PATCH 362/385] arm: multi_v7_defconfig: Update HD-audio configs Since the reorganization of HD-audio drivers, Realtek and HDMI codec drivers have been split. Update to the new Kconfigs to catch up. Fixes: aeeb85f26c3b ("ALSA: hda: Split Realtek HD-audio codec driver") Fixes: 73cd0490819d ("ALSA: hda/hdmi: Split vendor codec drivers") Reported-by: Stephen Rothwell Closes: https://lore.kernel.org/20250715170422.5162c666@canb.auug.org.au Link: https://patch.msgid.link/20250715075237.28476-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- arch/arm/configs/multi_v7_defconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 50c170b4619f..02ddd7ce9e3e 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -791,8 +791,11 @@ CONFIG_SND=m CONFIG_SND_HDA_TEGRA=m CONFIG_SND_HDA_INPUT_BEEP=y CONFIG_SND_HDA_PATCH_LOADER=y -CONFIG_SND_HDA_CODEC_REALTEK=m +CONFIG_SND_HDA_CODEC_REALTEK=y +CONFIG_SND_HDA_CODEC_REALTEK_LIB=m +CONFIG_SND_HDA_CODEC_ALC269=m CONFIG_SND_HDA_CODEC_HDMI=m +CONFIG_SND_HDA_CODEC_HDMI_TEGRA=m CONFIG_SND_USB_AUDIO=m CONFIG_SND_SOC=m CONFIG_SND_ATMEL_SOC=m From f261196d4bf1d413383eb1667e6eb199ff9af875 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Jul 2025 09:51:22 +0200 Subject: [PATCH 363/385] mips: loongson3_defconfig: Update HD-audio configs Since the reorganization of HD-audio drivers, Realtek driver has been split. Update to the new Kconfigs to catch up. Fixes: aeeb85f26c3b ("ALSA: hda: Split Realtek HD-audio codec driver") Link: https://patch.msgid.link/20250715075237.28476-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- arch/mips/configs/loongson3_defconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/mips/configs/loongson3_defconfig b/arch/mips/configs/loongson3_defconfig index 98844b457b7f..5ff0c1554168 100644 --- a/arch/mips/configs/loongson3_defconfig +++ b/arch/mips/configs/loongson3_defconfig @@ -292,7 +292,9 @@ CONFIG_SND_SEQ_DUMMY=m # CONFIG_SND_ISA is not set CONFIG_SND_HDA_INTEL=m CONFIG_SND_HDA_PATCH_LOADER=y -CONFIG_SND_HDA_CODEC_REALTEK=m +CONFIG_SND_HDA_CODEC_REALTEK=y +CONFIG_SND_HDA_CODEC_REALTEK_LIB=m +CONFIG_SND_HDA_CODEC_ALC269=m CONFIG_SND_HDA_CODEC_SIGMATEL=m CONFIG_SND_HDA_CODEC_HDMI=m CONFIG_SND_HDA_CODEC_CONEXANT=m From 3f2e4c11925ee24a34853b0d608ab85df2430555 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 15 Jul 2025 16:17:21 +0100 Subject: [PATCH 364/385] ASoC: SDCA: Fix off by one error in IRQ bound check Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202507150415.M1tCgi3p-lkp@intel.com/ Fixes: b126394d9ec6 ("ASoC: SDCA: Generic interrupt support") Signed-off-by: Charles Keepax Link: https://patch.msgid.link/20250715151723.2964336-2-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/sdca/sdca_interrupts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sdca/sdca_interrupts.c b/sound/soc/sdca/sdca_interrupts.c index 2f85fcc6e544..eb9e7eff4b4b 100644 --- a/sound/soc/sdca/sdca_interrupts.c +++ b/sound/soc/sdca/sdca_interrupts.c @@ -262,7 +262,7 @@ int sdca_irq_request(struct device *dev, struct sdca_interrupt_info *info, { int ret; - if (sdca_irq < 0 || sdca_irq > SDCA_MAX_INTERRUPTS) { + if (sdca_irq < 0 || sdca_irq >= SDCA_MAX_INTERRUPTS) { dev_err(dev, "bad irq request: %d\n", sdca_irq); return -EINVAL; } From 71562278a189af2ca202eafa0ab71a9b68469207 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 15 Jul 2025 16:17:22 +0100 Subject: [PATCH 365/385] ASoC: SDCA: Avoid use of uninitialised local name variable The local name variable is accidentally left over from an earlier version of the code. Remove the variable and its uninitialised usage. Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202507150415.M1tCgi3p-lkp@intel.com/ Fixes: b126394d9ec6 ("ASoC: SDCA: Generic interrupt support") Signed-off-by: Charles Keepax Link: https://patch.msgid.link/20250715151723.2964336-3-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/sdca/sdca_interrupts.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/sdca/sdca_interrupts.c b/sound/soc/sdca/sdca_interrupts.c index eb9e7eff4b4b..b76512732af8 100644 --- a/sound/soc/sdca/sdca_interrupts.c +++ b/sound/soc/sdca/sdca_interrupts.c @@ -342,7 +342,6 @@ int sdca_irq_populate(struct sdca_function_data *function, int irq = control->interrupt_position; struct sdca_interrupt *interrupt; irq_handler_t handler; - const char *name; int ret; if (irq == SDCA_NO_INTERRUPT) { @@ -385,7 +384,7 @@ int sdca_irq_populate(struct sdca_function_data *function, handler, interrupt); if (ret) { dev_err(dev, "failed to request irq %s: %d\n", - name, ret); + interrupt->name, ret); return ret; } } From 15247b5a63f506125360fa45d7aa1fbe8b903b95 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 15 Jul 2025 16:17:23 +0100 Subject: [PATCH 366/385] ASoC: SDCA: Update memory allocations to zero initialise All the memory allocations in the SDCA ASoC helpers rely on fields being zero initialised, the code should use kzalloc not kmalloc. Reported-by: Shuming Fan Fixes: 2c8b3a8e6aa8 ("ASoC: SDCA: Create DAPM widgets and routes from DisCo") Fixes: c3ca24e3fcb6 ("ASoC: SDCA: Create ALSA controls from DisCo") Signed-off-by: Charles Keepax Link: https://patch.msgid.link/20250715151723.2964336-4-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/sdca/sdca_asoc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c index dd7b19083c85..ebb1c87facf9 100644 --- a/sound/soc/sdca/sdca_asoc.c +++ b/sound/soc/sdca/sdca_asoc.c @@ -230,11 +230,11 @@ static int entity_early_parse_ge(struct device *dev, if (!control_name) return -ENOMEM; - kctl = devm_kmalloc(dev, sizeof(*kctl), GFP_KERNEL); + kctl = devm_kzalloc(dev, sizeof(*kctl), GFP_KERNEL); if (!kctl) return -ENOMEM; - soc_enum = devm_kmalloc(dev, sizeof(*soc_enum), GFP_KERNEL); + soc_enum = devm_kzalloc(dev, sizeof(*soc_enum), GFP_KERNEL); if (!soc_enum) return -ENOMEM; @@ -561,11 +561,11 @@ static int entity_parse_su_class(struct device *dev, const char **texts; int i; - kctl = devm_kmalloc(dev, sizeof(*kctl), GFP_KERNEL); + kctl = devm_kzalloc(dev, sizeof(*kctl), GFP_KERNEL); if (!kctl) return -ENOMEM; - soc_enum = devm_kmalloc(dev, sizeof(*soc_enum), GFP_KERNEL); + soc_enum = devm_kzalloc(dev, sizeof(*soc_enum), GFP_KERNEL); if (!soc_enum) return -ENOMEM; @@ -672,7 +672,7 @@ static int entity_parse_mu(struct device *dev, if (!control_name) return -ENOMEM; - mc = devm_kmalloc(dev, sizeof(*mc), GFP_KERNEL); + mc = devm_kzalloc(dev, sizeof(*mc), GFP_KERNEL); if (!mc) return -ENOMEM; @@ -926,7 +926,7 @@ static int populate_control(struct device *dev, if (!control_name) return -ENOMEM; - mc = devm_kmalloc(dev, sizeof(*mc), GFP_KERNEL); + mc = devm_kzalloc(dev, sizeof(*mc), GFP_KERNEL); if (!mc) return -ENOMEM; From 4eb6ad5d2080681b531db2c1764246f9a868062f Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 7 Jul 2025 13:41:49 +0100 Subject: [PATCH 367/385] ASoC: SDCA: Allow read-only controls to be deferrable The current SDCA Control parsing only checks the deferrable flag for Read/Write and Dual Ranked controls. However, reads can defer as well as writes so Read Only controls should also check for the deferrable flag. Add the handling for this into find_sdca_entity_control(). Fixes: 42b144cb6a2d ("ASoC: SDCA: Add SDCA Control parsing") Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250707124155.2596744-2-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/sdca/sdca_functions.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index be09b7a34102..7392ddcdd483 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -881,7 +881,8 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti control->value = tmp; control->has_fixed = true; } - + fallthrough; + case SDCA_ACCESS_MODE_RO: control->deferrable = fwnode_property_read_bool(control_node, "mipi-sdca-control-deferrable"); break; From cbcb5f5c2be523ef0908df290b3033138bd4c185 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 7 Jul 2025 13:41:50 +0100 Subject: [PATCH 368/385] ASoC: SDCA: Remove overly chatty input pin list warning An input pin list is not generally required, so a warning on the absence of one is a little extreme, remove this warning message. Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250707124155.2596744-3-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/sdca/sdca_functions.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index 7392ddcdd483..e567e364dc31 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -1635,7 +1635,6 @@ static int find_sdca_entity_connection(struct device *dev, ret = fwnode_property_read_u64(entity_node, "mipi-sdca-input-pin-list", &pin_list); if (ret == -EINVAL) { /* Allow missing pin lists, assume no pins. */ - dev_warn(dev, "%s: missing pin list\n", entity->label); return 0; } else if (ret) { dev_err(dev, "%s: failed to read pin list: %d\n", entity->label, ret); From c57ad862462f064c0bd943a5828f5e0eca469ca5 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 7 Jul 2025 13:41:51 +0100 Subject: [PATCH 369/385] ASoC: SDCA: Move SDCA search functions and export The ASoC code for SDCA contains several helper functions that search for controls/ranges/etc. As the code evolves these helpers are likely to be useful to anything interacting with the stored DisCo data. Move the helpers into sdca_function.c and export them so other modules can also use them. Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250707124155.2596744-4-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/sdca_function.h | 11 +++++ sound/soc/sdca/sdca_asoc.c | 73 ++++++--------------------------- sound/soc/sdca/sdca_functions.c | 50 ++++++++++++++++++++++ 3 files changed, 74 insertions(+), 60 deletions(-) diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h index b4a97ff08729..543c09e99ab1 100644 --- a/include/sound/sdca_function.h +++ b/include/sound/sdca_function.h @@ -1316,4 +1316,15 @@ int sdca_parse_function(struct device *dev, struct sdca_function_desc *desc, struct sdca_function_data *function); +struct sdca_control *sdca_selector_find_control(struct device *dev, + struct sdca_entity *entity, + const int sel); +struct sdca_control_range *sdca_control_find_range(struct device *dev, + struct sdca_entity *entity, + struct sdca_control *control, + int cols, int rows); +struct sdca_control_range *sdca_selector_find_range(struct device *dev, + struct sdca_entity *entity, + int sel, int cols, int rows); + #endif diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c index dd7b19083c85..11c9b3b935fc 100644 --- a/sound/soc/sdca/sdca_asoc.c +++ b/sound/soc/sdca/sdca_asoc.c @@ -26,53 +26,6 @@ #include #include -static struct sdca_control *selector_find_control(struct device *dev, - struct sdca_entity *entity, - const int sel) -{ - int i; - - for (i = 0; i < entity->num_controls; i++) { - struct sdca_control *control = &entity->controls[i]; - - if (control->sel == sel) - return control; - } - - dev_err(dev, "%s: control %#x: missing\n", entity->label, sel); - return NULL; -} - -static struct sdca_control_range *control_find_range(struct device *dev, - struct sdca_entity *entity, - struct sdca_control *control, - int cols, int rows) -{ - struct sdca_control_range *range = &control->range; - - if ((cols && range->cols != cols) || (rows && range->rows != rows) || - !range->data) { - dev_err(dev, "%s: control %#x: ranges invalid (%d,%d)\n", - entity->label, control->sel, range->cols, range->rows); - return NULL; - } - - return range; -} - -static struct sdca_control_range *selector_find_range(struct device *dev, - struct sdca_entity *entity, - int sel, int cols, int rows) -{ - struct sdca_control *control; - - control = selector_find_control(dev, entity, sel); - if (!control) - return NULL; - - return control_find_range(dev, entity, control, cols, rows); -} - static bool exported_control(struct sdca_entity *entity, struct sdca_control *control) { switch (SDCA_CTL_TYPE(entity->type, control->sel)) { @@ -213,7 +166,7 @@ static int entity_early_parse_ge(struct device *dev, const char **texts; int i; - control = selector_find_control(dev, entity, SDCA_CTL_GE_SELECTED_MODE); + control = sdca_selector_find_control(dev, entity, SDCA_CTL_GE_SELECTED_MODE); if (!control) return -EINVAL; @@ -221,7 +174,7 @@ static int entity_early_parse_ge(struct device *dev, dev_warn(dev, "%s: unexpected access layer: %x\n", entity->label, control->layers); - range = control_find_range(dev, entity, control, SDCA_SELECTED_MODE_NCOLS, 0); + range = sdca_control_find_range(dev, entity, control, SDCA_SELECTED_MODE_NCOLS, 0); if (!range) return -EINVAL; @@ -443,7 +396,7 @@ static int entity_parse_pde(struct device *dev, unsigned int mask = 0; int i; - control = selector_find_control(dev, entity, SDCA_CTL_PDE_REQUESTED_PS); + control = sdca_selector_find_control(dev, entity, SDCA_CTL_PDE_REQUESTED_PS); if (!control) return -EINVAL; @@ -452,7 +405,7 @@ static int entity_parse_pde(struct device *dev, dev_warn(dev, "%s: unexpected access layer: %x\n", entity->label, control->layers); - range = control_find_range(dev, entity, control, SDCA_REQUESTED_PS_NCOLS, 0); + range = sdca_control_find_range(dev, entity, control, SDCA_REQUESTED_PS_NCOLS, 0); if (!range) return -EINVAL; @@ -499,8 +452,8 @@ static int entity_parse_su_device(struct device *dev, return -EINVAL; } - range = selector_find_range(dev, entity->group, SDCA_CTL_GE_SELECTED_MODE, - SDCA_SELECTED_MODE_NCOLS, 0); + range = sdca_selector_find_range(dev, entity->group, SDCA_CTL_GE_SELECTED_MODE, + SDCA_SELECTED_MODE_NCOLS, 0); if (!range) return -EINVAL; @@ -613,7 +566,7 @@ static int entity_parse_su(struct device *dev, return -EINVAL; } - control = selector_find_control(dev, entity, SDCA_CTL_SU_SELECTOR); + control = sdca_selector_find_control(dev, entity, SDCA_CTL_SU_SELECTOR); if (!control) return -EINVAL; @@ -643,7 +596,7 @@ static int entity_parse_mu(struct device *dev, return -EINVAL; } - control = selector_find_control(dev, entity, SDCA_CTL_MU_MIXER); + control = sdca_selector_find_control(dev, entity, SDCA_CTL_MU_MIXER); if (!control) return -EINVAL; @@ -853,7 +806,7 @@ static int control_limit_kctl(struct device *dev, /* * FIXME: For now only handle the simple case of a single linear range */ - range = control_find_range(dev, entity, control, SDCA_VOLUME_LINEAR_NCOLS, 1); + range = sdca_control_find_range(dev, entity, control, SDCA_VOLUME_LINEAR_NCOLS, 1); if (!range) return -EINVAL; @@ -1140,9 +1093,9 @@ static int populate_rate_format(struct device *dev, } if (entity->iot.clock) { - range = selector_find_range(dev, entity->iot.clock, - SDCA_CTL_CS_SAMPLERATEINDEX, - SDCA_SAMPLERATEINDEX_NCOLS, 0); + range = sdca_selector_find_range(dev, entity->iot.clock, + SDCA_CTL_CS_SAMPLERATEINDEX, + SDCA_SAMPLERATEINDEX_NCOLS, 0); if (!range) return -EINVAL; @@ -1154,7 +1107,7 @@ static int populate_rate_format(struct device *dev, clock_rates = UINT_MAX; } - range = selector_find_range(dev, entity, sel, SDCA_USAGE_NCOLS, 0); + range = sdca_selector_find_range(dev, entity, sel, SDCA_USAGE_NCOLS, 0); if (!range) return -EINVAL; diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index e567e364dc31..d2e2c8d10b92 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -1941,5 +1941,55 @@ int sdca_parse_function(struct device *dev, } EXPORT_SYMBOL_NS(sdca_parse_function, "SND_SOC_SDCA"); +struct sdca_control *sdca_selector_find_control(struct device *dev, + struct sdca_entity *entity, + const int sel) +{ + int i; + + for (i = 0; i < entity->num_controls; i++) { + struct sdca_control *control = &entity->controls[i]; + + if (control->sel == sel) + return control; + } + + dev_err(dev, "%s: control %#x: missing\n", entity->label, sel); + return NULL; +} +EXPORT_SYMBOL_NS(sdca_selector_find_control, "SND_SOC_SDCA"); + +struct sdca_control_range *sdca_control_find_range(struct device *dev, + struct sdca_entity *entity, + struct sdca_control *control, + int cols, int rows) +{ + struct sdca_control_range *range = &control->range; + + if ((cols && range->cols != cols) || (rows && range->rows != rows) || + !range->data) { + dev_err(dev, "%s: control %#x: ranges invalid (%d,%d)\n", + entity->label, control->sel, range->cols, range->rows); + return NULL; + } + + return range; +} +EXPORT_SYMBOL_NS(sdca_control_find_range, "SND_SOC_SDCA"); + +struct sdca_control_range *sdca_selector_find_range(struct device *dev, + struct sdca_entity *entity, + int sel, int cols, int rows) +{ + struct sdca_control *control; + + control = sdca_selector_find_control(dev, entity, sel); + if (!control) + return NULL; + + return sdca_control_find_range(dev, entity, control, cols, rows); +} +EXPORT_SYMBOL_NS(sdca_selector_find_range, "SND_SOC_SDCA"); + MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SDCA library"); From 5f86d41d0410b072b5f4875ef5d38bf8d18eed55 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 7 Jul 2025 13:41:52 +0100 Subject: [PATCH 370/385] ASoC: soc-dai: Add private data to snd_soc_dai Add a private data pointer that can be used to store context along with the DAI. This will be useful to allow the SDCA class library to store data separately from the CODEC driver itself. Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250707124155.2596744-5-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index d19ab5572d2b..166c29557e9d 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -463,6 +463,9 @@ struct snd_soc_dai { /* bit field */ unsigned int probed:1; + + /* DAI private data */ + void *priv; }; static inline const struct snd_soc_pcm_stream * From 7b0d60dbb468fa82e9053292cdc8a5436400bfaf Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 7 Jul 2025 13:41:53 +0100 Subject: [PATCH 371/385] ASoC: SDCA: Add helper to add DAI constraints Currently the core SDCA code simply creates a place holder available channels from 1 to SDCA_MAX_CHANNEL_COUNT. Add a helper function that will constrain the number of channels based on the actual available SDCA Clusters in DisCo. Currently this code only handles Input Terminal Entities as they directly specify the Cluster. More work will be required later for Output Terminals which inherit their Cluster. Typically this new helper would be called from the DAIs startup callback. Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250707124155.2596744-6-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/sdca_asoc.h | 10 ++++ include/sound/sdca_function.h | 12 ++++ sound/soc/sdca/sdca_asoc.c | 99 +++++++++++++++++++++++++++++++++ sound/soc/sdca/sdca_functions.c | 18 ++++++ 4 files changed, 139 insertions(+) diff --git a/include/sound/sdca_asoc.h b/include/sound/sdca_asoc.h index 9121531f0826..bbf146e4fcea 100644 --- a/include/sound/sdca_asoc.h +++ b/include/sound/sdca_asoc.h @@ -11,9 +11,12 @@ #define __SDCA_ASOC_H__ struct device; +struct regmap; struct sdca_function_data; struct snd_kcontrol_new; +struct snd_pcm_substream; struct snd_soc_component_driver; +struct snd_soc_dai; struct snd_soc_dai_driver; struct snd_soc_dai_ops; struct snd_soc_dapm_route; @@ -39,4 +42,11 @@ int sdca_asoc_populate_component(struct device *dev, struct snd_soc_dai_driver **dai_drv, int *num_dai_drv, const struct snd_soc_dai_ops *ops); +int sdca_asoc_set_constraints(struct device *dev, struct regmap *regmap, + struct sdca_function_data *function, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +void sdca_asoc_free_constraints(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); + #endif // __SDCA_ASOC_H__ diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h index 543c09e99ab1..3bde07409bf3 100644 --- a/include/sound/sdca_function.h +++ b/include/sound/sdca_function.h @@ -1268,6 +1268,15 @@ struct sdca_cluster { struct sdca_channel *channels; }; +/** + * enum sdca_cluster_range - SDCA Range column definitions for ClusterIndex + */ +enum sdca_cluster_range { + SDCA_CLUSTER_BYTEINDEX = 0, + SDCA_CLUSTER_CLUSTERID = 1, + SDCA_CLUSTER_NCOLS = 2, +}; + /** * struct sdca_function_data - top-level information for one SDCA function * @desc: Pointer to short descriptor from initial parsing. @@ -1326,5 +1335,8 @@ struct sdca_control_range *sdca_control_find_range(struct device *dev, struct sdca_control_range *sdca_selector_find_range(struct device *dev, struct sdca_entity *entity, int sel, int cols, int rows); +struct sdca_cluster *sdca_id_find_cluster(struct device *dev, + struct sdca_function_data *function, + const int id); #endif diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c index 11c9b3b935fc..1a0149287584 100644 --- a/sound/soc/sdca/sdca_asoc.c +++ b/sound/soc/sdca/sdca_asoc.c @@ -7,16 +7,20 @@ * https://www.mipi.org/mipi-sdca-v1-0-download */ +#include #include +#include #include #include #include #include #include #include +#include #include #include #include +#include #include #include #include @@ -1269,3 +1273,98 @@ int sdca_asoc_populate_component(struct device *dev, return 0; } EXPORT_SYMBOL_NS(sdca_asoc_populate_component, "SND_SOC_SDCA"); + +/** + * sdca_asoc_set_constraints - constrain channels available on a DAI + * @dev: Pointer to the device, used for error messages. + * @regmap: Pointer to the Function register map. + * @function: Pointer to the Function information. + * @substream: Pointer to the PCM substream. + * @dai: Pointer to the ASoC DAI. + * + * Typically called from startup(). + * + * Return: Returns zero on success, and a negative error code on failure. + */ +int sdca_asoc_set_constraints(struct device *dev, struct regmap *regmap, + struct sdca_function_data *function, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + static const unsigned int channel_list[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + }; + struct sdca_entity *entity = &function->entities[dai->id]; + struct snd_pcm_hw_constraint_list *constraint; + struct sdca_control_range *range; + struct sdca_control *control; + unsigned int channel_mask = 0; + int i, ret; + + static_assert(ARRAY_SIZE(channel_list) == SDCA_MAX_CHANNEL_COUNT); + static_assert(sizeof(channel_mask) * BITS_PER_BYTE >= SDCA_MAX_CHANNEL_COUNT); + + if (entity->type != SDCA_ENTITY_TYPE_IT) + return 0; + + control = sdca_selector_find_control(dev, entity, SDCA_CTL_IT_CLUSTERINDEX); + if (!control) + return -EINVAL; + + range = sdca_control_find_range(dev, entity, control, SDCA_CLUSTER_NCOLS, 0); + if (!range) + return -EINVAL; + + for (i = 0; i < range->rows; i++) { + int clusterid = sdca_range(range, SDCA_CLUSTER_CLUSTERID, i); + struct sdca_cluster *cluster; + + cluster = sdca_id_find_cluster(dev, function, clusterid); + if (!cluster) + return -ENODEV; + + channel_mask |= (1 << (cluster->num_channels - 1)); + } + + dev_dbg(dev, "%s: set channel constraint mask: %#x\n", + entity->label, channel_mask); + + constraint = kzalloc(sizeof(*constraint), GFP_KERNEL); + if (!constraint) + return -ENOMEM; + + constraint->count = ARRAY_SIZE(channel_list); + constraint->list = channel_list; + constraint->mask = channel_mask; + + ret = snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + constraint); + if (ret) { + dev_err(dev, "%s: failed to add constraint: %d\n", entity->label, ret); + kfree(constraint); + return ret; + } + + dai->priv = constraint; + + return 0; +} +EXPORT_SYMBOL_NS(sdca_asoc_set_constraints, "SND_SOC_SDCA"); + +/** + * sdca_asoc_free_constraints - free constraint allocations + * @substream: Pointer to the PCM substream. + * @dai: Pointer to the ASoC DAI. + * + * Typically called from shutdown(). + */ +void sdca_asoc_free_constraints(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_pcm_hw_constraint_list *constraint = dai->priv; + + kfree(constraint); +} +EXPORT_SYMBOL_NS(sdca_asoc_free_constraints, "SND_SOC_SDCA"); diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index d2e2c8d10b92..4b6da587c4ac 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -1991,5 +1991,23 @@ struct sdca_control_range *sdca_selector_find_range(struct device *dev, } EXPORT_SYMBOL_NS(sdca_selector_find_range, "SND_SOC_SDCA"); +struct sdca_cluster *sdca_id_find_cluster(struct device *dev, + struct sdca_function_data *function, + const int id) +{ + int i; + + for (i = 0; i < function->num_clusters; i++) { + struct sdca_cluster *cluster = &function->clusters[i]; + + if (cluster->id == id) + return cluster; + } + + dev_err(dev, "%s: cluster %#x: missing\n", function->desc->name, id); + return NULL; +} +EXPORT_SYMBOL_NS(sdca_id_find_cluster, "SND_SOC_SDCA"); + MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SDCA library"); From 264d3d776fb1a428706b0ca0f679bbed876fe7c9 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 7 Jul 2025 13:41:54 +0100 Subject: [PATCH 372/385] ASoC: SDCA: Add a helper to get the SoundWire port number Add a helper function to extract the SoundWire hardware port number from the SDCA DataPort Selector Control. Typically this would be called from hw_params() and used to call sdw_stream_add_slave(). Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250707124155.2596744-7-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/sdca_asoc.h | 3 ++ include/sound/sdca_function.h | 8 ++++ sound/soc/sdca/sdca_asoc.c | 75 +++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/include/sound/sdca_asoc.h b/include/sound/sdca_asoc.h index bbf146e4fcea..800a26adcd8e 100644 --- a/include/sound/sdca_asoc.h +++ b/include/sound/sdca_asoc.h @@ -48,5 +48,8 @@ int sdca_asoc_set_constraints(struct device *dev, struct regmap *regmap, struct snd_soc_dai *dai); void sdca_asoc_free_constraints(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); +int sdca_asoc_get_port(struct device *dev, struct regmap *regmap, + struct sdca_function_data *function, + struct snd_soc_dai *dai); #endif // __SDCA_ASOC_H__ diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h index 3bde07409bf3..90d77fc46416 100644 --- a/include/sound/sdca_function.h +++ b/include/sound/sdca_function.h @@ -185,6 +185,14 @@ enum sdca_usage_range { SDCA_USAGE_NCOLS = 7, }; +/** + * enum sdca_dataport_selector_range - Column definitions for DataPort_Selector + */ +enum sdca_dataport_selector_range { + SDCA_DATAPORT_SELECTOR_NCOLS = 16, + SDCA_DATAPORT_SELECTOR_NROWS = 4, +}; + /** * enum sdca_mu_controls - SDCA Controls for Mixer Unit * diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c index 1a0149287584..03c663413cc9 100644 --- a/sound/soc/sdca/sdca_asoc.c +++ b/sound/soc/sdca/sdca_asoc.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -1368,3 +1369,77 @@ void sdca_asoc_free_constraints(struct snd_pcm_substream *substream, kfree(constraint); } EXPORT_SYMBOL_NS(sdca_asoc_free_constraints, "SND_SOC_SDCA"); + +/** + * sdca_asoc_get_port - return SoundWire port for a DAI + * @dev: Pointer to the device, used for error messages. + * @regmap: Pointer to the Function register map. + * @function: Pointer to the Function information. + * @dai: Pointer to the ASoC DAI. + * + * Typically called from hw_params(). + * + * Return: Returns a positive port number on success, and a negative error + * code on failure. + */ +int sdca_asoc_get_port(struct device *dev, struct regmap *regmap, + struct sdca_function_data *function, + struct snd_soc_dai *dai) +{ + struct sdca_entity *entity = &function->entities[dai->id]; + struct sdca_control_range *range; + unsigned int reg, val; + int sel = -EINVAL; + int i, ret; + + switch (entity->type) { + case SDCA_ENTITY_TYPE_IT: + sel = SDCA_CTL_IT_DATAPORT_SELECTOR; + break; + case SDCA_ENTITY_TYPE_OT: + sel = SDCA_CTL_OT_DATAPORT_SELECTOR; + break; + default: + break; + } + + if (sel < 0 || !entity->iot.is_dataport) { + dev_err(dev, "%s: port number only available for dataports\n", + entity->label); + return -EINVAL; + } + + range = sdca_selector_find_range(dev, entity, sel, SDCA_DATAPORT_SELECTOR_NCOLS, + SDCA_DATAPORT_SELECTOR_NROWS); + if (!range) + return -EINVAL; + + reg = SDW_SDCA_CTL(function->desc->adr, entity->id, sel, 0); + + ret = regmap_read(regmap, reg, &val); + if (ret) { + dev_err(dev, "%s: failed to read dataport selector: %d\n", + entity->label, ret); + return ret; + } + + for (i = 0; i < range->rows; i++) { + static const u8 port_mask = 0xF; + + sel = sdca_range(range, val & port_mask, i); + + /* + * FIXME: Currently only a single dataport is supported, so + * return the first one found, technically up to 4 dataports + * could be linked, but this is not yet supported. + */ + if (sel != 0xFF) + return sel; + + val >>= hweight8(port_mask); + } + + dev_err(dev, "%s: no dataport found\n", entity->label); + return -ENODEV; +} +EXPORT_SYMBOL_NS(sdca_asoc_get_port, "SND_SOC_SDCA"); From 4ed357f72a0e0a691304e5f14a3323811c8ce862 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 7 Jul 2025 13:41:55 +0100 Subject: [PATCH 373/385] ASoC: SDCA: Add hw_params() helper function Add a helper function that can be called from hw_params() in the DAI ops to configure the SDCA Cluster, Clock and Usage controls. These setup the channels, sample rate, and bit depths that will be used by the Terminal. Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250707124155.2596744-8-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/sdca_asoc.h | 6 ++ sound/soc/sdca/sdca_asoc.c | 180 +++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) diff --git a/include/sound/sdca_asoc.h b/include/sound/sdca_asoc.h index 800a26adcd8e..aa9124f93218 100644 --- a/include/sound/sdca_asoc.h +++ b/include/sound/sdca_asoc.h @@ -14,6 +14,7 @@ struct device; struct regmap; struct sdca_function_data; struct snd_kcontrol_new; +struct snd_pcm_hw_params; struct snd_pcm_substream; struct snd_soc_component_driver; struct snd_soc_dai; @@ -51,5 +52,10 @@ void sdca_asoc_free_constraints(struct snd_pcm_substream *substream, int sdca_asoc_get_port(struct device *dev, struct regmap *regmap, struct sdca_function_data *function, struct snd_soc_dai *dai); +int sdca_asoc_hw_params(struct device *dev, struct regmap *regmap, + struct sdca_function_data *function, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); #endif // __SDCA_ASOC_H__ diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c index 03c663413cc9..252d72377091 100644 --- a/sound/soc/sdca/sdca_asoc.c +++ b/sound/soc/sdca/sdca_asoc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -1443,3 +1444,182 @@ int sdca_asoc_get_port(struct device *dev, struct regmap *regmap, return -ENODEV; } EXPORT_SYMBOL_NS(sdca_asoc_get_port, "SND_SOC_SDCA"); + +static int set_cluster(struct device *dev, struct regmap *regmap, + struct sdca_function_data *function, + struct sdca_entity *entity, unsigned int channels) +{ + int sel = SDCA_CTL_IT_CLUSTERINDEX; + struct sdca_control_range *range; + int i, ret; + + range = sdca_selector_find_range(dev, entity, sel, SDCA_CLUSTER_NCOLS, 0); + if (!range) + return -EINVAL; + + for (i = 0; i < range->rows; i++) { + int cluster_id = sdca_range(range, SDCA_CLUSTER_CLUSTERID, i); + struct sdca_cluster *cluster; + + cluster = sdca_id_find_cluster(dev, function, cluster_id); + if (!cluster) + return -ENODEV; + + if (cluster->num_channels == channels) { + int index = sdca_range(range, SDCA_CLUSTER_BYTEINDEX, i); + unsigned int reg = SDW_SDCA_CTL(function->desc->adr, + entity->id, sel, 0); + + ret = regmap_update_bits(regmap, reg, 0xFF, index); + if (ret) { + dev_err(dev, "%s: failed to write cluster index: %d\n", + entity->label, ret); + return ret; + } + + dev_dbg(dev, "%s: set cluster to %d (%d channels)\n", + entity->label, index, channels); + + return 0; + } + } + + dev_err(dev, "%s: no cluster for %d channels\n", entity->label, channels); + return -EINVAL; +} + +static int set_clock(struct device *dev, struct regmap *regmap, + struct sdca_function_data *function, + struct sdca_entity *entity, int target_rate) +{ + int sel = SDCA_CTL_CS_SAMPLERATEINDEX; + struct sdca_control_range *range; + int i, ret; + + range = sdca_selector_find_range(dev, entity, sel, SDCA_SAMPLERATEINDEX_NCOLS, 0); + if (!range) + return -EINVAL; + + for (i = 0; i < range->rows; i++) { + unsigned int rate = sdca_range(range, SDCA_SAMPLERATEINDEX_RATE, i); + + if (rate == target_rate) { + unsigned int index = sdca_range(range, + SDCA_SAMPLERATEINDEX_INDEX, + i); + unsigned int reg = SDW_SDCA_CTL(function->desc->adr, + entity->id, sel, 0); + + ret = regmap_update_bits(regmap, reg, 0xFF, index); + if (ret) { + dev_err(dev, "%s: failed to write clock rate: %d\n", + entity->label, ret); + return ret; + } + + dev_dbg(dev, "%s: set clock rate to %d (%dHz)\n", + entity->label, index, rate); + + return 0; + } + } + + dev_err(dev, "%s: no clock rate for %dHz\n", entity->label, target_rate); + return -EINVAL; +} + +static int set_usage(struct device *dev, struct regmap *regmap, + struct sdca_function_data *function, + struct sdca_entity *entity, int sel, + int target_rate, int target_width) +{ + struct sdca_control_range *range; + int i, ret; + + range = sdca_selector_find_range(dev, entity, sel, SDCA_USAGE_NCOLS, 0); + if (!range) + return -EINVAL; + + for (i = 0; i < range->rows; i++) { + unsigned int rate = sdca_range(range, SDCA_USAGE_SAMPLE_RATE, i); + unsigned int width = sdca_range(range, SDCA_USAGE_SAMPLE_WIDTH, i); + + if ((!rate || rate == target_rate) && width == target_width) { + unsigned int usage = sdca_range(range, SDCA_USAGE_NUMBER, i); + unsigned int reg = SDW_SDCA_CTL(function->desc->adr, + entity->id, sel, 0); + + ret = regmap_update_bits(regmap, reg, 0xFF, usage); + if (ret) { + dev_err(dev, "%s: failed to write usage: %d\n", + entity->label, ret); + return ret; + } + + dev_dbg(dev, "%s: set usage to %#x (%dHz, %d bits)\n", + entity->label, usage, target_rate, target_width); + + return 0; + } + } + + dev_err(dev, "%s: no usage for %dHz, %dbits\n", + entity->label, target_rate, target_width); + return -EINVAL; +} + +/** + * sdca_asoc_hw_params - set SDCA channels, sample rate and bit depth + * @dev: Pointer to the device, used for error messages. + * @regmap: Pointer to the Function register map. + * @function: Pointer to the Function information. + * @substream: Pointer to the PCM substream. + * @params: Pointer to the hardware parameters. + * @dai: Pointer to the ASoC DAI. + * + * Typically called from hw_params(). + * + * Return: Returns zero on success, and a negative error code on failure. + */ +int sdca_asoc_hw_params(struct device *dev, struct regmap *regmap, + struct sdca_function_data *function, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct sdca_entity *entity = &function->entities[dai->id]; + int channels = params_channels(params); + int width = params_width(params); + int rate = params_rate(params); + int usage_sel; + int ret; + + switch (entity->type) { + case SDCA_ENTITY_TYPE_IT: + ret = set_cluster(dev, regmap, function, entity, channels); + if (ret) + return ret; + + usage_sel = SDCA_CTL_IT_USAGE; + break; + case SDCA_ENTITY_TYPE_OT: + usage_sel = SDCA_CTL_OT_USAGE; + break; + default: + dev_err(dev, "%s: hw_params on non-terminal entity\n", entity->label); + return -EINVAL; + } + + if (entity->iot.clock) { + ret = set_clock(dev, regmap, function, entity->iot.clock, rate); + if (ret) + return ret; + } + + ret = set_usage(dev, regmap, function, entity, usage_sel, rate, width); + if (ret) + return ret; + + return 0; +} +EXPORT_SYMBOL_NS(sdca_asoc_hw_params, "SND_SOC_SDCA"); From aa84580e058c4d7567b2a5e5a9d12f94af75d297 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 16 Jul 2025 09:49:58 +0200 Subject: [PATCH 374/385] ASoC: dt-bindings: qcom,lpass-va-macro: Define clock-names in top-level Device variants use different amount of clock inputs, but all of them are in the same order, 'clock-names' in top-level properties can define the list and each if:then: block can only narrow the number of items. This is preferred syntax, because it keeps list unified among devices and encourages adding new entries to the end of the list, instead of adding them in the middle. The change has no functional impact, but partially reverts approach implemented in commit cfad817095e1 ("ASoC: dt-bindings: qcom,lpass-va-macro: Add missing NPL clock"). Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250716074957.102402-2-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- .../bindings/sound/qcom,lpass-va-macro.yaml | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml index f41deaa6f4df..dd549db6c841 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml @@ -40,7 +40,11 @@ properties: clock-names: minItems: 1 - maxItems: 4 + items: + - const: mclk + - const: macro + - const: dcodec + - const: npl clock-output-names: maxItems: 1 @@ -80,8 +84,7 @@ allOf: clocks: maxItems: 1 clock-names: - items: - - const: mclk + maxItems: 1 - if: properties: @@ -94,10 +97,8 @@ allOf: minItems: 3 maxItems: 3 clock-names: - items: - - const: mclk - - const: macro - - const: dcodec + minItems: 3 + maxItems: 3 - if: properties: @@ -112,11 +113,8 @@ allOf: minItems: 4 maxItems: 4 clock-names: - items: - - const: mclk - - const: macro - - const: dcodec - - const: npl + minItems: 4 + maxItems: 4 - if: properties: @@ -130,10 +128,8 @@ allOf: minItems: 3 maxItems: 3 clock-names: - items: - - const: mclk - - const: macro - - const: dcodec + minItems: 3 + maxItems: 3 unevaluatedProperties: false From 8778837f0a5b7c1bc5dbf0cccd7619fec6981588 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 16 Jul 2025 08:57:07 +0200 Subject: [PATCH 375/385] ASoC: codec: tlv320aic32x4: Fix reset GPIO check rstn_gpio being a GPIO descriptor the check is wrong (inverted) for releasing the reset of the codec. Fixes: 790d5f8ee6f2 ("ASoC: codec: tlv320aic32x4: Convert to GPIO descriptors") Signed-off-by: Alexander Stein Reviewed-by: Peng Fan Link: https://patch.msgid.link/20250716065708.4041153-1-alexander.stein@ew.tq-group.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 3b89980e9bcf..7399080f8580 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -1388,7 +1388,7 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap, return ret; } - if (!aic32x4->rstn_gpio) { + if (aic32x4->rstn_gpio) { ndelay(10); /* deassert reset */ gpiod_set_value_cansleep(aic32x4->rstn_gpio, 0); From 03aa2ed9e187e42f25b3871b691d535fc19156c4 Mon Sep 17 00:00:00 2001 From: Balamurugan C Date: Wed, 16 Jul 2025 16:23:00 +0800 Subject: [PATCH 376/385] ASoC: Intel: sof_rt5682: Add HDMI-In capture with rt5682 support for PTL. Added match table entry on ptl machines to support HDMI-In capture with rt5682 I2S audio codec. also added the respective quirk configuration in rt5682 machine driver. Signed-off-by: Balamurugan C Signed-off-by: Bard Liao Link: https://patch.msgid.link/20250716082300.1810352-1-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_rt5682.c | 7 +++++++ sound/soc/intel/common/soc-acpi-intel-ptl-match.c | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index f5925bd0a3fc..4994aaccc583 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -892,6 +892,13 @@ static const struct platform_device_id board_ids[] = { SOF_SSP_PORT_BT_OFFLOAD(2) | SOF_BT_OFFLOAD_PRESENT), }, + { + .name = "ptl_rt5682_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(1) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_SSP_MASK_HDMI_CAPTURE(0x5)), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c index a8fee8cf4913..e292701dfcfe 100644 --- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c @@ -32,6 +32,13 @@ static const struct snd_soc_acpi_codecs ptl_lt6911_hdmi = { }; struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_machines[] = { + { + .comp_ids = &ptl_rt5682_rt5682s_hp, + .drv_name = "ptl_rt5682_c1_h02", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &ptl_lt6911_hdmi, + .sof_tplg_filename = "sof-ptl-rt5682-ssp1-hdmi-ssp02.tplg", + }, { .comp_ids = &ptl_rt5682_rt5682s_hp, .drv_name = "ptl_rt5682_def", From 0156c22fb0ca869381fe0520731da79f70389652 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Mon, 21 Jul 2025 14:54:05 +0100 Subject: [PATCH 377/385] ALSA: hda/realtek: Add support for ASUS Commercial laptops using CS35L41 HDA Add support for ASUS PM3406CKA and PM3606CKA. Laptops use 2 CS35L41 Amps with HDA, using Internal boost, with I2C Signed-off-by: Stefan Binding Link: https://patch.msgid.link/20250721135406.366912-1-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/hda/codecs/realtek/alc269.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index dc3ee1256c2b..88fc835c7088 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -6682,6 +6682,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), SND_PCI_QUIRK(0x1043, 0x1433, "ASUS GX650PY/PZ/PV/PU/PYV/PZV/PIV/PVV", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1454, "ASUS PM3406CKA", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x1460, "Asus VivoBook 15", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1463, "Asus GA402X/GA402N", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x1473, "ASUS GU604VI/VC/VE/VG/VJ/VQ/VU/VV/VY/VZ", ALC285_FIXUP_ASUS_HEADSET_MIC), @@ -6776,6 +6777,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x31d0, "ASUS Zen AIO 27 Z272SD_A272SD", ALC274_FIXUP_ASUS_ZEN_AIO_27), SND_PCI_QUIRK(0x1043, 0x31e1, "ASUS B5605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x31f1, "ASUS B3605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x3391, "ASUS PM3606CKA", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x3a20, "ASUS G614JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), SND_PCI_QUIRK(0x1043, 0x3a30, "ASUS G814JVR/JIR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), SND_PCI_QUIRK(0x1043, 0x3a40, "ASUS G814JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), From 17882721dcb49323eaa9728d7eaa2ae826c876f7 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Mon, 21 Jul 2025 19:23:46 +0800 Subject: [PATCH 378/385] ASoC: SDCA: add route by the number of input pins in MU entity This patch removed the code where num_sources should be the same as cn_list. For better resilience, it would be preferable to explicitly add the route mapping the input pins to this MU entity. Signed-off-by: Shuming Fan Reviewed-by: Charles Keepax Link: https://patch.msgid.link/20250721112346.388542-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/sdca/sdca_asoc.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c index 1482869a7ad5..c493ec530cc5 100644 --- a/sound/soc/sdca/sdca_asoc.c +++ b/sound/soc/sdca/sdca_asoc.c @@ -594,7 +594,6 @@ static int entity_parse_mu(struct device *dev, { struct sdca_control *control; struct snd_kcontrol_new *kctl; - int cn; int i; if (!entity->num_sources) { @@ -611,18 +610,11 @@ static int entity_parse_mu(struct device *dev, dev_warn(dev, "%s: unexpected access layer: %x\n", entity->label, control->layers); - if (entity->num_sources != hweight64(control->cn_list)) { - dev_err(dev, "%s: mismatched control and sources\n", entity->label); - return -EINVAL; - } - kctl = devm_kcalloc(dev, entity->num_sources, sizeof(*kctl), GFP_KERNEL); if (!kctl) return -ENOMEM; - i = 0; - for_each_set_bit(cn, (unsigned long *)&control->cn_list, - BITS_PER_TYPE(control->cn_list)) { + for (i = 0; i < entity->num_sources; i++) { const char *control_name; struct soc_mixer_control *mc; @@ -647,7 +639,6 @@ static int entity_parse_mu(struct device *dev, kctl[i].info = snd_soc_info_volsw; kctl[i].get = snd_soc_dapm_get_volsw; kctl[i].put = snd_soc_dapm_put_volsw; - i++; } (*widget)->id = snd_soc_dapm_mixer; From 5b838a24e9942d8b8da208f924701d0f989778cf Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 22 Jul 2025 11:27:54 +0100 Subject: [PATCH 379/385] ASoC: SDCA: Check devm_mutex_init() return value Fix interaction with commit daec29dcc873 ("locking/mutex: Mark devm_mutex_init() as __must_check"), add return value check. There is no need for additional complex error handling here, failure to init the mutex means the code can't progress, so the failure just needs to be passed up to the caller. Fixes: b126394d9ec6 ("ASoC: SDCA: Generic interrupt support") Signed-off-by: Stephen Rothwell Signed-off-by: Charles Keepax Link: https://patch.msgid.link/20250722102754.2514351-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/sdca/sdca_interrupts.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/sdca/sdca_interrupts.c b/sound/soc/sdca/sdca_interrupts.c index b76512732af8..d442ba2f5681 100644 --- a/sound/soc/sdca/sdca_interrupts.c +++ b/sound/soc/sdca/sdca_interrupts.c @@ -419,7 +419,9 @@ struct sdca_interrupt_info *sdca_irq_allocate(struct device *dev, info->irq_chip = sdca_irq_chip; - devm_mutex_init(dev, &info->irq_lock); + ret = devm_mutex_init(dev, &info->irq_lock); + if (ret) + return ERR_PTR(ret); ret = devm_regmap_add_irq_chip(dev, regmap, irq, IRQF_ONESHOT, 0, &info->irq_chip, &info->irq_data); From 59c5dbd585a0bee70e51fcdf36185f7602b9c285 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 22 Jul 2025 11:23:05 +0100 Subject: [PATCH 380/385] ASoC: SDCA: Shrink detected_mode_handler() stack frame The stack frame for detected_mode_handler() is a bit large. Dynamically allocate the control value struct, which is most of the size, to avoid this. Fixes: b9ab3b618241 ("ASoC: SDCA: Add some initial IRQ handlers") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202507182222.OLgOy9fX-lkp@intel.com/ Signed-off-by: Charles Keepax Reviewed-by: Arnd Bergmann Link: https://patch.msgid.link/20250722102305.2513755-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/sdca/sdca_interrupts.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/sdca/sdca_interrupts.c b/sound/soc/sdca/sdca_interrupts.c index d442ba2f5681..8018773ee426 100644 --- a/sound/soc/sdca/sdca_interrupts.c +++ b/sound/soc/sdca/sdca_interrupts.c @@ -144,7 +144,7 @@ static irqreturn_t detected_mode_handler(int irq, void *data) struct snd_soc_card *card = component->card; struct rw_semaphore *rwsem = &card->snd_card->controls_rwsem; struct snd_kcontrol *kctl = interrupt->priv; - struct snd_ctl_elem_value ucontrol; + struct snd_ctl_elem_value *ucontrol __free(kfree) = NULL; struct soc_enum *soc_enum; unsigned int reg, val; int ret; @@ -204,10 +204,14 @@ static irqreturn_t detected_mode_handler(int irq, void *data) dev_dbg(dev, "%s: %#x\n", interrupt->name, val); - ucontrol.value.enumerated.item[0] = snd_soc_enum_val_to_item(soc_enum, val); + ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL); + if (!ucontrol) + return IRQ_NONE; + + ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(soc_enum, val); down_write(rwsem); - ret = kctl->put(kctl, &ucontrol); + ret = kctl->put(kctl, ucontrol); up_write(rwsem); if (ret < 0) { dev_err(dev, "failed to update selected mode: %d\n", ret); From 246570cd351299959822ac21e75e2975f80ce4b7 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 22 Jul 2025 12:47:05 +0100 Subject: [PATCH 381/385] ASoC: SDCA: Fix implicit cast from le16 As the HID wDescriptorLength is explicitly marked as little endian it should be converted to host endian before being used. Fixes: ac558015dfd8 ("ASoC: SDCA: add a HID device for HIDE entity") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202507221024.M18hWD6q-lkp@intel.com/ Signed-off-by: Charles Keepax Link: https://patch.msgid.link/20250722114705.2816910-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/sdca/sdca_hid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sdca/sdca_hid.c b/sound/soc/sdca/sdca_hid.c index 2224ade59aff..967f7ec6fb79 100644 --- a/sound/soc/sdca/sdca_hid.c +++ b/sound/soc/sdca/sdca_hid.c @@ -24,7 +24,7 @@ static int sdwhid_parse(struct hid_device *hid) unsigned int rsize; int ret; - rsize = entity->hide.hid_desc.rpt_desc.wDescriptorLength; + rsize = le16_to_cpu(entity->hide.hid_desc.rpt_desc.wDescriptorLength); if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { dev_err(&hid->dev, "invalid size of report descriptor (%u)\n", rsize); From b102c9d89fecd72be83eaab9b384285e2d0dc940 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 23 Jul 2025 16:03:38 +0200 Subject: [PATCH 382/385] ASoC: dt-bindings: qcom,q6afe: Document q6usb subnode Document the subnode for Q6USB, used for USB audio offloading. Cc: Wesley Cheng Acked-by: Rob Herring (Arm) Signed-off-by: Luca Weiss Link: https://patch.msgid.link/20250723-fp4-usb-audio-offload-v3-1-6be84ed4fc39@fairphone.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/qcom,q6afe.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,q6afe.yaml b/Documentation/devicetree/bindings/sound/qcom,q6afe.yaml index 297aa362aa54..268f7073d797 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6afe.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,q6afe.yaml @@ -29,6 +29,12 @@ properties: unevaluatedProperties: false description: Qualcomm DSP audio ports + usbd: + type: object + $ref: /schemas/sound/qcom,q6usb.yaml# + unevaluatedProperties: false + description: Qualcomm DSP USB audio ports + required: - compatible - dais @@ -64,5 +70,12 @@ examples: qcom,sd-lines = <0 1 2 3>; }; }; + + usbd { + compatible = "qcom,q6usb"; + #sound-dai-cells = <1>; + iommus = <&apps_smmu 0x180f 0x0>; + qcom,usb-audio-intr-idx = /bits/ 16 <2>; + }; }; }; From d664e75317e19bb79b6d207f7729e35eca504a6a Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 23 Jul 2025 16:03:39 +0200 Subject: [PATCH 383/385] ASoC: dt-bindings: qcom,sm8250: Add Fairphone 4 sound card Document the bindings for the sound card on Fairphone 4 which uses the older non-audioreach audio architecture. Acked-by: Krzysztof Kozlowski Signed-off-by: Luca Weiss Link: https://patch.msgid.link/20250723-fp4-usb-audio-offload-v3-2-6be84ed4fc39@fairphone.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,sm8250.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index 6b4a8dbdaf61..5d3dbb6cb1ae 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -28,6 +28,7 @@ properties: - qcom,sm8750-sndcard - const: qcom,sm8450-sndcard - enum: + - fairphone,fp4-sndcard - fairphone,fp5-sndcard - qcom,apq8096-sndcard - qcom,qcm6490-idp-sndcard From c58c35ef6ae62e36927f506a5afc66610b7261d9 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 23 Jul 2025 16:03:40 +0200 Subject: [PATCH 384/385] ASoC: qcom: sm8250: Add Fairphone 4 soundcard compatible Add a compatible for the SM7225-based Fairphone 4 which can use this machine driver. Reviewed-by: Dmitry Baryshkov Signed-off-by: Luca Weiss Link: https://patch.msgid.link/20250723-fp4-usb-audio-offload-v3-3-6be84ed4fc39@fairphone.com Signed-off-by: Mark Brown --- sound/soc/qcom/sm8250.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index 69c514fad0b1..f5b75a06e5bd 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -208,6 +208,7 @@ static int sm8250_platform_probe(struct platform_device *pdev) } static const struct of_device_id snd_sm8250_dt_match[] = { + { .compatible = "fairphone,fp4-sndcard", .data = "sm7225" }, { .compatible = "fairphone,fp5-sndcard", .data = "qcm6490" }, { .compatible = "qcom,qrb4210-rb2-sndcard", .data = "sm4250" }, { .compatible = "qcom,qrb5165-rb5-sndcard", .data = "sm8250" }, From ab29b3460c5cec24bde75278d7ffca23cac1b867 Mon Sep 17 00:00:00 2001 From: Baojun Xu Date: Wed, 23 Jul 2025 22:24:23 +0800 Subject: [PATCH 385/385] ALSA: hda: Add TAS2770 support Add TAS2770 support in TI's HDA driver. And add hda_chip_id for more products. Distinguish DSP and non-DSP in firmware loading function. Signed-off-by: Baojun Xu Link: https://patch.msgid.link/20250723142423.38768-1-baojun.xu@ti.com Signed-off-by: Takashi Iwai --- include/sound/tas2770-tlv.h | 23 +++ .../hda/codecs/side-codecs/tas2781_hda_i2c.c | 161 +++++++++++------- 2 files changed, 127 insertions(+), 57 deletions(-) create mode 100644 include/sound/tas2770-tlv.h diff --git a/include/sound/tas2770-tlv.h b/include/sound/tas2770-tlv.h new file mode 100644 index 000000000000..c0bd495b4a07 --- /dev/null +++ b/include/sound/tas2770-tlv.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +// +// ALSA SoC Texas Instruments TAS2770 Audio Smart Amplifier +// +// Copyright (C) 2025 Texas Instruments Incorporated +// https://www.ti.com +// +// The TAS2770 hda driver implements for one, two, or even multiple +// TAS2770 chips. +// +// Author: Baojun Xu +// + +#ifndef __TAS2770_TLV_H__ +#define __TAS2770_TLV_H__ + +#define TAS2770_DVC_LEVEL TASDEVICE_REG(0x0, 0x0, 0x17) +#define TAS2770_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x03) + +static const __maybe_unused DECLARE_TLV_DB_SCALE(tas2770_dvc_tlv, 1650, 50, 0); +static const __maybe_unused DECLARE_TLV_DB_SCALE(tas2770_amp_tlv, 1100, 50, 0); + +#endif diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c index bacc3f6ed4bd..a0b132681804 100644 --- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "hda_local.h" @@ -45,9 +46,18 @@ #define TAS2563_CAL_TLIM TASDEVICE_REG(0, 0x10, 0x14) #define TAS2563_CAL_R0 TASDEVICE_REG(0, 0x0f, 0x34) +enum device_chip_id { + HDA_TAS2563, + HDA_TAS2770, + HDA_TAS2781, + HDA_OTHERS +}; + struct tas2781_hda_i2c_priv { struct snd_kcontrol *snd_ctls[2]; int (*save_calibration)(struct tas2781_hda *h); + + int hda_chip_id; }; static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data) @@ -245,6 +255,15 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol, return change; } +static const struct snd_kcontrol_new tas2770_snd_controls[] = { + ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS2770_AMP_LEVEL, + 0, 0, 20, 0, tas2781_amp_getvol, + tas2781_amp_putvol, tas2770_amp_tlv), + ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2770_DVC_LEVEL, + 0, 0, 31, 0, tas2781_amp_getvol, + tas2781_amp_putvol, tas2770_dvc_tlv), +}; + static const struct snd_kcontrol_new tas2781_snd_controls[] = { ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL, 1, 0, 20, 0, tas2781_amp_getvol, @@ -253,7 +272,7 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = { tas2781_force_fwload_get, tas2781_force_fwload_put), }; -static const struct snd_kcontrol_new tas2781_prof_ctrl = { +static const struct snd_kcontrol_new tasdevice_prof_ctrl = { .name = "Speaker Profile Id", .iface = SNDRV_CTL_ELEM_IFACE_CARD, .info = tasdevice_info_profile, @@ -261,7 +280,7 @@ static const struct snd_kcontrol_new tas2781_prof_ctrl = { .put = tasdevice_set_profile_id, }; -static const struct snd_kcontrol_new tas2781_dsp_prog_ctrl = { +static const struct snd_kcontrol_new tasdevice_dsp_prog_ctrl = { .name = "Speaker Program Id", .iface = SNDRV_CTL_ELEM_IFACE_CARD, .info = tasdevice_info_programs, @@ -269,7 +288,7 @@ static const struct snd_kcontrol_new tas2781_dsp_prog_ctrl = { .put = tasdevice_program_put, }; -static const struct snd_kcontrol_new tas2781_dsp_conf_ctrl = { +static const struct snd_kcontrol_new tasdevice_dsp_conf_ctrl = { .name = "Speaker Config Id", .iface = SNDRV_CTL_ELEM_IFACE_CARD, .info = tasdevice_info_config, @@ -378,44 +397,34 @@ static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda) snd_ctl_remove(codec->card, tas_hda->prof_ctl); } -static void tasdev_fw_ready(const struct firmware *fmw, void *context) +static void tasdev_add_kcontrols(struct tasdevice_priv *tas_priv, + struct snd_kcontrol **ctls, struct hda_codec *codec, + const struct snd_kcontrol_new *tas_snd_ctrls, int num_ctls) +{ + int i, ret; + + for (i = 0; i < num_ctls; i++) { + ctls[i] = snd_ctl_new1( + &tas_snd_ctrls[i], tas_priv); + ret = snd_ctl_add(codec->card, ctls[i]); + if (ret) { + dev_err(tas_priv->dev, + "Failed to add KControl %s = %d\n", + tas_snd_ctrls[i].name, ret); + break; + } + } +} + +static void tasdevice_dspfw_init(void *context) { struct tasdevice_priv *tas_priv = context; struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev); struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv; struct hda_codec *codec = tas_priv->codec; - int i, ret, spk_id; - - pm_runtime_get_sync(tas_priv->dev); - mutex_lock(&tas_priv->codec_lock); - - ret = tasdevice_rca_parser(tas_priv, fmw); - if (ret) - goto out; - - tas_hda->prof_ctl = snd_ctl_new1(&tas2781_prof_ctrl, tas_priv); - ret = snd_ctl_add(codec->card, tas_hda->prof_ctl); - if (ret) { - dev_err(tas_priv->dev, - "Failed to add KControl %s = %d\n", - tas2781_prof_ctrl.name, ret); - goto out; - } - - for (i = 0; i < ARRAY_SIZE(tas2781_snd_controls); i++) { - hda_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_controls[i], - tas_priv); - ret = snd_ctl_add(codec->card, hda_priv->snd_ctls[i]); - if (ret) { - dev_err(tas_priv->dev, - "Failed to add KControl %s = %d\n", - tas2781_snd_controls[i].name, ret); - goto out; - } - } + int ret, spk_id; tasdevice_dsp_remove(tas_priv); - tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; if (tas_priv->speaker_id != NULL) { // Speaker id need to be checked for ASUS only. @@ -441,28 +450,12 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) dev_err(tas_priv->dev, "dspfw load %s error\n", tas_priv->coef_binaryname); tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; - goto out; - } - - tas_hda->dsp_prog_ctl = snd_ctl_new1(&tas2781_dsp_prog_ctrl, - tas_priv); - ret = snd_ctl_add(codec->card, tas_hda->dsp_prog_ctl); - if (ret) { - dev_err(tas_priv->dev, - "Failed to add KControl %s = %d\n", - tas2781_dsp_prog_ctrl.name, ret); - goto out; - } - - tas_hda->dsp_conf_ctl = snd_ctl_new1(&tas2781_dsp_conf_ctrl, - tas_priv); - ret = snd_ctl_add(codec->card, tas_hda->dsp_conf_ctl); - if (ret) { - dev_err(tas_priv->dev, - "Failed to add KControl %s = %d\n", - tas2781_dsp_conf_ctrl.name, ret); - goto out; + return; } + tasdev_add_kcontrols(tas_priv, &tas_hda->dsp_prog_ctl, codec, + &tasdevice_dsp_prog_ctrl, 1); + tasdev_add_kcontrols(tas_priv, &tas_hda->dsp_conf_ctl, codec, + &tasdevice_dsp_conf_ctrl, 1); tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK; tasdevice_prmg_load(tas_priv, 0); @@ -475,9 +468,45 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) * calibrated data inside algo. */ hda_priv->save_calibration(tas_hda); +} - tasdevice_tuning_switch(tas_hda->priv, 0); - tas_hda->priv->playback_started = true; +static void tasdev_fw_ready(const struct firmware *fmw, void *context) +{ + struct tasdevice_priv *tas_priv = context; + struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev); + struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv; + struct hda_codec *codec = tas_priv->codec; + int ret; + + pm_runtime_get_sync(tas_priv->dev); + mutex_lock(&tas_priv->codec_lock); + + ret = tasdevice_rca_parser(tas_priv, fmw); + if (ret) + goto out; + + tas_priv->fw_state = TASDEVICE_RCA_FW_OK; + tasdev_add_kcontrols(tas_priv, &tas_hda->prof_ctl, codec, + &tasdevice_prof_ctrl, 1); + + switch (hda_priv->hda_chip_id) { + case HDA_TAS2770: + tasdev_add_kcontrols(tas_priv, hda_priv->snd_ctls, codec, + &tas2770_snd_controls[0], + ARRAY_SIZE(tas2770_snd_controls)); + break; + case HDA_TAS2781: + tasdev_add_kcontrols(tas_priv, hda_priv->snd_ctls, codec, + &tas2781_snd_controls[0], + ARRAY_SIZE(tas2781_snd_controls)); + tasdevice_dspfw_init(context); + break; + case HDA_TAS2563: + tasdevice_dspfw_init(context); + break; + default: + break; + } out: mutex_unlock(&tas_hda->priv->codec_lock); @@ -581,16 +610,33 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt) return -ENOMEM; if (strstr(dev_name(&clt->dev), "TIAS2781")) { + /* + * TAS2781, integrated on-chip DSP with + * global I2C address supported. + */ device_name = "TIAS2781"; + hda_priv->hda_chip_id = HDA_TAS2781; hda_priv->save_calibration = tas2781_save_calibration; tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR; + } else if (strstarts(dev_name(&clt->dev), "i2c-TXNW2770")) { + /* + * TAS2770, has no on-chip DSP, so no calibration data + * required; has no global I2C address supported. + */ + device_name = "TXNW2770"; + hda_priv->hda_chip_id = HDA_TAS2770; } else if (strstarts(dev_name(&clt->dev), "i2c-TXNW2781:00-tas2781-hda.0")) { device_name = "TXNW2781"; hda_priv->save_calibration = tas2781_save_calibration; tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR; } else if (strstr(dev_name(&clt->dev), "INT8866")) { + /* + * TAS2563, integrated on-chip DSP with + * global I2C address supported. + */ device_name = "INT8866"; + hda_priv->hda_chip_id = HDA_TAS2563; hda_priv->save_calibration = tas2563_save_calibration; tas_hda->priv->global_addr = TAS2563_GLOBAL_ADDR; } else { @@ -727,6 +773,7 @@ static const struct i2c_device_id tas2781_hda_i2c_id[] = { static const struct acpi_device_id tas2781_acpi_hda_match[] = { {"INT8866", 0 }, {"TIAS2781", 0 }, + {"TXNW2770", 0 }, {"TXNW2781", 0 }, {} };