From 5512ffd9f39832f312b7f903703ac39d6367fe8a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 30 Jun 2023 20:21:52 +0300 Subject: [PATCH 001/334] ASoC: rt5677: Refactor GPIO support code After compiler complains: sound/soc/codecs/rt5677.c:4748:30: warning: dubious: x | !y I looked into the code and realized that we can refactor it for better reading and fixing above issue at the same time. Hence this change. It does not imply any functional changes. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230630172155.83754-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 76 +++++++++++---------------------- sound/soc/codecs/rt5677.h | 88 ++++++--------------------------------- 2 files changed, 37 insertions(+), 127 deletions(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index ad14d18860fc..3a2a6b150cda 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4717,50 +4717,34 @@ static int rt5677_set_bias_level(struct snd_soc_component *component, return 0; } +static int rt5677_update_gpio_bits(struct rt5677_priv *rt5677, unsigned offset, int m, int v) +{ + unsigned int bank = offset / 5; + unsigned int shift = (offset % 5) * 3; + unsigned int reg = bank ? RT5677_GPIO_CTRL3 : RT5677_GPIO_CTRL2; + + return regmap_update_bits(rt5677->regmap, reg, m << shift, v << shift); +} + #ifdef CONFIG_GPIOLIB static void rt5677_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct rt5677_priv *rt5677 = gpiochip_get_data(chip); + int level = value ? RT5677_GPIOx_OUT_HI : RT5677_GPIOx_OUT_LO; + int m = RT5677_GPIOx_OUT_MASK; - switch (offset) { - case RT5677_GPIO1 ... RT5677_GPIO5: - regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, - 0x1 << (offset * 3 + 1), !!value << (offset * 3 + 1)); - break; - - case RT5677_GPIO6: - regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3, - RT5677_GPIO6_OUT_MASK, !!value << RT5677_GPIO6_OUT_SFT); - break; - - default: - break; - } + rt5677_update_gpio_bits(rt5677, offset, m, level); } static int rt5677_gpio_direction_out(struct gpio_chip *chip, unsigned offset, int value) { struct rt5677_priv *rt5677 = gpiochip_get_data(chip); + int level = value ? RT5677_GPIOx_OUT_HI : RT5677_GPIOx_OUT_LO; + int m = RT5677_GPIOx_DIR_MASK | RT5677_GPIOx_OUT_MASK; + int v = RT5677_GPIOx_DIR_OUT | level; - switch (offset) { - case RT5677_GPIO1 ... RT5677_GPIO5: - regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, - 0x3 << (offset * 3 + 1), - (0x2 | !!value) << (offset * 3 + 1)); - break; - - case RT5677_GPIO6: - regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3, - RT5677_GPIO6_DIR_MASK | RT5677_GPIO6_OUT_MASK, - RT5677_GPIO6_DIR_OUT | !!value << RT5677_GPIO6_OUT_SFT); - break; - - default: - break; - } - - return 0; + return rt5677_update_gpio_bits(rt5677, offset, m, v); } static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset) @@ -4778,26 +4762,14 @@ static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset) static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset) { struct rt5677_priv *rt5677 = gpiochip_get_data(chip); + int m = RT5677_GPIOx_DIR_MASK; + int v = RT5677_GPIOx_DIR_IN; - switch (offset) { - case RT5677_GPIO1 ... RT5677_GPIO5: - regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, - 0x1 << (offset * 3 + 2), 0x0); - break; - - case RT5677_GPIO6: - regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3, - RT5677_GPIO6_DIR_MASK, RT5677_GPIO6_DIR_IN); - break; - - default: - break; - } - - return 0; + return rt5677_update_gpio_bits(rt5677, offset, m, v); } -/** Configures the gpio as +/* + * Configures the GPIO as * 0 - floating * 1 - pull down * 2 - pull up @@ -5673,9 +5645,9 @@ static int rt5677_i2c_probe(struct i2c_client *i2c) regmap_update_bits(rt5677->regmap, RT5677_GEN_CTRL2, RT5677_GPIO5_FUNC_MASK, RT5677_GPIO5_FUNC_DMIC); - regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, - RT5677_GPIO5_DIR_MASK, - RT5677_GPIO5_DIR_OUT); + rt5677_update_gpio_bits(rt5677, RT5677_GPIO5, + RT5677_GPIOx_DIR_MASK, + RT5677_GPIOx_DIR_OUT); } if (rt5677->pdata.micbias1_vdd_3v3) diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 944ae02aafc2..5932b04cf85e 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1587,81 +1587,19 @@ #define RT5677_FUNC_MODE_DMIC_GPIO (0x0 << 13) #define RT5677_FUNC_MODE_JTAG (0x1 << 13) -/* GPIO Control 2 (0xc1) */ -#define RT5677_GPIO5_DIR_MASK (0x1 << 14) -#define RT5677_GPIO5_DIR_SFT 14 -#define RT5677_GPIO5_DIR_IN (0x0 << 14) -#define RT5677_GPIO5_DIR_OUT (0x1 << 14) -#define RT5677_GPIO5_OUT_MASK (0x1 << 13) -#define RT5677_GPIO5_OUT_SFT 13 -#define RT5677_GPIO5_OUT_LO (0x0 << 13) -#define RT5677_GPIO5_OUT_HI (0x1 << 13) -#define RT5677_GPIO5_P_MASK (0x1 << 12) -#define RT5677_GPIO5_P_SFT 12 -#define RT5677_GPIO5_P_NOR (0x0 << 12) -#define RT5677_GPIO5_P_INV (0x1 << 12) -#define RT5677_GPIO4_DIR_MASK (0x1 << 11) -#define RT5677_GPIO4_DIR_SFT 11 -#define RT5677_GPIO4_DIR_IN (0x0 << 11) -#define RT5677_GPIO4_DIR_OUT (0x1 << 11) -#define RT5677_GPIO4_OUT_MASK (0x1 << 10) -#define RT5677_GPIO4_OUT_SFT 10 -#define RT5677_GPIO4_OUT_LO (0x0 << 10) -#define RT5677_GPIO4_OUT_HI (0x1 << 10) -#define RT5677_GPIO4_P_MASK (0x1 << 9) -#define RT5677_GPIO4_P_SFT 9 -#define RT5677_GPIO4_P_NOR (0x0 << 9) -#define RT5677_GPIO4_P_INV (0x1 << 9) -#define RT5677_GPIO3_DIR_MASK (0x1 << 8) -#define RT5677_GPIO3_DIR_SFT 8 -#define RT5677_GPIO3_DIR_IN (0x0 << 8) -#define RT5677_GPIO3_DIR_OUT (0x1 << 8) -#define RT5677_GPIO3_OUT_MASK (0x1 << 7) -#define RT5677_GPIO3_OUT_SFT 7 -#define RT5677_GPIO3_OUT_LO (0x0 << 7) -#define RT5677_GPIO3_OUT_HI (0x1 << 7) -#define RT5677_GPIO3_P_MASK (0x1 << 6) -#define RT5677_GPIO3_P_SFT 6 -#define RT5677_GPIO3_P_NOR (0x0 << 6) -#define RT5677_GPIO3_P_INV (0x1 << 6) -#define RT5677_GPIO2_DIR_MASK (0x1 << 5) -#define RT5677_GPIO2_DIR_SFT 5 -#define RT5677_GPIO2_DIR_IN (0x0 << 5) -#define RT5677_GPIO2_DIR_OUT (0x1 << 5) -#define RT5677_GPIO2_OUT_MASK (0x1 << 4) -#define RT5677_GPIO2_OUT_SFT 4 -#define RT5677_GPIO2_OUT_LO (0x0 << 4) -#define RT5677_GPIO2_OUT_HI (0x1 << 4) -#define RT5677_GPIO2_P_MASK (0x1 << 3) -#define RT5677_GPIO2_P_SFT 3 -#define RT5677_GPIO2_P_NOR (0x0 << 3) -#define RT5677_GPIO2_P_INV (0x1 << 3) -#define RT5677_GPIO1_DIR_MASK (0x1 << 2) -#define RT5677_GPIO1_DIR_SFT 2 -#define RT5677_GPIO1_DIR_IN (0x0 << 2) -#define RT5677_GPIO1_DIR_OUT (0x1 << 2) -#define RT5677_GPIO1_OUT_MASK (0x1 << 1) -#define RT5677_GPIO1_OUT_SFT 1 -#define RT5677_GPIO1_OUT_LO (0x0 << 1) -#define RT5677_GPIO1_OUT_HI (0x1 << 1) -#define RT5677_GPIO1_P_MASK (0x1 << 0) -#define RT5677_GPIO1_P_SFT 0 -#define RT5677_GPIO1_P_NOR (0x0 << 0) -#define RT5677_GPIO1_P_INV (0x1 << 0) - -/* GPIO Control 3 (0xc2) */ -#define RT5677_GPIO6_DIR_MASK (0x1 << 2) -#define RT5677_GPIO6_DIR_SFT 2 -#define RT5677_GPIO6_DIR_IN (0x0 << 2) -#define RT5677_GPIO6_DIR_OUT (0x1 << 2) -#define RT5677_GPIO6_OUT_MASK (0x1 << 1) -#define RT5677_GPIO6_OUT_SFT 1 -#define RT5677_GPIO6_OUT_LO (0x0 << 1) -#define RT5677_GPIO6_OUT_HI (0x1 << 1) -#define RT5677_GPIO6_P_MASK (0x1 << 0) -#define RT5677_GPIO6_P_SFT 0 -#define RT5677_GPIO6_P_NOR (0x0 << 0) -#define RT5677_GPIO6_P_INV (0x1 << 0) +/* GPIO Control 2 (0xc1) & 3 (0xc2) common bits */ +#define RT5677_GPIOx_DIR_MASK (0x1 << 2) +#define RT5677_GPIOx_DIR_SFT 2 +#define RT5677_GPIOx_DIR_IN (0x0 << 2) +#define RT5677_GPIOx_DIR_OUT (0x1 << 2) +#define RT5677_GPIOx_OUT_MASK (0x1 << 1) +#define RT5677_GPIOx_OUT_SFT 1 +#define RT5677_GPIOx_OUT_LO (0x0 << 1) +#define RT5677_GPIOx_OUT_HI (0x1 << 1) +#define RT5677_GPIOx_P_MASK (0x1 << 0) +#define RT5677_GPIOx_P_SFT 0 +#define RT5677_GPIOx_P_NOR (0x0 << 0) +#define RT5677_GPIOx_P_INV (0x1 << 0) /* General Control (0xfa) */ #define RT5677_IRQ_DEBOUNCE_SEL_MASK (0x3 << 3) From c3d42d7baf6b4032171270e3df001fb946493452 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 30 Jun 2023 20:21:53 +0300 Subject: [PATCH 002/334] ASoC: rt5677: Use agnostic irq_domain_create_linear() Instead of irq_domain_add_linear() that requires of_node, use irq_domain_create_linear() that works outside of OF world. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230630172155.83754-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 3a2a6b150cda..17d5dd5d2974 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5511,7 +5511,7 @@ static int rt5677_init_irq(struct i2c_client *i2c) RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ); /* Ready to listen for interrupts */ - rt5677->domain = irq_domain_add_linear(i2c->dev.of_node, + rt5677->domain = irq_domain_create_linear(dev_fwnode(&i2c->dev), RT5677_IRQ_NUM, &rt5677_domain_ops, rt5677); if (!rt5677->domain) { dev_err(&i2c->dev, "Failed to create IRQ domain\n"); From 043bb9c012ee7d092a477159cc66dbdf62fd2666 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 30 Jun 2023 20:21:54 +0300 Subject: [PATCH 003/334] ASoC: rt5677: Use device_get_match_data() Use device_get_match_data() to simplify the code. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230630172155.83754-4-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 21 ++++----------------- sound/soc/codecs/rt5677.h | 4 ++-- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 17d5dd5d2974..b0c15e27c763 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -6,7 +6,6 @@ * Author: Oder Chiou */ -#include #include #include #include @@ -18,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -5531,6 +5529,7 @@ static int rt5677_init_irq(struct i2c_client *i2c) static int rt5677_i2c_probe(struct i2c_client *i2c) { + struct device *dev = &i2c->dev; struct rt5677_priv *rt5677; int ret; unsigned int val; @@ -5545,21 +5544,9 @@ static int rt5677_i2c_probe(struct i2c_client *i2c) INIT_DELAYED_WORK(&rt5677->dsp_work, rt5677_dsp_work); i2c_set_clientdata(i2c, rt5677); - if (i2c->dev.of_node) { - const struct of_device_id *match_id; - - match_id = of_match_device(rt5677_of_match, &i2c->dev); - if (match_id) - rt5677->type = (enum rt5677_type)match_id->data; - } else if (ACPI_HANDLE(&i2c->dev)) { - const struct acpi_device_id *acpi_id; - - acpi_id = acpi_match_device(rt5677_acpi_match, &i2c->dev); - if (acpi_id) - rt5677->type = (enum rt5677_type)acpi_id->driver_data; - } else { + rt5677->type = (enum rt5677_type)(uintptr_t)device_get_match_data(dev); + if (rt5677->type == 0) return -EINVAL; - } rt5677_read_device_properties(rt5677, &i2c->dev); @@ -5674,7 +5661,7 @@ static struct i2c_driver rt5677_i2c_driver = { .driver = { .name = RT5677_DRV_NAME, .of_match_table = rt5677_of_match, - .acpi_match_table = ACPI_PTR(rt5677_acpi_match), + .acpi_match_table = rt5677_acpi_match, }, .probe = rt5677_i2c_probe, .remove = rt5677_i2c_remove, diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 5932b04cf85e..d67ebae067d9 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1691,8 +1691,8 @@ enum { }; enum rt5677_type { - RT5677, - RT5676, + RT5677 = 1, + RT5676 = 2, }; /* ASRC clock source selection */ From ea1c1019a88d88cf0a7d6892f594b72ddb3b8c0b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 30 Jun 2023 20:21:55 +0300 Subject: [PATCH 004/334] ASoC: rt5677: Sort headers alphabetically It's hard to see what's included and what's not on the glance. Sort headers alphabetically to improve maintenance. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230630172155.83754-5-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index b0c15e27c763..0e70a3ab42b5 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -6,21 +6,21 @@ * Author: Oder Chiou */ -#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 From acb5c0b14b761df258e480cc721676073f6d953a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 7 Jul 2023 09:28:29 +0200 Subject: [PATCH 005/334] ASoC: amd: ps-sdw-dma: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230707072830.3395789-2-u.kleine-koenig@pengutronix.de Signed-off-by: Mark Brown --- sound/soc/amd/ps/ps-sdw-dma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/amd/ps/ps-sdw-dma.c b/sound/soc/amd/ps/ps-sdw-dma.c index 324c80fca672..6230d1b12225 100644 --- a/sound/soc/amd/ps/ps-sdw-dma.c +++ b/sound/soc/amd/ps/ps-sdw-dma.c @@ -488,10 +488,9 @@ static int acp63_sdw_platform_probe(struct platform_device *pdev) return 0; } -static int acp63_sdw_platform_remove(struct platform_device *pdev) +static void acp63_sdw_platform_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - return 0; } static int acp_restore_sdw_dma_config(struct sdw_dma_dev_data *sdw_data) @@ -552,7 +551,7 @@ static const struct dev_pm_ops acp63_pm_ops = { static struct platform_driver acp63_sdw_dma_driver = { .probe = acp63_sdw_platform_probe, - .remove = acp63_sdw_platform_remove, + .remove_new = acp63_sdw_platform_remove, .driver = { .name = "amd_ps_sdw_dma", .pm = &acp63_pm_ops, From 50a91c513fb7da5c48b1cffdaa30c1f98f403801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 7 Jul 2023 09:28:30 +0200 Subject: [PATCH 006/334] ASoC: starfive: jh7110_tdm: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230707072830.3395789-3-u.kleine-koenig@pengutronix.de Signed-off-by: Mark Brown --- sound/soc/starfive/jh7110_tdm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/starfive/jh7110_tdm.c b/sound/soc/starfive/jh7110_tdm.c index 5f5a6ca7dbda..705f1420097b 100644 --- a/sound/soc/starfive/jh7110_tdm.c +++ b/sound/soc/starfive/jh7110_tdm.c @@ -634,10 +634,9 @@ static int jh7110_tdm_probe(struct platform_device *pdev) return ret; } -static int jh7110_tdm_dev_remove(struct platform_device *pdev) +static void jh7110_tdm_dev_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - return 0; } static const struct of_device_id jh7110_tdm_of_match[] = { @@ -661,7 +660,7 @@ static struct platform_driver jh7110_tdm_driver = { .pm = pm_ptr(&jh7110_tdm_pm_ops), }, .probe = jh7110_tdm_probe, - .remove = jh7110_tdm_dev_remove, + .remove_new = jh7110_tdm_dev_remove, }; module_platform_driver(jh7110_tdm_driver); From be7dc10ab0bc247c2abbdefdaa9d5196df88e9d1 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 29 Jun 2023 13:24:42 +0200 Subject: [PATCH 007/334] ASoC: codecs: es8316: Add support for 24 MHz MCLK MCLK operates on 24MHz on Intel KabyLake-based platforms. To support that frequency add new MCLK-LRCK ratio. While at it, utilize ARRAY_SIZE rather than hardcode to improve robustness. Cc: Zhu Ning Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20230629112449.1755928-2-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8316.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 34cf60769b62..5d1fd505d6ba 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -27,9 +27,9 @@ * MCLK/LRCK ratios, but we also add ratio 400, which is commonly used on * Intel Cherry Trail platforms (19.2MHz MCLK, 48kHz LRCK). */ -#define NR_SUPPORTED_MCLK_LRCK_RATIOS 6 +#define NR_SUPPORTED_MCLK_LRCK_RATIOS ARRAY_SIZE(supported_mclk_lrck_ratios) static const unsigned int supported_mclk_lrck_ratios[] = { - 256, 384, 400, 512, 768, 1024 + 256, 384, 400, 500, 512, 768, 1024 }; struct es8316_priv { From c30d10aeb398cf71662cb8c6b0090ed9ab38dd8e Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 29 Jun 2023 13:24:43 +0200 Subject: [PATCH 008/334] ASoC: codecs: es8316: Add support for S24_3LE format Codec supports words that are 16/18/20/24/32 bits long. In case of 24, it should be treated as 24/24 not 24/32 i.e.: 24 valid bit-depth in 24 bit-depth container. For compatibility reasons, S24_LE is left as is. Cc: Zhu Ning Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20230629112449.1755928-3-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8316.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 5d1fd505d6ba..7e5eb13af428 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -494,6 +494,7 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream, bclk_divider /= 20; break; case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S24_3LE: wordlen = ES8316_SERDATA2_LEN_24; bclk_divider /= 24; break; From 32e40c8d6ff920354fde36299198c80e7a7d3b76 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 29 Jun 2023 13:24:44 +0200 Subject: [PATCH 009/334] ASoC: Intel: avs: Add es8336 machine board To support AVS-es8336 configuration add machine board connecting AVS platform component driver with es8316 codec one. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20230629112449.1755928-4-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/Kconfig | 10 + sound/soc/intel/avs/boards/Makefile | 2 + sound/soc/intel/avs/boards/es8336.c | 315 ++++++++++++++++++++++++++++ 3 files changed, 327 insertions(+) create mode 100644 sound/soc/intel/avs/boards/es8336.c diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig index e4c230efe8d7..cb07498d779e 100644 --- a/sound/soc/intel/avs/boards/Kconfig +++ b/sound/soc/intel/avs/boards/Kconfig @@ -22,6 +22,16 @@ config SND_SOC_INTEL_AVS_MACH_DMIC 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_ES8336 + tristate "es8336 I2S board" + depends on X86 && I2C + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_ES8316 + help + This adds support for AVS with ES8336 I2S codec configuration. + 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_HDAUDIO tristate "HD-Audio generic board" select SND_SOC_HDA diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile index b81343420370..a1c08c0cb170 100644 --- a/sound/soc/intel/avs/boards/Makefile +++ b/sound/soc/intel/avs/boards/Makefile @@ -2,6 +2,7 @@ snd-soc-avs-da7219-objs := da7219.o snd-soc-avs-dmic-objs := dmic.o +snd-soc-avs-es8336-objs := es8336.o snd-soc-avs-hdaudio-objs := hdaudio.o snd-soc-avs-i2s-test-objs := i2s_test.o snd-soc-avs-max98927-objs := max98927.o @@ -17,6 +18,7 @@ snd-soc-avs-ssm4567-objs := ssm4567.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DA7219) += snd-soc-avs-da7219.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_ES8336) += snd-soc-avs-es8336.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_I2S_TEST) += snd-soc-avs-i2s-test.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98927) += snd-soc-avs-max98927.o diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c new file mode 100644 index 000000000000..0a023f871d93 --- /dev/null +++ b/sound/soc/intel/avs/boards/es8336.c @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2023 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski +// Amadeusz Slawinski +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ES8336_CODEC_DAI "ES8316 HiFi" + +struct avs_card_drvdata { + struct snd_soc_jack jack; + struct gpio_desc *gpiod; +}; + +static const struct acpi_gpio_params enable_gpio = { 0, 0, true }; + +static const struct acpi_gpio_mapping speaker_gpios[] = { + { "speaker-enable-gpios", &enable_gpio, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, + { } +}; + +static int avs_es8336_speaker_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_card *card = w->dapm->card; + struct avs_card_drvdata *data; + bool speaker_en; + + data = snd_soc_card_get_drvdata(card); + /* As enable_gpio has active_low=true, logic is inverted. */ + speaker_en = !SND_SOC_DAPM_EVENT_ON(event); + + gpiod_set_value_cansleep(data->gpiod, speaker_en); + return 0; +} + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Internal Mic", NULL), + + SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0, + avs_es8336_speaker_power_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +}; + +static const struct snd_soc_dapm_route card_routes[] = { + {"Headphone", NULL, "HPOL"}, + {"Headphone", NULL, "HPOR"}, + + /* + * There is no separate speaker output instead the speakers are muxed to + * the HP outputs. The mux is controlled by the "Speaker Power" widget. + */ + {"Speaker", NULL, "HPOL"}, + {"Speaker", NULL, "HPOR"}, + {"Speaker", NULL, "Speaker Power"}, + + /* Mic route map */ + {"MIC1", NULL, "Internal Mic"}, + {"MIC2", NULL, "Headset Mic"}, +}; + +static const struct snd_kcontrol_new card_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Internal Mic"), +}; + +static struct snd_soc_jack_pin card_headset_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int avs_es8336_codec_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0); + struct snd_soc_component *component = codec_dai->component; + struct snd_soc_card *card = runtime->card; + struct snd_soc_jack_pin *pins; + struct avs_card_drvdata *data; + struct gpio_desc *gpiod; + int num_pins, ret; + + data = 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", SND_JACK_HEADSET | SND_JACK_BTN_0, + &data->jack, pins, num_pins); + if (ret) + return ret; + + ret = devm_acpi_dev_add_driver_gpios(codec_dai->dev, speaker_gpios); + if (ret) + dev_warn(codec_dai->dev, "Unable to add GPIO mapping table\n"); + + gpiod = gpiod_get_optional(codec_dai->dev, "speaker-enable", GPIOD_OUT_LOW); + if (IS_ERR(gpiod)) + return dev_err_probe(codec_dai->dev, PTR_ERR(gpiod), "Get gpiod failed: %ld\n", + PTR_ERR(gpiod)); + + data->gpiod = gpiod; + snd_jack_set_key(data->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_soc_component_set_jack(component, &data->jack, NULL); + + card->dapm.idle_bias_off = true; + + return 0; +} + +static void avs_es8336_codec_exit(struct snd_soc_pcm_runtime *runtime) +{ + struct avs_card_drvdata *data = snd_soc_card_get_drvdata(runtime->card); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0); + + snd_soc_component_set_jack(codec_dai->component, NULL, NULL); + gpiod_put(data->gpiod); +} + +static int avs_es8336_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0); + int clk_freq; + int ret; + + switch (boot_cpu_data.x86_model) { + case INTEL_FAM6_KABYLAKE_L: + case INTEL_FAM6_KABYLAKE: + clk_freq = 24000000; + break; + default: + clk_freq = 19200000; + break; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, 1, clk_freq, SND_SOC_CLOCK_OUT); + if (ret < 0) + dev_err(runtime->dev, "Set codec sysclk failed: %d\n", ret); + + return ret; +} + +static const struct snd_soc_ops avs_es8336_ops = { + .hw_params = avs_es8336_hw_params, +}; + +static int avs_es8336_be_fixup(struct snd_soc_pcm_runtime *runtime, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate, *channels; + struct snd_mask *fmt; + + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSPN to 24 bit */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_3LE); + + return 0; +} +static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, + struct snd_soc_dai_link **dai_link) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + platform->name = platform_name; + + dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); + 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, "SSP%d Pin", ssp_port); + dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-ESSX8336:00"); + dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, ES8336_CODEC_DAI); + if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) + return -ENOMEM; + + 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_es8336_codec_init; + dl->exit = avs_es8336_codec_exit; + dl->be_hw_params_fixup = avs_es8336_be_fixup; + dl->ops = &avs_es8336_ops; + dl->nonatomic = 1; + dl->no_pcm = 1; + dl->dpcm_capture = 1; + dl->dpcm_playback = 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, ES8336_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, ES8336_CODEC_DAI); + struct avs_card_drvdata *data = snd_soc_card_get_drvdata(card); + + return snd_soc_component_set_jack(codec_dai->component, &data->jack, NULL); +} + +static int avs_es8336_probe(struct platform_device *pdev) +{ + struct snd_soc_dai_link *dai_link; + struct snd_soc_acpi_mach *mach; + struct avs_card_drvdata *data; + struct snd_soc_card *card; + struct device *dev = &pdev->dev; + const char *pname; + int ssp_port, ret; + + mach = dev_get_platdata(dev); + pname = mach->mach_params.platform; + ssp_port = __ffs(mach->mach_params.i2s_link_mask); + + ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link); + if (ret) { + dev_err(dev, "Failed to create dai link: %d", ret); + return ret; + } + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!data || !card) + return -ENOMEM; + + card->name = "avs_es8336"; + 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->controls = card_controls; + card->num_controls = ARRAY_SIZE(card_controls); + 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, data); + + ret = snd_soc_fixup_dai_links_platform_name(card, pname); + if (ret) + return ret; + + return devm_snd_soc_register_card(dev, card); +} + +static struct platform_driver avs_es8336_driver = { + .probe = avs_es8336_probe, + .driver = { + .name = "avs_es8336", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(avs_es8336_driver); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:avs_es8336"); From d55bb0f1c1a365c42d8b4032cb965a255692a400 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 29 Jun 2023 13:24:45 +0200 Subject: [PATCH 010/334] ASoC: Intel: avs: Load es8336 board on KBL-based platforms Update board-selection tables to account for es8336 on KBL-based platforms. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20230629112449.1755928-5-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/board_selection.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index 60f8fb0bff95..5dc55f14b5a3 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -159,6 +159,14 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = { }, .tplg_filename = "da7219-tplg.bin", }, + { + .id = "ESSX8336", + .drv_name = "avs_es8336", + .mach_params = { + .i2s_link_mask = AVS_SSP(0), + }, + .tplg_filename = "es8336-tplg.bin", + }, {}, }; From 05c5d4e326cc41221a9c065c1e6fee4cdca549b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 29 Jun 2023 13:24:46 +0200 Subject: [PATCH 011/334] ASoC: Intel: avs: Add rt5663 machine board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To support AVS-rt5663 configuration add machine board connecting AVS platform component driver with rt5663 codec one. Signed-off-by: Amadeusz Sławiński Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20230629112449.1755928-6-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/Kconfig | 10 ++ sound/soc/intel/avs/boards/Makefile | 2 + sound/soc/intel/avs/boards/rt5663.c | 254 ++++++++++++++++++++++++++++ 3 files changed, 266 insertions(+) create mode 100644 sound/soc/intel/avs/boards/rt5663.c diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig index cb07498d779e..07353d37ecae 100644 --- a/sound/soc/intel/avs/boards/Kconfig +++ b/sound/soc/intel/avs/boards/Kconfig @@ -125,6 +125,16 @@ config SND_SOC_INTEL_AVS_MACH_RT298 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_RT5663 + tristate "rt5663 in I2S mode" + depends on I2C + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_RT5663 + help + This adds support for ASoC machine driver with RT5663 I2S audio codec. + 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_RT5682 tristate "rt5682 in I2S mode" depends on I2C diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile index a1c08c0cb170..34347bcd1e7d 100644 --- a/sound/soc/intel/avs/boards/Makefile +++ b/sound/soc/intel/avs/boards/Makefile @@ -13,6 +13,7 @@ snd-soc-avs-probe-objs := probe.o snd-soc-avs-rt274-objs := rt274.o snd-soc-avs-rt286-objs := rt286.o snd-soc-avs-rt298-objs := rt298.o +snd-soc-avs-rt5663-objs := rt5663.o snd-soc-avs-rt5682-objs := rt5682.o snd-soc-avs-ssm4567-objs := ssm4567.o @@ -29,5 +30,6 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_PROBE) += snd-soc-avs-probe.o 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_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/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c new file mode 100644 index 000000000000..770b36d05bf4 --- /dev/null +++ b/sound/soc/intel/avs/boards/rt5663.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2022-2023 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski +// Amadeusz Slawinski +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../../codecs/rt5663.h" + +#define RT5663_CODEC_DAI "rt5663-aif" + +struct rt5663_private { + struct snd_soc_jack jack; +}; + +static const struct snd_kcontrol_new card_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_soc_dapm_route card_routes[] = { + /* HP jack connectors */ + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + + /* Mic jacks */ + { "IN1P", NULL, "Headset Mic" }, + { "IN1N", NULL, "Headset Mic" }, +}; + +static struct snd_soc_jack_pin card_headset_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int avs_rt5663_codec_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_card *card = runtime->card; + struct rt5663_private *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_jack_pin *pins; + struct snd_soc_jack *jack; + int num_pins, ret; + + jack = &priv->jack; + 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 | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack, + pins, num_pins); + if (ret) + return ret; + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + snd_soc_component_set_jack(asoc_rtd_to_codec(runtime, 0)->component, jack, NULL); + + return 0; +} + +static void avs_rt5663_codec_exit(struct snd_soc_pcm_runtime *runtime) +{ + snd_soc_component_set_jack(asoc_rtd_to_codec(runtime, 0)->component, NULL, NULL); +} + +static int +avs_rt5663_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate, *channels; + struct snd_mask *fmt; + + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSPN to 24 bit */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +static int avs_rt5663_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + int ret; + + /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */ + rt5663_sel_asrc_clk_src(codec_dai->component, + RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER, + RT5663_CLK_SEL_I2S1_ASRC); + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN); + + return ret; +} + +static const struct snd_soc_ops avs_rt5663_ops = { + .hw_params = avs_rt5663_hw_params, +}; + + +static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, + struct snd_soc_dai_link **dai_link) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + platform->name = platform_name; + + dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); + 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, "SSP%d Pin", ssp_port); + dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10EC5663:00"); + dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT5663_CODEC_DAI); + if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) + return -ENOMEM; + + 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_rt5663_codec_init; + dl->exit = avs_rt5663_codec_exit; + dl->be_hw_params_fixup = avs_rt5663_be_fixup; + dl->nonatomic = 1; + dl->no_pcm = 1; + dl->dpcm_capture = 1; + dl->dpcm_playback = 1; + dl->ops = &avs_rt5663_ops; + + *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, RT5663_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, RT5663_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_rt5663_probe(struct platform_device *pdev) +{ + struct snd_soc_dai_link *dai_link; + struct snd_soc_acpi_mach *mach; + struct snd_soc_card *card; + struct rt5663_private *priv; + struct device *dev = &pdev->dev; + const char *pname; + int ssp_port, ret; + + mach = dev_get_platdata(dev); + pname = mach->mach_params.platform; + ssp_port = __ffs(mach->mach_params.i2s_link_mask); + + ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link); + if (ret) { + dev_err(dev, "Failed to create dai link: %d", ret); + return ret; + } + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!priv || !card) + return -ENOMEM; + + card->name = "avs_rt5663"; + 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->controls = card_controls; + card->num_controls = ARRAY_SIZE(card_controls); + 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, priv); + + ret = snd_soc_fixup_dai_links_platform_name(card, pname); + if (ret) + return ret; + + return devm_snd_soc_register_card(dev, card); +} + +static struct platform_driver avs_rt5663_driver = { + .probe = avs_rt5663_probe, + .driver = { + .name = "avs_rt5663", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(avs_rt5663_driver); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:avs_rt5663"); From 3ed180ac3cec77fe193573adcbaaca34bbc63551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 29 Jun 2023 13:24:47 +0200 Subject: [PATCH 012/334] ASoC: Intel: avs: Load rt5663 board on KBL-based platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update board-selection tables to account for rt5663 on KBL-based platforms. Signed-off-by: Amadeusz Sławiński Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20230629112449.1755928-7-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/board_selection.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index 5dc55f14b5a3..f91ef6c9612f 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -135,6 +135,14 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = { }, .tplg_filename = "max98927-tplg.bin", }, + { + .id = "10EC5663", + .drv_name = "avs_rt5663", + .mach_params = { + .i2s_link_mask = AVS_SSP(1), + }, + .tplg_filename = "rt5663-tplg.bin", + }, { .id = "MX98373", .drv_name = "avs_max98373", From 27cd41698de49c8afbcc148a0d76c35da3271519 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 29 Jun 2023 13:24:48 +0200 Subject: [PATCH 013/334] ASoC: Intel: avs: rt5682: Add missing components Align with what's done for all other boards and allocate jacks pins dynamically and explicitly specify ->dai_fmt for the DAI link. The latter clears any ambiguity - given the current implementation of the codec driver, specifying format is optional but should the implementation change, the sound card behaviour may be undesired. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20230629112449.1755928-8-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/rt5682.c | 32 +++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c index 7142a67900bf..bd0902bb5a37 100644 --- a/sound/soc/intel/avs/boards/rt5682.c +++ b/sound/soc/intel/avs/boards/rt5682.c @@ -79,14 +79,31 @@ static const struct snd_soc_dapm_route card_base_routes[] = { { "IN1P", NULL, "Headset Mic" }, }; +static struct snd_soc_jack_pin card_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component; - struct snd_soc_jack *jack; struct snd_soc_card *card = runtime->card; - int ret; + 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_jack_pins); + + pins = devm_kmemdup(card->dev, card_jack_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + if (!pins) + return -ENOMEM; /* Need to enable ASRC function for 24MHz mclk rate */ if ((avs_rt5682_quirk & AVS_RT5682_MCLK_EN) && @@ -95,12 +112,10 @@ static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime) RT5682_AD_STEREO1_FILTER, RT5682_CLK_SEL_I2S1_ASRC); } - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack); + + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack, + pins, num_pins); if (ret) { dev_err(card->dev, "Headset Jack creation failed: %d\n", ret); return ret; @@ -220,6 +235,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in 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_rt5682_codec_init; dl->exit = avs_rt5682_codec_exit; dl->be_hw_params_fixup = avs_rt5682_be_fixup; From 7012fa7d56b7b3e100e4ff0c8d8d7a183f09130d Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 29 Jun 2023 13:24:49 +0200 Subject: [PATCH 014/334] ASoC: Intel: avs: rt5682: Tidy up hw_params() To improve readability, reword several local variables to better match their counterparts in declarations of soc-dai.h. For similar reasons, wording for few comments is streamlined while redundant comments are removed. No functional changes. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20230629112449.1755928-9-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/rt5682.c | 35 +++++++++++++---------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c index bd0902bb5a37..b93468ae0977 100644 --- a/sound/soc/intel/avs/boards/rt5682.c +++ b/sound/soc/intel/avs/boards/rt5682.c @@ -145,39 +145,36 @@ avs_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_para { struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0); - int clk_id, clk_freq; - int pll_out, ret; + int pll_source, freq_in, freq_out; + int ret; if (avs_rt5682_quirk & AVS_RT5682_MCLK_EN) { - clk_id = RT5682_PLL1_S_MCLK; + pll_source = RT5682_PLL1_S_MCLK; if (avs_rt5682_quirk & AVS_RT5682_MCLK_24MHZ) - clk_freq = 24000000; + freq_in = 24000000; else - clk_freq = 19200000; + freq_in = 19200000; } else { - clk_id = RT5682_PLL1_S_BCLK1; - clk_freq = params_rate(params) * 50; + pll_source = RT5682_PLL1_S_BCLK1; + freq_in = params_rate(params) * 50; } - pll_out = params_rate(params) * 512; + freq_out = params_rate(params) * 512; - ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); + ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1, pll_source, freq_in, freq_out); if (ret < 0) - dev_err(runtime->dev, "snd_soc_dai_set_pll err = %d\n", ret); + dev_err(runtime->dev, "Set PLL failed: %d\n", ret); - /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, pll_out, SND_SOC_CLOCK_IN); + ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, freq_out, SND_SOC_CLOCK_IN); if (ret < 0) - dev_err(runtime->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + dev_err(runtime->dev, "Set sysclk failed: %d\n", ret); - /* slot_width should equal or large than data length, set them be the same */ + /* slot_width should be equal or larger than data length. */ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, params_width(params)); - if (ret < 0) { - dev_err(runtime->dev, "set TDM slot err:%d\n", ret); - return ret; - } + if (ret < 0) + dev_err(runtime->dev, "Set TDM slot failed: %d\n", ret); - return 0; + return ret; } static const struct snd_soc_ops avs_rt5682_ops = { From fd9965235099fc4cccd94f82a371192bf7645a3e Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Thu, 29 Jun 2023 15:43:47 +0800 Subject: [PATCH 015/334] ASoC: mediatek: mt8188: add memory-region support In certain projects, it is necessary to utilize the reserved memory region for audio dma. The patch takes into account the dts property 'memory-region', allowing for the specification of memory for afe memif through device tree. Signed-off-by: Trevor Wu Link: https://lore.kernel.org/r/20230629074348.21670-2-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8188/mt8188-afe-pcm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c index 6a24b339444b..5e14655c5617 100644 --- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c +++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -3193,11 +3194,15 @@ static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev) { struct mtk_base_afe *afe; struct mt8188_afe_private *afe_priv; - struct device *dev; + struct device *dev = &pdev->dev; struct reset_control *rstc; struct regmap *infra_ao; int i, irq_id, ret; + ret = of_reserved_mem_device_init(dev); + if (ret) + dev_dbg(dev, "failed to assign memory region: %d\n", ret); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33)); if (ret) return ret; @@ -3213,7 +3218,6 @@ static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev) afe_priv = afe->platform_priv; afe->dev = &pdev->dev; - dev = afe->dev; afe->base_addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(afe->base_addr)) From e3326e3bc4937622b4dc6e9721262483109b0f0c Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Thu, 29 Jun 2023 15:43:48 +0800 Subject: [PATCH 016/334] ASoC: dt-bindings: mediatek,mt8188-afe: add memory-region Add memory-region property to utilize the reserved memory region. Signed-off-by: Trevor Wu Acked-by: Rob Herring Link: https://lore.kernel.org/r/20230629074348.21670-3-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/mediatek,mt8188-afe.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8188-afe.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8188-afe.yaml index e6cb711ece77..0b92c71d8779 100644 --- a/Documentation/devicetree/bindings/sound/mediatek,mt8188-afe.yaml +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8188-afe.yaml @@ -25,6 +25,12 @@ properties: reset-names: const: audiosys + memory-region: + maxItems: 1 + description: | + Shared memory region for AFE memif. A "shared-dma-pool". + See ../reserved-memory/reserved-memory.yaml for details. + mediatek,topckgen: $ref: /schemas/types.yaml#/definitions/phandle description: The phandle of the mediatek topckgen controller @@ -176,6 +182,7 @@ examples: interrupts = ; resets = <&watchdog 14>; reset-names = "audiosys"; + memory-region = <&snd_dma_mem_reserved>; mediatek,topckgen = <&topckgen>; mediatek,infracfg = <&infracfg_ao>; power-domains = <&spm 13>; //MT8188_POWER_DOMAIN_AUDIO From e61b415515d3db57dce3af3e4a0441f08d8d8f15 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:05 +0530 Subject: [PATCH 017/334] ASoC: amd: acp: refactor the acp init and de-init sequence Remove the individual acp init and de-init functions from different variants of acp pci driver(for renoir/rembrandt platforms) and use a common file to define callbacks and refactor the callbacks to support existing platforms. Signed-off-by: Syed Saba Kareem Link: https://lore.kernel.org/r/20230626135515.1252063-2-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/Kconfig | 4 + sound/soc/amd/acp/Makefile | 2 + sound/soc/amd/acp/acp-legacy-common.c | 99 +++++++++++++++++++++++ sound/soc/amd/acp/acp-pci.c | 9 +++ sound/soc/amd/acp/acp-rembrandt.c | 110 -------------------------- sound/soc/amd/acp/acp-renoir.c | 92 --------------------- sound/soc/amd/acp/amd.h | 21 +++++ 7 files changed, 135 insertions(+), 202 deletions(-) create mode 100644 sound/soc/amd/acp/acp-legacy-common.c diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index ce0037810743..6a369e5d825c 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -18,6 +18,9 @@ if SND_SOC_AMD_ACP_COMMON config SND_SOC_AMD_ACP_PDM tristate +config SND_SOC_AMD_ACP_LEGACY_COMMON + tristate + config SND_SOC_AMD_ACP_I2S tristate @@ -28,6 +31,7 @@ config SND_SOC_AMD_ACP_PCM config SND_SOC_AMD_ACP_PCI tristate "AMD ACP PCI Driver Support" depends on X86 && PCI + select SND_SOC_AMD_ACP_LEGACY_COMMON help This options enables generic PCI driver for ACP device. diff --git a/sound/soc/amd/acp/Makefile b/sound/soc/amd/acp/Makefile index d9abb0ee5218..4e65fdbc8dca 100644 --- a/sound/soc/amd/acp/Makefile +++ b/sound/soc/amd/acp/Makefile @@ -8,6 +8,7 @@ snd-acp-pcm-objs := acp-platform.o snd-acp-i2s-objs := acp-i2s.o snd-acp-pdm-objs := acp-pdm.o +snd-acp-legacy-common-objs := acp-legacy-common.o snd-acp-pci-objs := acp-pci.o #platform specific driver @@ -22,6 +23,7 @@ snd-acp-sof-mach-objs := acp-sof-mach.o obj-$(CONFIG_SND_SOC_AMD_ACP_PCM) += snd-acp-pcm.o obj-$(CONFIG_SND_SOC_AMD_ACP_I2S) += snd-acp-i2s.o obj-$(CONFIG_SND_SOC_AMD_ACP_PDM) += snd-acp-pdm.o +obj-$(CONFIG_SND_SOC_AMD_ACP_LEGACY_COMMON) += snd-acp-legacy-common.o obj-$(CONFIG_SND_SOC_AMD_ACP_PCI) += snd-acp-pci.o obj-$(CONFIG_SND_AMD_ASOC_RENOIR) += snd-acp-renoir.o diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c new file mode 100644 index 000000000000..5b7000eae693 --- /dev/null +++ b/sound/soc/amd/acp/acp-legacy-common.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2023 Advanced Micro Devices, Inc. +// +// Authors: Syed Saba Kareem +// + +/* + * Common file to be used by amd platforms + */ + +#include "amd.h" +#include + +static int acp_power_on(struct acp_chip_info *chip) +{ + u32 val, acp_pgfsm_stat_reg, acp_pgfsm_ctrl_reg; + void __iomem *base; + + base = chip->base; + switch (chip->acp_rev) { + case ACP3X_DEV: + acp_pgfsm_stat_reg = ACP_PGFSM_STATUS; + acp_pgfsm_ctrl_reg = ACP_PGFSM_CONTROL; + break; + case ACP6X_DEV: + acp_pgfsm_stat_reg = ACP6X_PGFSM_STATUS; + acp_pgfsm_ctrl_reg = ACP6X_PGFSM_CONTROL; + break; + default: + return -EINVAL; + } + + val = readl(base + acp_pgfsm_stat_reg); + if (val == ACP_POWERED_ON) + return 0; + + if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS) + writel(ACP_PGFSM_CNTL_POWER_ON_MASK, base + acp_pgfsm_ctrl_reg); + + return readl_poll_timeout(base + acp_pgfsm_stat_reg, val, + !val, DELAY_US, ACP_TIMEOUT); +} + +static int acp_reset(void __iomem *base) +{ + u32 val; + int ret; + + writel(1, base + ACP_SOFT_RESET); + ret = readl_poll_timeout(base + ACP_SOFT_RESET, val, val & ACP_SOFT_RST_DONE_MASK, + DELAY_US, ACP_TIMEOUT); + if (ret) + return ret; + + writel(0, base + ACP_SOFT_RESET); + return readl_poll_timeout(base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT); +} + +int acp_init(struct acp_chip_info *chip) +{ + int ret; + + /* power on */ + ret = acp_power_on(chip); + if (ret) { + pr_err("ACP power on failed\n"); + return ret; + } + writel(0x01, chip->base + ACP_CONTROL); + + /* Reset */ + ret = acp_reset(chip->base); + if (ret) { + pr_err("ACP reset failed\n"); + return ret; + } + return 0; +} +EXPORT_SYMBOL_NS_GPL(acp_init, SND_SOC_ACP_COMMON); + +int acp_deinit(void __iomem *base) +{ + int ret; + + /* Reset */ + ret = acp_reset(base); + if (ret) + return ret; + + writel(0, base + ACP_CONTROL); + return 0; +} +EXPORT_SYMBOL_NS_GPL(acp_deinit, SND_SOC_ACP_COMMON); + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index 8154fbfd1229..a51cf7f32f7d 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -106,6 +106,7 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id goto unregister_dmic_dev; } + acp_init(chip); res = devm_kcalloc(&pci->dev, num_res, sizeof(struct resource), GFP_KERNEL); if (!res) { ret = -ENOMEM; @@ -154,10 +155,17 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id static void acp_pci_remove(struct pci_dev *pci) { + struct acp_chip_info *chip; + int ret; + + chip = pci_get_drvdata(pci); if (dmic_dev) platform_device_unregister(dmic_dev); if (pdev) platform_device_unregister(pdev); + ret = acp_deinit(chip->base); + if (ret) + dev_err(&pci->dev, "ACP de-init failed\n"); } /* PCI IDs */ @@ -177,4 +185,5 @@ static struct pci_driver snd_amd_acp_pci_driver = { module_pci_driver(snd_amd_acp_pci_driver); MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_ACP_COMMON); MODULE_ALIAS(DRV_NAME); diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c index 1b997837c7d8..59b1653b8479 100644 --- a/sound/soc/amd/acp/acp-rembrandt.c +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -24,26 +24,6 @@ #define DRV_NAME "acp_asoc_rembrandt" -#define ACP6X_PGFSM_CONTROL 0x1024 -#define ACP6X_PGFSM_STATUS 0x1028 - -#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001 - -#define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01 -#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0x00 -#define ACP_PGFSM_STATUS_MASK 0x03 -#define ACP_POWERED_ON 0x00 -#define ACP_POWER_ON_IN_PROGRESS 0x01 -#define ACP_POWERED_OFF 0x02 -#define ACP_POWER_OFF_IN_PROGRESS 0x03 - -#define ACP_ERROR_MASK 0x20000000 -#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF - - -static int rmb_acp_init(void __iomem *base); -static int rmb_acp_deinit(void __iomem *base); - static struct acp_resource rsrc = { .offset = 0, .no_of_ctrls = 2, @@ -180,54 +160,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = { }, }; -static int acp6x_power_on(void __iomem *base) -{ - u32 val; - int timeout; - - val = readl(base + ACP6X_PGFSM_STATUS); - - if (val == ACP_POWERED_ON) - return 0; - - if ((val & ACP_PGFSM_STATUS_MASK) != - ACP_POWER_ON_IN_PROGRESS) - writel(ACP_PGFSM_CNTL_POWER_ON_MASK, - base + ACP6X_PGFSM_CONTROL); - timeout = 0; - while (++timeout < 500) { - val = readl(base + ACP6X_PGFSM_STATUS); - if (!val) - return 0; - udelay(1); - } - return -ETIMEDOUT; -} - -static int acp6x_reset(void __iomem *base) -{ - u32 val; - int timeout; - - writel(1, base + ACP_SOFT_RESET); - timeout = 0; - while (++timeout < 500) { - val = readl(base + ACP_SOFT_RESET); - if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK) - break; - cpu_relax(); - } - writel(0, base + ACP_SOFT_RESET); - timeout = 0; - while (++timeout < 500) { - val = readl(base + ACP_SOFT_RESET); - if (!val) - return 0; - cpu_relax(); - } - return -ETIMEDOUT; -} - static void acp6x_enable_interrupts(struct acp_dev_data *adata) { struct acp_resource *rsrc = adata->rsrc; @@ -248,43 +180,6 @@ static void acp6x_disable_interrupts(struct acp_dev_data *adata) writel(0x00, ACP_EXTERNAL_INTR_ENB(adata)); } -static int rmb_acp_init(void __iomem *base) -{ - int ret; - - /* power on */ - ret = acp6x_power_on(base); - if (ret) { - pr_err("ACP power on failed\n"); - return ret; - } - writel(0x01, base + ACP_CONTROL); - - /* Reset */ - ret = acp6x_reset(base); - if (ret) { - pr_err("ACP reset failed\n"); - return ret; - } - - return 0; -} - -static int rmb_acp_deinit(void __iomem *base) -{ - int ret = 0; - - /* Reset */ - ret = acp6x_reset(base); - if (ret) { - pr_err("ACP reset failed\n"); - return ret; - } - - writel(0x00, base + ACP_CONTROL); - return 0; -} - static int rembrandt_audio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -303,8 +198,6 @@ static int rembrandt_audio_probe(struct platform_device *pdev) return -ENODEV; } - rmb_acp_init(chip->base); - adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL); if (!adata) return -ENOMEM; @@ -345,9 +238,6 @@ static void rembrandt_audio_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); - struct acp_chip_info *chip = dev_get_platdata(dev); - - rmb_acp_deinit(chip->base); acp6x_disable_interrupts(adata); acp_platform_unregister(dev); diff --git a/sound/soc/amd/acp/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c index f188365fe214..a73fd70171c1 100644 --- a/sound/soc/amd/acp/acp-renoir.c +++ b/sound/soc/amd/acp/acp-renoir.c @@ -25,20 +25,6 @@ #define DRV_NAME "acp_asoc_renoir" -#define ACP_SOFT_RST_DONE_MASK 0x00010001 - -#define ACP_PWR_ON_MASK 0x01 -#define ACP_PWR_OFF_MASK 0x00 -#define ACP_PGFSM_STAT_MASK 0x03 -#define ACP_POWERED_ON 0x00 -#define ACP_PWR_ON_IN_PROGRESS 0x01 -#define ACP_POWERED_OFF 0x02 -#define DELAY_US 5 -#define ACP_TIMEOUT 500 - -#define ACP_ERROR_MASK 0x20000000 -#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF - static struct acp_resource rsrc = { .offset = 20, .no_of_ctrls = 1, @@ -154,38 +140,6 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = { }, }; -static int acp3x_power_on(void __iomem *base) -{ - u32 val; - - val = readl(base + ACP_PGFSM_STATUS); - - if (val == ACP_POWERED_ON) - return 0; - - if ((val & ACP_PGFSM_STAT_MASK) != ACP_PWR_ON_IN_PROGRESS) - writel(ACP_PWR_ON_MASK, base + ACP_PGFSM_CONTROL); - - return readl_poll_timeout(base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP_TIMEOUT); -} - -static int acp3x_reset(void __iomem *base) -{ - u32 val; - int ret; - - writel(1, base + ACP_SOFT_RESET); - - ret = readl_poll_timeout(base + ACP_SOFT_RESET, val, val & ACP_SOFT_RST_DONE_MASK, - DELAY_US, ACP_TIMEOUT); - if (ret) - return ret; - - writel(0, base + ACP_SOFT_RESET); - - return readl_poll_timeout(base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT); -} - static void acp3x_enable_interrupts(struct acp_dev_data *adata) { struct acp_resource *rsrc = adata->rsrc; @@ -206,37 +160,6 @@ static void acp3x_disable_interrupts(struct acp_dev_data *adata) writel(0x00, ACP_EXTERNAL_INTR_ENB(adata)); } -static int rn_acp_init(void __iomem *base) -{ - int ret; - - /* power on */ - ret = acp3x_power_on(base); - if (ret) - return ret; - - writel(0x01, base + ACP_CONTROL); - - /* Reset */ - ret = acp3x_reset(base); - if (ret) - return ret; - - return 0; -} - -static int rn_acp_deinit(void __iomem *base) -{ - int ret = 0; - - /* Reset */ - ret = acp3x_reset(base); - if (ret) - return ret; - - writel(0x00, base + ACP_CONTROL); - return 0; -} static int renoir_audio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -256,12 +179,6 @@ static int renoir_audio_probe(struct platform_device *pdev) return -ENODEV; } - ret = rn_acp_init(chip->base); - if (ret) { - dev_err(&pdev->dev, "ACP Init failed\n"); - return -EINVAL; - } - adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL); if (!adata) return -ENOMEM; @@ -300,17 +217,8 @@ static void renoir_audio_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); - struct acp_chip_info *chip; - int ret; - - chip = dev_get_platdata(&pdev->dev); acp3x_disable_interrupts(adata); - - ret = rn_acp_deinit(chip->base); - if (ret) - dev_err(&pdev->dev, "ACP de-init Failed (%pe)\n", ERR_PTR(ret)); - acp_platform_unregister(dev); } diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index 12a176a50fd6..19327c4edcf3 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -92,6 +92,25 @@ #define SLOT_WIDTH_24 0x18 #define SLOT_WIDTH_32 0x20 +#define ACP6X_PGFSM_CONTROL 0x1024 +#define ACP6X_PGFSM_STATUS 0x1028 + +#define ACP_SOFT_RST_DONE_MASK 0x00010001 + +#define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01 +#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0x00 +#define ACP_PGFSM_STATUS_MASK 0x03 +#define ACP_POWERED_ON 0x00 +#define ACP_POWER_ON_IN_PROGRESS 0x01 +#define ACP_POWERED_OFF 0x02 +#define ACP_POWER_OFF_IN_PROGRESS 0x03 + +#define ACP_ERROR_MASK 0x20000000 +#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xffffffff + +#define ACP_TIMEOUT 500 +#define DELAY_US 5 + struct acp_chip_info { char *name; /* Platform name */ unsigned int acp_rev; /* ACP Revision id */ @@ -168,6 +187,8 @@ int acp_platform_unregister(struct device *dev); int acp_machine_select(struct acp_dev_data *adata); +int acp_init(struct acp_chip_info *chip); +int acp_deinit(void __iomem *base); /* Machine configuration */ int snd_amd_acp_find_config(struct pci_dev *pci); From 7ad6fb9dd1ca63f9f36e413036f36f075cdaec4a Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:06 +0530 Subject: [PATCH 018/334] ASoC: amd: acp: add acp i2s master clock generation for rembrandt platform Add acp i2s master clock generation logic for rembrandt platform. Signed-off-by: V Sujith Kumar Reddy Signed-off-by: Syed Saba Kareem Link: https://lore.kernel.org/r/20230626135515.1252063-3-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-legacy-common.c | 19 +++++++++++++++++++ sound/soc/amd/acp/acp-rembrandt.c | 26 ++++++++++++++++++++++++++ sound/soc/amd/acp/amd.h | 3 +++ 3 files changed, 48 insertions(+) diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c index 5b7000eae693..4302d8db88a4 100644 --- a/sound/soc/amd/acp/acp-legacy-common.c +++ b/sound/soc/amd/acp/acp-legacy-common.c @@ -13,6 +13,7 @@ */ #include "amd.h" +#include #include static int acp_power_on(struct acp_chip_info *chip) @@ -96,4 +97,22 @@ int acp_deinit(void __iomem *base) } EXPORT_SYMBOL_NS_GPL(acp_deinit, SND_SOC_ACP_COMMON); +int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data) +{ + pci_write_config_dword(dev, 0x60, smn_addr); + pci_write_config_dword(dev, 0x64, data); + return 0; +} +EXPORT_SYMBOL_NS_GPL(smn_write, SND_SOC_ACP_COMMON); + +int smn_read(struct pci_dev *dev, u32 smn_addr) +{ + u32 data; + + pci_write_config_dword(dev, 0x60, smn_addr); + pci_read_config_dword(dev, 0x64, &data); + return data; +} +EXPORT_SYMBOL_NS_GPL(smn_read, SND_SOC_ACP_COMMON); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c index 59b1653b8479..82a1bf2ddfc6 100644 --- a/sound/soc/amd/acp/acp-rembrandt.c +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -19,11 +19,17 @@ #include #include #include +#include #include "amd.h" #define DRV_NAME "acp_asoc_rembrandt" +#define MP1_C2PMSG_69 0x3B10A14 +#define MP1_C2PMSG_85 0x3B10A54 +#define MP1_C2PMSG_93 0x3B10A74 +#define HOST_BRIDGE_ID 0x14B5 + static struct acp_resource rsrc = { .offset = 0, .no_of_ctrls = 2, @@ -160,6 +166,25 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = { }, }; +static int acp6x_master_clock_generate(struct device *dev) +{ + int data = 0; + struct pci_dev *smn_dev; + + smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, HOST_BRIDGE_ID, NULL); + if (!smn_dev) { + dev_err(dev, "Failed to get host bridge device\n"); + return -ENODEV; + } + + smn_write(smn_dev, MP1_C2PMSG_93, 0); + smn_write(smn_dev, MP1_C2PMSG_85, 0xC4); + smn_write(smn_dev, MP1_C2PMSG_69, 0x4); + read_poll_timeout(smn_read, data, data, DELAY_US, + ACP_TIMEOUT, false, smn_dev, MP1_C2PMSG_93); + return 0; +} + static void acp6x_enable_interrupts(struct acp_dev_data *adata) { struct acp_resource *rsrc = adata->rsrc; @@ -228,6 +253,7 @@ static int rembrandt_audio_probe(struct platform_device *pdev) acp_machine_select(adata); dev_set_drvdata(dev, adata); + acp6x_master_clock_generate(dev); acp6x_enable_interrupts(adata); acp_platform_register(dev); diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index 19327c4edcf3..64f70d5a46fa 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -187,6 +187,9 @@ int acp_platform_unregister(struct device *dev); int acp_machine_select(struct acp_dev_data *adata); +int smn_read(struct pci_dev *dev, u32 smn_addr); +int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data); + int acp_init(struct acp_chip_info *chip); int acp_deinit(void __iomem *base); /* Machine configuration */ From fc11d3266dc7ed386efe91c20d09780bbded1f03 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:07 +0530 Subject: [PATCH 019/334] ASoC: amd: acp: remove the redundant acp enable/disable interrupts functions Instead of having individual acp enable/disable interrupts functions for each platform, implement common place holder to handle the same for all AMD platforms. Signed-off-by: Syed Saba Kareem Link: https://lore.kernel.org/r/20230626135515.1252063-4-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/Kconfig | 3 ++- sound/soc/amd/acp/acp-legacy-common.c | 21 +++++++++++++++++++++ sound/soc/amd/acp/acp-rembrandt.c | 24 ++---------------------- sound/soc/amd/acp/acp-renoir.c | 23 ++--------------------- sound/soc/amd/acp/amd.h | 2 ++ 5 files changed, 29 insertions(+), 44 deletions(-) diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index 6a369e5d825c..3aca8109475b 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -31,7 +31,6 @@ config SND_SOC_AMD_ACP_PCM config SND_SOC_AMD_ACP_PCI tristate "AMD ACP PCI Driver Support" depends on X86 && PCI - select SND_SOC_AMD_ACP_LEGACY_COMMON help This options enables generic PCI driver for ACP device. @@ -40,6 +39,7 @@ config SND_AMD_ASOC_RENOIR select SND_SOC_AMD_ACP_PCM select SND_SOC_AMD_ACP_I2S select SND_SOC_AMD_ACP_PDM + select SND_SOC_AMD_ACP_LEGACY_COMMON depends on X86 && PCI help This option enables Renoir I2S support on AMD platform. @@ -49,6 +49,7 @@ config SND_AMD_ASOC_REMBRANDT select SND_SOC_AMD_ACP_PCM select SND_SOC_AMD_ACP_I2S select SND_SOC_AMD_ACP_PDM + select SND_SOC_AMD_ACP_LEGACY_COMMON depends on X86 && PCI help This option enables Rembrandt I2S support on AMD platform. diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c index 4302d8db88a4..45a45d002915 100644 --- a/sound/soc/amd/acp/acp-legacy-common.c +++ b/sound/soc/amd/acp/acp-legacy-common.c @@ -16,6 +16,27 @@ #include #include +void acp_enable_interrupts(struct acp_dev_data *adata) +{ + struct acp_resource *rsrc = adata->rsrc; + u32 ext_intr_ctrl; + + writel(0x01, ACP_EXTERNAL_INTR_ENB(adata)); + ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); + ext_intr_ctrl |= ACP_ERROR_MASK; + writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); +} +EXPORT_SYMBOL_NS_GPL(acp_enable_interrupts, SND_SOC_ACP_COMMON); + +void acp_disable_interrupts(struct acp_dev_data *adata) +{ + struct acp_resource *rsrc = adata->rsrc; + + writel(ACP_EXT_INTR_STAT_CLEAR_MASK, ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); + writel(0x00, ACP_EXTERNAL_INTR_ENB(adata)); +} +EXPORT_SYMBOL_NS_GPL(acp_disable_interrupts, SND_SOC_ACP_COMMON); + static int acp_power_on(struct acp_chip_info *chip) { u32 val, acp_pgfsm_stat_reg, acp_pgfsm_ctrl_reg; diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c index 82a1bf2ddfc6..ea3d4aadc8e1 100644 --- a/sound/soc/amd/acp/acp-rembrandt.c +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -185,26 +185,6 @@ static int acp6x_master_clock_generate(struct device *dev) return 0; } -static void acp6x_enable_interrupts(struct acp_dev_data *adata) -{ - struct acp_resource *rsrc = adata->rsrc; - u32 ext_intr_ctrl; - - writel(0x01, ACP_EXTERNAL_INTR_ENB(adata)); - ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); - ext_intr_ctrl |= ACP_ERROR_MASK; - writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); -} - -static void acp6x_disable_interrupts(struct acp_dev_data *adata) -{ - struct acp_resource *rsrc = adata->rsrc; - - writel(ACP_EXT_INTR_STAT_CLEAR_MASK, - ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); - writel(0x00, ACP_EXTERNAL_INTR_ENB(adata)); -} - static int rembrandt_audio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -254,7 +234,7 @@ static int rembrandt_audio_probe(struct platform_device *pdev) dev_set_drvdata(dev, adata); acp6x_master_clock_generate(dev); - acp6x_enable_interrupts(adata); + acp_enable_interrupts(adata); acp_platform_register(dev); return 0; @@ -265,7 +245,7 @@ static void rembrandt_audio_remove(struct platform_device *pdev) struct device *dev = &pdev->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); - acp6x_disable_interrupts(adata); + acp_disable_interrupts(adata); acp_platform_unregister(dev); } diff --git a/sound/soc/amd/acp/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c index a73fd70171c1..1899658ab25d 100644 --- a/sound/soc/amd/acp/acp-renoir.c +++ b/sound/soc/amd/acp/acp-renoir.c @@ -140,25 +140,6 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = { }, }; -static void acp3x_enable_interrupts(struct acp_dev_data *adata) -{ - struct acp_resource *rsrc = adata->rsrc; - u32 ext_intr_ctrl; - - writel(0x01, ACP_EXTERNAL_INTR_ENB(adata)); - ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); - ext_intr_ctrl |= ACP_ERROR_MASK; - writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); -} - -static void acp3x_disable_interrupts(struct acp_dev_data *adata) -{ - struct acp_resource *rsrc = adata->rsrc; - - writel(ACP_EXT_INTR_STAT_CLEAR_MASK, - ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); - writel(0x00, ACP_EXTERNAL_INTR_ENB(adata)); -} static int renoir_audio_probe(struct platform_device *pdev) { @@ -207,7 +188,7 @@ static int renoir_audio_probe(struct platform_device *pdev) acp_machine_select(adata); dev_set_drvdata(dev, adata); - acp3x_enable_interrupts(adata); + acp_enable_interrupts(adata); acp_platform_register(dev); return 0; @@ -218,7 +199,7 @@ static void renoir_audio_remove(struct platform_device *pdev) struct device *dev = &pdev->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); - acp3x_disable_interrupts(adata); + acp_disable_interrupts(adata); acp_platform_unregister(dev); } diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index 64f70d5a46fa..c9cbda9c64ca 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -192,6 +192,8 @@ int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data); int acp_init(struct acp_chip_info *chip); int acp_deinit(void __iomem *base); +void acp_enable_interrupts(struct acp_dev_data *adata); +void acp_disable_interrupts(struct acp_dev_data *adata); /* Machine configuration */ int snd_amd_acp_find_config(struct pci_dev *pci); From 7a83903022dc3bd5214f6bdde8132c66015ab538 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:08 +0530 Subject: [PATCH 020/334] ASoC: amd: acp: store platform device reference created in pci probe call Store the platform device reference created in pci driver, it will be used in restoring the interrupts during system level resume. Signed-off-by: Syed Saba Kareem Link: https://lore.kernel.org/r/20230626135515.1252063-5-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-pci.c | 2 +- sound/soc/amd/acp/amd.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index a51cf7f32f7d..4fedad1b740e 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -140,7 +140,7 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id ret = PTR_ERR(pdev); goto unregister_dmic_dev; } - + chip->chip_pdev = pdev; return ret; unregister_dmic_dev: diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index c9cbda9c64ca..50a00974bec9 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -115,6 +115,7 @@ struct acp_chip_info { char *name; /* Platform name */ unsigned int acp_rev; /* ACP Revision id */ void __iomem *base; /* ACP memory PCI base */ + struct platform_device *chip_pdev; }; struct acp_stream { From 088a40980efbc2c449b72f0f2c7ebd82f71d08e2 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:09 +0530 Subject: [PATCH 021/334] ASoC: amd: acp: add pm ops support for acp pci driver Add pm ops support for common acp pci driver. Signed-off-by: Syed Saba Kareem Link: https://lore.kernel.org/r/20230626135515.1252063-6-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-pci.c | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index 4fedad1b740e..a32c14a109b7 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "amd.h" #include "../mach-config.h" @@ -141,6 +142,11 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id goto unregister_dmic_dev; } chip->chip_pdev = pdev; + dev_set_drvdata(&pci->dev, chip); + pm_runtime_set_autosuspend_delay(&pci->dev, 2000); + pm_runtime_use_autosuspend(&pci->dev); + pm_runtime_put_noidle(&pci->dev); + pm_runtime_allow(&pci->dev); return ret; unregister_dmic_dev: @@ -153,12 +159,49 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id return ret; }; +static int __maybe_unused snd_acp_suspend(struct device *dev) +{ + struct acp_chip_info *chip; + int ret; + + chip = dev_get_drvdata(dev); + ret = acp_deinit(chip->base); + if (ret) + dev_err(dev, "ACP de-init failed\n"); + return ret; +} + +static int __maybe_unused snd_acp_resume(struct device *dev) +{ + struct acp_chip_info *chip; + struct acp_dev_data *adata; + struct device child; + int ret; + + chip = dev_get_drvdata(dev); + ret = acp_init(chip); + if (ret) + dev_err(dev, "ACP init failed\n"); + child = chip->chip_pdev->dev; + adata = dev_get_drvdata(&child); + if (adata) + acp_enable_interrupts(adata); + return ret; +} + +static const struct dev_pm_ops acp_pm_ops = { + SET_RUNTIME_PM_OPS(snd_acp_suspend, snd_acp_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(snd_acp_suspend, snd_acp_resume) +}; + static void acp_pci_remove(struct pci_dev *pci) { struct acp_chip_info *chip; int ret; chip = pci_get_drvdata(pci); + pm_runtime_forbid(&pci->dev); + pm_runtime_get_noresume(&pci->dev); if (dmic_dev) platform_device_unregister(dmic_dev); if (pdev) @@ -181,6 +224,9 @@ static struct pci_driver snd_amd_acp_pci_driver = { .id_table = acp_pci_ids, .probe = acp_pci_probe, .remove = acp_pci_remove, + .driver = { + .pm = &acp_pm_ops, + }, }; module_pci_driver(snd_amd_acp_pci_driver); From c8786ac7bb374276b1c2b545b4a6be3b230be7cb Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:10 +0530 Subject: [PATCH 022/334] ASoC: amd: acp: store xfer_resolution of the stream Store the 'xfer_resolution' of the stream in private data structure, it will be used to reprogram the xfer_resolution for the active stream during system level resume. Signed-off-by: Syed Saba Kareem Link: https://lore.kernel.org/r/20230626135515.1252063-7-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-i2s.c | 2 ++ sound/soc/amd/acp/amd.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 09b6511c0a26..09dc5f2c0bfc 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -149,6 +149,7 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; } + adata->xfer_tx_resolution[dai->driver->id - 1] = xfer_resolution; } else { switch (dai->driver->id) { case I2S_BT_INSTANCE: @@ -167,6 +168,7 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; } + adata->xfer_rx_resolution[dai->driver->id - 1] = xfer_resolution; } val = readl(adata->acp_base + reg_val); diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index 50a00974bec9..42bf6b9e1e3e 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -166,6 +166,8 @@ struct acp_dev_data { struct acp_resource *rsrc; u32 tdm_tx_fmt[3]; u32 tdm_rx_fmt[3]; + u32 xfer_tx_resolution[3]; + u32 xfer_rx_resolution[3]; }; union acp_i2stdm_mstrclkgen { From a8d1316a264f36c2ffe798e42d6b415dc377851e Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:11 +0530 Subject: [PATCH 023/334] ASoC: amd: acp: export config_acp_dma() and config_pte_for_stream() symbols Export config_acp_dma() and config_pte_for_stream() functions. These functions will be used to restore stream configuration during system level resume. Signed-off-by: Syed Saba Kareem Link: https://lore.kernel.org/r/20230626135515.1252063-8-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-platform.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c index f220378ec20e..f516daf6fef4 100644 --- a/sound/soc/amd/acp/acp-platform.c +++ b/sound/soc/amd/acp/acp-platform.c @@ -127,7 +127,7 @@ static irqreturn_t i2s_irq_handler(int irq, void *data) return IRQ_NONE; } -static void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream) +void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream) { struct acp_resource *rsrc = adata->rsrc; u32 pte_reg, pte_size, reg_val; @@ -143,8 +143,9 @@ static void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + pte_size); writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL); } +EXPORT_SYMBOL_NS_GPL(config_pte_for_stream, SND_SOC_ACP_COMMON); -static void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int size) +void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int size) { struct snd_pcm_substream *substream = stream->substream; struct acp_resource *rsrc = adata->rsrc; @@ -168,6 +169,7 @@ static void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream addr += PAGE_SIZE; } } +EXPORT_SYMBOL_NS_GPL(config_acp_dma, SND_SOC_ACP_COMMON); static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { From 7373e6bee60cdac36a134897164885b2257a02ac Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:12 +0530 Subject: [PATCH 024/334] ASoC: amd: acp: store the pdm stream channel mask Store the pdm stream channel mask, it will be used during system level resume. Signed-off-by: Syed Saba Kareem Link: https://lore.kernel.org/r/20230626135515.1252063-9-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-pdm.c | 1 + sound/soc/amd/acp/amd.h | 1 + 2 files changed, 2 insertions(+) diff --git a/sound/soc/amd/acp/acp-pdm.c b/sound/soc/amd/acp/acp-pdm.c index f8030b79ac17..2833d2b7e596 100644 --- a/sound/soc/amd/acp/acp-pdm.c +++ b/sound/soc/amd/acp/acp-pdm.c @@ -135,6 +135,7 @@ static int acp_dmic_hwparams(struct snd_pcm_substream *substream, return -EINVAL; } + adata->ch_mask = ch_mask; if (params_format(hwparams) != SNDRV_PCM_FORMAT_S32_LE) { dev_err(dai->dev, "Invalid format:%d\n", params_format(hwparams)); return -EINVAL; diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index 42bf6b9e1e3e..085f3de53d50 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -164,6 +164,7 @@ struct acp_dev_data { u32 lrclk_div; struct acp_resource *rsrc; + u32 ch_mask; u32 tdm_tx_fmt[3]; u32 tdm_rx_fmt[3]; u32 xfer_tx_resolution[3]; From e3a96e441e05bbf599ce70c2a03e7acd55b275ee Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:13 +0530 Subject: [PATCH 025/334] ASoC: amd: acp: move pdm macros to common header file Move pdm related macros from pdm file to common header file so that it can be used across different files. Signed-off-by: Syed Saba Kareem Link: https://lore.kernel.org/r/20230626135515.1252063-10-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-pdm.c | 12 ------------ sound/soc/amd/acp/amd.h | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/soc/amd/acp/acp-pdm.c b/sound/soc/amd/acp/acp-pdm.c index 2833d2b7e596..f754bf79b5e3 100644 --- a/sound/soc/amd/acp/acp-pdm.c +++ b/sound/soc/amd/acp/acp-pdm.c @@ -25,18 +25,6 @@ #define DRV_NAME "acp-pdm" -#define PDM_DMA_STAT 0x10 -#define PDM_DMA_INTR_MASK 0x10000 -#define PDM_DEC_64 0x2 -#define PDM_CLK_FREQ_MASK 0x07 -#define PDM_MISC_CTRL_MASK 0x10 -#define PDM_ENABLE 0x01 -#define PDM_DISABLE 0x00 -#define DMA_EN_MASK 0x02 -#define DELAY_US 5 -#define PDM_TIMEOUT 1000 -#define ACP_REGION2_OFFSET 0x02000000 - static int acp_dmic_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index 085f3de53d50..15f772ce5286 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -111,6 +111,18 @@ #define ACP_TIMEOUT 500 #define DELAY_US 5 +#define PDM_DMA_STAT 0x10 +#define PDM_DMA_INTR_MASK 0x10000 +#define PDM_DEC_64 0x2 +#define PDM_CLK_FREQ_MASK 0x07 +#define PDM_MISC_CTRL_MASK 0x10 +#define PDM_ENABLE 0x01 +#define PDM_DISABLE 0x00 +#define DMA_EN_MASK 0x02 +#define DELAY_US 5 +#define PDM_TIMEOUT 1000 +#define ACP_REGION2_OFFSET 0x02000000 + struct acp_chip_info { char *name; /* Platform name */ unsigned int acp_rev; /* ACP Revision id */ From 5debf4ae138c81321832d41203483696cac1c580 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:14 +0530 Subject: [PATCH 026/334] ASoC: amd: acp: add pm ops support for rembrandt platform Add pm ops for rembrandt platform. Signed-off-by: Syed Saba Kareem Link: https://lore.kernel.org/r/20230626135515.1252063-11-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-legacy-common.c | 208 ++++++++++++++++++++++++++ sound/soc/amd/acp/acp-rembrandt.c | 42 +++++- sound/soc/amd/acp/amd.h | 9 ++ 3 files changed, 258 insertions(+), 1 deletion(-) diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c index 45a45d002915..ba58165cc6e6 100644 --- a/sound/soc/amd/acp/acp-legacy-common.c +++ b/sound/soc/amd/acp/acp-legacy-common.c @@ -37,6 +37,214 @@ void acp_disable_interrupts(struct acp_dev_data *adata) } EXPORT_SYMBOL_NS_GPL(acp_disable_interrupts, SND_SOC_ACP_COMMON); +static void set_acp_pdm_ring_buffer(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct acp_stream *stream = runtime->private_data; + struct device *dev = dai->component->dev; + struct acp_dev_data *adata = dev_get_drvdata(dev); + + u32 physical_addr, pdm_size, period_bytes; + + period_bytes = frames_to_bytes(runtime, runtime->period_size); + pdm_size = frames_to_bytes(runtime, runtime->buffer_size); + physical_addr = stream->reg_offset + MEM_WINDOW_START; + + /* Init ACP PDM Ring buffer */ + writel(physical_addr, adata->acp_base + ACP_WOV_RX_RINGBUFADDR); + writel(pdm_size, adata->acp_base + ACP_WOV_RX_RINGBUFSIZE); + writel(period_bytes, adata->acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE); + writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL); +} + +static void set_acp_pdm_clk(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct device *dev = dai->component->dev; + struct acp_dev_data *adata = dev_get_drvdata(dev); + unsigned int pdm_ctrl; + + /* Enable default ACP PDM clk */ + writel(PDM_CLK_FREQ_MASK, adata->acp_base + ACP_WOV_CLK_CTRL); + pdm_ctrl = readl(adata->acp_base + ACP_WOV_MISC_CTRL); + pdm_ctrl |= PDM_MISC_CTRL_MASK; + writel(pdm_ctrl, adata->acp_base + ACP_WOV_MISC_CTRL); + set_acp_pdm_ring_buffer(substream, dai); +} + +void restore_acp_pdm_params(struct snd_pcm_substream *substream, + struct acp_dev_data *adata) +{ + struct snd_soc_dai *dai; + struct snd_soc_pcm_runtime *soc_runtime; + u32 ext_int_ctrl; + + soc_runtime = asoc_substream_to_rtd(substream); + dai = asoc_rtd_to_cpu(soc_runtime, 0); + /* Programming channel mask and sampling rate */ + writel(adata->ch_mask, adata->acp_base + ACP_WOV_PDM_NO_OF_CHANNELS); + writel(PDM_DEC_64, adata->acp_base + ACP_WOV_PDM_DECIMATION_FACTOR); + + /* Enabling ACP Pdm interuppts */ + ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, 0)); + ext_int_ctrl |= PDM_DMA_INTR_MASK; + writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, 0)); + set_acp_pdm_clk(substream, dai); +} +EXPORT_SYMBOL_NS_GPL(restore_acp_pdm_params, SND_SOC_ACP_COMMON); + +static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct device *dev = dai->component->dev; + struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_resource *rsrc = adata->rsrc; + struct acp_stream *stream = substream->runtime->private_data; + u32 reg_dma_size, reg_fifo_size, reg_fifo_addr; + u32 phy_addr, acp_fifo_addr, ext_int_ctrl; + unsigned int dir = substream->stream; + + switch (dai->driver->id) { + case I2S_SP_INSTANCE: + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { + reg_dma_size = ACP_I2S_TX_DMA_SIZE; + acp_fifo_addr = rsrc->sram_pte_offset + + SP_PB_FIFO_ADDR_OFFSET; + reg_fifo_addr = ACP_I2S_TX_FIFOADDR; + reg_fifo_size = ACP_I2S_TX_FIFOSIZE; + phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR); + } else { + reg_dma_size = ACP_I2S_RX_DMA_SIZE; + acp_fifo_addr = rsrc->sram_pte_offset + + SP_CAPT_FIFO_ADDR_OFFSET; + reg_fifo_addr = ACP_I2S_RX_FIFOADDR; + reg_fifo_size = ACP_I2S_RX_FIFOSIZE; + phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR); + } + break; + case I2S_BT_INSTANCE: + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { + reg_dma_size = ACP_BT_TX_DMA_SIZE; + acp_fifo_addr = rsrc->sram_pte_offset + + BT_PB_FIFO_ADDR_OFFSET; + reg_fifo_addr = ACP_BT_TX_FIFOADDR; + reg_fifo_size = ACP_BT_TX_FIFOSIZE; + phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR); + } else { + reg_dma_size = ACP_BT_RX_DMA_SIZE; + acp_fifo_addr = rsrc->sram_pte_offset + + BT_CAPT_FIFO_ADDR_OFFSET; + reg_fifo_addr = ACP_BT_RX_FIFOADDR; + reg_fifo_size = ACP_BT_RX_FIFOSIZE; + phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR); + } + break; + case I2S_HS_INSTANCE: + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { + reg_dma_size = ACP_HS_TX_DMA_SIZE; + acp_fifo_addr = rsrc->sram_pte_offset + + HS_PB_FIFO_ADDR_OFFSET; + reg_fifo_addr = ACP_HS_TX_FIFOADDR; + reg_fifo_size = ACP_HS_TX_FIFOSIZE; + phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR); + } else { + reg_dma_size = ACP_HS_RX_DMA_SIZE; + acp_fifo_addr = rsrc->sram_pte_offset + + HS_CAPT_FIFO_ADDR_OFFSET; + reg_fifo_addr = ACP_HS_RX_FIFOADDR; + reg_fifo_size = ACP_HS_RX_FIFOSIZE; + phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR); + } + break; + default: + dev_err(dev, "Invalid dai id %x\n", dai->driver->id); + return -EINVAL; + } + + writel(DMA_SIZE, adata->acp_base + reg_dma_size); + writel(acp_fifo_addr, adata->acp_base + reg_fifo_addr); + writel(FIFO_SIZE, adata->acp_base + reg_fifo_size); + + ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); + ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) | + BIT(BT_RX_THRESHOLD(rsrc->offset)) | + BIT(I2S_TX_THRESHOLD(rsrc->offset)) | + BIT(BT_TX_THRESHOLD(rsrc->offset)) | + BIT(HS_RX_THRESHOLD(rsrc->offset)) | + BIT(HS_TX_THRESHOLD(rsrc->offset)); + + writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); + return 0; +} + +int restore_acp_i2s_params(struct snd_pcm_substream *substream, + struct acp_dev_data *adata, + struct acp_stream *stream) +{ + struct snd_soc_dai *dai; + struct snd_soc_pcm_runtime *soc_runtime; + u32 tdm_fmt, reg_val, fmt_reg, val; + + soc_runtime = asoc_substream_to_rtd(substream); + dai = asoc_rtd_to_cpu(soc_runtime, 0); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + tdm_fmt = adata->tdm_tx_fmt[stream->dai_id - 1]; + switch (stream->dai_id) { + case I2S_BT_INSTANCE: + reg_val = ACP_BTTDM_ITER; + fmt_reg = ACP_BTTDM_TXFRMT; + break; + case I2S_SP_INSTANCE: + reg_val = ACP_I2STDM_ITER; + fmt_reg = ACP_I2STDM_TXFRMT; + break; + case I2S_HS_INSTANCE: + reg_val = ACP_HSTDM_ITER; + fmt_reg = ACP_HSTDM_TXFRMT; + break; + default: + pr_err("Invalid dai id %x\n", stream->dai_id); + return -EINVAL; + } + val = adata->xfer_tx_resolution[stream->dai_id - 1] << 3; + } else { + tdm_fmt = adata->tdm_rx_fmt[stream->dai_id - 1]; + switch (stream->dai_id) { + case I2S_BT_INSTANCE: + reg_val = ACP_BTTDM_IRER; + fmt_reg = ACP_BTTDM_RXFRMT; + break; + case I2S_SP_INSTANCE: + reg_val = ACP_I2STDM_IRER; + fmt_reg = ACP_I2STDM_RXFRMT; + break; + case I2S_HS_INSTANCE: + reg_val = ACP_HSTDM_IRER; + fmt_reg = ACP_HSTDM_RXFRMT; + break; + default: + pr_err("Invalid dai id %x\n", stream->dai_id); + return -EINVAL; + } + val = adata->xfer_rx_resolution[stream->dai_id - 1] << 3; + } + writel(val, adata->acp_base + reg_val); + if (adata->tdm_mode == TDM_ENABLE) { + writel(tdm_fmt, adata->acp_base + fmt_reg); + val = readl(adata->acp_base + reg_val); + writel(val | 0x2, adata->acp_base + reg_val); + } + return set_acp_i2s_dma_fifo(substream, dai); +} +EXPORT_SYMBOL_NS_GPL(restore_acp_i2s_params, SND_SOC_ACP_COMMON); + static int acp_power_on(struct acp_chip_info *chip) { u32 val, acp_pgfsm_stat_reg, acp_pgfsm_ctrl_reg; diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c index ea3d4aadc8e1..89314d95ec2b 100644 --- a/sound/soc/amd/acp/acp-rembrandt.c +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "amd.h" @@ -236,7 +237,11 @@ static int rembrandt_audio_probe(struct platform_device *pdev) acp6x_master_clock_generate(dev); acp_enable_interrupts(adata); acp_platform_register(dev); - + pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); return 0; } @@ -247,13 +252,48 @@ static void rembrandt_audio_remove(struct platform_device *pdev) acp_disable_interrupts(adata); acp_platform_unregister(dev); + pm_runtime_disable(&pdev->dev); } +static int __maybe_unused rmb_pcm_resume(struct device *dev) +{ + struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_stream *stream; + struct snd_pcm_substream *substream; + snd_pcm_uframes_t buf_in_frames; + u64 buf_size; + + acp6x_master_clock_generate(dev); + spin_lock(&adata->acp_lock); + list_for_each_entry(stream, &adata->stream_list, list) { + if (stream) { + substream = stream->substream; + if (substream && substream->runtime) { + buf_in_frames = (substream->runtime->buffer_size); + buf_size = frames_to_bytes(substream->runtime, buf_in_frames); + config_pte_for_stream(adata, stream); + config_acp_dma(adata, stream, buf_size); + if (stream->dai_id) + restore_acp_i2s_params(substream, adata, stream); + else + restore_acp_pdm_params(substream, adata); + } + } + } + spin_unlock(&adata->acp_lock); + return 0; +} + +static const struct dev_pm_ops rmb_dma_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(NULL, rmb_pcm_resume) +}; + static struct platform_driver rembrandt_driver = { .probe = rembrandt_audio_probe, .remove_new = rembrandt_audio_remove, .driver = { .name = "acp_asoc_rembrandt", + .pm = &rmb_dma_pm_ops, }, }; diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index 15f772ce5286..2ebe2099cbb5 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -110,6 +110,7 @@ #define ACP_TIMEOUT 500 #define DELAY_US 5 +#define ACP_SUSPEND_DELAY_MS 2000 #define PDM_DMA_STAT 0x10 #define PDM_DMA_INTR_MASK 0x10000 @@ -213,6 +214,14 @@ void acp_disable_interrupts(struct acp_dev_data *adata); /* Machine configuration */ int snd_amd_acp_find_config(struct pci_dev *pci); +void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream); +void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int size); +void restore_acp_pdm_params(struct snd_pcm_substream *substream, + struct acp_dev_data *adata); + +int restore_acp_i2s_params(struct snd_pcm_substream *substream, + struct acp_dev_data *adata, struct acp_stream *stream); + static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int direction) { u64 byte_count = 0, low = 0, high = 0; From f97fa3dcb2db02013e6904c032a1d2d45707ee40 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 3 Jul 2023 16:52:08 +0300 Subject: [PATCH 027/334] lib/math: Move dvb_math.c into lib/math/int_log.c Some existing and new users may benefit from the intlog2() and intlog10() APIs, make them wide available. Reviewed-by: Mauro Carvalho Chehab Acked-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20230619172019.21457-2-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Reviewed-by: Randy Dunlap Link: https://lore.kernel.org/r/20230703135211.87416-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- Documentation/core-api/kernel-api.rst | 7 +++++-- Documentation/driver-api/media/dtv-common.rst | 9 --------- drivers/media/dvb-core/Makefile | 2 +- drivers/media/dvb-frontends/af9013_priv.h | 2 +- drivers/media/dvb-frontends/af9033_priv.h | 2 +- drivers/media/dvb-frontends/cxd2820r_priv.h | 2 +- drivers/media/dvb-frontends/cxd2841er.c | 2 +- .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c | 2 +- .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c | 2 +- drivers/media/dvb-frontends/cxd2880/cxd2880_top.c | 2 +- drivers/media/dvb-frontends/dib7000p.c | 2 +- drivers/media/dvb-frontends/dib8000.c | 2 +- drivers/media/dvb-frontends/dib9000.c | 2 +- drivers/media/dvb-frontends/drxk_hard.c | 2 +- drivers/media/dvb-frontends/lgdt3305.c | 2 +- drivers/media/dvb-frontends/lgdt3306a.c | 2 +- drivers/media/dvb-frontends/lgdt330x.c | 2 +- drivers/media/dvb-frontends/m88ds3103_priv.h | 2 +- drivers/media/dvb-frontends/mn88443x.c | 2 +- drivers/media/dvb-frontends/mn88472_priv.h | 2 +- drivers/media/dvb-frontends/mn88473_priv.h | 2 +- drivers/media/dvb-frontends/or51132.c | 2 +- drivers/media/dvb-frontends/or51211.c | 2 +- drivers/media/dvb-frontends/rtl2830_priv.h | 2 +- drivers/media/dvb-frontends/rtl2832_priv.h | 2 +- drivers/media/dvb-frontends/si2165.c | 2 +- drivers/media/dvb-frontends/stv0367.c | 2 +- drivers/media/dvb-frontends/tc90522.c | 2 +- drivers/media/dvb-frontends/tda10048.c | 2 +- include/{media/dvb_math.h => linux/int_log.h} | 7 +++---- lib/math/Makefile | 2 +- .../media/dvb-core/dvb_math.c => lib/math/int_log.c | 11 ++++++----- 32 files changed, 42 insertions(+), 48 deletions(-) rename include/{media/dvb_math.h => linux/int_log.h} (92%) rename drivers/media/dvb-core/dvb_math.c => lib/math/int_log.c (95%) diff --git a/Documentation/core-api/kernel-api.rst b/Documentation/core-api/kernel-api.rst index f2bcc5a7ea43..a526fbe06f86 100644 --- a/Documentation/core-api/kernel-api.rst +++ b/Documentation/core-api/kernel-api.rst @@ -162,8 +162,11 @@ Base 2 log and power Functions .. kernel-doc:: include/linux/log2.h :internal: -Integer power Functions ------------------------ +Integer log and power Functions +------------------------------- + +.. kernel-doc:: include/linux/int_log.h + :export: .. kernel-doc:: lib/math/int_pow.c :export: diff --git a/Documentation/driver-api/media/dtv-common.rst b/Documentation/driver-api/media/dtv-common.rst index f8b2c4dc8170..207a22bcaf4a 100644 --- a/Documentation/driver-api/media/dtv-common.rst +++ b/Documentation/driver-api/media/dtv-common.rst @@ -3,15 +3,6 @@ Digital TV Common functions --------------------------- -Math functions -~~~~~~~~~~~~~~ - -Provide some commonly-used math functions, usually required in order to -estimate signal strength and signal to noise measurements in dB. - -.. kernel-doc:: include/media/dvb_math.h - - DVB devices ~~~~~~~~~~~ diff --git a/drivers/media/dvb-core/Makefile b/drivers/media/dvb-core/Makefile index 62b028ded9f7..1cb3ca67bed9 100644 --- a/drivers/media/dvb-core/Makefile +++ b/drivers/media/dvb-core/Makefile @@ -8,6 +8,6 @@ dvb-vb2-$(CONFIG_DVB_MMAP) := dvb_vb2.o dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o \ dvb_ca_en50221.o dvb_frontend.o \ - $(dvb-net-y) dvb_ringbuffer.o $(dvb-vb2-y) dvb_math.o + $(dvb-net-y) dvb_ringbuffer.o $(dvb-vb2-y) obj-$(CONFIG_DVB_CORE) += dvb-core.o diff --git a/drivers/media/dvb-frontends/af9013_priv.h b/drivers/media/dvb-frontends/af9013_priv.h index 3b9b9424fe1a..bba7a9693a23 100644 --- a/drivers/media/dvb-frontends/af9013_priv.h +++ b/drivers/media/dvb-frontends/af9013_priv.h @@ -12,7 +12,7 @@ #define AF9013_PRIV_H #include -#include +#include #include "af9013.h" #include #include diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h index 0e64da0cdeab..7560da75ef00 100644 --- a/drivers/media/dvb-frontends/af9033_priv.h +++ b/drivers/media/dvb-frontends/af9033_priv.h @@ -14,7 +14,7 @@ #include #include #include -#include +#include struct reg_val { u32 reg; diff --git a/drivers/media/dvb-frontends/cxd2820r_priv.h b/drivers/media/dvb-frontends/cxd2820r_priv.h index 9b4d9cf8563d..605320bbc12b 100644 --- a/drivers/media/dvb-frontends/cxd2820r_priv.h +++ b/drivers/media/dvb-frontends/cxd2820r_priv.h @@ -11,7 +11,7 @@ #include #include -#include +#include #include "cxd2820r.h" #include /* For gpio_chip */ #include diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c index 5431f922f55e..ef403a9fb753 100644 --- a/drivers/media/dvb-frontends/cxd2841er.c +++ b/drivers/media/dvb-frontends/cxd2841er.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include "cxd2841er.h" #include "cxd2841er_priv.h" diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c index 604580bf7cf7..4e173dd87ecf 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c @@ -11,7 +11,7 @@ #include "cxd2880_tnrdmd_dvbt2.h" #include "cxd2880_tnrdmd_dvbt2_mon.h" -#include +#include static const int ref_dbm_1000[4][8] = { {-96000, -95000, -94000, -93000, -92000, -92000, -98000, -97000}, diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c index fedc3b4a2fa0..86d5a1e4022a 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c @@ -11,7 +11,7 @@ #include "cxd2880_tnrdmd_dvbt.h" #include "cxd2880_tnrdmd_dvbt_mon.h" -#include +#include static const int ref_dbm_1000[3][5] = { {-93000, -91000, -90000, -89000, -88000}, diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c index d5b1b3788e39..f67b6d24b8d4 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c @@ -11,7 +11,7 @@ #include #include -#include +#include #include "cxd2880.h" #include "cxd2880_tnrdmd_mon.h" diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index a90d2f51868f..b791e687d2e2 100644 --- a/drivers/media/dvb-frontends/dib7000p.c +++ b/drivers/media/dvb-frontends/dib7000p.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include "dib7000p.h" diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index fe19d127abb3..2abda7d1cb6e 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include diff --git a/drivers/media/dvb-frontends/dib9000.c b/drivers/media/dvb-frontends/dib9000.c index 914ca820c174..1c57587a917a 100644 --- a/drivers/media/dvb-frontends/dib9000.c +++ b/drivers/media/dvb-frontends/dib9000.c @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include "dib9000.h" diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index 3301ef75d441..6ad4f202f1bf 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -20,7 +20,7 @@ #include #include "drxk.h" #include "drxk_hard.h" -#include +#include static int power_down_dvbt(struct drxk_state *state, bool set_power_mode); static int power_down_qam(struct drxk_state *state); diff --git a/drivers/media/dvb-frontends/lgdt3305.c b/drivers/media/dvb-frontends/lgdt3305.c index 62d743988919..c15d3735d34c 100644 --- a/drivers/media/dvb-frontends/lgdt3305.c +++ b/drivers/media/dvb-frontends/lgdt3305.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include "lgdt3305.h" static int debug; diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index 70258884126b..3c6650f6e9a3 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include "lgdt3306a.h" #include diff --git a/drivers/media/dvb-frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c index 83565209c3b1..97a10996c7fa 100644 --- a/drivers/media/dvb-frontends/lgdt330x.c +++ b/drivers/media/dvb-frontends/lgdt330x.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include "lgdt330x_priv.h" #include "lgdt330x.h" diff --git a/drivers/media/dvb-frontends/m88ds3103_priv.h b/drivers/media/dvb-frontends/m88ds3103_priv.h index aa5306f40201..594ad9cbc2cc 100644 --- a/drivers/media/dvb-frontends/m88ds3103_priv.h +++ b/drivers/media/dvb-frontends/m88ds3103_priv.h @@ -10,7 +10,7 @@ #include #include "m88ds3103.h" -#include +#include #include #include #include diff --git a/drivers/media/dvb-frontends/mn88443x.c b/drivers/media/dvb-frontends/mn88443x.c index 2ce5692bc22c..db2921c736af 100644 --- a/drivers/media/dvb-frontends/mn88443x.c +++ b/drivers/media/dvb-frontends/mn88443x.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include "mn88443x.h" diff --git a/drivers/media/dvb-frontends/mn88472_priv.h b/drivers/media/dvb-frontends/mn88472_priv.h index 337562723f88..41f14bd67bfd 100644 --- a/drivers/media/dvb-frontends/mn88472_priv.h +++ b/drivers/media/dvb-frontends/mn88472_priv.h @@ -9,7 +9,7 @@ #define MN88472_PRIV_H #include -#include +#include #include "mn88472.h" #include #include diff --git a/drivers/media/dvb-frontends/mn88473_priv.h b/drivers/media/dvb-frontends/mn88473_priv.h index eca7f4e2b769..e9daaacfa22f 100644 --- a/drivers/media/dvb-frontends/mn88473_priv.h +++ b/drivers/media/dvb-frontends/mn88473_priv.h @@ -9,7 +9,7 @@ #define MN88473_PRIV_H #include -#include +#include #include "mn88473.h" #include #include diff --git a/drivers/media/dvb-frontends/or51132.c b/drivers/media/dvb-frontends/or51132.c index 24de1b115158..355f3598627b 100644 --- a/drivers/media/dvb-frontends/or51132.c +++ b/drivers/media/dvb-frontends/or51132.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include "or51132.h" diff --git a/drivers/media/dvb-frontends/or51211.c b/drivers/media/dvb-frontends/or51211.c index ddcaea5c9941..ae732dc5116e 100644 --- a/drivers/media/dvb-frontends/or51211.c +++ b/drivers/media/dvb-frontends/or51211.c @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include "or51211.h" diff --git a/drivers/media/dvb-frontends/rtl2830_priv.h b/drivers/media/dvb-frontends/rtl2830_priv.h index fae78ed78522..ae1fc24a4d84 100644 --- a/drivers/media/dvb-frontends/rtl2830_priv.h +++ b/drivers/media/dvb-frontends/rtl2830_priv.h @@ -9,7 +9,7 @@ #define RTL2830_PRIV_H #include -#include +#include #include "rtl2830.h" #include #include diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h index 5f79f95b9475..f11ba038d5f0 100644 --- a/drivers/media/dvb-frontends/rtl2832_priv.h +++ b/drivers/media/dvb-frontends/rtl2832_priv.h @@ -14,7 +14,7 @@ #include #include -#include +#include #include "rtl2832.h" struct rtl2832_dev { diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c index 72810efd1a96..434d003bf397 100644 --- a/drivers/media/dvb-frontends/si2165.c +++ b/drivers/media/dvb-frontends/si2165.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include "si2165_priv.h" #include "si2165.h" diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index 95e376f23506..a93f40617469 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include "stv0367.h" #include "stv0367_defs.h" diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c index 879f028f9682..1f8cbf45554a 100644 --- a/drivers/media/dvb-frontends/tc90522.c +++ b/drivers/media/dvb-frontends/tc90522.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include "tc90522.h" #define TC90522_I2C_THRU_REG 0xfe diff --git a/drivers/media/dvb-frontends/tda10048.c b/drivers/media/dvb-frontends/tda10048.c index 0b3f6999515e..3cb4e5270e4f 100644 --- a/drivers/media/dvb-frontends/tda10048.c +++ b/drivers/media/dvb-frontends/tda10048.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include "tda10048.h" #define TDA10048_DEFAULT_FIRMWARE "dvb-fe-tda10048-1.0.fw" diff --git a/include/media/dvb_math.h b/include/linux/int_log.h similarity index 92% rename from include/media/dvb_math.h rename to include/linux/int_log.h index 8690ec42954d..332306202464 100644 --- a/include/media/dvb_math.h +++ b/include/linux/int_log.h @@ -1,6 +1,5 @@ /* - * dvb-math provides some complex fixed-point math - * operations shared between the dvb related stuff + * Provides fixed-point logarithm operations. * * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com) * @@ -15,8 +14,8 @@ * GNU Lesser General Public License for more details. */ -#ifndef __DVB_MATH_H -#define __DVB_MATH_H +#ifndef __LINUX_INT_LOG_H +#define __LINUX_INT_LOG_H #include diff --git a/lib/math/Makefile b/lib/math/Makefile index bfac26ddfc22..91fcdb0c9efe 100644 --- a/lib/math/Makefile +++ b/lib/math/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-y += div64.o gcd.o lcm.o int_pow.o int_sqrt.o reciprocal_div.o +obj-y += div64.o gcd.o lcm.o int_log.o int_pow.o int_sqrt.o reciprocal_div.o obj-$(CONFIG_CORDIC) += cordic.o obj-$(CONFIG_PRIME_NUMBERS) += prime_numbers.o diff --git a/drivers/media/dvb-core/dvb_math.c b/lib/math/int_log.c similarity index 95% rename from drivers/media/dvb-core/dvb_math.c rename to lib/math/int_log.c index dc90564d7f34..322df25a22d6 100644 --- a/drivers/media/dvb-core/dvb_math.c +++ b/lib/math/int_log.c @@ -1,6 +1,5 @@ /* - * dvb-math provides some complex fixed-point math - * operations shared between the dvb related stuff + * Provides fixed-point logarithm operations. * * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com) * @@ -16,10 +15,12 @@ */ #include +#include +#include #include -#include +#include + #include -#include static const unsigned short logtable[256] = { 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7, @@ -53,7 +54,7 @@ static const unsigned short logtable[256] = { 0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83, 0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387, 0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973, - 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47 + 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47, }; unsigned int intlog2(u32 value) From 08f6a14b2d376e96cb7166694193ec3c3a496d25 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 3 Jul 2023 16:52:09 +0300 Subject: [PATCH 028/334] lib/math/int_log: Use ARRAY_SIZE(logtable) where makes sense Use ARRAY_SIZE(logtable) where makes sense. Reviewed-by: Mauro Carvalho Chehab Acked-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20230619172019.21457-3-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230703135211.87416-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- lib/math/int_log.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/math/int_log.c b/lib/math/int_log.c index 322df25a22d6..ea98fc0b3fe2 100644 --- a/lib/math/int_log.c +++ b/lib/math/int_log.c @@ -91,7 +91,7 @@ unsigned int intlog2(u32 value) * so we would use the entry 0x18 */ significand = value << (31 - msb); - logentry = (significand >> 23) & 0xff; + logentry = (significand >> 23) % ARRAY_SIZE(logtable); /** * last step we do is interpolation because of the @@ -109,7 +109,7 @@ unsigned int intlog2(u32 value) * logtable_next is 256 */ interpolation = ((significand & 0x7fffff) * - ((logtable[(logentry + 1) & 0xff] - + ((logtable[(logentry + 1) % ARRAY_SIZE(logtable)] - logtable[logentry]) & 0xffff)) >> 15; /* now we return the result */ From 9ab04d7ed8bdd395b0617a1647dd475681f99151 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 3 Jul 2023 16:52:10 +0300 Subject: [PATCH 029/334] lib/math/int_log: Replace LGPL-2.1-or-later boilerplate with SPDX identifier Replace license boilerplate in udftime.c with SPDX identifier for LGPL-2.1-or-later. Acked-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20230619172019.21457-4-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230703135211.87416-4-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- include/linux/int_log.h | 11 +---------- lib/math/int_log.c | 11 +---------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/include/linux/int_log.h b/include/linux/int_log.h index 332306202464..0a6f58c38b61 100644 --- a/include/linux/int_log.h +++ b/include/linux/int_log.h @@ -1,17 +1,8 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Provides fixed-point logarithm operations. * * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com) - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. */ #ifndef __LINUX_INT_LOG_H diff --git a/lib/math/int_log.c b/lib/math/int_log.c index ea98fc0b3fe2..8f9da3a2ad39 100644 --- a/lib/math/int_log.c +++ b/lib/math/int_log.c @@ -1,17 +1,8 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later /* * Provides fixed-point logarithm operations. * * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com) - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. */ #include From a04616321f50bc389cd8d19a6d300d3c3f1be77b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 3 Jul 2023 16:52:11 +0300 Subject: [PATCH 030/334] ASoC: nau8825: Replace copied'n'pasted intlog10() As the code even references to dvb_math.c, which is now available as int_log.c, replace its content by the calling respective API. Acked-by: Mark Brown Acked-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20230619172019.21457-5-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230703135211.87416-5-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 93 ++------------------------------------ 1 file changed, 3 insertions(+), 90 deletions(-) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 9e0e4ddf128e..5cb0de648bd3 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -38,7 +39,6 @@ #define NAU_FVCO_MIN 90000000 /* cross talk suppression detection */ -#define LOG10_MAGIC 646456993 #define GAIN_AUGMENT 22500 #define SIDETONE_BASE 207000 @@ -219,42 +219,6 @@ static const struct reg_sequence nau8825_regmap_patch[] = { { NAU8825_REG_MIC_BIAS, 0x0046 }, }; - -static const unsigned short logtable[256] = { - 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7, - 0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508, - 0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6, - 0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37, - 0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f, - 0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41, - 0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1, - 0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142, - 0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68, - 0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355, - 0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c, - 0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490, - 0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3, - 0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507, - 0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe, - 0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca, - 0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c, - 0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7, - 0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c, - 0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c, - 0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a, - 0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065, - 0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730, - 0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc, - 0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469, - 0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9, - 0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c, - 0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765, - 0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83, - 0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387, - 0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973, - 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47 -}; - /** * nau8825_sema_acquire - acquire the semaphore of nau88l25 * @nau8825: component to register the codec private data with @@ -368,65 +332,14 @@ static void nau8825_hpvol_ramp(struct nau8825 *nau8825, } /** - * nau8825_intlog10_dec3 - Computes log10 of a value - * the result is round off to 3 decimal. This function takes reference to - * dvb-math. The source code locates as the following. - * Linux/drivers/media/dvb-core/dvb_math.c + * nau8825_intlog10_dec3 - Computes log10 of a value, rounding the result to 3 decimal places. * @value: input for log10 * * return log10(value) * 1000 */ static u32 nau8825_intlog10_dec3(u32 value) { - u32 msb, logentry, significand, interpolation, log10val; - u64 log2val; - - /* first detect the msb (count begins at 0) */ - msb = fls(value) - 1; - /** - * now we use a logtable after the following method: - * - * log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24 - * where x = msb and therefore 1 <= y < 2 - * first y is determined by shifting the value left - * so that msb is bit 31 - * 0x00231f56 -> 0x8C7D5800 - * the result is y * 2^31 -> "significand" - * then the highest 9 bits are used for a table lookup - * the highest bit is discarded because it's always set - * the highest nine bits in our example are 100011000 - * so we would use the entry 0x18 - */ - significand = value << (31 - msb); - logentry = (significand >> 23) & 0xff; - /** - * last step we do is interpolation because of the - * limitations of the log table the error is that part of - * the significand which isn't used for lookup then we - * compute the ratio between the error and the next table entry - * and interpolate it between the log table entry used and the - * next one the biggest error possible is 0x7fffff - * (in our example it's 0x7D5800) - * needed value for next table entry is 0x800000 - * so the interpolation is - * (error / 0x800000) * (logtable_next - logtable_current) - * in the implementation the division is moved to the end for - * better accuracy there is also an overflow correction if - * logtable_next is 256 - */ - interpolation = ((significand & 0x7fffff) * - ((logtable[(logentry + 1) & 0xff] - - logtable[logentry]) & 0xffff)) >> 15; - - log2val = ((msb << 24) + (logtable[logentry] << 8) + interpolation); - /** - * log10(x) = log2(x) * log10(2) - */ - log10val = (log2val * LOG10_MAGIC) >> 31; - /** - * the result is round off to 3 decimal - */ - return log10val / ((1 << 24) / 1000); + return intlog10(value) / ((1 << 24) / 1000); } /** From a0cb05cb70b469198ad86c0b13b02cbba3ecd8fd Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Thu, 6 Jul 2023 00:47:58 +0300 Subject: [PATCH 031/334] ASoC: amd: vangogh: Make use of DRV_NAME The "acp5x_mach" string is provided for both driver name and MODULE_ALIAS. Since they need to match, ensure DRV_NAME macro is used in both locations. Signed-off-by: Cristian Ciocaltea Link: https://lore.kernel.org/r/20230705214800.193244-2-cristian.ciocaltea@collabora.com Signed-off-by: Mark Brown --- sound/soc/amd/vangogh/acp5x-mach.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/amd/vangogh/acp5x-mach.c b/sound/soc/amd/vangogh/acp5x-mach.c index e5bcd1e6eb73..5e36179cf611 100644 --- a/sound/soc/amd/vangogh/acp5x-mach.c +++ b/sound/soc/amd/vangogh/acp5x-mach.c @@ -381,7 +381,7 @@ static int acp5x_probe(struct platform_device *pdev) static struct platform_driver acp5x_mach_driver = { .driver = { - .name = "acp5x_mach", + .name = DRV_NAME, .pm = &snd_soc_pm_ops, }, .probe = acp5x_probe, From 3dd26e27ccb4f18b4d25c0a49e1888eca9c6a724 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Thu, 6 Jul 2023 00:47:59 +0300 Subject: [PATCH 032/334] ASoC: amd: vangogh: Use dmi_first_match() for DMI quirk handling In preparation for supporting ACPI probing, move DMI quirk handling logic at the probe's top, to be able to return as quickly as possible in case there is no DMI matching. Additionally, simplify the code by replacing dmi_check_system() and related callback with dmi_first_match(). While at it, also drop a few unnecessary empty lines. Signed-off-by: Cristian Ciocaltea Link: https://lore.kernel.org/r/20230705214800.193244-3-cristian.ciocaltea@collabora.com Signed-off-by: Mark Brown --- sound/soc/amd/vangogh/acp5x-mach.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/sound/soc/amd/vangogh/acp5x-mach.c b/sound/soc/amd/vangogh/acp5x-mach.c index 5e36179cf611..1efa8f8b77ab 100644 --- a/sound/soc/amd/vangogh/acp5x-mach.c +++ b/sound/soc/amd/vangogh/acp5x-mach.c @@ -22,7 +22,6 @@ #define DRV_NAME "acp5x_mach" #define DUAL_CHANNEL 2 -#define VG_JUPITER 1 #define ACP5X_NAU8821_BCLK 3072000 #define ACP5X_NAU8821_FREQ_OUT 12288000 #define ACP5X_NAU8821_COMP_NAME "i2c-NVTN2020:00" @@ -31,7 +30,6 @@ #define ACP5X_CS35L41_COMP_RNAME "spi-VLV1776:01" #define ACP5X_CS35L41_DAI_NAME "cs35l41-pcm" -static unsigned long acp5x_machine_id; static struct snd_soc_jack vg_headset; SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("acp5x_i2s_dma.0"))); @@ -242,7 +240,6 @@ static int acp5x_cs35l41_hw_params(struct snd_pcm_substream *substream, } return 0; - } static const struct snd_soc_ops acp5x_cs35l41_play_ops = { @@ -292,8 +289,6 @@ static struct snd_soc_dai_link acp5x_8821_35l41_dai[] = { }, }; - - static const struct snd_soc_dapm_widget acp5x_8821_35l41_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), @@ -331,16 +326,8 @@ static struct snd_soc_card acp5x_8821_35l41_card = { .num_controls = ARRAY_SIZE(acp5x_8821_controls), }; -static int acp5x_vg_quirk_cb(const struct dmi_system_id *id) -{ - acp5x_machine_id = VG_JUPITER; - - return 1; -} - static const struct dmi_system_id acp5x_vg_quirk_table[] = { { - .callback = acp5x_vg_quirk_cb, .matches = { DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Valve"), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jupiter"), @@ -351,23 +338,22 @@ static const struct dmi_system_id acp5x_vg_quirk_table[] = { static int acp5x_probe(struct platform_device *pdev) { + const struct dmi_system_id *dmi_id; struct acp5x_platform_info *machine; struct device *dev = &pdev->dev; struct snd_soc_card *card; int ret; + dmi_id = dmi_first_match(acp5x_vg_quirk_table); + if (!dmi_id) + return -ENODEV; + + card = &acp5x_8821_35l41_card; + machine = devm_kzalloc(dev, sizeof(*machine), GFP_KERNEL); if (!machine) return -ENOMEM; - dmi_check_system(acp5x_vg_quirk_table); - switch (acp5x_machine_id) { - case VG_JUPITER: - card = &acp5x_8821_35l41_card; - break; - default: - return -ENODEV; - } card->dev = dev; platform_set_drvdata(pdev, card); snd_soc_card_set_drvdata(card, machine); From dba22efd0d177a23c6da2a161e9a1ad29718924c Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Thu, 6 Jul 2023 00:48:00 +0300 Subject: [PATCH 033/334] ASoC: amd: vangogh: Add support for NAU8821/MAX98388 variant Extend the Vangogh machine driver to support a variant based on the Nuvoton NAU88L21 Codec and the Analog Devices MAX98388 Speaker Amplifier. Additionally, enable probing via ACPI match table for this and future hardware revisions. Co-developed-by: Lucas Tanure Signed-off-by: Lucas Tanure Signed-off-by: Cristian Ciocaltea Link: https://lore.kernel.org/r/20230705214800.193244-4-cristian.ciocaltea@collabora.com Signed-off-by: Mark Brown --- sound/soc/amd/Kconfig | 5 +- sound/soc/amd/vangogh/acp5x-mach.c | 135 +++++++++++++++++++++++++++-- 2 files changed, 131 insertions(+), 9 deletions(-) diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 1dd8579e8034..273688c05317 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -79,14 +79,15 @@ config SND_SOC_AMD_ACP5x ACP DMA driver, CPU DAI driver. config SND_SOC_AMD_VANGOGH_MACH - tristate "AMD Vangogh support for NAU8821 CS35L41" + tristate "AMD Vangogh support for NAU8821/CS35L41/MAX98388" select SND_SOC_NAU8821 select SND_SOC_CS35L41_SPI + select SND_SOC_MAX98388 select SND_AMD_ACP_CONFIG depends on SND_SOC_AMD_ACP5x && I2C && SPI_MASTER help This option enables machine driver for Vangogh platform - using NAU8821 and CS35L41 codecs. + using NAU8821 and either CS35L41 or MAX98388 codecs. Say m if you have such a device. If unsure select "N". diff --git a/sound/soc/amd/vangogh/acp5x-mach.c b/sound/soc/amd/vangogh/acp5x-mach.c index 1efa8f8b77ab..125a8e93478d 100644 --- a/sound/soc/amd/vangogh/acp5x-mach.c +++ b/sound/soc/amd/vangogh/acp5x-mach.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Machine driver for AMD Vangogh platform using NAU8821 & CS35L41 - * codecs. + * Machine driver for AMD Vangogh platform using either + * NAU8821 & CS35L41 or NAU8821 & MAX98388 codecs. * * Copyright 2021 Advanced Micro Devices, Inc. */ @@ -29,6 +29,9 @@ #define ACP5X_CS35L41_COMP_LNAME "spi-VLV1776:00" #define ACP5X_CS35L41_COMP_RNAME "spi-VLV1776:01" #define ACP5X_CS35L41_DAI_NAME "cs35l41-pcm" +#define ACP5X_MAX98388_COMP_LNAME "i2c-ADS8388:00" +#define ACP5X_MAX98388_COMP_RNAME "i2c-ADS8388:01" +#define ACP5X_MAX98388_DAI_NAME "max98388-aif1" static struct snd_soc_jack vg_headset; @@ -326,6 +329,108 @@ static struct snd_soc_card acp5x_8821_35l41_card = { .num_controls = ARRAY_SIZE(acp5x_8821_controls), }; +static int acp5x_max98388_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct acp5x_platform_info *machine = snd_soc_card_get_drvdata(rtd->card); + struct snd_pcm_runtime *runtime = substream->runtime; + + machine->play_i2s_instance = I2S_HS_INSTANCE; + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + return 0; +} + +static const struct snd_soc_ops acp5x_max98388_play_ops = { + .startup = acp5x_max98388_startup, +}; + +static struct snd_soc_codec_conf acp5x_max98388_conf[] = { + { + .dlc = COMP_CODEC_CONF(ACP5X_MAX98388_COMP_LNAME), + .name_prefix = "Left", + }, + { + .dlc = COMP_CODEC_CONF(ACP5X_MAX98388_COMP_RNAME), + .name_prefix = "Right", + }, +}; + +SND_SOC_DAILINK_DEF(max98388, DAILINK_COMP_ARRAY(COMP_CODEC(ACP5X_MAX98388_COMP_LNAME, + ACP5X_MAX98388_DAI_NAME), + COMP_CODEC(ACP5X_MAX98388_COMP_RNAME, + ACP5X_MAX98388_DAI_NAME))); + +static struct snd_soc_dai_link acp5x_8821_98388_dai[] = { + { + .name = "acp5x-8821-play", + .stream_name = "Playback/Capture", + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBC_CFC, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ops = &acp5x_8821_ops, + .init = acp5x_8821_init, + SND_SOC_DAILINK_REG(acp5x_i2s, nau8821, platform), + }, + { + .name = "acp5x-max98388-play", + .stream_name = "MAX98388 Playback", + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBC_CFC, + .dpcm_playback = 1, + .playback_only = 1, + .ops = &acp5x_max98388_play_ops, + SND_SOC_DAILINK_REG(acp5x_bt, max98388, platform), + }, +}; + +static const struct snd_soc_dapm_widget acp5x_8821_98388_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SPK("SPK", NULL), +}; + +static const struct snd_soc_dapm_route acp5x_8821_98388_route[] = { + { "Headphone", NULL, "HPOL" }, + { "Headphone", NULL, "HPOR" }, + { "MICL", NULL, "Headset Mic" }, + { "MICR", NULL, "Headset Mic" }, + { "DMIC", NULL, "Int Mic" }, + + { "Headphone", NULL, "Platform Clock" }, + { "Headset Mic", NULL, "Platform Clock" }, + { "Int Mic", NULL, "Platform Clock" }, + + { "SPK", NULL, "Left BE_OUT" }, + { "SPK", NULL, "Right BE_OUT" }, +}; + +static struct snd_soc_card acp5x_8821_98388_card = { + .name = "acp5x-max98388", + .owner = THIS_MODULE, + .dai_link = acp5x_8821_98388_dai, + .num_links = ARRAY_SIZE(acp5x_8821_98388_dai), + .dapm_widgets = acp5x_8821_98388_widgets, + .num_dapm_widgets = ARRAY_SIZE(acp5x_8821_98388_widgets), + .dapm_routes = acp5x_8821_98388_route, + .num_dapm_routes = ARRAY_SIZE(acp5x_8821_98388_route), + .codec_conf = acp5x_max98388_conf, + .num_configs = ARRAY_SIZE(acp5x_max98388_conf), + .controls = acp5x_8821_controls, + .num_controls = ARRAY_SIZE(acp5x_8821_controls), +}; + static const struct dmi_system_id acp5x_vg_quirk_table[] = { { .matches = { @@ -344,11 +449,20 @@ static int acp5x_probe(struct platform_device *pdev) struct snd_soc_card *card; int ret; - dmi_id = dmi_first_match(acp5x_vg_quirk_table); - if (!dmi_id) - return -ENODEV; + card = (struct snd_soc_card *)device_get_match_data(dev); + if (!card) { + /* + * This is normally the result of directly probing the driver + * in pci-acp5x through platform_device_register_full(), which + * is necessary for the CS35L41 variant, as it doesn't support + * ACPI probing and relies on DMI quirks. + */ + dmi_id = dmi_first_match(acp5x_vg_quirk_table); + if (!dmi_id) + return -ENODEV; - card = &acp5x_8821_35l41_card; + card = &acp5x_8821_35l41_card; + } machine = devm_kzalloc(dev, sizeof(*machine), GFP_KERNEL); if (!machine) @@ -365,10 +479,17 @@ static int acp5x_probe(struct platform_device *pdev) return 0; } +static const struct acpi_device_id acp5x_acpi_match[] = { + { "AMDI8821", (kernel_ulong_t)&acp5x_8821_98388_card }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, acp5x_acpi_match); + static struct platform_driver acp5x_mach_driver = { .driver = { .name = DRV_NAME, .pm = &snd_soc_pm_ops, + .acpi_match_table = acp5x_acpi_match, }, .probe = acp5x_probe, }; @@ -376,6 +497,6 @@ static struct platform_driver acp5x_mach_driver = { module_platform_driver(acp5x_mach_driver); MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); -MODULE_DESCRIPTION("NAU8821 & CS35L41 audio support"); +MODULE_DESCRIPTION("NAU8821/CS35L41 & NAU8821/MAX98388 audio support"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRV_NAME); From 4b526b3278becdf1f2bfd375078f5db469f8a6bb Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Fri, 7 Jul 2023 17:37:27 +0530 Subject: [PATCH 034/334] ASoC: amd: acp: Add machine driver support for nau8821 codec In newer variants nau8821 as primary codec. Add support for nau8821 codec in generic machine driver. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20230707120730.1948445-2-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/Kconfig | 1 + sound/soc/amd/acp/acp-mach-common.c | 167 ++++++++++++++++++++++++++++ sound/soc/amd/acp/acp-mach.h | 1 + 3 files changed, 169 insertions(+) diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index ce0037810743..a68bbe106b73 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -61,6 +61,7 @@ config SND_SOC_AMD_MACH_COMMON select SND_SOC_MAX98357A select SND_SOC_RT5682S select SND_SOC_NAU8825 + select SND_SOC_NAU8821 help This option enables common Machine driver module for ACP. diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index 6da17140beea..48abb8e9665d 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -25,12 +25,17 @@ #include "../../codecs/rt1019.h" #include "../../codecs/rt5682s.h" #include "../../codecs/nau8825.h" +#include "../../codecs/nau8821.h" #include "acp-mach.h" +static struct snd_soc_jack vg_headset; #define PCO_PLAT_CLK 48000000 #define RT5682_PLL_FREQ (48000 * 512) #define DUAL_CHANNEL 2 #define FOUR_CHANNEL 4 +#define NAU8821_CODEC_DAI "nau8821-hifi" +#define NAU8821_BCLK 1536000 +#define NAU8821_FREQ_OUT 12288000 #define TDM_MODE_ENABLE 1 @@ -790,6 +795,162 @@ static const struct snd_soc_ops acp_card_nau8825_ops = { .hw_params = acp_nau8825_hw_params, }; +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + int ret = 0; + + codec_dai = snd_soc_card_get_codec_dai(card, NAU8821_CODEC_DAI); + if (!codec_dai) { + dev_err(card->dev, "Codec dai not found\n"); + return -EIO; + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + ret = snd_soc_dai_set_sysclk(codec_dai, NAU8821_CLK_INTERNAL, + 0, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "set sysclk err = %d\n", ret); + return -EIO; + } + } else { + ret = snd_soc_dai_set_sysclk(codec_dai, NAU8821_CLK_FLL_BLK, 0, + SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(codec_dai->dev, "can't set FS clock %d\n", ret); + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, NAU8821_BCLK, + NAU8821_FREQ_OUT); + if (ret < 0) + dev_err(codec_dai->dev, "can't set FLL: %d\n", ret); + } + return ret; +} + +static const struct snd_soc_dapm_widget nau8821_widgets[] = { + SND_SOC_DAPM_HP("Headphone jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route nau8821_audio_route[] = { + /* HP jack connectors - unknown if we have jack detection */ + { "Headphone jack", NULL, "HPOL" }, + { "Headphone jack", NULL, "HPOR" }, + { "MICL", NULL, "Headset Mic" }, + { "MICR", NULL, "Headset Mic" }, + { "DMIC", NULL, "Int Mic" }, + { "Headphone jack", NULL, "Platform Clock" }, + { "Headset Mic", NULL, "Platform Clock" }, + { "Int Mic", NULL, "Platform Clock" }, +}; + +static const unsigned int nau8821_format[] = {16}; + +static struct snd_pcm_hw_constraint_list constraints_sample_bits = { + .list = nau8821_format, + .count = ARRAY_SIZE(nau8821_format), +}; + +static int acp_8821_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_component *component = codec_dai->component; + int ret; + + dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name); + + ret = snd_soc_dapm_new_controls(&card->dapm, nau8821_widgets, + ARRAY_SIZE(nau8821_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + // Don't need to add routes if widget addition failed + return ret; + } + + ret = snd_soc_card_jack_new(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &vg_headset); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); + return ret; + } + snd_jack_set_key(vg_headset.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(vg_headset.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(vg_headset.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(vg_headset.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + nau8821_enable_jack_detect(component, &vg_headset); + + return snd_soc_dapm_add_routes(&rtd->card->dapm, nau8821_audio_route, + ARRAY_SIZE(nau8821_audio_route)); +} + +static int acp_8821_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + &constraints_sample_bits); + return 0; +} + +static int acp_nau8821_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_card *card = rtd->card; + struct acp_card_drvdata *drvdata = card->drvdata; + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + int ret; + unsigned int fmt; + + if (drvdata->soc_mclk) + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; + else + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP; + + ret = snd_soc_dai_set_fmt(codec_dai, fmt); + if (ret < 0) { + dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, NAU8821_CLK_FLL_BLK, 0, + SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(card->dev, "can't set FS clock %d\n", ret); + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, snd_soc_params_to_bclk(params), + params_rate(params) * 256); + if (ret < 0) + dev_err(card->dev, "can't set FLL: %d\n", ret); + + return ret; +} + +static const struct snd_soc_ops acp_8821_ops = { + .startup = acp_8821_startup, + .hw_params = acp_nau8821_hw_params, +}; + +SND_SOC_DAILINK_DEF(nau8821, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-NVTN2020:00", + "nau8821-hifi"))); + /* Declare DMIC codec components */ SND_SOC_DAILINK_DEF(dmic_codec, DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); @@ -920,6 +1081,12 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].init = acp_card_rt5682s_init; links[i].ops = &acp_card_rt5682s_ops; } + if (drv_data->hs_codec_id == NAU8821) { + links[i].codecs = nau8821; + links[i].num_codecs = ARRAY_SIZE(nau8821); + links[i].init = acp_8821_init; + links[i].ops = &acp_8821_ops; + } i++; } diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h index 165f407697c0..f2b44a6189a6 100644 --- a/sound/soc/amd/acp/acp-mach.h +++ b/sound/soc/amd/acp/acp-mach.h @@ -41,6 +41,7 @@ enum codec_endpoints { MAX98360A, RT5682S, NAU8825, + NAU8821, }; enum platform_end_point { From ac91c8c89782d7d0781120a74c9bd939e3ce2831 Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Fri, 7 Jul 2023 17:37:28 +0530 Subject: [PATCH 035/334] ASoC: amd: acp: Add machine driver support for max98388 codec In newer platforms max98388 codec as amplifier codec. Add support for maxim codec in generic machine driver. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20230707120730.1948445-3-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/Kconfig | 1 + sound/soc/amd/acp/acp-mach-common.c | 100 ++++++++++++++++++++++++++++ sound/soc/amd/acp/acp-mach.h | 1 + 3 files changed, 102 insertions(+) diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index a68bbe106b73..d7f1c3c90484 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -62,6 +62,7 @@ config SND_SOC_AMD_MACH_COMMON select SND_SOC_RT5682S select SND_SOC_NAU8825 select SND_SOC_NAU8821 + select SND_SOC_MAX98388 help This option enables common Machine driver module for ACP. diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index 48abb8e9665d..ff5cbc4a6427 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -36,6 +36,7 @@ static struct snd_soc_jack vg_headset; #define NAU8821_CODEC_DAI "nau8821-hifi" #define NAU8821_BCLK 1536000 #define NAU8821_FREQ_OUT 12288000 +#define MAX98388_CODEC_DAI "max98388-aif1" #define TDM_MODE_ENABLE 1 @@ -666,6 +667,97 @@ static const struct snd_soc_ops acp_card_maxim_ops = { .hw_params = acp_card_maxim_hw_params, }; +SND_SOC_DAILINK_DEF(max98388, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ADS8388:00", "max98388-aif1"), + COMP_CODEC("i2c-ADS8388:01", "max98388-aif1"))); + +static const struct snd_soc_dapm_widget max98388_widgets[] = { + SND_SOC_DAPM_SPK("SPK", NULL), +}; + +static const struct snd_soc_dapm_route max98388_map[] = { + { "SPK", NULL, "Left BE_OUT" }, + { "SPK", NULL, "Right BE_OUT" }, +}; + +static struct snd_soc_codec_conf max98388_conf[] = { + { + .dlc = COMP_CODEC_CONF("i2c-ADS8388:00"), + .name_prefix = "Left", + }, + { + .dlc = COMP_CODEC_CONF("i2c-ADS8388:01"), + .name_prefix = "Right", + }, +}; + +static const unsigned int max98388_format[] = {16}; + +static struct snd_pcm_hw_constraint_list constraints_sample_bits_max = { + .list = max98388_format, + .count = ARRAY_SIZE(max98388_format), +}; + +static int acp_card_max98388_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + &constraints_sample_bits_max); + + return 0; +} + +static int acp_card_max98388_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct acp_card_drvdata *drvdata = card->drvdata; + int ret; + + if (drvdata->amp_codec_id != MAX98388) + return -EINVAL; + + ret = snd_soc_dapm_new_controls(&card->dapm, max98388_widgets, + ARRAY_SIZE(max98388_widgets)); + + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + /* Don't need to add routes if widget addition failed */ + return ret; + } + return snd_soc_dapm_add_routes(&rtd->card->dapm, max98388_map, + ARRAY_SIZE(max98388_map)); +} + +static int acp_max98388_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct snd_soc_dai *codec_dai = + snd_soc_card_get_codec_dai(card, + MAX98388_CODEC_DAI); + int ret; + + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF); + if (ret < 0) + return ret; + + return ret; +} + +static const struct snd_soc_ops acp_max98388_ops = { + .startup = acp_card_max98388_startup, + .hw_params = acp_max98388_hw_params, +}; + /* Declare nau8825 codec components */ SND_SOC_DAILINK_DEF(nau8825, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00", "nau8825-hifi"))); @@ -1174,6 +1266,14 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].ops = &acp_card_maxim_ops; links[i].init = acp_card_maxim_init; } + if (drv_data->amp_codec_id == MAX98388) { + links[i].codecs = max98388; + links[i].num_codecs = ARRAY_SIZE(max98388); + links[i].ops = &acp_max98388_ops; + links[i].init = acp_card_max98388_init; + card->codec_conf = max98388_conf; + card->num_configs = ARRAY_SIZE(max98388_conf); + } if (drv_data->amp_codec_id == RT1019) { links[i].codecs = rt1019; links[i].num_codecs = ARRAY_SIZE(rt1019); diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h index f2b44a6189a6..2b3ec6594023 100644 --- a/sound/soc/amd/acp/acp-mach.h +++ b/sound/soc/amd/acp/acp-mach.h @@ -42,6 +42,7 @@ enum codec_endpoints { RT5682S, NAU8825, NAU8821, + MAX98388, }; enum platform_end_point { From ef51cddf014b3e4909e9656025d1f7c2b4cc4117 Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Fri, 7 Jul 2023 17:37:29 +0530 Subject: [PATCH 036/334] ASoC: amd: Add acpi machine id's for vangogh platform Add acpi machine id's for vangogh platform and configure driver data to enable SOF sound card support on newer boards. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20230707120730.1948445-4-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp-config.c | 19 +++++++++++++++++++ sound/soc/amd/acp/acp-sof-mach.c | 16 ++++++++++++++++ sound/soc/amd/mach-config.h | 1 + 3 files changed, 36 insertions(+) diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c index 0932473b6394..f002397caeef 100644 --- a/sound/soc/amd/acp-config.c +++ b/sound/soc/amd/acp-config.c @@ -82,6 +82,11 @@ static struct snd_soc_acpi_codecs amp_max = { .codecs = {"MX98360A"} }; +static struct snd_soc_acpi_codecs amp_max98388 = { + .num_codecs = 1, + .codecs = {"ADS8388"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = { { .id = "10EC5682", @@ -130,6 +135,20 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = { }; EXPORT_SYMBOL(snd_soc_acpi_amd_sof_machines); +struct snd_soc_acpi_mach snd_soc_acpi_amd_vangogh_sof_machines[] = { + { + .id = "NVTN2020", + .drv_name = "nau8821-max", + .pdata = &acp_quirk_data, + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &_max98388, + .fw_filename = "sof-vangogh.ri", + .sof_tplg_filename = "sof-vangogh-nau8821-max.tplg", + }, + {}, +}; +EXPORT_SYMBOL(snd_soc_acpi_amd_vangogh_sof_machines); + struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[] = { { .id = "AMDI1019", diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c index 99a7d3879340..a1c893f33f74 100644 --- a/sound/soc/amd/acp/acp-sof-mach.c +++ b/sound/soc/amd/acp/acp-sof-mach.c @@ -83,6 +83,17 @@ static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = { .tdm_mode = false, }; +static struct acp_card_drvdata sof_nau8821_max98388_data = { + .hs_cpu_id = I2S_SP, + .amp_cpu_id = I2S_HS, + .dmic_cpu_id = NONE, + .hs_codec_id = NAU8821, + .amp_codec_id = MAX98388, + .dmic_codec_id = NONE, + .soc_mclk = true, + .tdm_mode = false, +}; + static const struct snd_kcontrol_new acp_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), @@ -166,6 +177,10 @@ static const struct platform_device_id board_ids[] = { .name = "rt5682s-hs-rt1019", .driver_data = (kernel_ulong_t)&sof_rt5682s_hs_rt1019_data }, + { + .name = "nau8821-max", + .driver_data = (kernel_ulong_t)&sof_nau8821_max98388_data + }, { } }; static struct platform_driver acp_asoc_audio = { @@ -187,4 +202,5 @@ MODULE_ALIAS("platform:rt5682s-max"); MODULE_ALIAS("platform:rt5682s-rt1019"); MODULE_ALIAS("platform:nau8825-max"); MODULE_ALIAS("platform:rt5682s-hs-rt1019"); +MODULE_ALIAS("platform:nau8821-max"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h index 7b4c625da40d..d392e6d6e6e1 100644 --- a/sound/soc/amd/mach-config.h +++ b/sound/soc/amd/mach-config.h @@ -20,6 +20,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_vangogh_sof_machines[]; struct config_entry { u32 flags; From 197b1f7f0df183db332b6b8851a29c8bc901571d Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Fri, 7 Jul 2023 17:37:30 +0530 Subject: [PATCH 037/334] ASoC: amd: Add new dmi entries to config entry Add new dmi sys vendor, product name and product family to config entry table to enable audio for valve boards. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20230707120730.1948445-5-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp-config.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c index f002397caeef..f27c27580009 100644 --- a/sound/soc/amd/acp-config.c +++ b/sound/soc/amd/acp-config.c @@ -47,6 +47,20 @@ static const struct config_entry config_table[] = { {} }, }, + { + .flags = FLAG_AMD_SOF, + .device = ACP_PCI_DEV_ID, + .dmi_table = (const struct dmi_system_id []) { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Valve"), + DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "Sephiroth"), + }, + }, + {} + }, + }, }; int snd_amd_acp_find_config(struct pci_dev *pci) From cacff5e8a305b98595829ac4f5fe669e015ce19c Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 23 Jun 2023 10:58:18 +0200 Subject: [PATCH 038/334] ASoC: dt-bindings: Add audio-iio-aux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Industrial I/O devices can be present in the audio path. These devices needs to be viewed as audio components in order to be fully integrated in the audio path. audio-iio-aux allows to consider these Industrial I/O devices as auxliary audio devices. Signed-off-by: Herve Codina Reviewed-by: Jonathan Cameron Reviewed-by: Rob Herring Reviewed-by: Christophe Leroy Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20230623085830.749991-2-herve.codina@bootlin.com Signed-off-by: Mark Brown --- .../bindings/sound/audio-iio-aux.yaml | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/audio-iio-aux.yaml diff --git a/Documentation/devicetree/bindings/sound/audio-iio-aux.yaml b/Documentation/devicetree/bindings/sound/audio-iio-aux.yaml new file mode 100644 index 000000000000..d3cc1ea4a175 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/audio-iio-aux.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/audio-iio-aux.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Audio IIO auxiliary + +maintainers: + - Herve Codina + +description: + Auxiliary device based on Industrial I/O device channels + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: audio-iio-aux + + io-channels: + description: + Industrial I/O device channels used + + io-channel-names: + description: + Industrial I/O channel names related to io-channels. + These names are used to provides sound controls, widgets and routes names. + + snd-control-invert-range: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: | + A list of 0/1 flags defining whether or not the related channel is + inverted + items: + enum: [0, 1] + default: 0 + description: | + Invert the sound control value compared to the IIO channel raw value. + - 1: The related sound control value is inverted meaning that the + minimum sound control value correspond to the maximum IIO channel + raw value and the maximum sound control value correspond to the + minimum IIO channel raw value. + - 0: The related sound control value is not inverted meaning that the + minimum (resp maximum) sound control value correspond to the + minimum (resp maximum) IIO channel raw value. + +required: + - compatible + - io-channels + - io-channel-names + +unevaluatedProperties: false + +examples: + - | + iio-aux { + compatible = "audio-iio-aux"; + io-channels = <&iio 0>, <&iio 1>, <&iio 2>, <&iio 3>; + io-channel-names = "CH0", "CH1", "CH2", "CH3"; + /* Invert CH1 and CH2 */ + snd-control-invert-range = <0 1 1 0>; + }; From b5f3484117b86cb128f500ff2d730c3cfcb9ddfc Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 23 Jun 2023 10:58:19 +0200 Subject: [PATCH 039/334] ASoC: dt-bindings: simple-card: Add additional-devs subnode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The additional-devs subnode allows to declared some virtual devices as sound card children. These virtual devices can then be used by the sound card and so be present in the audio path. The first virtual device supported is the audio IIO auxiliary device in order to support an IIO device as an audio auxiliary device. Signed-off-by: Herve Codina Reviewed-by: Jonathan Cameron Reviewed-by: Christophe Leroy Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20230623085830.749991-3-herve.codina@bootlin.com Signed-off-by: Mark Brown --- .../bindings/sound/simple-card.yaml | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/simple-card.yaml b/Documentation/devicetree/bindings/sound/simple-card.yaml index b05e05c81cc4..59ac2d1d1ccf 100644 --- a/Documentation/devicetree/bindings/sound/simple-card.yaml +++ b/Documentation/devicetree/bindings/sound/simple-card.yaml @@ -148,6 +148,15 @@ definitions: required: - sound-dai + additional-devs: + type: object + description: + Additional devices used by the simple audio card. + patternProperties: + '^iio-aux(-.+)?$': + type: object + $ref: audio-iio-aux.yaml# + properties: compatible: contains: @@ -187,6 +196,8 @@ properties: $ref: "#/definitions/mclk-fs" simple-audio-card,aux-devs: $ref: "#/definitions/aux-devs" + simple-audio-card,additional-devs: + $ref: "#/definitions/additional-devs" simple-audio-card,convert-rate: $ref: "#/definitions/convert-rate" simple-audio-card,convert-channels: @@ -359,6 +370,48 @@ examples: }; }; +# -------------------- +# route audio to/from a codec through an amplifier +# designed with a potentiometer driven by IIO: +# -------------------- + - | + sound { + compatible = "simple-audio-card"; + + simple-audio-card,aux-devs = <&_in>, <&_out>; + simple-audio-card,routing = + "CODEC LEFTIN", "AMP_IN LEFT OUT", + "CODEC RIGHTIN", "AMP_IN RIGHT OUT", + "AMP_OUT LEFT IN", "CODEC LEFTOUT", + "AMP_OUT RIGHT IN", "CODEC RIGHTOUT"; + + simple-audio-card,additional-devs { + amp_out: iio-aux-out { + compatible = "audio-iio-aux"; + io-channels = <&pot_out 0>, <&pot_out 1>; + io-channel-names = "LEFT", "RIGHT"; + snd-control-invert-range = <1 1>; + sound-name-prefix = "AMP_OUT"; + }; + + amp_in: iio_aux-in { + compatible = "audio-iio-aux"; + io-channels = <&pot_in 0>, <&pot_in 1>; + io-channel-names = "LEFT", "RIGHT"; + sound-name-prefix = "AMP_IN"; + }; + }; + + simple-audio-card,cpu { + sound-dai = <&cpu>; + }; + + simple-audio-card,codec { + sound-dai = <&codec>; + clocks = <&clocks>; + }; + }; + # -------------------- # Sampling Rate Conversion # -------------------- From f75c544d74133278b004195220f540d8ab953e14 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 23 Jun 2023 10:58:20 +0200 Subject: [PATCH 040/334] iio: inkern: Check error explicitly in iio_channel_read_max() The current implementation returns the error code as part of the default switch case. This can lead to returning an incorrect positive value in case of iio_avail_type enum entries evolution. In order to avoid this case, be more strict in error checking. Signed-off-by: Herve Codina Acked-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20230623085830.749991-4-herve.codina@bootlin.com Signed-off-by: Mark Brown --- drivers/iio/inkern.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 872fd5c24147..f738db9a0c04 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -858,6 +858,9 @@ static int iio_channel_read_max(struct iio_channel *chan, val2 = &unused; ret = iio_channel_read_avail(chan, &vals, type, &length, info); + if (ret < 0) + return ret; + switch (ret) { case IIO_AVAIL_RANGE: switch (*type) { @@ -888,7 +891,7 @@ static int iio_channel_read_max(struct iio_channel *chan, return 0; default: - return ret; + return -EINVAL; } } From 1e1b4fbd6d0f8c54af14dcf18bd3136816153b12 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 23 Jun 2023 10:58:21 +0200 Subject: [PATCH 041/334] iio: consumer.h: Fix raw values documentation notes The raw values notes mention 'ADC counts' and are not fully accurate. Reword the notes in order to remove the 'ADC counts' and describe the conversion needed between a raw value and a value in the standard units. Signed-off-by: Herve Codina Acked-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20230623085830.749991-5-herve.codina@bootlin.com Signed-off-by: Mark Brown --- include/linux/iio/consumer.h | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index 6802596b017c..f536820b9cf2 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -201,8 +201,9 @@ struct iio_dev * @chan: The channel being queried. * @val: Value read back. * - * Note raw reads from iio channels are in adc counts and hence - * scale will need to be applied if standard units required. + * Note, if standard units are required, raw reads from iio channels + * need the offset (default 0) and scale (default 1) to be applied + * as (raw + offset) * scale. */ int iio_read_channel_raw(struct iio_channel *chan, int *val); @@ -212,8 +213,9 @@ int iio_read_channel_raw(struct iio_channel *chan, * @chan: The channel being queried. * @val: Value read back. * - * Note raw reads from iio channels are in adc counts and hence - * scale will need to be applied if standard units required. + * Note, if standard units are required, raw reads from iio channels + * need the offset (default 0) and scale (default 1) to be applied + * as (raw + offset) * scale. * * In opposit to the normal iio_read_channel_raw this function * returns the average of multiple reads. @@ -281,8 +283,9 @@ int iio_read_channel_attribute(struct iio_channel *chan, int *val, * @chan: The channel being queried. * @val: Value being written. * - * Note raw writes to iio channels are in dac counts and hence - * scale will need to be applied if standard units required. + * Note that for raw writes to iio channels, if the value provided is + * in standard units, the affect of the scale and offset must be removed + * as (value / scale) - offset. */ int iio_write_channel_raw(struct iio_channel *chan, int val); @@ -292,8 +295,9 @@ int iio_write_channel_raw(struct iio_channel *chan, int val); * @chan: The channel being queried. * @val: Value read back. * - * Note raw reads from iio channels are in adc counts and hence - * scale will need to be applied if standard units are required. + * Note, if standard units are required, raw reads from iio channels + * need the offset (default 0) and scale (default 1) to be applied + * as (raw + offset) * scale. */ int iio_read_max_channel_raw(struct iio_channel *chan, int *val); @@ -308,8 +312,9 @@ int iio_read_max_channel_raw(struct iio_channel *chan, int *val); * For ranges, three vals are always returned; min, step and max. * For lists, all the possible values are enumerated. * - * Note raw available values from iio channels are in adc counts and - * hence scale will need to be applied if standard units are required. + * Note, if standard units are required, raw available values from iio + * channels need the offset (default 0) and scale (default 1) to be applied + * as (raw + offset) * scale. */ int iio_read_avail_channel_raw(struct iio_channel *chan, const int **vals, int *length); From ad4e8480a1db8713ee7dfcc2770ea9f577750111 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 23 Jun 2023 10:58:22 +0200 Subject: [PATCH 042/334] iio: inkern: Remove the 'unused' variable usage in iio_channel_read_max() The code uses a local variable to initialize a null pointer in order to avoid accessing this null pointer later on. Simply removed the 'unused' variable and check for the null pointer just before accessing it. Signed-off-by: Herve Codina Reviewed-by: Andy Shevchenko Acked-by: Jonathan Cameron Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20230623085830.749991-6-herve.codina@bootlin.com Signed-off-by: Mark Brown --- drivers/iio/inkern.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index f738db9a0c04..ce537b4ca6ca 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -849,14 +849,10 @@ static int iio_channel_read_max(struct iio_channel *chan, int *val, int *val2, int *type, enum iio_chan_info_enum info) { - int unused; const int *vals; int length; int ret; - if (!val2) - val2 = &unused; - ret = iio_channel_read_avail(chan, &vals, type, &length, info); if (ret < 0) return ret; @@ -869,7 +865,8 @@ static int iio_channel_read_max(struct iio_channel *chan, break; default: *val = vals[4]; - *val2 = vals[5]; + if (val2) + *val2 = vals[5]; } return 0; From 524cfdf6b88e2536f90f726b8c01ffe218f37d68 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 23 Jun 2023 10:58:23 +0200 Subject: [PATCH 043/334] iio: inkern: Fix headers inclusion order Fix the mutex.h inclusion order as it seems to be the only one misplaces. Signed-off-by: Herve Codina Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Acked-by: Jonathan Cameron Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20230623085830.749991-7-herve.codina@bootlin.com Signed-off-by: Mark Brown --- drivers/iio/inkern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index ce537b4ca6ca..71d0424383b6 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -5,9 +5,9 @@ */ #include #include +#include #include #include -#include #include #include From c952c748c7a983a8bda9112984e6f2c1f6e441a5 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 23 Jun 2023 10:58:24 +0200 Subject: [PATCH 044/334] minmax: Introduce {min,max}_array() Introduce min_array() (resp max_array()) in order to get the minimal (resp maximum) of values present in an array. Signed-off-by: Herve Codina Reviewed-by: Andy Shevchenko Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20230623085830.749991-8-herve.codina@bootlin.com Signed-off-by: Mark Brown --- include/linux/minmax.h | 64 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/include/linux/minmax.h b/include/linux/minmax.h index 396df1121bff..798c6963909f 100644 --- a/include/linux/minmax.h +++ b/include/linux/minmax.h @@ -133,6 +133,70 @@ */ #define max_t(type, x, y) __careful_cmp((type)(x), (type)(y), >) +/* + * Remove a const qualifier from integer types + * _Generic(foo, type-name: association, ..., default: association) performs a + * comparison against the foo type (not the qualified type). + * Do not use the const keyword in the type-name as it will not match the + * unqualified type of foo. + */ +#define __unconst_integer_type_cases(type) \ + unsigned type: (unsigned type)0, \ + signed type: (signed type)0 + +#define __unconst_integer_typeof(x) typeof( \ + _Generic((x), \ + char: (char)0, \ + __unconst_integer_type_cases(char), \ + __unconst_integer_type_cases(short), \ + __unconst_integer_type_cases(int), \ + __unconst_integer_type_cases(long), \ + __unconst_integer_type_cases(long long), \ + default: (x))) + +/* + * Do not check the array parameter using __must_be_array(). + * In the following legit use-case where the "array" passed is a simple pointer, + * __must_be_array() will return a failure. + * --- 8< --- + * int *buff + * ... + * min = min_array(buff, nb_items); + * --- 8< --- + * + * The first typeof(&(array)[0]) is needed in order to support arrays of both + * 'int *buff' and 'int buff[N]' types. + * + * The array can be an array of const items. + * typeof() keeps the const qualifier. Use __unconst_integer_typeof() in order + * to discard the const qualifier for the __element variable. + */ +#define __minmax_array(op, array, len) ({ \ + typeof(&(array)[0]) __array = (array); \ + typeof(len) __len = (len); \ + __unconst_integer_typeof(__array[0]) __element = __array[--__len]; \ + while (__len--) \ + __element = op(__element, __array[__len]); \ + __element; }) + +/** + * min_array - return minimum of values present in an array + * @array: array + * @len: array length + * + * Note that @len must not be zero (empty array). + */ +#define min_array(array, len) __minmax_array(min, array, len) + +/** + * max_array - return maximum of values present in an array + * @array: array + * @len: array length + * + * Note that @len must not be zero (empty array). + */ +#define max_array(array, len) __minmax_array(max, array, len) + /** * clamp_t - return a value clamped to a given range using a given type * @type: the type of variable to use From 97aee7157eeadaf628e7f76da5e49cee91f19901 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 23 Jun 2023 10:58:25 +0200 Subject: [PATCH 045/334] iio: inkern: Use max_array() to get the maximum value from an array Use max_array() to get the maximum value from an array instead of a custom local loop. Signed-off-by: Herve Codina Reviewed-by: Andy Shevchenko Acked-by: Jonathan Cameron Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20230623085830.749991-9-herve.codina@bootlin.com Signed-off-by: Mark Brown --- drivers/iio/inkern.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 71d0424383b6..8bfd91f74101 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -5,6 +5,7 @@ */ #include #include +#include #include #include #include @@ -875,11 +876,7 @@ static int iio_channel_read_max(struct iio_channel *chan, return -EINVAL; switch (*type) { case IIO_VAL_INT: - *val = vals[--length]; - while (length) { - if (vals[--length] > *val) - *val = vals[length]; - } + *val = max_array(vals, length); break; default: /* FIXME: learn about max for other iio values */ From 4dc603735826ec3963e30d6f25260255ca96d103 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 23 Jun 2023 10:58:26 +0200 Subject: [PATCH 046/334] iio: inkern: Replace a FIXME comment by a TODO one This FIXME comment is more a TODO one. It is a note when someone will need for this currently unsupported case. Change from FIXME to TODO. Signed-off-by: Herve Codina Suggested-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Acked-by: Jonathan Cameron Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20230623085830.749991-10-herve.codina@bootlin.com Signed-off-by: Mark Brown --- drivers/iio/inkern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 8bfd91f74101..19ddd77adb11 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -879,7 +879,7 @@ static int iio_channel_read_max(struct iio_channel *chan, *val = max_array(vals, length); break; default: - /* FIXME: learn about max for other iio values */ + /* TODO: learn about max for other iio values */ return -EINVAL; } return 0; From 7560418078b939e1e83f7dce502ec3c1ca8c152f Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 23 Jun 2023 10:58:27 +0200 Subject: [PATCH 047/334] iio: inkern: Add a helper to query an available minimum raw value A helper, iio_read_max_channel_raw() exists to read the available maximum raw value of a channel but nothing similar exists to read the available minimum raw value. This new helper, iio_read_min_channel_raw(), fills the hole and can be used for reading the available minimum raw value of a channel. It is fully based on the existing iio_read_max_channel_raw(). Signed-off-by: Herve Codina Reviewed-by: Andy Shevchenko Acked-by: Jonathan Cameron Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20230623085830.749991-11-herve.codina@bootlin.com Signed-off-by: Mark Brown --- drivers/iio/inkern.c | 63 ++++++++++++++++++++++++++++++++++++ include/linux/iio/consumer.h | 12 +++++++ 2 files changed, 75 insertions(+) diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 19ddd77adb11..7a1f6713318a 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -909,6 +909,69 @@ int iio_read_max_channel_raw(struct iio_channel *chan, int *val) } EXPORT_SYMBOL_GPL(iio_read_max_channel_raw); +static int iio_channel_read_min(struct iio_channel *chan, + int *val, int *val2, int *type, + enum iio_chan_info_enum info) +{ + const int *vals; + int length; + int ret; + + ret = iio_channel_read_avail(chan, &vals, type, &length, info); + if (ret < 0) + return ret; + + switch (ret) { + case IIO_AVAIL_RANGE: + switch (*type) { + case IIO_VAL_INT: + *val = vals[0]; + break; + default: + *val = vals[0]; + if (val2) + *val2 = vals[1]; + } + return 0; + + case IIO_AVAIL_LIST: + if (length <= 0) + return -EINVAL; + switch (*type) { + case IIO_VAL_INT: + *val = min_array(vals, length); + break; + default: + /* TODO: learn about min for other iio values */ + return -EINVAL; + } + return 0; + + default: + return -EINVAL; + } +} + +int iio_read_min_channel_raw(struct iio_channel *chan, int *val) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); + int ret; + int type; + + mutex_lock(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) { + ret = -ENODEV; + goto err_unlock; + } + + ret = iio_channel_read_min(chan, val, NULL, &type, IIO_CHAN_INFO_RAW); +err_unlock: + mutex_unlock(&iio_dev_opaque->info_exist_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(iio_read_min_channel_raw); + int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index f536820b9cf2..e9910b41d48e 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -301,6 +301,18 @@ int iio_write_channel_raw(struct iio_channel *chan, int val); */ int iio_read_max_channel_raw(struct iio_channel *chan, int *val); +/** + * iio_read_min_channel_raw() - read minimum available raw value from a given + * channel, i.e. the minimum possible value. + * @chan: The channel being queried. + * @val: Value read back. + * + * Note, if standard units are required, raw reads from iio channels + * need the offset (default 0) and scale (default 1) to be applied + * as (raw + offset) * scale. + */ +int iio_read_min_channel_raw(struct iio_channel *chan, int *val); + /** * iio_read_avail_channel_raw() - read available raw values from a given channel * @chan: The channel being queried. From 12e58fec5b2aff3ae6fef4e6c278f295a666b9b6 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 23 Jun 2023 10:58:28 +0200 Subject: [PATCH 048/334] ASoC: soc-dapm.h: Convert macros to return a compound literal The SND_SOC_DAPM_* helpers family are used to build widgets array in a static way. Convert them to return a compound literal in order to use them in both static and dynamic way. With this conversion, the different SND_SOC_DAPM_* parameters can be computed by the code and the widget can be built based on this parameter computation. static int create_widget(char *input_name) { struct snd_soc_dapm_widget widget; char name*; ... name = input_name; if (!name) name = "default"; widget = SND_SOC_DAPM_INPUT(name); ... } Signed-off-by: Herve Codina Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20230623085830.749991-12-herve.codina@bootlin.com Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 138 ++++++++++++++++++++++++++------------- 1 file changed, 92 insertions(+), 46 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 87f8e1793af1..2e38dff16779 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -42,36 +42,45 @@ struct soc_enum; /* codec domain */ #define SND_SOC_DAPM_VMID(wname) \ -{ .id = snd_soc_dapm_vmid, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_vmid, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0} /* platform domain */ #define SND_SOC_DAPM_SIGGEN(wname) \ -{ .id = snd_soc_dapm_siggen, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_siggen, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM } #define SND_SOC_DAPM_SINK(wname) \ -{ .id = snd_soc_dapm_sink, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_sink, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM } #define SND_SOC_DAPM_INPUT(wname) \ -{ .id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM } #define SND_SOC_DAPM_OUTPUT(wname) \ -{ .id = snd_soc_dapm_output, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_output, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM } #define SND_SOC_DAPM_MIC(wname, wevent) \ -{ .id = snd_soc_dapm_mic, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mic, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD} #define SND_SOC_DAPM_HP(wname, wevent) \ -{ .id = snd_soc_dapm_hp, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_hp, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} #define SND_SOC_DAPM_SPK(wname, wevent) \ -{ .id = snd_soc_dapm_spk, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_spk, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} #define SND_SOC_DAPM_LINE(wname, wevent) \ -{ .id = snd_soc_dapm_line, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_line, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} @@ -82,93 +91,110 @@ struct soc_enum; /* path domain */ #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\ wcontrols, wncontrols) \ -{ .id = snd_soc_dapm_pga, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_pga, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\ wcontrols, wncontrols) \ -{ .id = snd_soc_dapm_out_drv, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_out_drv, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \ wcontrols, wncontrols)\ -{ .id = snd_soc_dapm_mixer, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mixer, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \ wcontrols, wncontrols)\ -{ .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} /* DEPRECATED: use SND_SOC_DAPM_SUPPLY */ #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \ -{ .id = snd_soc_dapm_micbias, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_micbias, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = NULL, .num_kcontrols = 0} #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \ -{ .id = snd_soc_dapm_switch, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_switch, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = 1} #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \ -{ .id = snd_soc_dapm_mux, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mux, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = 1} #define SND_SOC_DAPM_DEMUX(wname, wreg, wshift, winvert, wcontrols) \ -{ .id = snd_soc_dapm_demux, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_demux, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = 1} /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\ wcontrols) \ -{ .id = snd_soc_dapm_pga, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_pga, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} #define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \ wcontrols)\ -{ .id = snd_soc_dapm_mixer, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mixer, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} #define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \ wcontrols)\ -{ .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} /* path domain with event - event handler must return 0 for success */ #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \ wncontrols, wevent, wflags) \ -{ .id = snd_soc_dapm_pga, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_pga, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \ .event = wevent, .event_flags = wflags} #define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \ wncontrols, wevent, wflags) \ -{ .id = snd_soc_dapm_out_drv, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_out_drv, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \ .event = wevent, .event_flags = wflags} #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \ wncontrols, wevent, wflags) \ -{ .id = snd_soc_dapm_mixer, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mixer, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \ .event = wevent, .event_flags = wflags} #define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \ wcontrols, wncontrols, wevent, wflags) \ -{ .id = snd_soc_dapm_mixer, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mixer, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, \ .num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags} #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \ wevent, wflags) \ -{ .id = snd_soc_dapm_switch, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_switch, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = 1, \ .event = wevent, .event_flags = wflags} #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \ wevent, wflags) \ -{ .id = snd_soc_dapm_mux, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mux, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = 1, \ .event = wevent, .event_flags = wflags} @@ -176,101 +202,121 @@ struct soc_enum; /* additional sequencing control within an event type */ #define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \ wevent, wflags) \ -{ .id = snd_soc_dapm_pga, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_pga, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags, \ .subseq = wsubseq} #define SND_SOC_DAPM_SUPPLY_S(wname, wsubseq, wreg, wshift, winvert, wevent, \ wflags) \ -{ .id = snd_soc_dapm_supply, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_supply, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags, .subseq = wsubseq} /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \ wevent, wflags) \ -{ .id = snd_soc_dapm_pga, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_pga, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ .event = wevent, .event_flags = wflags} #define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \ wevent, wflags) \ -{ .id = snd_soc_dapm_mixer, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mixer, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ .event = wevent, .event_flags = wflags} #define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \ wcontrols, wevent, wflags) \ -{ .id = snd_soc_dapm_mixer, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mixer, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ .event = wevent, .event_flags = wflags} /* events that are pre and post DAPM */ #define SND_SOC_DAPM_PRE(wname, wevent) \ -{ .id = snd_soc_dapm_pre, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_pre, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD} #define SND_SOC_DAPM_POST(wname, wevent) \ -{ .id = snd_soc_dapm_post, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_post, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD} /* stream domain */ #define SND_SOC_DAPM_AIF_IN(wname, stname, wchan, wreg, wshift, winvert) \ -{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } #define SND_SOC_DAPM_AIF_IN_E(wname, stname, wchan, wreg, wshift, winvert, \ wevent, wflags) \ -{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags } #define SND_SOC_DAPM_AIF_OUT(wname, stname, wchan, wreg, wshift, winvert) \ -{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } #define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wchan, wreg, wshift, winvert, \ wevent, wflags) \ -{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags } #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \ -{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) } #define SND_SOC_DAPM_DAC_E(wname, stname, wreg, wshift, winvert, \ wevent, wflags) \ -{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags} #define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \ -{ .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } #define SND_SOC_DAPM_ADC_E(wname, stname, wreg, wshift, winvert, \ wevent, wflags) \ -{ .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags} #define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \ -{ .id = snd_soc_dapm_clock_supply, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_clock_supply, .name = wname, \ .reg = SND_SOC_NOPM, .event = dapm_clock_event, \ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD } /* generic widgets */ #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \ -{ .id = wid, .name = wname, .kcontrol_news = NULL, .num_kcontrols = 0, \ +(struct snd_soc_dapm_widget) { \ + .id = wid, .name = wname, .kcontrol_news = NULL, .num_kcontrols = 0, \ .reg = wreg, .shift = wshift, .mask = wmask, \ .on_val = won_val, .off_val = woff_val, } #define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \ -{ .id = snd_soc_dapm_supply, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_supply, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags} #define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay, wflags) \ -{ .id = snd_soc_dapm_regulator_supply, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_regulator_supply, .name = wname, \ .reg = SND_SOC_NOPM, .shift = wdelay, .event = 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) \ -{ .id = snd_soc_dapm_pinctrl, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .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, \ From 1d298ad822178d365b53eac298c1752730505306 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 23 Jun 2023 10:58:29 +0200 Subject: [PATCH 049/334] ASoC: codecs: Add support for the generic IIO auxiliary devices Industrial I/O devices can be present in the audio path. These devices needs to be used as audio components in order to be fully integrated in the audio path. This support allows to consider these Industrial I/O devices as auxiliary audio devices and allows one to control them using mixer controls. Signed-off-by: Herve Codina Reviewed-by: Jonathan Cameron Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20230623085830.749991-13-herve.codina@bootlin.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 12 ++ sound/soc/codecs/Makefile | 2 + sound/soc/codecs/audio-iio-aux.c | 344 +++++++++++++++++++++++++++++++ 3 files changed, 358 insertions(+) create mode 100644 sound/soc/codecs/audio-iio-aux.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c2de4ee72183..42146b436ac3 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -53,6 +53,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_AK5558 imply SND_SOC_ALC5623 imply SND_SOC_ALC5632 + imply SND_SOC_AUDIO_IIO_AUX imply SND_SOC_AW8738 imply SND_SOC_AW88395 imply SND_SOC_BT_SCO @@ -614,6 +615,17 @@ config SND_SOC_ALC5632 tristate depends on I2C +config SND_SOC_AUDIO_IIO_AUX + tristate "Audio IIO Auxiliary device" + depends on IIO + help + Enable support for Industrial I/O devices as audio auxiliary devices. + This allows to have an IIO device present in the audio path and + controlled using mixer controls. + + To compile this driver as a module, choose M here: the module + will be called snd-soc-audio-iio-aux. + config SND_SOC_AW8738 tristate "Awinic AW8738 Audio Amplifier" select GPIOLIB diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index b48a9a323b84..32dcc6de58bd 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -45,6 +45,7 @@ snd-soc-ak4671-objs := ak4671.o snd-soc-ak5386-objs := ak5386.o snd-soc-ak5558-objs := ak5558.o snd-soc-arizona-objs := arizona.o arizona-jack.o +snd-soc-audio-iio-aux-objs := audio-iio-aux.o snd-soc-aw8738-objs := aw8738.o snd-soc-aw88395-lib-objs := aw88395/aw88395_lib.o snd-soc-aw88395-objs := aw88395/aw88395.o \ @@ -428,6 +429,7 @@ obj-$(CONFIG_SND_SOC_AK5558) += snd-soc-ak5558.o obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o +obj-$(CONFIG_SND_SOC_AUDIO_IIO_AUX) += snd-soc-audio-iio-aux.o obj-$(CONFIG_SND_SOC_AW8738) += snd-soc-aw8738.o obj-$(CONFIG_SND_SOC_AW88395_LIB) += snd-soc-aw88395-lib.o obj-$(CONFIG_SND_SOC_AW88395) +=snd-soc-aw88395.o diff --git a/sound/soc/codecs/audio-iio-aux.c b/sound/soc/codecs/audio-iio-aux.c new file mode 100644 index 000000000000..a8bf14239bd7 --- /dev/null +++ b/sound/soc/codecs/audio-iio-aux.c @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// ALSA SoC glue to use IIO devices as audio components +// +// Copyright 2023 CS GROUP France +// +// Author: Herve Codina + +#include +#include +#include +#include +#include +#include + +#include +#include + +struct audio_iio_aux_chan { + struct iio_channel *iio_chan; + const char *name; + int max; + int min; + bool is_invert_range; +}; + +struct audio_iio_aux { + struct device *dev; + struct audio_iio_aux_chan *chans; + unsigned int num_chans; +}; + +static int audio_iio_aux_info_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct audio_iio_aux_chan *chan = (struct audio_iio_aux_chan *)kcontrol->private_value; + + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = chan->max - chan->min; + uinfo->type = (uinfo->value.integer.max == 1) ? + SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; + return 0; +} + +static int audio_iio_aux_get_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct audio_iio_aux_chan *chan = (struct audio_iio_aux_chan *)kcontrol->private_value; + int max = chan->max; + int min = chan->min; + bool invert_range = chan->is_invert_range; + int ret; + int val; + + ret = iio_read_channel_raw(chan->iio_chan, &val); + if (ret < 0) + return ret; + + ucontrol->value.integer.value[0] = val - min; + if (invert_range) + ucontrol->value.integer.value[0] = max - ucontrol->value.integer.value[0]; + + return 0; +} + +static int audio_iio_aux_put_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct audio_iio_aux_chan *chan = (struct audio_iio_aux_chan *)kcontrol->private_value; + int max = chan->max; + int min = chan->min; + bool invert_range = chan->is_invert_range; + int val; + int ret; + int tmp; + + val = ucontrol->value.integer.value[0]; + if (val < 0) + return -EINVAL; + if (val > max - min) + return -EINVAL; + + val = val + min; + if (invert_range) + val = max - val; + + ret = iio_read_channel_raw(chan->iio_chan, &tmp); + if (ret < 0) + return ret; + + if (tmp == val) + return 0; + + ret = iio_write_channel_raw(chan->iio_chan, val); + if (ret) + return ret; + + return 1; /* The value changed */ +} + +static int audio_iio_aux_add_controls(struct snd_soc_component *component, + struct audio_iio_aux_chan *chan) +{ + struct snd_kcontrol_new control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = chan->name, + .info = audio_iio_aux_info_volsw, + .get = audio_iio_aux_get_volsw, + .put = audio_iio_aux_put_volsw, + .private_value = (unsigned long)chan, + }; + + return snd_soc_add_component_controls(component, &control, 1); +} + +/* + * These data could be on stack but they are pretty big. + * As ASoC internally copy them and protect them against concurrent accesses + * (snd_soc_bind_card() protects using client_mutex), keep them in the global + * data area. + */ +static struct snd_soc_dapm_widget widgets[3]; +static struct snd_soc_dapm_route routes[2]; + +/* Be sure sizes are correct (need 3 widgets and 2 routes) */ +static_assert(ARRAY_SIZE(widgets) >= 3, "3 widgets are needed"); +static_assert(ARRAY_SIZE(routes) >= 2, "2 routes are needed"); + +static int audio_iio_aux_add_dapms(struct snd_soc_component *component, + struct audio_iio_aux_chan *chan) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + char *output_name; + char *input_name; + char *pga_name; + int ret; + + input_name = kasprintf(GFP_KERNEL, "%s IN", chan->name); + if (!input_name) + return -ENOMEM; + + output_name = kasprintf(GFP_KERNEL, "%s OUT", chan->name); + if (!output_name) { + ret = -ENOMEM; + goto out_free_input_name; + } + + pga_name = kasprintf(GFP_KERNEL, "%s PGA", chan->name); + if (!pga_name) { + ret = -ENOMEM; + goto out_free_output_name; + } + + widgets[0] = SND_SOC_DAPM_INPUT(input_name); + widgets[1] = SND_SOC_DAPM_OUTPUT(output_name); + widgets[2] = SND_SOC_DAPM_PGA(pga_name, SND_SOC_NOPM, 0, 0, NULL, 0); + ret = snd_soc_dapm_new_controls(dapm, widgets, 3); + if (ret) + goto out_free_pga_name; + + routes[0].sink = pga_name; + routes[0].control = NULL; + routes[0].source = input_name; + routes[1].sink = output_name; + routes[1].control = NULL; + routes[1].source = pga_name; + ret = snd_soc_dapm_add_routes(dapm, routes, 2); + + /* Allocated names are no more needed (duplicated in ASoC internals) */ + +out_free_pga_name: + kfree(pga_name); +out_free_output_name: + kfree(output_name); +out_free_input_name: + kfree(input_name); + return ret; +} + +static int audio_iio_aux_component_probe(struct snd_soc_component *component) +{ + struct audio_iio_aux *iio_aux = snd_soc_component_get_drvdata(component); + struct audio_iio_aux_chan *chan; + int ret; + int i; + + for (i = 0; i < iio_aux->num_chans; i++) { + chan = iio_aux->chans + i; + + ret = iio_read_max_channel_raw(chan->iio_chan, &chan->max); + if (ret) + return dev_err_probe(component->dev, ret, + "chan[%d] %s: Cannot get max raw value\n", + i, chan->name); + + ret = iio_read_min_channel_raw(chan->iio_chan, &chan->min); + if (ret) + return dev_err_probe(component->dev, ret, + "chan[%d] %s: Cannot get min raw value\n", + i, chan->name); + + if (chan->min > chan->max) { + /* + * This should never happen but to avoid any check + * later, just swap values here to ensure that the + * minimum value is lower than the maximum value. + */ + dev_dbg(component->dev, "chan[%d] %s: Swap min and max\n", + i, chan->name); + swap(chan->min, chan->max); + } + + /* Set initial value */ + ret = iio_write_channel_raw(chan->iio_chan, + chan->is_invert_range ? chan->max : chan->min); + if (ret) + return dev_err_probe(component->dev, ret, + "chan[%d] %s: Cannot set initial value\n", + i, chan->name); + + ret = audio_iio_aux_add_controls(component, chan); + if (ret) + return ret; + + ret = audio_iio_aux_add_dapms(component, chan); + if (ret) + return ret; + + dev_dbg(component->dev, "chan[%d]: Added %s (min=%d, max=%d, invert=%s)\n", + i, chan->name, chan->min, chan->max, + str_on_off(chan->is_invert_range)); + } + + return 0; +} + +static const struct snd_soc_component_driver audio_iio_aux_component_driver = { + .probe = audio_iio_aux_component_probe, +}; + +static int audio_iio_aux_probe(struct platform_device *pdev) +{ + struct audio_iio_aux_chan *iio_aux_chan; + struct device *dev = &pdev->dev; + struct audio_iio_aux *iio_aux; + const char **names; + u32 *invert_ranges; + int count; + int ret; + int i; + + iio_aux = devm_kzalloc(dev, sizeof(*iio_aux), GFP_KERNEL); + if (!iio_aux) + return -ENOMEM; + + iio_aux->dev = dev; + + count = device_property_string_array_count(dev, "io-channel-names"); + if (count < 0) + return dev_err_probe(dev, count, "failed to count io-channel-names\n"); + + iio_aux->num_chans = count; + + iio_aux->chans = devm_kmalloc_array(dev, iio_aux->num_chans, + sizeof(*iio_aux->chans), GFP_KERNEL); + if (!iio_aux->chans) + return -ENOMEM; + + names = kcalloc(iio_aux->num_chans, sizeof(*names), GFP_KERNEL); + if (!names) + return -ENOMEM; + + invert_ranges = kcalloc(iio_aux->num_chans, sizeof(*invert_ranges), GFP_KERNEL); + if (!invert_ranges) { + ret = -ENOMEM; + goto out_free_names; + } + + ret = device_property_read_string_array(dev, "io-channel-names", + names, iio_aux->num_chans); + if (ret < 0) { + dev_err_probe(dev, ret, "failed to read io-channel-names\n"); + goto out_free_invert_ranges; + } + + /* + * snd-control-invert-range is optional and can contain fewer items + * than the number of channels. Unset values default to 0. + */ + count = device_property_count_u32(dev, "snd-control-invert-range"); + if (count > 0) { + count = min_t(unsigned int, count, iio_aux->num_chans); + ret = device_property_read_u32_array(dev, "snd-control-invert-range", + invert_ranges, count); + if (ret < 0) { + dev_err_probe(dev, ret, "failed to read snd-control-invert-range\n"); + goto out_free_invert_ranges; + } + } + + for (i = 0; i < iio_aux->num_chans; i++) { + iio_aux_chan = iio_aux->chans + i; + iio_aux_chan->name = names[i]; + iio_aux_chan->is_invert_range = invert_ranges[i]; + + iio_aux_chan->iio_chan = devm_iio_channel_get(dev, iio_aux_chan->name); + if (IS_ERR(iio_aux_chan->iio_chan)) { + ret = PTR_ERR(iio_aux_chan->iio_chan); + dev_err_probe(dev, ret, "get IIO channel '%s' failed\n", + iio_aux_chan->name); + goto out_free_invert_ranges; + } + } + + platform_set_drvdata(pdev, iio_aux); + + ret = devm_snd_soc_register_component(dev, &audio_iio_aux_component_driver, + NULL, 0); +out_free_invert_ranges: + kfree(invert_ranges); +out_free_names: + kfree(names); + return ret; +} + +static const struct of_device_id audio_iio_aux_ids[] = { + { .compatible = "audio-iio-aux" }, + { } +}; +MODULE_DEVICE_TABLE(of, audio_iio_aux_ids); + +static struct platform_driver audio_iio_aux_driver = { + .driver = { + .name = "audio-iio-aux", + .of_match_table = audio_iio_aux_ids, + }, + .probe = audio_iio_aux_probe, +}; +module_platform_driver(audio_iio_aux_driver); + +MODULE_AUTHOR("Herve Codina "); +MODULE_DESCRIPTION("IIO ALSA SoC aux driver"); +MODULE_LICENSE("GPL"); From 6d8ad35d119ca4c9c6fdf83faa733102c4a63f4b Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 23 Jun 2023 10:58:30 +0200 Subject: [PATCH 050/334] ASoC: simple-card: Handle additional devices An additional-devs subnode can be present in the simple-card top node. This subnode is used to declared some "virtual" additional devices. Create related devices from this subnode and avoid this subnode presence to interfere with the already supported subnodes analysis. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20230623085830.749991-14-herve.codina@bootlin.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 46 +++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 0745bf6a09aa..a78babf44f38 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -346,6 +346,7 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv, struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; struct device_node *node; + struct device_node *add_devs; uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev); bool is_top = 0; int ret = 0; @@ -357,6 +358,8 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv, is_top = 1; } + add_devs = of_get_child_by_name(top, PREFIX "additional-devs"); + /* loop for all dai-link */ do { struct asoc_simple_data adata; @@ -365,6 +368,12 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv, struct device_node *np; int num = of_get_child_count(node); + /* Skip additional-devs node */ + if (node == add_devs) { + node = of_get_next_child(top, node); + continue; + } + /* get codec */ codec = of_get_child_by_name(node, is_top ? PREFIX "codec" : "codec"); @@ -378,12 +387,15 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv, /* get convert-xxx property */ memset(&adata, 0, sizeof(adata)); - for_each_child_of_node(node, np) + for_each_child_of_node(node, np) { + if (np == add_devs) + continue; simple_parse_convert(dev, np, &adata); + } /* loop for all CPU/Codec node */ for_each_child_of_node(node, np) { - if (plat == np) + if (plat == np || add_devs == np) continue; /* * It is DPCM @@ -426,6 +438,7 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv, } while (!is_top && node); error: + of_node_put(add_devs); of_node_put(node); return ret; } @@ -463,6 +476,31 @@ static int simple_for_each_link(struct asoc_simple_priv *priv, return ret; } +static void simple_depopulate_aux(void *data) +{ + struct asoc_simple_priv *priv = data; + + of_platform_depopulate(simple_priv_to_dev(priv)); +} + +static int simple_populate_aux(struct asoc_simple_priv *priv) +{ + struct device *dev = simple_priv_to_dev(priv); + struct device_node *node; + int ret; + + node = of_get_child_by_name(dev->of_node, PREFIX "additional-devs"); + if (!node) + return 0; + + ret = of_platform_populate(node, NULL, NULL, dev); + of_node_put(node); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, simple_depopulate_aux, priv); +} + static int simple_parse_of(struct asoc_simple_priv *priv, struct link_info *li) { struct snd_soc_card *card = simple_priv_to_card(priv); @@ -492,6 +530,10 @@ static int simple_parse_of(struct asoc_simple_priv *priv, struct link_info *li) if (ret < 0) return ret; + ret = simple_populate_aux(priv); + if (ret < 0) + return ret; + ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs"); return ret; From 2b48d170fb9965dda9d41edcb0bbfc9ee4c6584f Mon Sep 17 00:00:00 2001 From: Mastan Katragadda Date: Fri, 30 Jun 2023 12:35:43 +0530 Subject: [PATCH 051/334] ASoC: SOF: amd: refactor PSP smn_read Use the read_poll_timeout marco for PSP smn_read calls. Signed-off-by: Mastan Katragadda Link: https://lore.kernel.org/r/20230630070544.2167421-2-Mastan.Katragadda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 36 ++++++++++++++++-------------------- sound/soc/sof/amd/acp.h | 4 ++-- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index afb505461ea1..c450931ae77e 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -28,12 +28,14 @@ static int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data) return 0; } -static int smn_read(struct pci_dev *dev, u32 smn_addr, u32 *data) +static int smn_read(struct pci_dev *dev, u32 smn_addr) { - pci_write_config_dword(dev, 0x60, smn_addr); - pci_read_config_dword(dev, 0x64, data); + u32 data = 0; - return 0; + pci_write_config_dword(dev, 0x60, smn_addr); + pci_read_config_dword(dev, 0x64, &data); + + return data; } static void init_dma_descriptor(struct acp_dev_data *adata) @@ -150,15 +152,13 @@ int configure_and_run_dma(struct acp_dev_data *adata, unsigned int src_addr, static int psp_mbox_ready(struct acp_dev_data *adata, bool ack) { struct snd_sof_dev *sdev = adata->dev; - int timeout; + int ret; u32 data; - for (timeout = ACP_PSP_TIMEOUT_COUNTER; timeout > 0; timeout--) { - msleep(20); - smn_read(adata->smn_dev, MP0_C2PMSG_114_REG, &data); - if (data & MBOX_READY_MASK) - return 0; - } + ret = read_poll_timeout(smn_read, data, data & MBOX_READY_MASK, MBOX_DELAY_US, + ACP_PSP_TIMEOUT_US, false, adata->smn_dev, MP0_C2PMSG_114_REG); + if (!ret) + return 0; dev_err(sdev->dev, "PSP error status %x\n", data & MBOX_STATUS_MASK); @@ -177,23 +177,19 @@ static int psp_mbox_ready(struct acp_dev_data *adata, bool ack) static int psp_send_cmd(struct acp_dev_data *adata, int cmd) { struct snd_sof_dev *sdev = adata->dev; - int ret, timeout; + int ret; u32 data; if (!cmd) return -EINVAL; /* Get a non-zero Doorbell value from PSP */ - for (timeout = ACP_PSP_TIMEOUT_COUNTER; timeout > 0; timeout--) { - msleep(MBOX_DELAY); - smn_read(adata->smn_dev, MP0_C2PMSG_73_REG, &data); - if (data) - break; - } + ret = read_poll_timeout(smn_read, data, data, MBOX_DELAY_US, ACP_PSP_TIMEOUT_US, false, + adata->smn_dev, MP0_C2PMSG_73_REG); - if (!timeout) { + if (ret) { dev_err(sdev->dev, "Failed to get Doorbell from MBOX %x\n", MP0_C2PMSG_73_REG); - return -EINVAL; + return ret; } /* Check if PSP is ready for new command */ diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index dc624f727aa3..c3659dbc3745 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -61,12 +61,12 @@ #define HOST_BRIDGE_CZN 0x1630 #define HOST_BRIDGE_RMB 0x14B5 #define ACP_SHA_STAT 0x8000 -#define ACP_PSP_TIMEOUT_COUNTER 5 +#define ACP_PSP_TIMEOUT_US 1000000 #define ACP_EXT_INTR_ERROR_STAT 0x20000000 #define MP0_C2PMSG_114_REG 0x3810AC8 #define MP0_C2PMSG_73_REG 0x3810A24 #define MBOX_ACP_SHA_DMA_COMMAND 0x70000 -#define MBOX_DELAY 1000 +#define MBOX_DELAY_US 1000 #define MBOX_READY_MASK 0x80000000 #define MBOX_STATUS_MASK 0xFFFF From 521d675d2497f890e881dc48e954a1559460e97c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 21 Jun 2023 02:18:10 +0000 Subject: [PATCH 052/334] ASoC: soc-core.c: initialize dlc on snd_soc_get_dai_id() Current snd_soc_get_dai_id() is initializing dlc *manually*, but it will might be a problem if dlc had new extra parameter. This patch uses default initialization, otherwise, non initialized part will be strange value. This is prepare for multi Component support. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pm5pblst.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1a0bde23f5e6..3b39c9d1c158 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3235,11 +3235,12 @@ EXPORT_SYMBOL_GPL(snd_soc_get_stream_cpu); int snd_soc_get_dai_id(struct device_node *ep) { struct snd_soc_component *component; - struct snd_soc_dai_link_component dlc; + struct snd_soc_dai_link_component dlc = { + .of_node = of_graph_get_port_parent(ep), + }; int ret; - dlc.of_node = of_graph_get_port_parent(ep); - dlc.name = NULL; + /* * For example HDMI case, HDMI has video/sound port, * but ALSA SoC needs sound port number only. From 0e66a2c694096abc54ed58b3be654103f155ea43 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 21 Jun 2023 02:18:17 +0000 Subject: [PATCH 053/334] ASoC: soc-core.c: cleanup soc_dai_link_sanity_check() Required CPU/Codec/Platform dlc (snd_soc_dai_link_component) are similar but not same, and very complex. Current implementation is very confusable and it will be more complex if multi Component was supported. This patch cleanup it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87o7l9blsn.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 131 ++++++++++++++++++++++++------------------- 1 file changed, 72 insertions(+), 59 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3b39c9d1c158..7da43f22a650 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -238,6 +238,21 @@ static inline void snd_soc_debugfs_exit(void) { } #endif +static inline int snd_soc_dlc_component_is_empty(struct snd_soc_dai_link_component *dlc) +{ + return !(dlc->name || dlc->of_node); +} + +static inline int snd_soc_dlc_component_is_invalid(struct snd_soc_dai_link_component *dlc) +{ + return (dlc->name && dlc->of_node); +} + +static inline int snd_soc_dlc_dai_is_empty(struct snd_soc_dai_link_component *dlc) +{ + return !dlc->dai_name; +} + static int snd_soc_rtd_add_component(struct snd_soc_pcm_runtime *rtd, struct snd_soc_component *component) { @@ -829,102 +844,100 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card, struct snd_soc_dai_link *link) { int i; - struct snd_soc_dai_link_component *cpu, *codec, *platform; + struct snd_soc_dai_link_component *dlc; - for_each_link_codecs(link, i, codec) { + /* Codec check */ + for_each_link_codecs(link, i, dlc) { /* * Codec must be specified by 1 of name or OF node, * not both or neither. */ - if (!!codec->name == !!codec->of_node) { - dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n", - link->name); - return -EINVAL; - } + if (snd_soc_dlc_component_is_invalid(dlc)) + goto component_invalid; + + if (snd_soc_dlc_component_is_empty(dlc)) + goto component_empty; /* Codec DAI name must be specified */ - if (!codec->dai_name) { - dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n", - link->name); - return -EINVAL; - } + if (snd_soc_dlc_dai_is_empty(dlc)) + goto dai_empty; /* * Defer card registration if codec component is not added to * component list. */ - if (!soc_find_component(codec)) { - dev_dbg(card->dev, - "ASoC: codec component %s not found for link %s\n", - codec->name, link->name); - return -EPROBE_DEFER; - } + if (!soc_find_component(dlc)) + goto component_not_find; } - for_each_link_platforms(link, i, platform) { + /* Platform check */ + for_each_link_platforms(link, i, dlc) { /* * Platform may be specified by either name or OF node, but it * can be left unspecified, then no components will be inserted * in the rtdcom list */ - if (!!platform->name == !!platform->of_node) { - dev_err(card->dev, - "ASoC: Neither/both platform name/of_node are set for %s\n", - link->name); - return -EINVAL; - } + if (snd_soc_dlc_component_is_invalid(dlc)) + goto component_invalid; + + if (snd_soc_dlc_component_is_empty(dlc)) + goto component_empty; /* * Defer card registration if platform component is not added to * component list. */ - if (!soc_find_component(platform)) { - dev_dbg(card->dev, - "ASoC: platform component %s not found for link %s\n", - platform->name, link->name); - return -EPROBE_DEFER; - } + if (!soc_find_component(dlc)) + goto component_not_find; } - for_each_link_cpus(link, i, cpu) { + /* CPU check */ + for_each_link_cpus(link, i, dlc) { /* * CPU device may be specified by either name or OF node, but * can be left unspecified, and will be matched based on DAI * name alone.. */ - if (cpu->name && cpu->of_node) { - dev_err(card->dev, - "ASoC: Neither/both cpu name/of_node are set for %s\n", - link->name); - return -EINVAL; - } + if (snd_soc_dlc_component_is_invalid(dlc)) + goto component_invalid; - /* - * Defer card registration if cpu dai component is not added to - * component list. - */ - if ((cpu->of_node || cpu->name) && - !soc_find_component(cpu)) { - dev_dbg(card->dev, - "ASoC: cpu component %s not found for link %s\n", - cpu->name, link->name); - return -EPROBE_DEFER; - } - /* - * At least one of CPU DAI name or CPU device name/node must be - * specified - */ - if (!cpu->dai_name && - !(cpu->name || cpu->of_node)) { - dev_err(card->dev, - "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n", - link->name); - return -EINVAL; + if (snd_soc_dlc_component_is_empty(dlc)) { + /* + * At least one of CPU DAI name or CPU device name/node must be specified + */ + if (snd_soc_dlc_dai_is_empty(dlc)) + goto component_dai_empty; + } else { + /* + * Defer card registration if Component is not added + */ + if (!soc_find_component(dlc)) + goto component_not_find; } } return 0; + +component_invalid: + dev_err(card->dev, "ASoC: Both Component name/of_node are set for %s\n", link->name); + return -EINVAL; + +component_empty: + dev_err(card->dev, "ASoC: Neither Component name/of_node are set for %s\n", link->name); + return -EINVAL; + +component_not_find: + dev_err(card->dev, "ASoC: Component %s not found for link %s\n", dlc->name, link->name); + return -EPROBE_DEFER; + +dai_empty: + dev_err(card->dev, "ASoC: DAI name is not set for %s\n", link->name); + return -EINVAL; + +component_dai_empty: + dev_err(card->dev, "ASoC: Neither DAI/Component name/of_node are set for %s\n", link->name); + return -EINVAL; } /** From 7f6ecc220272dff53b7cec0ae2a863eefcb5335b Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 5 Jul 2023 12:23:48 +0800 Subject: [PATCH 054/334] ASoC: rt5645: implement set_jack callback Add a wrapper function to support set_jack component driver callback. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20230705042349.24905-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index a506d940a2ea..b0953e9bcaf9 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3258,6 +3258,22 @@ int rt5645_set_jack_detect(struct snd_soc_component *component, } EXPORT_SYMBOL_GPL(rt5645_set_jack_detect); +static int rt5645_component_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *hs_jack, void *data) +{ + struct snd_soc_jack *mic_jack = NULL; + struct snd_soc_jack *btn_jack = NULL; + int *type = (int *)data; + + if (*type & SND_JACK_MICROPHONE) + mic_jack = hs_jack; + if (*type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3)) + btn_jack = hs_jack; + + return rt5645_set_jack_detect(component, hs_jack, mic_jack, btn_jack); +} + static void rt5645_jack_detect_work(struct work_struct *work) { struct rt5645_priv *rt5645 = @@ -3532,6 +3548,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt5645 = { .num_dapm_widgets = ARRAY_SIZE(rt5645_dapm_widgets), .dapm_routes = rt5645_dapm_routes, .num_dapm_routes = ARRAY_SIZE(rt5645_dapm_routes), + .set_jack = rt5645_component_set_jack, .use_pmdown_time = 1, .endianness = 1, }; From 82770b76abae2ff9d70f354a61983b921e63bae1 Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Sun, 25 Jun 2023 14:54:12 +0800 Subject: [PATCH 055/334] ASoC: imx-pcm-rpmsg: Set PCM hardware parameters separately Different PCM devices may have different PCM hardware parameters. It requires PCM hardware parameters set separately if there is more than one rpmsg sound card. Signed-off-by: Chancel Liu Acked-by: Shengjiu Wang Link: https://lore.kernel.org/r/20230625065412.651870-1-chancel.liu@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-pcm-rpmsg.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c index 765dad607bf6..d63782b8bdef 100644 --- a/sound/soc/fsl/imx-pcm-rpmsg.c +++ b/sound/soc/fsl/imx-pcm-rpmsg.c @@ -228,6 +228,10 @@ static int imx_rpmsg_pcm_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct rpmsg_info *info = dev_get_drvdata(component->dev); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev); + struct snd_pcm_hardware pcm_hardware; struct rpmsg_msg *msg; int ret = 0; int cmd; @@ -255,10 +259,11 @@ static int imx_rpmsg_pcm_open(struct snd_soc_component *component, info->send_message(msg, info); - imx_rpmsg_pcm_hardware.period_bytes_max = - imx_rpmsg_pcm_hardware.buffer_bytes_max / 2; + pcm_hardware = imx_rpmsg_pcm_hardware; + pcm_hardware.buffer_bytes_max = rpmsg->buffer_size; + pcm_hardware.period_bytes_max = pcm_hardware.buffer_bytes_max / 2; - snd_soc_set_runtime_hwparams(substream, &imx_rpmsg_pcm_hardware); + snd_soc_set_runtime_hwparams(substream, &pcm_hardware); ret = snd_pcm_hw_constraint_integer(substream->runtime, SNDRV_PCM_HW_PARAM_PERIODS); @@ -597,7 +602,6 @@ static int imx_rpmsg_pcm_new(struct snd_soc_component *component, if (ret) return ret; - imx_rpmsg_pcm_hardware.buffer_bytes_max = rpmsg->buffer_size; return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_WC, pcm->card->dev, rpmsg->buffer_size); } From 065aa861b1243704b329a6d8407d8399614df6bd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 29 Jun 2023 23:52:20 +0000 Subject: [PATCH 056/334] ASoC: soc-core: protect dlc->of_node under mutex dlc->of_node will be set on snd_soc_get_dlc(), but we want 1) protect it by mutex, 2) set only when successed. This patch do it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/878rc1kerv.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7da43f22a650..94e856d67a46 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3278,8 +3278,6 @@ int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_ struct snd_soc_component *pos; int ret = -EPROBE_DEFER; - dlc->of_node = args->np; - mutex_lock(&client_mutex); for_each_component(pos) { struct device_node *component_of_node = soc_component_to_node(pos); @@ -3333,6 +3331,10 @@ int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_ break; } + + if (ret == 0) + dlc->of_node = args->np; + mutex_unlock(&client_mutex); return ret; } From 209fb30ee1c7edc6807ac94f98c9ce78b4891aed Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 21 Jun 2023 16:07:50 +0800 Subject: [PATCH 057/334] ASoC: rt722-sdca: Remove redundant sdca mask Remove redundant sdca mask for clear code. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/20230621080750.13511-1-jack.yu@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt722-sdca-sdw.c | 2 +- sound/soc/codecs/rt722-sdca.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c index cc57e4e27805..a9416bd163e8 100644 --- a/sound/soc/codecs/rt722-sdca-sdw.c +++ b/sound/soc/codecs/rt722-sdca-sdw.c @@ -175,7 +175,7 @@ static int rt722_sdca_update_status(struct sdw_slave *slave, * This also could sync with the cache value as the rt722_sdca_jack_init set. */ sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1, - SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6); + SDW_SCP_SDCA_INTMASK_SDCA_6); sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); } diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c index 9c0d34366c9e..0e1c65a20392 100644 --- a/sound/soc/codecs/rt722-sdca.c +++ b/sound/soc/codecs/rt722-sdca.c @@ -191,8 +191,7 @@ static void rt722_sdca_jack_detect_handler(struct work_struct *work) return; /* SDW_SCP_SDCA_INT_SDCA_6 is used for jack detection */ - if (rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_6 || - rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_0) { + if (rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_6) { ret = rt722_sdca_headset_detect(rt722); if (ret < 0) return; From 754d1ce3ab6bec057bf94b0ec1a789fdfa2fef99 Mon Sep 17 00:00:00 2001 From: Seven Lee Date: Wed, 28 Jun 2023 16:50:09 +0800 Subject: [PATCH 058/334] ASoC: dt-bindings: nau8821: Convert to dtschema Convert the NAU8821 audio CODEC bindings to DT schema. Signed-off-by: Seven Lee Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230628085009.1130318-1-wtli@nuvoton.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/nau8821.txt | 55 -------- .../bindings/sound/nuvoton,nau8821.yaml | 125 ++++++++++++++++++ 2 files changed, 125 insertions(+), 55 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/nau8821.txt create mode 100644 Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml diff --git a/Documentation/devicetree/bindings/sound/nau8821.txt b/Documentation/devicetree/bindings/sound/nau8821.txt deleted file mode 100644 index 7c84e7c7327a..000000000000 --- a/Documentation/devicetree/bindings/sound/nau8821.txt +++ /dev/null @@ -1,55 +0,0 @@ -Nuvoton NAU88L21 audio codec - -This device supports I2C only. - -Required properties: - - compatible : Must be "nuvoton,nau8821" - - - reg : the I2C address of the device. This is either 0x1B (CSB=0) or 0x54 (CSB=1). - -Optional properties: - - nuvoton,jkdet-enable: Enable jack detection via JKDET pin. - - nuvoton,jkdet-pull-enable: Enable JKDET pin pull. If set - pin pull enabled, - otherwise pin in high impedance state. - - nuvoton,jkdet-pull-up: Pull-up JKDET pin. If set then JKDET pin is pull up, otherwise pull down. - - nuvoton,jkdet-polarity: JKDET pin polarity. 0 - active high, 1 - active low. - - - nuvoton,vref-impedance: VREF Impedance selection - 0 - Open - 1 - 25 kOhm - 2 - 125 kOhm - 3 - 2.5 kOhm - - - nuvoton,micbias-voltage: Micbias voltage level. - 0 - VDDA - 1 - VDDA - 2 - VDDA * 1.1 - 3 - VDDA * 1.2 - 4 - VDDA * 1.3 - 5 - VDDA * 1.4 - 6 - VDDA * 1.53 - 7 - VDDA * 1.53 - - - nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms - - nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms - - - nuvoton,dmic-clk-threshold: the ADC threshold of DMIC clock. - - nuvoton,key_enable: Headset button detection switch. - -Example: - - headset: nau8821@1b { - compatible = "nuvoton,nau8821"; - reg = <0x1b>; - interrupt-parent = <&gpio>; - interrupts = <23 IRQ_TYPE_LEVEL_LOW>; - nuvoton,jkdet-enable; - nuvoton,jkdet-pull-enable; - nuvoton,jkdet-pull-up; - nuvoton,jkdet-polarity = ; - nuvoton,vref-impedance = <2>; - nuvoton,micbias-voltage = <6>; - nuvoton,jack-insert-debounce = <7>; - nuvoton,jack-eject-debounce = <7>; - nuvoton,dmic-clk-threshold = 3072000; - }; diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml new file mode 100644 index 000000000000..fc2f4ce4db88 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml @@ -0,0 +1,125 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nuvoton,nau8821.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NAU88L21 audio codec + +maintainers: + - Seven Lee + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: nuvoton,nau8821 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + nuvoton,jkdet-enable: + description: Enable jack detection via JKDET pin. + type: boolean + + nuvoton,jkdet-pull-enable: + description: Enable JKDET pin pull. If set - pin pull enabled, + otherwise pin in high impedance state. + type: boolean + + nuvoton,jkdet-pull-up: + description: Pull-up JKDET pin. If set then JKDET pin is pull up, + otherwise pull down. + type: boolean + + nuvoton,key-enable: + description: handles key press detection. + type: boolean + + nuvoton,jkdet-polarity: + description: JKDET pin polarity. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # active high + - 1 # active low + default: 1 + + nuvoton,micbias-voltage: + description: MICBIAS output level select. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # VDDA + - 1 # VDDA * 1 + - 2 # VDDA * 1.1 + - 3 # VDDA * 1.2 + - 4 # VDDA * 1.3 + - 5 # VDDA * 1.4 + - 6 # VDDA * 1.53 + - 7 # VDDA * 1.53 + default: 6 + + nuvoton,vref-impedance: + description: VMID Tie-off impedance select. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # open + - 1 # 25KOhms + - 2 # 125KOhms + - 3 # 2.5KOhms + default: 2 + + nuvoton,jack-insert-debounce: + description: number from 0 to 7 that sets debounce time to 2^(n+2)ms. + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 7 + default: 7 + + nuvoton,jack-eject-debounce: + description: number from 0 to 7 that sets debounce time to 2^(n+2)ms. + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 7 + default: 0 + + nuvoton,dmic-clk-threshold: + description: DMIC clock speed expected value. Unit is Hz. + $ref: /schemas/types.yaml#/definitions/uint32 + default: 3072000 + + '#sound-dai-cells': + const: 0 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + codec@1b { + compatible = "nuvoton,nau8821"; + reg = <0x1b>; + interrupt-parent = <&gpio>; + interrupts = <23 IRQ_TYPE_LEVEL_LOW>; + nuvoton,jkdet-enable; + nuvoton,jkdet-pull-enable; + nuvoton,jkdet-pull-up; + nuvoton,key-enable; + nuvoton,jkdet-polarity = ; + nuvoton,micbias-voltage = <6>; + nuvoton,vref-impedance = <2>; + nuvoton,jack-insert-debounce = <7>; + nuvoton,jack-eject-debounce = <0>; + nuvoton,dmic-clk-threshold = <3072000>; + #sound-dai-cells = <0>; + }; + }; From 24e04c94bebc4144f790a21a93d090cf9673acd9 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Sun, 25 Jun 2023 09:05:47 +0800 Subject: [PATCH 059/334] ASoC: tas2781: No need to set device_driver owner Remove .owner field if calls are used which set it automatically. to silence the warning: ./sound/soc/codecs/tas2781-i2c.c:746:3-8: No need to set .owner here. The core will do it. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=5589 Signed-off-by: Yang Li Link: https://lore.kernel.org/r/20230625010547.7353-1-yang.lee@linux.alibaba.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2781-i2c.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index 4c59429a42b7..55cd5e3c23a5 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -743,7 +743,6 @@ MODULE_DEVICE_TABLE(acpi, tasdevice_acpi_match); static struct i2c_driver tasdevice_i2c_driver = { .driver = { .name = "tas2781-codec", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tasdevice_of_match), #ifdef CONFIG_ACPI .acpi_match_table = ACPI_PTR(tasdevice_acpi_match), From 221acc16aee16eb246bad32a6b9014021218b7cd Mon Sep 17 00:00:00 2001 From: Maxim Kochetkov Date: Thu, 22 Jun 2023 23:00:29 +0300 Subject: [PATCH 060/334] ASoC: dwc: Add TDM mode support Depending on hardware implementaion of DWC I2S controller may support TDM mode if enabled in SoC at design time. Unfortunately there is no way to detect TDM capability for DWC by reading registers. Anyway, if such capability enabled, TDM mode can be enabled and configured by dai-tdm-slot-* DT options. Signed-off-by: Maxim Kochetkov Link: https://lore.kernel.org/r/20230622200031.120168-1-fido_max@inbox.ru Signed-off-by: Mark Brown --- sound/soc/dwc/dwc-i2s.c | 65 +++++++++++++++++++++++++++++++++++++++-- sound/soc/dwc/dwc-pcm.c | 8 ++--- sound/soc/dwc/local.h | 24 +++++++++++++++ 3 files changed, 90 insertions(+), 7 deletions(-) diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index 97d652f0e84d..1f1ee14b04e6 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -183,7 +183,15 @@ static void i2s_start(struct dw_i2s_dev *dev, { struct i2s_clk_config_data *config = &dev->config; - i2s_write_reg(dev->i2s_base, IER, 1); + u32 reg = IER_IEN; + + if (dev->tdm_slots) { + reg |= (dev->tdm_slots - 1) << IER_TDM_SLOTS_SHIFT; + reg |= IER_INTF_TYPE; + reg |= dev->frame_offset << IER_FRAME_OFF_SHIFT; + } + + i2s_write_reg(dev->i2s_base, IER, reg); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) i2s_write_reg(dev->i2s_base, ITER, 1); @@ -233,13 +241,15 @@ static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) dev->xfer_resolution); i2s_write_reg(dev->i2s_base, TFCR(ch_reg), dev->fifo_th - 1); - i2s_write_reg(dev->i2s_base, TER(ch_reg), 1); + i2s_write_reg(dev->i2s_base, TER(ch_reg), TER_TXCHEN | + dev->tdm_mask << TER_TXSLOT_SHIFT); } else { i2s_write_reg(dev->i2s_base, RCR(ch_reg), dev->xfer_resolution); i2s_write_reg(dev->i2s_base, RFCR(ch_reg), dev->fifo_th - 1); - i2s_write_reg(dev->i2s_base, RER(ch_reg), 1); + i2s_write_reg(dev->i2s_base, RER(ch_reg), RER_RXCHEN | + dev->tdm_mask << RER_RXSLOT_SHIFT); } } @@ -276,6 +286,9 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + if (dev->tdm_slots) + config->data_width = 32; + config->chan_nr = params_channels(params); switch (config->chan_nr) { @@ -384,14 +397,58 @@ static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) ret = -EINVAL; break; } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_DSP_A: + dev->frame_offset = 1; + break; + case SND_SOC_DAIFMT_DSP_B: + dev->frame_offset = 0; + break; + default: + dev_err(dev->dev, "DAI format unsupported"); + return -EINVAL; + } + return ret; } +static int dw_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); + + if (slot_width != 32) + return -EINVAL; + + if (slots < 0 || slots > 16) + return -EINVAL; + + if (rx_mask != tx_mask) + return -EINVAL; + + if (!rx_mask) + return -EINVAL; + + dev->tdm_slots = slots; + dev->tdm_mask = rx_mask; + + dev->l_reg = RSLOT_TSLOT(ffs(rx_mask) - 1); + dev->r_reg = RSLOT_TSLOT(fls(rx_mask) - 1); + + return 0; +} + static const struct snd_soc_dai_ops dw_i2s_dai_ops = { .hw_params = dw_i2s_hw_params, .prepare = dw_i2s_prepare, .trigger = dw_i2s_trigger, .set_fmt = dw_i2s_set_fmt, + .set_tdm_slot = dw_i2s_set_tdm_slot, }; #ifdef CONFIG_PM @@ -726,6 +783,8 @@ static int dw_i2s_probe(struct platform_device *pdev) if (irq >= 0) { ret = dw_pcm_register(pdev); dev->use_pio = true; + dev->l_reg = LRBR_LTHR(0); + dev->r_reg = RRBR_RTHR(0); } else { ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); diff --git a/sound/soc/dwc/dwc-pcm.c b/sound/soc/dwc/dwc-pcm.c index 9f25631d43d3..f99262b89008 100644 --- a/sound/soc/dwc/dwc-pcm.c +++ b/sound/soc/dwc/dwc-pcm.c @@ -31,8 +31,8 @@ static unsigned int dw_pcm_tx_##sample_bits(struct dw_i2s_dev *dev, \ int i; \ \ for (i = 0; i < dev->fifo_th; i++) { \ - iowrite32(p[tx_ptr][0], dev->i2s_base + LRBR_LTHR(0)); \ - iowrite32(p[tx_ptr][1], dev->i2s_base + RRBR_RTHR(0)); \ + iowrite32(p[tx_ptr][0], dev->i2s_base + dev->l_reg); \ + iowrite32(p[tx_ptr][1], dev->i2s_base + dev->r_reg); \ period_pos++; \ if (++tx_ptr >= runtime->buffer_size) \ tx_ptr = 0; \ @@ -51,8 +51,8 @@ static unsigned int dw_pcm_rx_##sample_bits(struct dw_i2s_dev *dev, \ int i; \ \ for (i = 0; i < dev->fifo_th; i++) { \ - p[rx_ptr][0] = ioread32(dev->i2s_base + LRBR_LTHR(0)); \ - p[rx_ptr][1] = ioread32(dev->i2s_base + RRBR_RTHR(0)); \ + p[rx_ptr][0] = ioread32(dev->i2s_base + dev->l_reg); \ + p[rx_ptr][1] = ioread32(dev->i2s_base + dev->r_reg); \ period_pos++; \ if (++rx_ptr >= runtime->buffer_size) \ rx_ptr = 0; \ diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h index ba4e397099be..4ce96bac2f39 100644 --- a/sound/soc/dwc/local.h +++ b/sound/soc/dwc/local.h @@ -25,6 +25,13 @@ #define RXFFR 0x014 #define TXFFR 0x018 +/* Enable register fields */ +#define IER_TDM_SLOTS_SHIFT 8 +#define IER_FRAME_OFF_SHIFT 5 +#define IER_FRAME_OFF BIT(5) +#define IER_INTF_TYPE BIT(1) +#define IER_IEN BIT(0) + /* Interrupt status register fields */ #define ISR_TXFO BIT(5) #define ISR_TXFE BIT(4) @@ -46,6 +53,15 @@ #define TFCR(x) (0x40 * x + 0x04C) #define RFF(x) (0x40 * x + 0x050) #define TFF(x) (0x40 * x + 0x054) +#define RSLOT_TSLOT(x) (0x4 * (x) + 0x224) + +/* Receive enable register fields */ +#define RER_RXSLOT_SHIFT 8 +#define RER_RXCHEN BIT(0) + +/* Transmit enable register fields */ +#define TER_TXSLOT_SHIFT 8 +#define TER_TXCHEN BIT(0) /* I2SCOMPRegisters */ #define I2S_COMP_PARAM_2 0x01F0 @@ -105,6 +121,8 @@ struct dw_i2s_dev { u32 ccr; u32 xfer_resolution; u32 fifo_th; + u32 l_reg; + u32 r_reg; /* data related to DMA transfers b/w i2s and DMAC */ union dw_i2s_snd_dma_data play_dma_data; @@ -114,6 +132,12 @@ struct dw_i2s_dev { /* data related to PIO transfers */ bool use_pio; + + /* data related to TDM mode */ + u32 tdm_slots; + u32 tdm_mask; + u32 frame_offset; + struct snd_pcm_substream __rcu *tx_substream; struct snd_pcm_substream __rcu *rx_substream; unsigned int (*tx_fn)(struct dw_i2s_dev *dev, From e125891c2ed6f6d3f59375caf04d76802c86efae Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Tue, 27 Jun 2023 18:24:21 +0200 Subject: [PATCH 061/334] ASoC: Convert pm8916-wcd-analog-codec to YAML Convert the PM8916 analog WCD codec bindings to YAML. Signed-off-by: Konrad Dybcio Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230627-topic-more_bindings-v1-5-6b4b6cd081e5@linaro.org Signed-off-by: Mark Brown --- .../sound/qcom,msm8916-wcd-analog.txt | 101 ----------- .../sound/qcom,pm8916-wcd-analog-codec.yaml | 160 ++++++++++++++++++ 2 files changed, 160 insertions(+), 101 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt create mode 100644 Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt deleted file mode 100644 index e7d17dda55db..000000000000 --- a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt +++ /dev/null @@ -1,101 +0,0 @@ -msm8916 analog audio CODEC - -Bindings for codec Analog IP which is integrated in pmic pm8916, - -## Bindings for codec core on pmic: - -Required properties - - compatible = "qcom,pm8916-wcd-analog-codec"; - - reg: represents the slave base address provided to the peripheral. - - interrupts: List of interrupts in given SPMI peripheral. - - interrupt-names: Names specified to above list of interrupts in same - order. List of supported interrupt names are: - "cdc_spk_cnp_int" - Speaker click and pop interrupt. - "cdc_spk_clip_int" - Speaker clip interrupt. - "cdc_spk_ocp_int" - Speaker over current protect interrupt. - "mbhc_ins_rem_det1" - jack insert removal detect interrupt 1. - "mbhc_but_rel_det" - button release interrupt. - "mbhc_but_press_det" - button press event - "mbhc_ins_rem_det" - jack insert removal detect interrupt. - "mbhc_switch_int" - multi button headset interrupt. - "cdc_ear_ocp_int" - Earphone over current protect interrupt. - "cdc_hphr_ocp_int" - Headphone R over current protect interrupt. - "cdc_hphl_ocp_det" - Headphone L over current protect interrupt. - "cdc_ear_cnp_int" - earphone cnp interrupt. - "cdc_hphr_cnp_int" - hphr click and pop interrupt. - "cdc_hphl_cnp_int" - hphl click and pop interrupt. - - - clocks: Handle to mclk. - - clock-names: should be "mclk" - - vdd-cdc-io-supply: phandle to VDD_CDC_IO regulator DT node. - - vdd-cdc-tx-rx-cx-supply: phandle to VDD_CDC_TX/RX/CX regulator DT node. - - vdd-micbias-supply: phandle of VDD_MICBIAS supply's regulator DT node. - -Optional Properties: - - qcom,mbhc-vthreshold-low: Array of 5 threshold voltages in mV for 5 buttons - detection on headset when the mbhc is powered up - by internal current source, this is a low power. - - qcom,mbhc-vthreshold-high: Array of 5 thresold voltages in mV for 5 buttons - detection on headset when mbhc is powered up - from micbias. -- qcom,micbias-lvl: Voltage (mV) for Mic Bias -- qcom,hphl-jack-type-normally-open: boolean, present if hphl pin on jack is a - NO (Normally Open). If not specified, then - its assumed that hphl pin on jack is NC - (Normally Closed). -- qcom,gnd-jack-type-normally-open: boolean, present if gnd pin on jack is - NO (Normally Open). If not specified, then - its assumed that gnd pin on jack is NC - (Normally Closed). -- qcom,micbias1-ext-cap: boolean, present if micbias1 has external capacitor - connected. -- qcom,micbias2-ext-cap: boolean, present if micbias2 has external capacitor - connected. - -Example: - -spmi_bus { - ... - audio-codec@f000{ - compatible = "qcom,pm8916-wcd-analog-codec"; - reg = <0xf000 0x200>; - reg-names = "pmic-codec-core"; - clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>; - clock-names = "mclk"; - qcom,mbhc-vthreshold-low = <75 150 237 450 500>; - qcom,mbhc-vthreshold-high = <75 150 237 450 500>; - interrupt-parent = <&spmi_bus>; - interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>, - <0x1 0xf0 0x1 IRQ_TYPE_NONE>, - <0x1 0xf0 0x2 IRQ_TYPE_NONE>, - <0x1 0xf0 0x3 IRQ_TYPE_NONE>, - <0x1 0xf0 0x4 IRQ_TYPE_NONE>, - <0x1 0xf0 0x5 IRQ_TYPE_NONE>, - <0x1 0xf0 0x6 IRQ_TYPE_NONE>, - <0x1 0xf0 0x7 IRQ_TYPE_NONE>, - <0x1 0xf1 0x0 IRQ_TYPE_NONE>, - <0x1 0xf1 0x1 IRQ_TYPE_NONE>, - <0x1 0xf1 0x2 IRQ_TYPE_NONE>, - <0x1 0xf1 0x3 IRQ_TYPE_NONE>, - <0x1 0xf1 0x4 IRQ_TYPE_NONE>, - <0x1 0xf1 0x5 IRQ_TYPE_NONE>; - interrupt-names = "cdc_spk_cnp_int", - "cdc_spk_clip_int", - "cdc_spk_ocp_int", - "mbhc_ins_rem_det1", - "mbhc_but_rel_det", - "mbhc_but_press_det", - "mbhc_ins_rem_det", - "mbhc_switch_int", - "cdc_ear_ocp_int", - "cdc_hphr_ocp_int", - "cdc_hphl_ocp_det", - "cdc_ear_cnp_int", - "cdc_hphr_cnp_int", - "cdc_hphl_cnp_int"; - vdd-cdc-io-supply = <&pm8916_l5>; - vdd-cdc-tx-rx-cx-supply = <&pm8916_l5>; - vdd-micbias-supply = <&pm8916_l13>; - #sound-dai-cells = <1>; - }; -}; diff --git a/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml new file mode 100644 index 000000000000..c385028c4296 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml @@ -0,0 +1,160 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/qcom,pm8916-wcd-analog-codec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm PM8916 WCD Analog Audio Codec + +maintainers: + - Konrad Dybcio + +description: + The analog WCD audio codec found on Qualcomm PM8916 PMIC. + +properties: + compatible: + const: qcom,pm8916-wcd-analog-codec + + reg: + maxItems: 1 + + reg-names: + items: + - const: pmic-codec-core + + clocks: + maxItems: 1 + + clock-names: + items: + - const: mclk + + interrupts: + maxItems: 14 + + interrupt-names: + items: + - const: cdc_spk_cnp_int + - const: cdc_spk_clip_int + - const: cdc_spk_ocp_int + - const: mbhc_ins_rem_det1 + - const: mbhc_but_rel_det + - const: mbhc_but_press_det + - const: mbhc_ins_rem_det + - const: mbhc_switch_int + - const: cdc_ear_ocp_int + - const: cdc_hphr_ocp_int + - const: cdc_hphl_ocp_det + - const: cdc_ear_cnp_int + - const: cdc_hphr_cnp_int + - const: cdc_hphl_cnp_int + + vdd-cdc-io-supply: + description: 1.8V buck supply + + vdd-cdc-tx-rx-cx-supply: + description: 1.8V SIDO buck supply + + vdd-micbias-supply: + description: micbias supply + + qcom,mbhc-vthreshold-low: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: + Array of 5 threshold voltages in mV for 5-button detection on + headset when MBHC is powered by an internal current source. + minItems: 5 + maxItems: 5 + + qcom,mbhc-vthreshold-high: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: + Array of 5 threshold voltages in mV for 5-button detection on + headset when MBHC is powered from micbias. + minItems: 5 + maxItems: 5 + + qcom,micbias-lvl: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Voltage (mV) for Mic Bias + + qcom,hphl-jack-type-normally-open: + type: boolean + description: + True if the HPHL pin on the jack is NO (Normally Open), false if it's + NC (Normally Closed). + + qcom,gnd-jack-type-normally-open: + type: boolean + description: + True if the GND pin on the jack is NO (Normally Open), false if it's + NC (Normally Closed). + + qcom,micbias1-ext-cap: + type: boolean + description: + True if micbias1 has an external capacitor. + + qcom,micbias2-ext-cap: + type: boolean + description: + True if micbias2 has an external capacitor. + + "#sound-dai-cells": + const: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + #include + + audio-codec@f000{ + compatible = "qcom,pm8916-wcd-analog-codec"; + reg = <0xf000 0x200>; + reg-names = "pmic-codec-core"; + clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>; + clock-names = "mclk"; + qcom,mbhc-vthreshold-low = <75 150 237 450 500>; + qcom,mbhc-vthreshold-high = <75 150 237 450 500>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>, + <0x1 0xf0 0x1 IRQ_TYPE_NONE>, + <0x1 0xf0 0x2 IRQ_TYPE_NONE>, + <0x1 0xf0 0x3 IRQ_TYPE_NONE>, + <0x1 0xf0 0x4 IRQ_TYPE_NONE>, + <0x1 0xf0 0x5 IRQ_TYPE_NONE>, + <0x1 0xf0 0x6 IRQ_TYPE_NONE>, + <0x1 0xf0 0x7 IRQ_TYPE_NONE>, + <0x1 0xf1 0x0 IRQ_TYPE_NONE>, + <0x1 0xf1 0x1 IRQ_TYPE_NONE>, + <0x1 0xf1 0x2 IRQ_TYPE_NONE>, + <0x1 0xf1 0x3 IRQ_TYPE_NONE>, + <0x1 0xf1 0x4 IRQ_TYPE_NONE>, + <0x1 0xf1 0x5 IRQ_TYPE_NONE>; + interrupt-names = "cdc_spk_cnp_int", + "cdc_spk_clip_int", + "cdc_spk_ocp_int", + "mbhc_ins_rem_det1", + "mbhc_but_rel_det", + "mbhc_but_press_det", + "mbhc_ins_rem_det", + "mbhc_switch_int", + "cdc_ear_ocp_int", + "cdc_hphr_ocp_int", + "cdc_hphl_ocp_det", + "cdc_ear_cnp_int", + "cdc_hphr_cnp_int", + "cdc_hphl_cnp_int"; + vdd-cdc-io-supply = <&pm8916_l5>; + vdd-cdc-tx-rx-cx-supply = <&pm8916_l5>; + vdd-micbias-supply = <&pm8916_l13>; + #sound-dai-cells = <1>; + }; From c70064b96f509daa78f57992aeabcf274fb2fed4 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 30 Jun 2023 21:48:36 -0700 Subject: [PATCH 062/334] ASoC: stac9766: fix build errors with REGMAP_AC97 Select REGMAP_AC97 to fix these build errors: ERROR: modpost: "regmap_ac97_default_volatile" [sound/soc/codecs/snd-soc-stac9766.ko] undefined! ERROR: modpost: "__regmap_init_ac97" [sound/soc/codecs/snd-soc-stac9766.ko] undefined! Fixes: 6bbf787bb70c ("ASoC: stac9766: Convert to regmap") Signed-off-by: Randy Dunlap Cc: Lars-Peter Clausen Cc: Mark Brown Cc: Liam Girdwood Cc: alsa-devel@alsa-project.org Link: https://lore.kernel.org/r/20230701044836.18789-1-rdunlap@infradead.org Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c2de4ee72183..947473d2da7d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1708,6 +1708,7 @@ config SND_SOC_STA529 config SND_SOC_STAC9766 tristate depends on SND_SOC_AC97_BUS + select REGMAP_AC97 config SND_SOC_STI_SAS tristate "codec Audio support for STI SAS codec" From c7a0f10b885164e4804dc144c375076c2e0d39f6 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 5 Jul 2023 12:29:31 +0800 Subject: [PATCH 063/334] ASoC: rt5645: add the system level suspend-resume callback This patch handles the regmap settings and re-detects the jack when the system level suspend/resume. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20230705042931.24950-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index b0953e9bcaf9..5be5ec0260e9 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -4199,11 +4199,44 @@ static void rt5645_i2c_shutdown(struct i2c_client *i2c) regmap_write(rt5645->regmap, RT5645_RESET, 0); } +static int __maybe_unused rt5645_sys_suspend(struct device *dev) +{ + struct rt5645_priv *rt5645 = dev_get_drvdata(dev); + + del_timer_sync(&rt5645->btn_check_timer); + cancel_delayed_work_sync(&rt5645->jack_detect_work); + cancel_delayed_work_sync(&rt5645->rcclock_work); + + regcache_cache_only(rt5645->regmap, true); + regcache_mark_dirty(rt5645->regmap); + return 0; +} + +static int __maybe_unused rt5645_sys_resume(struct device *dev) +{ + struct rt5645_priv *rt5645 = dev_get_drvdata(dev); + + regcache_cache_only(rt5645->regmap, false); + regcache_sync(rt5645->regmap); + + if (rt5645->hp_jack) { + rt5645->jack_type = 0; + queue_delayed_work(system_power_efficient_wq, + &rt5645->jack_detect_work, msecs_to_jiffies(0)); + } + return 0; +} + +static const struct dev_pm_ops rt5645_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt5645_sys_suspend, rt5645_sys_resume) +}; + static struct i2c_driver rt5645_i2c_driver = { .driver = { .name = "rt5645", .of_match_table = of_match_ptr(rt5645_of_match), .acpi_match_table = ACPI_PTR(rt5645_acpi_match), + .pm = &rt5645_pm, }, .probe = rt5645_i2c_probe, .remove = rt5645_i2c_remove, From 0825d54a3081151201bbfe05f4d408613ef3ef1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= Date: Tue, 20 Jun 2023 18:08:25 -0400 Subject: [PATCH 064/334] kselftest/alsa: pcm-test: Move stream duration and margin to variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The duration to stream for and time margin to consider the stream failed are currently hardcoded values. Move them to variables so they can be reused and more easily changed. Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230620220839.2215057-2-nfraprado@collabora.com Signed-off-by: Takashi Iwai --- tools/testing/selftests/alsa/pcm-test.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/alsa/pcm-test.c b/tools/testing/selftests/alsa/pcm-test.c index b7eef32addb4..9384aebae99b 100644 --- a/tools/testing/selftests/alsa/pcm-test.c +++ b/tools/testing/selftests/alsa/pcm-test.c @@ -258,6 +258,8 @@ static void test_pcm_time(struct pcm_data *data, enum test_class class, const char *test_name, snd_config_t *pcm_cfg) { char name[64], key[128], msg[256]; + const int duration_s = 4, margin_ms = 100; + const int duration_ms = duration_s * 1000; const char *cs; int i, err; snd_pcm_t *handle = NULL; @@ -442,7 +444,7 @@ static void test_pcm_time(struct pcm_data *data, enum test_class class, skip = false; timestamp_now(&tstamp); - for (i = 0; i < 4; i++) { + for (i = 0; i < duration_s; i++) { if (data->stream == SND_PCM_STREAM_PLAYBACK) { frames = snd_pcm_writei(handle, samples, rate); if (frames < 0) { @@ -472,8 +474,8 @@ static void test_pcm_time(struct pcm_data *data, enum test_class class, snd_pcm_drain(handle); ms = timestamp_diff_ms(&tstamp); - if (ms < 3900 || ms > 4100) { - snprintf(msg, sizeof(msg), "time mismatch: expected 4000ms got %lld", ms); + if (ms < duration_ms - margin_ms || ms > duration_ms + margin_ms) { + snprintf(msg, sizeof(msg), "time mismatch: expected %dms got %lld", duration_ms, ms); goto __close; } From 7d43f51e4046c49230dea0d4f991c4cd1759327f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= Date: Tue, 20 Jun 2023 18:08:26 -0400 Subject: [PATCH 065/334] kselftest/alsa: pcm-test: Decrease stream duration from 4 to 2 seconds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently test_pcm_time() streams audio on each PCM with each configuration for 4 seconds. This time can add up, and with the current 45 second kselftest timeout, some machines like mt8192-asurada-spherion can't even run to completion. Lower the duration to 2 seconds to cut the test duration in half, without reducing the test coverage. Signed-off-by: Nícolas F. R. A. Prado Link: https://lore.kernel.org/r/20230620220839.2215057-3-nfraprado@collabora.com Signed-off-by: Takashi Iwai --- tools/testing/selftests/alsa/pcm-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/alsa/pcm-test.c b/tools/testing/selftests/alsa/pcm-test.c index 9384aebae99b..2f5e3c462194 100644 --- a/tools/testing/selftests/alsa/pcm-test.c +++ b/tools/testing/selftests/alsa/pcm-test.c @@ -258,7 +258,7 @@ static void test_pcm_time(struct pcm_data *data, enum test_class class, const char *test_name, snd_config_t *pcm_cfg) { char name[64], key[128], msg[256]; - const int duration_s = 4, margin_ms = 100; + const int duration_s = 2, margin_ms = 100; const int duration_ms = duration_s * 1000; const char *cs; int i, err; From fbb64eedf5a3a98071ee75808cfc1367d1e75783 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 10 Jul 2023 08:59:55 +0200 Subject: [PATCH 066/334] ALSA: emu10k1: make E-MU dock monitoring interrupt-driven ... instead of using a one-second polling timer. Signed-off-by: Oswald Buddenhagen Link: https://lore.kernel.org/r/20230710065956.1246364-1-oswald.buddenhagen@gmx.de Signed-off-by: Takashi Iwai --- include/sound/emu10k1.h | 4 +-- sound/pci/emu10k1/emu10k1.c | 8 +---- sound/pci/emu10k1/emu10k1_main.c | 51 ++++++++++++++++++-------------- sound/pci/emu10k1/io.c | 2 ++ sound/pci/emu10k1/irq.c | 7 +++++ 5 files changed, 40 insertions(+), 32 deletions(-) diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 386a5f3be3e0..43c097952c3c 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1678,8 +1678,7 @@ struct snd_emu1010 { unsigned int clock_fallback; unsigned int optical_in; /* 0:SPDIF, 1:ADAT */ unsigned int optical_out; /* 0:SPDIF, 1:ADAT */ - struct delayed_work firmware_work; - u32 last_reg; + struct work_struct firmware_work; }; struct snd_emu10k1 { @@ -1761,6 +1760,7 @@ struct snd_emu10k1 { void (*capture_efx_interrupt)(struct snd_emu10k1 *emu, unsigned int status); void (*spdif_interrupt)(struct snd_emu10k1 *emu, unsigned int status); void (*dsp_interrupt)(struct snd_emu10k1 *emu); + void (*gpio_interrupt)(struct snd_emu10k1 *emu); void (*p16v_interrupt)(struct snd_emu10k1 *emu); struct snd_pcm_substream *pcm_capture_substream; diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 23adace1b969..1a13c086e86c 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -176,9 +176,6 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, if (err < 0) return err; - if (emu->card_capabilities->emu_model) - schedule_delayed_work(&emu->emu1010.firmware_work, 0); - pci_set_drvdata(pci, card); dev++; return 0; @@ -194,7 +191,7 @@ static int snd_emu10k1_suspend(struct device *dev) emu->suspend = 1; - cancel_delayed_work_sync(&emu->emu1010.firmware_work); + cancel_work_sync(&emu->emu1010.firmware_work); snd_ac97_suspend(emu->ac97); @@ -224,9 +221,6 @@ static int snd_emu10k1_resume(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D0); - if (emu->card_capabilities->emu_model) - schedule_delayed_work(&emu->emu1010.firmware_work, 0); - return 0; } diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 58ed72de6403..661164dbf547 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -391,7 +391,10 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) } #endif - snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE); + if (emu->card_capabilities->emu_model) + snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE | INTE_A_GPIOENABLE); + else + snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE); } int snd_emu10k1_done(struct snd_emu10k1 *emu) @@ -745,14 +748,13 @@ static void emu1010_firmware_work(struct work_struct *work) int err; emu = container_of(work, struct snd_emu10k1, - emu1010.firmware_work.work); + emu1010.firmware_work); if (emu->card->shutdown) return; #ifdef CONFIG_PM_SLEEP if (emu->suspend) return; #endif - snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); /* IRQ Status */ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); /* OPTIONS: Which cards are attached to the EMU */ if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) { /* Audio Dock attached */ @@ -763,13 +765,8 @@ static void emu1010_firmware_work(struct work_struct *work) EMU_HANA_FPGA_CONFIG_AUDIODOCK); err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw); if (err < 0) - goto next; - + return; snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0); - snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); - dev_info(emu->card->dev, - "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n", tmp); - /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp); dev_info(emu->card->dev, "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp); @@ -778,7 +775,7 @@ static void emu1010_firmware_work(struct work_struct *work) dev_info(emu->card->dev, "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n", tmp); - goto next; + return; } dev_info(emu->card->dev, "emu1010: Audio Dock Firmware loaded\n"); @@ -790,18 +787,22 @@ static void emu1010_firmware_work(struct work_struct *work) msleep(10); /* Unmute all. Default is muted after a firmware load */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); - } else if (!reg && emu->emu1010.last_reg) { + } +} + +static void emu1010_interrupt(struct snd_emu10k1 *emu) +{ + u32 sts; + + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &sts); + if (sts & EMU_HANA_IRQ_DOCK_LOST) { /* Audio Dock removed */ dev_info(emu->card->dev, "emu1010: Audio Dock detached\n"); /* The hardware auto-mutes all, so we unmute again */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); + } else if (sts & EMU_HANA_IRQ_DOCK) { + schedule_work(&emu->emu1010.firmware_work); } - - next: - emu->emu1010.last_reg = reg; - if (!emu->card->shutdown) - schedule_delayed_work(&emu->emu1010.firmware_work, - msecs_to_jiffies(1000)); } /* @@ -870,6 +871,8 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg); + if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) + schedule_work(&emu->emu1010.firmware_work); if (emu->card_capabilities->no_adat) { emu->emu1010.optical_in = 0; /* IN_SPDIF */ emu->emu1010.optical_out = 0; /* OUT_SPDIF */ @@ -895,10 +898,12 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) /* MIDI routing */ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, EMU_HANA_MIDI_INA_FROM_HAMOA | EMU_HANA_MIDI_INB_FROM_DOCK2); snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, EMU_HANA_MIDI_OUT_DOCK2 | EMU_HANA_MIDI_OUT_SYNC2); - /* IRQ Enable: All on */ - /* snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x0f); */ - /* IRQ Enable: All off */ - snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00); + + emu->gpio_interrupt = emu1010_interrupt; + // Note: The Audigy INTE is set later + snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, + EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ®); // Clear pending IRQs emu->emu1010.clock_source = 1; /* 48000 */ emu->emu1010.clock_fallback = 1; /* 48000 */ @@ -938,7 +943,7 @@ static void snd_emu10k1_free(struct snd_card *card) /* Disable 48Volt power to Audio Dock */ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0); } - cancel_delayed_work_sync(&emu->emu1010.firmware_work); + cancel_work_sync(&emu->emu1010.firmware_work); release_firmware(emu->firmware); release_firmware(emu->dock_fw); snd_util_memhdr_free(emu->memhdr); @@ -1517,7 +1522,7 @@ int snd_emu10k1_create(struct snd_card *card, emu->irq = -1; emu->synth = NULL; emu->get_synth_voice = NULL; - INIT_DELAYED_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work); + INIT_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work); /* read revision & serial */ emu->revision = pci->revision; pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial); diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index a0d66ce3ee83..c695cb863e5e 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -302,6 +302,8 @@ static void snd_emu1010_fpga_read_locked(struct snd_emu10k1 *emu, u32 reg, u32 * { // The higest input pin is used as the designated interrupt trigger, // so it needs to be masked out. + // But note that any other input pin change will also cause an IRQ, + // so using this function often causes an IRQ as a side effect. u32 mask = emu->card_capabilities->ca0108_chip ? 0x1f : 0x7f; if (snd_BUG_ON(reg > 0x3f)) return; diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c index a813ef8c2f8d..8573248dd799 100644 --- a/sound/pci/emu10k1/irq.c +++ b/sound/pci/emu10k1/irq.c @@ -149,6 +149,13 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) outl(0, emu->port + INTE2); status &= ~IPR_P16V; } + if (status & IPR_A_GPIO) { + if (emu->gpio_interrupt) + emu->gpio_interrupt(emu); + else + snd_emu10k1_intr_disable(emu, INTE_A_GPIOENABLE); + status &= ~IPR_A_GPIO; + } if (status) { dev_err(emu->card->dev, From 6657fcc91db9b01fcbc4f8de0659e10cabd7ce2f Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Thu, 13 Jul 2023 03:14:23 +0800 Subject: [PATCH 067/334] ASoC: Intel: sof_rt5682: add jsl_rt5650 board config This configuration supports JSL boards which implement ALC5650 dual I2S interface codec. Two DAI links are added: AIF1 (on codec side) for headphone and AIF2 for speakers. Signed-off-by: Brent Lu Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230712191423.443765-1-brent.lu@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 5 +- sound/soc/intel/boards/sof_rt5682.c | 80 ++++++++++++++++++- .../intel/common/soc-acpi-intel-jsl-match.c | 12 +++ 3 files changed, 93 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index f472f603ab75..1fe830af2b84 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -475,7 +475,7 @@ endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC if SND_SOC_SOF_HDA_LINK || SND_SOC_SOF_BAYTRAIL config SND_SOC_INTEL_SOF_RT5682_MACH - tristate "SOF with rt5682 codec in I2S Mode" + tristate "SOF with rt5650/rt5682 codec in I2S Mode" depends on I2C && ACPI depends on ((SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC) &&\ (MFD_INTEL_LPSS || COMPILE_TEST)) ||\ @@ -485,6 +485,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH select SND_SOC_RT1011 select SND_SOC_RT1015 select SND_SOC_RT1015P + select SND_SOC_RT5645 select SND_SOC_RT5682_I2C select SND_SOC_RT5682S select SND_SOC_DMIC @@ -494,7 +495,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH select SND_SOC_INTEL_SOF_REALTEK_COMMON help This adds support for ASoC machine driver for SOF platforms - with rt5682 codec. + with rt5650 or rt5682 codec. Say Y if you have such a device. If unsure select "N". diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 7c034d671cf3..b4f07bdcf8b4 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -22,6 +22,7 @@ #include #include "../../codecs/rt5682.h" #include "../../codecs/rt5682s.h" +#include "../../codecs/rt5645.h" #include "../../codecs/hdac_hdmi.h" #include "../common/soc-intel-quirks.h" #include "hda_dsp_common.h" @@ -60,6 +61,7 @@ #define SOF_MAX98390_SPEAKER_AMP_PRESENT BIT(24) #define SOF_MAX98390_TWEETER_SPEAKER_PRESENT BIT(25) #define SOF_RT1019_SPEAKER_AMP_PRESENT BIT(26) +#define SOF_RT5650_HEADPHONE_CODEC_PRESENT BIT(27) /* Default: MCLK on, MCLK 19.2M, SSP0 */ @@ -305,6 +307,7 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; struct snd_soc_jack *jack; + int extra_jack_data; int ret; /* need to enable ASRC function for 24MHz mclk rate */ @@ -315,7 +318,16 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) RT5682S_DA_STEREO1_FILTER | RT5682S_AD_STEREO1_FILTER, RT5682S_CLK_SEL_I2S1_ASRC); - else + else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) { + rt5645_sel_asrc_clk_src(component, + RT5645_DA_STEREO_FILTER | + RT5645_AD_STEREO_FILTER, + RT5645_CLK_SEL_I2S1_ASRC); + rt5645_sel_asrc_clk_src(component, + RT5645_DA_MONO_L_FILTER | + RT5645_DA_MONO_R_FILTER, + RT5645_CLK_SEL_I2S2_ASRC); + } else rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER | RT5682_AD_STEREO1_FILTER, @@ -365,7 +377,12 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - ret = snd_soc_component_set_jack(component, jack, NULL); + + if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) { + extra_jack_data = SND_JACK_MICROPHONE | SND_JACK_BTN_0; + ret = snd_soc_component_set_jack(component, jack, &extra_jack_data); + } else + ret = snd_soc_component_set_jack(component, jack, NULL); if (ret) { dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); @@ -402,6 +419,8 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT) pll_source = RT5682S_PLL_S_MCLK; + else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) + pll_source = RT5645_PLL1_S_MCLK; else pll_source = RT5682_PLL1_S_MCLK; @@ -422,6 +441,8 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, } else { if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT) pll_source = RT5682S_PLL_S_BCLK1; + else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) + pll_source = RT5645_PLL1_S_BCLK1; else pll_source = RT5682_PLL1_S_BCLK1; @@ -431,6 +452,9 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT) { pll_id = RT5682S_PLL2; clk_id = RT5682S_SCLK_S_PLL2; + } else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) { + pll_id = 0; /* not used in codec driver */ + clk_id = RT5645_SCLK_S_PLL1; } else { pll_id = RT5682_PLL1; clk_id = RT5682_SCLK_S_PLL1; @@ -559,11 +583,30 @@ static const struct snd_soc_dapm_route sof_map[] = { { "IN1P", NULL, "Headset Mic" }, }; +static const struct snd_soc_dapm_route rt5650_spk_dapm_routes[] = { + /* speaker */ + { "Left Spk", NULL, "SPOL" }, + { "Right Spk", NULL, "SPOR" }, +}; + static const struct snd_soc_dapm_route dmic_map[] = { /* digital mics */ {"DMic", NULL, "SoC DMIC"}, }; +static int rt5650_spk_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_add_routes(&card->dapm, rt5650_spk_dapm_routes, + ARRAY_SIZE(rt5650_spk_dapm_routes)); + if (ret) + dev_err(rtd->dev, "fail to add dapm routes, ret=%d\n", ret); + + return ret; +} + static int dmic_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; @@ -614,6 +657,17 @@ static struct snd_soc_dai_link_component rt5682s_component[] = { } }; +static struct snd_soc_dai_link_component rt5650_components[] = { + { + .name = "i2c-10EC5650:00", + .dai_name = "rt5645-aif1", + }, + { + .name = "i2c-10EC5650:00", + .dai_name = "rt5645-aif2", + } +}; + static struct snd_soc_dai_link_component dmic_component[] = { { .name = "dmic-codec", @@ -652,6 +706,9 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT) { links[id].codecs = rt5682s_component; links[id].num_codecs = ARRAY_SIZE(rt5682s_component); + } else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) { + links[id].codecs = &rt5650_components[0]; + links[id].num_codecs = 1; } else { links[id].codecs = rt5682_component; links[id].num_codecs = ARRAY_SIZE(rt5682_component); @@ -804,6 +861,11 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].init = max_98390_spk_codec_init; links[id].ops = &max_98390_ops; + } else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) { + links[id].codecs = &rt5650_components[1]; + links[id].num_codecs = 1; + links[id].init = rt5650_spk_init; + links[id].ops = &sof_rt5682_ops; } else { max_98357a_dai_link(&links[id]); } @@ -890,6 +952,12 @@ static int sof_audio_probe(struct platform_device *pdev) /* Detect the headset codec variant */ if (acpi_dev_present("RTL5682", NULL, -1)) sof_rt5682_quirk |= SOF_RT5682S_HEADPHONE_CODEC_PRESENT; + else if (acpi_dev_present("10EC5650", NULL, -1)) { + sof_rt5682_quirk |= SOF_RT5650_HEADPHONE_CODEC_PRESENT; + + sof_audio_card_rt5682.name = devm_kstrdup(&pdev->dev, "rt5650", + GFP_KERNEL); + } if (soc_intel_is_byt() || soc_intel_is_cht()) { is_legacy_cpu = 1; @@ -1178,6 +1246,14 @@ static const struct platform_device_id board_ids[] = { SOF_RT5682_SSP_AMP(0) | SOF_RT5682_NUM_HDMIDEV(3)), }, + { + .name = "jsl_rt5650", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_MCLK_24MHZ | + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(1)), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c index f5c7e1bbded0..f56bd7d656e9 100644 --- a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c @@ -34,6 +34,11 @@ static const struct snd_soc_acpi_codecs mx98360a_spk = { .codecs = {"MX98360A"} }; +static struct snd_soc_acpi_codecs rt5650_spk = { + .num_codecs = 1, + .codecs = {"10EC5650"} +}; + static const struct snd_soc_acpi_codecs rt5682_rt5682s_hp = { .num_codecs = 2, .codecs = {"10EC5682", "RTL5682"}, @@ -98,6 +103,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = { SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, }, + { + .id = "10EC5650", + .drv_name = "jsl_rt5650", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &rt5650_spk, + .sof_tplg_filename = "sof-jsl-rt5650.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_jsl_machines); From deb1200f6eb634a6e4d08ada953b72be1e8adcfa Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 12 Jul 2023 16:57:48 +0200 Subject: [PATCH 068/334] ALSA: emu10k1: fix return value of snd_emu1010_adc_pads_put() It returned zero even if the value had changed. Signed-off-by: Oswald Buddenhagen Link: https://lore.kernel.org/r/20230712145750.125086-1-oswald.buddenhagen@gmx.de Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emumixer.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index f9500cd50a4b..573e1c7c5e50 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -770,18 +770,21 @@ static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value]; unsigned int val, cache; + int change; + val = ucontrol->value.integer.value[0]; cache = emu->emu1010.adc_pads; if (val == 1) cache = cache | mask; else cache = cache & ~mask; - if (cache != emu->emu1010.adc_pads) { + change = (cache != emu->emu1010.adc_pads); + if (change) { snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache ); emu->emu1010.adc_pads = cache; } - return 0; + return change; } static const struct snd_kcontrol_new emu1010_adc_pads_ctl = { From 67192cc0f0263847ab3ccdcfe90989624a0c7fe3 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 12 Jul 2023 16:57:49 +0200 Subject: [PATCH 069/334] ALSA: emu10k1: remove superfluous IRQ enable state saving The mixer, PCM prepare, MIDI, synth driver, and procfs callbacks are all always invoked with IRQs enabled, so there is no point in saving the state. snd_emu1010_load_firmware_entry() is called from emu1010_firmware_work() and snd_emu10k1_emu1010_init(); the latter from snd_emu10k1_create() and snd_emu10k1_resume(), all of which have IRQs enabled. The voice and memory functions are called from mixed contexts, so they keep the state saving. The low-level functions all keep the state saving, because it's not feasible to keep track of what is called where. Signed-off-by: Oswald Buddenhagen Link: https://lore.kernel.org/r/20230712145750.125086-2-oswald.buddenhagen@gmx.de Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1_main.c | 5 ++-- sound/pci/emu10k1/emu10k1_synth.c | 10 +++---- sound/pci/emu10k1/emumixer.c | 45 +++++++++++++------------------ sound/pci/emu10k1/emumpu401.c | 40 ++++++++++++--------------- sound/pci/emu10k1/emupcm.c | 6 ++--- sound/pci/emu10k1/emuproc.c | 10 +++---- 6 files changed, 47 insertions(+), 69 deletions(-) diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 661164dbf547..a11fcba4b9af 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -667,7 +667,6 @@ static int snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu, u16 reg; u8 value; __always_unused u16 write_post; - unsigned long flags; if (!fw_entry) return -EIO; @@ -679,7 +678,7 @@ static int snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu, * GPIO5 -> FPGA DIN * FPGA CONFIG OFF -> FPGA PGMN */ - spin_lock_irqsave(&emu->emu_lock, flags); + spin_lock_irq(&emu->emu_lock); outw(0x00, emu->port + A_GPIO); /* Set PGMN low for 100uS. */ write_post = inw(emu->port + A_GPIO); udelay(100); @@ -702,7 +701,7 @@ static int snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu, /* After programming, set GPIO bit 4 high again. */ outw(0x10, emu->port + A_GPIO); write_post = inw(emu->port + A_GPIO); - spin_unlock_irqrestore(&emu->emu_lock, flags); + spin_unlock_irq(&emu->emu_lock); return 0; } diff --git a/sound/pci/emu10k1/emu10k1_synth.c b/sound/pci/emu10k1/emu10k1_synth.c index 759e66e1105a..68dfcb24b889 100644 --- a/sound/pci/emu10k1/emu10k1_synth.c +++ b/sound/pci/emu10k1/emu10k1_synth.c @@ -22,7 +22,6 @@ static int snd_emu10k1_synth_probe(struct device *_dev) struct snd_emux *emux; struct snd_emu10k1 *hw; struct snd_emu10k1_synth_arg *arg; - unsigned long flags; arg = SNDRV_SEQ_DEVICE_ARGPTR(dev); if (arg == NULL) @@ -56,10 +55,10 @@ static int snd_emu10k1_synth_probe(struct device *_dev) return -ENOMEM; } - spin_lock_irqsave(&hw->voice_lock, flags); + spin_lock_irq(&hw->voice_lock); hw->synth = emux; hw->get_synth_voice = snd_emu10k1_synth_get_voice; - spin_unlock_irqrestore(&hw->voice_lock, flags); + spin_unlock_irq(&hw->voice_lock); dev->driver_data = emux; @@ -71,7 +70,6 @@ static int snd_emu10k1_synth_remove(struct device *_dev) struct snd_seq_device *dev = to_seq_dev(_dev); struct snd_emux *emux; struct snd_emu10k1 *hw; - unsigned long flags; if (dev->driver_data == NULL) return 0; /* not registered actually */ @@ -79,10 +77,10 @@ static int snd_emu10k1_synth_remove(struct device *_dev) emux = dev->driver_data; hw = emux->hw; - spin_lock_irqsave(&hw->voice_lock, flags); + spin_lock_irq(&hw->voice_lock); hw->synth = NULL; hw->get_synth_voice = NULL; - spin_unlock_irqrestore(&hw->voice_lock, flags); + spin_unlock_irq(&hw->voice_lock); snd_emux_free(emux); return 0; diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 573e1c7c5e50..9a94f08f2463 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -1193,7 +1193,6 @@ static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, unsigned int ngain, ogain; u16 gpio; int change = 0; - unsigned long flags; u32 source; /* If the capture source has changed, * update the capture volume from the cached value @@ -1207,13 +1206,13 @@ static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, change = (emu->i2c_capture_source != source_id); if (change) { snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ - spin_lock_irqsave(&emu->emu_lock, flags); + spin_lock_irq(&emu->emu_lock); gpio = inw(emu->port + A_IOCFG); if (source_id==0) outw(gpio | 0x4, emu->port + A_IOCFG); else outw(gpio & ~0x4, emu->port + A_IOCFG); - spin_unlock_irqrestore(&emu->emu_lock, flags); + spin_unlock_irq(&emu->emu_lock); ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ @@ -1357,7 +1356,6 @@ static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol, struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); int change; unsigned int reg, val, tmp; - unsigned long flags; switch(ucontrol->value.enumerated.item[0]) { case 0: @@ -1375,14 +1373,14 @@ static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol, } - spin_lock_irqsave(&emu->reg_lock, flags); + spin_lock_irq(&emu->reg_lock); reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); tmp = reg & ~A_SPDIF_RATE_MASK; tmp |= val; change = (tmp != reg); if (change) snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); - spin_unlock_irqrestore(&emu->reg_lock, flags); + spin_unlock_irq(&emu->reg_lock); return change; } @@ -1499,7 +1497,6 @@ static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol, static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_pcm_mixer *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; @@ -1507,7 +1504,7 @@ static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol, int num_efx = emu->audigy ? 8 : 4; int mask = emu->audigy ? 0x3f : 0x0f; - spin_lock_irqsave(&emu->reg_lock, flags); + spin_lock_irq(&emu->reg_lock); for (voice = 0; voice < 3; voice++) for (idx = 0; idx < num_efx; idx++) { val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask; @@ -1527,7 +1524,7 @@ static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol, &mix->send_routing[0][0]); } } - spin_unlock_irqrestore(&emu->reg_lock, flags); + spin_unlock_irq(&emu->reg_lock); return change; } @@ -1569,14 +1566,13 @@ static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol, static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_pcm_mixer *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; int change = 0, idx, val; int num_efx = emu->audigy ? 8 : 4; - spin_lock_irqsave(&emu->reg_lock, flags); + spin_lock_irq(&emu->reg_lock); for (idx = 0; idx < 3*num_efx; idx++) { val = ucontrol->value.integer.value[idx] & 255; if (mix->send_volume[idx/num_efx][idx%num_efx] != val) { @@ -1595,7 +1591,7 @@ static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol, &mix->send_volume[0][0]); } } - spin_unlock_irqrestore(&emu->reg_lock, flags); + spin_unlock_irq(&emu->reg_lock); return change; } @@ -1635,13 +1631,12 @@ static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol, static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_pcm_mixer *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; int change = 0, idx, val; - spin_lock_irqsave(&emu->reg_lock, flags); + spin_lock_irq(&emu->reg_lock); for (idx = 0; idx < 3; idx++) { unsigned uval = ucontrol->value.integer.value[idx] & 0x1ffff; val = uval * 0x8000U / 0xffffU; @@ -1658,7 +1653,7 @@ static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol, snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]); } } - spin_unlock_irqrestore(&emu->reg_lock, flags); + spin_unlock_irq(&emu->reg_lock); return change; } @@ -1704,7 +1699,6 @@ static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol, static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; @@ -1712,7 +1706,7 @@ static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, int num_efx = emu->audigy ? 8 : 4; int mask = emu->audigy ? 0x3f : 0x0f; - spin_lock_irqsave(&emu->reg_lock, flags); + spin_lock_irq(&emu->reg_lock); for (idx = 0; idx < num_efx; idx++) { val = ucontrol->value.integer.value[idx] & mask; if (mix->send_routing[0][idx] != val) { @@ -1727,7 +1721,7 @@ static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, &mix->send_routing[0][0]); } } - spin_unlock_irqrestore(&emu->reg_lock, flags); + spin_unlock_irq(&emu->reg_lock); return change; } @@ -1769,14 +1763,13 @@ static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol, static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; int change = 0, idx, val; int num_efx = emu->audigy ? 8 : 4; - spin_lock_irqsave(&emu->reg_lock, flags); + spin_lock_irq(&emu->reg_lock); for (idx = 0; idx < num_efx; idx++) { val = ucontrol->value.integer.value[idx] & 255; if (mix->send_volume[0][idx] != val) { @@ -1790,7 +1783,7 @@ static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol, &mix->send_volume[0][0]); } } - spin_unlock_irqrestore(&emu->reg_lock, flags); + spin_unlock_irq(&emu->reg_lock); return change; } @@ -1829,14 +1822,13 @@ static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol, static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; int change = 0, val; unsigned uval; - spin_lock_irqsave(&emu->reg_lock, flags); + spin_lock_irq(&emu->reg_lock); uval = ucontrol->value.integer.value[0] & 0x1ffff; val = uval * 0x8000U / 0xffffU; if (mix->attn[0] != val) { @@ -1848,7 +1840,7 @@ static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol, snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]); } } - spin_unlock_irqrestore(&emu->reg_lock, flags); + spin_unlock_irq(&emu->reg_lock); return change; } @@ -1884,7 +1876,6 @@ static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); unsigned int reg, val, sw; int change = 0; @@ -1892,7 +1883,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, sw = ucontrol->value.integer.value[0]; if (emu->card_capabilities->invert_shared_spdif) sw = !sw; - spin_lock_irqsave(&emu->emu_lock, flags); + spin_lock_irq(&emu->emu_lock); if ( emu->card_capabilities->i2c_adc) { /* Do nothing for Audigy 2 ZS Notebook */ } else if (emu->audigy) { @@ -1913,7 +1904,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, reg |= val; outl(reg | val, emu->port + HCFG); } - spin_unlock_irqrestore(&emu->emu_lock, flags); + spin_unlock_irq(&emu->emu_lock); return change; } diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c index 3ce9b2129ce6..747c34b3d566 100644 --- a/sound/pci/emu10k1/emumpu401.c +++ b/sound/pci/emu10k1/emumpu401.c @@ -104,10 +104,9 @@ static void snd_emu10k1_midi_interrupt2(struct snd_emu10k1 *emu, unsigned int st static int snd_emu10k1_midi_cmd(struct snd_emu10k1 * emu, struct snd_emu10k1_midi *midi, unsigned char cmd, int ack) { - unsigned long flags; int timeout, ok; - spin_lock_irqsave(&midi->input_lock, flags); + spin_lock_irq(&midi->input_lock); mpu401_write_data(emu, midi, 0x00); /* mpu401_clear_rx(emu, midi); */ @@ -126,7 +125,7 @@ static int snd_emu10k1_midi_cmd(struct snd_emu10k1 * emu, struct snd_emu10k1_mid } else { ok = 1; } - spin_unlock_irqrestore(&midi->input_lock, flags); + spin_unlock_irq(&midi->input_lock); if (!ok) { dev_err(emu->card->dev, "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n", @@ -142,22 +141,21 @@ static int snd_emu10k1_midi_input_open(struct snd_rawmidi_substream *substream) { struct snd_emu10k1 *emu; struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; - unsigned long flags; emu = midi->emu; if (snd_BUG_ON(!emu)) return -ENXIO; - spin_lock_irqsave(&midi->open_lock, flags); + spin_lock_irq(&midi->open_lock); midi->midi_mode |= EMU10K1_MIDI_MODE_INPUT; midi->substream_input = substream; if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) { - spin_unlock_irqrestore(&midi->open_lock, flags); + spin_unlock_irq(&midi->open_lock); if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1)) goto error_out; if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1)) goto error_out; } else { - spin_unlock_irqrestore(&midi->open_lock, flags); + spin_unlock_irq(&midi->open_lock); } return 0; @@ -169,22 +167,21 @@ static int snd_emu10k1_midi_output_open(struct snd_rawmidi_substream *substream) { struct snd_emu10k1 *emu; struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; - unsigned long flags; emu = midi->emu; if (snd_BUG_ON(!emu)) return -ENXIO; - spin_lock_irqsave(&midi->open_lock, flags); + spin_lock_irq(&midi->open_lock); midi->midi_mode |= EMU10K1_MIDI_MODE_OUTPUT; midi->substream_output = substream; if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) { - spin_unlock_irqrestore(&midi->open_lock, flags); + spin_unlock_irq(&midi->open_lock); if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1)) goto error_out; if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1)) goto error_out; } else { - spin_unlock_irqrestore(&midi->open_lock, flags); + spin_unlock_irq(&midi->open_lock); } return 0; @@ -196,21 +193,20 @@ static int snd_emu10k1_midi_input_close(struct snd_rawmidi_substream *substream) { struct snd_emu10k1 *emu; struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; - unsigned long flags; int err = 0; emu = midi->emu; if (snd_BUG_ON(!emu)) return -ENXIO; - spin_lock_irqsave(&midi->open_lock, flags); + spin_lock_irq(&midi->open_lock); snd_emu10k1_intr_disable(emu, midi->rx_enable); midi->midi_mode &= ~EMU10K1_MIDI_MODE_INPUT; midi->substream_input = NULL; if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) { - spin_unlock_irqrestore(&midi->open_lock, flags); + spin_unlock_irq(&midi->open_lock); err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0); } else { - spin_unlock_irqrestore(&midi->open_lock, flags); + spin_unlock_irq(&midi->open_lock); } return err; } @@ -219,21 +215,20 @@ static int snd_emu10k1_midi_output_close(struct snd_rawmidi_substream *substream { struct snd_emu10k1 *emu; struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; - unsigned long flags; int err = 0; emu = midi->emu; if (snd_BUG_ON(!emu)) return -ENXIO; - spin_lock_irqsave(&midi->open_lock, flags); + spin_lock_irq(&midi->open_lock); snd_emu10k1_intr_disable(emu, midi->tx_enable); midi->midi_mode &= ~EMU10K1_MIDI_MODE_OUTPUT; midi->substream_output = NULL; if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) { - spin_unlock_irqrestore(&midi->open_lock, flags); + spin_unlock_irq(&midi->open_lock); err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0); } else { - spin_unlock_irqrestore(&midi->open_lock, flags); + spin_unlock_irq(&midi->open_lock); } return err; } @@ -256,7 +251,6 @@ static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substr { struct snd_emu10k1 *emu; struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; - unsigned long flags; emu = midi->emu; if (snd_BUG_ON(!emu)) @@ -267,13 +261,13 @@ static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substr unsigned char byte; /* try to send some amount of bytes here before interrupts */ - spin_lock_irqsave(&midi->output_lock, flags); + spin_lock_irq(&midi->output_lock); while (max > 0) { if (mpu401_output_ready(emu, midi)) { if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT) || snd_rawmidi_transmit(substream, &byte, 1) != 1) { /* no more data */ - spin_unlock_irqrestore(&midi->output_lock, flags); + spin_unlock_irq(&midi->output_lock); return; } mpu401_write_data(emu, midi, byte); @@ -282,7 +276,7 @@ static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substr break; } } - spin_unlock_irqrestore(&midi->output_lock, flags); + spin_unlock_irq(&midi->output_lock); snd_emu10k1_intr_enable(emu, midi->tx_enable); } else { snd_emu10k1_intr_disable(emu, midi->tx_enable); diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 387288d623d7..8b3d1b35d6e7 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -343,9 +343,7 @@ static void snd_emu10k1_pcm_init_voices(struct snd_emu10k1 *emu, unsigned int end_addr, struct snd_emu10k1_pcm_mixer *mix) { - unsigned long flags; - - spin_lock_irqsave(&emu->reg_lock, flags); + spin_lock_irq(&emu->reg_lock); snd_emu10k1_pcm_init_voice(emu, evoice, w_16, stereo, start_addr, end_addr, &mix->send_routing[stereo][0], @@ -355,7 +353,7 @@ static void snd_emu10k1_pcm_init_voices(struct snd_emu10k1 *emu, start_addr, end_addr, &mix->send_routing[2][0], &mix->send_volume[2][0]); - spin_unlock_irqrestore(&emu->reg_lock, flags); + spin_unlock_irq(&emu->reg_lock); } static void snd_emu10k1_pcm_init_extra_voice(struct snd_emu10k1 *emu, diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 7e2cc532471f..5533277e4d47 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -536,15 +536,14 @@ static unsigned int snd_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn) { - unsigned long flags; unsigned int regptr, val; regptr = (reg << 16) | chn; - spin_lock_irqsave(&emu->emu_lock, flags); + spin_lock_irq(&emu->emu_lock); outl(regptr, emu->port + iobase + PTR); val = inl(emu->port + iobase + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); + spin_unlock_irq(&emu->emu_lock); return val; } @@ -555,14 +554,13 @@ static void snd_ptr_write(struct snd_emu10k1 *emu, unsigned int data) { unsigned int regptr; - unsigned long flags; regptr = (reg << 16) | chn; - spin_lock_irqsave(&emu->emu_lock, flags); + spin_lock_irq(&emu->emu_lock); outl(regptr, emu->port + iobase + PTR); outl(data, emu->port + iobase + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); + spin_unlock_irq(&emu->emu_lock); } From 52beea42d825321a7ded656f14f5672b290dbd16 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:50 +0100 Subject: [PATCH 070/334] ASoC: ad1836: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the ad1836 driver to use the more modern data structure. Reviewed-by: Nuno Sa Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-ad-maple-v1-1-7d2f35d42b5f@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/ad1836.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 2c64df96b5ce..949077108bef 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -358,7 +358,7 @@ static const struct regmap_config ad1836_regmap_config = { .max_register = AD1836_ADC_CTRL3, .reg_defaults = ad1836_reg_defaults, .num_reg_defaults = ARRAY_SIZE(ad1836_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int ad1836_spi_probe(struct spi_device *spi) From 625ea9e6d5c4509634b49a8e7436ea3248220e9e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:51 +0100 Subject: [PATCH 071/334] ASoC: ad1980: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the ad1980 driver to use the more modern data structure. Reviewed-by: Nuno Sa Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-ad-maple-v1-2-7d2f35d42b5f@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/ad1980.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 5e777d7fd5d9..3c1ae13c1aae 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -92,7 +92,7 @@ static const struct regmap_config ad1980_regmap_config = { .reg_stride = 2, .val_bits = 16, .max_register = 0x7e, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = regmap_ac97_default_volatile, .readable_reg = ad1980_readable_reg, From b7fea0e30fbdc4c5cba6edbf5e5b8aabd0a5660a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:52 +0100 Subject: [PATCH 072/334] ASoC: adau1372: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the adau1382 driver to use the more modern data structure. Reviewed-by: Nuno Sa Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-ad-maple-v1-3-7d2f35d42b5f@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/adau1372.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/adau1372.c b/sound/soc/codecs/adau1372.c index d9bde7eb043a..98380a7ce64d 100644 --- a/sound/soc/codecs/adau1372.c +++ b/sound/soc/codecs/adau1372.c @@ -1056,7 +1056,7 @@ const struct regmap_config adau1372_regmap_config = { .reg_defaults = adau1372_reg_defaults, .num_reg_defaults = ARRAY_SIZE(adau1372_reg_defaults), .volatile_reg = adau1372_volatile_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_GPL(adau1372_regmap_config); From da27e493ce9394134deecfbecfd46c8836141191 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:53 +0100 Subject: [PATCH 073/334] ASoC: adau1373: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the adau1373 driver to use the more modern data structure. Reviewed-by: Nuno Sa Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-ad-maple-v1-4-7d2f35d42b5f@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/adau1373.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index c5b087b8fffc..b0ab0a69b207 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1451,7 +1451,7 @@ static const struct regmap_config adau1373_regmap_config = { .volatile_reg = adau1373_register_volatile, .max_register = ADAU1373_SOFT_RESET, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = adau1373_reg_defaults, .num_reg_defaults = ARRAY_SIZE(adau1373_reg_defaults), }; From e0e3bb187bfba6ec2a0bd1b7d36fdacb6a8e3010 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:54 +0100 Subject: [PATCH 074/334] ASoC: adau1701: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the adau1701 driver to use the more modern data structure. Reviewed-by: Nuno Sa Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-ad-maple-v1-5-7d2f35d42b5f@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/adau1701.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 8c8de3b3c901..94831aad7ac6 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -778,7 +778,7 @@ static const struct regmap_config adau1701_regmap = { .reg_bits = 16, .val_bits = 32, .max_register = ADAU1701_MAX_REGISTER, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = adau1701_volatile_reg, .reg_write = adau1701_reg_write, .reg_read = adau1701_reg_read, From 97e3b4845d389c8e309e13445bc02ad01fdbda7a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:55 +0100 Subject: [PATCH 075/334] ASoC: adau1761: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the adau1761 driver to use the more modern data structure. Reviewed-by: Nuno Sa Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-ad-maple-v1-6-7d2f35d42b5f@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/adau1761.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index 3ccc7acac205..1f09ea385f8a 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c @@ -1014,7 +1014,7 @@ const struct regmap_config adau1761_regmap_config = { .readable_reg = adau1761_readable_register, .volatile_reg = adau17x1_volatile_register, .precious_reg = adau17x1_precious_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_GPL(adau1761_regmap_config); From 3841ff1bacccc253c48c2c4a2c5e087dfae4b51e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:56 +0100 Subject: [PATCH 076/334] ASoC: adau1781: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the adau1781 driver to use the more modern data structure. Reviewed-by: Nuno Sa Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-ad-maple-v1-7-7d2f35d42b5f@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/adau1781.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c index ff6be24863bf..faad2f9f8dd2 100644 --- a/sound/soc/codecs/adau1781.c +++ b/sound/soc/codecs/adau1781.c @@ -472,7 +472,7 @@ const struct regmap_config adau1781_regmap_config = { .readable_reg = adau1781_readable_register, .volatile_reg = adau17x1_volatile_register, .precious_reg = adau17x1_precious_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_GPL(adau1781_regmap_config); From a0a4cef897b550cf4beaf3fcb1742c3dc895f5f8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:57 +0100 Subject: [PATCH 077/334] ASoC: adau1977: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the adau1977 driver to use the more modern data structure. Reviewed-by: Nuno Sa Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-ad-maple-v1-8-7d2f35d42b5f@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/adau1977.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c index 7a9672f94fc6..ae59efb38f26 100644 --- a/sound/soc/codecs/adau1977.c +++ b/sound/soc/codecs/adau1977.c @@ -991,7 +991,7 @@ const struct regmap_config adau1977_regmap_config = { .max_register = ADAU1977_REG_DC_HPF_CAL, .volatile_reg = adau1977_register_volatile, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = adau1977_reg_defaults, .num_reg_defaults = ARRAY_SIZE(adau1977_reg_defaults), }; From c05c32dd82a602e5b75c3e473e55e7b6325a1967 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:58 +0100 Subject: [PATCH 078/334] ASoC: adau7118: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the adau7118 driver to use the more modern data structure. Reviewed-by: Nuno Sa Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-ad-maple-v1-9-7d2f35d42b5f@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/adau7118-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/adau7118-i2c.c b/sound/soc/codecs/adau7118-i2c.c index 73f181f7757e..b302b28eca7c 100644 --- a/sound/soc/codecs/adau7118-i2c.c +++ b/sound/soc/codecs/adau7118-i2c.c @@ -43,7 +43,7 @@ static const struct regmap_config adau7118_regmap_config = { .val_bits = 8, .reg_defaults = adau7118_reg_defaults, .num_reg_defaults = ARRAY_SIZE(adau7118_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = ADAU7118_REG_RESET, .volatile_reg = adau7118_volatile, }; From 07e835e35b5dc7e1906e2dbd6d72cb9336846ba6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:59 +0100 Subject: [PATCH 079/334] ASoC: adav80x: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the adav80x driver to use the more modern data structure. Reviewed-by: Nuno Sa Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-ad-maple-v1-10-7d2f35d42b5f@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/adav80x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index fcff35f26cec..bb08969c5917 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -870,7 +870,7 @@ const struct regmap_config adav80x_regmap_config = { .max_register = ADAV80X_PLL_OUTE, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = adav80x_reg_defaults, .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults), }; From 6d2a87ddd9c2488732ca422476a9417ca312f75a Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 13 Jul 2023 14:51:06 +0800 Subject: [PATCH 080/334] ASoC: amd: acp: clean up some inconsistent indentings sound/soc/amd/acp/acp-rembrandt.c:283 rmb_pcm_resume() warn: inconsistent indenting Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=5863 Signed-off-by: Yang Li Link: https://lore.kernel.org/r/20230713065106.21564-1-yang.lee@linux.alibaba.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-rembrandt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c index 89314d95ec2b..21e67ed956d1 100644 --- a/sound/soc/amd/acp/acp-rembrandt.c +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -280,8 +280,8 @@ static int __maybe_unused rmb_pcm_resume(struct device *dev) } } } - spin_unlock(&adata->acp_lock); - return 0; + spin_unlock(&adata->acp_lock); + return 0; } static const struct dev_pm_ops rmb_dma_pm_ops = { From df43fba7c75545094639be42a85502634f075a19 Mon Sep 17 00:00:00 2001 From: Min-Hua Chen Date: Thu, 13 Jul 2023 23:17:43 +0800 Subject: [PATCH 081/334] ASoC: q6dsp: q6apm: make g_apm static This patch fixes the following sprse warning: sound/soc/qcom/qdsp6/q6apm.c:30:14: sparse: warning: symbol 'g_apm' was not declared. Should it be static? No functional change intended Signed-off-by: Min-Hua Chen Link: https://lore.kernel.org/r/20230713151744.86072-1-minhuadotchen@gmail.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6apm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c index 5d44d07acd69..2a2a5bd98110 100644 --- a/sound/soc/qcom/qdsp6/q6apm.c +++ b/sound/soc/qcom/qdsp6/q6apm.c @@ -27,7 +27,7 @@ struct apm_graph_mgmt_cmd { #define APM_GRAPH_MGMT_PSIZE(p, n) ALIGN(struct_size(p, sub_graph_id_list, n), 8) -struct q6apm *g_apm; +static struct q6apm *g_apm; int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt, uint32_t rsp_opcode) { From 678a0bbe158076805843f6a58aa09b365fc43871 Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Thu, 13 Jul 2023 11:59:52 +0400 Subject: [PATCH 082/334] ALSA: pcmtest: Add 'open' PCM callback error injection Extend 'pcmtest' virtual driver with 'open' callback error injection functionality, as it already can inject errors into other PCM callbacks. Add module parameter which enables EBUSY error injection in the 'open' PCM callback. Signed-off-by: Ivan Orlov Link: https://lore.kernel.org/r/20230713075953.13692-1-ivan.orlov0322@gmail.com Signed-off-by: Takashi Iwai --- sound/drivers/pcmtest.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/drivers/pcmtest.c b/sound/drivers/pcmtest.c index 291e7fe47893..e74c523e49eb 100644 --- a/sound/drivers/pcmtest.c +++ b/sound/drivers/pcmtest.c @@ -65,6 +65,7 @@ static int inject_delay; static bool inject_hwpars_err; static bool inject_prepare_err; static bool inject_trigger_err; +static bool inject_open_err; static short fill_mode = FILL_MODE_PAT; @@ -88,6 +89,9 @@ module_param(inject_prepare_err, bool, 0600); MODULE_PARM_DESC(inject_prepare_err, "Inject EINVAL error in the 'prepare' callback"); module_param(inject_trigger_err, bool, 0600); MODULE_PARM_DESC(inject_trigger_err, "Inject EINVAL error in the 'trigger' callback"); +module_param(inject_open_err, bool, 0600); +MODULE_PARM_DESC(inject_open_err, "Inject EBUSY error in the 'open' callback"); + struct pcmtst { struct snd_pcm *pcm; @@ -364,6 +368,9 @@ static int snd_pcmtst_pcm_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct pcmtst_buf_iter *v_iter; + if (inject_open_err) + return -EBUSY; + v_iter = kzalloc(sizeof(*v_iter), GFP_KERNEL); if (!v_iter) return -ENOMEM; From f9d1b819307c242f2e648f16a05c0f908c525616 Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Thu, 13 Jul 2023 11:59:53 +0400 Subject: [PATCH 083/334] ALSA: pcmtest: minor optimizations Decrease the buffer filling overhead with conditional remainder calculation in the 'inc_buf_pos' inline function. Fix the driver to use already defined variables where it is possible in 'check_buf_block_ni' and 'fill_block_pattern_n' functions. Signed-off-by: Ivan Orlov Link: https://lore.kernel.org/r/20230713075953.13692-2-ivan.orlov0322@gmail.com 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 e74c523e49eb..08e14b5eb772 100644 --- a/sound/drivers/pcmtest.c +++ b/sound/drivers/pcmtest.c @@ -144,7 +144,8 @@ static inline void inc_buf_pos(struct pcmtst_buf_iter *v_iter, size_t by, size_t { v_iter->total_bytes += by; v_iter->buf_pos += by; - v_iter->buf_pos %= bytes; + if (v_iter->buf_pos >= bytes) + v_iter->buf_pos %= bytes; } /* @@ -200,10 +201,10 @@ static void check_buf_block_ni(struct pcmtst_buf_iter *v_iter, struct snd_pcm_ru u8 current_byte; for (i = 0; i < v_iter->b_rw; i++) { - current_byte = runtime->dma_area[buf_pos_n(v_iter, channels, i % channels)]; + ch_num = i % channels; + current_byte = runtime->dma_area[buf_pos_n(v_iter, channels, ch_num)]; if (!current_byte) break; - ch_num = i % channels; if (current_byte != patt_bufs[ch_num].buf[(v_iter->total_bytes / channels) % patt_bufs[ch_num].len]) { v_iter->is_buf_corrupted = true; @@ -243,7 +244,7 @@ static void fill_block_pattern_n(struct pcmtst_buf_iter *v_iter, struct snd_pcm_ for (i = 0; i < v_iter->b_rw; i++) { ch_num = i % channels; - runtime->dma_area[buf_pos_n(v_iter, channels, i % channels)] = + runtime->dma_area[buf_pos_n(v_iter, channels, ch_num)] = patt_bufs[ch_num].buf[(v_iter->total_bytes / channels) % patt_bufs[ch_num].len]; inc_buf_pos(v_iter, 1, runtime->dma_bytes); From 083912c240de0c5f797da0443f5a99e87b75fcb3 Mon Sep 17 00:00:00 2001 From: Zhu Ning Date: Fri, 14 Jul 2023 11:24:49 +0800 Subject: [PATCH 084/334] ASoC: codecs: ES8326: Add es8326_mute function The internal analog power and hp Vref of es8326 should always be on to reduce pop noise. The HP_VOL and HP_CAL are moved to es8326_mute function so they are turned on at last and turned off at first. Also, the calibration should be done manually once during start-up to reduce DC offset on headphone. Signed-off-by: Zhu Ning Link: https://lore.kernel.org/r/20230714032453.3334-1-zhuning0077@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 75 ++++++++++++++++----------------------- sound/soc/codecs/es8326.h | 9 +++-- 2 files changed, 37 insertions(+), 47 deletions(-) diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index 7cb5b57ae655..a7fbb758eeee 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -38,6 +38,9 @@ struct es8326_priv { u8 interrupt_clk; bool jd_inverted; unsigned int sysclk; + + bool calibrated; + int version; }; static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9550, 50, 0); @@ -121,33 +124,12 @@ static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = { /* Analog Power Supply*/ SND_SOC_DAPM_DAC("Right DAC", NULL, ES8326_ANA_PDN, 0, 1), SND_SOC_DAPM_DAC("Left DAC", NULL, ES8326_ANA_PDN, 1, 1), - SND_SOC_DAPM_SUPPLY("Analog Power", ES8326_ANA_PDN, 7, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("IBias Power", ES8326_ANA_PDN, 6, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC Vref", ES8326_ANA_PDN, 5, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("DAC Vref", ES8326_ANA_PDN, 4, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("Vref Power", ES8326_ANA_PDN, 3, 1, NULL, 0), SND_SOC_DAPM_SUPPLY("MICBIAS1", ES8326_ANA_MICBIAS, 2, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("MICBIAS2", ES8326_ANA_MICBIAS, 3, 0, NULL, 0), SND_SOC_DAPM_PGA("LHPMIX", ES8326_DAC2HPMIX, 7, 0, NULL, 0), SND_SOC_DAPM_PGA("RHPMIX", ES8326_DAC2HPMIX, 3, 0, NULL, 0), - /* Headphone Charge Pump and Output */ - SND_SOC_DAPM_SUPPLY("HPOR Cal", ES8326_HP_CAL, 7, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("HPOL Cal", ES8326_HP_CAL, 3, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", ES8326_HP_DRIVER, - 3, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("Headphone Driver Bias", ES8326_HP_DRIVER, - 2, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("Headphone LDO", ES8326_HP_DRIVER, - 1, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("Headphone Reference", ES8326_HP_DRIVER, - 0, 1, NULL, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOR Supply", ES8326_HP_CAL, - ES8326_HPOR_SHIFT, 7, 7, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOL Supply", ES8326_HP_CAL, - 0, 7, 7, 0), - SND_SOC_DAPM_OUTPUT("HPOL"), SND_SOC_DAPM_OUTPUT("HPOR"), }; @@ -166,34 +148,12 @@ static const struct snd_soc_dapm_route es8326_dapm_routes[] = { {"I2S OUT", NULL, "ADC L"}, {"I2S OUT", NULL, "ADC R"}, - {"I2S OUT", NULL, "Analog Power"}, - {"I2S OUT", NULL, "ADC Vref"}, - {"I2S OUT", NULL, "Vref Power"}, - {"I2S OUT", NULL, "IBias Power"}, - {"I2S IN", NULL, "Analog Power"}, - {"I2S IN", NULL, "DAC Vref"}, - {"I2S IN", NULL, "Vref Power"}, - {"I2S IN", NULL, "IBias Power"}, - {"Right DAC", NULL, "I2S IN"}, {"Left DAC", NULL, "I2S IN"}, {"LHPMIX", NULL, "Left DAC"}, {"RHPMIX", NULL, "Right DAC"}, - {"HPOR", NULL, "HPOR Cal"}, - {"HPOL", NULL, "HPOL Cal"}, - {"HPOR", NULL, "HPOR Supply"}, - {"HPOL", NULL, "HPOL Supply"}, - {"HPOL", NULL, "Headphone Charge Pump"}, - {"HPOR", NULL, "Headphone Charge Pump"}, - {"HPOL", NULL, "Headphone Driver Bias"}, - {"HPOR", NULL, "Headphone Driver Bias"}, - {"HPOL", NULL, "Headphone LDO"}, - {"HPOR", NULL, "Headphone LDO"}, - {"HPOL", NULL, "Headphone Reference"}, - {"HPOR", NULL, "Headphone Reference"}, - {"HPOL", NULL, "LHPMIX"}, {"HPOR", NULL, "RHPMIX"}, }; @@ -419,6 +379,31 @@ static int es8326_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } +static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction) +{ + struct snd_soc_component *component = dai->component; + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); + + if (mute) { + regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF); + regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE, + ES8326_MUTE_MASK, ES8326_MUTE); + regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xf0); + } else { + if (!es8326->calibrated) { + regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_FORCE_CAL); + msleep(30); + es8326->calibrated = true; + } + regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa0); + regmap_write(es8326->regmap, ES8326_HP_VOL, 0x00); + regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_ON); + regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE, + ES8326_MUTE_MASK, ~(ES8326_MUTE)); + } + return 0; +} + static int es8326_set_bias_level(struct snd_soc_component *codec, enum snd_soc_bias_level level) { @@ -469,6 +454,8 @@ static const struct snd_soc_dai_ops es8326_ops = { .hw_params = es8326_pcm_hw_params, .set_fmt = es8326_set_dai_fmt, .set_sysclk = es8326_set_dai_sysclk, + .mute_stream = es8326_mute, + .no_capture_mute = 1, }; static struct snd_soc_dai_driver es8326_dai = { @@ -691,7 +678,7 @@ static int es8326_suspend(struct snd_soc_component *component) cancel_delayed_work_sync(&es8326->jack_detect_work); es8326_disable_micbias(component); - + es8326->calibrated = false; regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_OFF); regcache_cache_only(es8326->regmap, true); regcache_mark_dirty(es8326->regmap); diff --git a/sound/soc/codecs/es8326.h b/sound/soc/codecs/es8326.h index 8e5ffe5ee10d..3f8f7da58062 100644 --- a/sound/soc/codecs/es8326.h +++ b/sound/soc/codecs/es8326.h @@ -9,8 +9,6 @@ #ifndef _ES8326_H #define _ES8326_H -#define CONFIG_HHTECH_MINIPMP 1 - /* ES8326 register space */ #define ES8326_RESET 0x00 #define ES8326_CLK_CTL 0x01 @@ -94,6 +92,8 @@ #define ES8326_PWRUP_SEQ_EN (1 << 5) #define ES8326_CODEC_RESET (0x0f << 0) #define ES8326_CSM_OFF (0 << 7) +#define ES8326_MUTE_MASK (3 << 0) +#define ES8326_MUTE (3 << 0) /* ES8326_CLK_CTL */ #define ES8326_CLK_ON (0x7f << 0) @@ -122,7 +122,9 @@ #define ES8326_MIC2_SEL (1 << 5) /* ES8326_HP_CAL */ -#define ES8326_HPOR_SHIFT 4 +#define ES8326_HP_OFF 0 +#define ES8326_HP_FORCE_CAL ((1 << 7) | (1 << 3)) +#define ES8326_HP_ON ((7 << 4) | (7 << 0)) /* ES8326_ADC1_SRC */ #define ES8326_ADC1_SHIFT 0 @@ -180,3 +182,4 @@ #define ES8326_VERSION_B (1 << 0) #endif + From 7e9f28398a6e226d4c31cb0e5501a36f37fa139d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:51:08 -0600 Subject: [PATCH 085/334] ALSA: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230714175109.4066599-1-robh@kernel.org Signed-off-by: Takashi Iwai --- sound/atmel/ac97c.c | 3 +-- sound/drivers/serial-generic.c | 2 +- sound/pci/hda/hda_tegra.c | 3 ++- sound/ppc/awacs.c | 1 + sound/ppc/burgundy.c | 1 + sound/sparc/amd7930.c | 3 +-- sound/sparc/cs4231.c | 2 +- sound/sparc/dbri.c | 2 +- 8 files changed, 9 insertions(+), 8 deletions(-) diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index c8912b8a1dc5..402b5f66dcc3 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -12,13 +12,12 @@ #include #include #include +#include #include #include #include #include #include -#include -#include #include #include diff --git a/sound/drivers/serial-generic.c b/sound/drivers/serial-generic.c index e1f864dc7939..b0262541802a 100644 --- a/sound/drivers/serial-generic.c +++ b/sound/drivers/serial-generic.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 9d0ab043880b..39fa036616ce 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -16,7 +16,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c index 53d558b2806c..659866cfe3b4 100644 --- a/sound/ppc/awacs.c +++ b/sound/ppc/awacs.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include "pmac.h" diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c index 4fb990ab2ceb..400a886562b1 100644 --- a/sound/ppc/burgundy.c +++ b/sound/ppc/burgundy.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "pmac.h" #include "burgundy.h" diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index c434b69a83f1..0fea04acc3ea 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include @@ -47,7 +47,6 @@ #include #include -#include static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index 31bac355ec4d..c2ad3fa2f25a 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 376aed136a45..050e98f32d36 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -69,7 +69,7 @@ #include #include -#include +#include #include #include From 272aedb250cff93c2c25d19db9f4691329238f98 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 19:29:32 +0100 Subject: [PATCH 086/334] ASoC: wcd9335: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wcd9335 driver to use the more modern data structure. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230712-asoc-qcom-maple-v1-1-15f8089664b9@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 8bf3510a3ea3..a05b553e6472 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -4968,7 +4968,7 @@ static bool wcd9335_is_volatile_register(struct device *dev, unsigned int reg) static struct regmap_config wcd9335_regmap_config = { .reg_bits = 16, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = WCD9335_MAX_REGISTER, .can_multi_write = true, .ranges = wcd9335_ranges, From 8caeeb54d8283601eab27f6d0ca727476cba7f1c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 19:29:33 +0100 Subject: [PATCH 087/334] ASoC: wcd938x: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wcd938x driver to use the more modern data structure. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230712-asoc-qcom-maple-v1-2-15f8089664b9@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd938x-sdw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c index bd0e9fbc12eb..6951120057e5 100644 --- a/sound/soc/codecs/wcd938x-sdw.c +++ b/sound/soc/codecs/wcd938x-sdw.c @@ -1183,7 +1183,7 @@ static const struct regmap_config wcd938x_regmap_config = { .name = "wcd938x_csr", .reg_bits = 32, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wcd938x_defaults, .num_reg_defaults = ARRAY_SIZE(wcd938x_defaults), .max_register = WCD938X_MAX_REGISTER, From daf95b06a0615d8b2a6716d14a3b8605b90f1ed2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 19:29:34 +0100 Subject: [PATCH 088/334] ASoC: wsa881x: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wsa881x driver to use the more modern data structure. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230712-asoc-qcom-maple-v1-3-15f8089664b9@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wsa881x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index 97f6873a0a8c..3c025dabaf7a 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -637,7 +637,7 @@ static bool wsa881x_volatile_register(struct device *dev, unsigned int reg) static struct regmap_config wsa881x_regmap_config = { .reg_bits = 32, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wsa881x_defaults, .max_register = WSA881X_SPKR_STATUS3, .num_reg_defaults = ARRAY_SIZE(wsa881x_defaults), From e1de05805133d2f2803001b4804d010b6812ca4a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 19:29:35 +0100 Subject: [PATCH 089/334] ASoC: wsa883x: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wsa883x driver to use the more modern data structure. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230712-asoc-qcom-maple-v1-4-15f8089664b9@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wsa883x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index e40d583a1ce6..197fae23762f 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -938,7 +938,7 @@ static bool wsa883x_volatile_register(struct device *dev, unsigned int reg) static struct regmap_config wsa883x_regmap_config = { .reg_bits = 32, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wsa883x_defaults, .max_register = WSA883X_MAX_REGISTER, .num_reg_defaults = ARRAY_SIZE(wsa883x_defaults), From 143f8c69a27f3fa8ed30c7f6790ea039fff57cfe Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Fri, 14 Jul 2023 17:29:12 +0800 Subject: [PATCH 090/334] ASoC: dt-bindings: fsl_rpmsg: Add compatible string for i.MX93 Add compatible string for i.MX93 platform which supports audio function through rpmsg channel between Cortex-A and Cortex-M core. Signed-off-by: Chancel Liu Acked-by: Rob Herring Link: https://lore.kernel.org/r/20230714092913.1591195-2-chancel.liu@nxp.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml index e847611a85f7..6df0e03a1d4b 100644 --- a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml @@ -25,6 +25,7 @@ properties: - fsl,imx8mm-rpmsg-audio - fsl,imx8mp-rpmsg-audio - fsl,imx8ulp-rpmsg-audio + - fsl,imx93-rpmsg-audio model: $ref: /schemas/types.yaml#/definitions/string From 60f38a592efe08e5ced454e8a05f6814e6e221ec Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Fri, 14 Jul 2023 17:29:13 +0800 Subject: [PATCH 091/334] ASoC: fsl_rpmsg: Add support for i.MX93 platform Add compatible string and specific soc data to support rpmsg sound card on i.MX93 platform. Signed-off-by: Chancel Liu Link: https://lore.kernel.org/r/20230714092913.1591195-3-chancel.liu@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_rpmsg.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c index 15b48b5ea856..abe19a8a7aa7 100644 --- a/sound/soc/fsl/fsl_rpmsg.c +++ b/sound/soc/fsl/fsl_rpmsg.c @@ -170,12 +170,20 @@ static const struct fsl_rpmsg_soc_data imx8mp_data = { SNDRV_PCM_FMTBIT_S32_LE, }; +static const struct fsl_rpmsg_soc_data imx93_data = { + .rates = SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, +}; + static const struct of_device_id fsl_rpmsg_ids[] = { { .compatible = "fsl,imx7ulp-rpmsg-audio", .data = &imx7ulp_data}, { .compatible = "fsl,imx8mm-rpmsg-audio", .data = &imx8mm_data}, { .compatible = "fsl,imx8mn-rpmsg-audio", .data = &imx8mn_data}, { .compatible = "fsl,imx8mp-rpmsg-audio", .data = &imx8mp_data}, { .compatible = "fsl,imx8ulp-rpmsg-audio", .data = &imx7ulp_data}, + { .compatible = "fsl,imx93-rpmsg-audio", .data = &imx93_data}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_rpmsg_ids); From 1a74b21ce59f4343e8bf64ec4c20bcbbaea96c5f Mon Sep 17 00:00:00 2001 From: V sujith kumar Reddy Date: Thu, 13 Jul 2023 18:27:07 +0530 Subject: [PATCH 092/334] ASoC: SOF: amd: Add Probe functionality support for amd platforms. This patch consist of probe client device registration,stream tag and dma channel configuration for SOF firmware. Signed-off-by: V sujith kumar Reddy Link: https://lore.kernel.org/r/20230713125709.418851-2-vsujithkumar.reddy@amd.corp-partner.google.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/Kconfig | 8 ++ sound/soc/sof/amd/Makefile | 1 + sound/soc/sof/amd/acp-common.c | 4 + sound/soc/sof/amd/acp-ipc.c | 26 ++++++ sound/soc/sof/amd/acp-probes.c | 147 +++++++++++++++++++++++++++++++++ sound/soc/sof/amd/acp.h | 9 ++ 6 files changed, 195 insertions(+) create mode 100644 sound/soc/sof/amd/acp-probes.c diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig index 1cb92d6030e3..7dbc8df5cfe6 100644 --- a/sound/soc/sof/amd/Kconfig +++ b/sound/soc/sof/amd/Kconfig @@ -21,6 +21,7 @@ config SND_SOC_SOF_AMD_COMMON select SND_SOC_SOF_PCI_DEV select SND_AMD_ACP_CONFIG select SND_SOC_SOF_XTENSA + select SND_SOC_SOF_ACP_PROBES select SND_SOC_ACPI if ACPI help This option is not user-selectable but automatically handled by @@ -42,4 +43,11 @@ config SND_SOC_SOF_AMD_REMBRANDT Say Y if you want to enable SOF on Rembrandt. If unsure select "N". +config SND_SOC_SOF_ACP_PROBES + tristate + select SND_SOC_SOF_DEBUG_PROBES + help + This option is not user-selectable but automatically handled by + 'select' statements at a higher level + endif diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index 5626d13b3e69..ef9f7df4e379 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -5,6 +5,7 @@ # Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o acp-trace.o acp-common.o +snd-sof-amd-acp-$(CONFIG_SND_SOC_SOF_ACP_PROBES) = acp-probes.o snd-sof-amd-renoir-objs := pci-rn.o renoir.o snd-sof-amd-rembrandt-objs := pci-rmb.o rembrandt.o diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c index df36b411a12e..3a0c7688dcfe 100644 --- a/sound/soc/sof/amd/acp-common.c +++ b/sound/soc/sof/amd/acp-common.c @@ -196,6 +196,10 @@ struct snd_sof_dsp_ops sof_acp_common_ops = { .dbg_dump = amd_sof_dump, .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, .dsp_arch_ops = &sof_xtensa_arch_ops, + + /* probe client device registation */ + .register_ipc_clients = acp_probes_register, + .unregister_ipc_clients = acp_probes_unregister, }; EXPORT_SYMBOL_NS(sof_acp_common_ops, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c index 8a0fc635a997..81a2c096a185 100644 --- a/sound/soc/sof/amd/acp-ipc.c +++ b/sound/soc/sof/amd/acp-ipc.c @@ -155,6 +155,8 @@ static void acp_dsp_ipc_get_reply(struct snd_sof_dev *sdev) irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) { struct snd_sof_dev *sdev = context; + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); + struct acp_dev_data *adata = sdev->pdata->hw_pdata; unsigned int dsp_msg_write = sdev->debug_box.offset + offsetof(struct scratch_ipc_conf, sof_dsp_msg_write); unsigned int dsp_ack_write = sdev->debug_box.offset + @@ -200,6 +202,30 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) return IRQ_HANDLED; } + if (desc->probe_reg_offset) { + u32 val; + u32 posn; + + /* Probe register consists of two parts + * (0-30) bit has cumulative position value + * 31 bit is a synchronization flag between DSP and CPU + * for the position update + */ + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->probe_reg_offset); + if (val & PROBE_STATUS_BIT) { + posn = val & ~PROBE_STATUS_BIT; + if (adata->probe_stream) { + /* Probe related posn value is of 31 bits limited to 2GB + * once wrapped DSP won't send posn interrupt. + */ + adata->probe_stream->cstream_posn = posn; + snd_compr_fragment_elapsed(adata->probe_stream->cstream); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->probe_reg_offset, posn); + ipc_irq = true; + } + } + } + if (!ipc_irq) dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n"); diff --git a/sound/soc/sof/amd/acp-probes.c b/sound/soc/sof/amd/acp-probes.c new file mode 100644 index 000000000000..778cf1a8b610 --- /dev/null +++ b/sound/soc/sof/amd/acp-probes.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2023 Advanced Micro Devices, Inc. +// +// Authors: V Sujith Kumar Reddy + +/* + * Probe interface for generic AMD audio ACP DSP block + */ + +#include +#include +#include "../sof-priv.h" +#include "../sof-client-probes.h" +#include "../sof-client.h" +#include "../ops.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +static int acp_probes_compr_startup(struct sof_client_dev *cdev, + struct snd_compr_stream *cstream, + struct snd_soc_dai *dai, u32 *stream_id) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + struct acp_dsp_stream *stream; + struct acp_dev_data *adata; + + adata = sdev->pdata->hw_pdata; + stream = acp_dsp_stream_get(sdev, 0); + if (!stream) + return -ENODEV; + + stream->cstream = cstream; + cstream->runtime->private_data = stream; + + adata->probe_stream = stream; + *stream_id = stream->stream_tag; + + return 0; +} + +static int acp_probes_compr_shutdown(struct sof_client_dev *cdev, + struct snd_compr_stream *cstream, + struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + struct acp_dsp_stream *stream = cstream->runtime->private_data; + struct acp_dev_data *adata; + int ret; + + ret = acp_dsp_stream_put(sdev, stream); + if (ret < 0) { + dev_err(sdev->dev, "Failed to release probe compress stream\n"); + return ret; + } + + adata = sdev->pdata->hw_pdata; + stream->cstream = NULL; + cstream->runtime->private_data = NULL; + adata->probe_stream = NULL; + + return 0; +} + +static int acp_probes_compr_set_params(struct sof_client_dev *cdev, + struct snd_compr_stream *cstream, + struct snd_compr_params *params, + struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + struct acp_dsp_stream *stream = cstream->runtime->private_data; + unsigned int buf_offset, index; + u32 size; + int ret; + + stream->dmab = cstream->runtime->dma_buffer_p; + stream->num_pages = PFN_UP(cstream->runtime->dma_bytes); + size = cstream->runtime->buffer_size; + + ret = acp_dsp_stream_config(sdev, stream); + if (ret < 0) { + acp_dsp_stream_put(sdev, stream); + return ret; + } + + /* write buffer size of stream in scratch memory */ + + buf_offset = sdev->debug_box.offset + + offsetof(struct scratch_reg_conf, buf_size); + index = stream->stream_tag - 1; + buf_offset = buf_offset + index * 4; + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + buf_offset, size); + + return 0; +} + +static int acp_probes_compr_trigger(struct sof_client_dev *cdev, + struct snd_compr_stream *cstream, + int cmd, struct snd_soc_dai *dai) +{ + /* Nothing to do here, as it is a mandatory callback just defined */ + return 0; +} + +static int acp_probes_compr_pointer(struct sof_client_dev *cdev, + struct snd_compr_stream *cstream, + struct snd_compr_tstamp *tstamp, + struct snd_soc_dai *dai) +{ + struct acp_dsp_stream *stream = cstream->runtime->private_data; + struct snd_soc_pcm_stream *pstream; + + pstream = &dai->driver->capture; + tstamp->copied_total = stream->cstream_posn; + tstamp->sampling_rate = snd_pcm_rate_bit_to_rate(pstream->rates); + + return 0; +} + +/* SOF client implementation */ +static const struct sof_probes_host_ops acp_probes_ops = { + .startup = acp_probes_compr_startup, + .shutdown = acp_probes_compr_shutdown, + .set_params = acp_probes_compr_set_params, + .trigger = acp_probes_compr_trigger, + .pointer = acp_probes_compr_pointer, +}; + +int acp_probes_register(struct snd_sof_dev *sdev) +{ + return sof_client_dev_register(sdev, "acp-probes", 0, &acp_probes_ops, + sizeof(acp_probes_ops)); +} +EXPORT_SYMBOL_NS(acp_probes_register, SND_SOC_SOF_AMD_COMMON); + +void acp_probes_unregister(struct snd_sof_dev *sdev) +{ + sof_client_dev_unregister(sdev, "acp-probes", 0); +} +EXPORT_SYMBOL_NS(acp_probes_unregister, SND_SOC_SOF_AMD_COMMON); + +MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT); + diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index c3659dbc3745..72fa0af971f0 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -77,6 +77,7 @@ #define AMD_STACK_DUMP_SIZE 32 #define SRAM1_SIZE 0x13A000 +#define PROBE_STATUS_BIT BIT(31) enum clock_source { ACP_CLOCK_96M = 0, @@ -156,6 +157,8 @@ struct acp_dsp_stream { int active; unsigned int reg_offset; size_t posn_offset; + struct snd_compr_stream *cstream; + u64 cstream_posn; }; struct sof_amd_acp_desc { @@ -168,6 +171,7 @@ struct sof_amd_acp_desc { u32 hw_semaphore_offset; u32 acp_clkmux_sel; u32 fusion_dsp_offset; + u32 probe_reg_offset; }; /* Common device data struct for ACP devices */ @@ -186,6 +190,7 @@ struct acp_dev_data { struct acp_dsp_stream stream_buf[ACP_MAX_STREAM]; struct acp_dsp_stream *dtrace_stream; struct pci_dev *smn_dev; + struct acp_dsp_stream *probe_stream; }; void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); @@ -273,4 +278,8 @@ static inline const struct sof_amd_acp_desc *get_chip_info(struct snd_sof_pdata return desc->chip_info; } + +int acp_probes_register(struct snd_sof_dev *sdev); +void acp_probes_unregister(struct snd_sof_dev *sdev); + #endif From 5e1c5df5048b320adffcb03e0cdfc6027364ed30 Mon Sep 17 00:00:00 2001 From: V sujith kumar Reddy Date: Thu, 13 Jul 2023 18:27:08 +0530 Subject: [PATCH 093/334] ASoC: SOF: Add acp-probe id to sof probe client driver for registration. This patch adds acp-probe id as a match id to support probe functionality for amd platforms. Signed-off-by: V sujith kumar Reddy Link: https://lore.kernel.org/r/20230713125709.418851-3-vsujithkumar.reddy@amd.corp-partner.google.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-client-probes.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c index 8d9e9d5f40e4..5530b5d793d0 100644 --- a/sound/soc/sof/sof-client-probes.c +++ b/sound/soc/sof/sof-client-probes.c @@ -523,6 +523,7 @@ static void sof_probes_client_remove(struct auxiliary_device *auxdev) static const struct auxiliary_device_id sof_probes_client_id_table[] = { { .name = "snd_sof.hda-probes", }, + { .name = "snd_sof.acp-probes", }, {}, }; MODULE_DEVICE_TABLE(auxiliary, sof_probes_client_id_table); From 8278aa8edb4037ca5050a1b0bf32b38ef9fa59bc Mon Sep 17 00:00:00 2001 From: V sujith kumar Reddy Date: Thu, 13 Jul 2023 18:27:09 +0530 Subject: [PATCH 094/334] ASoC: SOF: amd: Add Probe register offset for renoir and rembrandt platform. Add Probe register offset for renoir and rembrandt platform to get position update. Signed-off-by: V sujith kumar Reddy Link: https://lore.kernel.org/r/20230713125709.418851-4-vsujithkumar.reddy@amd.corp-partner.google.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/pci-rmb.c | 2 ++ sound/soc/sof/amd/pci-rn.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/sound/soc/sof/amd/pci-rmb.c b/sound/soc/sof/amd/pci-rmb.c index 58b3092425f1..9935e457b467 100644 --- a/sound/soc/sof/amd/pci-rmb.c +++ b/sound/soc/sof/amd/pci-rmb.c @@ -25,6 +25,7 @@ #define ACP6x_REG_START 0x1240000 #define ACP6x_REG_END 0x125C000 +#define ACP6X_FUTURE_REG_ACLK_0 0x1854 static const struct sof_amd_acp_desc rembrandt_chip_info = { .rev = 6, @@ -36,6 +37,7 @@ static const struct sof_amd_acp_desc rembrandt_chip_info = { .hw_semaphore_offset = ACP6X_AXI2DAGB_SEM_0, .acp_clkmux_sel = ACP6X_CLKMUX_SEL, .fusion_dsp_offset = ACP6X_DSP_FUSION_RUNSTALL, + .probe_reg_offset = ACP6X_FUTURE_REG_ACLK_0, }; static const struct sof_dev_desc rembrandt_desc = { diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c index 7409e21ce5aa..c72d5d8aff8e 100644 --- a/sound/soc/sof/amd/pci-rn.c +++ b/sound/soc/sof/amd/pci-rn.c @@ -25,6 +25,7 @@ #define ACP3x_REG_START 0x1240000 #define ACP3x_REG_END 0x125C000 +#define ACP3X_FUTURE_REG_ACLK_0 0x1860 static const struct sof_amd_acp_desc renoir_chip_info = { .rev = 3, @@ -35,6 +36,7 @@ static const struct sof_amd_acp_desc renoir_chip_info = { .sram_pte_offset = ACP3X_SRAM_PTE_OFFSET, .hw_semaphore_offset = ACP3X_AXI2DAGB_SEM_0, .acp_clkmux_sel = ACP3X_CLKMUX_SEL, + .probe_reg_offset = ACP3X_FUTURE_REG_ACLK_0, }; static const struct sof_dev_desc renoir_desc = { From 09f75f098105d65c37915e41a6ed3a75ec3ecfc7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Jul 2023 10:19:53 +0900 Subject: [PATCH 095/334] ASoC: soc-dai.c: add DAI get/match functions Current ASoC is specifying and checking DAI name. But where it came from and how to check was ambiguous. This patch adds snd_soc_dai_name_get() / snd_soc_dlc_dai_is_match() and makes it clear. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87h6qco952.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 ++ sound/soc/soc-core.c | 62 +++++++++++++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index e3906ecda740..a4538040e88d 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -271,6 +271,8 @@ int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai, struct snd_compr_stream *cstream, struct snd_compr_metadata *metadata); +const char *snd_soc_dai_name_get(struct snd_soc_dai *dai); + struct snd_soc_dai_ops { /* * DAI clocking configuration, all optional. diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 94e856d67a46..ee309d3fe89c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -253,6 +253,47 @@ static inline int snd_soc_dlc_dai_is_empty(struct snd_soc_dai_link_component *dl return !dlc->dai_name; } +static int snd_soc_is_matching_dai(const struct snd_soc_dai_link_component *dlc, + struct snd_soc_dai *dai) +{ + if (!dlc) + return 0; + + if (!dlc->dai_name) + return 1; + + /* see snd_soc_dai_name_get() */ + + if (strcmp(dlc->dai_name, dai->name) == 0) + return 1; + + if (dai->driver->name && + strcmp(dai->driver->name, dlc->dai_name) == 0) + return 1; + + if (dai->component->name && + strcmp(dlc->dai_name, dai->component->name) == 0) + return 1; + + return 0; +} + +const char *snd_soc_dai_name_get(struct snd_soc_dai *dai) +{ + /* see snd_soc_is_matching_dai() */ + if (dai->name) + return dai->name; + + if (dai->driver->name) + return dai->driver->name; + + if (dai->component->name) + return dai->component->name; + + return NULL; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_name_get); + static int snd_soc_rtd_add_component(struct snd_soc_pcm_runtime *rtd, struct snd_soc_component *component) { @@ -810,18 +851,11 @@ struct snd_soc_dai *snd_soc_find_dai( lockdep_assert_held(&client_mutex); /* Find CPU DAI from registered DAIs */ - for_each_component(component) { - if (!snd_soc_is_matching_component(dlc, component)) - continue; - for_each_component_dais(component, dai) { - if (dlc->dai_name && strcmp(dai->name, dlc->dai_name) - && (!dai->driver->name - || strcmp(dai->driver->name, dlc->dai_name))) - continue; - - return dai; - } - } + for_each_component(component) + if (snd_soc_is_matching_component(dlc, component)) + for_each_component_dais(component, dai) + if (snd_soc_is_matching_dai(dlc, dai)) + return dai; return NULL; } @@ -3316,9 +3350,7 @@ int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_ id--; } - dlc->dai_name = dai->driver->name; - if (!dlc->dai_name) - dlc->dai_name = pos->name; + dlc->dai_name = snd_soc_dai_name_get(dai); } else if (ret) { /* * if another error than ENOTSUPP is returned go on and From 45655ec69cb954d7fa594054bec33d6d5b99f8d5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Jul 2023 10:20:00 +0900 Subject: [PATCH 096/334] ASoC: soc-core.c: enable multi Component Current ASoC Card is using dlc (snd_soc_dai_link_component) to find target DAI / Component to be used. Current dlc has below 3 items to identify DAI / Component (a) name for Component (b) of_node for Component (c) dai_name for DAI (a) or (b) is used to identify target Component, and (c) is used to identify DAI. One of the biggest issue on it today is dlc needs "name matching" for "dai_name" (c). It was not a big deal when we were using platform_device, because we could specify nessesary "dai_name" via its platform_data. But we need to find DAI name pointer from whole registered datas and/or each related driver somehow in case of DT, because we can't specify it. Therefore, Card driver parses DT and assumes the DAI, and find its name pointer. How to assume is based on each Component and/or Card. Next biggest issue is Component node (a)/(b). Basically, Component is registered when CPU/Codec driver was probed() (X). Here, 1 Component is possible to have some DAIs. int xxx_probe(struct platform_device *pdev) { ... (X) ret = devm_snd_soc_register_component(pdev->dev, &component_driver, &dai_driver, dai_driver_num); ... } The image of each data will be like below. One note here is "driver" is included for later explanation. +-driver------+ |+-component-+| || dai0|| || dai1|| || ...|| |+-----------+| +-------------+ The point here is 1 driver has 1 Component, because basically driver calles snd_soc_register_component() (= X) once. Here is the very basic CPU/Codec connection image. HW image SW image +-- Board ------------+ +-card--------------------------+ |+-----+ +------+| |+-driver------+ +-driver------+| || CPU | <--> |CodecA|| ||+-component-+| |+-component-+|| |+-----+ +------+| ||| dai|<=>|dai ||| +---------------------+ ||+-----------+| |+-----------+|| |+-------------+ +-------------+| +-------------------------------+ It will be very complex if it has multi DAIs. Here is intuitive easy to understandable HW / SW example. HW image SW image +-- Board ---------------+ +-card--------------------------+ |+--------+ +------+| |+-driver------+ +-driver------+| || CPU ch0| <--> |CodecA|| ||+-component-+| |+-component-+|| || | +------+| ||| ch0 dai|<=>|dai ||| || | +------+| ||| || |+-----------+|| || ch1| <--> |CodecB|| ||| || +-------------+| |+--------+ +------+| ||| || +-driver------+| +------------------------+ ||| || |+-component-+|| ||| ch1 dai|<=>|dai ||| ||+-----------+| |+-----------+|| |+-------------+ +-------------+| +-------------------------------+ It will be handled as multi interface as "one Card". card0,0: CPU-ch0 - CodecA card0,1: CPU-ch1 - CodecB ^ But, here is the HW image example which will be more complex +-- Basic Board ---------+ |+--------+ +------+| || CPU ch0| <--> |CodecA|| || ch1| <-+ +------+| |+--------+ | | +-------------|----------+ +-- expansion board -----+ | | +------+| | +->|CodecB|| | +------+| +------------------------+ We intuitively think we want to handle these as "2 Sound Cards". card0,0: CPU-ch0 - CodecA card1,0: CPU-ch1 - CodecB ^ But below image which we can register today doesn't allow it, because the same Component will be connected to both Card0/1, but it will be rejected by (Z). +-driver------+ |+-component-+| +-card0-------------------------+ ||| || +-driver------+| ||| || |+-component-+|| ||| ch0 dai|<=>|dai ||| ||| || |+-----------+|| ||| || +-------------+| +-------------------------------+ || || +-card1-------------------------+ ||| || +-driver------+| ||| || |+-component-+|| ||| ch1 dai|<=>|dai ||| ||| || |+-----------+|| ||| || +-------------+| +-------------------------------+ |+-----------+| +-------------+ static int soc_probe_component() { ... if (component->card) { (Z) if (component->card != card) { dev_err(component->dev, ...); return -ENODEV; } return 0; } ... } So, how about to call snd_soc_register_component() (= X) multiple times on probe() to avoid buplicated component->card limitation, to be like below ? +-driver------+ +-card0-------------------------+ || | +-driver------+| ||+-component-+| |+-component-+|| ||| ch0 dai|<=>|dai ||| ||+-----------+| |+-----------+|| || | +-------------+| +-------------------------------+ | | +-card1-------------------------+ || | +-driver------+| ||+-component-+| |+-component-+|| ||| ch1 dai|<=>|dai ||| ||+-----------+| |+-----------+|| || | +-------------+| +-------------------------------+ +-------------+ Yes, looks good. But unfortunately it doesn't help us for now. Let's see soc_component_to_node() and snd_soc_is_matching_component() static struct device_node *soc_component_to_node(struct snd_soc_component *component) { ... (A) of_node = component->dev->of_node; ... } static int snd_soc_is_matching_component(...) { ... (B) if (dlc->of_node && component_of_node != dlc->of_node) ... } dlc checkes "of_node" to identify target component (B), but this "of_node" came from component->dev (A) which is added by snd_soc_register_component() (X) on probe(). This means we can have different "component->card", but have same "component->dev" in this case. Even though we calls snd_soc_register_component() (= X) multiple times, all Components have same driver's dev, thus it is impossible to identified the Component. And if it was impossible to identify Component, it is impossible to identify DAI on current implementation. So, how to handle above complex HW image today is 2 patterns. One is handles it as "1 big sound card". The SW image is like below. SW image +-card--------------------------+ |+-driver------+ +-driver------+| ||+-component-+| |+-component-+|| ||| ch0 dai|<=>|dai ||| ||| || |+-----------+|| ||| || +-------------+| ||| || +-driver------+| ||| || |+-component-+|| ||| ch1 dai|<->|dai ||| ||+-----------+| |+-----------+|| |+-------------+ +-------------+| +-------------------------------+ But the problem is not intuitive. We want to handle it as "2 Cards". 2nd pattern is like below. SW image +-card0-------------------------+ |+-driver------+ +-driver------+| ||+-component-+| |+-component-+|| ||| ch0 dai|<=>|dai ||| ||+-----------+| |+-----------+|| |+-------------+ +-------------+| +-------------------------------+ +-card1-------------------------+ |+-driver------+ +-driver------+| ||+-component-+| |+-component-+|| ||| ch1 dai|<=>|dai ||| ||+-----------+| |+-----------+|| |+-------------+ +-------------+| +-------------------------------+ It handles as "2 Cards", but CPU part needs to be probed as 2 drivers. It is also not intuitive. To solve this issue, we need to have multi Component support. In current implementation, we need to identify Component first to identify DAI, and it is using name matching to identify DAI. But how about to be enable to directly identify DAI by unique way instead of name matching ? In such case, we can directly identify DAI, then it can identify Component from DAI. For example Simple-Card / Audio-Graph-Card case, it is specifying DAI via its node. Simple-Card sound-dai = <&cpu-sound>; Audio-Graph-Card dais = <&cpu-sound>; If each CPU/Codec driver keeps this property when probing, we can identify DAI directly from Card. Being able to identify DAI directly means being able to identify its Component as well even though Component has same dev (= B). This patch adds new "dai_node" for it. To keeping compatibility, it checks "dai_node" first if it has, otherwise, use existing method (name matching). Link: https://lore.kernel.org/r/87fskz5yrr.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87fs5wo94v.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 1 + include/sound/soc.h | 1 + sound/soc/soc-core.c | 32 ++++++++++++++++++++++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index a4538040e88d..a33d803fe548 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -399,6 +399,7 @@ struct snd_soc_dai_driver { unsigned int id; unsigned int base; struct snd_soc_dobj dobj; + struct of_phandle_args *dai_args; /* DAI driver callbacks */ int (*probe)(struct snd_soc_dai *dai); diff --git a/include/sound/soc.h b/include/sound/soc.h index b27f84580c5b..dda731795bd4 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -651,6 +651,7 @@ struct snd_soc_dai_link_component { const char *name; struct device_node *of_node; const char *dai_name; + struct of_phandle_args *dai_args; }; struct snd_soc_dai_link_codec_ch_map { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ee309d3fe89c..8487a4c12753 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -238,9 +238,25 @@ static inline void snd_soc_debugfs_exit(void) { } #endif +static int snd_soc_is_match_dai_args(struct of_phandle_args *args1, + struct of_phandle_args *args2) +{ + if (!args1 || !args2) + return 0; + + if (args1->np != args2->np) + return 0; + + for (int i = 0; i < args1->args_count; i++) + if (args1->args[i] != args2->args[i]) + return 0; + + return 1; +} + static inline int snd_soc_dlc_component_is_empty(struct snd_soc_dai_link_component *dlc) { - return !(dlc->name || dlc->of_node); + return !(dlc->dai_args || dlc->name || dlc->of_node); } static inline int snd_soc_dlc_component_is_invalid(struct snd_soc_dai_link_component *dlc) @@ -250,7 +266,7 @@ static inline int snd_soc_dlc_component_is_invalid(struct snd_soc_dai_link_compo static inline int snd_soc_dlc_dai_is_empty(struct snd_soc_dai_link_component *dlc) { - return !dlc->dai_name; + return !(dlc->dai_args || dlc->dai_name); } static int snd_soc_is_matching_dai(const struct snd_soc_dai_link_component *dlc, @@ -259,6 +275,9 @@ static int snd_soc_is_matching_dai(const struct snd_soc_dai_link_component *dlc, if (!dlc) return 0; + if (dlc->dai_args) + return snd_soc_is_match_dai_args(dai->driver->dai_args, dlc->dai_args); + if (!dlc->dai_name) return 1; @@ -799,6 +818,15 @@ static int snd_soc_is_matching_component( if (!dlc) return 0; + if (dlc->dai_args) { + struct snd_soc_dai *dai; + + for_each_component_dais(component, dai) + if (snd_soc_is_matching_dai(dlc, dai)) + return 1; + return 0; + } + component_of_node = soc_component_to_node(component); if (dlc->of_node && component_of_node != dlc->of_node) From 442ae56cf5c007faaf7440d4aa018c62e5761157 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Jul 2023 10:20:06 +0900 Subject: [PATCH 097/334] ASoC: soc-core.c: add snd_soc_get_dai_via_args() To enable multi Component, Card driver need to get DAI via dai_args to identify it. This patch adds snd_soc_get_dai_via_args() for it. This is helper function for multi Component support. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87edlgo94p.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 1 + sound/soc/soc-core.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index dda731795bd4..1b3c58fe14c4 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1336,6 +1336,7 @@ int snd_soc_add_pcm_runtimes(struct snd_soc_card *card, void snd_soc_remove_pcm_runtime(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd); +struct snd_soc_dai *snd_soc_get_dai_via_args(struct of_phandle_args *dai_args); struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv, bool legacy_dai_naming); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 8487a4c12753..22a065f4c908 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3446,6 +3446,24 @@ int snd_soc_of_get_dai_name(struct device_node *of_node, } EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name); +struct snd_soc_dai *snd_soc_get_dai_via_args(struct of_phandle_args *dai_args) +{ + struct snd_soc_dai *dai; + struct snd_soc_component *component; + + mutex_lock(&client_mutex); + for_each_component(component) { + for_each_component_dais(component, dai) + if (snd_soc_is_match_dai_args(dai->driver->dai_args, dai_args)) + goto found; + } + dai = NULL; +found: + mutex_unlock(&client_mutex); + return dai; +} +EXPORT_SYMBOL_GPL(snd_soc_get_dai_via_args); + static void __snd_soc_of_put_component(struct snd_soc_dai_link_component *component) { if (component->of_node) { From 988bad5ee4d7138d26081f3661779b63725605d8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Jul 2023 10:20:11 +0900 Subject: [PATCH 098/334] ASoC: soc-core.c: add snd_soc_dlc_use_cpu_as_platform() Current snd_soc_is_matching_component() checks "of_node" or "dai_args". Thus coping "of_node" only is not enough to use CPU as Platform. This patch adds snd_soc_dlc_use_cpu_as_platform() and help it. This is helper function for multi Component support. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87cz10o94k.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 2 ++ sound/soc/generic/simple-card-utils.c | 2 +- sound/soc/soc-core.c | 8 ++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 1b3c58fe14c4..94fca10f01ad 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1336,6 +1336,8 @@ int snd_soc_add_pcm_runtimes(struct snd_soc_card *card, void snd_soc_remove_pcm_runtime(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd); +void snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platforms, + struct snd_soc_dai_link_component *cpus); struct snd_soc_dai *snd_soc_get_dai_via_args(struct of_phandle_args *dai_args); struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv, diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 3019626b0592..c142571992a1 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -649,7 +649,7 @@ void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platfo * simple-card.c :: simple_count_noml() */ if (!platforms->of_node) - platforms->of_node = cpus->of_node; + snd_soc_dlc_use_cpu_as_platform(platforms, cpus); } EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 22a065f4c908..9fd7e633d374 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3005,6 +3005,14 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot); +void snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platforms, + struct snd_soc_dai_link_component *cpus) +{ + platforms->of_node = cpus->of_node; + platforms->dai_args = cpus->dai_args; +} +EXPORT_SYMBOL_GPL(snd_soc_dlc_use_cpu_as_platform); + void snd_soc_of_parse_node_prefix(struct device_node *np, struct snd_soc_codec_conf *codec_conf, struct device_node *of_node, From bbde4a30c6b18dd034dcce41612907dc64817175 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Jul 2023 10:20:17 +0900 Subject: [PATCH 099/334] ASoC: soc-core.c: add snd_soc_copy_dai_args() To use multi Component support, we need to check dai_args whether Card could get DAI from args (CPU/Codec needs set dai_args on DAI driver). If it could, we need to allocate dai_args for dlc. This patch adds snd_soc_copy_dai_args() for it. This is helper function for multi Component support. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87bkgko94e.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 2 ++ sound/soc/soc-core.c | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 94fca10f01ad..fa2337a3cf4c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1338,6 +1338,8 @@ void snd_soc_remove_pcm_runtime(struct snd_soc_card *card, void snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platforms, struct snd_soc_dai_link_component *cpus); +struct of_phandle_args *snd_soc_copy_dai_args(struct device *dev, + struct of_phandle_args *args); struct snd_soc_dai *snd_soc_get_dai_via_args(struct of_phandle_args *dai_args); struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9fd7e633d374..a5b96c17633a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -809,6 +809,19 @@ static struct device_node return of_node; } +struct of_phandle_args *snd_soc_copy_dai_args(struct device *dev, struct of_phandle_args *args) +{ + struct of_phandle_args *ret = devm_kzalloc(dev, sizeof(*ret), GFP_KERNEL); + + if (!ret) + return NULL; + + *ret = *args; + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_copy_dai_args); + static int snd_soc_is_matching_component( const struct snd_soc_dai_link_component *dlc, struct snd_soc_component *component) From 90de551c1bf0c78ca5cd10c5ff424dee4d44cb1c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Jul 2023 10:20:22 +0900 Subject: [PATCH 100/334] ASoC: simple-card-utils.c: enable multi Component support If CPU/Codec driver keeps its DAI node, we can directly identify actual DAI by using snd_soc_get_dai_via_args(). This means we can use multi Component. This patch enables multi Component support on Audio Graph Card/Card2. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87a5w4o949.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 5 ++--- sound/soc/generic/audio-graph-card.c | 2 +- sound/soc/generic/audio-graph-card2.c | 2 +- sound/soc/generic/simple-card-utils.c | 21 ++++++++++++++++++--- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index b450d5873227..d1a95bc33c56 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -192,9 +192,8 @@ int asoc_simple_remove(struct platform_device *pdev); int asoc_graph_card_probe(struct snd_soc_card *card); int asoc_graph_is_ports0(struct device_node *port); -int asoc_graph_parse_dai(struct device_node *ep, - struct snd_soc_dai_link_component *dlc, - int *is_single_link); +int asoc_graph_parse_dai(struct device *dev, struct device_node *ep, + struct snd_soc_dai_link_component *dlc, int *is_single_link); #ifdef DEBUG static inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv, diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index c6e0f9132193..0b8258b6bd8e 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -126,7 +126,7 @@ static int graph_parse_node(struct asoc_simple_priv *priv, graph_parse_mclk_fs(top, ep, dai_props); - ret = asoc_graph_parse_dai(ep, dlc, cpu); + ret = asoc_graph_parse_dai(dev, ep, dlc, cpu); if (ret < 0) return ret; diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 542c4a114940..98732468a992 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -407,7 +407,7 @@ static int __graph_parse_node(struct asoc_simple_priv *priv, graph_parse_mclk_fs(ep, dai_props); - ret = asoc_graph_parse_dai(ep, dlc, &is_single_links); + ret = asoc_graph_parse_dai(dev, ep, dlc, &is_single_links); if (ret < 0) return ret; diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index c142571992a1..5b18a4af022f 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -1066,12 +1066,12 @@ static int graph_get_dai_id(struct device_node *ep) return id; } -int asoc_graph_parse_dai(struct device_node *ep, - struct snd_soc_dai_link_component *dlc, - int *is_single_link) +int asoc_graph_parse_dai(struct device *dev, struct device_node *ep, + struct snd_soc_dai_link_component *dlc, int *is_single_link) { struct device_node *node; struct of_phandle_args args = {}; + struct snd_soc_dai *dai; int ret; if (!ep) @@ -1079,6 +1079,20 @@ int asoc_graph_parse_dai(struct device_node *ep, node = of_graph_get_port_parent(ep); + /* + * Try to find from DAI node + */ + args.np = ep; + dai = snd_soc_get_dai_via_args(&args); + if (dai) { + dlc->dai_name = snd_soc_dai_name_get(dai); + dlc->dai_args = snd_soc_copy_dai_args(dev, &args); + if (!dlc->dai_args) + return -ENOMEM; + + goto parse_dai_end; + } + /* Get dai->name */ args.np = node; args.args[0] = graph_get_dai_id(ep); @@ -1109,6 +1123,7 @@ int asoc_graph_parse_dai(struct device_node *ep, return ret; } +parse_dai_end: if (is_single_link) *is_single_link = of_graph_get_endpoint_count(node) == 1; From 970dc991b2aaf22cdd497bf66c8fbb13c28c7de4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Jul 2023 10:20:28 +0900 Subject: [PATCH 101/334] ASoC: simple-card.c: enable multi Component support If CPU/Codec driver keeps its DAI node, we can directly identify actual DAI by using snd_soc_get_dai_via_args(). This means we can use multi Component. This patch enables multi Component support for Simple Card Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/878rboo943.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index a78babf44f38..190f11366e84 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -52,11 +52,13 @@ static int asoc_simple_parse_platform(struct device_node *node, return 0; } -static int asoc_simple_parse_dai(struct device_node *node, +static int asoc_simple_parse_dai(struct device *dev, + struct device_node *node, struct snd_soc_dai_link_component *dlc, int *is_single_link) { struct of_phandle_args args; + struct snd_soc_dai *dai; int ret; if (!node) @@ -70,6 +72,19 @@ static int asoc_simple_parse_dai(struct device_node *node, if (ret) return ret; + /* + * Try to find from DAI args + */ + dai = snd_soc_get_dai_via_args(&args); + if (dai) { + dlc->dai_name = snd_soc_dai_name_get(dai); + dlc->dai_args = snd_soc_copy_dai_args(dev, &args); + if (!dlc->dai_args) + return -ENOMEM; + + goto parse_dai_end; + } + /* * FIXME * @@ -93,6 +108,7 @@ static int asoc_simple_parse_dai(struct device_node *node, if (ret < 0) return ret; +parse_dai_end: if (is_single_link) *is_single_link = !args.args_count; @@ -156,7 +172,7 @@ static int simple_parse_node(struct asoc_simple_priv *priv, simple_parse_mclk_fs(top, np, dai_props, prefix); - ret = asoc_simple_parse_dai(np, dlc, cpu); + ret = asoc_simple_parse_dai(dev, np, dlc, cpu); if (ret) return ret; From 7562539e15f1376577d7b62e904b509d17c4bc3f Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 11 Jul 2023 11:48:41 +0800 Subject: [PATCH 102/334] ASoC: bcm: bcm63xx-i2s-whistler: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230711034846.69437-1-frank.li@vivo.com Signed-off-by: Mark Brown --- sound/soc/bcm/bcm63xx-i2s-whistler.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/sound/soc/bcm/bcm63xx-i2s-whistler.c b/sound/soc/bcm/bcm63xx-i2s-whistler.c index 18c51dbbc8dc..c64609718738 100644 --- a/sound/soc/bcm/bcm63xx-i2s-whistler.c +++ b/sound/soc/bcm/bcm63xx-i2s-whistler.c @@ -225,7 +225,6 @@ static int bcm63xx_i2s_dev_probe(struct platform_device *pdev) { int ret = 0; void __iomem *regs; - struct resource *r_mem, *region; struct bcm_i2s_priv *i2s_priv; struct regmap *regmap_i2s; struct clk *i2s_clk; @@ -241,20 +240,7 @@ static int bcm63xx_i2s_dev_probe(struct platform_device *pdev) return PTR_ERR(i2s_clk); } - r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r_mem) { - dev_err(&pdev->dev, "Unable to get register resource.\n"); - return -ENODEV; - } - - region = devm_request_mem_region(&pdev->dev, r_mem->start, - resource_size(r_mem), DRV_NAME); - if (!region) { - dev_err(&pdev->dev, "Memory region already claimed\n"); - return -EBUSY; - } - - regs = devm_ioremap_resource(&pdev->dev, r_mem); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) { ret = PTR_ERR(regs); return ret; From c8b04f008fc33ab2b902a1780c205810d157c849 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 11 Jul 2023 11:48:42 +0800 Subject: [PATCH 103/334] ASoC: ti: Convert to devm_platform_ioremap_resource_byname() Use devm_platform_ioremap_resource_byname() to simplify code. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230711034846.69437-2-frank.li@vivo.com Signed-off-by: Mark Brown --- sound/soc/ti/omap-dmic.c | 4 +--- sound/soc/ti/omap-mcpdm.c | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/soc/ti/omap-dmic.c b/sound/soc/ti/omap-dmic.c index 825c70a443da..cb60af36dbc3 100644 --- a/sound/soc/ti/omap-dmic.c +++ b/sound/soc/ti/omap-dmic.c @@ -488,12 +488,10 @@ static int asoc_dmic_probe(struct platform_device *pdev) dmic->dma_data.filter_data = "up_link"; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); - dmic->io_base = devm_ioremap_resource(&pdev->dev, res); + dmic->io_base = devm_platform_ioremap_resource_byname(pdev, "mpu"); if (IS_ERR(dmic->io_base)) return PTR_ERR(dmic->io_base); - ret = devm_snd_soc_register_component(&pdev->dev, &omap_dmic_component, &omap_dmic_dai, 1); diff --git a/sound/soc/ti/omap-mcpdm.c b/sound/soc/ti/omap-mcpdm.c index 0b18a7bfd3fd..35deceb73427 100644 --- a/sound/soc/ti/omap-mcpdm.c +++ b/sound/soc/ti/omap-mcpdm.c @@ -563,8 +563,7 @@ static int asoc_mcpdm_probe(struct platform_device *pdev) mcpdm->dma_data[0].filter_data = "dn_link"; mcpdm->dma_data[1].filter_data = "up_link"; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); - mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res); + mcpdm->io_base = devm_platform_ioremap_resource_byname(pdev, "mpu"); if (IS_ERR(mcpdm->io_base)) return PTR_ERR(mcpdm->io_base); From e1537b59633cc0e30305e498ba9eead45e762910 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 11 Jul 2023 11:48:43 +0800 Subject: [PATCH 104/334] ASoC: mediatek: mt8186: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230711034846.69437-3-frank.li@vivo.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8186/mt8186-afe-pcm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c index a868a04ed4e7..b86159f70a33 100644 --- a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c +++ b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c @@ -2815,7 +2815,6 @@ static int mt8186_afe_pcm_dev_probe(struct platform_device *pdev) { struct mtk_base_afe *afe; struct mt8186_afe_private *afe_priv; - struct resource *res; struct reset_control *rstc; struct device *dev = &pdev->dev; int i, ret, irq_id; @@ -2836,8 +2835,7 @@ static int mt8186_afe_pcm_dev_probe(struct platform_device *pdev) afe_priv = afe->platform_priv; afe->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - afe->base_addr = devm_ioremap_resource(dev, res); + afe->base_addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(afe->base_addr)) return PTR_ERR(afe->base_addr); From 97b19db1cfb34303101a3f30c26ef0e2ede07d89 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 11 Jul 2023 11:48:44 +0800 Subject: [PATCH 105/334] ASoC: pxa: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230711034846.69437-4-frank.li@vivo.com Signed-off-by: Mark Brown --- sound/soc/pxa/pxa2xx-i2s.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 3e4c70403672..10636506b622 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -370,18 +370,11 @@ static const struct snd_soc_component_driver pxa_i2s_component = { static int pxa2xx_i2s_drv_probe(struct platform_device *pdev) { - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct resource *res; - if (!res) { - dev_err(&pdev->dev, "missing MMIO resource\n"); - return -ENXIO; - } - - i2s_reg_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(i2s_reg_base)) { - dev_err(&pdev->dev, "ioremap failed\n"); + i2s_reg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(i2s_reg_base)) return PTR_ERR(i2s_reg_base); - } pxa2xx_i2s_pcm_stereo_out.addr = res->start + SADR; pxa2xx_i2s_pcm_stereo_in.addr = res->start + SADR; From 976201dd5f597b7c25b9fc5ebeee382b5e6bf8fb Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 11 Jul 2023 11:48:45 +0800 Subject: [PATCH 106/334] ASoC: tegra: tegra20_ac97: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20230711034846.69437-5-frank.li@vivo.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_ac97.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c index a4073a746ae3..60e7df41c64c 100644 --- a/sound/soc/tegra/tegra20_ac97.c +++ b/sound/soc/tegra/tegra20_ac97.c @@ -328,8 +328,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev) goto err; } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, mem); + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); if (IS_ERR(regs)) { ret = PTR_ERR(regs); goto err_clk_put; From e0c90edb5f491e2664b5f7922c3a6868fe06ada1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 7 Jul 2023 16:17:25 -0600 Subject: [PATCH 107/334] ASoC: dt-bindings: audio-graph-card2: Drop incomplete example The example in audio-graph-card2 binding is incomplete, uses undocumented compatibles strings, and doesn't follow typical .dts formatting. Rather than try to fix with what would probably be a lengthy example, just drop the example. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230707221725.1071292-1-robh@kernel.org Signed-off-by: Mark Brown --- .../bindings/sound/audio-graph-card2.yaml | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/audio-graph-card2.yaml b/Documentation/devicetree/bindings/sound/audio-graph-card2.yaml index 3de7b36829da..d3ce4de449d5 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph-card2.yaml +++ b/Documentation/devicetree/bindings/sound/audio-graph-card2.yaml @@ -39,22 +39,4 @@ required: additionalProperties: false -examples: - - | - sound { - compatible = "audio-graph-card2"; - - links = <&cpu_port>; - }; - - cpu { - compatible = "cpu-driver"; - - cpu_port: port { cpu_ep: endpoint { remote-endpoint = <&codec_ep>; }; }; - }; - - codec { - compatible = "codec-driver"; - - port { codec_ep: endpoint { remote-endpoint = <&cpu_ep>; }; }; - }; +... From c960b012ec4747265f0392a31570045d3f982447 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sat, 15 Jul 2023 18:07:38 +0200 Subject: [PATCH 108/334] ALSA: emu10k1: track loss of external clock on E-MU cards 85;95;0c This uses IRQs to track spontaneous changes to the word clock source register. FWIW, that this can happen in the first place is the reason why it is futile to lock the clock source mixer setting while the device is open - we can't consistently control the rate anyway. Though arguably, we should reset any open streams when that happens, as they become corrupted anyway. Signed-off-by: Oswald Buddenhagen Link: https://lore.kernel.org/r/20230715160738.326832-1-oswald.buddenhagen@gmx.de Signed-off-by: Takashi Iwai --- include/sound/emu10k1.h | 5 +++++ sound/pci/emu10k1/emu10k1.c | 1 + sound/pci/emu10k1/emu10k1_main.c | 30 +++++++++++++++++++++++++++++- sound/pci/emu10k1/emumixer.c | 12 ++++++++---- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 43c097952c3c..7c55a8244747 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -992,6 +992,9 @@ SUB_REG_NC(A_EHC, A_I2S_CAPTURE_RATE, 0x00000e00) /* This sets the capture PCM #define EMU_HANA_WCLOCK_4X 0x10 #define EMU_HANA_WCLOCK_MULT_RESERVED 0x18 +// If the selected external clock source is/becomes invalid or incompatible +// with the clock multiplier, the clock source is reset to this value, and +// a WCLK_CHANGED interrupt is raised. #define EMU_HANA_DEFCLOCK 0x06 /* 000000x 1 bits Default Word Clock */ #define EMU_HANA_DEFCLOCK_48K 0x00 #define EMU_HANA_DEFCLOCK_44_1K 0x01 @@ -1679,6 +1682,7 @@ struct snd_emu1010 { unsigned int optical_in; /* 0:SPDIF, 1:ADAT */ unsigned int optical_out; /* 0:SPDIF, 1:ADAT */ struct work_struct firmware_work; + struct work_struct clock_work; }; struct snd_emu10k1 { @@ -1753,6 +1757,7 @@ struct snd_emu10k1 { struct snd_kcontrol *ctl_efx_send_routing; struct snd_kcontrol *ctl_efx_send_volume; struct snd_kcontrol *ctl_efx_attn; + struct snd_kcontrol *ctl_clock_source; void (*hwvol_interrupt)(struct snd_emu10k1 *emu, unsigned int status); void (*capture_interrupt)(struct snd_emu10k1 *emu, unsigned int status); diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 1a13c086e86c..421053569aa0 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -192,6 +192,7 @@ static int snd_emu10k1_suspend(struct device *dev) emu->suspend = 1; cancel_work_sync(&emu->emu1010.firmware_work); + cancel_work_sync(&emu->emu1010.clock_work); snd_ac97_suspend(emu->ac97); diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index a11fcba4b9af..604645bfc908 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -789,6 +789,30 @@ static void emu1010_firmware_work(struct work_struct *work) } } +static void emu1010_clock_work(struct work_struct *work) +{ + struct snd_emu10k1 *emu; + struct snd_ctl_elem_id id; + + emu = container_of(work, struct snd_emu10k1, + emu1010.clock_work); + if (emu->card->shutdown) + return; +#ifdef CONFIG_PM_SLEEP + if (emu->suspend) + return; +#endif + + spin_lock_irq(&emu->reg_lock); + // This is the only thing that can actually happen. + emu->emu1010.clock_source = emu->emu1010.clock_fallback; + emu->emu1010.wclock = 1 - emu->emu1010.clock_source; + snd_emu1010_update_clock(emu); + spin_unlock_irq(&emu->reg_lock); + snd_ctl_build_ioff(&id, emu->ctl_clock_source, 0); + snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE, &id); +} + static void emu1010_interrupt(struct snd_emu10k1 *emu) { u32 sts; @@ -802,6 +826,8 @@ static void emu1010_interrupt(struct snd_emu10k1 *emu) } else if (sts & EMU_HANA_IRQ_DOCK) { schedule_work(&emu->emu1010.firmware_work); } + if (sts & EMU_HANA_IRQ_WCLK_CHANGED) + schedule_work(&emu->emu1010.clock_work); } /* @@ -901,7 +927,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) emu->gpio_interrupt = emu1010_interrupt; // Note: The Audigy INTE is set later snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, - EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST); + EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST | EMU_HANA_IRQ_WCLK_CHANGED); snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ®); // Clear pending IRQs emu->emu1010.clock_source = 1; /* 48000 */ @@ -943,6 +969,7 @@ static void snd_emu10k1_free(struct snd_card *card) snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0); } cancel_work_sync(&emu->emu1010.firmware_work); + cancel_work_sync(&emu->emu1010.clock_work); release_firmware(emu->firmware); release_firmware(emu->dock_fw); snd_util_memhdr_free(emu->memhdr); @@ -1522,6 +1549,7 @@ int snd_emu10k1_create(struct snd_card *card, emu->synth = NULL; emu->get_synth_voice = NULL; INIT_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work); + INIT_WORK(&emu->emu1010.clock_work, emu1010_clock_work); /* read revision & serial */ emu->revision = pci->revision; pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial); diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 9a94f08f2463..f39025748072 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -986,17 +986,21 @@ static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol, val = ucontrol->value.enumerated.item[0] ; if (val >= emu_ci->num) return -EINVAL; + spin_lock_irq(&emu->reg_lock); change = (emu->emu1010.clock_source != val); if (change) { emu->emu1010.clock_source = val; emu->emu1010.wclock = emu_ci->vals[val]; + snd_emu1010_update_clock(emu); snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE); snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, emu->emu1010.wclock); + spin_unlock_irq(&emu->reg_lock); + msleep(10); // Allow DLL to settle snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); - - snd_emu1010_update_clock(emu); + } else { + spin_unlock_irq(&emu->reg_lock); } return change; } @@ -2336,8 +2340,8 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, emu1010_map_source(emu_ri, emu_ri->out_dflts[i]); snd_emu1010_apply_sources(emu); - err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1010_clock_source, emu)); + kctl = emu->ctl_clock_source = snd_ctl_new1(&snd_emu1010_clock_source, emu); + err = snd_ctl_add(card, kctl); if (err < 0) return err; err = snd_ctl_add(card, From c435d375fd76733218ff59408a4b1f15e50b2e11 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sat, 15 Jul 2023 18:08:02 +0200 Subject: [PATCH 109/334] ALSA: emu10k1: set the "no filtering" bits on PCM voices on Audigy Given that the filter is already set to neutral for PCM voices, the only observable effect is that the Z1/Z2/FXBUS registers don't have a stray bit set for negative numbers anymore. The bit is below the ones significant for output, but it would mess with 32-bit sample recombination, which we intend to add. kX-project does that, but I had to figure out myself why. Signed-off-by: Oswald Buddenhagen Link: https://lore.kernel.org/r/20230715160802.326872-1-oswald.buddenhagen@gmx.de Signed-off-by: Takashi Iwai --- include/sound/emu10k1.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 7c55a8244747..1af9e6819392 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -902,6 +902,11 @@ SUB_REG_NC(A_EHC, A_I2S_CAPTURE_RATE, 0x00000e00) /* This sets the capture PCM #define A_TTDA 0x7a /* Tank Table DMA Address */ #define A_TTDD 0x7b /* Tank Table DMA Data */ +// In A_FXRT1 & A_FXRT2, the 0x80 bit of each byte completely disables the +// filter (CVCF_CURRENTFILTER) for the corresponding channel. There is no +// effect on the volume (CVCF_CURRENTVOLUME) or the interpolator's filter +// (CCCA_INTERPROM_MASK). + #define A_FXRT2 0x7c #define A_FXRT_CHANNELE 0x0000003f /* Effects send bus number for channel's effects send E */ #define A_FXRT_CHANNELF 0x00003f00 /* Effects send bus number for channel's effects send F */ @@ -914,8 +919,6 @@ SUB_REG_NC(A_EHC, A_I2S_CAPTURE_RATE, 0x00000e00) /* This sets the capture PCM #define A_FXSENDAMOUNT_G_MASK 0x0000FF00 #define A_FXSENDAMOUNT_H_MASK 0x000000FF -/* 0x7c, 0x7e "high bit is used for filtering" */ - /* The send amounts for this one are the same as used with the emu10k1 */ #define A_FXRT1 0x7e #define A_FXRT_CHANNELA 0x0000003f @@ -1526,10 +1529,10 @@ struct snd_emu10k1_pcm_mixer { ((route[0] | (route[1] << 4) | (route[2] << 8) | (route[3] << 12)) << 16) #define snd_emu10k1_compose_audigy_fxrt1(route) \ -((unsigned int)route[0] | ((unsigned int)route[1] << 8) | ((unsigned int)route[2] << 16) | ((unsigned int)route[3] << 24)) +((unsigned int)route[0] | ((unsigned int)route[1] << 8) | ((unsigned int)route[2] << 16) | ((unsigned int)route[3] << 24) | 0x80808080) #define snd_emu10k1_compose_audigy_fxrt2(route) \ -((unsigned int)route[4] | ((unsigned int)route[5] << 8) | ((unsigned int)route[6] << 16) | ((unsigned int)route[7] << 24)) +((unsigned int)route[4] | ((unsigned int)route[5] << 8) | ((unsigned int)route[6] << 16) | ((unsigned int)route[7] << 24) | 0x80808080) #define snd_emu10k1_compose_audigy_sendamounts(vol) \ (((unsigned int)vol[4] << 24) | ((unsigned int)vol[5] << 16) | ((unsigned int)vol[6] << 8) | (unsigned int)vol[7]) From 9034ff11693b0246ef0e2bd5b69b2686c429070f Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sat, 15 Jul 2023 18:08:38 +0200 Subject: [PATCH 110/334] ALSA: emu10k1: clean up driver status comments Empty BUGS and TODO sections don't really help anyone, so remove them. Version information is chronically outdated, and not really useful in a git world anyway, so remove it as well. Also remove duplicated (and outdated, of course) status section from p16v.h (the one in p16v.c is in better shape). Signed-off-by: Oswald Buddenhagen Link: https://lore.kernel.org/r/20230715160839.326978-1-oswald.buddenhagen@gmx.de Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1_main.c | 6 ---- sound/pci/emu10k1/emufx.c | 6 ---- sound/pci/emu10k1/emumixer.c | 6 ---- sound/pci/emu10k1/emupcm.c | 6 ---- sound/pci/emu10k1/emuproc.c | 6 ---- sound/pci/emu10k1/io.c | 6 ---- sound/pci/emu10k1/irq.c | 6 ---- sound/pci/emu10k1/p16v.h | 56 -------------------------------- sound/pci/emu10k1/p17v.h | 1 - sound/pci/emu10k1/timer.c | 6 ---- sound/pci/emu10k1/tina2.h | 1 - sound/pci/emu10k1/voice.c | 6 ---- 12 files changed, 112 deletions(-) diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 604645bfc908..29f7ad70941d 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -8,12 +8,6 @@ * Added support for Audigy 2 Value. * Added EMU 1010 support. * General bug fixes and enhancements. - * - * BUGS: - * -- - * - * TODO: - * -- */ #include diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 9904bcfee106..e0ad339c5bbf 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -6,12 +6,6 @@ * * Copyright (c) by James Courtier-Dutton * Added EMU 1010 support. - * - * BUGS: - * -- - * - * TODO: - * -- */ #include diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index f39025748072..4bf2014fba70 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -8,12 +8,6 @@ * * Copyright (c) by James Courtier-Dutton * Added EMU 1010 support. - * - * BUGS: - * -- - * - * TODO: - * -- */ #include diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 8b3d1b35d6e7..7a1d448f0656 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -4,12 +4,6 @@ * Creative Labs, Inc. * Routines for control of EMU10K1 chips / PCM routines * Multichannel PCM support Copyright (c) Lee Revell - * - * BUGS: - * -- - * - * TODO: - * -- */ #include diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 5533277e4d47..39b422297c70 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -6,12 +6,6 @@ * * Copyright (c) by James Courtier-Dutton * Added EMU 1010 support. - * - * BUGS: - * -- - * - * TODO: - * -- */ #include diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index c695cb863e5e..7e4483c5bd2a 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -3,12 +3,6 @@ * Copyright (c) by Jaroslav Kysela * Creative Labs, Inc. * Routines for control of EMU10K1 chips - * - * BUGS: - * -- - * - * TODO: - * -- */ #include diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c index 8573248dd799..71aa90b9cc88 100644 --- a/sound/pci/emu10k1/irq.c +++ b/sound/pci/emu10k1/irq.c @@ -3,12 +3,6 @@ * Copyright (c) by Jaroslav Kysela * Creative Labs, Inc. * Routines for IRQ control of EMU10K1 chips - * - * BUGS: - * -- - * - * TODO: - * -- */ #include diff --git a/sound/pci/emu10k1/p16v.h b/sound/pci/emu10k1/p16v.h index 9d429ad1feff..95ab8071751b 100644 --- a/sound/pci/emu10k1/p16v.h +++ b/sound/pci/emu10k1/p16v.h @@ -2,62 +2,6 @@ /* * Copyright (c) by James Courtier-Dutton * Driver p16v chips - * Version: 0.21 - * - * FEATURES currently supported: - * Output fixed at S32_LE, 2 channel to hw:0,0 - * Rates: 44.1, 48, 96, 192. - * - * Changelog: - * 0.8 - * Use separate card based buffer for periods table. - * 0.9 - * Use 2 channel output streams instead of 8 channel. - * (8 channel output streams might be good for ASIO type output) - * Corrected speaker output, so Front -> Front etc. - * 0.10 - * Fixed missed interrupts. - * 0.11 - * Add Sound card model number and names. - * Add Analog volume controls. - * 0.12 - * Corrected playback interrupts. Now interrupt per period, instead of half period. - * 0.13 - * Use single trigger for multichannel. - * 0.14 - * Mic capture now works at fixed: S32_LE, 96000Hz, Stereo. - * 0.15 - * Force buffer_size / period_size == INTEGER. - * 0.16 - * Update p16v.c to work with changed alsa api. - * 0.17 - * Update p16v.c to work with changed alsa api. Removed boot_devs. - * 0.18 - * Merging with snd-emu10k1 driver. - * 0.19 - * One stereo channel at 24bit now works. - * 0.20 - * Added better register defines. - * 0.21 - * Split from p16v.c - * - * BUGS: - * Some stability problems when unloading the snd-p16v kernel module. - * -- - * - * TODO: - * SPDIF out. - * Find out how to change capture sample rates. E.g. To record SPDIF at 48000Hz. - * Currently capture fixed at 48000Hz. - * - * -- - * GENERAL INFO: - * Model: SB0240 - * P16V Chip: CA0151-DBS - * Audigy 2 Chip: CA0102-IAT - * AC97 Codec: STAC 9721 - * ADC: Philips 1361T (Stereo 24bit) - * DAC: CS4382-K (8-channel, 24bit, 192Khz) * * This code was initially based on code from ALSA's emu10k1x.c which is: * Copyright (c) by Francisco Moraes diff --git a/sound/pci/emu10k1/p17v.h b/sound/pci/emu10k1/p17v.h index d4ada1c430c8..ee4f4ab4b79c 100644 --- a/sound/pci/emu10k1/p17v.h +++ b/sound/pci/emu10k1/p17v.h @@ -2,7 +2,6 @@ /* * Copyright (c) by James Courtier-Dutton * Driver p17v chips - * Version: 0.01 */ /******************************************************************************/ diff --git a/sound/pci/emu10k1/timer.c b/sound/pci/emu10k1/timer.c index f3c78adf3248..8798604e7f98 100644 --- a/sound/pci/emu10k1/timer.c +++ b/sound/pci/emu10k1/timer.c @@ -3,12 +3,6 @@ * Copyright (c) by Lee Revell * Clemens Ladisch * Routines for control of EMU10K1 chips - * - * BUGS: - * -- - * - * TODO: - * -- */ #include diff --git a/sound/pci/emu10k1/tina2.h b/sound/pci/emu10k1/tina2.h index 7fd235345292..e3fcb290271c 100644 --- a/sound/pci/emu10k1/tina2.h +++ b/sound/pci/emu10k1/tina2.h @@ -2,7 +2,6 @@ /* * Copyright (c) by James Courtier-Dutton * Driver tina2 chips - * Version: 0.1 */ /********************************************************************************************************/ diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c index 6939498e26f0..ffe87f359a0e 100644 --- a/sound/pci/emu10k1/voice.c +++ b/sound/pci/emu10k1/voice.c @@ -6,12 +6,6 @@ * Routines for control of EMU10K1 chips - voice manager * * Rewrote voice allocator for multichannel support - rlrevell 12/2004 - * - * BUGS: - * -- - * - * TODO: - * -- */ #include From 6d68d9cba1d0d1ee628a783eb9e7d38a0c3691b8 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sat, 15 Jul 2023 18:08:39 +0200 Subject: [PATCH 111/334] ALSA: emu10k1: rework copyright statements - Remove the "log-like" parts, following the same logic as the previous commit - Unify format - Add missing major contributors, including myself - Sort entries in order of first contribution (Creative comes last for optical reasons; they don't appear to have directly contributed anyway) Signed-off-by: Oswald Buddenhagen Link: https://lore.kernel.org/r/20230715160839.326978-2-oswald.buddenhagen@gmx.de Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1.c | 4 +--- sound/pci/emu10k1/emu10k1_main.c | 8 +++----- sound/pci/emu10k1/emufx.c | 6 +++--- sound/pci/emu10k1/emumixer.c | 8 ++++---- sound/pci/emu10k1/emupcm.c | 5 ++++- sound/pci/emu10k1/emuproc.c | 7 ++++--- sound/pci/emu10k1/io.c | 4 ++++ sound/pci/emu10k1/timer.c | 2 ++ sound/pci/emu10k1/voice.c | 6 +++--- 9 files changed, 28 insertions(+), 22 deletions(-) diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 421053569aa0..fe72e7d77241 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -2,9 +2,7 @@ /* * The driver for the EMU10K1 (SB Live!) based soundcards * Copyright (c) by Jaroslav Kysela - * - * Copyright (c) by James Courtier-Dutton - * Added support for Audigy 2 Value. + * James Courtier-Dutton */ #include diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 29f7ad70941d..de5c41e578e1 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1,13 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) by Jaroslav Kysela + * James Courtier-Dutton + * Oswald Buddenhagen * Creative Labs, Inc. - * Routines for control of EMU10K1 chips * - * Copyright (c) by James Courtier-Dutton - * Added support for Audigy 2 Value. - * Added EMU 1010 support. - * General bug fixes and enhancements. + * Routines for control of EMU10K1 chips */ #include diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index e0ad339c5bbf..347141635604 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) by Jaroslav Kysela + * James Courtier-Dutton + * Oswald Buddenhagen * Creative Labs, Inc. - * Routines for effect processor FX8010 * - * Copyright (c) by James Courtier-Dutton - * Added EMU 1010 support. + * Routines for effect processor FX8010 */ #include diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 4bf2014fba70..f72a01f8f8f2 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -2,12 +2,12 @@ /* * Copyright (c) by Jaroslav Kysela , * Takashi Iwai + * Lee Revell + * James Courtier-Dutton + * Oswald Buddenhagen * Creative Labs, Inc. - * Routines for control of EMU10K1 chips / mixer routines - * Multichannel PCM support Copyright (c) Lee Revell * - * Copyright (c) by James Courtier-Dutton - * Added EMU 1010 support. + * Routines for control of EMU10K1 chips / mixer routines */ #include diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 7a1d448f0656..7f4c1b38d6ec 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1,9 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) by Jaroslav Kysela + * Lee Revell + * James Courtier-Dutton + * Oswald Buddenhagen * Creative Labs, Inc. + * * Routines for control of EMU10K1 chips / PCM routines - * Multichannel PCM support Copyright (c) Lee Revell */ #include diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 39b422297c70..2f80fd91017c 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -1,11 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) by Jaroslav Kysela + * Lee Revell + * James Courtier-Dutton + * Oswald Buddenhagen * Creative Labs, Inc. - * Routines for control of EMU10K1 chips / proc interface routines * - * Copyright (c) by James Courtier-Dutton - * Added EMU 1010 support. + * Routines for control of EMU10K1 chips / proc interface routines */ #include diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index 7e4483c5bd2a..74df2330015f 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -1,7 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) by Jaroslav Kysela + * Lee Revell + * James Courtier-Dutton + * Oswald Buddenhagen * Creative Labs, Inc. + * * Routines for control of EMU10K1 chips */ diff --git a/sound/pci/emu10k1/timer.c b/sound/pci/emu10k1/timer.c index 8798604e7f98..bb2478319361 100644 --- a/sound/pci/emu10k1/timer.c +++ b/sound/pci/emu10k1/timer.c @@ -2,6 +2,8 @@ /* * Copyright (c) by Lee Revell * Clemens Ladisch + * Oswald Buddenhagen + * * Routines for control of EMU10K1 chips */ diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c index ffe87f359a0e..77fb5427aaed 100644 --- a/sound/pci/emu10k1/voice.c +++ b/sound/pci/emu10k1/voice.c @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) by Jaroslav Kysela - * Creative Labs, Inc. * Lee Revell - * Routines for control of EMU10K1 chips - voice manager + * Oswald Buddenhagen + * Creative Labs, Inc. * - * Rewrote voice allocator for multichannel support - rlrevell 12/2004 + * Routines for control of EMU10K1 chips - voice manager */ #include From 8b30cdbe0b911562fc1496078162dc9547b69be5 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Thu, 13 Jul 2023 18:25:12 -0400 Subject: [PATCH 112/334] ASoC: codec: wm8960: add additional probe check for codec identification The wm8960 codec is not readable, resulting in a NACK for address 0x3d (8-bit). This can partially indicate it. For example: wm8962 codec use the same address but is readable. This additional probe check will help prevent loading the wm8960 module incorrectly on wm8962 hardware. Signed-off-by: Frank Li Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20230713222513.1636591-1-Frank.Li@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 366f5d769d6d..b2c1432d4f9b 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -1415,6 +1415,7 @@ static int wm8960_i2c_probe(struct i2c_client *i2c) struct wm8960_data *pdata = dev_get_platdata(&i2c->dev); struct wm8960_priv *wm8960; int ret; + u8 val; wm8960 = devm_kzalloc(&i2c->dev, sizeof(struct wm8960_priv), GFP_KERNEL); @@ -1436,6 +1437,12 @@ static int wm8960_i2c_probe(struct i2c_client *i2c) else if (i2c->dev.of_node) wm8960_set_pdata_from_of(i2c, &wm8960->pdata); + ret = i2c_master_recv(i2c, &val, sizeof(val)); + if (ret >= 0) { + dev_err(&i2c->dev, "Not wm8960, wm8960 reg can not read by i2c\n"); + return -EINVAL; + } + ret = wm8960_reset(wm8960->regmap); if (ret != 0) { dev_err(&i2c->dev, "Failed to issue reset\n"); From 97efc0aa96f990966fe584149afa1aadcf7b8568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Mon, 17 Jul 2023 13:44:57 +0200 Subject: [PATCH 113/334] PCI: Sort Intel PCI IDs by number MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some of the PCI IDs are not sorted correctly, reorder them by growing ID number. Reviewed-by: Andy Shevchenko Acked-by: Bjorn Helgaas Acked-by: Mark Brown Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20230717114511.484999-2-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- include/linux/pci_ids.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 2dc75df1437f..add7fb6bd844 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2677,8 +2677,6 @@ #define PCI_DEVICE_ID_INTEL_82815_MC 0x1130 #define PCI_DEVICE_ID_INTEL_82815_CGC 0x1132 #define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221 -#define PCI_DEVICE_ID_INTEL_7505_0 0x2550 -#define PCI_DEVICE_ID_INTEL_7205_0 0x255d #define PCI_DEVICE_ID_INTEL_82437 0x122d #define PCI_DEVICE_ID_INTEL_82371FB_0 0x122e #define PCI_DEVICE_ID_INTEL_82371FB_1 0x1230 @@ -2772,6 +2770,8 @@ #define PCI_DEVICE_ID_INTEL_82850_HB 0x2530 #define PCI_DEVICE_ID_INTEL_82860_HB 0x2531 #define PCI_DEVICE_ID_INTEL_E7501_MCH 0x254c +#define PCI_DEVICE_ID_INTEL_7505_0 0x2550 +#define PCI_DEVICE_ID_INTEL_7205_0 0x255d #define PCI_DEVICE_ID_INTEL_82845G_HB 0x2560 #define PCI_DEVICE_ID_INTEL_82845G_IG 0x2562 #define PCI_DEVICE_ID_INTEL_82865_HB 0x2570 @@ -2806,9 +2806,9 @@ #define PCI_DEVICE_ID_INTEL_3000_HB 0x2778 #define PCI_DEVICE_ID_INTEL_82945GM_HB 0x27a0 #define PCI_DEVICE_ID_INTEL_82945GM_IG 0x27a2 +#define PCI_DEVICE_ID_INTEL_ICH7_30 0x27b0 #define PCI_DEVICE_ID_INTEL_ICH7_0 0x27b8 #define PCI_DEVICE_ID_INTEL_ICH7_1 0x27b9 -#define PCI_DEVICE_ID_INTEL_ICH7_30 0x27b0 #define PCI_DEVICE_ID_INTEL_TGP_LPC 0x27bc #define PCI_DEVICE_ID_INTEL_ICH7_31 0x27bd #define PCI_DEVICE_ID_INTEL_ICH7_17 0x27da @@ -2824,14 +2824,14 @@ #define PCI_DEVICE_ID_INTEL_ICH8_6 0x2850 #define PCI_DEVICE_ID_INTEL_VMD_28C0 0x28c0 #define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910 -#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917 #define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912 #define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913 #define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914 +#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916 +#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917 +#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918 #define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919 #define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930 -#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916 -#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918 #define PCI_DEVICE_ID_INTEL_I7_MCR 0x2c18 #define PCI_DEVICE_ID_INTEL_I7_MC_TAD 0x2c19 #define PCI_DEVICE_ID_INTEL_I7_MC_RAS 0x2c1a @@ -2848,8 +2848,8 @@ #define PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR 0x2c31 #define PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK 0x2c32 #define PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC 0x2c33 -#define PCI_DEVICE_ID_INTEL_I7_NONCORE 0x2c41 #define PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT 0x2c40 +#define PCI_DEVICE_ID_INTEL_I7_NONCORE 0x2c41 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE 0x2c50 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT 0x2c51 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2 0x2c70 @@ -2895,10 +2895,10 @@ #define PCI_DEVICE_ID_INTEL_IOAT_TBG3 0x3433 #define PCI_DEVICE_ID_INTEL_82830_HB 0x3575 #define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577 -#define PCI_DEVICE_ID_INTEL_82854_HB 0x358c -#define PCI_DEVICE_ID_INTEL_82854_IG 0x358e #define PCI_DEVICE_ID_INTEL_82855GM_HB 0x3580 #define PCI_DEVICE_ID_INTEL_82855GM_IG 0x3582 +#define PCI_DEVICE_ID_INTEL_82854_HB 0x358c +#define PCI_DEVICE_ID_INTEL_82854_IG 0x358e #define PCI_DEVICE_ID_INTEL_E7520_MCH 0x3590 #define PCI_DEVICE_ID_INTEL_E7320_MCH 0x3592 #define PCI_DEVICE_ID_INTEL_MCH_PA 0x3595 @@ -2908,11 +2908,11 @@ #define PCI_DEVICE_ID_INTEL_MCH_PC 0x3599 #define PCI_DEVICE_ID_INTEL_MCH_PC1 0x359a #define PCI_DEVICE_ID_INTEL_E7525_MCH 0x359e +#define PCI_DEVICE_ID_INTEL_IOAT_CNB 0x360b +#define PCI_DEVICE_ID_INTEL_FBD_CNB 0x360c #define PCI_DEVICE_ID_INTEL_I7300_MCH_ERR 0x360c #define PCI_DEVICE_ID_INTEL_I7300_MCH_FB0 0x360f #define PCI_DEVICE_ID_INTEL_I7300_MCH_FB1 0x3610 -#define PCI_DEVICE_ID_INTEL_IOAT_CNB 0x360b -#define PCI_DEVICE_ID_INTEL_FBD_CNB 0x360c #define PCI_DEVICE_ID_INTEL_IOAT_JSF0 0x3710 #define PCI_DEVICE_ID_INTEL_IOAT_JSF1 0x3711 #define PCI_DEVICE_ID_INTEL_IOAT_JSF2 0x3712 @@ -2943,16 +2943,12 @@ #define PCI_DEVICE_ID_INTEL_IOAT_SNB7 0x3c27 #define PCI_DEVICE_ID_INTEL_IOAT_SNB8 0x3c2e #define PCI_DEVICE_ID_INTEL_IOAT_SNB9 0x3c2f -#define PCI_DEVICE_ID_INTEL_UNC_HA 0x3c46 -#define PCI_DEVICE_ID_INTEL_UNC_IMC0 0x3cb0 -#define PCI_DEVICE_ID_INTEL_UNC_IMC1 0x3cb1 -#define PCI_DEVICE_ID_INTEL_UNC_IMC2 0x3cb4 -#define PCI_DEVICE_ID_INTEL_UNC_IMC3 0x3cb5 #define PCI_DEVICE_ID_INTEL_UNC_QPI0 0x3c41 #define PCI_DEVICE_ID_INTEL_UNC_QPI1 0x3c42 #define PCI_DEVICE_ID_INTEL_UNC_R2PCIE 0x3c43 #define PCI_DEVICE_ID_INTEL_UNC_R3QPI0 0x3c44 #define PCI_DEVICE_ID_INTEL_UNC_R3QPI1 0x3c45 +#define PCI_DEVICE_ID_INTEL_UNC_HA 0x3c46 #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS 0x3c71 /* 15.1 */ #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR0 0x3c72 /* 16.2 */ #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR1 0x3c73 /* 16.3 */ @@ -2964,6 +2960,10 @@ #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1 0x3cab /* 15.3 */ #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2 0x3cac /* 15.4 */ #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3 0x3cad /* 15.5 */ +#define PCI_DEVICE_ID_INTEL_UNC_IMC0 0x3cb0 +#define PCI_DEVICE_ID_INTEL_UNC_IMC1 0x3cb1 +#define PCI_DEVICE_ID_INTEL_UNC_IMC2 0x3cb4 +#define PCI_DEVICE_ID_INTEL_UNC_IMC3 0x3cb5 #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO 0x3cb8 /* 17.0 */ #define PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX 0x3ce0 #define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0 0x3cf4 /* 12.6 */ From 2407c45329ddfac0b760d2095c484b371dec8ec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Mon, 17 Jul 2023 13:44:58 +0200 Subject: [PATCH 114/334] PCI: Add Intel Audio DSP devices to pci_ids.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Those IDs are mostly sprinkled between HDA, Skylake, SOF and avs drivers. Almost every use contains additional comments to identify to which platform those IDs refer to. Add those IDs to pci_ids.h header, so that there is one place which defines those names. Acked-by: Mark Brown Acked-by: Bjorn Helgaas Reviewed-by: Andy Shevchenko # for the Intel Tangier ID Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20230717114511.484999-3-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- include/linux/pci_ids.h | 73 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index add7fb6bd844..3066660cd39b 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2644,6 +2644,7 @@ #define PCI_VENDOR_ID_INTEL 0x8086 #define PCI_DEVICE_ID_INTEL_EESSC 0x0008 +#define PCI_DEVICE_ID_INTEL_HDA_CML_LP 0x02c8 #define PCI_DEVICE_ID_INTEL_PXHD_0 0x0320 #define PCI_DEVICE_ID_INTEL_PXHD_1 0x0321 #define PCI_DEVICE_ID_INTEL_PXH_0 0x0329 @@ -2659,8 +2660,10 @@ #define PCI_DEVICE_ID_INTEL_82424 0x0483 #define PCI_DEVICE_ID_INTEL_82378 0x0484 #define PCI_DEVICE_ID_INTEL_82425 0x0486 +#define PCI_DEVICE_ID_INTEL_HDA_CML_H 0x06c8 #define PCI_DEVICE_ID_INTEL_MRST_SD0 0x0807 #define PCI_DEVICE_ID_INTEL_MRST_SD1 0x0808 +#define PCI_DEVICE_ID_INTEL_HDA_OAKTRAIL 0x080a #define PCI_DEVICE_ID_INTEL_MFD_SD 0x0820 #define PCI_DEVICE_ID_INTEL_MFD_SDIO1 0x0821 #define PCI_DEVICE_ID_INTEL_MFD_SDIO2 0x0822 @@ -2670,12 +2673,18 @@ #define PCI_DEVICE_ID_INTEL_QUARK_X1000_ILB 0x095e #define PCI_DEVICE_ID_INTEL_I960 0x0960 #define PCI_DEVICE_ID_INTEL_I960RM 0x0962 +#define PCI_DEVICE_ID_INTEL_HDA_HSW_0 0x0a0c +#define PCI_DEVICE_ID_INTEL_HDA_HSW_2 0x0c0c #define PCI_DEVICE_ID_INTEL_CENTERTON_ILB 0x0c60 +#define PCI_DEVICE_ID_INTEL_HDA_HSW_3 0x0d0c +#define PCI_DEVICE_ID_INTEL_HDA_BYT 0x0f04 +#define PCI_DEVICE_ID_INTEL_SST_BYT 0x0f28 #define PCI_DEVICE_ID_INTEL_8257X_SOL 0x1062 #define PCI_DEVICE_ID_INTEL_82573E_SOL 0x1085 #define PCI_DEVICE_ID_INTEL_82573L_SOL 0x108f #define PCI_DEVICE_ID_INTEL_82815_MC 0x1130 #define PCI_DEVICE_ID_INTEL_82815_CGC 0x1132 +#define PCI_DEVICE_ID_INTEL_SST_TNG 0x119a #define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221 #define PCI_DEVICE_ID_INTEL_82437 0x122d #define PCI_DEVICE_ID_INTEL_82371FB_0 0x122e @@ -2702,20 +2711,26 @@ #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_BRIDGE 0x1576 #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_NHI 0x1577 #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_BRIDGE 0x1578 +#define PCI_DEVICE_ID_INTEL_HDA_BDW 0x160c #define PCI_DEVICE_ID_INTEL_80960_RP 0x1960 #define PCI_DEVICE_ID_INTEL_QAT_C3XXX 0x19e2 #define PCI_DEVICE_ID_INTEL_QAT_C3XXX_VF 0x19e3 #define PCI_DEVICE_ID_INTEL_82840_HB 0x1a21 #define PCI_DEVICE_ID_INTEL_82845_HB 0x1a30 #define PCI_DEVICE_ID_INTEL_IOAT 0x1a38 +#define PCI_DEVICE_ID_INTEL_HDA_CPT 0x1c20 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN 0x1c41 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX 0x1c5f +#define PCI_DEVICE_ID_INTEL_HDA_PBG 0x1d20 #define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_0 0x1d40 #define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_1 0x1d41 +#define PCI_DEVICE_ID_INTEL_HDA_PPT 0x1e20 #define PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI 0x1e31 #define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MIN 0x1e40 #define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX 0x1e5f #define PCI_DEVICE_ID_INTEL_VMD_201D 0x201d +#define PCI_DEVICE_ID_INTEL_HDA_BSW 0x2284 +#define PCI_DEVICE_ID_INTEL_SST_BSW 0x22a8 #define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MIN 0x2310 #define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MAX 0x231f #define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410 @@ -2793,12 +2808,14 @@ #define PCI_DEVICE_ID_INTEL_ICH6_0 0x2640 #define PCI_DEVICE_ID_INTEL_ICH6_1 0x2641 #define PCI_DEVICE_ID_INTEL_ICH6_2 0x2642 +#define PCI_DEVICE_ID_INTEL_HDA_ICH6 0x2668 #define PCI_DEVICE_ID_INTEL_ICH6_16 0x266a #define PCI_DEVICE_ID_INTEL_ICH6_17 0x266d #define PCI_DEVICE_ID_INTEL_ICH6_18 0x266e #define PCI_DEVICE_ID_INTEL_ICH6_19 0x266f #define PCI_DEVICE_ID_INTEL_ESB2_0 0x2670 #define PCI_DEVICE_ID_INTEL_ESB2_14 0x2698 +#define PCI_DEVICE_ID_INTEL_HDA_ESB2 0x269a #define PCI_DEVICE_ID_INTEL_ESB2_17 0x269b #define PCI_DEVICE_ID_INTEL_ESB2_18 0x269e #define PCI_DEVICE_ID_INTEL_82945G_HB 0x2770 @@ -2811,6 +2828,7 @@ #define PCI_DEVICE_ID_INTEL_ICH7_1 0x27b9 #define PCI_DEVICE_ID_INTEL_TGP_LPC 0x27bc #define PCI_DEVICE_ID_INTEL_ICH7_31 0x27bd +#define PCI_DEVICE_ID_INTEL_HDA_ICH7 0x27d8 #define PCI_DEVICE_ID_INTEL_ICH7_17 0x27da #define PCI_DEVICE_ID_INTEL_ICH7_19 0x27dd #define PCI_DEVICE_ID_INTEL_ICH7_20 0x27de @@ -2821,6 +2839,7 @@ #define PCI_DEVICE_ID_INTEL_ICH8_3 0x2814 #define PCI_DEVICE_ID_INTEL_ICH8_4 0x2815 #define PCI_DEVICE_ID_INTEL_ICH8_5 0x283e +#define PCI_DEVICE_ID_INTEL_HDA_ICH8 0x284b #define PCI_DEVICE_ID_INTEL_ICH8_6 0x2850 #define PCI_DEVICE_ID_INTEL_VMD_28C0 0x28c0 #define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910 @@ -2832,6 +2851,8 @@ #define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918 #define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919 #define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930 +#define PCI_DEVICE_ID_INTEL_HDA_ICH9_0 0x293e +#define PCI_DEVICE_ID_INTEL_HDA_ICH9_1 0x293f #define PCI_DEVICE_ID_INTEL_I7_MCR 0x2c18 #define PCI_DEVICE_ID_INTEL_I7_MC_TAD 0x2c19 #define PCI_DEVICE_ID_INTEL_I7_MC_RAS 0x2c1a @@ -2883,6 +2904,7 @@ #define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2 0x2db1 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2 0x2db2 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2 0x2db3 +#define PCI_DEVICE_ID_INTEL_HDA_GML 0x3198 #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 #define PCI_DEVICE_ID_INTEL_IOAT_TBG4 0x3429 #define PCI_DEVICE_ID_INTEL_IOAT_TBG5 0x342a @@ -2893,6 +2915,7 @@ #define PCI_DEVICE_ID_INTEL_IOAT_TBG1 0x3431 #define PCI_DEVICE_ID_INTEL_IOAT_TBG2 0x3432 #define PCI_DEVICE_ID_INTEL_IOAT_TBG3 0x3433 +#define PCI_DEVICE_ID_INTEL_HDA_ICL_LP 0x34c8 #define PCI_DEVICE_ID_INTEL_82830_HB 0x3575 #define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577 #define PCI_DEVICE_ID_INTEL_82855GM_HB 0x3580 @@ -2925,14 +2948,19 @@ #define PCI_DEVICE_ID_INTEL_IOAT_JSF9 0x3719 #define PCI_DEVICE_ID_INTEL_QAT_C62X 0x37c8 #define PCI_DEVICE_ID_INTEL_QAT_C62X_VF 0x37c9 +#define PCI_DEVICE_ID_INTEL_HDA_ICL_N 0x38c8 #define PCI_DEVICE_ID_INTEL_ICH10_0 0x3a14 #define PCI_DEVICE_ID_INTEL_ICH10_1 0x3a16 #define PCI_DEVICE_ID_INTEL_ICH10_2 0x3a18 #define PCI_DEVICE_ID_INTEL_ICH10_3 0x3a1a #define PCI_DEVICE_ID_INTEL_ICH10_4 0x3a30 +#define PCI_DEVICE_ID_INTEL_HDA_ICH10_0 0x3a3e #define PCI_DEVICE_ID_INTEL_ICH10_5 0x3a60 +#define PCI_DEVICE_ID_INTEL_HDA_ICH10_1 0x3a6e #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN 0x3b00 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX 0x3b1f +#define PCI_DEVICE_ID_INTEL_HDA_5_3400_SERIES_0 0x3b56 +#define PCI_DEVICE_ID_INTEL_HDA_5_3400_SERIES_1 0x3b57 #define PCI_DEVICE_ID_INTEL_IOAT_SNB0 0x3c20 #define PCI_DEVICE_ID_INTEL_IOAT_SNB1 0x3c21 #define PCI_DEVICE_ID_INTEL_IOAT_SNB2 0x3c22 @@ -2969,12 +2997,31 @@ #define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0 0x3cf4 /* 12.6 */ #define PCI_DEVICE_ID_INTEL_SBRIDGE_BR 0x3cf5 /* 13.6 */ #define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1 0x3cf6 /* 12.7 */ +#define PCI_DEVICE_ID_INTEL_HDA_ICL_H 0x3dc8 #define PCI_DEVICE_ID_INTEL_IOAT_SNB 0x402f #define PCI_DEVICE_ID_INTEL_5400_ERR 0x4030 #define PCI_DEVICE_ID_INTEL_5400_FBD0 0x4035 #define PCI_DEVICE_ID_INTEL_5400_FBD1 0x4036 +#define PCI_DEVICE_ID_INTEL_HDA_TGL_H 0x43c8 +#define PCI_DEVICE_ID_INTEL_HDA_DG1 0x490d +#define PCI_DEVICE_ID_INTEL_HDA_EHL_0 0x4b55 +#define PCI_DEVICE_ID_INTEL_HDA_EHL_3 0x4b58 +#define PCI_DEVICE_ID_INTEL_HDA_JSL_N 0x4dc8 +#define PCI_DEVICE_ID_INTEL_HDA_DG2_0 0x4f90 +#define PCI_DEVICE_ID_INTEL_HDA_DG2_1 0x4f91 +#define PCI_DEVICE_ID_INTEL_HDA_DG2_2 0x4f92 #define PCI_DEVICE_ID_INTEL_EP80579_0 0x5031 #define PCI_DEVICE_ID_INTEL_EP80579_1 0x5032 +#define PCI_DEVICE_ID_INTEL_HDA_ADL_P 0x51c8 +#define PCI_DEVICE_ID_INTEL_HDA_ADL_PS 0x51c9 +#define PCI_DEVICE_ID_INTEL_HDA_RPL_P_0 0x51ca +#define PCI_DEVICE_ID_INTEL_HDA_RPL_P_1 0x51cb +#define PCI_DEVICE_ID_INTEL_HDA_ADL_M 0x51cc +#define PCI_DEVICE_ID_INTEL_HDA_ADL_PX 0x51cd +#define PCI_DEVICE_ID_INTEL_HDA_RPL_M 0x51ce +#define PCI_DEVICE_ID_INTEL_HDA_RPL_PX 0x51cf +#define PCI_DEVICE_ID_INTEL_HDA_ADL_N 0x54c8 +#define PCI_DEVICE_ID_INTEL_HDA_APL 0x5a98 #define PCI_DEVICE_ID_INTEL_5100_16 0x65f0 #define PCI_DEVICE_ID_INTEL_5100_19 0x65f3 #define PCI_DEVICE_ID_INTEL_5100_21 0x65f5 @@ -3008,8 +3055,12 @@ #define PCI_DEVICE_ID_INTEL_82443GX_0 0x71a0 #define PCI_DEVICE_ID_INTEL_82443GX_2 0x71a2 #define PCI_DEVICE_ID_INTEL_82372FB_1 0x7601 +#define PCI_DEVICE_ID_INTEL_HDA_RPL_S 0x7a50 +#define PCI_DEVICE_ID_INTEL_HDA_ADL_S 0x7ad0 +#define PCI_DEVICE_ID_INTEL_HDA_MTL 0x7e28 #define PCI_DEVICE_ID_INTEL_SCH_LPC 0x8119 #define PCI_DEVICE_ID_INTEL_SCH_IDE 0x811a +#define PCI_DEVICE_ID_INTEL_HDA_POULSBO 0x811b #define PCI_DEVICE_ID_INTEL_E6XX_CU 0x8183 #define PCI_DEVICE_ID_INTEL_ITC_LPC 0x8186 #define PCI_DEVICE_ID_INTEL_82454GX 0x84c4 @@ -3018,9 +3069,31 @@ #define PCI_DEVICE_ID_INTEL_82454NX 0x84cb #define PCI_DEVICE_ID_INTEL_84460GX 0x84ea #define PCI_DEVICE_ID_INTEL_IXP4XX 0x8500 +#define PCI_DEVICE_ID_INTEL_HDA_LPT 0x8c20 +#define PCI_DEVICE_ID_INTEL_HDA_9_SERIES 0x8ca0 +#define PCI_DEVICE_ID_INTEL_HDA_WBG_0 0x8d20 +#define PCI_DEVICE_ID_INTEL_HDA_WBG_1 0x8d21 #define PCI_DEVICE_ID_INTEL_IXP2800 0x9004 +#define PCI_DEVICE_ID_INTEL_HDA_LKF 0x98c8 #define PCI_DEVICE_ID_INTEL_VMD_9A0B 0x9a0b +#define PCI_DEVICE_ID_INTEL_HDA_LPT_LP_0 0x9c20 +#define PCI_DEVICE_ID_INTEL_HDA_LPT_LP_1 0x9c21 +#define PCI_DEVICE_ID_INTEL_HDA_WPT_LP 0x9ca0 +#define PCI_DEVICE_ID_INTEL_HDA_SKL_LP 0x9d70 +#define PCI_DEVICE_ID_INTEL_HDA_KBL_LP 0x9d71 +#define PCI_DEVICE_ID_INTEL_HDA_CNL_LP 0x9dc8 +#define PCI_DEVICE_ID_INTEL_HDA_TGL_LP 0xa0c8 +#define PCI_DEVICE_ID_INTEL_HDA_SKL 0xa170 +#define PCI_DEVICE_ID_INTEL_HDA_KBL 0xa171 +#define PCI_DEVICE_ID_INTEL_HDA_LBG_0 0xa1f0 +#define PCI_DEVICE_ID_INTEL_HDA_LBG_1 0xa270 +#define PCI_DEVICE_ID_INTEL_HDA_KBL_H 0xa2f0 +#define PCI_DEVICE_ID_INTEL_HDA_CNL_H 0xa348 +#define PCI_DEVICE_ID_INTEL_HDA_CML_S 0xa3f0 +#define PCI_DEVICE_ID_INTEL_HDA_LNL_P 0xa828 #define PCI_DEVICE_ID_INTEL_S21152BB 0xb152 +#define PCI_DEVICE_ID_INTEL_HDA_CML_R 0xf0c8 +#define PCI_DEVICE_ID_INTEL_HDA_RKL_S 0xf1c8 #define PCI_VENDOR_ID_WANGXUN 0x8088 From e9207825c899cec6df488b16ecf93c8f667842f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Mon, 17 Jul 2023 13:44:59 +0200 Subject: [PATCH 115/334] ASoC: SOF: Remove unused Broxton PCI ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current code references 0x1a98 which is BXT-M (not -T as it is commented) and it's an RVP, BXT-M B0 to be specific. From what we know no BXT is available on market. Reviewed-by: Andy Shevchenko Acked-by: Mark Brown Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20230717114511.484999-4-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- sound/hda/intel-dsp-config.c | 7 ------- sound/soc/sof/intel/pci-apl.c | 2 -- 2 files changed, 9 deletions(-) diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index 317bdf6dcbef..5cee995f7a42 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -53,13 +53,6 @@ static const struct config_entry config_table[] = { .device = 0x119a, }, #endif -/* Broxton-T */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) - { - .flags = FLAG_SOF, - .device = 0x1a98, - }, -#endif /* * Apollolake (Broxton-P) * the legacy HDAudio driver is used except on Up Squared (SOF) and diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c index 69cad5a6bc72..bc3ad64baec5 100644 --- a/sound/soc/sof/intel/pci-apl.c +++ b/sound/soc/sof/intel/pci-apl.c @@ -87,8 +87,6 @@ static const struct sof_dev_desc glk_desc = { static const struct pci_device_id sof_pci_ids[] = { { PCI_DEVICE(0x8086, 0x5a98), /* BXT-P (ApolloLake) */ .driver_data = (unsigned long)&bxt_desc}, - { PCI_DEVICE(0x8086, 0x1a98),/* BXT-T */ - .driver_data = (unsigned long)&bxt_desc}, { PCI_DEVICE(0x8086, 0x3198), /* GeminiLake */ .driver_data = (unsigned long)&glk_desc}, { 0, } From 97b7aeb2d9a7efab43233aa9f20de365db064e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Mon, 17 Jul 2023 13:45:00 +0200 Subject: [PATCH 116/334] ALSA: Remove unused Broxton PCI ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current code references 0x1a98 which is BXT-M (not -T as it is commented) and it's an RVP, BXT-M B0 to be specific. From what we know no BXT is available on market. Reviewed-by: Andy Shevchenko Acked-by: Mark Brown Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20230717114511.484999-5-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index ef831770ca7d..8f0cebb83302 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2564,9 +2564,6 @@ static const struct pci_device_id azx_ids[] = { /* Broxton-P(Apollolake) */ { PCI_DEVICE(0x8086, 0x5a98), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, - /* Broxton-T */ - { PCI_DEVICE(0x8086, 0x1a98), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, /* Gemini-Lake */ { PCI_DEVICE(0x8086, 0x3198), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, From cab8cf497d708d74407745d05fdf8a3a1f83ce4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Mon, 17 Jul 2023 13:45:01 +0200 Subject: [PATCH 117/334] ALSA: hda: Add controller matching macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some HDA controllers require additional handling, so there are macros to match them, however those are spread across multiple files. Add them all in one place, so they can be reused. Reviewed-by: Andy Shevchenko Acked-by: Mark Brown Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20230717114511.484999-6-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- include/sound/hdaudio.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 2ffdf58bd6d4..32c59053b48e 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -704,4 +705,29 @@ static inline unsigned int snd_array_index(struct snd_array *array, void *ptr) for ((idx) = 0, (ptr) = (array)->list; (idx) < (array)->used; \ (ptr) = snd_array_elem(array, ++(idx))) +/* + * Device matching + */ + +#define HDA_CONTROLLER_IS_HSW(pci) (pci_match_id((struct pci_device_id []){ \ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_HSW_0) }, \ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_HSW_2) }, \ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_HSW_3) }, \ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_BDW) }, \ + { } \ + }, pci)) + +#define HDA_CONTROLLER_IS_APL(pci) (pci_match_id((struct pci_device_id []){ \ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_APL) }, \ + { } \ + }, pci)) + +#define HDA_CONTROLLER_IN_GPU(pci) (pci_match_id((struct pci_device_id []){ \ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_DG1) }, \ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_DG2_0) }, \ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_DG2_1) }, \ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_DG2_2) }, \ + { } \ + }, pci) || HDA_CONTROLLER_IS_HSW(pci)) + #endif /* __SOUND_HDAUDIO_H */ From 1b21bd7a565c724cd3f4d5f222c356faca2a4508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Mon, 17 Jul 2023 13:45:02 +0200 Subject: [PATCH 118/334] ALSA: hda: Use global PCI match macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using local macro to match PCI device, use global one. As Apollolake is Broxton-P successor that made it to the market, be precise and use APL shortcut. Reviewed-by: Andy Shevchenko Acked-by: Mark Brown Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20230717114511.484999-7-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 8f0cebb83302..5e59dcc35665 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -330,18 +330,6 @@ enum { #define needs_eld_notify_link(chip) false #endif -#define CONTROLLER_IN_GPU(pci) (((pci)->vendor == 0x8086) && \ - (((pci)->device == 0x0a0c) || \ - ((pci)->device == 0x0c0c) || \ - ((pci)->device == 0x0d0c) || \ - ((pci)->device == 0x160c) || \ - ((pci)->device == 0x490d) || \ - ((pci)->device == 0x4f90) || \ - ((pci)->device == 0x4f91) || \ - ((pci)->device == 0x4f92))) - -#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) - static const char * const driver_short_names[] = { [AZX_DRIVER_ICH] = "HDA Intel", [AZX_DRIVER_PCH] = "HDA Intel PCH", @@ -573,7 +561,7 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) snd_hdac_set_codec_wakeup(bus, false); /* reduce dma latency to avoid noise */ - if (IS_BXT(pci)) + if (HDA_CONTROLLER_IS_APL(pci)) bxt_reduce_dma_latency(chip); if (bus->mlcap != NULL) @@ -2175,7 +2163,7 @@ static int azx_probe(struct pci_dev *pci, #endif /* CONFIG_SND_HDA_PATCH_LOADER */ #ifndef CONFIG_SND_HDA_I915 - if (CONTROLLER_IN_GPU(pci)) + if (HDA_CONTROLLER_IN_GPU(pci)) dev_err(card->dev, "Haswell/Broadwell HDMI/DP must build in CONFIG_SND_HDA_I915\n"); #endif @@ -2283,7 +2271,7 @@ static int azx_probe_continue(struct azx *chip) * for other chips, still continue probing as other * codecs can be on the same link. */ - if (CONTROLLER_IN_GPU(pci)) { + if (HDA_CONTROLLER_IN_GPU(pci)) { dev_err(chip->card->dev, "HSW/BDW HD-audio HDMI/DP requires binding with gfx driver\n"); goto out_free; @@ -2294,7 +2282,7 @@ static int azx_probe_continue(struct azx *chip) } /* HSW/BDW controllers need this power */ - if (CONTROLLER_IN_GPU(pci)) + if (HDA_CONTROLLER_IN_GPU(pci)) hda->need_i915_power = true; } From fd6f3a84ab59784b83f0609cf17e5199f2141395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Mon, 17 Jul 2023 13:45:03 +0200 Subject: [PATCH 119/334] ALSA: hda/i915: Use global PCI match macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using local macro to match PCI device, use global one. Reviewed-by: Andy Shevchenko Acked-by: Mark Brown Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20230717114511.484999-8-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- sound/hda/hdac_i915.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c index 161a9711cd63..2a451ff4fe6a 100644 --- a/sound/hda/hdac_i915.c +++ b/sound/hda/hdac_i915.c @@ -11,11 +11,6 @@ #include #include -#define IS_HSW_CONTROLLER(pci) (((pci)->device == 0x0a0c) || \ - ((pci)->device == 0x0c0c) || \ - ((pci)->device == 0x0d0c) || \ - ((pci)->device == 0x160c)) - /** * snd_hdac_i915_set_bclk - Reprogram BCLK for HSW/BDW * @bus: HDA core bus @@ -39,7 +34,7 @@ void snd_hdac_i915_set_bclk(struct hdac_bus *bus) if (!acomp || !acomp->ops || !acomp->ops->get_cdclk_freq) return; /* only for i915 binding */ - if (!IS_HSW_CONTROLLER(pci)) + if (!HDA_CONTROLLER_IS_HSW(pci)) return; /* only HSW/BDW */ cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev); From 76e3a424646ee1ff71062d61b51852cb389badfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Mon, 17 Jul 2023 13:45:04 +0200 Subject: [PATCH 120/334] ASoC: Intel: Skylake: Use global PCI match macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using local macro to match PCI device, use global one. As Apollolake is Broxton-P successor that made it to the market, be precise and use APL shortcut. IS_CFL() macro is dropped as it is unused. Acked-by: Mark Brown Reviewed-by: Andy Shevchenko Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20230717114511.484999-9-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- include/sound/hda_codec.h | 3 --- sound/soc/intel/skylake/skl-pcm.c | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index bbb7805e85d8..5497dc9c396a 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -18,9 +18,6 @@ #include #include -#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) -#define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348) - /* * Structures */ diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index a4209d88b0c6..ac3dc8c63c26 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include "skl.h" @@ -152,7 +153,7 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params) * The recommended SDxFMT programming sequence for BXT * platforms is to couple the stream before writing the format */ - if (IS_BXT(skl->pci)) { + if (HDA_CONTROLLER_IS_APL(skl->pci)) { snd_hdac_ext_stream_decouple(bus, stream, false); err = snd_hdac_stream_setup(hdac_stream(stream)); snd_hdac_ext_stream_decouple(bus, stream, true); From 0cd0a7c2c599e57b5dcb1c3a0717a31615b72de3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Mon, 17 Jul 2023 13:45:05 +0200 Subject: [PATCH 121/334] ALSA: intel-dsp-config: Convert to PCI device IDs defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use PCI device IDs from pci_ids.h header. Also simplify comments for Alder Lake and Raptor Lake platforms, as new IDs make it clear what revision is in use. Acked-by: Mark Brown Reviewed-by: Andy Shevchenko # for Intel Tangier ID Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20230717114511.484999-10-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- sound/hda/intel-dsp-config.c | 135 ++++++++++++++++------------------- 1 file changed, 63 insertions(+), 72 deletions(-) diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index 5cee995f7a42..48bd1fb06f26 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -50,7 +50,7 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) { .flags = FLAG_SOF, - .device = 0x119a, + .device = PCI_DEVICE_ID_INTEL_SST_TNG, }, #endif /* @@ -61,7 +61,7 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) { .flags = FLAG_SOF, - .device = 0x5a98, + .device = PCI_DEVICE_ID_INTEL_HDA_APL, .dmi_table = (const struct dmi_system_id []) { { .ident = "Up Squared", @@ -75,14 +75,14 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SOF, - .device = 0x5a98, + .device = PCI_DEVICE_ID_INTEL_HDA_APL, .codec_hid = &essx_83x6, }, #endif #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) { .flags = FLAG_SST, - .device = 0x5a98, + .device = PCI_DEVICE_ID_INTEL_HDA_APL, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -103,7 +103,7 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL) { .flags = FLAG_SST, - .device = 0x9d70, + .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -116,14 +116,14 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, - .device = 0x9d70, + .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, }, #endif /* Kabylake-LP */ #if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL) { .flags = FLAG_SST, - .device = 0x9d71, + .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -136,7 +136,7 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, - .device = 0x9d71, + .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, }, #endif @@ -148,7 +148,7 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) { .flags = FLAG_SOF, - .device = 0x3198, + .device = PCI_DEVICE_ID_INTEL_HDA_GML, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -161,7 +161,7 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SOF, - .device = 0x3198, + .device = PCI_DEVICE_ID_INTEL_HDA_GML, .codec_hid = &essx_83x6, }, #endif @@ -181,7 +181,7 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) { .flags = FLAG_SOF, - .device = 0x9dc8, + .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -200,12 +200,12 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SOF, - .device = 0x09dc8, + .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP, .codec_hid = &essx_83x6, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x9dc8, + .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP, }, #endif @@ -213,7 +213,7 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) { .flags = FLAG_SOF, - .device = 0xa348, + .device = PCI_DEVICE_ID_INTEL_HDA_CNL_H, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -226,7 +226,7 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0xa348, + .device = PCI_DEVICE_ID_INTEL_HDA_CNL_H, }, #endif @@ -234,7 +234,7 @@ static const struct config_entry config_table[] = { /* Cometlake-LP */ { .flags = FLAG_SOF, - .device = 0x02c8, + .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -260,17 +260,17 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SOF, - .device = 0x02c8, + .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP, .codec_hid = &essx_83x6, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x02c8, + .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP, }, /* Cometlake-H */ { .flags = FLAG_SOF, - .device = 0x06c8, + .device = PCI_DEVICE_ID_INTEL_HDA_CML_H, .dmi_table = (const struct dmi_system_id []) { { .matches = { @@ -289,12 +289,12 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SOF, - .device = 0x06c8, + .device = PCI_DEVICE_ID_INTEL_HDA_CML_H, .codec_hid = &essx_83x6, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x06c8, + .device = PCI_DEVICE_ID_INTEL_HDA_CML_H, }, #endif @@ -302,7 +302,7 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) { .flags = FLAG_SOF, - .device = 0x34c8, + .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -315,12 +315,12 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SOF, - .device = 0x34c8, + .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP, .codec_hid = &essx_83x6, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x34c8, + .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP, }, #endif @@ -328,7 +328,7 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE) { .flags = FLAG_SOF, - .device = 0x4dc8, + .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -341,12 +341,12 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SOF, - .device = 0x4dc8, + .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N, .codec_hid = &essx_83x6, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, - .device = 0x4dc8, + .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N, }, #endif @@ -354,7 +354,7 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) { .flags = FLAG_SOF, - .device = 0xa0c8, + .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -373,16 +373,16 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SOF, - .device = 0xa0c8, + .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP, .codec_hid = &essx_83x6, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0xa0c8, + .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x43c8, + .device = PCI_DEVICE_ID_INTEL_HDA_TGL_H, }, #endif @@ -390,78 +390,69 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, - .device = 0x4b55, + .device = PCI_DEVICE_ID_INTEL_HDA_EHL_0, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, - .device = 0x4b58, + .device = PCI_DEVICE_ID_INTEL_HDA_EHL_3, }, #endif -/* Alder Lake */ +/* Alder Lake / Raptor Lake */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE) - /* Alderlake-S */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x7ad0, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_S, }, - /* RaptorLake-S */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x7a50, + .device = PCI_DEVICE_ID_INTEL_HDA_RPL_S, }, - /* Alderlake-P */ { .flags = FLAG_SOF, - .device = 0x51c8, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P, .codec_hid = &essx_83x6, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51c8, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51cd, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PX, }, - /* Alderlake-PS */ { .flags = FLAG_SOF, - .device = 0x51c9, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS, .codec_hid = &essx_83x6, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51c9, - }, - /* Alderlake-M */ - { - .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51cc, - }, - /* Alderlake-N */ - { - .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x54c8, - }, - /* RaptorLake-P */ - { - .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51ca, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51cb, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_M, }, - /* RaptorLake-M */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51ce, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_N, }, - /* RaptorLake-PX */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51cf, + .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0, + }, + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, + .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1, + }, + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, + .device = PCI_DEVICE_ID_INTEL_HDA_RPL_M, + }, + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, + .device = PCI_DEVICE_ID_INTEL_HDA_RPL_PX, }, #endif @@ -542,7 +533,7 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci) const struct config_entry *cfg; /* Intel vendor only */ - if (pci->vendor != 0x8086) + if (pci->vendor != PCI_VENDOR_ID_INTEL) return SND_INTEL_DSP_DRIVER_ANY; /* @@ -550,12 +541,12 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci) * for HDMI/DP support, ignore kernel parameter */ switch (pci->device) { - case 0x160c: /* Broadwell */ - case 0x0a0c: /* Haswell */ - case 0x0c0c: - case 0x0d0c: - case 0x0f04: /* Baytrail */ - case 0x2284: /* Braswell */ + case PCI_DEVICE_ID_INTEL_HDA_BDW: + case PCI_DEVICE_ID_INTEL_HDA_HSW_0: + case PCI_DEVICE_ID_INTEL_HDA_HSW_2: + case PCI_DEVICE_ID_INTEL_HDA_HSW_3: + case PCI_DEVICE_ID_INTEL_HDA_BYT: + case PCI_DEVICE_ID_INTEL_HDA_BSW: return SND_INTEL_DSP_DRIVER_ANY; } From e6232c80a55f812010c7c40b757cc5aa22e48199 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Mon, 17 Jul 2023 13:45:06 +0200 Subject: [PATCH 122/334] ALSA: hda: Convert to PCI device IDs defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use PCI device IDs from pci_ids.h header and while at it to simplify declarations change to using PCI_DEVICE_DATA() macro for Intel IDs and PCI_VDEVICE() for all other that have defined vendor. Acked-by: Mark Brown Reviewed-by: Andy Shevchenko Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20230717114511.484999-11-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 350 +++++++++++++++----------------------- 1 file changed, 140 insertions(+), 210 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 5e59dcc35665..176567f0d0e0 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2416,330 +2416,260 @@ static void azx_shutdown(struct pci_dev *pci) /* PCI IDs */ static const struct pci_device_id azx_ids[] = { /* CPT */ - { PCI_DEVICE(0x8086, 0x1c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, + { PCI_DEVICE_DATA(INTEL, HDA_CPT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM) }, /* PBG */ - { PCI_DEVICE(0x8086, 0x1d20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, + { PCI_DEVICE_DATA(INTEL, HDA_PBG, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM) }, /* Panther Point */ - { PCI_DEVICE(0x8086, 0x1e20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, + { PCI_DEVICE_DATA(INTEL, HDA_PPT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM) }, /* Lynx Point */ - { PCI_DEVICE(0x8086, 0x8c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + { PCI_DEVICE_DATA(INTEL, HDA_LPT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) }, /* 9 Series */ - { PCI_DEVICE(0x8086, 0x8ca0), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + { PCI_DEVICE_DATA(INTEL, HDA_9_SERIES, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) }, /* Wellsburg */ - { PCI_DEVICE(0x8086, 0x8d20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, - { PCI_DEVICE(0x8086, 0x8d21), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + { PCI_DEVICE_DATA(INTEL, HDA_WBG_0, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) }, + { PCI_DEVICE_DATA(INTEL, HDA_WBG_1, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) }, /* Lewisburg */ - { PCI_DEVICE(0x8086, 0xa1f0), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, - { PCI_DEVICE(0x8086, 0xa270), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, + { PCI_DEVICE_DATA(INTEL, HDA_LBG_0, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_LBG_1, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE) }, /* Lynx Point-LP */ - { PCI_DEVICE(0x8086, 0x9c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + { PCI_DEVICE_DATA(INTEL, HDA_LPT_LP_0, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) }, /* Lynx Point-LP */ - { PCI_DEVICE(0x8086, 0x9c21), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + { PCI_DEVICE_DATA(INTEL, HDA_LPT_LP_1, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) }, /* Wildcat Point-LP */ - { PCI_DEVICE(0x8086, 0x9ca0), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, - /* Sunrise Point */ - { PCI_DEVICE(0x8086, 0xa170), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, - /* Sunrise Point-LP */ - { PCI_DEVICE(0x8086, 0x9d70), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, + { PCI_DEVICE_DATA(INTEL, HDA_WPT_LP, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) }, + /* Skylake (Sunrise Point) */ + { PCI_DEVICE_DATA(INTEL, HDA_SKL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + /* Skylake-LP (Sunrise Point-LP) */ + { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Kabylake */ - { PCI_DEVICE(0x8086, 0xa171), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, + { PCI_DEVICE_DATA(INTEL, HDA_KBL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Kabylake-LP */ - { PCI_DEVICE(0x8086, 0x9d71), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, + { PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Kabylake-H */ - { PCI_DEVICE(0x8086, 0xa2f0), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, + { PCI_DEVICE_DATA(INTEL, HDA_KBL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Coffelake */ - { PCI_DEVICE(0x8086, 0xa348), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_CNL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Cannonlake */ - { PCI_DEVICE(0x8086, 0x9dc8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* CometLake-LP */ - { PCI_DEVICE(0x8086, 0x02C8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_CML_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* CometLake-H */ - { PCI_DEVICE(0x8086, 0x06C8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0xf1c8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_CML_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_RKL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* CometLake-S */ - { PCI_DEVICE(0x8086, 0xa3f0), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_CML_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* CometLake-R */ - { PCI_DEVICE(0x8086, 0xf0c8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_CML_R, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Icelake */ - { PCI_DEVICE(0x8086, 0x34c8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_ICL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Icelake-H */ - { PCI_DEVICE(0x8086, 0x3dc8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_ICL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Jasperlake */ - { PCI_DEVICE(0x8086, 0x38c8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x4dc8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_ICL_N, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_JSL_N, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Tigerlake */ - { PCI_DEVICE(0x8086, 0xa0c8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_TGL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Tigerlake-H */ - { PCI_DEVICE(0x8086, 0x43c8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_TGL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* DG1 */ - { PCI_DEVICE(0x8086, 0x490d), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_DG1, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* DG2 */ - { PCI_DEVICE(0x8086, 0x4f90), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x4f91), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x4f92), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_DG2_0, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_DG2_1, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_DG2_2, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Alderlake-S */ - { PCI_DEVICE(0x8086, 0x7ad0), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Alderlake-P */ - { PCI_DEVICE(0x8086, 0x51c8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x51c9), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x51cd), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_P, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_PS, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_PX, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Alderlake-M */ - { PCI_DEVICE(0x8086, 0x51cc), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_M, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Alderlake-N */ - { PCI_DEVICE(0x8086, 0x54c8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_N, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Elkhart Lake */ - { PCI_DEVICE(0x8086, 0x4b55), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x4b58), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_EHL_0, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_EHL_3, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Raptor Lake */ - { PCI_DEVICE(0x8086, 0x7a50), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x51ca), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x51cb), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x51ce), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x51cf), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - /* Meteorlake-P */ - { PCI_DEVICE(0x8086, 0x7e28), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_0, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_1, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_M, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_MTL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Lunarlake-P */ - { PCI_DEVICE(0x8086, 0xa828), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - /* Broxton-P(Apollolake) */ - { PCI_DEVICE(0x8086, 0x5a98), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, + { PCI_DEVICE_DATA(INTEL, HDA_LNL_P, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + /* Apollolake (Broxton-P) */ + { PCI_DEVICE_DATA(INTEL, HDA_APL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON) }, /* Gemini-Lake */ - { PCI_DEVICE(0x8086, 0x3198), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, + { PCI_DEVICE_DATA(INTEL, HDA_GML, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON) }, /* Haswell */ - { PCI_DEVICE(0x8086, 0x0a0c), - .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, - { PCI_DEVICE(0x8086, 0x0c0c), - .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, - { PCI_DEVICE(0x8086, 0x0d0c), - .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, + { PCI_DEVICE_DATA(INTEL, HDA_HSW_0, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL) }, + { PCI_DEVICE_DATA(INTEL, HDA_HSW_2, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL) }, + { PCI_DEVICE_DATA(INTEL, HDA_HSW_3, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL) }, /* Broadwell */ - { PCI_DEVICE(0x8086, 0x160c), - .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_BROADWELL }, + { PCI_DEVICE_DATA(INTEL, HDA_BDW, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_BROADWELL) }, /* 5 Series/3400 */ - { PCI_DEVICE(0x8086, 0x3b56), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, - { PCI_DEVICE(0x8086, 0x3b57), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, + { PCI_DEVICE_DATA(INTEL, HDA_5_3400_SERIES_0, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM) }, + { PCI_DEVICE_DATA(INTEL, HDA_5_3400_SERIES_1, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM) }, /* Poulsbo */ - { PCI_DEVICE(0x8086, 0x811b), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE | - AZX_DCAPS_POSFIX_LPIB }, + { PCI_DEVICE_DATA(INTEL, HDA_POULSBO, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE | + AZX_DCAPS_POSFIX_LPIB) }, /* Oaktrail */ - { PCI_DEVICE(0x8086, 0x080a), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE }, + { PCI_DEVICE_DATA(INTEL, HDA_OAKTRAIL, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE) }, /* BayTrail */ - { PCI_DEVICE(0x8086, 0x0f04), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BAYTRAIL }, + { PCI_DEVICE_DATA(INTEL, HDA_BYT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BAYTRAIL) }, /* Braswell */ - { PCI_DEVICE(0x8086, 0x2284), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BRASWELL }, + { PCI_DEVICE_DATA(INTEL, HDA_BSW, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BRASWELL) }, /* ICH6 */ - { PCI_DEVICE(0x8086, 0x2668), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + { PCI_DEVICE_DATA(INTEL, HDA_ICH6, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) }, /* ICH7 */ - { PCI_DEVICE(0x8086, 0x27d8), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + { PCI_DEVICE_DATA(INTEL, HDA_ICH7, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) }, /* ESB2 */ - { PCI_DEVICE(0x8086, 0x269a), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + { PCI_DEVICE_DATA(INTEL, HDA_ESB2, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) }, /* ICH8 */ - { PCI_DEVICE(0x8086, 0x284b), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + { PCI_DEVICE_DATA(INTEL, HDA_ICH8, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) }, /* ICH9 */ - { PCI_DEVICE(0x8086, 0x293e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + { PCI_DEVICE_DATA(INTEL, HDA_ICH9_0, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) }, /* ICH9 */ - { PCI_DEVICE(0x8086, 0x293f), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + { PCI_DEVICE_DATA(INTEL, HDA_ICH9_1, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) }, /* ICH10 */ - { PCI_DEVICE(0x8086, 0x3a3e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + { PCI_DEVICE_DATA(INTEL, HDA_ICH10_0, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) }, /* ICH10 */ - { PCI_DEVICE(0x8086, 0x3a6e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + { PCI_DEVICE_DATA(INTEL, HDA_ICH10_1, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) }, /* Generic Intel */ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_NO_ALIGN_BUFSIZE }, /* ATI SB 450/600/700/800/900 */ - { PCI_DEVICE(0x1002, 0x437b), + { PCI_VDEVICE(ATI, 0x437b), .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB }, - { PCI_DEVICE(0x1002, 0x4383), + { PCI_VDEVICE(ATI, 0x4383), .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB }, /* AMD Hudson */ - { PCI_DEVICE(0x1022, 0x780d), + { PCI_VDEVICE(AMD, 0x780d), .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB }, /* AMD, X370 & co */ - { PCI_DEVICE(0x1022, 0x1457), + { PCI_VDEVICE(AMD, 0x1457), .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB }, /* AMD, X570 & co */ - { PCI_DEVICE(0x1022, 0x1487), + { PCI_VDEVICE(AMD, 0x1487), .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB }, /* AMD Stoney */ - { PCI_DEVICE(0x1022, 0x157a), + { PCI_VDEVICE(AMD, 0x157a), .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB | AZX_DCAPS_PM_RUNTIME }, /* AMD Raven */ - { PCI_DEVICE(0x1022, 0x15e3), + { PCI_VDEVICE(AMD, 0x15e3), .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB }, /* ATI HDMI */ - { PCI_DEVICE(0x1002, 0x0002), + { PCI_VDEVICE(ATI, 0x0002), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0x1308), + { PCI_VDEVICE(ATI, 0x1308), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, - { PCI_DEVICE(0x1002, 0x157a), + { PCI_VDEVICE(ATI, 0x157a), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, - { PCI_DEVICE(0x1002, 0x15b3), + { PCI_VDEVICE(ATI, 0x15b3), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, - { PCI_DEVICE(0x1002, 0x793b), + { PCI_VDEVICE(ATI, 0x793b), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0x7919), + { PCI_VDEVICE(ATI, 0x7919), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0x960f), + { PCI_VDEVICE(ATI, 0x960f), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0x970f), + { PCI_VDEVICE(ATI, 0x970f), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0x9840), + { PCI_VDEVICE(ATI, 0x9840), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, - { PCI_DEVICE(0x1002, 0xaa00), + { PCI_VDEVICE(ATI, 0xaa00), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa08), + { PCI_VDEVICE(ATI, 0xaa08), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa10), + { PCI_VDEVICE(ATI, 0xaa10), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa18), + { PCI_VDEVICE(ATI, 0xaa18), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa20), + { PCI_VDEVICE(ATI, 0xaa20), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa28), + { PCI_VDEVICE(ATI, 0xaa28), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa30), + { PCI_VDEVICE(ATI, 0xaa30), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa38), + { PCI_VDEVICE(ATI, 0xaa38), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa40), + { PCI_VDEVICE(ATI, 0xaa40), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa48), + { PCI_VDEVICE(ATI, 0xaa48), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa50), + { PCI_VDEVICE(ATI, 0xaa50), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa58), + { PCI_VDEVICE(ATI, 0xaa58), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa60), + { PCI_VDEVICE(ATI, 0xaa60), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa68), + { PCI_VDEVICE(ATI, 0xaa68), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa80), + { PCI_VDEVICE(ATI, 0xaa80), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa88), + { PCI_VDEVICE(ATI, 0xaa88), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa90), + { PCI_VDEVICE(ATI, 0xaa90), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa98), + { PCI_VDEVICE(ATI, 0xaa98), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0x9902), + { PCI_VDEVICE(ATI, 0x9902), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, - { PCI_DEVICE(0x1002, 0xaaa0), + { PCI_VDEVICE(ATI, 0xaaa0), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, - { PCI_DEVICE(0x1002, 0xaaa8), + { PCI_VDEVICE(ATI, 0xaaa8), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, - { PCI_DEVICE(0x1002, 0xaab0), + { PCI_VDEVICE(ATI, 0xaab0), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, - { PCI_DEVICE(0x1002, 0xaac0), + { PCI_VDEVICE(ATI, 0xaac0), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xaac8), + { PCI_VDEVICE(ATI, 0xaac8), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xaad8), + { PCI_VDEVICE(ATI, 0xaad8), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xaae0), + { PCI_VDEVICE(ATI, 0xaae0), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xaae8), + { PCI_VDEVICE(ATI, 0xaae8), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xaaf0), + { PCI_VDEVICE(ATI, 0xaaf0), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xaaf8), + { PCI_VDEVICE(ATI, 0xaaf8), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xab00), + { PCI_VDEVICE(ATI, 0xab00), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xab08), + { PCI_VDEVICE(ATI, 0xab08), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xab10), + { PCI_VDEVICE(ATI, 0xab10), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xab18), + { PCI_VDEVICE(ATI, 0xab18), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xab20), + { PCI_VDEVICE(ATI, 0xab20), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xab28), + { PCI_VDEVICE(ATI, 0xab28), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xab30), + { PCI_VDEVICE(ATI, 0xab30), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xab38), + { PCI_VDEVICE(ATI, 0xab38), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, /* GLENFLY */ @@ -2749,15 +2679,15 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_GFHDMI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT }, /* VIA VT8251/VT8237A */ - { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA }, + { PCI_VDEVICE(VIA, 0x3288), .driver_data = AZX_DRIVER_VIA }, /* VIA GFX VT7122/VX900 */ - { PCI_DEVICE(0x1106, 0x9170), .driver_data = AZX_DRIVER_GENERIC }, + { PCI_VDEVICE(VIA, 0x9170), .driver_data = AZX_DRIVER_GENERIC }, /* VIA GFX VT6122/VX11 */ - { PCI_DEVICE(0x1106, 0x9140), .driver_data = AZX_DRIVER_GENERIC }, + { PCI_VDEVICE(VIA, 0x9140), .driver_data = AZX_DRIVER_GENERIC }, /* SIS966 */ - { PCI_DEVICE(0x1039, 0x7502), .driver_data = AZX_DRIVER_SIS }, + { PCI_VDEVICE(SI, 0x7502), .driver_data = AZX_DRIVER_SIS }, /* ULI M5461 */ - { PCI_DEVICE(0x10b9, 0x5461), .driver_data = AZX_DRIVER_ULI }, + { PCI_VDEVICE(AL, 0x5461), .driver_data = AZX_DRIVER_ULI }, /* NVIDIA MCP */ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, @@ -2770,9 +2700,9 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_TERA | AZX_DCAPS_NO_64BIT }, /* Creative X-Fi (CA0110-IBG) */ /* CTHDA chips */ - { PCI_DEVICE(0x1102, 0x0010), + { PCI_VDEVICE(CREATIVE, 0x0010), .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA }, - { PCI_DEVICE(0x1102, 0x0012), + { PCI_VDEVICE(CREATIVE, 0x0012), .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA }, #if !IS_ENABLED(CONFIG_SND_CTXFI) /* the following entry conflicts with snd-ctxfi driver, @@ -2786,18 +2716,18 @@ static const struct pci_device_id azx_ids[] = { AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB }, #else /* this entry seems still valid -- i.e. without emu20kx chip */ - { PCI_DEVICE(0x1102, 0x0009), + { PCI_VDEVICE(CREATIVE, 0x0009), .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND | AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB }, #endif /* CM8888 */ - { PCI_DEVICE(0x13f6, 0x5011), + { PCI_VDEVICE(CMEDIA, 0x5011), .driver_data = AZX_DRIVER_CMEDIA | AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_SNOOP_OFF }, /* Vortex86MX */ - { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC }, + { PCI_VDEVICE(RDC, 0x3010), .driver_data = AZX_DRIVER_GENERIC }, /* VMware HDAudio */ - { PCI_DEVICE(0x15ad, 0x1977), .driver_data = AZX_DRIVER_GENERIC }, + { PCI_VDEVICE(VMWARE, 0x1977), .driver_data = AZX_DRIVER_GENERIC }, /* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, @@ -2808,11 +2738,11 @@ static const struct pci_device_id azx_ids[] = { .class_mask = 0xffffff, .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI }, /* Zhaoxin */ - { PCI_DEVICE(0x1d17, 0x3288), .driver_data = AZX_DRIVER_ZHAOXIN }, + { PCI_VDEVICE(ZHAOXIN, 0x3288), .driver_data = AZX_DRIVER_ZHAOXIN }, /* Loongson HDAudio*/ - {PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_HDA), + { PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDA), .driver_data = AZX_DRIVER_LOONGSON }, - {PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_HDMI), + { PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDMI), .driver_data = AZX_DRIVER_LOONGSON }, { 0, } }; From 8d9614b885894c084b2617794512a8c3385228f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Mon, 17 Jul 2023 13:45:07 +0200 Subject: [PATCH 123/334] ASoC: Intel: avs: Convert to PCI device IDs defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use PCI device IDs from pci_ids.h header and while at it change to using PCI_DEVICE_DATA() macro, to simplify declarations. Acked-by: Mark Brown Reviewed-by: Andy Shevchenko Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20230717114511.484999-12-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- sound/soc/intel/avs/core.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c index 637501850728..859b217fc761 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -745,14 +745,14 @@ static const struct avs_spec apl_desc = { }; static const struct pci_device_id avs_ids[] = { - { PCI_VDEVICE(INTEL, 0x9d70), (unsigned long)&skl_desc }, /* SKL */ - { PCI_VDEVICE(INTEL, 0xa170), (unsigned long)&skl_desc }, /* SKL-H */ - { PCI_VDEVICE(INTEL, 0x9d71), (unsigned long)&skl_desc }, /* KBL */ - { PCI_VDEVICE(INTEL, 0xa171), (unsigned long)&skl_desc }, /* KBL-H */ - { PCI_VDEVICE(INTEL, 0xa2f0), (unsigned long)&skl_desc }, /* KBL-S */ - { PCI_VDEVICE(INTEL, 0xa3f0), (unsigned long)&skl_desc }, /* CML-V */ - { PCI_VDEVICE(INTEL, 0x5a98), (unsigned long)&apl_desc }, /* APL */ - { PCI_VDEVICE(INTEL, 0x3198), (unsigned long)&apl_desc }, /* GML */ + { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &skl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_SKL, &skl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, &skl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_KBL, &skl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_KBL_H, &skl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_CML_S, &skl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_APL, &apl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_GML, &apl_desc) }, { 0 } }; MODULE_DEVICE_TABLE(pci, avs_ids); From ea15d60252dc08f1ddda1efa1fc96cc4a9248b09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Mon, 17 Jul 2023 13:45:08 +0200 Subject: [PATCH 124/334] ASoC: Intel: avs: Convert to PCI device IDs defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use PCI device IDs from pci_ids.h header. Adjust AVS_MACH_ENTRY() macro, so device ID can be provided in short form. Acked-by: Mark Brown Reviewed-by: Andy Shevchenko Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20230717114511.484999-13-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- sound/soc/intel/avs/board_selection.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index 60f8fb0bff95..b32e02940e30 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -263,14 +263,14 @@ struct avs_acpi_boards { }; #define AVS_MACH_ENTRY(_id, _mach) \ - { .id = (_id), .machs = (_mach), } + { .id = PCI_DEVICE_ID_INTEL_##_id, .machs = (_mach), } /* supported I2S boards per platform */ static const struct avs_acpi_boards i2s_boards[] = { - AVS_MACH_ENTRY(0x9d70, avs_skl_i2s_machines), /* SKL */ - AVS_MACH_ENTRY(0x9d71, avs_kbl_i2s_machines), /* KBL */ - AVS_MACH_ENTRY(0x5a98, avs_apl_i2s_machines), /* APL */ - AVS_MACH_ENTRY(0x3198, avs_gml_i2s_machines), /* GML */ + AVS_MACH_ENTRY(HDA_SKL_LP, avs_skl_i2s_machines), + AVS_MACH_ENTRY(HDA_KBL_LP, avs_kbl_i2s_machines), + AVS_MACH_ENTRY(HDA_APL, avs_apl_i2s_machines), + AVS_MACH_ENTRY(HDA_GML, avs_gml_i2s_machines), {}, }; From a2db8743eda573de477e57319ea95ae088d6397c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Mon, 17 Jul 2023 13:45:09 +0200 Subject: [PATCH 125/334] ASoC: Intel: Skylake: Convert to PCI device IDs defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use PCI device IDs from pci_ids.h header and while at it change to using PCI_DEVICE_DATA() macro, to simplify declarations. As Apollolake is Broxton-P successor that made it to the market, be precise and use APL shortcut. Acked-by: Mark Brown Reviewed-by: Andy Shevchenko Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20230717114511.484999-14-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- sound/soc/intel/skylake/skl-messages.c | 16 ++++++------ sound/soc/intel/skylake/skl.c | 36 +++++++------------------- 2 files changed, 18 insertions(+), 34 deletions(-) diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index d31509298a0a..fc2eb04da172 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -169,7 +169,7 @@ static struct skl_dsp_loader_ops bxt_get_loader_ops(void) static const struct skl_dsp_ops dsp_ops[] = { { - .id = 0x9d70, + .id = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, .num_cores = 2, .loader_ops = skl_get_loader_ops, .init = skl_sst_dsp_init, @@ -177,7 +177,7 @@ static const struct skl_dsp_ops dsp_ops[] = { .cleanup = skl_sst_dsp_cleanup }, { - .id = 0x9d71, + .id = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, .num_cores = 2, .loader_ops = skl_get_loader_ops, .init = skl_sst_dsp_init, @@ -185,7 +185,7 @@ static const struct skl_dsp_ops dsp_ops[] = { .cleanup = skl_sst_dsp_cleanup }, { - .id = 0x5a98, + .id = PCI_DEVICE_ID_INTEL_HDA_APL, .num_cores = 2, .loader_ops = bxt_get_loader_ops, .init = bxt_sst_dsp_init, @@ -193,7 +193,7 @@ static const struct skl_dsp_ops dsp_ops[] = { .cleanup = bxt_sst_dsp_cleanup }, { - .id = 0x3198, + .id = PCI_DEVICE_ID_INTEL_HDA_GML, .num_cores = 2, .loader_ops = bxt_get_loader_ops, .init = bxt_sst_dsp_init, @@ -201,7 +201,7 @@ static const struct skl_dsp_ops dsp_ops[] = { .cleanup = bxt_sst_dsp_cleanup }, { - .id = 0x9dc8, + .id = PCI_DEVICE_ID_INTEL_HDA_CNL_LP, .num_cores = 4, .loader_ops = bxt_get_loader_ops, .init = cnl_sst_dsp_init, @@ -209,7 +209,7 @@ static const struct skl_dsp_ops dsp_ops[] = { .cleanup = cnl_sst_dsp_cleanup }, { - .id = 0xa348, + .id = PCI_DEVICE_ID_INTEL_HDA_CNL_H, .num_cores = 4, .loader_ops = bxt_get_loader_ops, .init = cnl_sst_dsp_init, @@ -217,7 +217,7 @@ static const struct skl_dsp_ops dsp_ops[] = { .cleanup = cnl_sst_dsp_cleanup }, { - .id = 0x02c8, + .id = PCI_DEVICE_ID_INTEL_HDA_CML_LP, .num_cores = 4, .loader_ops = bxt_get_loader_ops, .init = cnl_sst_dsp_init, @@ -225,7 +225,7 @@ static const struct skl_dsp_ops dsp_ops[] = { .cleanup = cnl_sst_dsp_cleanup }, { - .id = 0x06c8, + .id = PCI_DEVICE_ID_INTEL_HDA_CML_H, .num_cores = 4, .loader_ops = bxt_get_loader_ops, .init = cnl_sst_dsp_init, diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 998bd0232cf1..77408a981b97 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -608,8 +608,8 @@ struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id) static void init_skl_xtal_rate(int pci_id) { switch (pci_id) { - case 0x9d70: - case 0x9d71: + case PCI_DEVICE_ID_INTEL_HDA_SKL_LP: + case PCI_DEVICE_ID_INTEL_HDA_KBL_LP: skl_clk_src[0].rate = 24000000; return; @@ -1145,44 +1145,28 @@ static void skl_remove(struct pci_dev *pci) /* PCI IDs */ static const struct pci_device_id skl_ids[] = { #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL) - /* Sunrise Point-LP */ - { PCI_DEVICE(0x8086, 0x9d70), - .driver_data = (unsigned long)&snd_soc_acpi_intel_skl_machines}, + { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &snd_soc_acpi_intel_skl_machines) }, #endif #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) - /* BXT-P */ - { PCI_DEVICE(0x8086, 0x5a98), - .driver_data = (unsigned long)&snd_soc_acpi_intel_bxt_machines}, + { PCI_DEVICE_DATA(INTEL, HDA_APL, &snd_soc_acpi_intel_bxt_machines) }, #endif #if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL) - /* KBL */ - { PCI_DEVICE(0x8086, 0x9D71), - .driver_data = (unsigned long)&snd_soc_acpi_intel_kbl_machines}, + { PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, &snd_soc_acpi_intel_kbl_machines) }, #endif #if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK) - /* GLK */ - { PCI_DEVICE(0x8086, 0x3198), - .driver_data = (unsigned long)&snd_soc_acpi_intel_glk_machines}, + { PCI_DEVICE_DATA(INTEL, HDA_GML, &snd_soc_acpi_intel_glk_machines) }, #endif #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL) - /* CNL */ - { PCI_DEVICE(0x8086, 0x9dc8), - .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, + { PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, &snd_soc_acpi_intel_cnl_machines) }, #endif #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CFL) - /* CFL */ - { PCI_DEVICE(0x8086, 0xa348), - .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, + { PCI_DEVICE_DATA(INTEL, HDA_CNL_H, &snd_soc_acpi_intel_cnl_machines) }, #endif #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_LP) - /* CML-LP */ - { PCI_DEVICE(0x8086, 0x02c8), - .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, + { PCI_DEVICE_DATA(INTEL, HDA_CML_LP, &snd_soc_acpi_intel_cnl_machines) }, #endif #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_H) - /* CML-H */ - { PCI_DEVICE(0x8086, 0x06c8), - .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, + { PCI_DEVICE_DATA(INTEL, HDA_CML_H, &snd_soc_acpi_intel_cnl_machines) }, #endif { 0, } }; From a9022f4bec01f98f21106d66c81dfdacc57fe759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Mon, 17 Jul 2023 13:45:10 +0200 Subject: [PATCH 126/334] ASoC: SOF: Intel: Convert to PCI device IDs defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use PCI device IDs from pci_ids.h header and while at it change to using PCI_DEVICE_DATA() macro, to simplify declarations. Acked-by: Mark Brown Reviewed-by: Andy Shevchenko Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20230717114511.484999-15-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- sound/soc/sof/intel/pci-apl.c | 6 ++--- sound/soc/sof/intel/pci-cnl.c | 15 ++++-------- sound/soc/sof/intel/pci-icl.c | 12 ++++------ sound/soc/sof/intel/pci-mtl.c | 3 +-- sound/soc/sof/intel/pci-skl.c | 6 ++--- sound/soc/sof/intel/pci-tgl.c | 45 ++++++++++++----------------------- sound/soc/sof/intel/pci-tng.c | 3 +-- 7 files changed, 30 insertions(+), 60 deletions(-) diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c index bc3ad64baec5..460f87f25dac 100644 --- a/sound/soc/sof/intel/pci-apl.c +++ b/sound/soc/sof/intel/pci-apl.c @@ -85,10 +85,8 @@ static const struct sof_dev_desc glk_desc = { /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { - { PCI_DEVICE(0x8086, 0x5a98), /* BXT-P (ApolloLake) */ - .driver_data = (unsigned long)&bxt_desc}, - { PCI_DEVICE(0x8086, 0x3198), /* GeminiLake */ - .driver_data = (unsigned long)&glk_desc}, + { PCI_DEVICE_DATA(INTEL, HDA_APL, &bxt_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_GML, &glk_desc) }, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); diff --git a/sound/soc/sof/intel/pci-cnl.c b/sound/soc/sof/intel/pci-cnl.c index 8895508a0be6..e2c50e7b0aa7 100644 --- a/sound/soc/sof/intel/pci-cnl.c +++ b/sound/soc/sof/intel/pci-cnl.c @@ -120,16 +120,11 @@ static const struct sof_dev_desc cml_desc = { /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { - { PCI_DEVICE(0x8086, 0x9dc8), /* CNL-LP */ - .driver_data = (unsigned long)&cnl_desc}, - { PCI_DEVICE(0x8086, 0xa348), /* CNL-H */ - .driver_data = (unsigned long)&cfl_desc}, - { PCI_DEVICE(0x8086, 0x02c8), /* CML-LP */ - .driver_data = (unsigned long)&cml_desc}, - { PCI_DEVICE(0x8086, 0x06c8), /* CML-H */ - .driver_data = (unsigned long)&cml_desc}, - { PCI_DEVICE(0x8086, 0xa3f0), /* CML-S */ - .driver_data = (unsigned long)&cml_desc}, + { PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, &cnl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_CNL_H, &cfl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_CML_LP, &cml_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_CML_H, &cml_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_CML_S, &cml_desc) }, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); diff --git a/sound/soc/sof/intel/pci-icl.c b/sound/soc/sof/intel/pci-icl.c index 5fb5a820693e..0a65df3ed9e2 100644 --- a/sound/soc/sof/intel/pci-icl.c +++ b/sound/soc/sof/intel/pci-icl.c @@ -86,14 +86,10 @@ static const struct sof_dev_desc jsl_desc = { /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { - { PCI_DEVICE(0x8086, 0x34C8), /* ICL-LP */ - .driver_data = (unsigned long)&icl_desc}, - { PCI_DEVICE(0x8086, 0x3dc8), /* ICL-H */ - .driver_data = (unsigned long)&icl_desc}, - { PCI_DEVICE(0x8086, 0x38c8), /* ICL-N */ - .driver_data = (unsigned long)&jsl_desc}, - { PCI_DEVICE(0x8086, 0x4dc8), /* JSL-N */ - .driver_data = (unsigned long)&jsl_desc}, + { PCI_DEVICE_DATA(INTEL, HDA_ICL_LP, &icl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ICL_H, &icl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ICL_N, &jsl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_JSL_N, &jsl_desc) }, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c index e276e1e37fed..7868b0827e84 100644 --- a/sound/soc/sof/intel/pci-mtl.c +++ b/sound/soc/sof/intel/pci-mtl.c @@ -52,8 +52,7 @@ static const struct sof_dev_desc mtl_desc = { /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { - { PCI_DEVICE(0x8086, 0x7E28), /* MTL */ - .driver_data = (unsigned long)&mtl_desc}, + { PCI_DEVICE_DATA(INTEL, HDA_MTL, &mtl_desc) }, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); diff --git a/sound/soc/sof/intel/pci-skl.c b/sound/soc/sof/intel/pci-skl.c index 5e69af6eed34..a6588b138a8c 100644 --- a/sound/soc/sof/intel/pci-skl.c +++ b/sound/soc/sof/intel/pci-skl.c @@ -69,10 +69,8 @@ static struct sof_dev_desc kbl_desc = { /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { - /* Sunrise Point-LP */ - { PCI_DEVICE(0x8086, 0x9d70), .driver_data = (unsigned long)&skl_desc}, - /* KBL */ - { PCI_DEVICE(0x8086, 0x9d71), .driver_data = (unsigned long)&kbl_desc}, + { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &skl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, &kbl_desc) }, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index ca37ff1bbd2a..d688f9373fb2 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -284,36 +284,21 @@ static const struct sof_dev_desc rpl_desc = { /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { - { PCI_DEVICE(0x8086, 0xa0c8), /* TGL-LP */ - .driver_data = (unsigned long)&tgl_desc}, - { PCI_DEVICE(0x8086, 0x43c8), /* TGL-H */ - .driver_data = (unsigned long)&tglh_desc}, - { PCI_DEVICE(0x8086, 0x4b55), /* EHL */ - .driver_data = (unsigned long)&ehl_desc}, - { PCI_DEVICE(0x8086, 0x4b58), /* EHL */ - .driver_data = (unsigned long)&ehl_desc}, - { PCI_DEVICE(0x8086, 0x7ad0), /* ADL-S */ - .driver_data = (unsigned long)&adls_desc}, - { PCI_DEVICE(0x8086, 0x7a50), /* RPL-S */ - .driver_data = (unsigned long)&rpls_desc}, - { PCI_DEVICE(0x8086, 0x51c8), /* ADL-P */ - .driver_data = (unsigned long)&adl_desc}, - { PCI_DEVICE(0x8086, 0x51c9), /* ADL-PS */ - .driver_data = (unsigned long)&adl_desc}, - { PCI_DEVICE(0x8086, 0x51ca), /* RPL-P */ - .driver_data = (unsigned long)&rpl_desc}, - { PCI_DEVICE(0x8086, 0x51cb), /* RPL-P */ - .driver_data = (unsigned long)&rpl_desc}, - { PCI_DEVICE(0x8086, 0x51cc), /* ADL-M */ - .driver_data = (unsigned long)&adl_desc}, - { PCI_DEVICE(0x8086, 0x51cd), /* ADL-P */ - .driver_data = (unsigned long)&adl_desc}, - { PCI_DEVICE(0x8086, 0x51ce), /* RPL-M */ - .driver_data = (unsigned long)&rpl_desc}, - { PCI_DEVICE(0x8086, 0x51cf), /* RPL-PX */ - .driver_data = (unsigned long)&rpl_desc}, - { PCI_DEVICE(0x8086, 0x54c8), /* ADL-N */ - .driver_data = (unsigned long)&adl_n_desc}, + { PCI_DEVICE_DATA(INTEL, HDA_TGL_LP, &tgl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_TGL_H, &tglh_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_EHL_0, &ehl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_EHL_3, &ehl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_S, &adls_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_S, &rpls_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_P, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_PS, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_0, &rpl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_1, &rpl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_M, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_PX, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_M, &rpl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, &rpl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_N, &adl_n_desc) }, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); diff --git a/sound/soc/sof/intel/pci-tng.c b/sound/soc/sof/intel/pci-tng.c index 8c22a00266c0..4ae4fe17cc0b 100644 --- a/sound/soc/sof/intel/pci-tng.c +++ b/sound/soc/sof/intel/pci-tng.c @@ -225,8 +225,7 @@ static const struct sof_dev_desc tng_desc = { /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { - { PCI_DEVICE(0x8086, 0x119a), - .driver_data = (unsigned long)&tng_desc}, + { PCI_DEVICE_DATA(INTEL, SST_TNG, &tng_desc) }, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); From 2218e10e6fec05f76d6cd2c7eed4cb5af447360b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Mon, 17 Jul 2023 13:45:11 +0200 Subject: [PATCH 127/334] ASoC: Intel: sst: Convert to PCI device IDs defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use PCI device IDs from pci_ids.h header. BSW replaces CHV, as 0x22a8 was added in PCI header as BSW ID for consistency, as they are same (similar) platforms. The ACPI IDs are used only internally and lower 16 bits uniquely define the device as vendor ID for Intel is 8086 for all of them. Use PCI_DEVICE_DATA() to match PCI device to be consistent with other Intel audio drivers. Suggested-by: Andy Shevchenko Acked-by: Mark Brown Reviewed-by: Cezary Rojewski Reviewed-by: Andy Shevchenko Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20230717114511.484999-16-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- sound/soc/intel/atom/sst/sst.c | 14 ++++++++++---- sound/soc/intel/atom/sst/sst.h | 7 ++----- sound/soc/intel/atom/sst/sst_pci.c | 4 ++-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index a0d29510d2bc..e0357d257c6c 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -174,9 +175,9 @@ int sst_driver_ops(struct intel_sst_drv *sst) { switch (sst->dev_id) { - case SST_MRFLD_PCI_ID: - case SST_BYT_ACPI_ID: - case SST_CHV_ACPI_ID: + case PCI_DEVICE_ID_INTEL_SST_TNG: + case PCI_DEVICE_ID_INTEL_SST_BYT: + case PCI_DEVICE_ID_INTEL_SST_BSW: sst->tstamp = SST_TIME_STAMP_MRFLD; sst->ops = &mrfld_ops; return 0; @@ -221,8 +222,13 @@ static void sst_init_locks(struct intel_sst_drv *ctx) spin_lock_init(&ctx->block_lock); } +/* + * Driver handles PCI IDs in ACPI - sst_acpi_probe() - and we are using only + * device ID part. If real ACPI ID appears, the kstrtouint() returns error, so + * we are fine with using unsigned short as dev_id type. + */ int sst_alloc_drv_context(struct intel_sst_drv **ctx, - struct device *dev, unsigned int dev_id) + struct device *dev, unsigned short dev_id) { *ctx = devm_kzalloc(dev, sizeof(struct intel_sst_drv), GFP_KERNEL); if (!(*ctx)) diff --git a/sound/soc/intel/atom/sst/sst.h b/sound/soc/intel/atom/sst/sst.h index 4d37d39fd8f4..126903e126e4 100644 --- a/sound/soc/intel/atom/sst/sst.h +++ b/sound/soc/intel/atom/sst/sst.h @@ -20,9 +20,6 @@ /* driver names */ #define SST_DRV_NAME "intel_sst_driver" -#define SST_MRFLD_PCI_ID 0x119A -#define SST_BYT_ACPI_ID 0x80860F28 -#define SST_CHV_ACPI_ID 0x808622A8 #define SST_SUSPEND_DELAY 2000 #define FW_CONTEXT_MEM (64*1024) @@ -358,7 +355,7 @@ struct sst_fw_save { struct intel_sst_drv { int sst_state; int irq_num; - unsigned int dev_id; + unsigned short dev_id; void __iomem *ddr; void __iomem *shim; void __iomem *mailbox; @@ -523,7 +520,7 @@ int sst_register(struct device *); int sst_unregister(struct device *); int sst_alloc_drv_context(struct intel_sst_drv **ctx, - struct device *dev, unsigned int dev_id); + struct device *dev, unsigned short dev_id); int sst_context_init(struct intel_sst_drv *ctx); void sst_context_cleanup(struct intel_sst_drv *ctx); void sst_configure_runtime_pm(struct intel_sst_drv *ctx); diff --git a/sound/soc/intel/atom/sst/sst_pci.c b/sound/soc/intel/atom/sst/sst_pci.c index 4058b4f80a0c..d1e64c3500be 100644 --- a/sound/soc/intel/atom/sst/sst_pci.c +++ b/sound/soc/intel/atom/sst/sst_pci.c @@ -32,7 +32,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) /* map registers */ /* DDR base */ - if (ctx->dev_id == SST_MRFLD_PCI_ID) { + if (ctx->dev_id == PCI_DEVICE_ID_INTEL_SST_TNG) { ctx->ddr_base = pci_resource_start(pci, 0); /* check that the relocated IMR base matches with FW Binary */ ddr_base = relocate_imr_addr_mrfld(ctx->ddr_base); @@ -173,7 +173,7 @@ static void intel_sst_remove(struct pci_dev *pci) /* PCI Routines */ static const struct pci_device_id intel_sst_ids[] = { - { PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0}, + { PCI_DEVICE_DATA(INTEL, SST_TNG, 0) }, { 0, } }; From 317af09e296f70e4fb55b17f49655e103a794172 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:14 +0100 Subject: [PATCH 128/334] ASoC: cs35l36: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the cs35l36 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-1-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l36.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c index 04ba7f25012e..20084c7d3acb 100644 --- a/sound/soc/codecs/cs35l36.c +++ b/sound/soc/codecs/cs35l36.c @@ -1312,7 +1312,7 @@ static struct regmap_config cs35l36_regmap = { .precious_reg = cs35l36_precious_reg, .volatile_reg = cs35l36_volatile_reg, .readable_reg = cs35l36_readable_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static irqreturn_t cs35l36_irq(int irq, void *data) From 78138627acc014dc3a23cb6f29f53a025544743f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:15 +0100 Subject: [PATCH 129/334] ASoC: cs35l41: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the cs35l41 driver to use the more modern data structure. Tested-by: Charles Keepax Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-2-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l41-lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c index 1e4205295a0d..ac7cc492bcb0 100644 --- a/sound/soc/codecs/cs35l41-lib.c +++ b/sound/soc/codecs/cs35l41-lib.c @@ -743,7 +743,7 @@ struct regmap_config cs35l41_regmap_i2c = { .volatile_reg = cs35l41_volatile_reg, .readable_reg = cs35l41_readable_reg, .precious_reg = cs35l41_precious_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_GPL(cs35l41_regmap_i2c); @@ -760,7 +760,7 @@ struct regmap_config cs35l41_regmap_spi = { .volatile_reg = cs35l41_volatile_reg, .readable_reg = cs35l41_readable_reg, .precious_reg = cs35l41_precious_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_GPL(cs35l41_regmap_spi); From f9ad18b24c24b06820fcd72975f1b08b1d466168 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:16 +0100 Subject: [PATCH 130/334] ASoC: cs35l45: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the cs35l45 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-3-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l45-tables.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs35l45-tables.c b/sound/soc/codecs/cs35l45-tables.c index 066f83c0c7ac..621af1785979 100644 --- a/sound/soc/codecs/cs35l45-tables.c +++ b/sound/soc/codecs/cs35l45-tables.c @@ -255,7 +255,7 @@ const struct regmap_config cs35l45_i2c_regmap = { .num_reg_defaults = ARRAY_SIZE(cs35l45_defaults), .volatile_reg = cs35l45_volatile_reg, .readable_reg = cs35l45_readable_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_NS_GPL(cs35l45_i2c_regmap, SND_SOC_CS35L45); @@ -271,7 +271,7 @@ const struct regmap_config cs35l45_spi_regmap = { .num_reg_defaults = ARRAY_SIZE(cs35l45_defaults), .volatile_reg = cs35l45_volatile_reg, .readable_reg = cs35l45_readable_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_NS_GPL(cs35l45_spi_regmap, SND_SOC_CS35L45); From faa48c9bdaa1625b008d07ce08660d56f198592c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:17 +0100 Subject: [PATCH 131/334] ASoC: cs35l56: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the cs35l56 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-4-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56-shared.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index 60da8c75b7b9..d561fbdc12de 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -319,7 +319,7 @@ struct regmap_config cs35l56_regmap_i2c = { .volatile_reg = cs35l56_volatile_reg, .readable_reg = cs35l56_readable_reg, .precious_reg = cs35l56_precious_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_i2c, SND_SOC_CS35L56_SHARED); @@ -336,7 +336,7 @@ struct regmap_config cs35l56_regmap_spi = { .volatile_reg = cs35l56_volatile_reg, .readable_reg = cs35l56_readable_reg, .precious_reg = cs35l56_precious_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_spi, SND_SOC_CS35L56_SHARED); @@ -352,7 +352,7 @@ struct regmap_config cs35l56_regmap_sdw = { .volatile_reg = cs35l56_volatile_reg, .readable_reg = cs35l56_readable_reg, .precious_reg = cs35l56_precious_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_sdw, SND_SOC_CS35L56_SHARED); From b5a0e5e4bf96de3d34f3d36afc32b3e9cd0376c2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:18 +0100 Subject: [PATCH 132/334] ASoC: cs42l51: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the cs42l51 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-5-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l51.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index a67cd3ee84e0..36066fac394f 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -703,7 +703,7 @@ const struct regmap_config cs42l51_regmap = { .volatile_reg = cs42l51_volatile_reg, .writeable_reg = cs42l51_writeable_reg, .max_register = CS42L51_CHARGE_FREQ, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_GPL(cs42l51_regmap); From b0a0e231abb5c3753d479d49d62308c7a1b20838 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:19 +0100 Subject: [PATCH 133/334] ASoC: cs4265: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the cs4265 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-6-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs4265.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index 0cfc5ab36a13..1ed1e60d8e53 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -564,7 +564,7 @@ static const struct regmap_config cs4265_regmap = { .num_reg_defaults = ARRAY_SIZE(cs4265_reg_defaults), .readable_reg = cs4265_readable_register, .volatile_reg = cs4265_volatile_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int cs4265_i2c_probe(struct i2c_client *i2c_client) From 7a2827ad082cb70bb7884e5630b58503e41b2932 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:20 +0100 Subject: [PATCH 134/334] ASoC: cs4270: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the cs4270 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-7-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs4270.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index ab32f15e3b44..3df567214952 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -636,7 +636,7 @@ static const struct regmap_config cs4270_regmap = { .max_register = CS4270_LASTREG, .reg_defaults = cs4270_reg_defaults, .num_reg_defaults = ARRAY_SIZE(cs4270_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .write_flag_mask = CS4270_I2C_INCR, .readable_reg = cs4270_reg_is_readable, From 99d2c7b8e50458bb620bb7b3d2ed809484a7ecd3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:21 +0100 Subject: [PATCH 135/334] ASoC: cs42l52: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the cs42l52 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-8-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l52.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 1f1ded0ff0ac..4fc8a6ae8d92 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -1084,7 +1084,7 @@ static const struct regmap_config cs42l52_regmap = { .num_reg_defaults = ARRAY_SIZE(cs42l52_reg_defaults), .readable_reg = cs42l52_readable_register, .volatile_reg = cs42l52_volatile_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int cs42l52_i2c_probe(struct i2c_client *i2c_client) From cb8ac2658f8ae2a3a921b0c4f3400922e361597f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:22 +0100 Subject: [PATCH 136/334] ASoC: cs42l56: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the cs42l56 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-9-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l56.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 4c646e8d72aa..1714857594fb 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -1125,7 +1125,7 @@ static const struct regmap_config cs42l56_regmap = { .num_reg_defaults = ARRAY_SIZE(cs42l56_reg_defaults), .readable_reg = cs42l56_readable_register, .volatile_reg = cs42l56_volatile_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int cs42l56_handle_of_data(struct i2c_client *i2c_client, From e3753fd3b362e01c9faabbea4412d6eae24cfdff Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:23 +0100 Subject: [PATCH 137/334] ASoC: cs42xx8: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the cs42xx8 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-10-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs42xx8.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index 4558ec38a7ac..9c44b6283b8f 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -458,7 +458,7 @@ const struct regmap_config cs42xx8_regmap_config = { .num_reg_defaults = ARRAY_SIZE(cs42xx8_reg), .volatile_reg = cs42xx8_volatile_register, .writeable_reg = cs42xx8_writeable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_GPL(cs42xx8_regmap_config); From a4ccfe889dfe1eb1b6304402169b140fc329f535 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:24 +0100 Subject: [PATCH 138/334] ASoC: cs4349: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the cs4349 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-11-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs4349.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 8365dd0ebe2a..ef08e51901b5 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -271,7 +271,7 @@ static const struct regmap_config cs4349_regmap = { .num_reg_defaults = ARRAY_SIZE(cs4349_reg_defaults), .readable_reg = cs4349_readable_register, .writeable_reg = cs4349_writeable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int cs4349_i2c_probe(struct i2c_client *client) From 4c04586a7962598933313fd08f19ed76138c1fd9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:25 +0100 Subject: [PATCH 139/334] ASoC: wm2200: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm2200 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-12-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 277b8c468c78..36cdf97993a5 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2151,7 +2151,7 @@ static const struct regmap_config wm2200_regmap = { .num_reg_defaults = ARRAY_SIZE(wm2200_reg_defaults), .volatile_reg = wm2200_volatile_register, .readable_reg = wm2200_readable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .ranges = wm2200_ranges, .num_ranges = ARRAY_SIZE(wm2200_ranges), }; From 4f2e3688abee076f49b78b5d4fca67bb37dbe375 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:26 +0100 Subject: [PATCH 140/334] ASoC: wm5100: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm5100 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-13-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm5100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index a86eacb2a9bb..ff63723928a1 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2400,7 +2400,7 @@ static const struct regmap_config wm5100_regmap = { .num_reg_defaults = ARRAY_SIZE(wm5100_reg_defaults), .volatile_reg = wm5100_volatile_register, .readable_reg = wm5100_readable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static const unsigned int wm5100_mic_ctrl_reg[] = { From 1a37aa4195e2169f2ad6d74608bfcaa95697c9f8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:27 +0100 Subject: [PATCH 141/334] ASoC: wm9081: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm9081 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-14-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm9081.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 34a07db7342a..e7ec799573d3 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -1295,7 +1295,7 @@ static const struct regmap_config wm9081_regmap = { .num_reg_defaults = ARRAY_SIZE(wm9081_reg), .volatile_reg = wm9081_volatile_register, .readable_reg = wm9081_readable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int wm9081_i2c_probe(struct i2c_client *i2c) From b028b1efe7103e5a2a01d7ca087fd43c2d4977e6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:28 +0100 Subject: [PATCH 142/334] ASoC: wm9090: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm9090 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-15-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm9090.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index 432729c753dd..50c1cbccfdb9 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -553,7 +553,7 @@ static const struct regmap_config wm9090_regmap = { .volatile_reg = wm9090_volatile, .readable_reg = wm9090_readable, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm9090_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm9090_reg_defaults), }; From d3c4ba7dbe15e5268ba07f2dcefafd274d110e80 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:29 +0100 Subject: [PATCH 143/334] ASoC: wm8510: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8510 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-16-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8510.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index c0ed76d5b65f..6636a70f3895 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -607,7 +607,7 @@ static const struct regmap_config wm8510_regmap = { .reg_defaults = wm8510_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8510_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8510_volatile, }; From 247c6960bfdabeae5088b4ecf5e06a68b1ae492a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:30 +0100 Subject: [PATCH 144/334] ASoC: wm8523: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8523 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-17-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8523.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 55c72c5ac845..ea87cd3cc0d6 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -437,7 +437,7 @@ static const struct regmap_config wm8523_regmap = { .reg_defaults = wm8523_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8523_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8523_volatile_register, }; From 43bc153d2e684dcbd23311899c136b183ba21840 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:31 +0100 Subject: [PATCH 145/334] ASoC: wm8580: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8580 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-18-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8580.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 34ae7fe05398..6d22f7d40ec2 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -975,7 +975,7 @@ static const struct regmap_config wm8580_regmap = { .reg_defaults = wm8580_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8580_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8580_volatile, }; From 368a233bc3cf590bea7f27774cc94ff121addd65 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:32 +0100 Subject: [PATCH 146/334] ASoC: wm8711: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8711 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-19-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8711.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 903a0147d584..916f297164de 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -393,7 +393,7 @@ static const struct regmap_config wm8711_regmap = { .reg_defaults = wm8711_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8711_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8711_volatile, }; From 9a2abf70e2635a59fde1806994387a79fb351308 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:33 +0100 Subject: [PATCH 147/334] ASoC: wm8728: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8728 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-20-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8728.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 5ea6d8fd10f6..0c943e7d4159 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -236,7 +236,7 @@ static const struct regmap_config wm8728_regmap = { .reg_defaults = wm8728_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8728_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; #if defined(CONFIG_SPI_MASTER) From 59bd5113d8ca0765e8f12307a4b1ac0e3daa91f4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:34 +0100 Subject: [PATCH 148/334] ASoC: wm8731: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8731 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-21-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8731.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index d5ab3ba126a6..efc160c75f40 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -642,7 +642,7 @@ const struct regmap_config wm8731_regmap = { .max_register = WM8731_RESET, .volatile_reg = wm8731_volatile, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8731_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8731_reg_defaults), }; From ee8169f94985e5c88d2c4e9daed0b5f8345032b1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:35 +0100 Subject: [PATCH 149/334] ASoC: wm8737: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8737 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-22-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8737.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index 9f4e372e90ea..0d231c289ef3 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -599,7 +599,7 @@ static const struct regmap_config wm8737_regmap = { .reg_defaults = wm8737_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8737_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8737_volatile, }; From 5dd4ddde85586f4b53be219f27cac2cd15e02417 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:36 +0100 Subject: [PATCH 150/334] ASoC: wm8741: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8741 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-23-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8741.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index 787156b980a1..19e8fc4062c7 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -543,7 +543,7 @@ static const struct regmap_config wm8741_regmap = { .reg_defaults = wm8741_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8741_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741) From ef1589123dbb7102b49f9997c5b31b0721aff242 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:37 +0100 Subject: [PATCH 151/334] ASoC: wm8750: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8750 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-24-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8750.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 20dc9ff9fea9..2d2feaf95e49 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -735,7 +735,7 @@ static const struct regmap_config wm8750_regmap = { .reg_defaults = wm8750_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8750_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; #if defined(CONFIG_SPI_MASTER) From 3c884cb5c28c45197b81bbdcf2d41a37649ee895 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:38 +0100 Subject: [PATCH 152/334] ASoC: wm8753: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8753 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-25-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8753.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 5e8a8eb41b2b..b5d8290c37d9 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1507,7 +1507,7 @@ static const struct regmap_config wm8753_regmap = { .max_register = WM8753_ADCTL2, .volatile_reg = wm8753_volatile, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8753_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8753_reg_defaults), }; From 7aa7ab713b71fddc71603b9b3c9ab963fd9831a4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:39 +0100 Subject: [PATCH 153/334] ASoC: wm8770: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8770 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-26-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8770.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index e03fee8869c3..2469f4f3bea3 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c @@ -632,7 +632,7 @@ static const struct regmap_config wm8770_regmap = { .reg_defaults = wm8770_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8770_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8770_volatile_reg, }; From 080c82a56659fd5cbf811007193bf04d3c31922e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:40 +0100 Subject: [PATCH 154/334] ASoC: wm8776: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8776 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-27-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8776.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index 212224a68006..0673bbd32bab 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -451,7 +451,7 @@ static const struct regmap_config wm8776_regmap = { .reg_defaults = wm8776_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8776_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8776_volatile, }; From 200ba27767702c11f965e619b43ebfe9989a1996 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:41 +0100 Subject: [PATCH 155/334] ASoC: wm8804: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8804 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-28-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8804.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 0b234bae480e..bbb4b6e3b41c 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -555,7 +555,7 @@ const struct regmap_config wm8804_regmap_config = { .max_register = WM8804_MAX_REGISTER, .volatile_reg = wm8804_volatile, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8804_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8804_reg_defaults), }; From 2c609c6b42c911df772d97c4ddf10d9374607e0c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:42 +0100 Subject: [PATCH 156/334] ASoC: wm8900: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8900 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-29-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8900.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 320ccd92f318..84d06c190411 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1223,7 +1223,7 @@ static const struct regmap_config wm8900_regmap = { .reg_defaults = wm8900_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8900_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8900_volatile_register, }; From 7de380eeba5b616a4bf08acbbc5aa6e76bcb4299 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:43 +0100 Subject: [PATCH 157/334] ASoC: wm8903: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8903 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-30-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 901b65ef8de5..84ae1102ac88 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1902,7 +1902,7 @@ static const struct regmap_config wm8903_regmap = { .volatile_reg = wm8903_volatile_register, .readable_reg = wm8903_readable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8903_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8903_reg_defaults), }; From 9bd4bc4cb48927d581ff2886bf701bfdb4735724 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:44 +0100 Subject: [PATCH 158/334] ASoC: wm8904: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8904 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-31-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8904.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 068e610b1b4c..ac4e1654a967 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -2148,7 +2148,7 @@ static const struct regmap_config wm8904_regmap = { .volatile_reg = wm8904_volatile_register, .readable_reg = wm8904_readable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8904_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8904_reg_defaults), }; From 11e1354036391054f496aa4c4e724e160dfcded2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:45 +0100 Subject: [PATCH 159/334] ASoC: wm8960: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8960 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-32-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index b2c1432d4f9b..92fb7ab6e896 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -1387,7 +1387,7 @@ static const struct regmap_config wm8960_regmap = { .reg_defaults = wm8960_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8960_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8960_volatile, }; From d643047ec77ed17fef7b2ce76ecd5e88b3b5f7d8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:46 +0100 Subject: [PATCH 160/334] ASoC: wm8961: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8961 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-33-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8961.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index c076f78d04ce..8f8330efb341 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -904,7 +904,7 @@ static const struct regmap_config wm8961_regmap = { .reg_defaults = wm8961_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8961_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8961_volatile, .readable_reg = wm8961_readable, From 3a17f8d71bba92538165a5b55f095b7cb0e71529 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:47 +0100 Subject: [PATCH 161/334] ASoC: wm8962: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8962 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-34-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8962.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 68ea15be7330..83ce5dbecc45 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3573,7 +3573,7 @@ static const struct regmap_config wm8962_regmap = { .num_reg_defaults = ARRAY_SIZE(wm8962_reg), .volatile_reg = wm8962_volatile_register, .readable_reg = wm8962_readable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int wm8962_set_pdata_from_of(struct i2c_client *i2c, From 3aceedcda294273bedf7af7836e2457a98836b09 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:48 +0100 Subject: [PATCH 162/334] ASoC: wm8991: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8991 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-35-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8991.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 8cb2ae829699..590318aafaea 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -1253,7 +1253,7 @@ static const struct regmap_config wm8991_regmap = { .volatile_reg = wm8991_volatile, .reg_defaults = wm8991_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8991_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int wm8991_i2c_probe(struct i2c_client *i2c) From 663aa3325f5b971596b08c768bc705cc6f49dd18 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:49 +0100 Subject: [PATCH 163/334] ASoC: wm8993: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8993 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-36-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8993.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index feb997c698e2..5b788f35e5e4 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1608,7 +1608,7 @@ static const struct regmap_config wm8993_regmap = { .volatile_reg = wm8993_volatile, .readable_reg = wm8993_readable, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8993_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8993_reg_defaults), }; From ae394355be78c6be4da1a6f18da8b588215aaa2c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:50 +0100 Subject: [PATCH 164/334] ASoC: wm8995: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8995 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-37-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8995.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 90588614edcc..4ffa1896faab 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -2193,7 +2193,7 @@ static const struct regmap_config wm8995_regmap = { .num_reg_defaults = ARRAY_SIZE(wm8995_reg_defaults), .volatile_reg = wm8995_volatile, .readable_reg = wm8995_readable, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; #if defined(CONFIG_SPI_MASTER) From a4b6c6ec975c9f871cbde1f30a554665475498ef Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:51 +0100 Subject: [PATCH 165/334] ASoC: wm8996: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8996 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-38-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8996.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 5d0eb0ae0475..df6195778c57 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2610,7 +2610,7 @@ static const struct regmap_config wm8996_regmap = { .num_reg_defaults = ARRAY_SIZE(wm8996_reg), .volatile_reg = wm8996_volatile_register, .readable_reg = wm8996_readable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int wm8996_probe(struct snd_soc_component *component) From 9bed789c4f14bd607892ff31d9164b5ed544ebaf Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:52 +0100 Subject: [PATCH 166/334] ASoC: wm8940: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the w8940 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-39-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8940.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 53c27986d216..b9432f8b64e5 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -815,7 +815,7 @@ static const struct regmap_config wm8940_regmap = { .max_register = WM8940_MONOMIX, .reg_defaults = wm8940_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8940_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .readable_reg = wm8940_readable_register, .volatile_reg = wm8940_volatile_register, From 6066d156a3a36139feb0c80645dddadae2ddaf01 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:53 +0100 Subject: [PATCH 167/334] ASoC: wm8955: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8955 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-40-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8955.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 78044f580a67..4f4338326438 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -962,7 +962,7 @@ static const struct regmap_config wm8955_regmap = { .volatile_reg = wm8955_volatile, .writeable_reg = wm8955_writeable, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8955_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8955_reg_defaults), }; From 97f93367cd735813aa5bf0d7ef64c956a7ac8013 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:54 +0100 Subject: [PATCH 168/334] ASoC: wm8971: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8971 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-41-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8971.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index b22d8f0b59be..e88f323d28b2 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -668,7 +668,7 @@ static const struct regmap_config wm8971_regmap = { .reg_defaults = wm8971_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8971_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int wm8971_i2c_probe(struct i2c_client *i2c) From 5891932208f76375940a2a96b113fd328b70ddd1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:55 +0100 Subject: [PATCH 169/334] ASoC: wm8978: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8978 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-42-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8978.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index 5c829301cf4c..718bfef302cc 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -1014,7 +1014,7 @@ static const struct regmap_config wm8978_regmap_config = { .max_register = WM8978_MAX_REGISTER, .volatile_reg = wm8978_volatile, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8978_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8978_reg_defaults), }; From 20dbc7a892ffe6aa20a4b1eaf0353cdf4c762fcb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:56 +0100 Subject: [PATCH 170/334] ASoC: wm8983: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8983 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-43-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8983.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index 2bd26e2478d9..b26d6a68e8d2 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -995,7 +995,7 @@ static const struct regmap_config wm8983_regmap = { .reg_defaults = wm8983_defaults, .num_reg_defaults = ARRAY_SIZE(wm8983_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = WM8983_MAX_REGISTER, .writeable_reg = wm8983_writeable, From 2fa0213ed798bee59fa815171d3855dcc133a416 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:57 +0100 Subject: [PATCH 171/334] ASoC: wm8985: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8985 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-44-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8985.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index c0816bcfa294..8606e0752a60 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c @@ -1125,7 +1125,7 @@ static const struct regmap_config wm8985_regmap = { .max_register = WM8985_MAX_REGISTER, .writeable_reg = wm8985_writeable, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8985_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8985_reg_defaults), }; From fb60b65a65b038f1881a3f1a0146c07e22f647d0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:58 +0100 Subject: [PATCH 172/334] ASoC: wm8988: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm8988 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-45-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8988.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index b440719cca7d..76f214f12ce0 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -832,7 +832,7 @@ static const struct regmap_config wm8988_regmap = { .max_register = WM8988_LPPB, .writeable_reg = wm8988_writeable, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8988_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8988_reg_defaults), }; From 7e510925e00d1daea10f9474505b4f1b9ec24433 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:59 +0100 Subject: [PATCH 173/334] ASoC: wm9705: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm9705 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-46-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm9705.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index d04902ef1d5f..5c6aebe29cf1 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -64,7 +64,7 @@ static const struct regmap_config wm9705_regmap_config = { .reg_stride = 2, .val_bits = 16, .max_register = 0x7e, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = regmap_ac97_default_volatile, From 2e3a4ee07211b047881b3f2e944453cdd4deaf96 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:14:00 +0100 Subject: [PATCH 174/334] ASoC: wm9712: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm9712 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-47-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm9712.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index df9b7980706b..e63921de0c37 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -86,7 +86,7 @@ static const struct regmap_config wm9712_regmap_config = { .reg_stride = 2, .val_bits = 16, .max_register = 0x7e, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm9712_volatile_reg, From 8bfb4c81b9c896448e5d7229f1849bd0ad7c2f20 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:14:01 +0100 Subject: [PATCH 175/334] ASoC: wm9713: Update to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. In v6.5 it has also acquired the ability to generate multi-register writes in sync operations, bringing performance up to parity with the rbtree cache there. Update the wm9713 driver to use the more modern data structure. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230713-asoc-cirrus-maple-v1-48-a62651831735@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm9713.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 5d2e54e06e30..64b69316e4c7 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -727,7 +727,7 @@ static const struct regmap_config wm9713_regmap_config = { .reg_stride = 2, .val_bits = 16, .max_register = 0x7e, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm9713_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm9713_reg_defaults), From c1325a2d5182f263f2edbc6e0c1e581e4c5d5a95 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 18 Jul 2023 10:04:18 +0300 Subject: [PATCH 176/334] ASoC: amd: acp: delete unnecessary NULL check The list iterator can't be NULL. Delete the check and pull the code in one tab. Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/b0c5b0ca-68da-47e6-a8b0-e0714f0de119@moroto.mountain Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-rembrandt.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c index 21e67ed956d1..cc8284f417c0 100644 --- a/sound/soc/amd/acp/acp-rembrandt.c +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -266,18 +266,16 @@ static int __maybe_unused rmb_pcm_resume(struct device *dev) acp6x_master_clock_generate(dev); spin_lock(&adata->acp_lock); list_for_each_entry(stream, &adata->stream_list, list) { - if (stream) { - substream = stream->substream; - if (substream && substream->runtime) { - buf_in_frames = (substream->runtime->buffer_size); - buf_size = frames_to_bytes(substream->runtime, buf_in_frames); - config_pte_for_stream(adata, stream); - config_acp_dma(adata, stream, buf_size); - if (stream->dai_id) - restore_acp_i2s_params(substream, adata, stream); - else - restore_acp_pdm_params(substream, adata); - } + substream = stream->substream; + if (substream && substream->runtime) { + buf_in_frames = (substream->runtime->buffer_size); + buf_size = frames_to_bytes(substream->runtime, buf_in_frames); + config_pte_for_stream(adata, stream); + config_acp_dma(adata, stream, buf_size); + if (stream->dai_id) + restore_acp_i2s_params(substream, adata, stream); + else + restore_acp_pdm_params(substream, adata); } } spin_unlock(&adata->acp_lock); From da7c07b1083809888c82522e74370f962fb7685e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Jul 2023 01:28:42 +0100 Subject: [PATCH 177/334] driver core: Provide stubs for !IOMEM builds The various _ioremap_resource functions are not built when CONFIG_HAS_IOMEM is disabled but no stubs are provided. Given how widespread IOMEM usage is in drivers and how rare !IOMEM configurations are in practical use let's just provide some stubs so users will build without having to add explicit dependencies on HAS_IOMEM. The most likely use case is builds with UML for KUnit testing. Reviewed-by: Greg Kroah-Hartman Reviewed-by: David Gow Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230718-asoc-topology-kunit-enable-v2-1-0ee11e662b92@kernel.org Signed-off-by: Mark Brown --- include/linux/device.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/include/linux/device.h b/include/linux/device.h index bbaeabd04b0d..6731d7dc1a2a 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -349,6 +349,7 @@ unsigned long devm_get_free_pages(struct device *dev, gfp_t gfp_mask, unsigned int order); void devm_free_pages(struct device *dev, unsigned long addr); +#ifdef CONFIG_HAS_IOMEM void __iomem *devm_ioremap_resource(struct device *dev, const struct resource *res); void __iomem *devm_ioremap_resource_wc(struct device *dev, @@ -357,6 +358,31 @@ void __iomem *devm_ioremap_resource_wc(struct device *dev, void __iomem *devm_of_iomap(struct device *dev, struct device_node *node, int index, resource_size_t *size); +#else + +static inline +void __iomem *devm_ioremap_resource(struct device *dev, + const struct resource *res) +{ + return ERR_PTR(-EINVAL); +} + +static inline +void __iomem *devm_ioremap_resource_wc(struct device *dev, + const struct resource *res) +{ + return ERR_PTR(-EINVAL); +} + +static inline +void __iomem *devm_of_iomap(struct device *dev, + struct device_node *node, int index, + resource_size_t *size) +{ + return ERR_PTR(-EINVAL); +} + +#endif /* allows to add/remove a custom action to devres stack */ void devm_remove_action(struct device *dev, void (*action)(void *), void *data); From a0c74f6c9ea9cebd7a8f38142bf87e7c12c2905d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Jul 2023 01:28:43 +0100 Subject: [PATCH 178/334] platform: Provide stubs for !HAS_IOMEM builds The various _ioremap_resource functions are not built when CONFIG_HAS_IOMEM is disabled but no stubs are provided. Given how widespread IOMEM usage is in drivers and how rare !IOMEM configurations are in practical use let's just provide some stubs so users will build without having to add explicit dependencies on IOMEM. The most likely use case is builds with UML for KUnit testing. Reviewed-by: Greg Kroah-Hartman Reviewed-by: David Gow Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230718-asoc-topology-kunit-enable-v2-2-0ee11e662b92@kernel.org Signed-off-by: Mark Brown --- include/linux/platform_device.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index b845fd83f429..7a41c72c1959 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -63,6 +63,8 @@ extern struct resource *platform_get_mem_or_io(struct platform_device *, extern struct device * platform_find_device_by_driver(struct device *start, const struct device_driver *drv); + +#ifdef CONFIG_HAS_IOMEM extern void __iomem * devm_platform_get_and_ioremap_resource(struct platform_device *pdev, unsigned int index, struct resource **res); @@ -72,6 +74,32 @@ devm_platform_ioremap_resource(struct platform_device *pdev, extern void __iomem * devm_platform_ioremap_resource_byname(struct platform_device *pdev, const char *name); +#else + +static inline void __iomem * +devm_platform_get_and_ioremap_resource(struct platform_device *pdev, + unsigned int index, struct resource **res) +{ + return ERR_PTR(-EINVAL); +} + + +static inline void __iomem * +devm_platform_ioremap_resource(struct platform_device *pdev, + unsigned int index) +{ + return ERR_PTR(-EINVAL); +} + +static inline void __iomem * +devm_platform_ioremap_resource_byname(struct platform_device *pdev, + const char *name) +{ + return ERR_PTR(-EINVAL); +} + +#endif + extern int platform_get_irq(struct platform_device *, unsigned int); extern int platform_get_irq_optional(struct platform_device *, unsigned int); extern int platform_irq_count(struct platform_device *); From 512d092d78823f9813f4af38090b33c454137a4c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Jul 2023 01:28:44 +0100 Subject: [PATCH 179/334] ALSA: Enable build with UML In order to facilitate testing using KUnit allow ALSA to build with UML, it's not super useful at runtime but that's a user problem rather than an actual dependency. The apparent reason for the dependency was the widespread use of iomem APIs in ALSA drivers, earlier patches in this series have provided stubs for these APIs so that there are no build time issues even without individual drivers having IOMEM dependencies added. Tested-by: David Gow Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230718-asoc-topology-kunit-enable-v2-3-0ee11e662b92@kernel.org Signed-off-by: Mark Brown --- sound/Kconfig | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/Kconfig b/sound/Kconfig index 0ddfb717b81d..f0e15822e858 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -39,8 +39,6 @@ config SOUND_OSS_CORE_PRECLAIM source "sound/oss/dmasound/Kconfig" -if !UML - menuconfig SND tristate "Advanced Linux Sound Architecture" help @@ -103,8 +101,6 @@ source "sound/virtio/Kconfig" endif # SND -endif # !UML - endif # SOUND config AC97_BUS From 5aaa4024e14f8b878a348338a74b4c97bc2478b1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Jul 2023 01:28:45 +0100 Subject: [PATCH 180/334] kunit: Enable ASoC in all_tests.config There are KUnit tests for some of the ASoC utility functions which are not enabled in the KUnit all_tests.config, do so. Reviewed-by: David Gow Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230718-asoc-topology-kunit-enable-v2-4-0ee11e662b92@kernel.org Signed-off-by: Mark Brown --- tools/testing/kunit/configs/all_tests.config | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/testing/kunit/configs/all_tests.config b/tools/testing/kunit/configs/all_tests.config index 0393940c706a..13d15bc693fb 100644 --- a/tools/testing/kunit/configs/all_tests.config +++ b/tools/testing/kunit/configs/all_tests.config @@ -35,3 +35,7 @@ CONFIG_DAMON_DBGFS=y CONFIG_SECURITY=y CONFIG_SECURITY_APPARMOR=y + +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_SOC=y From b7dc237ef8b0897f5750a738d2c57469909a6a15 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Jul 2023 01:28:46 +0100 Subject: [PATCH 181/334] ASoC: topology: Add explicit build option The default KUnit build options are not supposed to enable any subsystems that were not already enabled but the topology code is a library which is generally selected by drivers that want to use it. Since KUnit is frequently run in virtual environments with minimal driver support this makes it difficult to enable the toplogy tests so provide an explicit Kconfig option which can be directly enabled when using KUnit, and also include this in the KUnit all_tests.config. Reviewed-by: David Gow Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230718-asoc-topology-kunit-enable-v2-5-0ee11e662b92@kernel.org Signed-off-by: Mark Brown --- sound/soc/Kconfig | 11 +++++++++++ tools/testing/kunit/configs/all_tests.config | 1 + 2 files changed, 12 insertions(+) diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index bfa9622e1ab1..439fa631c342 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -38,6 +38,17 @@ config SND_SOC_TOPOLOGY bool select SND_DYNAMIC_MINORS +config SND_SOC_TOPOLOGY_BUILD + bool "Build topology core" + select SND_SOC_TOPOLOGY + depends on KUNIT + help + This option exists to facilitate running the KUnit tests for + the topology core, KUnit is frequently tested in virtual + environments with minimal drivers enabled but the topology + core is usually selected by drivers. There is little reason + to enable it if not doing a KUnit build. + config SND_SOC_TOPOLOGY_KUNIT_TEST tristate "KUnit tests for SoC topology" depends on KUNIT diff --git a/tools/testing/kunit/configs/all_tests.config b/tools/testing/kunit/configs/all_tests.config index 13d15bc693fb..b8adb59455ef 100644 --- a/tools/testing/kunit/configs/all_tests.config +++ b/tools/testing/kunit/configs/all_tests.config @@ -39,3 +39,4 @@ CONFIG_SECURITY_APPARMOR=y CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_SOC=y +CONFIG_SND_SOC_TOPOLOGY_BUILD=y From df4167d658d45946677f91d84e9d40570c875cb8 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 18 Jul 2023 15:46:25 +0100 Subject: [PATCH 182/334] ASoC: cs35l56: Patch soft registers to defaults The soft (firmware) registers for volume/mute/posture are not reset by a chip soft-reset, so use a regmap patch to set them to defaults. cs35l56_reread_firmware_registers() has been removed. Its intent was to use whatever the firmware set as a default. But the driver now patches the defaults to the registers. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230718144625.39634-1-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l56.h | 2 +- sound/soc/codecs/cs35l56-shared.c | 38 +++++++++++++------------------ sound/soc/codecs/cs35l56.c | 5 ++-- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index 1f9713d7ca76..ec672daa36cf 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -260,7 +260,7 @@ extern const struct cs_dsp_region cs35l56_dsp1_regions[CS35L56_NUM_DSP_REGIONS]; extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC]; extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC]; -void cs35l56_reread_firmware_registers(struct device *dev, struct regmap *regmap); +int cs35l56_set_patch(struct regmap *regmap); int cs35l56_get_bclk_freq_id(unsigned int freq); void cs35l56_fill_supply_names(struct regulator_bulk_data *data); diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index 60da8c75b7b9..7126f06b8047 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -11,6 +11,19 @@ #include "cs35l56.h" +static const struct reg_sequence cs35l56_patch[] = { + /* These are not reset by a soft-reset, so patch to defaults. */ + { CS35L56_MAIN_RENDER_USER_MUTE, 0x00000000 }, + { CS35L56_MAIN_RENDER_USER_VOLUME, 0x00000000 }, + { CS35L56_MAIN_POSTURE_NUMBER, 0x00000000 }, +}; + +int cs35l56_set_patch(struct regmap *regmap) +{ + return regmap_register_patch(regmap, cs35l56_patch, ARRAY_SIZE(cs35l56_patch)); +} +EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, SND_SOC_CS35L56_SHARED); + static const struct reg_default cs35l56_reg_defaults[] = { { CS35L56_ASP1_ENABLES1, 0x00000000 }, { CS35L56_ASP1_CONTROL1, 0x00000028 }, @@ -35,9 +48,9 @@ static const struct reg_default cs35l56_reg_defaults[] = { { CS35L56_IRQ1_MASK_8, 0xfc000fff }, { CS35L56_IRQ1_MASK_18, 0x1f7df0ff }, { CS35L56_IRQ1_MASK_20, 0x15c00000 }, - /* CS35L56_MAIN_RENDER_USER_MUTE - soft register, no default */ - /* CS35L56_MAIN_RENDER_USER_VOLUME - soft register, no default */ - /* CS35L56_MAIN_POSTURE_NUMBER - soft register, no default */ + { CS35L56_MAIN_RENDER_USER_MUTE, 0x00000000 }, + { CS35L56_MAIN_RENDER_USER_VOLUME, 0x00000000 }, + { CS35L56_MAIN_POSTURE_NUMBER, 0x00000000 }, }; static bool cs35l56_is_dsp_memory(unsigned int reg) @@ -181,25 +194,6 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg) } } -static const u32 cs35l56_firmware_registers[] = { - CS35L56_MAIN_RENDER_USER_MUTE, - CS35L56_MAIN_RENDER_USER_VOLUME, - CS35L56_MAIN_POSTURE_NUMBER, -}; - -void cs35l56_reread_firmware_registers(struct device *dev, struct regmap *regmap) -{ - int i; - unsigned int val; - - for (i = 0; i < ARRAY_SIZE(cs35l56_firmware_registers); i++) { - regmap_read(regmap, cs35l56_firmware_registers[i], &val); - dev_dbg(dev, "%s: %d: %#x: %#x\n", __func__, - i, cs35l56_firmware_registers[i], val); - } -} -EXPORT_SYMBOL_NS_GPL(cs35l56_reread_firmware_registers, SND_SOC_CS35L56_SHARED); - const struct cs_dsp_region cs35l56_dsp1_regions[] = { { .type = WMFW_HALO_PM_PACKED, .base = CS35L56_DSP1_PMEM_0 }, { .type = WMFW_HALO_XM_PACKED, .base = CS35L56_DSP1_XMEM_PACKED_0 }, diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index c03f9d3c9a13..e046fdd26b74 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -1572,8 +1572,9 @@ int cs35l56_init(struct cs35l56_private *cs35l56) if (ret) return ret; - /* Populate soft registers in the regmap cache */ - cs35l56_reread_firmware_registers(cs35l56->dev, cs35l56->regmap); + ret = cs35l56_set_patch(cs35l56->regmap); + if (ret) + return ret; /* Registers could be dirty after soft reset or SoundWire enumeration */ regcache_sync(cs35l56->regmap); From 4edc07fc7fe1a9eec1a4ebc518d2dec222382f43 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 19 Jul 2023 15:08:37 +0200 Subject: [PATCH 183/334] ASoC: amd: acp: fix SND_SOC_AMD_ACP_PCI depdenencies The new PM functions require code that is part of the snd-acp-legacy-common module: x86_64-linux-ld: sound/soc/amd/acp/acp-pci.o: in function `snd_acp_resume': acp-pci.c:(.text+0x23): undefined reference to `acp_init' x86_64-linux-ld: acp-pci.c:(.text+0x58): undefined reference to `acp_enable_interrupts' x86_64-linux-ld: sound/soc/amd/acp/acp-pci.o: in function `snd_acp_suspend': acp-pci.c:(.text+0x89): undefined reference to `acp_deinit' x86_64-linux-ld: sound/soc/amd/acp/acp-pci.o: in function `acp_pci_remove': acp-pci.c:(.text+0xec): undefined reference to `acp_deinit' x86_64-linux-ld: sound/soc/amd/acp/acp-pci.o: in function `acp_pci_probe': acp-pci.c:(.text+0x26b): undefined reference to `acp_init' Select that Kconfig symbol as is done for the other frontends. Fixes: 088a40980efbc ("ASoC: amd: acp: add pm ops support for acp pci driver") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20230719130846.633701-1-arnd@kernel.org Signed-off-by: Mark Brown --- sound/soc/amd/acp/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index 9e31b5d16790..631cdf96d637 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -30,6 +30,7 @@ config SND_SOC_AMD_ACP_PCM config SND_SOC_AMD_ACP_PCI tristate "AMD ACP PCI Driver Support" + select SND_SOC_AMD_ACP_LEGACY_COMMON depends on X86 && PCI help This options enables generic PCI driver for ACP device. From 30019d220cf9ec4df4e5f5d9082baf5519516018 Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Thu, 6 Jul 2023 14:41:23 +0800 Subject: [PATCH 184/334] ASoC: mediatek: mt8188: DPCM used FE and BE merged parameters To ensure that DPCM takes into account the backend hardware limitations when user space queries the hw_params of a device, we need to add dpcm_merged_format, dpcm_merged_chan, and dpcm_merged_rate to the FE dai_links. This patch includes only stereo FE dai_links, since multi-channel FEs may be reserved for specific purposes. Therefore, it may not be appropriate to consider BE conditions. Signed-off-by: Trevor Wu Link: https://lore.kernel.org/r/20230706064123.29790-1-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8188/mt8188-mt6359.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/mediatek/mt8188/mt8188-mt6359.c b/sound/soc/mediatek/mt8188/mt8188-mt6359.c index ac69c23e0da1..7c9e08e6a4f5 100644 --- a/sound/soc/mediatek/mt8188/mt8188-mt6359.c +++ b/sound/soc/mediatek/mt8188/mt8188-mt6359.c @@ -723,6 +723,9 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_playback = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + .dpcm_merged_format = 1, SND_SOC_DAILINK_REG(playback2), }, [DAI_LINK_DL3_FE] = { @@ -734,6 +737,9 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_playback = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + .dpcm_merged_format = 1, SND_SOC_DAILINK_REG(playback3), }, [DAI_LINK_DL6_FE] = { @@ -745,6 +751,9 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_playback = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + .dpcm_merged_format = 1, SND_SOC_DAILINK_REG(playback6), }, [DAI_LINK_DL7_FE] = { @@ -833,6 +842,9 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_capture = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + .dpcm_merged_format = 1, SND_SOC_DAILINK_REG(capture4), }, [DAI_LINK_UL5_FE] = { @@ -844,6 +856,9 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_capture = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + .dpcm_merged_format = 1, SND_SOC_DAILINK_REG(capture5), }, [DAI_LINK_UL6_FE] = { From 82e7c8b93a0614b1725e0ea11d0a77b04e058716 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Wed, 5 Jul 2023 21:03:22 +0200 Subject: [PATCH 185/334] ASoC: ti: omap-mcbsp: Ignore errors for getting fck_src Commit 349355ce3a05 ("ARM: OMAP2+: Drop legacy platform data for omap4 mcbsp") dropped prcm_fck for omap4, so the clk_src might not be available making the clk_get(src) fail. In such cases, rely on the devicetree to assign the correct parent. Signed-off-by: Andreas Kemnade Link: https://lore.kernel.org/r/20230705190324.355282-2-andreas@kemnade.info Signed-off-by: Mark Brown --- sound/soc/ti/omap-mcbsp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/ti/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c index 21fa7b978799..f9fe96b61852 100644 --- a/sound/soc/ti/omap-mcbsp.c +++ b/sound/soc/ti/omap-mcbsp.c @@ -70,8 +70,8 @@ static int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id) fck_src = clk_get(mcbsp->dev, src); if (IS_ERR(fck_src)) { - dev_err(mcbsp->dev, "CLKS: could not clk_get() %s\n", src); - return -EINVAL; + dev_info(mcbsp->dev, "CLKS: could not clk_get() %s\n", src); + return 0; } pm_runtime_put_sync(mcbsp->dev); From 65bc25b8d0904e0aff66b1c3a9dd4c0dcb8efbf1 Mon Sep 17 00:00:00 2001 From: Matus Gajdos Date: Wed, 19 Jul 2023 18:31:53 +0200 Subject: [PATCH 186/334] ASoC: fsl_spdif: Add support for 22.05 kHz sample rate Add support for 22.05 kHz sample rate for TX. Signed-off-by: Matus Gajdos Reviewed-by: Fabio Estevam Link: https://lore.kernel.org/r/20230719163154.19492-1-matuszpd@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 8 ++++++-- sound/soc/fsl/fsl_spdif.h | 6 ++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 015c3708aa04..95e639711eba 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -514,6 +514,10 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream, int ret; switch (sample_rate) { + case 22050: + rate = SPDIF_TXRATE_22050; + csfs = IEC958_AES3_CON_FS_22050; + break; case 32000: rate = SPDIF_TXRATE_32000; csfs = IEC958_AES3_CON_FS_32000; @@ -1422,7 +1426,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, struct clk *clk, u64 savesub, enum spdif_txrate index, bool round) { - static const u32 rate[] = { 32000, 44100, 48000, 88200, 96000, 176400, + static const u32 rate[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, }; bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk); u64 rate_ideal, rate_actual, sub; @@ -1483,7 +1487,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, enum spdif_txrate index) { - static const u32 rate[] = { 32000, 44100, 48000, 88200, 96000, 176400, + static const u32 rate[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, }; struct platform_device *pdev = spdif_priv->pdev; struct device *dev = &pdev->dev; diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h index 75b42a692c90..2bc1b10c17d4 100644 --- a/sound/soc/fsl/fsl_spdif.h +++ b/sound/soc/fsl/fsl_spdif.h @@ -175,7 +175,8 @@ enum spdif_gainsel { /* SPDIF tx rate */ enum spdif_txrate { - SPDIF_TXRATE_32000 = 0, + SPDIF_TXRATE_22050 = 0, + SPDIF_TXRATE_32000, SPDIF_TXRATE_44100, SPDIF_TXRATE_48000, SPDIF_TXRATE_88200, @@ -191,7 +192,8 @@ enum spdif_txrate { #define SPDIF_QSUB_SIZE (SPDIF_UBITS_SIZE / 8) -#define FSL_SPDIF_RATES_PLAYBACK (SNDRV_PCM_RATE_32000 | \ +#define FSL_SPDIF_RATES_PLAYBACK (SNDRV_PCM_RATE_22050 | \ + SNDRV_PCM_RATE_32000 | \ SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | \ SNDRV_PCM_RATE_88200 | \ From d4e99962d16ce60ac9ecf995489dc60d7854f1bd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:12:54 +0200 Subject: [PATCH 187/334] ALSA: control: Take card->controls_rwsem in snd_ctl_rename() snd_ctl_rename() expects that card->controls_rwsem is held in the caller side for avoiding possible races, but actually no one really did that. It's likely because this operation is done usually only at the device initialization where no race can happen. But, it's still safer to take a lock, so we just take the lock inside snd_ctl_rename() like most of other API functions do. Link: https://lore.kernel.org/r/20230718141304.1032-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/control.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/core/control.c b/sound/core/control.c index 8386b53acdcd..a41d19c46df2 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -769,11 +769,12 @@ EXPORT_SYMBOL(snd_ctl_rename_id); * * Renames the specified control on the card to the new name. * - * Make sure to take the control write lock - down_write(&card->controls_rwsem). + * Note that this function takes card->controls_rwsem lock internally. */ void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl, const char *name) { + down_write(&card->controls_rwsem); remove_hash_entries(card, kctl); if (strscpy(kctl->id.name, name, sizeof(kctl->id.name)) < 0) @@ -781,6 +782,7 @@ void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl, name, kctl->id.name); add_hash_entries(card, kctl); + up_write(&card->controls_rwsem); } EXPORT_SYMBOL(snd_ctl_rename); From 6eca69147542686a412b2657c0fd74bc4a38cc44 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:12:55 +0200 Subject: [PATCH 188/334] staging: greybus: audio_helper: Use snd_ctl_remove_id() Use the standard snd_ctl_remove_id() helper function instead of open code. This allows us to reduce the manual card->rwsem lock in the caller side. Acked-by: Greg Kroah-Hartman Cc: Johan Hovold Cc: Alex Elder Cc: greybus-dev@lists.linaro.org Link: https://lore.kernel.org/r/20230718141304.1032-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- drivers/staging/greybus/audio_helper.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/drivers/staging/greybus/audio_helper.c b/drivers/staging/greybus/audio_helper.c index 223987616e07..97ce5b9ad7fd 100644 --- a/drivers/staging/greybus/audio_helper.c +++ b/drivers/staging/greybus/audio_helper.c @@ -149,7 +149,6 @@ static int gbaudio_remove_controls(struct snd_card *card, struct device *dev, for (i = 0; i < num_controls; i++) { const struct snd_kcontrol_new *control = &controls[i]; struct snd_ctl_elem_id id; - struct snd_kcontrol *kctl; if (prefix) snprintf(id.name, sizeof(id.name), "%s %s", prefix, @@ -161,17 +160,10 @@ static int gbaudio_remove_controls(struct snd_card *card, struct device *dev, id.device = control->device; id.subdevice = control->subdevice; id.index = control->index; - kctl = snd_ctl_find_id(card, &id); - if (!kctl) { - dev_err(dev, "Failed to find %s\n", control->name); - continue; - } - err = snd_ctl_remove(card, kctl); - if (err < 0) { + err = snd_ctl_remove_id(card, &id); + if (err < 0) dev_err(dev, "%d: Failed to remove %s\n", err, control->name); - continue; - } } return 0; } @@ -181,11 +173,7 @@ int gbaudio_remove_component_controls(struct snd_soc_component *component, unsigned int num_controls) { struct snd_card *card = component->card->snd_card; - int err; - down_write(&card->controls_rwsem); - err = gbaudio_remove_controls(card, component->dev, controls, - num_controls, component->name_prefix); - up_write(&card->controls_rwsem); - return err; + return gbaudio_remove_controls(card, component->dev, controls, + num_controls, component->name_prefix); } From d8b366c40638d5aedad74646707b2b04b7342210 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:12:56 +0200 Subject: [PATCH 189/334] ASoC: atmel: mchp-pdmc: Use snd_ctl_remove_id() Use the standard snd_ctl_remove_id() helper instead of open code for removing a kctl. This helps for avoiding possible races. Reviewed-by: Claudiu Beznea Acked-by: Mark Brown Link: https://lore.kernel.org/r/20230718141304.1032-4-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/soc/atmel/mchp-pdmc.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c index c79c73e6791e..1a069f4cdcda 100644 --- a/sound/soc/atmel/mchp-pdmc.c +++ b/sound/soc/atmel/mchp-pdmc.c @@ -386,7 +386,6 @@ static int mchp_pdmc_open(struct snd_soc_component *component, for (i = 0; i < ARRAY_SIZE(mchp_pdmc_snd_controls); i++) { const struct snd_kcontrol_new *control = &mchp_pdmc_snd_controls[i]; struct snd_ctl_elem_id id; - struct snd_kcontrol *kctl; int err; if (component->name_prefix) @@ -400,17 +399,10 @@ static int mchp_pdmc_open(struct snd_soc_component *component, id.device = control->device; id.subdevice = control->subdevice; id.index = control->index; - kctl = snd_ctl_find_id(component->card->snd_card, &id); - if (!kctl) { - dev_err(component->dev, "Failed to find %s\n", control->name); - continue; - } - err = snd_ctl_remove(component->card->snd_card, kctl); - if (err < 0) { + err = snd_ctl_remove_id(component->card->snd_card, &id); + if (err < 0) dev_err(component->dev, "%d: Failed to remove %s\n", err, control->name); - continue; - } } return 0; From 192c4cccd015f52c94d0420eb5d7305a1ca28998 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:12:57 +0200 Subject: [PATCH 190/334] ALSA: control: Take controls_rwsem lock in snd_ctl_remove() So far, snd_ctl_remove() requires its caller to take card->controls_rwsem manually before the call for avoiding possible races. However, many callers don't care and miss the locking. Basically it's cumbersome and error-prone to enforce it to each caller. Moreover, card->controls_rwsem is a field that should be used only by internal or proper helpers, and it's not to be touched at random external places. This patch is an attempt to make those calls more consistent: now snd_ctl_remove() takes the card->controls_rwsem internally, just like other API functions for kctls. Since a few callers already take the controls_rwsem locks, the patch removes those locks at the same time, too. Link: https://lore.kernel.org/r/20230718141304.1032-5-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/control.c | 27 +++++++++++++++++++++------ sound/core/jack.c | 2 -- sound/core/pcm.c | 2 -- sound/isa/sb/emu8000.c | 2 -- sound/isa/sb/sb16_csp.c | 2 -- sound/pci/emu10k1/emufx.c | 2 -- sound/pci/hda/hda_codec.c | 2 -- sound/soc/soc-topology.c | 3 --- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/sound/core/control.c b/sound/core/control.c index a41d19c46df2..9c933350ec6b 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -39,6 +39,9 @@ static LIST_HEAD(snd_control_compat_ioctls); #endif static struct snd_ctl_layer_ops *snd_ctl_layer; +static int snd_ctl_remove_locked(struct snd_card *card, + struct snd_kcontrol *kcontrol); + static int snd_ctl_open(struct inode *inode, struct file *file) { unsigned long flags; @@ -483,7 +486,7 @@ static int __snd_ctl_add_replace(struct snd_card *card, return -EBUSY; } - err = snd_ctl_remove(card, old); + err = snd_ctl_remove_locked(card, old); if (err < 0) return err; } @@ -589,20 +592,32 @@ static int __snd_ctl_remove(struct snd_card *card, return 0; } +static inline int snd_ctl_remove_locked(struct snd_card *card, + struct snd_kcontrol *kcontrol) +{ + return __snd_ctl_remove(card, kcontrol, true); +} + /** * snd_ctl_remove - remove the control from the card and release it * @card: the card instance * @kcontrol: the control instance to remove * * Removes the control from the card and then releases the instance. - * You don't need to call snd_ctl_free_one(). You must be in - * the write lock - down_write(&card->controls_rwsem). + * You don't need to call snd_ctl_free_one(). * * Return: 0 if successful, or a negative error code on failure. + * + * Note that this function takes card->controls_rwsem lock internally. */ int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol) { - return __snd_ctl_remove(card, kcontrol, true); + int ret; + + down_write(&card->controls_rwsem); + ret = snd_ctl_remove_locked(card, kcontrol); + up_write(&card->controls_rwsem); + return ret; } EXPORT_SYMBOL(snd_ctl_remove); @@ -627,7 +642,7 @@ int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id) up_write(&card->controls_rwsem); return -ENOENT; } - ret = snd_ctl_remove(card, kctl); + ret = snd_ctl_remove_locked(card, kctl); up_write(&card->controls_rwsem); return ret; } @@ -665,7 +680,7 @@ static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file, ret = -EBUSY; goto error; } - ret = snd_ctl_remove(card, kctl); + ret = snd_ctl_remove_locked(card, kctl); error: up_write(&card->controls_rwsem); return ret; diff --git a/sound/core/jack.c b/sound/core/jack.c index 03d155ed362b..e0f034e7275c 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -66,12 +66,10 @@ static int snd_jack_dev_free(struct snd_device *device) struct snd_card *card = device->card; struct snd_jack_kctl *jack_kctl, *tmp_jack_kctl; - down_write(&card->controls_rwsem); list_for_each_entry_safe(jack_kctl, tmp_jack_kctl, &jack->kctl_list, list) { list_del_init(&jack_kctl->list); snd_ctl_remove(card, jack_kctl->kctl); } - up_write(&card->controls_rwsem); if (jack->private_free) jack->private_free(jack); diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 9d95e3731123..1c0bb3a07bff 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -814,9 +814,7 @@ static void free_chmap(struct snd_pcm_str *pstr) if (pstr->chmap_kctl) { struct snd_card *card = pstr->pcm->card; - down_write(&card->controls_rwsem); snd_ctl_remove(card, pstr->chmap_kctl); - up_write(&card->controls_rwsem); pstr->chmap_kctl = NULL; } } diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index e02029677743..a6405772d537 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -1040,10 +1040,8 @@ snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu) __error: for (i = 0; i < EMU8000_NUM_CONTROLS; i++) { - down_write(&card->controls_rwsem); if (emu->controls[i]) snd_ctl_remove(card, emu->controls[i]); - up_write(&card->controls_rwsem); } return err; } diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index 7ad8c5f7b664..8d8357019719 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -1080,7 +1080,6 @@ static void snd_sb_qsound_destroy(struct snd_sb_csp * p) card = p->chip->card; - down_write(&card->controls_rwsem); if (p->qsound_switch) { snd_ctl_remove(card, p->qsound_switch); p->qsound_switch = NULL; @@ -1089,7 +1088,6 @@ static void snd_sb_qsound_destroy(struct snd_sb_csp * p) snd_ctl_remove(card, p->qsound_space); p->qsound_space = NULL; } - up_write(&card->controls_rwsem); /* cancel pending transfer of QSound parameters */ spin_lock_irqsave (&p->q_lock, flags); diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 9904bcfee106..70c8252a92d9 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -977,11 +977,9 @@ static int snd_emu10k1_del_controls(struct snd_emu10k1 *emu, in_kernel); if (err < 0) return err; - down_write(&card->controls_rwsem); ctl = snd_emu10k1_look_for_ctl(emu, &id); if (ctl) snd_ctl_remove(card, ctl->kcontrol); - up_write(&card->controls_rwsem); } return 0; } diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index bd19f92aeeec..33af707a65ab 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1769,10 +1769,8 @@ void snd_hda_ctls_clear(struct hda_codec *codec) int i; struct hda_nid_item *items = codec->mixers.list; - down_write(&codec->card->controls_rwsem); for (i = 0; i < codec->mixers.used; i++) snd_ctl_remove(codec->card, items[i].kctl); - up_write(&codec->card->controls_rwsem); snd_array_free(&codec->mixers); snd_array_free(&codec->nids); } diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 8add361e87c6..03ec3c5adc3a 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -2564,7 +2564,6 @@ EXPORT_SYMBOL_GPL(snd_soc_tplg_component_load); /* remove dynamic controls from the component driver */ int snd_soc_tplg_component_remove(struct snd_soc_component *comp) { - struct snd_card *card = comp->card->snd_card; struct snd_soc_dobj *dobj, *next_dobj; int pass; @@ -2572,7 +2571,6 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp) for (pass = SOC_TPLG_PASS_END; pass >= SOC_TPLG_PASS_START; pass--) { /* remove mixer controls */ - down_write(&card->controls_rwsem); list_for_each_entry_safe(dobj, next_dobj, &comp->dobj_list, list) { @@ -2607,7 +2605,6 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp) break; } } - up_write(&card->controls_rwsem); } /* let caller know if FW can be freed when no objects are left */ From 8320ba0ce534dea603b7ba22f484ee39ef2ce746 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:12:58 +0200 Subject: [PATCH 191/334] ALSA: control: Add lockdep warning to internal functions To assure the proper locking, add the lockdep check to __snd_ctl_remove(), __snd_ctl_add_replace() and other internal functions to handle user controls. Link: https://lore.kernel.org/r/20230718141304.1032-6-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/control.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/core/control.c b/sound/core/control.c index 9c933350ec6b..8aaa2a84a670 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -469,6 +469,8 @@ static int __snd_ctl_add_replace(struct snd_card *card, struct snd_kcontrol *old; int err; + lockdep_assert_held_write(&card->controls_rwsem); + id = kcontrol->id; if (id.index > UINT_MAX - kcontrol->count) return -EINVAL; @@ -578,6 +580,8 @@ static int __snd_ctl_remove(struct snd_card *card, { unsigned int idx; + lockdep_assert_held_write(&card->controls_rwsem); + if (snd_BUG_ON(!card || !kcontrol)) return -EINVAL; list_del(&kcontrol->list); @@ -1524,6 +1528,8 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, int i; int change; + lockdep_assert_held_write(&ue->card->controls_rwsem); + if (size > 1024 * 128) /* sane value */ return -EINVAL; @@ -1600,6 +1606,8 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) unsigned int i; const uintptr_t user_ptrval = ue->info.value.enumerated.names_ptr; + lockdep_assert_held_write(&ue->card->controls_rwsem); + buf_len = ue->info.value.enumerated.names_length; if (buf_len > 64 * 1024) return -EINVAL; @@ -1904,6 +1912,8 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, struct snd_ctl_elem_id id; struct snd_kcontrol_volatile *vd; + lockdep_assert_held(&file->card->controls_rwsem); + if (copy_from_user(&header, buf, sizeof(header))) return -EFAULT; From a3bee62e90d8fdfdbd325323106de00b3e3a729f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:12:59 +0200 Subject: [PATCH 192/334] ASoC: sigmadsp: Simplify with snd_ctl_activate_id() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the standard snd_ctl_activate_id() helper instead of an open code for code simplification. Acked-by: Mark Brown Cc: Lars-Peter Clausen Cc: "Nuno Sá" Link: https://lore.kernel.org/r/20230718141304.1032-7-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/soc/codecs/sigmadsp.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 3047a6fbb380..b93c078a8040 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -669,36 +669,19 @@ static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp, struct sigmadsp_control *ctrl, unsigned int samplerate_mask) { struct snd_card *card = sigmadsp->component->card->snd_card; - struct snd_kcontrol_volatile *vd; - struct snd_ctl_elem_id id; bool active; - bool changed = false; + int changed; active = sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask); - - down_write(&card->controls_rwsem); - if (!ctrl->kcontrol) { - up_write(&card->controls_rwsem); + if (!ctrl->kcontrol) return; - } - - id = ctrl->kcontrol->id; - vd = &ctrl->kcontrol->vd[0]; - if (active == (bool)(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)) { - vd->access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE; - changed = true; - } - up_write(&card->controls_rwsem); - - if (active && changed) { + changed = snd_ctl_activate_id(card, &ctrl->kcontrol->id, active); + if (active && changed > 0) { mutex_lock(&sigmadsp->lock); if (ctrl->cached) sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache); mutex_unlock(&sigmadsp->lock); } - - if (changed) - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &id); } /** From dc438bac711d703e08cffa527db192c4b1630cd4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:13:00 +0200 Subject: [PATCH 193/334] staging: greybus: Avoid abusing controls_rwsem The controls_rwsem of snd_card object is rather an internal lock, and not really meant to be used by others for its data protection. This patch addresses it by replacing the controls_rwsem usages with the own (new) mutex. Note that the up_write() and down_write() calls around gbaudio_remove_component_controls() are simply dropped without replacement. These temporary up/down were a workaround since gbaudio_remove_component_controls() itself took the rwsem. Now it was also gone, we can clean up the workaround, too. Acked-by: Greg Kroah-Hartman Cc: Vaibhav Agarwal Cc: Mark Greer Cc: Johan Hovold Cc: Alex Elder Cc: greybus-dev@lists.linaro.org Link: https://lore.kernel.org/r/20230718141304.1032-8-tiwai@suse.de Signed-off-by: Takashi Iwai --- drivers/staging/greybus/audio_codec.c | 18 +++++++----------- drivers/staging/greybus/audio_codec.h | 1 + 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/staging/greybus/audio_codec.c b/drivers/staging/greybus/audio_codec.c index 72ace74ea605..2f05e761fb9a 100644 --- a/drivers/staging/greybus/audio_codec.c +++ b/drivers/staging/greybus/audio_codec.c @@ -807,7 +807,6 @@ int gbaudio_register_module(struct gbaudio_module_info *module) { int ret; struct snd_soc_component *comp; - struct snd_card *card; struct gbaudio_jack *jack = NULL; if (!gbcodec) { @@ -816,21 +815,20 @@ int gbaudio_register_module(struct gbaudio_module_info *module) } comp = gbcodec->component; - card = comp->card->snd_card; - down_write(&card->controls_rwsem); + mutex_lock(&gbcodec->register_mutex); if (module->num_dais) { dev_err(gbcodec->dev, "%d:DAIs not supported via gbcodec driver\n", module->num_dais); - up_write(&card->controls_rwsem); + mutex_unlock(&gbcodec->register_mutex); return -EINVAL; } ret = gbaudio_init_jack(module, comp->card); if (ret) { - up_write(&card->controls_rwsem); + mutex_unlock(&gbcodec->register_mutex); return ret; } @@ -867,7 +865,7 @@ int gbaudio_register_module(struct gbaudio_module_info *module) ret = snd_soc_dapm_new_widgets(comp->card); dev_dbg(comp->dev, "Registered %s module\n", module->name); - up_write(&card->controls_rwsem); + mutex_unlock(&gbcodec->register_mutex); return ret; } EXPORT_SYMBOL(gbaudio_register_module); @@ -935,13 +933,12 @@ static void gbaudio_codec_cleanup(struct gbaudio_module_info *module) void gbaudio_unregister_module(struct gbaudio_module_info *module) { struct snd_soc_component *comp = gbcodec->component; - struct snd_card *card = comp->card->snd_card; struct gbaudio_jack *jack, *n; int mask; dev_dbg(comp->dev, "Unregister %s module\n", module->name); - down_write(&card->controls_rwsem); + mutex_lock(&gbcodec->register_mutex); mutex_lock(&gbcodec->lock); gbaudio_codec_cleanup(module); list_del(&module->list); @@ -978,10 +975,8 @@ void gbaudio_unregister_module(struct gbaudio_module_info *module) dev_dbg(comp->dev, "Removing %d controls\n", module->num_controls); /* release control semaphore */ - up_write(&card->controls_rwsem); gbaudio_remove_component_controls(comp, module->controls, module->num_controls); - down_write(&card->controls_rwsem); } if (module->dapm_widgets) { dev_dbg(comp->dev, "Removing %d widgets\n", @@ -992,7 +987,7 @@ void gbaudio_unregister_module(struct gbaudio_module_info *module) dev_dbg(comp->dev, "Unregistered %s module\n", module->name); - up_write(&card->controls_rwsem); + mutex_unlock(&gbcodec->register_mutex); } EXPORT_SYMBOL(gbaudio_unregister_module); @@ -1012,6 +1007,7 @@ static int gbcodec_probe(struct snd_soc_component *comp) info->dev = comp->dev; INIT_LIST_HEAD(&info->module_list); mutex_init(&info->lock); + mutex_init(&info->register_mutex); INIT_LIST_HEAD(&info->dai_list); /* init dai_list used to maintain runtime stream info */ diff --git a/drivers/staging/greybus/audio_codec.h b/drivers/staging/greybus/audio_codec.h index ce15e800e607..f3f7a7ec6be4 100644 --- a/drivers/staging/greybus/audio_codec.h +++ b/drivers/staging/greybus/audio_codec.h @@ -71,6 +71,7 @@ struct gbaudio_codec_info { /* to maintain runtime stream params for each DAI */ struct list_head dai_list; struct mutex lock; + struct mutex register_mutex; }; struct gbaudio_widget { From 6723670a483501497dc339ae37676525245a913a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:13:01 +0200 Subject: [PATCH 194/334] ALSA: control: Make snd_ctl_find_id() argument const The id object passed to snd_ctl_find_id() is only read, and we can mark it with const gracefully. Link: https://lore.kernel.org/r/20230718141304.1032-9-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/control.h | 2 +- sound/core/control.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/sound/control.h b/include/sound/control.h index cc3dcc6cfb0f..e61b749bf204 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -141,7 +141,7 @@ int snd_ctl_rename_id(struct snd_card * card, struct snd_ctl_elem_id *src_id, st void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl, const char *name); int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, int active); struct snd_kcontrol *snd_ctl_find_numid(struct snd_card * card, unsigned int numid); -struct snd_kcontrol *snd_ctl_find_id(struct snd_card * card, struct snd_ctl_elem_id *id); +struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, const struct snd_ctl_elem_id *id); int snd_ctl_create(struct snd_card *card); diff --git a/sound/core/control.c b/sound/core/control.c index 8aaa2a84a670..180e5768a10f 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -858,7 +858,7 @@ EXPORT_SYMBOL(snd_ctl_find_numid); * */ struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, - struct snd_ctl_elem_id *id) + const struct snd_ctl_elem_id *id) { struct snd_kcontrol *kctl; From b1e055f67611daf098e27e8731386eeb5257bde3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:13:02 +0200 Subject: [PATCH 195/334] ALSA: control: Introduce unlocked version for snd_ctl_find_*() helpers For reducing the unnecessary use of controls_rwsem in the drivers, this patch adds a new variant for snd_ctl_find_*() helpers: snd_ctl_find_id_locked() and snd_ctl_find_numid_locked() look for a kctl element inside the card->controls_rwsem -- that is, doing the very same as what snd_ctl_find_id() and snd_ctl_find_numid() did until now. snd_ctl_find_id() and snd_ctl_find_numid() remain same, i.e. still unlocked version, but they will be switched to locked version once after all callers are replaced. The patch also replaces the calls of snd_ctl_find_id() and snd_ctl_find_numid() in a few places; all of those are places where we know that the functions are called properly with controls_rwsem held. All others are without rwsem (although they should have been). After this patch, we'll turn on the locking in snd_ctl_find_id() and snd_ctl_find_numid() to be more race-free. Link: https://lore.kernel.org/r/20230718141304.1032-10-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/control.h | 4 ++- sound/core/control.c | 69 +++++++++++++++++++++++++++---------- sound/core/control_compat.c | 2 +- sound/core/control_led.c | 2 +- sound/core/oss/mixer_oss.c | 10 +++--- sound/pci/emu10k1/emufx.c | 2 +- 6 files changed, 61 insertions(+), 28 deletions(-) diff --git a/include/sound/control.h b/include/sound/control.h index e61b749bf204..42e8dbb22d8e 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -140,7 +140,9 @@ int snd_ctl_remove_id(struct snd_card * card, struct snd_ctl_elem_id *id); int snd_ctl_rename_id(struct snd_card * card, struct snd_ctl_elem_id *src_id, struct snd_ctl_elem_id *dst_id); void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl, const char *name); int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, int active); -struct snd_kcontrol *snd_ctl_find_numid(struct snd_card * card, unsigned int numid); +struct snd_kcontrol *snd_ctl_find_numid_locked(struct snd_card *card, unsigned int numid); +struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid); +struct snd_kcontrol *snd_ctl_find_id_locked(struct snd_card *card, const struct snd_ctl_elem_id *id); struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, const struct snd_ctl_elem_id *id); int snd_ctl_create(struct snd_card *card); diff --git a/sound/core/control.c b/sound/core/control.c index 180e5768a10f..30741293708d 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -475,7 +475,7 @@ static int __snd_ctl_add_replace(struct snd_card *card, if (id.index > UINT_MAX - kcontrol->count) return -EINVAL; - old = snd_ctl_find_id(card, &id); + old = snd_ctl_find_id_locked(card, &id); if (!old) { if (mode == CTL_REPLACE) return -EINVAL; @@ -641,7 +641,7 @@ int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id) int ret; down_write(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, id); + kctl = snd_ctl_find_id_locked(card, id); if (kctl == NULL) { up_write(&card->controls_rwsem); return -ENOENT; @@ -670,7 +670,7 @@ static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file, int idx, ret; down_write(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, id); + kctl = snd_ctl_find_id_locked(card, id); if (kctl == NULL) { ret = -ENOENT; goto error; @@ -711,7 +711,7 @@ int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, int ret; down_write(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, id); + kctl = snd_ctl_find_id_locked(card, id); if (kctl == NULL) { ret = -ENOENT; goto unlock; @@ -765,7 +765,7 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id, int saved_numid; down_write(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, src_id); + kctl = snd_ctl_find_id_locked(card, src_id); if (kctl == NULL) { up_write(&card->controls_rwsem); return -ENOENT; @@ -820,7 +820,7 @@ snd_ctl_find_numid_slow(struct snd_card *card, unsigned int numid) #endif /* !CONFIG_SND_CTL_FAST_LOOKUP */ /** - * snd_ctl_find_numid - find the control instance with the given number-id + * snd_ctl_find_numid_locked - find the control instance with the given number-id * @card: the card instance * @numid: the number-id to search * @@ -830,9 +830,9 @@ snd_ctl_find_numid_slow(struct snd_card *card, unsigned int numid) * (if the race condition can happen). * * Return: The pointer of the instance if found, or %NULL if not. - * */ -struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid) +struct snd_kcontrol * +snd_ctl_find_numid_locked(struct snd_card *card, unsigned int numid) { if (snd_BUG_ON(!card || !numid)) return NULL; @@ -842,10 +842,26 @@ struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numi return snd_ctl_find_numid_slow(card, numid); #endif } +EXPORT_SYMBOL(snd_ctl_find_numid_locked); + +/** + * snd_ctl_find_numid - find the control instance with the given number-id + * @card: the card instance + * @numid: the number-id to search + * + * Finds the control instance with the given number-id from the card. + * + * Return: The pointer of the instance if found, or %NULL if not. + */ +struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, + unsigned int numid) +{ + return snd_ctl_find_numid_locked(card, numid); +} EXPORT_SYMBOL(snd_ctl_find_numid); /** - * snd_ctl_find_id - find the control instance with the given id + * snd_ctl_find_id_locked - find the control instance with the given id * @card: the card instance * @id: the id to search * @@ -855,17 +871,16 @@ EXPORT_SYMBOL(snd_ctl_find_numid); * (if the race condition can happen). * * Return: The pointer of the instance if found, or %NULL if not. - * */ -struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, - const struct snd_ctl_elem_id *id) +struct snd_kcontrol *snd_ctl_find_id_locked(struct snd_card *card, + const struct snd_ctl_elem_id *id) { struct snd_kcontrol *kctl; if (snd_BUG_ON(!card || !id)) return NULL; if (id->numid != 0) - return snd_ctl_find_numid(card, id->numid); + return snd_ctl_find_numid_locked(card, id->numid); #ifdef CONFIG_SND_CTL_FAST_LOOKUP kctl = xa_load(&card->ctl_hash, get_ctl_id_hash(id)); if (kctl && elem_id_matches(kctl, id)) @@ -880,6 +895,22 @@ struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, return NULL; } +EXPORT_SYMBOL(snd_ctl_find_id_locked); + +/** + * snd_ctl_find_id - find the control instance with the given id + * @card: the card instance + * @id: the id to search + * + * Finds the control instance with the given id from the card. + * + * Return: The pointer of the instance if found, or %NULL if not. + */ +struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, + const struct snd_ctl_elem_id *id) +{ + return snd_ctl_find_id_locked(card, id); +} EXPORT_SYMBOL(snd_ctl_find_id); static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl, @@ -1194,7 +1225,7 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl, int result; down_read(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, &info->id); + kctl = snd_ctl_find_id_locked(card, &info->id); if (kctl == NULL) result = -ENOENT; else @@ -1233,7 +1264,7 @@ static int snd_ctl_elem_read(struct snd_card *card, int ret; down_read(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, &control->id); + kctl = snd_ctl_find_id_locked(card, &control->id); if (kctl == NULL) { ret = -ENOENT; goto unlock; @@ -1310,7 +1341,7 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, int result; down_write(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, &control->id); + kctl = snd_ctl_find_id_locked(card, &control->id); if (kctl == NULL) { up_write(&card->controls_rwsem); return -ENOENT; @@ -1391,7 +1422,7 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file, if (copy_from_user(&id, _id, sizeof(id))) return -EFAULT; down_write(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, &id); + kctl = snd_ctl_find_id_locked(card, &id); if (kctl == NULL) { result = -ENOENT; } else { @@ -1419,7 +1450,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file, if (copy_from_user(&id, _id, sizeof(id))) return -EFAULT; down_write(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, &id); + kctl = snd_ctl_find_id_locked(card, &id); if (kctl == NULL) { result = -ENOENT; } else { @@ -1927,7 +1958,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, container_size = header.length; container = buf->tlv; - kctl = snd_ctl_find_numid(file->card, header.numid); + kctl = snd_ctl_find_numid_locked(file->card, header.numid); if (kctl == NULL) return -ENOENT; diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 9cae5d74335c..0e8b1bfb040e 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -173,7 +173,7 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, int err; down_read(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, id); + kctl = snd_ctl_find_id_locked(card, id); if (! kctl) { up_read(&card->controls_rwsem); return -ENOENT; diff --git a/sound/core/control_led.c b/sound/core/control_led.c index ee77547bf8dc..67fc2a1dcf7a 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -251,7 +251,7 @@ static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id, card = snd_card_ref(card_number); if (card) { down_write(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, id); + kctl = snd_ctl_find_id_locked(card, id); if (kctl) { ioff = snd_ctl_get_ioff(kctl, id); vd = &kctl->vd[ioff]; diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 9620115cfdc0..dae2da380835 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -524,7 +524,7 @@ static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, c id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; strscpy(id.name, name, sizeof(id.name)); id.index = index; - return snd_ctl_find_id(card, &id); + return snd_ctl_find_id_locked(card, &id); } static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer, @@ -540,7 +540,7 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer, if (numid == ID_UNKNOWN) return; down_read(&card->controls_rwsem); - kctl = snd_ctl_find_numid(card, numid); + kctl = snd_ctl_find_numid_locked(card, numid); if (!kctl) { up_read(&card->controls_rwsem); return; @@ -579,7 +579,7 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer, if (numid == ID_UNKNOWN) return; down_read(&card->controls_rwsem); - kctl = snd_ctl_find_numid(card, numid); + kctl = snd_ctl_find_numid_locked(card, numid); if (!kctl) { up_read(&card->controls_rwsem); return; @@ -645,7 +645,7 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer, if (numid == ID_UNKNOWN) return; down_read(&card->controls_rwsem); - kctl = snd_ctl_find_numid(card, numid); + kctl = snd_ctl_find_numid_locked(card, numid); if (!kctl) { up_read(&card->controls_rwsem); return; @@ -688,7 +688,7 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, if (numid == ID_UNKNOWN) return; down_read(&card->controls_rwsem); - kctl = snd_ctl_find_numid(card, numid); + kctl = snd_ctl_find_numid_locked(card, numid); if (!kctl) { up_read(&card->controls_rwsem); return; diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 70c8252a92d9..318a064f2cec 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -800,7 +800,7 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, continue; gctl_id = (struct snd_ctl_elem_id *)&gctl->id; down_read(&emu->card->controls_rwsem); - if (snd_ctl_find_id(emu->card, gctl_id)) { + if (snd_ctl_find_id_locked(emu->card, gctl_id)) { up_read(&emu->card->controls_rwsem); err = -EEXIST; goto __error; From 9c2cc5652e4390bd4492433d96ad4caa785b09de Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:13:03 +0200 Subject: [PATCH 196/334] ALSA: control: Take lock in snd_ctl_find_id() and snd_ctl_find_numid() Now all needed callers have been replaced with *_locked() versions, let's turn on the locking in snd_ctl_find_id() and snd_ctl_find_numid(). This patch also adds the lockdep assertions for debugging, too. Link: https://lore.kernel.org/r/20230718141304.1032-11-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/control.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/sound/core/control.c b/sound/core/control.c index 30741293708d..e13e9d6b3b89 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -836,6 +836,7 @@ snd_ctl_find_numid_locked(struct snd_card *card, unsigned int numid) { if (snd_BUG_ON(!card || !numid)) return NULL; + lockdep_assert_held(&card->controls_rwsem); #ifdef CONFIG_SND_CTL_FAST_LOOKUP return xa_load(&card->ctl_numids, numid); #else @@ -852,11 +853,18 @@ EXPORT_SYMBOL(snd_ctl_find_numid_locked); * Finds the control instance with the given number-id from the card. * * Return: The pointer of the instance if found, or %NULL if not. + * + * Note that this function takes card->controls_rwsem lock internally. */ struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid) { - return snd_ctl_find_numid_locked(card, numid); + struct snd_kcontrol *kctl; + + down_read(&card->controls_rwsem); + kctl = snd_ctl_find_numid_locked(card, numid); + up_read(&card->controls_rwsem); + return kctl; } EXPORT_SYMBOL(snd_ctl_find_numid); @@ -879,6 +887,7 @@ struct snd_kcontrol *snd_ctl_find_id_locked(struct snd_card *card, if (snd_BUG_ON(!card || !id)) return NULL; + lockdep_assert_held(&card->controls_rwsem); if (id->numid != 0) return snd_ctl_find_numid_locked(card, id->numid); #ifdef CONFIG_SND_CTL_FAST_LOOKUP @@ -905,11 +914,18 @@ EXPORT_SYMBOL(snd_ctl_find_id_locked); * Finds the control instance with the given id from the card. * * Return: The pointer of the instance if found, or %NULL if not. + * + * Note that this function takes card->controls_rwsem lock internally. */ struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, const struct snd_ctl_elem_id *id) { - return snd_ctl_find_id_locked(card, id); + struct snd_kcontrol *kctl; + + down_read(&card->controls_rwsem); + kctl = snd_ctl_find_id_locked(card, id); + up_read(&card->controls_rwsem); + return kctl; } EXPORT_SYMBOL(snd_ctl_find_id); From 3315cf95834fb5d612f6a5eb718c3620b80dd05e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:13:04 +0200 Subject: [PATCH 197/334] ALSA: emu10k1: Go back and simplify with snd_ctl_find_id() Now that snd_ctl_find_id() takes the locking itself, we can get rid of the messy locking in the caller side in snd_emu10k1_verify_controls(). Link: https://lore.kernel.org/r/20230718141304.1032-12-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emufx.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 318a064f2cec..f114bda25eea 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -799,13 +799,10 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, if (snd_emu10k1_look_for_ctl(emu, &gctl->id)) continue; gctl_id = (struct snd_ctl_elem_id *)&gctl->id; - down_read(&emu->card->controls_rwsem); - if (snd_ctl_find_id_locked(emu->card, gctl_id)) { - up_read(&emu->card->controls_rwsem); + if (snd_ctl_find_id(emu->card, gctl_id)) { err = -EEXIST; goto __error; } - up_read(&emu->card->controls_rwsem); if (gctl_id->iface != SNDRV_CTL_ELEM_IFACE_MIXER && gctl_id->iface != SNDRV_CTL_ELEM_IFACE_PCM) { err = -EINVAL; From e8c213ca026d3cadbc306885ad1b37efab02c218 Mon Sep 17 00:00:00 2001 From: Francesco Dolcini Date: Wed, 19 Jul 2023 14:47:51 +0200 Subject: [PATCH 198/334] ASoC: dt-bindings: nau8822: Add #sound-dai-cells Add #sound-dai-cells property and reference dai-common.yaml schema, this is required since NAU8822 can be used as a platform DAI link. Signed-off-by: Francesco Dolcini Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230719124752.248898-2-francesco@dolcini.it Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/nuvoton,nau8822.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8822.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8822.yaml index 65105402a53d..edc8cc756980 100644 --- a/Documentation/devicetree/bindings/sound/nuvoton,nau8822.yaml +++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8822.yaml @@ -21,6 +21,9 @@ properties: reg: maxItems: 1 + "#sound-dai-cells": + const: 0 + nuvoton,spk-btl: description: If set, configure the two loudspeaker outputs as a Bridge Tied Load output @@ -31,6 +34,9 @@ required: - compatible - reg +allOf: + - $ref: dai-common.yaml# + additionalProperties: false examples: From c214131f492083025e33354430d5b420add88b5e Mon Sep 17 00:00:00 2001 From: Francesco Dolcini Date: Wed, 19 Jul 2023 14:47:52 +0200 Subject: [PATCH 199/334] ASoC: dt-bindings: nau8822: Add MCLK clock Add nau8822 master clock input. Signed-off-by: Francesco Dolcini Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230719124752.248898-3-francesco@dolcini.it Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/nuvoton,nau8822.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8822.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8822.yaml index edc8cc756980..cb8182bbc491 100644 --- a/Documentation/devicetree/bindings/sound/nuvoton,nau8822.yaml +++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8822.yaml @@ -24,6 +24,12 @@ properties: "#sound-dai-cells": const: 0 + clocks: + maxItems: 1 + + clock-names: + const: mclk + nuvoton,spk-btl: description: If set, configure the two loudspeaker outputs as a Bridge Tied Load output From 83759352fd0b941c3ab3d365bf5f754b9e2f1af9 Mon Sep 17 00:00:00 2001 From: Francesco Dolcini Date: Wed, 19 Jul 2023 14:19:18 +0200 Subject: [PATCH 200/334] ASoC: dt-bindings: wm8904: Convert to dtschema Convert the WM8904 audio CODEC bindings to DT schema. Compared to the original binding #sound-dai-cells and the missing power supplies are added. The latter are all required as described in the datasheet. Datasheet: https://statics.cirrus.com/pubs/proDatasheet/WM8904_Rev4.1.pdf Signed-off-by: Francesco Dolcini Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230719121918.247397-1-francesco@dolcini.it Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/wlf,wm8904.yaml | 74 +++++++++++++++++++ .../devicetree/bindings/sound/wm8904.txt | 33 --------- 2 files changed, 74 insertions(+), 33 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/wlf,wm8904.yaml delete mode 100644 Documentation/devicetree/bindings/sound/wm8904.txt diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8904.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8904.yaml new file mode 100644 index 000000000000..329260cf0fa0 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wlf,wm8904.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/wlf,wm8904.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Wolfson WM8904/WM8912 audio codecs + +maintainers: + - patches@opensource.cirrus.com + +description: | + Pins on the device (for linking into audio routes): + IN1L, IN1R, IN2L, IN2R, IN3L, IN3R, HPOUTL, HPOUTR, LINEOUTL, LINEOUTR, + MICBIAS + +properties: + compatible: + enum: + - wlf,wm8904 + - wlf,wm8912 + + reg: + maxItems: 1 + + "#sound-dai-cells": + const: 0 + + clocks: + maxItems: 1 + + clock-names: + const: mclk + + AVDD-supply: true + CPVDD-supply: true + DBVDD-supply: true + DCVDD-supply: true + MICVDD-supply: true + +required: + - compatible + - reg + - clocks + - clock-names + - AVDD-supply + - CPVDD-supply + - DBVDD-supply + - DCVDD-supply + - MICVDD-supply + +allOf: + - $ref: dai-common.yaml# + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@1a { + compatible = "wlf,wm8904"; + reg = <0x1a>; + clocks = <&pck0>; + clock-names = "mclk"; + AVDD-supply = <®_1p8v>; + CPVDD-supply = <®_1p8v>; + DBVDD-supply = <®_1p8v>; + DCVDD-supply = <®_1p8v>; + MICVDD-supply = <®_1p8v>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/wm8904.txt b/Documentation/devicetree/bindings/sound/wm8904.txt deleted file mode 100644 index 66bf261423b9..000000000000 --- a/Documentation/devicetree/bindings/sound/wm8904.txt +++ /dev/null @@ -1,33 +0,0 @@ -WM8904 audio CODEC - -This device supports I2C only. - -Required properties: - - compatible: "wlf,wm8904" or "wlf,wm8912" - - reg: the I2C address of the device. - - clock-names: "mclk" - - clocks: reference to - - -Pins on the device (for linking into audio routes): - - * IN1L - * IN1R - * IN2L - * IN2R - * IN3L - * IN3R - * HPOUTL - * HPOUTR - * LINEOUTL - * LINEOUTR - * MICBIAS - -Examples: - -codec: wm8904@1a { - compatible = "wlf,wm8904"; - reg = <0x1a>; - clocks = <&pck0>; - clock-names = "mclk"; -}; From 944b5c7146fbd0a68f501d9a8a87c3fc5767a3de Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 18 Jul 2023 13:40:13 +0200 Subject: [PATCH 201/334] ASoC: dt-bindings: pm8916-analog-codec: Fix misleading example SPMI devices typically have a single address cell and no size cell, i.e. reg = <0xf000> for the audio codec instead of reg = <0xf000 0x200>. The example is a bit misleading because it uses the latter. Copying this into the device tree would be incorrect and was fixed before for pm8916.dtsi in commit c2f0cbb57dba ("arm64: dts: qcom: pm8916: Remove invalid reg size from wcd_codec"). Make the example more clear by adding the outer "pmic" node which specifies the same #address/size-cells that would be used in the real deivce tree. Signed-off-by: Stephan Gerhold Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230718-pm8916-mclk-v1-1-4b4a58b4240a@gerhold.net Signed-off-by: Mark Brown --- .../sound/qcom,pm8916-wcd-analog-codec.yaml | 90 ++++++++++--------- 1 file changed, 49 insertions(+), 41 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml index c385028c4296..77e3cfba4746 100644 --- a/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml @@ -115,46 +115,54 @@ examples: - | #include #include + #include - audio-codec@f000{ - compatible = "qcom,pm8916-wcd-analog-codec"; - reg = <0xf000 0x200>; - reg-names = "pmic-codec-core"; - clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>; - clock-names = "mclk"; - qcom,mbhc-vthreshold-low = <75 150 237 450 500>; - qcom,mbhc-vthreshold-high = <75 150 237 450 500>; - interrupt-parent = <&spmi_bus>; - interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>, - <0x1 0xf0 0x1 IRQ_TYPE_NONE>, - <0x1 0xf0 0x2 IRQ_TYPE_NONE>, - <0x1 0xf0 0x3 IRQ_TYPE_NONE>, - <0x1 0xf0 0x4 IRQ_TYPE_NONE>, - <0x1 0xf0 0x5 IRQ_TYPE_NONE>, - <0x1 0xf0 0x6 IRQ_TYPE_NONE>, - <0x1 0xf0 0x7 IRQ_TYPE_NONE>, - <0x1 0xf1 0x0 IRQ_TYPE_NONE>, - <0x1 0xf1 0x1 IRQ_TYPE_NONE>, - <0x1 0xf1 0x2 IRQ_TYPE_NONE>, - <0x1 0xf1 0x3 IRQ_TYPE_NONE>, - <0x1 0xf1 0x4 IRQ_TYPE_NONE>, - <0x1 0xf1 0x5 IRQ_TYPE_NONE>; - interrupt-names = "cdc_spk_cnp_int", - "cdc_spk_clip_int", - "cdc_spk_ocp_int", - "mbhc_ins_rem_det1", - "mbhc_but_rel_det", - "mbhc_but_press_det", - "mbhc_ins_rem_det", - "mbhc_switch_int", - "cdc_ear_ocp_int", - "cdc_hphr_ocp_int", - "cdc_hphl_ocp_det", - "cdc_ear_cnp_int", - "cdc_hphr_cnp_int", - "cdc_hphl_cnp_int"; - vdd-cdc-io-supply = <&pm8916_l5>; - vdd-cdc-tx-rx-cx-supply = <&pm8916_l5>; - vdd-micbias-supply = <&pm8916_l13>; - #sound-dai-cells = <1>; + pmic@1 { + compatible = "qcom,pm8916", "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + audio-codec@f000 { + compatible = "qcom,pm8916-wcd-analog-codec"; + reg = <0xf000>; + reg-names = "pmic-codec-core"; + clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>; + clock-names = "mclk"; + qcom,mbhc-vthreshold-low = <75 150 237 450 500>; + qcom,mbhc-vthreshold-high = <75 150 237 450 500>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>, + <0x1 0xf0 0x1 IRQ_TYPE_NONE>, + <0x1 0xf0 0x2 IRQ_TYPE_NONE>, + <0x1 0xf0 0x3 IRQ_TYPE_NONE>, + <0x1 0xf0 0x4 IRQ_TYPE_NONE>, + <0x1 0xf0 0x5 IRQ_TYPE_NONE>, + <0x1 0xf0 0x6 IRQ_TYPE_NONE>, + <0x1 0xf0 0x7 IRQ_TYPE_NONE>, + <0x1 0xf1 0x0 IRQ_TYPE_NONE>, + <0x1 0xf1 0x1 IRQ_TYPE_NONE>, + <0x1 0xf1 0x2 IRQ_TYPE_NONE>, + <0x1 0xf1 0x3 IRQ_TYPE_NONE>, + <0x1 0xf1 0x4 IRQ_TYPE_NONE>, + <0x1 0xf1 0x5 IRQ_TYPE_NONE>; + interrupt-names = "cdc_spk_cnp_int", + "cdc_spk_clip_int", + "cdc_spk_ocp_int", + "mbhc_ins_rem_det1", + "mbhc_but_rel_det", + "mbhc_but_press_det", + "mbhc_ins_rem_det", + "mbhc_switch_int", + "cdc_ear_ocp_int", + "cdc_hphr_ocp_int", + "cdc_hphl_ocp_det", + "cdc_ear_cnp_int", + "cdc_hphr_cnp_int", + "cdc_hphl_cnp_int"; + vdd-cdc-io-supply = <&pm8916_l5>; + vdd-cdc-tx-rx-cx-supply = <&pm8916_l5>; + vdd-micbias-supply = <&pm8916_l13>; + #sound-dai-cells = <1>; + }; }; From dfc491e55255a96b2d43cdb74db10d4222890769 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 18 Jul 2023 13:40:14 +0200 Subject: [PATCH 202/334] ASoC: dt-bindings: pm8916-analog-codec: Drop pointless reg-names pm8916-wcd-analog-codec has just a single reg region, so having a name for it provides no additional value. Drop it completely from the schema and example. There is not really any point in keeping it (even as deprecated) because it was never used. In old DTBs it will just be ignored as before. Signed-off-by: Stephan Gerhold Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230718-pm8916-mclk-v1-2-4b4a58b4240a@gerhold.net Signed-off-by: Mark Brown --- .../bindings/sound/qcom,pm8916-wcd-analog-codec.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml index 77e3cfba4746..5053799c88b5 100644 --- a/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml @@ -19,10 +19,6 @@ properties: reg: maxItems: 1 - reg-names: - items: - - const: pmic-codec-core - clocks: maxItems: 1 @@ -126,7 +122,6 @@ examples: audio-codec@f000 { compatible = "qcom,pm8916-wcd-analog-codec"; reg = <0xf000>; - reg-names = "pmic-codec-core"; clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>; clock-names = "mclk"; qcom,mbhc-vthreshold-low = <75 150 237 450 500>; From 469c6d9cd1cfb468f01a15f940272504a6b5d083 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 18 Jul 2023 13:40:15 +0200 Subject: [PATCH 203/334] ASoC: dt-bindings: pm8916-analog-codec: Drop invalid mclk The audio codec typically used for the MSM8916 SoC is split into two parts: the digital codec is part of the SoC, while the analog codec is part of the PM8916 PMIC. The analog codec in the PMIC has no direct connection to the mclk of the SoC (GCC_CODEC_DIGCODEC_CLK). As the name of the clock suggests this is supplied to the digital part of the codec. During playback it will use this clock to transmit the audio data via the "CDC PDM" pins to the PMIC. In this case the analog codec indirectly receives the clock signal through the digital codec. GCC_CODEC_DIGCODEC_CLK is already managed by the driver of the digital part of the codec in the SoC. Having this clock on the analog PMIC part additionally is redundant and incorrect because the analog codec cannot receive the clock signal without going through the digital codec. Cc: Srinivas Kandagatla Signed-off-by: Stephan Gerhold Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230718-pm8916-mclk-v1-3-4b4a58b4240a@gerhold.net Signed-off-by: Mark Brown --- .../bindings/sound/qcom,pm8916-wcd-analog-codec.yaml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml index 5053799c88b5..94e7a1860977 100644 --- a/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml @@ -19,13 +19,6 @@ properties: reg: maxItems: 1 - clocks: - maxItems: 1 - - clock-names: - items: - - const: mclk - interrupts: maxItems: 14 @@ -109,7 +102,6 @@ additionalProperties: false examples: - | - #include #include #include @@ -122,8 +114,6 @@ examples: audio-codec@f000 { compatible = "qcom,pm8916-wcd-analog-codec"; reg = <0xf000>; - clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>; - clock-names = "mclk"; qcom,mbhc-vthreshold-low = <75 150 237 450 500>; qcom,mbhc-vthreshold-high = <75 150 237 450 500>; interrupt-parent = <&spmi_bus>; From 97f29c1a6143762626f4f9bd9fc2f8a2282b9dcd Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 18 Jul 2023 13:40:16 +0200 Subject: [PATCH 204/334] ASoC: codecs: msm8916-wcd-analog: Drop invalid mclk The audio codec typically used for the MSM8916 SoC is split into two parts: the digital codec is part of the SoC, while the analog codec is part of the PM8916 PMIC. The analog codec in the PMIC has no direct connection to the mclk of the SoC (GCC_CODEC_DIGCODEC_CLK). As the name of the clock suggests this is supplied to the digital part of the codec. During playback it will use this clock to transmit the audio data via the "CDC PDM" pins to the PMIC. In this case the analog codec indirectly receives the clock signal through the digital codec. GCC_CODEC_DIGCODEC_CLK is already managed by the driver of the digital part of the codec in the SoC. Having this clock on the analog PMIC part additionally is redundant and incorrect because the analog codec cannot receive the clock signal without going through the digital codec. Cc: Srinivas Kandagatla Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20230718-pm8916-mclk-v1-4-4b4a58b4240a@gerhold.net Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-analog.c | 43 ++++----------------------- 1 file changed, 6 insertions(+), 37 deletions(-) diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index cec90cf920ff..d4456a714c97 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -1198,12 +1197,6 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) if (ret < 0) return ret; - priv->mclk = devm_clk_get(dev, "mclk"); - if (IS_ERR(priv->mclk)) { - dev_err(dev, "failed to get mclk\n"); - return PTR_ERR(priv->mclk); - } - for (i = 0; i < ARRAY_SIZE(supply_names); i++) priv->supplies[i].supply = supply_names[i]; @@ -1214,17 +1207,9 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) return ret; } - ret = clk_prepare_enable(priv->mclk); - if (ret < 0) { - dev_err(dev, "failed to enable mclk %d\n", ret); - return ret; - } - irq = platform_get_irq_byname(pdev, "mbhc_switch_int"); - if (irq < 0) { - ret = irq; - goto err_disable_clk; - } + if (irq < 0) + return irq; ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_mbhc_switch_irq_handler, @@ -1236,10 +1221,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) if (priv->mbhc_btn_enabled) { irq = platform_get_irq_byname(pdev, "mbhc_but_press_det"); - if (irq < 0) { - ret = irq; - goto err_disable_clk; - } + if (irq < 0) + return irq; ret = devm_request_threaded_irq(dev, irq, NULL, mbhc_btn_press_irq_handler, @@ -1250,10 +1233,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) dev_err(dev, "cannot request mbhc button press irq\n"); irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det"); - if (irq < 0) { - ret = irq; - goto err_disable_clk; - } + if (irq < 0) + return irq; ret = devm_request_threaded_irq(dev, irq, NULL, mbhc_btn_release_irq_handler, @@ -1270,17 +1251,6 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) return devm_snd_soc_register_component(dev, &pm8916_wcd_analog, pm8916_wcd_analog_dai, ARRAY_SIZE(pm8916_wcd_analog_dai)); - -err_disable_clk: - clk_disable_unprepare(priv->mclk); - return ret; -} - -static void pm8916_wcd_analog_spmi_remove(struct platform_device *pdev) -{ - struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(&pdev->dev); - - clk_disable_unprepare(priv->mclk); } static const struct of_device_id pm8916_wcd_analog_spmi_match_table[] = { @@ -1296,7 +1266,6 @@ static struct platform_driver pm8916_wcd_analog_spmi_driver = { .of_match_table = pm8916_wcd_analog_spmi_match_table, }, .probe = pm8916_wcd_analog_spmi_probe, - .remove_new = pm8916_wcd_analog_spmi_remove, }; module_platform_driver(pm8916_wcd_analog_spmi_driver); From 5c0f9652da47061ed3f7815c1dfeb205c545ce54 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 18 Jul 2023 13:40:17 +0200 Subject: [PATCH 205/334] ASoC: codecs: msm8916-wcd-analog: Properly handle probe errors The probe() function fails with an error for platform_get_irq_byname() but only logs when devm_request_threaded_irq() fails. Make this consistent and fail to probe in that case as well. In practice this should never happen unless something is really wrong. Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20230718-pm8916-mclk-v1-5-4b4a58b4240a@gerhold.net Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-analog.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index d4456a714c97..9ca381812975 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -1216,8 +1216,10 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "mbhc switch irq", priv); - if (ret) + if (ret) { dev_err(dev, "cannot request mbhc switch irq\n"); + return ret; + } if (priv->mbhc_btn_enabled) { irq = platform_get_irq_byname(pdev, "mbhc_but_press_det"); @@ -1229,8 +1231,10 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "mbhc btn press irq", priv); - if (ret) + if (ret) { dev_err(dev, "cannot request mbhc button press irq\n"); + return ret; + } irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det"); if (irq < 0) @@ -1241,9 +1245,10 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "mbhc btn release irq", priv); - if (ret) + if (ret) { dev_err(dev, "cannot request mbhc button release irq\n"); - + return ret; + } } dev_set_drvdata(dev, priv); From 68fa05d4a82b8f4ca6fa85be85833e35bd6ebef9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:20:58 +0200 Subject: [PATCH 206/334] ALSA: control: Introduce snd_ctl_find_id_mixer() A commonly seen pattern is to run snd_ctl_find_id() for a mixer control element with a given string. Let's provide a standard helper for achieving that for simplifying the code. Link: https://lore.kernel.org/r/20230720082108.31346-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/control.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/include/sound/control.h b/include/sound/control.h index 42e8dbb22d8e..69d950a34ca3 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -145,6 +145,28 @@ struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numi struct snd_kcontrol *snd_ctl_find_id_locked(struct snd_card *card, const struct snd_ctl_elem_id *id); struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, const struct snd_ctl_elem_id *id); +/** + * snd_ctl_find_id_mixer - find the control instance with the given name string + * @card: the card instance + * @name: the name string + * + * Finds the control instance with the given name and + * @SNDRV_CTL_ELEM_IFACE_MIXER. Other fields are set to zero. + * + * This is merely a wrapper to snd_ctl_find_id(). + * + * Return: The pointer of the instance if found, or %NULL if not. + */ +static inline struct snd_kcontrol * +snd_ctl_find_id_mixer(struct snd_card *card, const char *name) +{ + struct snd_ctl_elem_id id = {}; + + id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + strscpy(id.name, name, sizeof(id.name)); + return snd_ctl_find_id(card, &id); +} + int snd_ctl_create(struct snd_card *card); int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn); From 7affe6fd2a3a75ad0f052bc7e9965b38807bb113 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:20:59 +0200 Subject: [PATCH 207/334] ALSA: ca0106: Simplify with snd_ctl_find_id_mixer() Replace an open code with the new snd_ctl_find_id_mixer(). There is no functional change. Link: https://lore.kernel.org/r/20230720082108.31346-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_mixer.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index f6381c098d4f..2f37d2c3dd38 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -706,19 +706,9 @@ static int remove_ctl(struct snd_card *card, const char *name) return snd_ctl_remove_id(card, &id); } -static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name) -{ - struct snd_ctl_elem_id sid; - memset(&sid, 0, sizeof(sid)); - /* FIXME: strcpy is bad. */ - strcpy(sid.name, name); - sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - return snd_ctl_find_id(card, &sid); -} - static int rename_ctl(struct snd_card *card, const char *src, const char *dst) { - struct snd_kcontrol *kctl = ctl_find(card, src); + struct snd_kcontrol *kctl = snd_ctl_find_id_mixer(card, src); if (kctl) { snd_ctl_rename(card, kctl, dst); return 0; @@ -765,7 +755,8 @@ static void add_followers(struct snd_card *card, struct snd_kcontrol *master, const char * const *list) { for (; *list; list++) { - struct snd_kcontrol *follower = ctl_find(card, *list); + struct snd_kcontrol *follower = + snd_ctl_find_id_mixer(card, *list); if (follower) snd_ctl_add_follower(master, follower); } From f45828d464566140ee18089d0255199ba06db24a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:21:00 +0200 Subject: [PATCH 208/334] ALSA: cs46xx: Simplify with snd_ctl_find_id_mixer() Replace an open code with the new snd_ctl_find_id_mixer(). There is no functional change. Link: https://lore.kernel.org/r/20230720082108.31346-4-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/cs46xx/cs46xx_lib.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 7d882b33d45e..f3a94bb537bd 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -2449,7 +2449,6 @@ static int cs46xx_detect_codec(struct snd_cs46xx *chip, int codec) int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device) { struct snd_card *card = chip->card; - struct snd_ctl_elem_id id; int err; unsigned int idx; static const struct snd_ac97_bus_ops ops = { @@ -2490,10 +2489,8 @@ int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device) } /* get EAPD mixer switch (for voyetra hack) */ - memset(&id, 0, sizeof(id)); - id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strcpy(id.name, "External Amplifier"); - chip->eapd_switch = snd_ctl_find_id(chip->card, &id); + chip->eapd_switch = snd_ctl_find_id_mixer(chip->card, + "External Amplifier"); #ifdef CONFIG_SND_CS46XX_NEW_DSP if (chip->nr_ac97_codecs == 1) { From aa9e91806517399da497f4d38912c66ca44ed2f7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:21:01 +0200 Subject: [PATCH 209/334] ALSA: emu10k1: Simplify with snd_ctl_find_id_mixer() Replace an open code with the new snd_ctl_find_id_mixer(). There is no functional change. Link: https://lore.kernel.org/r/20230720082108.31346-5-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emumixer.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index f72a01f8f8f2..0a32ea53d8c6 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -1982,18 +1982,9 @@ static int remove_ctl(struct snd_card *card, const char *name) return snd_ctl_remove_id(card, &id); } -static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name) -{ - struct snd_ctl_elem_id sid; - memset(&sid, 0, sizeof(sid)); - strcpy(sid.name, name); - sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - return snd_ctl_find_id(card, &sid); -} - static int rename_ctl(struct snd_card *card, const char *src, const char *dst) { - struct snd_kcontrol *kctl = ctl_find(card, src); + struct snd_kcontrol *kctl = snd_ctl_find_id_mixer(card, src); if (kctl) { snd_ctl_rename(card, kctl, dst); return 0; From 5f2a937bd15614ad1836aacea06c6a1f49734859 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:21:02 +0200 Subject: [PATCH 210/334] ALSA: es1968: Simplify with snd_ctl_find_id_mixer() Replace an open code with the new snd_ctl_find_id_mixer(). There is no functional change. Link: https://lore.kernel.org/r/20230720082108.31346-6-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/es1968.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 4a7e20bb11bc..4bc0f53c223b 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -2005,9 +2005,6 @@ snd_es1968_mixer(struct es1968 *chip) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; -#ifndef CONFIG_SND_ES1968_INPUT - struct snd_ctl_elem_id elem_id; -#endif int err; static const struct snd_ac97_bus_ops ops = { .write = snd_es1968_ac97_write, @@ -2027,14 +2024,10 @@ snd_es1968_mixer(struct es1968 *chip) #ifndef CONFIG_SND_ES1968_INPUT /* attach master switch / volumes for h/w volume control */ - memset(&elem_id, 0, sizeof(elem_id)); - elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strcpy(elem_id.name, "Master Playback Switch"); - chip->master_switch = snd_ctl_find_id(chip->card, &elem_id); - memset(&elem_id, 0, sizeof(elem_id)); - elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strcpy(elem_id.name, "Master Playback Volume"); - chip->master_volume = snd_ctl_find_id(chip->card, &elem_id); + chip->master_switch = snd_ctl_find_id_mixer(chip->card, + "Master Playback Switch"); + chip->master_volume = snd_ctl_find_id_mixer(chip->card, + "Master Playback Volume"); #endif return 0; From 171c983027c7790d44902531e7e90ab01bee3b17 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:21:03 +0200 Subject: [PATCH 211/334] ALSA: ice1712: Simplify with snd_ctl_find_id_mixer() Replace an open code with the new snd_ctl_find_id_mixer(). There is no functional change. Also, add the missing NULL checks in psc724_set_jack_state() to deal with error cases. Link: https://lore.kernel.org/r/20230720082108.31346-7-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/ice1712/juli.c | 13 ++----------- sound/pci/ice1712/psc724.c | 19 ++++++++----------- sound/pci/ice1712/quartet.c | 13 ++----------- sound/pci/ice1712/wm8776.c | 6 +----- 4 files changed, 13 insertions(+), 38 deletions(-) diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index f0f8324b08b6..d80ecf1edc16 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -408,22 +408,13 @@ static const char * const follower_vols[] = { static DECLARE_TLV_DB_SCALE(juli_master_db_scale, -6350, 50, 1); -static struct snd_kcontrol *ctl_find(struct snd_card *card, - const char *name) -{ - struct snd_ctl_elem_id sid = {0}; - - strscpy(sid.name, name, sizeof(sid.name)); - sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - return snd_ctl_find_id(card, &sid); -} - static void add_followers(struct snd_card *card, struct snd_kcontrol *master, const char * const *list) { for (; *list; list++) { - struct snd_kcontrol *follower = ctl_find(card, *list); + struct snd_kcontrol *follower = + snd_ctl_find_id_mixer(card, *list); /* dev_dbg(card->dev, "add_followers - %s\n", *list); */ if (follower) { /* dev_dbg(card->dev, "follower %s found\n", *list); */ diff --git a/sound/pci/ice1712/psc724.c b/sound/pci/ice1712/psc724.c index 82cf365cda10..0818e42c94ca 100644 --- a/sound/pci/ice1712/psc724.c +++ b/sound/pci/ice1712/psc724.c @@ -177,7 +177,6 @@ static bool psc724_get_master_switch(struct snd_ice1712 *ice) static void psc724_set_jack_state(struct snd_ice1712 *ice, bool hp_connected) { struct psc724_spec *spec = ice->spec; - struct snd_ctl_elem_id elem_id; struct snd_kcontrol *kctl; u16 power = spec->wm8776.regs[WM8776_REG_PWRDOWN] & ~WM8776_PWR_HPPD; @@ -187,17 +186,15 @@ static void psc724_set_jack_state(struct snd_ice1712 *ice, bool hp_connected) snd_wm8776_set_power(&spec->wm8776, power); spec->hp_connected = hp_connected; /* notify about master speaker mute change */ - memset(&elem_id, 0, sizeof(elem_id)); - elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strscpy(elem_id.name, "Master Speakers Playback Switch", - sizeof(elem_id.name)); - kctl = snd_ctl_find_id(ice->card, &elem_id); - snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); + kctl = snd_ctl_find_id_mixer(ice->card, + "Master Speakers Playback Switch"); + if (kctl) + snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); /* and headphone mute change */ - strscpy(elem_id.name, spec->wm8776.ctl[WM8776_CTL_HP_SW].name, - sizeof(elem_id.name)); - kctl = snd_ctl_find_id(ice->card, &elem_id); - snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); + kctl = snd_ctl_find_id_mixer(ice->card, + spec->wm8776.ctl[WM8776_CTL_HP_SW].name); + if (kctl) + snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); } static void psc724_update_hp_jack_state(struct work_struct *work) diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c index 20b3e8f94719..9450c4b104f7 100644 --- a/sound/pci/ice1712/quartet.c +++ b/sound/pci/ice1712/quartet.c @@ -766,21 +766,12 @@ static const char * const follower_vols[] = { static DECLARE_TLV_DB_SCALE(qtet_master_db_scale, -6350, 50, 1); -static struct snd_kcontrol *ctl_find(struct snd_card *card, - const char *name) -{ - struct snd_ctl_elem_id sid = {0}; - - strscpy(sid.name, name, sizeof(sid.name)); - sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - return snd_ctl_find_id(card, &sid); -} - static void add_followers(struct snd_card *card, struct snd_kcontrol *master, const char * const *list) { for (; *list; list++) { - struct snd_kcontrol *follower = ctl_find(card, *list); + struct snd_kcontrol *follower = + snd_ctl_find_id_mixer(card, *list); if (follower) snd_ctl_add_follower(master, follower); } diff --git a/sound/pci/ice1712/wm8776.c b/sound/pci/ice1712/wm8776.c index 6eda86119dff..493425697bb4 100644 --- a/sound/pci/ice1712/wm8776.c +++ b/sound/pci/ice1712/wm8776.c @@ -34,13 +34,9 @@ static void snd_wm8776_activate_ctl(struct snd_wm8776 *wm, struct snd_card *card = wm->card; struct snd_kcontrol *kctl; struct snd_kcontrol_volatile *vd; - struct snd_ctl_elem_id elem_id; unsigned int index_offset; - memset(&elem_id, 0, sizeof(elem_id)); - strscpy(elem_id.name, ctl_name, sizeof(elem_id.name)); - elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kctl = snd_ctl_find_id(card, &elem_id); + kctl = snd_ctl_find_id_mixer(card, ctl_name); if (!kctl) return; index_offset = snd_ctl_get_ioff(kctl, &kctl->id); From 233913c0bc60cf2ce68d5399da430b872c813a5e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:21:04 +0200 Subject: [PATCH 212/334] ALSA: maestro3: Simplify with snd_ctl_find_id_mixer() Replace an open code with the new snd_ctl_find_id_mixer(). There is no functional change. Link: https://lore.kernel.org/r/20230720082108.31346-8-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/maestro3.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 261850775c80..305cbd24a391 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -2029,9 +2029,6 @@ static int snd_m3_mixer(struct snd_m3 *chip) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; -#ifndef CONFIG_SND_MAESTRO3_INPUT - struct snd_ctl_elem_id elem_id; -#endif int err; static const struct snd_ac97_bus_ops ops = { .write = snd_m3_ac97_write, @@ -2054,14 +2051,10 @@ static int snd_m3_mixer(struct snd_m3 *chip) snd_ac97_write(chip->ac97, AC97_PCM, 0); #ifndef CONFIG_SND_MAESTRO3_INPUT - memset(&elem_id, 0, sizeof(elem_id)); - elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strcpy(elem_id.name, "Master Playback Switch"); - chip->master_switch = snd_ctl_find_id(chip->card, &elem_id); - memset(&elem_id, 0, sizeof(elem_id)); - elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strcpy(elem_id.name, "Master Playback Volume"); - chip->master_volume = snd_ctl_find_id(chip->card, &elem_id); + chip->master_switch = snd_ctl_find_id_mixer(chip->card, + "Master Playback Switch"); + chip->master_volume = snd_ctl_find_id_mixer(chip->card, + "Master Playback Volume"); #endif return 0; From a16ea09d2254a03dca61818c884a6c36233f63dc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:21:05 +0200 Subject: [PATCH 213/334] ALSA: via82xx: Simplify with snd_ctl_find_id_mixer() Replace an open code with the new snd_ctl_find_id_mixer(). There is no functional change. Link: https://lore.kernel.org/r/20230720082108.31346-9-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/via82xx.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 361b83fd721e..d8666ff7bdfa 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -1984,11 +1984,7 @@ static int snd_via8233_init_misc(struct via82xx *chip) /* when no h/w PCM volume control is found, use DXS volume control * as the PCM vol control */ - struct snd_ctl_elem_id sid; - memset(&sid, 0, sizeof(sid)); - strcpy(sid.name, "PCM Playback Volume"); - sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - if (! snd_ctl_find_id(chip->card, &sid)) { + if (!snd_ctl_find_id_mixer(chip->card, "PCM Playback Volume")) { dev_info(chip->card->dev, "Using DXS as PCM Playback\n"); err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_pcmdxs_volume_control, chip)); From b6ba0aa46138a9dd0ebad718f761814d6071605d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:21:06 +0200 Subject: [PATCH 214/334] ALSA: cmipci: Simplify with snd_ctl_find_id_mixer() Replace an open code with the new snd_ctl_find_id_mixer(). There is no functional change. Link: https://lore.kernel.org/r/20230720082108.31346-10-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/cmipci.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 6d25c12d9ef0..1415baac9c36 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -2734,12 +2734,8 @@ static int snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device) } for (idx = 0; idx < CM_SAVED_MIXERS; idx++) { - struct snd_ctl_elem_id elem_id; struct snd_kcontrol *ctl; - memset(&elem_id, 0, sizeof(elem_id)); - elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strcpy(elem_id.name, cm_saved_mixer[idx].name); - ctl = snd_ctl_find_id(cm->card, &elem_id); + ctl = snd_ctl_find_id_mixer(cm->card, cm_saved_mixer[idx].name); if (ctl) cm->mixer_res_ctl[idx] = ctl; } From ca141fe31df06fd5769e3d1d41e2a7b68b308243 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:21:07 +0200 Subject: [PATCH 215/334] ASoC: mediatek: mt8188: Simplify with snd_ctl_find_id_mixer() Replace an open code with the new snd_ctl_find_id_mixer(). There is no functional change. Acked-by: Mark Brown Cc: Trevor Wu Link: https://lore.kernel.org/r/20230720082108.31346-11-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/soc/mediatek/mt8188/mt8188-mt6359.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/soc/mediatek/mt8188/mt8188-mt6359.c b/sound/soc/mediatek/mt8188/mt8188-mt6359.c index ac69c23e0da1..6ebcc9497ea0 100644 --- a/sound/soc/mediatek/mt8188/mt8188-mt6359.c +++ b/sound/soc/mediatek/mt8188/mt8188-mt6359.c @@ -969,16 +969,6 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { }, }; -static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name) -{ - struct snd_ctl_elem_id sid; - - memset(&sid, 0, sizeof(sid)); - strcpy(sid.name, name); - sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - return snd_ctl_find_id(card, &sid); -} - static void mt8188_fixup_controls(struct snd_soc_card *card) { struct mt8188_mt6359_priv *priv = snd_soc_card_get_drvdata(card); @@ -995,7 +985,7 @@ static void mt8188_fixup_controls(struct snd_soc_card *card) snd_soc_dapm_free_widget(w); } - kctl = ctl_find(card->snd_card, "Headphone Switch"); + kctl = snd_ctl_find_id_mixer(card->snd_card, "Headphone Switch"); if (kctl) snd_ctl_remove(card->snd_card, kctl); else From ebc1bfebdacab9e7fd77eec2c5dbcef73980ab00 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:21:08 +0200 Subject: [PATCH 216/334] ALSA: ac97: Simplify with snd_ctl_find_id_mixer() Replace an open code with the new snd_ctl_find_id_mixer(). There is no functional change. Link: https://lore.kernel.org/r/20230720082108.31346-12-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_patch.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 4b5f33de70d5..ccfd9c7bf900 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -3431,11 +3431,7 @@ static const char * const follower_sws_vt1616[] = { static struct snd_kcontrol *snd_ac97_find_mixer_ctl(struct snd_ac97 *ac97, const char *name) { - struct snd_ctl_elem_id id; - memset(&id, 0, sizeof(id)); - id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strcpy(id.name, name); - return snd_ctl_find_id(ac97->bus->card, &id); + return snd_ctl_find_id_mixer(ac97->bus->card, name); } /* create a virtual master control and add followers */ From ae07eb9bf23e1a52cdb28222a71eb014131018d8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Jul 2023 09:16:40 +0200 Subject: [PATCH 217/334] ALSA: vmaster: Add snd_ctl_add_followers() helper Add a new helper to add multiple vmaster followers in a shot. The same function was open-coded in various places, and this helper replaces them. Link: https://lore.kernel.org/r/20230721071643.3631-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/control.h | 3 +++ sound/core/vmaster.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/include/sound/control.h b/include/sound/control.h index 69d950a34ca3..9a4f4f7138da 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -262,6 +262,9 @@ snd_ctl_add_follower(struct snd_kcontrol *master, struct snd_kcontrol *follower) return _snd_ctl_add_follower(master, follower, 0); } +int snd_ctl_add_followers(struct snd_card *card, struct snd_kcontrol *master, + const char * const *list); + /** * snd_ctl_add_follower_uncached - Add a virtual follower control * @master: vmaster element diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c index d0f11f37889b..378d2c7c3d4a 100644 --- a/sound/core/vmaster.c +++ b/sound/core/vmaster.c @@ -280,6 +280,34 @@ int _snd_ctl_add_follower(struct snd_kcontrol *master, } EXPORT_SYMBOL(_snd_ctl_add_follower); +/** + * snd_ctl_add_followers - add multiple followers to vmaster + * @card: card instance + * @master: the target vmaster kcontrol object + * @list: NULL-terminated list of name strings of followers to be added + * + * Adds the multiple follower kcontrols with the given names. + * Returns 0 for success or a negative error code. + */ +int snd_ctl_add_followers(struct snd_card *card, struct snd_kcontrol *master, + const char * const *list) +{ + struct snd_kcontrol *follower; + int err; + + for (; *list; list++) { + follower = snd_ctl_find_id_mixer(card, *list); + if (follower) { + err = snd_ctl_add_follower(master, follower); + if (err < 0) + return err; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_ctl_add_followers); + /* * ctl callbacks for master controls */ From 1caf64d91f72321191f7dc24d8e950222acc9bfa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Jul 2023 09:16:41 +0200 Subject: [PATCH 218/334] ALSA: ac97: Use the standard snd_ctl_add_followers() helper Instead of open-code, use the new standard helper to manage vmaster stuff for code simplification. Except for a debug print, there should be no functional change. Link: https://lore.kernel.org/r/20230721071643.3631-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_patch.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index ccfd9c7bf900..1d786bd5ce3e 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -3440,7 +3440,6 @@ static int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name, const char * const *followers) { struct snd_kcontrol *kctl; - const char * const *s; int err; kctl = snd_ctl_make_virtual_master(name, tlv); @@ -3450,20 +3449,7 @@ static int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name, if (err < 0) return err; - for (s = followers; *s; s++) { - struct snd_kcontrol *sctl; - - sctl = snd_ac97_find_mixer_ctl(ac97, *s); - if (!sctl) { - dev_dbg(ac97->bus->card->dev, - "Cannot find follower %s, skipped\n", *s); - continue; - } - err = snd_ctl_add_follower(kctl, sctl); - if (err < 0) - return err; - } - return 0; + return snd_ctl_add_followers(ac97->bus->card, kctl, followers); } static int patch_vt1616_specific(struct snd_ac97 * ac97) From b7bb11fa361f4319b1bbf7cc390ef4dd83236be3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Jul 2023 09:16:42 +0200 Subject: [PATCH 219/334] ALSA: ca0106: Use the standard snd_ctl_add_followers() helper Instead of open-code, use the new standard helper to manage vmaster stuff for code simplification. Also, handle the errors from the helper more properly instead of silently ignoring. Link: https://lore.kernel.org/r/20230721071643.3631-4-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_mixer.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 2f37d2c3dd38..1d5a899b2c24 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -751,17 +751,6 @@ static const char * const follower_sws[] = { NULL }; -static void add_followers(struct snd_card *card, - struct snd_kcontrol *master, const char * const *list) -{ - for (; *list; list++) { - struct snd_kcontrol *follower = - snd_ctl_find_id_mixer(card, *list); - if (follower) - snd_ctl_add_follower(master, follower); - } -} - int snd_ca0106_mixer(struct snd_ca0106 *emu) { int err; @@ -843,7 +832,9 @@ int snd_ca0106_mixer(struct snd_ca0106 *emu) err = snd_ctl_add(card, vmaster); if (err < 0) return err; - add_followers(card, vmaster, follower_vols); + err = snd_ctl_add_followers(card, vmaster, follower_vols); + if (err < 0) + return err; if (emu->details->spi_dac) { vmaster = snd_ctl_make_virtual_master("Master Playback Switch", @@ -853,7 +844,9 @@ int snd_ca0106_mixer(struct snd_ca0106 *emu) err = snd_ctl_add(card, vmaster); if (err < 0) return err; - add_followers(card, vmaster, follower_sws); + err = snd_ctl_add_followers(card, vmaster, follower_sws); + if (err < 0) + return err; } strcpy(card->mixername, "CA0106"); From 157ac57073bc33396ed719bfdcdccb72798a822d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Jul 2023 09:16:43 +0200 Subject: [PATCH 220/334] ALSA: ice1712: Use the standard snd_ctl_add_followers() helper Instead of open-code, use the new standard helper to manage vmaster stuff for code simplification. Also, handle the errors from the helper more properly instead of silently ignoring. The code changes the call order of snd_ctl_add() of the vmaster object and its followers for avoiding the possible memory leaks at error path. But there should be no difference in the functionality. Link: https://lore.kernel.org/r/20230721071643.3631-5-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/ice1712/juli.c | 19 +++---------------- sound/pci/ice1712/quartet.c | 15 +++------------ 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index d80ecf1edc16..d679842ae1bd 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -408,21 +408,6 @@ static const char * const follower_vols[] = { static DECLARE_TLV_DB_SCALE(juli_master_db_scale, -6350, 50, 1); -static void add_followers(struct snd_card *card, - struct snd_kcontrol *master, - const char * const *list) -{ - for (; *list; list++) { - struct snd_kcontrol *follower = - snd_ctl_find_id_mixer(card, *list); - /* dev_dbg(card->dev, "add_followers - %s\n", *list); */ - if (follower) { - /* dev_dbg(card->dev, "follower %s found\n", *list); */ - snd_ctl_add_follower(master, follower); - } - } -} - static int juli_add_controls(struct snd_ice1712 *ice) { struct juli_spec *spec = ice->spec; @@ -445,8 +430,10 @@ static int juli_add_controls(struct snd_ice1712 *ice) juli_master_db_scale); if (!vmaster) return -ENOMEM; - add_followers(ice->card, vmaster, follower_vols); err = snd_ctl_add(ice->card, vmaster); + if (err < 0) + return err; + err = snd_ctl_add_followers(ice->card, vmaster, follower_vols); if (err < 0) return err; diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c index 9450c4b104f7..f61ee9f5c754 100644 --- a/sound/pci/ice1712/quartet.c +++ b/sound/pci/ice1712/quartet.c @@ -766,17 +766,6 @@ static const char * const follower_vols[] = { static DECLARE_TLV_DB_SCALE(qtet_master_db_scale, -6350, 50, 1); -static void add_followers(struct snd_card *card, - struct snd_kcontrol *master, const char * const *list) -{ - for (; *list; list++) { - struct snd_kcontrol *follower = - snd_ctl_find_id_mixer(card, *list); - if (follower) - snd_ctl_add_follower(master, follower); - } -} - static int qtet_add_controls(struct snd_ice1712 *ice) { struct qtet_spec *spec = ice->spec; @@ -797,8 +786,10 @@ static int qtet_add_controls(struct snd_ice1712 *ice) qtet_master_db_scale); if (!vmaster) return -ENOMEM; - add_followers(ice->card, vmaster, follower_vols); err = snd_ctl_add(ice->card, vmaster); + if (err < 0) + return err; + err = snd_ctl_add_followers(ice->card, vmaster, follower_vols); if (err < 0) return err; /* only capture SPDIF over AK4113 */ From 8cf2e3b1961e59dabc75e9e917d58439164a8f84 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 21 Jul 2023 16:24:02 +0800 Subject: [PATCH 221/334] ASoC: wm8960: Add DAC filter characteristics selection Support DAC filter characteristics selection: Normal mode and Sloping stopband. Sloping stopband may have better frequency response. Signed-off-by: Shengjiu Wang Acked-by: Charles Keepax Link: https://lore.kernel.org/r/1689927842-21165-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 92fb7ab6e896..c2bd9ef41ebb 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -155,6 +155,7 @@ static const char *wm8960_adc_data_output_sel[] = { "Left Data = Right ADC; Right Data = Left ADC", }; static const char *wm8960_dmonomix[] = {"Stereo", "Mono"}; +static const char *wm8960_dacslope[] = {"Normal", "Sloping"}; static const struct soc_enum wm8960_enum[] = { SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity), @@ -165,6 +166,7 @@ static const struct soc_enum wm8960_enum[] = { SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode), SOC_ENUM_SINGLE(WM8960_ADDCTL1, 2, 4, wm8960_adc_data_output_sel), SOC_ENUM_SINGLE(WM8960_ADDCTL1, 4, 2, wm8960_dmonomix), + SOC_ENUM_SINGLE(WM8960_DACCTL2, 1, 2, wm8960_dacslope), }; static const int deemph_settings[] = { 0, 32000, 44100, 48000 }; @@ -307,6 +309,7 @@ SOC_SINGLE_TLV("Right Output Mixer RINPUT3 Volume", SOC_ENUM("ADC Data Output Select", wm8960_enum[6]), SOC_ENUM("DAC Mono Mix", wm8960_enum[7]), +SOC_ENUM("DAC Filter Characteristics", wm8960_enum[8]), }; static const struct snd_kcontrol_new wm8960_lin_boost[] = { From 3c851b6384729d60b968cd37a03382bf50acb92b Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 21 Jul 2023 16:57:21 +0300 Subject: [PATCH 222/334] ALSA: hda/hdmi: keep codec entries in numerical order Switch order of Intel MTL and RPL codec entries to keep the codec device id list nicely ordered. Also use the opportunity to fix the naming to the convention used elsewhere in the drivers. Signed-off-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230721135722.31288-2-peter.ujfalusi@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 260d3e64f658..5139b6e087b3 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -4632,8 +4632,8 @@ 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(0x8086281f, "Raptorlake-P HDMI", patch_i915_adlp_hdmi), -HDA_CODEC_ENTRY(0x8086281d, "Meteorlake HDMI", patch_i915_adlp_hdmi), +HDA_CODEC_ENTRY(0x8086281d, "Meteor Lake HDMI", patch_i915_adlp_hdmi), +HDA_CODEC_ENTRY(0x8086281f, "Raptor Lake P 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), From 6d37a07fdcf9431124cdbf030fbea99c4f352ead Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 21 Jul 2023 16:57:22 +0300 Subject: [PATCH 223/334] ALSA: hda: add HDMI codec ID for Intel LNL Add HDMI codec ID for Intel Lunar Lake platform. Signed-off-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230721135722.31288-3-peter.ujfalusi@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 5139b6e087b3..1cde2a69bdb4 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -4634,6 +4634,7 @@ 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(0x8086281f, "Raptor Lake P HDMI", patch_i915_adlp_hdmi), +HDA_CODEC_ENTRY(0x80862820, "Lunar 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), From 898673b905b9318489430663083f629bc38c7461 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Fri, 21 Jul 2023 14:21:10 +0100 Subject: [PATCH 224/334] ASoC: cs35l56: Move shared data into a common data structure The ASoC and HDA drivers have structures that contain some of the same information - instead of maintaining two locations for this data the drivers should share a common data structure as this will enable common utility functions to be created. The first step is to move the location of these members in the ASoC driver. Signed-off-by: Simon Trimmer Signed-off-by: Richard Fitzgerald Acked-by: Mark Brown Link: https://lore.kernel.org/r/20230721132120.5523-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l56.h | 15 +- sound/soc/codecs/cs35l56-i2c.c | 14 +- sound/soc/codecs/cs35l56-sdw.c | 68 ++--- sound/soc/codecs/cs35l56-shared.c | 5 +- sound/soc/codecs/cs35l56-spi.c | 10 +- sound/soc/codecs/cs35l56.c | 404 +++++++++++++++--------------- sound/soc/codecs/cs35l56.h | 13 +- 7 files changed, 270 insertions(+), 259 deletions(-) diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index ec672daa36cf..532796efdaa5 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -252,6 +252,19 @@ #define CS35L56_NUM_BULK_SUPPLIES 3 #define CS35L56_NUM_DSP_REGIONS 5 +struct cs35l56_base { + struct device *dev; + struct regmap *regmap; + int irq; + struct mutex irq_lock; + u8 rev; + bool init_done; + bool fw_patched; + bool secured; + bool can_hibernate; + struct gpio_desc *reset_gpio; +}; + extern struct regmap_config cs35l56_regmap_i2c; extern struct regmap_config cs35l56_regmap_spi; extern struct regmap_config cs35l56_regmap_sdw; @@ -260,7 +273,7 @@ extern const struct cs_dsp_region cs35l56_dsp1_regions[CS35L56_NUM_DSP_REGIONS]; extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC]; extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC]; -int cs35l56_set_patch(struct regmap *regmap); +int cs35l56_set_patch(struct cs35l56_base *cs35l56_base); int cs35l56_get_bclk_freq_id(unsigned int freq); void cs35l56_fill_supply_names(struct regulator_bulk_data *data); diff --git a/sound/soc/codecs/cs35l56-i2c.c b/sound/soc/codecs/cs35l56-i2c.c index ed2a41943d97..888fdfa5f5db 100644 --- a/sound/soc/codecs/cs35l56-i2c.c +++ b/sound/soc/codecs/cs35l56-i2c.c @@ -26,14 +26,14 @@ static int cs35l56_i2c_probe(struct i2c_client *client) if (!cs35l56) return -ENOMEM; - cs35l56->dev = dev; - cs35l56->can_hibernate = true; + cs35l56->base.dev = dev; + cs35l56->base.can_hibernate = true; i2c_set_clientdata(client, cs35l56); - cs35l56->regmap = devm_regmap_init_i2c(client, regmap_config); - if (IS_ERR(cs35l56->regmap)) { - ret = PTR_ERR(cs35l56->regmap); - return dev_err_probe(cs35l56->dev, ret, "Failed to allocate register map\n"); + cs35l56->base.regmap = devm_regmap_init_i2c(client, regmap_config); + if (IS_ERR(cs35l56->base.regmap)) { + ret = PTR_ERR(cs35l56->base.regmap); + return dev_err_probe(cs35l56->base.dev, ret, "Failed to allocate register map\n"); } ret = cs35l56_common_probe(cs35l56); @@ -42,7 +42,7 @@ static int cs35l56_i2c_probe(struct i2c_client *client) ret = cs35l56_init(cs35l56); if (ret == 0) - ret = cs35l56_irq_request(cs35l56, client->irq); + ret = cs35l56_irq_request(&cs35l56->base, client->irq); if (ret < 0) cs35l56_remove(cs35l56); diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c index 2cde78605ba9..98be005b8787 100644 --- a/sound/soc/codecs/cs35l56-sdw.c +++ b/sound/soc/codecs/cs35l56-sdw.c @@ -166,13 +166,13 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral) struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev); int ret; - pm_runtime_get_noresume(cs35l56->dev); + pm_runtime_get_noresume(cs35l56->base.dev); - regcache_cache_only(cs35l56->regmap, false); + regcache_cache_only(cs35l56->base.regmap, false); ret = cs35l56_init(cs35l56); if (ret < 0) { - regcache_cache_only(cs35l56->regmap, true); + regcache_cache_only(cs35l56->base.regmap, true); goto out; } @@ -180,15 +180,15 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral) * cs35l56_init can return with !init_done if it triggered * a soft reset. */ - if (cs35l56->init_done) { + if (cs35l56->base.init_done) { /* Enable SoundWire interrupts */ sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_MASK_1, CS35L56_SDW_INT_MASK_CODEC_IRQ); } out: - pm_runtime_mark_last_busy(cs35l56->dev); - pm_runtime_put_autosuspend(cs35l56->dev); + pm_runtime_mark_last_busy(cs35l56->base.dev); + pm_runtime_put_autosuspend(cs35l56->base.dev); } static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral, @@ -198,7 +198,7 @@ static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral, /* SoundWire core holds our pm_runtime when calling this function. */ - dev_dbg(cs35l56->dev, "int control_port=%#x\n", status->control_port); + dev_dbg(cs35l56->base.dev, "int control_port=%#x\n", status->control_port); if ((status->control_port & SDW_SCP_INT1_IMPL_DEF) == 0) return 0; @@ -207,7 +207,7 @@ static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral, * Prevent bus manager suspending and possibly issuing a * bus-reset before the queued work has run. */ - pm_runtime_get_noresume(cs35l56->dev); + pm_runtime_get_noresume(cs35l56->base.dev); /* * Mask and clear until it has been handled. The read of GEN_INT_STAT_1 @@ -230,14 +230,14 @@ static void cs35l56_sdw_irq_work(struct work_struct *work) struct cs35l56_private, sdw_irq_work); - cs35l56_irq(-1, cs35l56); + cs35l56_irq(-1, &cs35l56->base); /* unmask interrupts */ if (!cs35l56->sdw_irq_no_unmask) sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_MASK_1, CS35L56_SDW_INT_MASK_CODEC_IRQ); - pm_runtime_put_autosuspend(cs35l56->dev); + pm_runtime_put_autosuspend(cs35l56->base.dev); } static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral) @@ -246,7 +246,7 @@ static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral) struct sdw_slave_prop *prop = &peripheral->prop; struct sdw_dpn_prop *ports; - ports = devm_kcalloc(cs35l56->dev, 2, sizeof(*ports), GFP_KERNEL); + ports = devm_kcalloc(cs35l56->base.dev, 2, sizeof(*ports), GFP_KERNEL); if (!ports) return -ENOMEM; @@ -279,17 +279,17 @@ static int cs35l56_sdw_update_status(struct sdw_slave *peripheral, switch (status) { case SDW_SLAVE_ATTACHED: - dev_dbg(cs35l56->dev, "%s: ATTACHED\n", __func__); + dev_dbg(cs35l56->base.dev, "%s: ATTACHED\n", __func__); if (cs35l56->sdw_attached) break; - if (!cs35l56->init_done || cs35l56->soft_resetting) + if (!cs35l56->base.init_done || cs35l56->soft_resetting) cs35l56_sdw_init(peripheral); cs35l56->sdw_attached = true; break; case SDW_SLAVE_UNATTACHED: - dev_dbg(cs35l56->dev, "%s: UNATTACHED\n", __func__); + dev_dbg(cs35l56->base.dev, "%s: UNATTACHED\n", __func__); cs35l56->sdw_attached = false; break; default: @@ -305,7 +305,7 @@ static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56, unsigned int curr_scale_reg, next_scale_reg; int curr_scale, next_scale, ret; - if (!cs35l56->init_done) + if (!cs35l56->base.init_done) return 0; if (peripheral->bus->params.curr_bank) { @@ -324,13 +324,13 @@ static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56, */ curr_scale = sdw_read_no_pm(peripheral, curr_scale_reg); if (curr_scale < 0) { - dev_err(cs35l56->dev, "Failed to read current clock scale: %d\n", curr_scale); + dev_err(cs35l56->base.dev, "Failed to read current clock scale: %d\n", curr_scale); return curr_scale; } next_scale = sdw_read_no_pm(peripheral, next_scale_reg); if (next_scale < 0) { - dev_err(cs35l56->dev, "Failed to read next clock scale: %d\n", next_scale); + dev_err(cs35l56->base.dev, "Failed to read next clock scale: %d\n", next_scale); return next_scale; } @@ -338,7 +338,8 @@ static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56, next_scale = cs35l56->old_sdw_clock_scale; ret = sdw_write_no_pm(peripheral, next_scale_reg, next_scale); if (ret < 0) { - dev_err(cs35l56->dev, "Failed to modify current clock scale: %d\n", ret); + dev_err(cs35l56->base.dev, "Failed to modify current clock scale: %d\n", + ret); return ret; } } @@ -346,11 +347,11 @@ static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56, cs35l56->old_sdw_clock_scale = curr_scale; ret = sdw_write_no_pm(peripheral, curr_scale_reg, CS35L56_SDW_INVALID_BUS_SCALE); if (ret < 0) { - dev_err(cs35l56->dev, "Failed to modify current clock scale: %d\n", ret); + dev_err(cs35l56->base.dev, "Failed to modify current clock scale: %d\n", ret); return ret; } - dev_dbg(cs35l56->dev, "Next bus scale: %#x\n", next_scale); + dev_dbg(cs35l56->base.dev, "Next bus scale: %#x\n", next_scale); return 0; } @@ -362,9 +363,10 @@ static int cs35l56_sdw_bus_config(struct sdw_slave *peripheral, int sclk; sclk = params->curr_dr_freq / 2; - dev_dbg(cs35l56->dev, "%s: sclk=%u c=%u r=%u\n", __func__, sclk, params->col, params->row); + dev_dbg(cs35l56->base.dev, "%s: sclk=%u c=%u r=%u\n", + __func__, sclk, params->col, params->row); - if (cs35l56->rev < 0xb0) + if (cs35l56->base.rev < 0xb0) return cs35l56_a1_kick_divider(cs35l56, peripheral); return 0; @@ -376,7 +378,7 @@ static int __maybe_unused cs35l56_sdw_clk_stop(struct sdw_slave *peripheral, { struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev); - dev_dbg(cs35l56->dev, "%s: mode:%d type:%d\n", __func__, mode, type); + dev_dbg(cs35l56->base.dev, "%s: mode:%d type:%d\n", __func__, mode, type); return 0; } @@ -397,10 +399,10 @@ static int __maybe_unused cs35l56_sdw_handle_unattach(struct cs35l56_private *cs if (peripheral->unattach_request) { /* Cannot access registers until bus is re-initialized. */ - dev_dbg(cs35l56->dev, "Wait for initialization_complete\n"); + dev_dbg(cs35l56->base.dev, "Wait for initialization_complete\n"); if (!wait_for_completion_timeout(&peripheral->initialization_complete, msecs_to_jiffies(5000))) { - dev_err(cs35l56->dev, "initialization_complete timed out\n"); + dev_err(cs35l56->base.dev, "initialization_complete timed out\n"); return -ETIMEDOUT; } @@ -419,7 +421,7 @@ static int __maybe_unused cs35l56_sdw_runtime_suspend(struct device *dev) { struct cs35l56_private *cs35l56 = dev_get_drvdata(dev); - if (!cs35l56->init_done) + if (!cs35l56->base.init_done) return 0; return cs35l56_runtime_suspend(dev); @@ -432,7 +434,7 @@ static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev) dev_dbg(dev, "Runtime resume\n"); - if (!cs35l56->init_done) + if (!cs35l56->base.init_done) return 0; ret = cs35l56_sdw_handle_unattach(cs35l56); @@ -454,7 +456,7 @@ static int __maybe_unused cs35l56_sdw_system_suspend(struct device *dev) { struct cs35l56_private *cs35l56 = dev_get_drvdata(dev); - if (!cs35l56->init_done) + if (!cs35l56->base.init_done) return 0; /* @@ -493,21 +495,21 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi if (!cs35l56) return -ENOMEM; - cs35l56->dev = dev; + cs35l56->base.dev = dev; cs35l56->sdw_peripheral = peripheral; INIT_WORK(&cs35l56->sdw_irq_work, cs35l56_sdw_irq_work); dev_set_drvdata(dev, cs35l56); - cs35l56->regmap = devm_regmap_init(dev, &cs35l56_regmap_bus_sdw, + cs35l56->base.regmap = devm_regmap_init(dev, &cs35l56_regmap_bus_sdw, peripheral, &cs35l56_regmap_sdw); - if (IS_ERR(cs35l56->regmap)) { - ret = PTR_ERR(cs35l56->regmap); + if (IS_ERR(cs35l56->base.regmap)) { + ret = PTR_ERR(cs35l56->base.regmap); return dev_err_probe(dev, ret, "Failed to allocate register map\n"); } /* Start in cache-only until device is enumerated */ - regcache_cache_only(cs35l56->regmap, true); + regcache_cache_only(cs35l56->base.regmap, true); ret = cs35l56_common_probe(cs35l56); if (ret != 0) diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index cb0130d1e7e9..47b915f33f52 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -18,9 +18,10 @@ static const struct reg_sequence cs35l56_patch[] = { { CS35L56_MAIN_POSTURE_NUMBER, 0x00000000 }, }; -int cs35l56_set_patch(struct regmap *regmap) +int cs35l56_set_patch(struct cs35l56_base *cs35l56_base) { - return regmap_register_patch(regmap, cs35l56_patch, ARRAY_SIZE(cs35l56_patch)); + return regmap_register_patch(cs35l56_base->regmap, cs35l56_patch, + ARRAY_SIZE(cs35l56_patch)); } EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, SND_SOC_CS35L56_SHARED); diff --git a/sound/soc/codecs/cs35l56-spi.c b/sound/soc/codecs/cs35l56-spi.c index 996aab10500e..2057fce435be 100644 --- a/sound/soc/codecs/cs35l56-spi.c +++ b/sound/soc/codecs/cs35l56-spi.c @@ -25,13 +25,13 @@ static int cs35l56_spi_probe(struct spi_device *spi) return -ENOMEM; spi_set_drvdata(spi, cs35l56); - cs35l56->regmap = devm_regmap_init_spi(spi, regmap_config); - if (IS_ERR(cs35l56->regmap)) { - ret = PTR_ERR(cs35l56->regmap); + cs35l56->base.regmap = devm_regmap_init_spi(spi, regmap_config); + if (IS_ERR(cs35l56->base.regmap)) { + ret = PTR_ERR(cs35l56->base.regmap); return dev_err_probe(&spi->dev, ret, "Failed to allocate register map\n"); } - cs35l56->dev = &spi->dev; + cs35l56->base.dev = &spi->dev; ret = cs35l56_common_probe(cs35l56); if (ret != 0) @@ -39,7 +39,7 @@ static int cs35l56_spi_probe(struct spi_device *spi) ret = cs35l56_init(cs35l56); if (ret == 0) - ret = cs35l56_irq_request(cs35l56, spi->irq); + ret = cs35l56_irq_request(&cs35l56->base, spi->irq); if (ret < 0) cs35l56_remove(cs35l56); diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index e046fdd26b74..4eb8e5b09bfd 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -34,17 +34,17 @@ static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); -static int cs35l56_mbox_send(struct cs35l56_private *cs35l56, unsigned int command) +static int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command) { unsigned int val; int ret; - regmap_write(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, command); - ret = regmap_read_poll_timeout(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, + regmap_write(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, command); + ret = regmap_read_poll_timeout(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, val, (val == 0), CS35L56_MBOX_POLL_US, CS35L56_MBOX_TIMEOUT_US); if (ret) { - dev_warn(cs35l56->dev, "MBOX command %#x failed: %d\n", command, ret); + dev_warn(cs35l56_base->dev, "MBOX command %#x failed: %d\n", command, ret); return ret; } @@ -174,25 +174,25 @@ static int cs35l56_play_event(struct snd_soc_dapm_widget *w, unsigned int val; int ret; - dev_dbg(cs35l56->dev, "play: %d\n", event); + dev_dbg(cs35l56->base.dev, "play: %d\n", event); switch (event) { case SND_SOC_DAPM_PRE_PMU: /* Don't wait for ACK, we check in POST_PMU that it completed */ - return regmap_write(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, + return regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_AUDIO_PLAY); case SND_SOC_DAPM_POST_PMU: /* Wait for firmware to enter PS0 power state */ - ret = regmap_read_poll_timeout(cs35l56->regmap, + ret = regmap_read_poll_timeout(cs35l56->base.regmap, CS35L56_TRANSDUCER_ACTUAL_PS, val, (val == CS35L56_PS0), CS35L56_PS0_POLL_US, CS35L56_PS0_TIMEOUT_US); if (ret) - dev_err(cs35l56->dev, "PS0 wait failed: %d\n", ret); + dev_err(cs35l56->base.dev, "PS0 wait failed: %d\n", ret); return ret; case SND_SOC_DAPM_POST_PMD: - return cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_AUDIO_PAUSE); + return cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PAUSE); default: return 0; } @@ -310,14 +310,14 @@ static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); - dev_dbg(cs35l56->dev, "%s: %d\n", __func__, event); + dev_dbg(cs35l56->base.dev, "%s: %d\n", __func__, event); return wm_adsp_event(w, kcontrol, event); } irqreturn_t cs35l56_irq(int irq, void *data) { - struct cs35l56_private *cs35l56 = data; + struct cs35l56_base *cs35l56_base = data; unsigned int status1 = 0, status8 = 0, status20 = 0; unsigned int mask1, mask8, mask20; unsigned int val; @@ -325,77 +325,77 @@ irqreturn_t cs35l56_irq(int irq, void *data) irqreturn_t ret = IRQ_NONE; - if (!cs35l56->init_done) + if (!cs35l56_base->init_done) return IRQ_NONE; - mutex_lock(&cs35l56->irq_lock); + mutex_lock(&cs35l56_base->irq_lock); - rv = pm_runtime_resume_and_get(cs35l56->dev); + rv = pm_runtime_resume_and_get(cs35l56_base->dev); if (rv < 0) { - dev_err(cs35l56->dev, "irq: failed to get pm_runtime: %d\n", rv); + dev_err(cs35l56_base->dev, "irq: failed to get pm_runtime: %d\n", rv); goto err_unlock; } - regmap_read(cs35l56->regmap, CS35L56_IRQ1_STATUS, &val); + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val); if ((val & CS35L56_IRQ1_STS_MASK) == 0) { - dev_dbg(cs35l56->dev, "Spurious IRQ: no pending interrupt\n"); + dev_dbg(cs35l56_base->dev, "Spurious IRQ: no pending interrupt\n"); goto err; } /* Ack interrupts */ - regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_1, &status1); - regmap_read(cs35l56->regmap, CS35L56_IRQ1_MASK_1, &mask1); + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, &status1); + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_1, &mask1); status1 &= ~mask1; - regmap_write(cs35l56->regmap, CS35L56_IRQ1_EINT_1, status1); + regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, status1); - regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_8, &status8); - regmap_read(cs35l56->regmap, CS35L56_IRQ1_MASK_8, &mask8); + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, &status8); + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_8, &mask8); status8 &= ~mask8; - regmap_write(cs35l56->regmap, CS35L56_IRQ1_EINT_8, status8); + regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, status8); - regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_20, &status20); - regmap_read(cs35l56->regmap, CS35L56_IRQ1_MASK_20, &mask20); + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_20, &status20); + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, &mask20); status20 &= ~mask20; /* We don't want EINT20 but they default to unmasked: force mask */ - regmap_write(cs35l56->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff); + regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff); - dev_dbg(cs35l56->dev, "%s: %#x %#x\n", __func__, status1, status8); + dev_dbg(cs35l56_base->dev, "%s: %#x %#x\n", __func__, status1, status8); /* Check to see if unmasked bits are active */ if (!status1 && !status8 && !status20) goto err; if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK) - dev_crit(cs35l56->dev, "Amp short error\n"); + dev_crit(cs35l56_base->dev, "Amp short error\n"); if (status8 & CS35L56_TEMP_ERR_EINT1_MASK) - dev_crit(cs35l56->dev, "Overtemp error\n"); + dev_crit(cs35l56_base->dev, "Overtemp error\n"); ret = IRQ_HANDLED; err: - pm_runtime_put(cs35l56->dev); + pm_runtime_put(cs35l56_base->dev); err_unlock: - mutex_unlock(&cs35l56->irq_lock); + mutex_unlock(&cs35l56_base->irq_lock); return ret; } EXPORT_SYMBOL_NS_GPL(cs35l56_irq, SND_SOC_CS35L56_CORE); -int cs35l56_irq_request(struct cs35l56_private *cs35l56, int irq) +int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq) { int ret; if (!irq) return 0; - ret = devm_request_threaded_irq(cs35l56->dev, irq, NULL, cs35l56_irq, + ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq, IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW, - "cs35l56", cs35l56); + "cs35l56", cs35l56_base); if (!ret) - cs35l56->irq = irq; + cs35l56_base->irq = irq; else - dev_err(cs35l56->dev, "Failed to get IRQ: %d\n", ret); + dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n", ret); return ret; } @@ -406,13 +406,13 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(codec_dai->component); unsigned int val; - dev_dbg(cs35l56->dev, "%s: %#x\n", __func__, fmt); + dev_dbg(cs35l56->base.dev, "%s: %#x\n", __func__, fmt); switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { case SND_SOC_DAIFMT_CBC_CFC: break; default: - dev_err(cs35l56->dev, "Unsupported clock source mode\n"); + dev_err(cs35l56->base.dev, "Unsupported clock source mode\n"); return -EINVAL; } @@ -426,7 +426,7 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f cs35l56->tdm_mode = false; break; default: - dev_err(cs35l56->dev, "Unsupported DAI format\n"); + dev_err(cs35l56->base.dev, "Unsupported DAI format\n"); return -EINVAL; } @@ -443,18 +443,18 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f case SND_SOC_DAIFMT_NB_NF: break; default: - dev_err(cs35l56->dev, "Invalid clock invert\n"); + dev_err(cs35l56->base.dev, "Invalid clock invert\n"); return -EINVAL; } - regmap_update_bits(cs35l56->regmap, + regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL2, CS35L56_ASP_FMT_MASK | CS35L56_ASP_BCLK_INV_MASK | CS35L56_ASP_FSYNC_INV_MASK, val); /* Hi-Z DOUT in unused slots and when all TX are disabled */ - regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL3, + regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL3, CS35L56_ASP1_DOUT_HIZ_CTRL_MASK, CS35L56_ASP_UNUSED_HIZ_OFF_HIZ); @@ -485,7 +485,7 @@ static void cs35l56_set_asp_slot_positions(struct cs35l56_private *cs35l56, channel_shift += 8; } - regmap_write(cs35l56->regmap, reg, reg_val); + regmap_write(cs35l56->base.regmap, reg, reg_val); } static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, @@ -494,20 +494,20 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component); if ((slots == 0) || (slot_width == 0)) { - dev_dbg(cs35l56->dev, "tdm config cleared\n"); + dev_dbg(cs35l56->base.dev, "tdm config cleared\n"); cs35l56->asp_slot_width = 0; cs35l56->asp_slot_count = 0; return 0; } if (slot_width > (CS35L56_ASP_RX_WIDTH_MASK >> CS35L56_ASP_RX_WIDTH_SHIFT)) { - dev_err(cs35l56->dev, "tdm invalid slot width %d\n", slot_width); + dev_err(cs35l56->base.dev, "tdm invalid slot width %d\n", slot_width); return -EINVAL; } /* More than 32 slots would give an unsupportable BCLK frequency */ if (slots > 32) { - dev_err(cs35l56->dev, "tdm invalid slot count %d\n", slots); + dev_err(cs35l56->base.dev, "tdm invalid slot count %d\n", slots); return -EINVAL; } @@ -524,7 +524,7 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx cs35l56_set_asp_slot_positions(cs35l56, CS35L56_ASP1_FRAME_CONTROL1, rx_mask); cs35l56_set_asp_slot_positions(cs35l56, CS35L56_ASP1_FRAME_CONTROL5, tx_mask); - dev_dbg(cs35l56->dev, "tdm slot width: %u count: %u tx_mask: %#x rx_mask: %#x\n", + dev_dbg(cs35l56->base.dev, "tdm slot width: %u count: %u tx_mask: %#x rx_mask: %#x\n", cs35l56->asp_slot_width, cs35l56->asp_slot_count, tx_mask, rx_mask); return 0; @@ -544,7 +544,8 @@ static int cs35l56_asp_dai_hw_params(struct snd_pcm_substream *substream, else asp_width = asp_wl; - dev_dbg(cs35l56->dev, "%s: wl=%d, width=%d, rate=%d", __func__, asp_wl, asp_width, rate); + dev_dbg(cs35l56->base.dev, "%s: wl=%d, width=%d, rate=%d", + __func__, asp_wl, asp_width, rate); if (!cs35l56->sysclk_set) { unsigned int slots = cs35l56->asp_slot_count; @@ -562,26 +563,26 @@ static int cs35l56_asp_dai_hw_params(struct snd_pcm_substream *substream, bclk_freq = asp_width * slots * rate; freq_id = cs35l56_get_bclk_freq_id(bclk_freq); if (freq_id < 0) { - dev_err(cs35l56->dev, "%s: Invalid BCLK %u\n", __func__, bclk_freq); + dev_err(cs35l56->base.dev, "%s: Invalid BCLK %u\n", __func__, bclk_freq); return -EINVAL; } - regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL1, + regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL1, CS35L56_ASP_BCLK_FREQ_MASK, freq_id << CS35L56_ASP_BCLK_FREQ_SHIFT); } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL2, + regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL2, CS35L56_ASP_RX_WIDTH_MASK, asp_width << CS35L56_ASP_RX_WIDTH_SHIFT); - regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_DATA_CONTROL5, + regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_DATA_CONTROL5, CS35L56_ASP_RX_WL_MASK, asp_wl); } else { - regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL2, + regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL2, CS35L56_ASP_TX_WIDTH_MASK, asp_width << CS35L56_ASP_TX_WIDTH_SHIFT); - regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_DATA_CONTROL1, + regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_DATA_CONTROL1, CS35L56_ASP_TX_WL_MASK, asp_wl); } @@ -603,7 +604,7 @@ static int cs35l56_asp_dai_set_sysclk(struct snd_soc_dai *dai, if (freq_id < 0) return freq_id; - regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL1, + regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL1, CS35L56_ASP_BCLK_FREQ_MASK, freq_id << CS35L56_ASP_BCLK_FREQ_SHIFT); cs35l56->sysclk_set = true; @@ -646,9 +647,9 @@ static int cs35l56_sdw_dai_hw_params(struct snd_pcm_substream *substream, struct sdw_port_config pconfig; int ret; - dev_dbg(cs35l56->dev, "%s: rate %d\n", __func__, params_rate(params)); + dev_dbg(cs35l56->base.dev, "%s: rate %d\n", __func__, params_rate(params)); - if (!cs35l56->init_done) + if (!cs35l56->base.init_done) return -ENODEV; if (!sdw_stream) @@ -761,30 +762,30 @@ static struct snd_soc_dai_driver cs35l56_dai[] = { } }; -static int cs35l56_wait_for_firmware_boot(struct cs35l56_private *cs35l56) +static int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base) { unsigned int reg; unsigned int val; int ret; - if (cs35l56->rev < CS35L56_REVID_B0) + if (cs35l56_base->rev < CS35L56_REVID_B0) reg = CS35L56_DSP1_HALO_STATE_A1; else reg = CS35L56_DSP1_HALO_STATE; - ret = regmap_read_poll_timeout(cs35l56->regmap, reg, + ret = regmap_read_poll_timeout(cs35l56_base->regmap, reg, val, (val < 0xFFFF) && (val >= CS35L56_HALO_STATE_BOOT_DONE), CS35L56_HALO_STATE_POLL_US, CS35L56_HALO_STATE_TIMEOUT_US); if ((ret < 0) && (ret != -ETIMEDOUT)) { - dev_err(cs35l56->dev, "Failed to read HALO_STATE: %d\n", ret); + dev_err(cs35l56_base->dev, "Failed to read HALO_STATE: %d\n", ret); return ret; } if ((ret == -ETIMEDOUT) || (val != CS35L56_HALO_STATE_BOOT_DONE)) { - dev_err(cs35l56->dev, "Firmware boot fail: HALO_STATE=%#x\n", val); + dev_err(cs35l56_base->dev, "Firmware boot fail: HALO_STATE=%#x\n", val); return -EIO; } @@ -809,8 +810,8 @@ static void cs35l56_system_reset(struct cs35l56_private *cs35l56) * Must enter cache-only first so there can't be any more register * accesses other than the controlled system reset sequence below. */ - regcache_cache_only(cs35l56->regmap, true); - regmap_multi_reg_write_bypassed(cs35l56->regmap, + regcache_cache_only(cs35l56->base.regmap, true); + regmap_multi_reg_write_bypassed(cs35l56->base.regmap, cs35l56_system_reset_seq, ARRAY_SIZE(cs35l56_system_reset_seq)); @@ -819,7 +820,7 @@ static void cs35l56_system_reset(struct cs35l56_private *cs35l56) return; usleep_range(CS35L56_CONTROL_PORT_READY_US, CS35L56_CONTROL_PORT_READY_US + 400); - regcache_cache_only(cs35l56->regmap, false); + regcache_cache_only(cs35l56->base.regmap, false); } static void cs35l56_secure_patch(struct cs35l56_private *cs35l56) @@ -829,9 +830,9 @@ static void cs35l56_secure_patch(struct cs35l56_private *cs35l56) /* Use wm_adsp to load and apply the firmware patch and coefficient files */ ret = wm_adsp_power_up(&cs35l56->dsp); if (ret) - dev_dbg(cs35l56->dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret); + dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret); else - cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_AUDIO_REINIT); + cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT); } static void cs35l56_patch(struct cs35l56_private *cs35l56) @@ -854,31 +855,31 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56) flush_work(&cs35l56->sdw_irq_work); } - ret = cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_SHUTDOWN); + ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_SHUTDOWN); if (ret) goto err; - if (cs35l56->rev < CS35L56_REVID_B0) + if (cs35l56->base.rev < CS35L56_REVID_B0) reg = CS35L56_DSP1_PM_CUR_STATE_A1; else reg = CS35L56_DSP1_PM_CUR_STATE; - ret = regmap_read_poll_timeout(cs35l56->regmap, reg, + ret = regmap_read_poll_timeout(cs35l56->base.regmap, reg, val, (val == CS35L56_HALO_STATE_SHUTDOWN), CS35L56_HALO_STATE_POLL_US, CS35L56_HALO_STATE_TIMEOUT_US); if (ret < 0) - dev_err(cs35l56->dev, "Failed to poll PM_CUR_STATE to 1 is %d (ret %d)\n", + dev_err(cs35l56->base.dev, "Failed to poll PM_CUR_STATE to 1 is %d (ret %d)\n", val, ret); /* Use wm_adsp to load and apply the firmware patch and coefficient files */ ret = wm_adsp_power_up(&cs35l56->dsp); if (ret) { - dev_dbg(cs35l56->dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret); + dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret); goto err; } - mutex_lock(&cs35l56->irq_lock); + mutex_lock(&cs35l56->base.irq_lock); init_completion(&cs35l56->init_completion); @@ -892,18 +893,20 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56) */ if (!wait_for_completion_timeout(&cs35l56->init_completion, msecs_to_jiffies(5000))) { - dev_err(cs35l56->dev, "%s: init_completion timed out (SDW)\n", __func__); + dev_err(cs35l56->base.dev, "%s: init_completion timed out (SDW)\n", + __func__); goto err_unlock; } } else if (cs35l56_init(cs35l56)) { goto err_unlock; } - regmap_clear_bits(cs35l56->regmap, CS35L56_PROTECTION_STATUS, CS35L56_FIRMWARE_MISSING); - cs35l56->fw_patched = true; + regmap_clear_bits(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, + CS35L56_FIRMWARE_MISSING); + cs35l56->base.fw_patched = true; err_unlock: - mutex_unlock(&cs35l56->irq_lock); + mutex_unlock(&cs35l56->base.irq_lock); err: /* Re-enable SoundWire interrupts */ if (cs35l56->sdw_peripheral) { @@ -919,10 +922,10 @@ static void cs35l56_dsp_work(struct work_struct *work) struct cs35l56_private, dsp_work); - if (!cs35l56->init_done) + if (!cs35l56->base.init_done) return; - pm_runtime_get_sync(cs35l56->dev); + pm_runtime_get_sync(cs35l56->base.dev); /* * When the device is running in secure mode the firmware files can @@ -930,13 +933,13 @@ static void cs35l56_dsp_work(struct work_struct *work) * shutdown the firmware to apply them and can use the lower cost * reinit sequence instead. */ - if (cs35l56->secured) + if (cs35l56->base.secured) cs35l56_secure_patch(cs35l56); else cs35l56_patch(cs35l56); - pm_runtime_mark_last_busy(cs35l56->dev); - pm_runtime_put_autosuspend(cs35l56->dev); + pm_runtime_mark_last_busy(cs35l56->base.dev); + pm_runtime_put_autosuspend(cs35l56->base.dev); } static int cs35l56_component_probe(struct snd_soc_component *component) @@ -948,16 +951,16 @@ static int cs35l56_component_probe(struct snd_soc_component *component) if (!wait_for_completion_timeout(&cs35l56->init_completion, msecs_to_jiffies(5000))) { - dev_err(cs35l56->dev, "%s: init_completion timed out\n", __func__); + dev_err(cs35l56->base.dev, "%s: init_completion timed out\n", __func__); return -ENODEV; } cs35l56->component = component; wm_adsp2_component_probe(&cs35l56->dsp, component); - debugfs_create_bool("init_done", 0444, debugfs_root, &cs35l56->init_done); - debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->can_hibernate); - debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->fw_patched); + debugfs_create_bool("init_done", 0444, debugfs_root, &cs35l56->base.init_done); + debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->base.can_hibernate); + debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->base.fw_patched); queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work); @@ -1024,23 +1027,23 @@ int cs35l56_runtime_suspend(struct device *dev) unsigned int val; int ret; - if (!cs35l56->init_done) + if (!cs35l56->base.init_done) return 0; /* Firmware must have entered a power-save state */ - ret = regmap_read_poll_timeout(cs35l56->regmap, + ret = regmap_read_poll_timeout(cs35l56->base.regmap, CS35L56_TRANSDUCER_ACTUAL_PS, val, (val >= CS35L56_PS3), CS35L56_PS3_POLL_US, CS35L56_PS3_TIMEOUT_US); if (ret) - dev_warn(cs35l56->dev, "PS3 wait failed: %d\n", ret); + dev_warn(cs35l56->base.dev, "PS3 wait failed: %d\n", ret); /* Clear BOOT_DONE so it can be used to detect a reboot */ - regmap_write(cs35l56->regmap, CS35L56_IRQ1_EINT_4, CS35L56_OTP_BOOT_DONE_MASK); + regmap_write(cs35l56->base.regmap, CS35L56_IRQ1_EINT_4, CS35L56_OTP_BOOT_DONE_MASK); - if (!cs35l56->can_hibernate) { - regcache_cache_only(cs35l56->regmap, true); + if (!cs35l56->base.can_hibernate) { + regcache_cache_only(cs35l56->base.regmap, true); dev_dbg(dev, "Suspended: no hibernate"); return 0; @@ -1050,15 +1053,15 @@ int cs35l56_runtime_suspend(struct device *dev) * Enable auto-hibernate. If it is woken by some other wake source * it will automatically return to hibernate. */ - cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE); + cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE); /* * Must enter cache-only first so there can't be any more register * accesses other than the controlled hibernate sequence below. */ - regcache_cache_only(cs35l56->regmap, true); + regcache_cache_only(cs35l56->base.regmap, true); - regmap_multi_reg_write_bypassed(cs35l56->regmap, + regmap_multi_reg_write_bypassed(cs35l56->base.regmap, cs35l56_hibernate_seq, ARRAY_SIZE(cs35l56_hibernate_seq)); @@ -1072,7 +1075,7 @@ static int __maybe_unused cs35l56_runtime_resume_i2c_spi(struct device *dev) { struct cs35l56_private *cs35l56 = dev_get_drvdata(dev); - if (!cs35l56->init_done) + if (!cs35l56->base.init_done) return 0; return cs35l56_runtime_resume_common(cs35l56); @@ -1083,7 +1086,7 @@ int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56) unsigned int val; int ret; - if (!cs35l56->can_hibernate) + if (!cs35l56->base.can_hibernate) goto out_sync; if (!cs35l56->sdw_peripheral) { @@ -1091,7 +1094,7 @@ int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56) * Dummy transaction to trigger I2C/SPI auto-wake. This will NAK on I2C. * Must be done before releasing cache-only. */ - regmap_multi_reg_write_bypassed(cs35l56->regmap, + regmap_multi_reg_write_bypassed(cs35l56->base.regmap, cs35l56_hibernate_wake_seq, ARRAY_SIZE(cs35l56_hibernate_wake_seq)); @@ -1100,36 +1103,36 @@ int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56) } out_sync: - regcache_cache_only(cs35l56->regmap, false); + regcache_cache_only(cs35l56->base.regmap, false); - ret = cs35l56_wait_for_firmware_boot(cs35l56); + ret = cs35l56_wait_for_firmware_boot(&cs35l56->base); if (ret) { - dev_err(cs35l56->dev, "Hibernate wake failed: %d\n", ret); + dev_err(cs35l56->base.dev, "Hibernate wake failed: %d\n", ret); goto err; } - ret = cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE); + ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE); if (ret) goto err; /* BOOT_DONE will be 1 if the amp reset */ - regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_4, &val); + regmap_read(cs35l56->base.regmap, CS35L56_IRQ1_EINT_4, &val); if (val & CS35L56_OTP_BOOT_DONE_MASK) { - dev_dbg(cs35l56->dev, "Registers reset in suspend\n"); - regcache_mark_dirty(cs35l56->regmap); + dev_dbg(cs35l56->base.dev, "Registers reset in suspend\n"); + regcache_mark_dirty(cs35l56->base.regmap); } - regcache_sync(cs35l56->regmap); + regcache_sync(cs35l56->base.regmap); - dev_dbg(cs35l56->dev, "Resumed"); + dev_dbg(cs35l56->base.dev, "Resumed"); return 0; err: - regmap_write(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, + regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_HIBERNATE_NOW); - regcache_cache_only(cs35l56->regmap, true); + regcache_cache_only(cs35l56->base.regmap, true); return ret; } @@ -1141,14 +1144,14 @@ static int cs35l56_is_fw_reload_needed(struct cs35l56_private *cs35l56) int ret; /* Nothing to re-patch if we haven't done any patching yet. */ - if (!cs35l56->fw_patched) + if (!cs35l56->base.fw_patched) return false; /* * If we have control of RESET we will have asserted it so the firmware * will need re-patching. */ - if (cs35l56->reset_gpio) + if (cs35l56->base.reset_gpio) return true; /* @@ -1156,22 +1159,22 @@ static int cs35l56_is_fw_reload_needed(struct cs35l56_private *cs35l56) * can't be used here to test for memory retention. * Assume that tuning must be re-loaded. */ - if (cs35l56->secured) + if (cs35l56->base.secured) return true; - ret = pm_runtime_resume_and_get(cs35l56->dev); + ret = pm_runtime_resume_and_get(cs35l56->base.dev); if (ret) { - dev_err(cs35l56->dev, "Failed to runtime_get: %d\n", ret); + dev_err(cs35l56->base.dev, "Failed to runtime_get: %d\n", ret); return ret; } - ret = regmap_read(cs35l56->regmap, CS35L56_PROTECTION_STATUS, &val); + ret = regmap_read(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, &val); if (ret) - dev_err(cs35l56->dev, "Failed to read PROTECTION_STATUS: %d\n", ret); + dev_err(cs35l56->base.dev, "Failed to read PROTECTION_STATUS: %d\n", ret); else ret = !!(val & CS35L56_FIRMWARE_MISSING); - pm_runtime_put_autosuspend(cs35l56->dev); + pm_runtime_put_autosuspend(cs35l56->base.dev); return ret; } @@ -1191,8 +1194,8 @@ int cs35l56_system_suspend(struct device *dev) * clear it. Prevent this race by temporarily disabling the parent irq * until we reach _no_irq. */ - if (cs35l56->irq) - disable_irq(cs35l56->irq); + if (cs35l56->base.irq) + disable_irq(cs35l56->base.irq); return pm_runtime_force_suspend(dev); } @@ -1209,8 +1212,8 @@ int cs35l56_system_suspend_late(struct device *dev) * RESET is usually shared by all amps so it must not be asserted until * all driver instances have done their suspend() stage. */ - if (cs35l56->reset_gpio) { - gpiod_set_value_cansleep(cs35l56->reset_gpio, 0); + if (cs35l56->base.reset_gpio) { + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); cs35l56_wait_min_reset_pulse(); } @@ -1227,8 +1230,8 @@ int cs35l56_system_suspend_no_irq(struct device *dev) dev_dbg(dev, "system_suspend_no_irq\n"); /* Handlers are now disabled so the parent IRQ can safely be re-enabled. */ - if (cs35l56->irq) - enable_irq(cs35l56->irq); + if (cs35l56->base.irq) + enable_irq(cs35l56->base.irq); return 0; } @@ -1247,8 +1250,8 @@ int cs35l56_system_resume_no_irq(struct device *dev) * clear it, until it has fully resumed. Prevent this race by temporarily * disabling the parent irq until we complete resume(). */ - if (cs35l56->irq) - disable_irq(cs35l56->irq); + if (cs35l56->base.irq) + disable_irq(cs35l56->base.irq); return 0; } @@ -1262,8 +1265,8 @@ int cs35l56_system_resume_early(struct device *dev) dev_dbg(dev, "system_resume_early\n"); /* Ensure a spec-compliant RESET pulse. */ - if (cs35l56->reset_gpio) { - gpiod_set_value_cansleep(cs35l56->reset_gpio, 0); + if (cs35l56->base.reset_gpio) { + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); cs35l56_wait_min_reset_pulse(); } @@ -1275,7 +1278,7 @@ int cs35l56_system_resume_early(struct device *dev) } /* Release shared RESET before drivers start resume(). */ - gpiod_set_value_cansleep(cs35l56->reset_gpio, 1); + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1); return 0; } @@ -1290,8 +1293,8 @@ int cs35l56_system_resume(struct device *dev) /* Undo pm_runtime_force_suspend() before re-enabling the irq */ ret = pm_runtime_force_resume(dev); - if (cs35l56->irq) - enable_irq(cs35l56->irq); + if (cs35l56->base.irq) + enable_irq(cs35l56->base.irq); if (ret) return ret; @@ -1301,11 +1304,11 @@ int cs35l56_system_resume(struct device *dev) return 0; ret = cs35l56_is_fw_reload_needed(cs35l56); - dev_dbg(cs35l56->dev, "fw_reload_needed: %d\n", ret); + dev_dbg(cs35l56->base.dev, "fw_reload_needed: %d\n", ret); if (ret < 1) return ret; - cs35l56->fw_patched = false; + cs35l56->base.fw_patched = false; queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work); /* @@ -1334,8 +1337,8 @@ static int cs35l56_dsp_init(struct cs35l56_private *cs35l56) dsp->cs_dsp.type = WMFW_HALO; dsp->cs_dsp.rev = 0; dsp->fw = 12; - dsp->cs_dsp.dev = cs35l56->dev; - dsp->cs_dsp.regmap = cs35l56->regmap; + dsp->cs_dsp.dev = cs35l56->base.dev; + dsp->cs_dsp.regmap = cs35l56->base.regmap; dsp->cs_dsp.base = CS35L56_DSP1_CORE_BASE; dsp->cs_dsp.base_sysinfo = CS35L56_DSP1_SYS_INFO_ID; dsp->cs_dsp.mem = cs35l56_dsp1_regions; @@ -1343,11 +1346,11 @@ static int cs35l56_dsp_init(struct cs35l56_private *cs35l56) dsp->cs_dsp.no_core_startstop = true; dsp->wmfw_optional = true; - dev_dbg(cs35l56->dev, "DSP system name: '%s'\n", dsp->system_name); + dev_dbg(cs35l56->base.dev, "DSP system name: '%s'\n", dsp->system_name); ret = wm_halo_init(dsp); if (ret != 0) { - dev_err(cs35l56->dev, "wm_halo_init failed\n"); + dev_err(cs35l56->base.dev, "wm_halo_init failed\n"); return ret; } @@ -1356,7 +1359,7 @@ static int cs35l56_dsp_init(struct cs35l56_private *cs35l56) static int cs35l56_acpi_get_name(struct cs35l56_private *cs35l56) { - acpi_handle handle = ACPI_HANDLE(cs35l56->dev); + acpi_handle handle = ACPI_HANDLE(cs35l56->base.dev); const char *sub; /* If there is no ACPI_HANDLE, there is no ACPI for this system, return 0 */ @@ -1373,7 +1376,7 @@ static int cs35l56_acpi_get_name(struct cs35l56_private *cs35l56) } cs35l56->dsp.system_name = sub; - dev_dbg(cs35l56->dev, "Subsystem ID: %s\n", cs35l56->dsp.system_name); + dev_dbg(cs35l56->base.dev, "Subsystem ID: %s\n", cs35l56->dsp.system_name); return 0; } @@ -1383,38 +1386,39 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56) int ret; init_completion(&cs35l56->init_completion); - mutex_init(&cs35l56->irq_lock); + mutex_init(&cs35l56->base.irq_lock); - dev_set_drvdata(cs35l56->dev, cs35l56); + dev_set_drvdata(cs35l56->base.dev, cs35l56); cs35l56_fill_supply_names(cs35l56->supplies); - ret = devm_regulator_bulk_get(cs35l56->dev, ARRAY_SIZE(cs35l56->supplies), + ret = devm_regulator_bulk_get(cs35l56->base.dev, ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies); if (ret != 0) - return dev_err_probe(cs35l56->dev, ret, "Failed to request supplies\n"); + return dev_err_probe(cs35l56->base.dev, ret, "Failed to request supplies\n"); /* Reset could be controlled by the BIOS or shared by multiple amps */ - cs35l56->reset_gpio = devm_gpiod_get_optional(cs35l56->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(cs35l56->reset_gpio)) { - ret = PTR_ERR(cs35l56->reset_gpio); + cs35l56->base.reset_gpio = devm_gpiod_get_optional(cs35l56->base.dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(cs35l56->base.reset_gpio)) { + ret = PTR_ERR(cs35l56->base.reset_gpio); /* * If RESET is shared the first amp to probe will grab the reset * line and reset all the amps */ if (ret != -EBUSY) - return dev_err_probe(cs35l56->dev, ret, "Failed to get reset GPIO\n"); + return dev_err_probe(cs35l56->base.dev, ret, "Failed to get reset GPIO\n"); - dev_info(cs35l56->dev, "Reset GPIO busy, assume shared reset\n"); - cs35l56->reset_gpio = NULL; + dev_info(cs35l56->base.dev, "Reset GPIO busy, assume shared reset\n"); + cs35l56->base.reset_gpio = NULL; } ret = regulator_bulk_enable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies); if (ret != 0) - return dev_err_probe(cs35l56->dev, ret, "Failed to enable supplies\n"); + return dev_err_probe(cs35l56->base.dev, ret, "Failed to enable supplies\n"); - if (cs35l56->reset_gpio) { + if (cs35l56->base.reset_gpio) { cs35l56_wait_min_reset_pulse(); - gpiod_set_value_cansleep(cs35l56->reset_gpio, 1); + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1); } ret = cs35l56_acpi_get_name(cs35l56); @@ -1423,22 +1427,22 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56) ret = cs35l56_dsp_init(cs35l56); if (ret < 0) { - dev_err_probe(cs35l56->dev, ret, "DSP init failed\n"); + dev_err_probe(cs35l56->base.dev, ret, "DSP init failed\n"); goto err; } - ret = devm_snd_soc_register_component(cs35l56->dev, + ret = devm_snd_soc_register_component(cs35l56->base.dev, &soc_component_dev_cs35l56, cs35l56_dai, ARRAY_SIZE(cs35l56_dai)); if (ret < 0) { - dev_err_probe(cs35l56->dev, ret, "Register codec failed\n"); + dev_err_probe(cs35l56->base.dev, ret, "Register codec failed\n"); goto err; } return 0; err: - gpiod_set_value_cansleep(cs35l56->reset_gpio, 0); + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies); return ret; @@ -1457,20 +1461,20 @@ int cs35l56_init(struct cs35l56_private *cs35l56) if (cs35l56->soft_resetting) goto post_soft_reset; - if (cs35l56->init_done) + if (cs35l56->base.init_done) return 0; - pm_runtime_set_autosuspend_delay(cs35l56->dev, 100); - pm_runtime_use_autosuspend(cs35l56->dev); - pm_runtime_set_active(cs35l56->dev); - pm_runtime_enable(cs35l56->dev); + pm_runtime_set_autosuspend_delay(cs35l56->base.dev, 100); + pm_runtime_use_autosuspend(cs35l56->base.dev); + pm_runtime_set_active(cs35l56->base.dev); + pm_runtime_enable(cs35l56->base.dev); /* * If the system is not using a reset_gpio then issue a * dummy read to force a wakeup. */ - if (!cs35l56->reset_gpio) - regmap_read(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, &devid); + if (!cs35l56->base.reset_gpio) + regmap_read(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, &devid); /* Wait for control port to be ready (datasheet tIRS). */ usleep_range(CS35L56_CONTROL_PORT_READY_US, @@ -1481,20 +1485,20 @@ int cs35l56_init(struct cs35l56_private *cs35l56) * devices so the REVID needs to be determined before waiting for the * firmware to boot. */ - ret = regmap_read(cs35l56->regmap, CS35L56_REVID, &revid); + ret = regmap_read(cs35l56->base.regmap, CS35L56_REVID, &revid); if (ret < 0) { - dev_err(cs35l56->dev, "Get Revision ID failed\n"); + dev_err(cs35l56->base.dev, "Get Revision ID failed\n"); return ret; } - cs35l56->rev = revid & (CS35L56_AREVID_MASK | CS35L56_MTLREVID_MASK); + cs35l56->base.rev = revid & (CS35L56_AREVID_MASK | CS35L56_MTLREVID_MASK); - ret = cs35l56_wait_for_firmware_boot(cs35l56); + ret = cs35l56_wait_for_firmware_boot(&cs35l56->base); if (ret) return ret; - ret = regmap_read(cs35l56->regmap, CS35L56_DEVID, &devid); + ret = regmap_read(cs35l56->base.regmap, CS35L56_DEVID, &devid); if (ret < 0) { - dev_err(cs35l56->dev, "Get Device ID failed\n"); + dev_err(cs35l56->base.dev, "Get Device ID failed\n"); return ret; } devid &= CS35L56_DEVID_MASK; @@ -1503,50 +1507,50 @@ int cs35l56_init(struct cs35l56_private *cs35l56) case 0x35A56: break; default: - dev_err(cs35l56->dev, "Unknown device %x\n", devid); + dev_err(cs35l56->base.dev, "Unknown device %x\n", devid); return ret; } - ret = regmap_read(cs35l56->regmap, CS35L56_DSP_RESTRICT_STS1, &secured); + ret = regmap_read(cs35l56->base.regmap, CS35L56_DSP_RESTRICT_STS1, &secured); if (ret) { - dev_err(cs35l56->dev, "Get Secure status failed\n"); + dev_err(cs35l56->base.dev, "Get Secure status failed\n"); return ret; } /* When any bus is restricted treat the device as secured */ if (secured & CS35L56_RESTRICTED_MASK) - cs35l56->secured = true; + cs35l56->base.secured = true; - ret = regmap_read(cs35l56->regmap, CS35L56_OTPID, &otpid); + ret = regmap_read(cs35l56->base.regmap, CS35L56_OTPID, &otpid); if (ret < 0) { - dev_err(cs35l56->dev, "Get OTP ID failed\n"); + dev_err(cs35l56->base.dev, "Get OTP ID failed\n"); return ret; } - dev_info(cs35l56->dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d\n", - cs35l56->secured ? "s" : "", cs35l56->rev, otpid); + dev_info(cs35l56->base.dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d\n", + cs35l56->base.secured ? "s" : "", cs35l56->base.rev, otpid); /* Populate the DSP information with the revision and security state */ - cs35l56->dsp.part = devm_kasprintf(cs35l56->dev, GFP_KERNEL, "cs35l56%s-%02x", - cs35l56->secured ? "s" : "", cs35l56->rev); + cs35l56->dsp.part = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, "cs35l56%s-%02x", + cs35l56->base.secured ? "s" : "", cs35l56->base.rev); if (!cs35l56->dsp.part) return -ENOMEM; /* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */ - regmap_write(cs35l56->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff); - regmap_update_bits(cs35l56->regmap, CS35L56_IRQ1_MASK_1, + regmap_write(cs35l56->base.regmap, CS35L56_IRQ1_MASK_20, 0xffffffff); + regmap_update_bits(cs35l56->base.regmap, CS35L56_IRQ1_MASK_1, CS35L56_AMP_SHORT_ERR_EINT1_MASK, 0); - regmap_update_bits(cs35l56->regmap, CS35L56_IRQ1_MASK_8, + regmap_update_bits(cs35l56->base.regmap, CS35L56_IRQ1_MASK_8, CS35L56_TEMP_ERR_EINT1_MASK, 0); - if (!cs35l56->reset_gpio) { - dev_dbg(cs35l56->dev, "No reset gpio: using soft reset\n"); + if (!cs35l56->base.reset_gpio) { + dev_dbg(cs35l56->base.dev, "No reset gpio: using soft reset\n"); cs35l56_system_reset(cs35l56); if (cs35l56->sdw_peripheral) { /* Keep alive while we wait for re-enumeration */ - pm_runtime_get_noresume(cs35l56->dev); + pm_runtime_get_noresume(cs35l56->base.dev); return 0; } } @@ -1556,30 +1560,30 @@ int cs35l56_init(struct cs35l56_private *cs35l56) cs35l56->soft_resetting = false; /* Done re-enumerating after one-time init so release the keep-alive */ - if (cs35l56->sdw_peripheral && !cs35l56->init_done) - pm_runtime_put_noidle(cs35l56->dev); + if (cs35l56->sdw_peripheral && !cs35l56->base.init_done) + pm_runtime_put_noidle(cs35l56->base.dev); - regcache_mark_dirty(cs35l56->regmap); - ret = cs35l56_wait_for_firmware_boot(cs35l56); + regcache_mark_dirty(cs35l56->base.regmap); + ret = cs35l56_wait_for_firmware_boot(&cs35l56->base); if (ret) return ret; - dev_dbg(cs35l56->dev, "Firmware rebooted after soft reset\n"); + dev_dbg(cs35l56->base.dev, "Firmware rebooted after soft reset\n"); } /* Disable auto-hibernate so that runtime_pm has control */ - ret = cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE); + ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE); if (ret) return ret; - ret = cs35l56_set_patch(cs35l56->regmap); + ret = cs35l56_set_patch(&cs35l56->base); if (ret) return ret; /* Registers could be dirty after soft reset or SoundWire enumeration */ - regcache_sync(cs35l56->regmap); + regcache_sync(cs35l56->base.regmap); - cs35l56->init_done = true; + cs35l56->base.init_done = true; complete(&cs35l56->init_completion); return 0; @@ -1588,26 +1592,26 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_init, SND_SOC_CS35L56_CORE); void cs35l56_remove(struct cs35l56_private *cs35l56) { - cs35l56->init_done = false; + cs35l56->base.init_done = false; /* * WAKE IRQs unmask if CS35L56 hibernates so free the handler to * prevent it racing with remove(). */ - if (cs35l56->irq) - devm_free_irq(cs35l56->dev, cs35l56->irq, cs35l56); + if (cs35l56->base.irq) + devm_free_irq(cs35l56->base.dev, cs35l56->base.irq, &cs35l56->base); flush_workqueue(cs35l56->dsp_wq); destroy_workqueue(cs35l56->dsp_wq); - pm_runtime_suspend(cs35l56->dev); - pm_runtime_disable(cs35l56->dev); + pm_runtime_suspend(cs35l56->base.dev); + pm_runtime_disable(cs35l56->base.dev); - regcache_cache_only(cs35l56->regmap, true); + regcache_cache_only(cs35l56->base.regmap, true); kfree(cs35l56->dsp.system_name); - gpiod_set_value_cansleep(cs35l56->reset_gpio, 0); + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies); } EXPORT_SYMBOL_NS_GPL(cs35l56_remove, SND_SOC_CS35L56_CORE); diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h index 1f7894662fcb..f39f8fa9e37e 100644 --- a/sound/soc/codecs/cs35l56.h +++ b/sound/soc/codecs/cs35l56.h @@ -32,26 +32,17 @@ struct sdw_slave; struct cs35l56_private { struct wm_adsp dsp; /* must be first member */ + struct cs35l56_base base; struct work_struct dsp_work; struct workqueue_struct *dsp_wq; - struct mutex irq_lock; struct snd_soc_component *component; - struct device *dev; - struct regmap *regmap; struct regulator_bulk_data supplies[CS35L56_NUM_BULK_SUPPLIES]; - int irq; struct sdw_slave *sdw_peripheral; - u8 rev; struct work_struct sdw_irq_work; - bool secured; bool sdw_irq_no_unmask; bool soft_resetting; - bool init_done; bool sdw_attached; - bool fw_patched; - bool can_hibernate; struct completion init_completion; - struct gpio_desc *reset_gpio; u32 rx_mask; u32 tx_mask; @@ -73,7 +64,7 @@ int cs35l56_system_resume_no_irq(struct device *dev); int cs35l56_system_resume_early(struct device *dev); int cs35l56_system_resume(struct device *dev); irqreturn_t cs35l56_irq(int irq, void *data); -int cs35l56_irq_request(struct cs35l56_private *cs35l56, int irq); +int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq); int cs35l56_common_probe(struct cs35l56_private *cs35l56); int cs35l56_init(struct cs35l56_private *cs35l56); void cs35l56_remove(struct cs35l56_private *cs35l56); From cf6e7486de80b680fe178a6517dd7c4166a12dbc Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Fri, 21 Jul 2023 14:21:11 +0100 Subject: [PATCH 225/334] ASoC: cs35l56: Make cs35l56_system_reset() code more generic The function can be more easily reused in HDA if the tracking of whether a soft reset is being performed and whether the device is connected to a SoundWire bus is moved out of the function. Signed-off-by: Simon Trimmer Signed-off-by: Richard Fitzgerald Acked-by: Mark Brown Link: https://lore.kernel.org/r/20230721132120.5523-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 4eb8e5b09bfd..7a83e388e869 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -802,10 +802,8 @@ static const struct reg_sequence cs35l56_system_reset_seq[] = { REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET), }; -static void cs35l56_system_reset(struct cs35l56_private *cs35l56) +static void cs35l56_system_reset(struct cs35l56_private *cs35l56, bool is_soundwire) { - cs35l56->soft_resetting = true; - /* * Must enter cache-only first so there can't be any more register * accesses other than the controlled system reset sequence below. @@ -816,7 +814,7 @@ static void cs35l56_system_reset(struct cs35l56_private *cs35l56) ARRAY_SIZE(cs35l56_system_reset_seq)); /* On SoundWire the registers won't be accessible until it re-enumerates. */ - if (cs35l56->sdw_peripheral) + if (is_soundwire) return; usleep_range(CS35L56_CONTROL_PORT_READY_US, CS35L56_CONTROL_PORT_READY_US + 400); @@ -883,7 +881,8 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56) init_completion(&cs35l56->init_completion); - cs35l56_system_reset(cs35l56); + cs35l56->soft_resetting = true; + cs35l56_system_reset(cs35l56, !!cs35l56->sdw_peripheral); if (cs35l56->sdw_peripheral) { /* @@ -1547,7 +1546,8 @@ int cs35l56_init(struct cs35l56_private *cs35l56) if (!cs35l56->base.reset_gpio) { dev_dbg(cs35l56->base.dev, "No reset gpio: using soft reset\n"); - cs35l56_system_reset(cs35l56); + cs35l56->soft_resetting = true; + cs35l56_system_reset(cs35l56, !!cs35l56->sdw_peripheral); if (cs35l56->sdw_peripheral) { /* Keep alive while we wait for re-enumeration */ pm_runtime_get_noresume(cs35l56->base.dev); From 0a2e49230f7f1796aa79c532426d56e8739ee4b1 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Fri, 21 Jul 2023 14:21:12 +0100 Subject: [PATCH 226/334] ASoC: cs35l56: Convert utility functions to use common data structure Use the new cs35l56_base struct for utility functions. Signed-off-by: Simon Trimmer Signed-off-by: Richard Fitzgerald Acked-by: Mark Brown Link: https://lore.kernel.org/r/20230721132120.5523-4-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 7a83e388e869..87e2f618850b 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -802,14 +802,14 @@ static const struct reg_sequence cs35l56_system_reset_seq[] = { REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET), }; -static void cs35l56_system_reset(struct cs35l56_private *cs35l56, bool is_soundwire) +static void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire) { /* * Must enter cache-only first so there can't be any more register * accesses other than the controlled system reset sequence below. */ - regcache_cache_only(cs35l56->base.regmap, true); - regmap_multi_reg_write_bypassed(cs35l56->base.regmap, + regcache_cache_only(cs35l56_base->regmap, true); + regmap_multi_reg_write_bypassed(cs35l56_base->regmap, cs35l56_system_reset_seq, ARRAY_SIZE(cs35l56_system_reset_seq)); @@ -818,7 +818,7 @@ static void cs35l56_system_reset(struct cs35l56_private *cs35l56, bool is_soundw return; usleep_range(CS35L56_CONTROL_PORT_READY_US, CS35L56_CONTROL_PORT_READY_US + 400); - regcache_cache_only(cs35l56->base.regmap, false); + regcache_cache_only(cs35l56_base->regmap, false); } static void cs35l56_secure_patch(struct cs35l56_private *cs35l56) @@ -882,7 +882,7 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56) init_completion(&cs35l56->init_completion); cs35l56->soft_resetting = true; - cs35l56_system_reset(cs35l56, !!cs35l56->sdw_peripheral); + cs35l56_system_reset(&cs35l56->base, !!cs35l56->sdw_peripheral); if (cs35l56->sdw_peripheral) { /* @@ -1137,20 +1137,20 @@ int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56) } EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, SND_SOC_CS35L56_CORE); -static int cs35l56_is_fw_reload_needed(struct cs35l56_private *cs35l56) +static int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base) { unsigned int val; int ret; /* Nothing to re-patch if we haven't done any patching yet. */ - if (!cs35l56->base.fw_patched) + if (!cs35l56_base->fw_patched) return false; /* * If we have control of RESET we will have asserted it so the firmware * will need re-patching. */ - if (cs35l56->base.reset_gpio) + if (cs35l56_base->reset_gpio) return true; /* @@ -1158,22 +1158,22 @@ static int cs35l56_is_fw_reload_needed(struct cs35l56_private *cs35l56) * can't be used here to test for memory retention. * Assume that tuning must be re-loaded. */ - if (cs35l56->base.secured) + if (cs35l56_base->secured) return true; - ret = pm_runtime_resume_and_get(cs35l56->base.dev); + ret = pm_runtime_resume_and_get(cs35l56_base->dev); if (ret) { - dev_err(cs35l56->base.dev, "Failed to runtime_get: %d\n", ret); + dev_err(cs35l56_base->dev, "Failed to runtime_get: %d\n", ret); return ret; } - ret = regmap_read(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, &val); + ret = regmap_read(cs35l56_base->regmap, CS35L56_PROTECTION_STATUS, &val); if (ret) - dev_err(cs35l56->base.dev, "Failed to read PROTECTION_STATUS: %d\n", ret); + dev_err(cs35l56_base->dev, "Failed to read PROTECTION_STATUS: %d\n", ret); else ret = !!(val & CS35L56_FIRMWARE_MISSING); - pm_runtime_put_autosuspend(cs35l56->base.dev); + pm_runtime_put_autosuspend(cs35l56_base->dev); return ret; } @@ -1302,7 +1302,7 @@ int cs35l56_system_resume(struct device *dev) if (!cs35l56->component) return 0; - ret = cs35l56_is_fw_reload_needed(cs35l56); + ret = cs35l56_is_fw_reload_needed(&cs35l56->base); dev_dbg(cs35l56->base.dev, "fw_reload_needed: %d\n", ret); if (ret < 1) return ret; @@ -1547,7 +1547,7 @@ int cs35l56_init(struct cs35l56_private *cs35l56) if (!cs35l56->base.reset_gpio) { dev_dbg(cs35l56->base.dev, "No reset gpio: using soft reset\n"); cs35l56->soft_resetting = true; - cs35l56_system_reset(cs35l56, !!cs35l56->sdw_peripheral); + cs35l56_system_reset(&cs35l56->base, !!cs35l56->sdw_peripheral); if (cs35l56->sdw_peripheral) { /* Keep alive while we wait for re-enumeration */ pm_runtime_get_noresume(cs35l56->base.dev); From 8a731fd37f8b33026e545f5ee5cdd7b9a837cbeb Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Fri, 21 Jul 2023 14:21:13 +0100 Subject: [PATCH 227/334] ASoC: cs35l56: Move utility functions to shared file Move the cs35l56 utility functions into the shared file so they are available for use in HDA. Signed-off-by: Simon Trimmer Signed-off-by: Richard Fitzgerald Acked-by: Mark Brown Link: https://lore.kernel.org/r/20230721132120.5523-5-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l56.h | 7 + sound/soc/codecs/cs35l56-shared.c | 208 ++++++++++++++++++++++++++++++ sound/soc/codecs/cs35l56.c | 203 ----------------------------- 3 files changed, 215 insertions(+), 203 deletions(-) diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index 532796efdaa5..3d2875094a21 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -274,6 +274,13 @@ extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC]; extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC]; int cs35l56_set_patch(struct cs35l56_base *cs35l56_base); +int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command); +int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base); +void cs35l56_wait_min_reset_pulse(void); +void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire); +int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq); +irqreturn_t cs35l56_irq(int irq, void *data); +int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base); int cs35l56_get_bclk_freq_id(unsigned int freq); void cs35l56_fill_supply_names(struct regulator_bulk_data *data); diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index 47b915f33f52..d22aede1ee8d 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -195,6 +195,214 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg) } } +int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command) +{ + unsigned int val; + int ret; + + regmap_write(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, command); + ret = regmap_read_poll_timeout(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, + val, (val == 0), + CS35L56_MBOX_POLL_US, CS35L56_MBOX_TIMEOUT_US); + if (ret) { + dev_warn(cs35l56_base->dev, "MBOX command %#x failed: %d\n", command, ret); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_mbox_send, SND_SOC_CS35L56_SHARED); + +int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base) +{ + unsigned int reg; + unsigned int val; + int ret; + + if (cs35l56_base->rev < CS35L56_REVID_B0) + reg = CS35L56_DSP1_HALO_STATE_A1; + else + reg = CS35L56_DSP1_HALO_STATE; + + ret = regmap_read_poll_timeout(cs35l56_base->regmap, reg, + val, + (val < 0xFFFF) && (val >= CS35L56_HALO_STATE_BOOT_DONE), + CS35L56_HALO_STATE_POLL_US, + CS35L56_HALO_STATE_TIMEOUT_US); + + if ((ret < 0) && (ret != -ETIMEDOUT)) { + dev_err(cs35l56_base->dev, "Failed to read HALO_STATE: %d\n", ret); + return ret; + } + + if ((ret == -ETIMEDOUT) || (val != CS35L56_HALO_STATE_BOOT_DONE)) { + dev_err(cs35l56_base->dev, "Firmware boot fail: HALO_STATE=%#x\n", val); + return -EIO; + } + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_wait_for_firmware_boot, SND_SOC_CS35L56_SHARED); + +void cs35l56_wait_min_reset_pulse(void) +{ + /* Satisfy minimum reset pulse width spec */ + usleep_range(CS35L56_RESET_PULSE_MIN_US, 2 * CS35L56_RESET_PULSE_MIN_US); +} +EXPORT_SYMBOL_NS_GPL(cs35l56_wait_min_reset_pulse, SND_SOC_CS35L56_SHARED); + +static const struct reg_sequence cs35l56_system_reset_seq[] = { + REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET), +}; + +void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire) +{ + /* + * Must enter cache-only first so there can't be any more register + * accesses other than the controlled system reset sequence below. + */ + regcache_cache_only(cs35l56_base->regmap, true); + regmap_multi_reg_write_bypassed(cs35l56_base->regmap, + cs35l56_system_reset_seq, + ARRAY_SIZE(cs35l56_system_reset_seq)); + + /* On SoundWire the registers won't be accessible until it re-enumerates. */ + if (is_soundwire) + return; + + usleep_range(CS35L56_CONTROL_PORT_READY_US, CS35L56_CONTROL_PORT_READY_US + 400); + regcache_cache_only(cs35l56_base->regmap, false); +} +EXPORT_SYMBOL_NS_GPL(cs35l56_system_reset, SND_SOC_CS35L56_SHARED); + +int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq) +{ + int ret; + + if (!irq) + return 0; + + ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq, + IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW, + "cs35l56", cs35l56_base); + if (!ret) + cs35l56_base->irq = irq; + else + dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, SND_SOC_CS35L56_SHARED); + +irqreturn_t cs35l56_irq(int irq, void *data) +{ + struct cs35l56_base *cs35l56_base = data; + unsigned int status1 = 0, status8 = 0, status20 = 0; + unsigned int mask1, mask8, mask20; + unsigned int val; + int rv; + + irqreturn_t ret = IRQ_NONE; + + if (!cs35l56_base->init_done) + return IRQ_NONE; + + mutex_lock(&cs35l56_base->irq_lock); + + rv = pm_runtime_resume_and_get(cs35l56_base->dev); + if (rv < 0) { + dev_err(cs35l56_base->dev, "irq: failed to get pm_runtime: %d\n", rv); + goto err_unlock; + } + + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val); + if ((val & CS35L56_IRQ1_STS_MASK) == 0) { + dev_dbg(cs35l56_base->dev, "Spurious IRQ: no pending interrupt\n"); + goto err; + } + + /* Ack interrupts */ + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, &status1); + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_1, &mask1); + status1 &= ~mask1; + regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, status1); + + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, &status8); + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_8, &mask8); + status8 &= ~mask8; + regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, status8); + + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_20, &status20); + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, &mask20); + status20 &= ~mask20; + /* We don't want EINT20 but they default to unmasked: force mask */ + regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff); + + dev_dbg(cs35l56_base->dev, "%s: %#x %#x\n", __func__, status1, status8); + + /* Check to see if unmasked bits are active */ + if (!status1 && !status8 && !status20) + goto err; + + if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK) + dev_crit(cs35l56_base->dev, "Amp short error\n"); + + if (status8 & CS35L56_TEMP_ERR_EINT1_MASK) + dev_crit(cs35l56_base->dev, "Overtemp error\n"); + + ret = IRQ_HANDLED; + +err: + pm_runtime_put(cs35l56_base->dev); +err_unlock: + mutex_unlock(&cs35l56_base->irq_lock); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_irq, SND_SOC_CS35L56_SHARED); + +int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base) +{ + unsigned int val; + int ret; + + /* Nothing to re-patch if we haven't done any patching yet. */ + if (!cs35l56_base->fw_patched) + return false; + + /* + * If we have control of RESET we will have asserted it so the firmware + * will need re-patching. + */ + if (cs35l56_base->reset_gpio) + return true; + + /* + * In secure mode FIRMWARE_MISSING is cleared by the BIOS loader so + * can't be used here to test for memory retention. + * Assume that tuning must be re-loaded. + */ + if (cs35l56_base->secured) + return true; + + ret = pm_runtime_resume_and_get(cs35l56_base->dev); + if (ret) { + dev_err(cs35l56_base->dev, "Failed to runtime_get: %d\n", ret); + return ret; + } + + ret = regmap_read(cs35l56_base->regmap, CS35L56_PROTECTION_STATUS, &val); + if (ret) + dev_err(cs35l56_base->dev, "Failed to read PROTECTION_STATUS: %d\n", ret); + else + ret = !!(val & CS35L56_FIRMWARE_MISSING); + + pm_runtime_put_autosuspend(cs35l56_base->dev); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_is_fw_reload_needed, SND_SOC_CS35L56_SHARED); + const struct cs_dsp_region cs35l56_dsp1_regions[] = { { .type = WMFW_HALO_PM_PACKED, .base = CS35L56_DSP1_PMEM_0 }, { .type = WMFW_HALO_XM_PACKED, .base = CS35L56_DSP1_XMEM_PACKED_0 }, diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 87e2f618850b..5598000187a7 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -34,23 +34,6 @@ static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); -static int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command) -{ - unsigned int val; - int ret; - - regmap_write(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, command); - ret = regmap_read_poll_timeout(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, - val, (val == 0), - CS35L56_MBOX_POLL_US, CS35L56_MBOX_TIMEOUT_US); - if (ret) { - dev_warn(cs35l56_base->dev, "MBOX command %#x failed: %d\n", command, ret); - return ret; - } - - return 0; -} - static void cs35l56_wait_dsp_ready(struct cs35l56_private *cs35l56) { /* Wait for patching to complete */ @@ -315,92 +298,6 @@ static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w, return wm_adsp_event(w, kcontrol, event); } -irqreturn_t cs35l56_irq(int irq, void *data) -{ - struct cs35l56_base *cs35l56_base = data; - unsigned int status1 = 0, status8 = 0, status20 = 0; - unsigned int mask1, mask8, mask20; - unsigned int val; - int rv; - - irqreturn_t ret = IRQ_NONE; - - if (!cs35l56_base->init_done) - return IRQ_NONE; - - mutex_lock(&cs35l56_base->irq_lock); - - rv = pm_runtime_resume_and_get(cs35l56_base->dev); - if (rv < 0) { - dev_err(cs35l56_base->dev, "irq: failed to get pm_runtime: %d\n", rv); - goto err_unlock; - } - - regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val); - if ((val & CS35L56_IRQ1_STS_MASK) == 0) { - dev_dbg(cs35l56_base->dev, "Spurious IRQ: no pending interrupt\n"); - goto err; - } - - /* Ack interrupts */ - regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, &status1); - regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_1, &mask1); - status1 &= ~mask1; - regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, status1); - - regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, &status8); - regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_8, &mask8); - status8 &= ~mask8; - regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, status8); - - regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_20, &status20); - regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, &mask20); - status20 &= ~mask20; - /* We don't want EINT20 but they default to unmasked: force mask */ - regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff); - - dev_dbg(cs35l56_base->dev, "%s: %#x %#x\n", __func__, status1, status8); - - /* Check to see if unmasked bits are active */ - if (!status1 && !status8 && !status20) - goto err; - - if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK) - dev_crit(cs35l56_base->dev, "Amp short error\n"); - - if (status8 & CS35L56_TEMP_ERR_EINT1_MASK) - dev_crit(cs35l56_base->dev, "Overtemp error\n"); - - ret = IRQ_HANDLED; - -err: - pm_runtime_put(cs35l56_base->dev); -err_unlock: - mutex_unlock(&cs35l56_base->irq_lock); - - return ret; -} -EXPORT_SYMBOL_NS_GPL(cs35l56_irq, SND_SOC_CS35L56_CORE); - -int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq) -{ - int ret; - - if (!irq) - return 0; - - ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq, - IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW, - "cs35l56", cs35l56_base); - if (!ret) - cs35l56_base->irq = irq; - else - dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n", ret); - - return ret; -} -EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, SND_SOC_CS35L56_CORE); - static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(codec_dai->component); @@ -762,65 +659,6 @@ static struct snd_soc_dai_driver cs35l56_dai[] = { } }; -static int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base) -{ - unsigned int reg; - unsigned int val; - int ret; - - if (cs35l56_base->rev < CS35L56_REVID_B0) - reg = CS35L56_DSP1_HALO_STATE_A1; - else - reg = CS35L56_DSP1_HALO_STATE; - - ret = regmap_read_poll_timeout(cs35l56_base->regmap, reg, - val, - (val < 0xFFFF) && (val >= CS35L56_HALO_STATE_BOOT_DONE), - CS35L56_HALO_STATE_POLL_US, - CS35L56_HALO_STATE_TIMEOUT_US); - - if ((ret < 0) && (ret != -ETIMEDOUT)) { - dev_err(cs35l56_base->dev, "Failed to read HALO_STATE: %d\n", ret); - return ret; - } - - if ((ret == -ETIMEDOUT) || (val != CS35L56_HALO_STATE_BOOT_DONE)) { - dev_err(cs35l56_base->dev, "Firmware boot fail: HALO_STATE=%#x\n", val); - return -EIO; - } - - return 0; -} - -static inline void cs35l56_wait_min_reset_pulse(void) -{ - /* Satisfy minimum reset pulse width spec */ - usleep_range(CS35L56_RESET_PULSE_MIN_US, 2 * CS35L56_RESET_PULSE_MIN_US); -} - -static const struct reg_sequence cs35l56_system_reset_seq[] = { - REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET), -}; - -static void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire) -{ - /* - * Must enter cache-only first so there can't be any more register - * accesses other than the controlled system reset sequence below. - */ - regcache_cache_only(cs35l56_base->regmap, true); - regmap_multi_reg_write_bypassed(cs35l56_base->regmap, - cs35l56_system_reset_seq, - ARRAY_SIZE(cs35l56_system_reset_seq)); - - /* On SoundWire the registers won't be accessible until it re-enumerates. */ - if (is_soundwire) - return; - - usleep_range(CS35L56_CONTROL_PORT_READY_US, CS35L56_CONTROL_PORT_READY_US + 400); - regcache_cache_only(cs35l56_base->regmap, false); -} - static void cs35l56_secure_patch(struct cs35l56_private *cs35l56) { int ret; @@ -1137,47 +975,6 @@ int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56) } EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, SND_SOC_CS35L56_CORE); -static int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base) -{ - unsigned int val; - int ret; - - /* Nothing to re-patch if we haven't done any patching yet. */ - if (!cs35l56_base->fw_patched) - return false; - - /* - * If we have control of RESET we will have asserted it so the firmware - * will need re-patching. - */ - if (cs35l56_base->reset_gpio) - return true; - - /* - * In secure mode FIRMWARE_MISSING is cleared by the BIOS loader so - * can't be used here to test for memory retention. - * Assume that tuning must be re-loaded. - */ - if (cs35l56_base->secured) - return true; - - ret = pm_runtime_resume_and_get(cs35l56_base->dev); - if (ret) { - dev_err(cs35l56_base->dev, "Failed to runtime_get: %d\n", ret); - return ret; - } - - ret = regmap_read(cs35l56_base->regmap, CS35L56_PROTECTION_STATUS, &val); - if (ret) - dev_err(cs35l56_base->dev, "Failed to read PROTECTION_STATUS: %d\n", ret); - else - ret = !!(val & CS35L56_FIRMWARE_MISSING); - - pm_runtime_put_autosuspend(cs35l56_base->dev); - - return ret; -} - int cs35l56_system_suspend(struct device *dev) { struct cs35l56_private *cs35l56 = dev_get_drvdata(dev); From 9974d5b57697770cba2a99c6fe925d01152cd544 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 21 Jul 2023 14:21:14 +0100 Subject: [PATCH 228/334] ASoC: cs35l56: Move runtime suspend/resume to shared library The majority of runtime_suspend and runtime_resume handling doesn't have anything specific to the ASoC driver, so can be shared by the HDA driver. Move this code into the shared library. Signed-off-by: Richard Fitzgerald Acked-by: Mark Brown Link: https://lore.kernel.org/r/20230721132120.5523-6-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l56.h | 2 + sound/soc/codecs/cs35l56-sdw.c | 4 +- sound/soc/codecs/cs35l56-shared.c | 118 +++++++++++++++++++++++++++++ sound/soc/codecs/cs35l56.c | 120 +----------------------------- sound/soc/codecs/cs35l56.h | 2 - 5 files changed, 126 insertions(+), 120 deletions(-) diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index 3d2875094a21..e48f662dcbce 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -281,6 +281,8 @@ void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire); int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq); irqreturn_t cs35l56_irq(int irq, void *data); int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base); +int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base); +int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire); int cs35l56_get_bclk_freq_id(unsigned int freq); void cs35l56_fill_supply_names(struct regulator_bulk_data *data); diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c index 98be005b8787..b433266b7844 100644 --- a/sound/soc/codecs/cs35l56-sdw.c +++ b/sound/soc/codecs/cs35l56-sdw.c @@ -424,7 +424,7 @@ static int __maybe_unused cs35l56_sdw_runtime_suspend(struct device *dev) if (!cs35l56->base.init_done) return 0; - return cs35l56_runtime_suspend(dev); + return cs35l56_runtime_suspend_common(&cs35l56->base); } static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev) @@ -441,7 +441,7 @@ static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev) if (ret < 0) return ret; - ret = cs35l56_runtime_resume_common(cs35l56); + ret = cs35l56_runtime_resume_common(&cs35l56->base, true); if (ret) return ret; diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index d22aede1ee8d..737a9ea27495 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -403,6 +403,124 @@ int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base) } EXPORT_SYMBOL_NS_GPL(cs35l56_is_fw_reload_needed, SND_SOC_CS35L56_SHARED); +static const struct reg_sequence cs35l56_hibernate_seq[] = { + /* This must be the last register access */ + REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_HIBERNATE_NOW), +}; + +static const struct reg_sequence cs35l56_hibernate_wake_seq[] = { + REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_WAKEUP), +}; + +int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base) +{ + unsigned int val; + int ret; + + if (!cs35l56_base->init_done) + return 0; + + /* Firmware must have entered a power-save state */ + ret = regmap_read_poll_timeout(cs35l56_base->regmap, + CS35L56_TRANSDUCER_ACTUAL_PS, + val, (val >= CS35L56_PS3), + CS35L56_PS3_POLL_US, + CS35L56_PS3_TIMEOUT_US); + if (ret) + dev_warn(cs35l56_base->dev, "PS3 wait failed: %d\n", ret); + + /* Clear BOOT_DONE so it can be used to detect a reboot */ + regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_4, CS35L56_OTP_BOOT_DONE_MASK); + + if (!cs35l56_base->can_hibernate) { + regcache_cache_only(cs35l56_base->regmap, true); + dev_dbg(cs35l56_base->dev, "Suspended: no hibernate"); + + return 0; + } + + /* + * Enable auto-hibernate. If it is woken by some other wake source + * it will automatically return to hibernate. + */ + cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE); + + /* + * Must enter cache-only first so there can't be any more register + * accesses other than the controlled hibernate sequence below. + */ + regcache_cache_only(cs35l56_base->regmap, true); + + regmap_multi_reg_write_bypassed(cs35l56_base->regmap, + cs35l56_hibernate_seq, + ARRAY_SIZE(cs35l56_hibernate_seq)); + + dev_dbg(cs35l56_base->dev, "Suspended: hibernate"); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_suspend_common, SND_SOC_CS35L56_SHARED); + +int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire) +{ + unsigned int val; + int ret; + + if (!cs35l56_base->init_done) + return 0; + + if (!cs35l56_base->can_hibernate) + goto out_sync; + + if (!is_soundwire) { + /* + * Dummy transaction to trigger I2C/SPI auto-wake. This will NAK on I2C. + * Must be done before releasing cache-only. + */ + regmap_multi_reg_write_bypassed(cs35l56_base->regmap, + cs35l56_hibernate_wake_seq, + ARRAY_SIZE(cs35l56_hibernate_wake_seq)); + + usleep_range(CS35L56_CONTROL_PORT_READY_US, + CS35L56_CONTROL_PORT_READY_US + 400); + } + +out_sync: + regcache_cache_only(cs35l56_base->regmap, false); + + ret = cs35l56_wait_for_firmware_boot(cs35l56_base); + if (ret) { + dev_err(cs35l56_base->dev, "Hibernate wake failed: %d\n", ret); + goto err; + } + + ret = cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE); + if (ret) + goto err; + + /* BOOT_DONE will be 1 if the amp reset */ + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_4, &val); + if (val & CS35L56_OTP_BOOT_DONE_MASK) { + dev_dbg(cs35l56_base->dev, "Registers reset in suspend\n"); + regcache_mark_dirty(cs35l56_base->regmap); + } + + regcache_sync(cs35l56_base->regmap); + + dev_dbg(cs35l56_base->dev, "Resumed"); + + return 0; + +err: + regmap_write(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, + CS35L56_MBOX_CMD_HIBERNATE_NOW); + + regcache_cache_only(cs35l56_base->regmap, true); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, SND_SOC_CS35L56_SHARED); + const struct cs_dsp_region cs35l56_dsp1_regions[] = { { .type = WMFW_HALO_PM_PACKED, .base = CS35L56_DSP1_PMEM_0 }, { .type = WMFW_HALO_XM_PACKED, .base = CS35L56_DSP1_XMEM_PACKED_0 }, diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 5598000187a7..701f1072a609 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -849,132 +849,20 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l56 = { .suspend_bias_off = 1, /* see cs35l56_system_resume() */ }; -static const struct reg_sequence cs35l56_hibernate_seq[] = { - /* This must be the last register access */ - REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_HIBERNATE_NOW), -}; - -static const struct reg_sequence cs35l56_hibernate_wake_seq[] = { - REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_WAKEUP), -}; - -int cs35l56_runtime_suspend(struct device *dev) +static int __maybe_unused cs35l56_runtime_suspend_i2c_spi(struct device *dev) { struct cs35l56_private *cs35l56 = dev_get_drvdata(dev); - unsigned int val; - int ret; - if (!cs35l56->base.init_done) - return 0; - - /* Firmware must have entered a power-save state */ - ret = regmap_read_poll_timeout(cs35l56->base.regmap, - CS35L56_TRANSDUCER_ACTUAL_PS, - val, (val >= CS35L56_PS3), - CS35L56_PS3_POLL_US, - CS35L56_PS3_TIMEOUT_US); - if (ret) - dev_warn(cs35l56->base.dev, "PS3 wait failed: %d\n", ret); - - /* Clear BOOT_DONE so it can be used to detect a reboot */ - regmap_write(cs35l56->base.regmap, CS35L56_IRQ1_EINT_4, CS35L56_OTP_BOOT_DONE_MASK); - - if (!cs35l56->base.can_hibernate) { - regcache_cache_only(cs35l56->base.regmap, true); - dev_dbg(dev, "Suspended: no hibernate"); - - return 0; - } - - /* - * Enable auto-hibernate. If it is woken by some other wake source - * it will automatically return to hibernate. - */ - cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE); - - /* - * Must enter cache-only first so there can't be any more register - * accesses other than the controlled hibernate sequence below. - */ - regcache_cache_only(cs35l56->base.regmap, true); - - regmap_multi_reg_write_bypassed(cs35l56->base.regmap, - cs35l56_hibernate_seq, - ARRAY_SIZE(cs35l56_hibernate_seq)); - - dev_dbg(dev, "Suspended: hibernate"); - - return 0; + return cs35l56_runtime_suspend_common(&cs35l56->base); } -EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_suspend, SND_SOC_CS35L56_CORE); static int __maybe_unused cs35l56_runtime_resume_i2c_spi(struct device *dev) { struct cs35l56_private *cs35l56 = dev_get_drvdata(dev); - if (!cs35l56->base.init_done) - return 0; - - return cs35l56_runtime_resume_common(cs35l56); + return cs35l56_runtime_resume_common(&cs35l56->base, false); } -int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56) -{ - unsigned int val; - int ret; - - if (!cs35l56->base.can_hibernate) - goto out_sync; - - if (!cs35l56->sdw_peripheral) { - /* - * Dummy transaction to trigger I2C/SPI auto-wake. This will NAK on I2C. - * Must be done before releasing cache-only. - */ - regmap_multi_reg_write_bypassed(cs35l56->base.regmap, - cs35l56_hibernate_wake_seq, - ARRAY_SIZE(cs35l56_hibernate_wake_seq)); - - usleep_range(CS35L56_CONTROL_PORT_READY_US, - CS35L56_CONTROL_PORT_READY_US + 400); - } - -out_sync: - regcache_cache_only(cs35l56->base.regmap, false); - - ret = cs35l56_wait_for_firmware_boot(&cs35l56->base); - if (ret) { - dev_err(cs35l56->base.dev, "Hibernate wake failed: %d\n", ret); - goto err; - } - - ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE); - if (ret) - goto err; - - /* BOOT_DONE will be 1 if the amp reset */ - regmap_read(cs35l56->base.regmap, CS35L56_IRQ1_EINT_4, &val); - if (val & CS35L56_OTP_BOOT_DONE_MASK) { - dev_dbg(cs35l56->base.dev, "Registers reset in suspend\n"); - regcache_mark_dirty(cs35l56->base.regmap); - } - - regcache_sync(cs35l56->base.regmap); - - dev_dbg(cs35l56->base.dev, "Resumed"); - - return 0; - -err: - regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, - CS35L56_MBOX_CMD_HIBERNATE_NOW); - - regcache_cache_only(cs35l56->base.regmap, true); - - return ret; -} -EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, SND_SOC_CS35L56_CORE); - int cs35l56_system_suspend(struct device *dev) { struct cs35l56_private *cs35l56 = dev_get_drvdata(dev); @@ -1414,7 +1302,7 @@ void cs35l56_remove(struct cs35l56_private *cs35l56) EXPORT_SYMBOL_NS_GPL(cs35l56_remove, SND_SOC_CS35L56_CORE); const struct dev_pm_ops cs35l56_pm_ops_i2c_spi = { - SET_RUNTIME_PM_OPS(cs35l56_runtime_suspend, cs35l56_runtime_resume_i2c_spi, NULL) + SET_RUNTIME_PM_OPS(cs35l56_runtime_suspend_i2c_spi, cs35l56_runtime_resume_i2c_spi, NULL) SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend, cs35l56_system_resume) LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_late, cs35l56_system_resume_early) NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_no_irq, cs35l56_system_resume_no_irq) diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h index f39f8fa9e37e..8159c3e217d9 100644 --- a/sound/soc/codecs/cs35l56.h +++ b/sound/soc/codecs/cs35l56.h @@ -55,8 +55,6 @@ struct cs35l56_private { extern const struct dev_pm_ops cs35l56_pm_ops_i2c_spi; -int cs35l56_runtime_suspend(struct device *dev); -int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56); int cs35l56_system_suspend(struct device *dev); int cs35l56_system_suspend_late(struct device *dev); int cs35l56_system_suspend_no_irq(struct device *dev); From 22e51dbb257a218e43de42764b5bdc5302f27cd1 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 21 Jul 2023 14:21:15 +0100 Subject: [PATCH 229/334] ASoC: cs35l56: Move cs_dsp init into shared library Move the code that initialized the struct cs_dsp members into the shared library so that the HDA driver can use it. Signed-off-by: Richard Fitzgerald Acked-by: Mark Brown Link: https://lore.kernel.org/r/20230721132120.5523-7-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l56.h | 2 +- sound/soc/codecs/cs35l56-shared.c | 18 ++++++++++++++++-- sound/soc/codecs/cs35l56.c | 11 +---------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index e48f662dcbce..6ab12e2035cd 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -269,7 +269,6 @@ extern struct regmap_config cs35l56_regmap_i2c; extern struct regmap_config cs35l56_regmap_spi; extern struct regmap_config cs35l56_regmap_sdw; -extern const struct cs_dsp_region cs35l56_dsp1_regions[CS35L56_NUM_DSP_REGIONS]; extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC]; extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC]; @@ -283,6 +282,7 @@ irqreturn_t cs35l56_irq(int irq, void *data); int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base); int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base); int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire); +void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp); int cs35l56_get_bclk_freq_id(unsigned int freq); void cs35l56_fill_supply_names(struct regulator_bulk_data *data); diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index 737a9ea27495..fe8df04951f3 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -521,14 +521,28 @@ int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_sou } EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, SND_SOC_CS35L56_SHARED); -const struct cs_dsp_region cs35l56_dsp1_regions[] = { +static const struct cs_dsp_region cs35l56_dsp1_regions[] = { { .type = WMFW_HALO_PM_PACKED, .base = CS35L56_DSP1_PMEM_0 }, { .type = WMFW_HALO_XM_PACKED, .base = CS35L56_DSP1_XMEM_PACKED_0 }, { .type = WMFW_HALO_YM_PACKED, .base = CS35L56_DSP1_YMEM_PACKED_0 }, { .type = WMFW_ADSP2_XM, .base = CS35L56_DSP1_XMEM_UNPACKED24_0 }, { .type = WMFW_ADSP2_YM, .base = CS35L56_DSP1_YMEM_UNPACKED24_0 }, }; -EXPORT_SYMBOL_NS_GPL(cs35l56_dsp1_regions, SND_SOC_CS35L56_SHARED); + +void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp) +{ + cs_dsp->num = 1; + cs_dsp->type = WMFW_HALO; + cs_dsp->rev = 0; + cs_dsp->dev = cs35l56_base->dev; + cs_dsp->regmap = cs35l56_base->regmap; + cs_dsp->base = CS35L56_DSP1_CORE_BASE; + cs_dsp->base_sysinfo = CS35L56_DSP1_SYS_INFO_ID; + cs_dsp->mem = cs35l56_dsp1_regions; + cs_dsp->num_mems = ARRAY_SIZE(cs35l56_dsp1_regions); + cs_dsp->no_core_startstop = true; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_init_cs_dsp, SND_SOC_CS35L56_SHARED); static const u32 cs35l56_bclk_valid_for_pll_freq_table[] = { [0x0C] = 128000, diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 701f1072a609..430829f8a320 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -1016,18 +1016,9 @@ static int cs35l56_dsp_init(struct cs35l56_private *cs35l56) INIT_WORK(&cs35l56->dsp_work, cs35l56_dsp_work); dsp = &cs35l56->dsp; + cs35l56_init_cs_dsp(&cs35l56->base, &dsp->cs_dsp); dsp->part = "cs35l56"; - dsp->cs_dsp.num = 1; - dsp->cs_dsp.type = WMFW_HALO; - dsp->cs_dsp.rev = 0; dsp->fw = 12; - dsp->cs_dsp.dev = cs35l56->base.dev; - dsp->cs_dsp.regmap = cs35l56->base.regmap; - dsp->cs_dsp.base = CS35L56_DSP1_CORE_BASE; - dsp->cs_dsp.base_sysinfo = CS35L56_DSP1_SYS_INFO_ID; - dsp->cs_dsp.mem = cs35l56_dsp1_regions; - dsp->cs_dsp.num_mems = ARRAY_SIZE(cs35l56_dsp1_regions); - dsp->cs_dsp.no_core_startstop = true; dsp->wmfw_optional = true; dev_dbg(cs35l56->base.dev, "DSP system name: '%s'\n", dsp->system_name); From 84851aa055c890f2ea731a128e8feb64520c2c8e Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 21 Jul 2023 14:21:16 +0100 Subject: [PATCH 230/334] ASoC: cs35l56: Move part of cs35l56_init() to shared library Part of the initialization code in cs35l56_init() can be re-used by the HDA driver so move it into a new function in the shared library. Signed-off-by: Richard Fitzgerald Acked-by: Mark Brown Link: https://lore.kernel.org/r/20230721132120.5523-8-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l56.h | 1 + sound/soc/codecs/cs35l56-shared.c | 79 +++++++++++++++++++++++++++++++ sound/soc/codecs/cs35l56.c | 71 +-------------------------- 3 files changed, 82 insertions(+), 69 deletions(-) diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index 6ab12e2035cd..0d6cdfb6107b 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -283,6 +283,7 @@ int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base); int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base); int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire); void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp); +int cs35l56_hw_init(struct cs35l56_base *cs35l56_base); int cs35l56_get_bclk_freq_id(unsigned int freq); void cs35l56_fill_supply_names(struct regulator_bulk_data *data); diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index fe8df04951f3..8a98070ece5e 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -544,6 +544,85 @@ void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_ds } EXPORT_SYMBOL_NS_GPL(cs35l56_init_cs_dsp, SND_SOC_CS35L56_SHARED); +int cs35l56_hw_init(struct cs35l56_base *cs35l56_base) +{ + int ret; + unsigned int devid, revid, otpid, secured; + + /* + * If the system is not using a reset_gpio then issue a + * dummy read to force a wakeup. + */ + if (!cs35l56_base->reset_gpio) + regmap_read(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, &devid); + + /* Wait for control port to be ready (datasheet tIRS). */ + usleep_range(CS35L56_CONTROL_PORT_READY_US, + CS35L56_CONTROL_PORT_READY_US + 400); + + /* + * The HALO_STATE register is in different locations on Ax and B0 + * devices so the REVID needs to be determined before waiting for the + * firmware to boot. + */ + ret = regmap_read(cs35l56_base->regmap, CS35L56_REVID, &revid); + if (ret < 0) { + dev_err(cs35l56_base->dev, "Get Revision ID failed\n"); + return ret; + } + cs35l56_base->rev = revid & (CS35L56_AREVID_MASK | CS35L56_MTLREVID_MASK); + + ret = cs35l56_wait_for_firmware_boot(cs35l56_base); + if (ret) + return ret; + + ret = regmap_read(cs35l56_base->regmap, CS35L56_DEVID, &devid); + if (ret < 0) { + dev_err(cs35l56_base->dev, "Get Device ID failed\n"); + return ret; + } + devid &= CS35L56_DEVID_MASK; + + switch (devid) { + case 0x35A56: + break; + default: + dev_err(cs35l56_base->dev, "Unknown device %x\n", devid); + return ret; + } + + ret = regmap_read(cs35l56_base->regmap, CS35L56_DSP_RESTRICT_STS1, &secured); + if (ret) { + dev_err(cs35l56_base->dev, "Get Secure status failed\n"); + return ret; + } + + /* When any bus is restricted treat the device as secured */ + if (secured & CS35L56_RESTRICTED_MASK) + cs35l56_base->secured = true; + + ret = regmap_read(cs35l56_base->regmap, CS35L56_OTPID, &otpid); + if (ret < 0) { + dev_err(cs35l56_base->dev, "Get OTP ID failed\n"); + return ret; + } + + dev_info(cs35l56_base->dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d\n", + cs35l56_base->secured ? "s" : "", cs35l56_base->rev, otpid); + + /* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */ + regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff); + regmap_update_bits(cs35l56_base->regmap, CS35L56_IRQ1_MASK_1, + CS35L56_AMP_SHORT_ERR_EINT1_MASK, + 0); + regmap_update_bits(cs35l56_base->regmap, CS35L56_IRQ1_MASK_8, + CS35L56_TEMP_ERR_EINT1_MASK, + 0); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_hw_init, SND_SOC_CS35L56_SHARED); + static const u32 cs35l56_bclk_valid_for_pll_freq_table[] = { [0x0C] = 128000, [0x0F] = 256000, diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 430829f8a320..d06b83dfc462 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -1127,7 +1127,6 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_common_probe, SND_SOC_CS35L56_CORE); int cs35l56_init(struct cs35l56_private *cs35l56) { int ret; - unsigned int devid, revid, otpid, secured; /* * Check whether the actions associated with soft reset or one time @@ -1144,66 +1143,9 @@ int cs35l56_init(struct cs35l56_private *cs35l56) pm_runtime_set_active(cs35l56->base.dev); pm_runtime_enable(cs35l56->base.dev); - /* - * If the system is not using a reset_gpio then issue a - * dummy read to force a wakeup. - */ - if (!cs35l56->base.reset_gpio) - regmap_read(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, &devid); - - /* Wait for control port to be ready (datasheet tIRS). */ - usleep_range(CS35L56_CONTROL_PORT_READY_US, - CS35L56_CONTROL_PORT_READY_US + 400); - - /* - * The HALO_STATE register is in different locations on Ax and B0 - * devices so the REVID needs to be determined before waiting for the - * firmware to boot. - */ - ret = regmap_read(cs35l56->base.regmap, CS35L56_REVID, &revid); - if (ret < 0) { - dev_err(cs35l56->base.dev, "Get Revision ID failed\n"); + ret = cs35l56_hw_init(&cs35l56->base); + if (ret < 0) return ret; - } - cs35l56->base.rev = revid & (CS35L56_AREVID_MASK | CS35L56_MTLREVID_MASK); - - ret = cs35l56_wait_for_firmware_boot(&cs35l56->base); - if (ret) - return ret; - - ret = regmap_read(cs35l56->base.regmap, CS35L56_DEVID, &devid); - if (ret < 0) { - dev_err(cs35l56->base.dev, "Get Device ID failed\n"); - return ret; - } - devid &= CS35L56_DEVID_MASK; - - switch (devid) { - case 0x35A56: - break; - default: - dev_err(cs35l56->base.dev, "Unknown device %x\n", devid); - return ret; - } - - ret = regmap_read(cs35l56->base.regmap, CS35L56_DSP_RESTRICT_STS1, &secured); - if (ret) { - dev_err(cs35l56->base.dev, "Get Secure status failed\n"); - return ret; - } - - /* When any bus is restricted treat the device as secured */ - if (secured & CS35L56_RESTRICTED_MASK) - cs35l56->base.secured = true; - - ret = regmap_read(cs35l56->base.regmap, CS35L56_OTPID, &otpid); - if (ret < 0) { - dev_err(cs35l56->base.dev, "Get OTP ID failed\n"); - return ret; - } - - dev_info(cs35l56->base.dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d\n", - cs35l56->base.secured ? "s" : "", cs35l56->base.rev, otpid); /* Populate the DSP information with the revision and security state */ cs35l56->dsp.part = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, "cs35l56%s-%02x", @@ -1211,15 +1153,6 @@ int cs35l56_init(struct cs35l56_private *cs35l56) if (!cs35l56->dsp.part) return -ENOMEM; - /* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */ - regmap_write(cs35l56->base.regmap, CS35L56_IRQ1_MASK_20, 0xffffffff); - regmap_update_bits(cs35l56->base.regmap, CS35L56_IRQ1_MASK_1, - CS35L56_AMP_SHORT_ERR_EINT1_MASK, - 0); - regmap_update_bits(cs35l56->base.regmap, CS35L56_IRQ1_MASK_8, - CS35L56_TEMP_ERR_EINT1_MASK, - 0); - if (!cs35l56->base.reset_gpio) { dev_dbg(cs35l56->base.dev, "No reset gpio: using soft reset\n"); cs35l56->soft_resetting = true; From f32a2bcbc092d60ba8a1b00a22607b220d53a25e Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Fri, 21 Jul 2023 14:21:17 +0100 Subject: [PATCH 231/334] ASoC: cs35l56: Make common function for control port wait Move the waits for CS35L56_CONTROL_PORT_READY_US into a common function, and also allow a wider range of allowed wait times. Signed-off-by: Simon Trimmer Signed-off-by: Richard Fitzgerald Acked-by: Mark Brown Link: https://lore.kernel.org/r/20230721132120.5523-9-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l56.h | 1 + sound/soc/codecs/cs35l56-shared.c | 16 ++++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index 0d6cdfb6107b..79e117abee06 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -275,6 +275,7 @@ extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC]; int cs35l56_set_patch(struct cs35l56_base *cs35l56_base); int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command); int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base); +void cs35l56_wait_control_port_ready(void); void cs35l56_wait_min_reset_pulse(void); void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire); int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq); diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index 8a98070ece5e..4e3becb9581d 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -244,6 +244,13 @@ int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base) } EXPORT_SYMBOL_NS_GPL(cs35l56_wait_for_firmware_boot, SND_SOC_CS35L56_SHARED); +void cs35l56_wait_control_port_ready(void) +{ + /* Wait for control port to be ready (datasheet tIRS). */ + usleep_range(CS35L56_CONTROL_PORT_READY_US, 2 * CS35L56_CONTROL_PORT_READY_US); +} +EXPORT_SYMBOL_NS_GPL(cs35l56_wait_control_port_ready, SND_SOC_CS35L56_SHARED); + void cs35l56_wait_min_reset_pulse(void) { /* Satisfy minimum reset pulse width spec */ @@ -270,7 +277,7 @@ void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire) if (is_soundwire) return; - usleep_range(CS35L56_CONTROL_PORT_READY_US, CS35L56_CONTROL_PORT_READY_US + 400); + cs35l56_wait_control_port_ready(); regcache_cache_only(cs35l56_base->regmap, false); } EXPORT_SYMBOL_NS_GPL(cs35l56_system_reset, SND_SOC_CS35L56_SHARED); @@ -481,8 +488,7 @@ int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_sou cs35l56_hibernate_wake_seq, ARRAY_SIZE(cs35l56_hibernate_wake_seq)); - usleep_range(CS35L56_CONTROL_PORT_READY_US, - CS35L56_CONTROL_PORT_READY_US + 400); + cs35l56_wait_control_port_ready(); } out_sync: @@ -556,9 +562,7 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base) if (!cs35l56_base->reset_gpio) regmap_read(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, &devid); - /* Wait for control port to be ready (datasheet tIRS). */ - usleep_range(CS35L56_CONTROL_PORT_READY_US, - CS35L56_CONTROL_PORT_READY_US + 400); + cs35l56_wait_control_port_ready(); /* * The HALO_STATE register is in different locations on Ax and B0 From 444dfa0912639fb2431553e8e54d2b35fdf590c2 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Fri, 21 Jul 2023 14:21:18 +0100 Subject: [PATCH 232/334] ASoC: cs35l56: Make a common function to shutdown the DSP Move issuing of a CS35L56_MBOX_CMD_SHUTDOWN command and then waiting for the DSP to reach CS35L56_HALO_STATE_SHUTDOWN in the register appropriate for the hardware revision into a common function. Signed-off-by: Simon Trimmer Signed-off-by: Richard Fitzgerald Acked-by: Mark Brown Link: https://lore.kernel.org/r/20230721132120.5523-10-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l56.h | 1 + sound/soc/codecs/cs35l56-shared.c | 26 ++++++++++++++++++++++++++ sound/soc/codecs/cs35l56.c | 17 +---------------- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index 79e117abee06..3950322bf3cb 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -274,6 +274,7 @@ extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC]; int cs35l56_set_patch(struct cs35l56_base *cs35l56_base); int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command); +int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base); int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base); void cs35l56_wait_control_port_ready(void); void cs35l56_wait_min_reset_pulse(void); diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index 4e3becb9581d..ae373f335ea8 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -213,6 +213,32 @@ int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command) } EXPORT_SYMBOL_NS_GPL(cs35l56_mbox_send, SND_SOC_CS35L56_SHARED); +int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base) +{ + int ret; + unsigned int reg; + unsigned int val; + + ret = cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_SHUTDOWN); + if (ret) + return ret; + + if (cs35l56_base->rev < CS35L56_REVID_B0) + reg = CS35L56_DSP1_PM_CUR_STATE_A1; + else + reg = CS35L56_DSP1_PM_CUR_STATE; + + ret = regmap_read_poll_timeout(cs35l56_base->regmap, reg, + val, (val == CS35L56_HALO_STATE_SHUTDOWN), + CS35L56_HALO_STATE_POLL_US, + CS35L56_HALO_STATE_TIMEOUT_US); + if (ret < 0) + dev_err(cs35l56_base->dev, "Failed to poll PM_CUR_STATE to 1 is %d (ret %d)\n", + val, ret); + return ret; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_firmware_shutdown, SND_SOC_CS35L56_SHARED); + int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base) { unsigned int reg; diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index d06b83dfc462..19b6b4fbe5de 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -673,8 +673,6 @@ static void cs35l56_secure_patch(struct cs35l56_private *cs35l56) static void cs35l56_patch(struct cs35l56_private *cs35l56) { - unsigned int reg; - unsigned int val; int ret; /* @@ -691,23 +689,10 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56) flush_work(&cs35l56->sdw_irq_work); } - ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_SHUTDOWN); + ret = cs35l56_firmware_shutdown(&cs35l56->base); if (ret) goto err; - if (cs35l56->base.rev < CS35L56_REVID_B0) - reg = CS35L56_DSP1_PM_CUR_STATE_A1; - else - reg = CS35L56_DSP1_PM_CUR_STATE; - - ret = regmap_read_poll_timeout(cs35l56->base.regmap, reg, - val, (val == CS35L56_HALO_STATE_SHUTDOWN), - CS35L56_HALO_STATE_POLL_US, - CS35L56_HALO_STATE_TIMEOUT_US); - if (ret < 0) - dev_err(cs35l56->base.dev, "Failed to poll PM_CUR_STATE to 1 is %d (ret %d)\n", - val, ret); - /* Use wm_adsp to load and apply the firmware patch and coefficient files */ ret = wm_adsp_power_up(&cs35l56->dsp); if (ret) { From 64e05321506261b737abdbfc7a82144f30d0a925 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 21 Jul 2023 14:21:19 +0100 Subject: [PATCH 233/334] ALSA: hda: Fix missing header dependencies Add #includes of dependencies into hda_auto_parser.h and hda_generic.h hda_auto_parser.h uses definitions in hda_local.h. hda_generic.h uses definitions in hda_local.h and hda_auto_parser.h. It also references struct hda_jack_callback, but only as a pointer. This has been forward-declared so hda_jack.h only needs to be included in source that actually uses it. Signed-off-by: Richard Fitzgerald Reviewed-by: Takashi Iwai Link: https://lore.kernel.org/r/20230721132120.5523-11-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/pci/hda/hda_auto_parser.h | 2 ++ sound/pci/hda/hda_generic.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/pci/hda/hda_auto_parser.h index df63d66af1ab..579b11beac71 100644 --- a/sound/pci/hda/hda_auto_parser.h +++ b/sound/pci/hda/hda_auto_parser.h @@ -8,6 +8,8 @@ #ifndef __SOUND_HDA_AUTO_PARSER_H #define __SOUND_HDA_AUTO_PARSER_H +#include "hda_local.h" + /* * Helper for automatic pin configuration */ diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 34eba40cc6e6..a8eea8367629 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -9,6 +9,9 @@ #define __SOUND_HDA_GENERIC_H #include +#include "hda_auto_parser.h" + +struct hda_jack_callback; /* table entry for multi-io paths */ struct hda_multi_io { From 73cfbfa9caea8eda54b4c6e49a9555533660aa1e Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Fri, 21 Jul 2023 14:21:20 +0100 Subject: [PATCH 234/334] ALSA: hda/cs35l56: Add driver for Cirrus Logic CS35L56 amplifier Add a driver for the Cirrus Logic CS35L56 amplifier. This uses the same component binding API as the CS35L41 driver. This is not a standalone HDA device; it provides control of the CS35L56 for systems that use a combination of an HDA codec and CS35L56 amplifiers with audio routed through the HDA codec. The CS35L56 combines a high-performance mono audio amplifier, Class-H tracking inductive boost converter, Halo Core(TM) DSP and a DC-DC boost converter supporting Class-H tracking. Control interfaces are I2C or SPI through the standard Linux I2C or SPI bus framework. Most chip functionality is controlled by on-board ROM firmware that is always running. Firmware patches can be applied by the driver in the form of a .wmfw file (firmware patch) and/or a .bin file (system tuning). Signed-off-by: Simon Trimmer Signed-off-by: Richard Fitzgerald Reviewed-by: Takashi Iwai Link: https://lore.kernel.org/r/20230721132120.5523-12-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/pci/hda/Kconfig | 31 + sound/pci/hda/Makefile | 6 + sound/pci/hda/cs35l56_hda.c | 995 ++++++++++++++++++++++++++++++++ sound/pci/hda/cs35l56_hda.h | 48 ++ sound/pci/hda/cs35l56_hda_i2c.c | 69 +++ sound/pci/hda/cs35l56_hda_spi.c | 68 +++ 6 files changed, 1217 insertions(+) create mode 100644 sound/pci/hda/cs35l56_hda.c create mode 100644 sound/pci/hda/cs35l56_hda.h create mode 100644 sound/pci/hda/cs35l56_hda_i2c.c create mode 100644 sound/pci/hda/cs35l56_hda_spi.c diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 886255a03e8b..dd6922267a4b 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -130,6 +130,37 @@ config SND_HDA_SCODEC_CS35L41_SPI 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 || COMPILE_TEST + depends on SND_SOC + select CS_DSP + select SND_HDA_GENERIC + select SND_SOC_CS35L56_SHARED + select SND_HDA_SCODEC_CS35L56 + select SND_HDA_CS_DSP_CONTROLS + 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 || COMPILE_TEST + depends on SND_SOC + select CS_DSP + select SND_HDA_GENERIC + select SND_SOC_CS35L56_SHARED + select SND_HDA_SCODEC_CS35L56 + select SND_HDA_CS_DSP_CONTROLS + help + Say Y or M here to include CS35L56 amplifier support with + SPI control. + config SND_HDA_CODEC_REALTEK tristate "Build Realtek HD-audio codec support" select SND_HDA_GENERIC diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 00d306104484..c6e6509e7b8e 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -31,6 +31,9 @@ snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o snd-hda-scodec-cs35l41-objs := cs35l41_hda.o snd-hda-scodec-cs35l41-i2c-objs := cs35l41_hda_i2c.o snd-hda-scodec-cs35l41-spi-objs := cs35l41_hda_spi.o +snd-hda-scodec-cs35l56-objs := cs35l56_hda.o +snd-hda-scodec-cs35l56-i2c-objs := cs35l56_hda_i2c.o +snd-hda-scodec-cs35l56-spi-objs := cs35l56_hda_spi.o snd-hda-cs-dsp-ctls-objs := hda_cs_dsp_ctl.o # common driver @@ -55,6 +58,9 @@ obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.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_CS_DSP_CONTROLS) += snd-hda-cs-dsp-ctls.o # this must be the last entry after codec drivers; diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c new file mode 100644 index 000000000000..71e95e64f8a4 --- /dev/null +++ b/sound/pci/hda/cs35l56_hda.c @@ -0,0 +1,995 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// HDA audio driver for Cirrus Logic CS35L56 smart amp +// +// Copyright (C) 2023 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cs35l56_hda.h" +#include "hda_component.h" +#include "hda_cs_dsp_ctl.h" +#include "hda_generic.h" + + /* + * The cs35l56_hda_dai_config[] reg sequence configures the device as + * ASP1_BCLK_FREQ = 3.072 MHz + * ASP1_RX_WIDTH = 32 cycles per slot, ASP1_TX_WIDTH = 32 cycles per slot, ASP1_FMT = I2S + * ASP1_DOUT_HIZ_CONTROL = Hi-Z during unused timeslots + * ASP1_RX_WL = 24 bits per sample + * ASP1_TX_WL = 24 bits per sample + * ASP1_RXn_EN 1..3 and ASP1_TXn_EN 1..4 disabled + */ +static const struct reg_sequence cs35l56_hda_dai_config[] = { + { CS35L56_ASP1_CONTROL1, 0x00000021 }, + { CS35L56_ASP1_CONTROL2, 0x20200200 }, + { CS35L56_ASP1_CONTROL3, 0x00000003 }, + { CS35L56_ASP1_DATA_CONTROL5, 0x00000018 }, + { CS35L56_ASP1_DATA_CONTROL1, 0x00000018 }, + { CS35L56_ASP1_ENABLES1, 0x00000000 }, +}; + +static void cs35l56_hda_play(struct cs35l56_hda *cs35l56) +{ + unsigned int val; + int ret; + + pm_runtime_get_sync(cs35l56->base.dev); + ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PLAY); + if (ret == 0) { + /* Wait for firmware to enter PS0 power state */ + ret = regmap_read_poll_timeout(cs35l56->base.regmap, + CS35L56_TRANSDUCER_ACTUAL_PS, + val, (val == CS35L56_PS0), + CS35L56_PS0_POLL_US, + CS35L56_PS0_TIMEOUT_US); + if (ret) + dev_warn(cs35l56->base.dev, "PS0 wait failed: %d\n", ret); + } + regmap_set_bits(cs35l56->base.regmap, CS35L56_ASP1_ENABLES1, + BIT(CS35L56_ASP_RX1_EN_SHIFT) | BIT(CS35L56_ASP_RX2_EN_SHIFT) | + cs35l56->asp_tx_mask); + cs35l56->playing = true; +} + +static void cs35l56_hda_pause(struct cs35l56_hda *cs35l56) +{ + cs35l56->playing = false; + cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PAUSE); + regmap_clear_bits(cs35l56->base.regmap, CS35L56_ASP1_ENABLES1, + BIT(CS35L56_ASP_RX1_EN_SHIFT) | BIT(CS35L56_ASP_RX2_EN_SHIFT) | + 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); +} + +static void cs35l56_hda_playback_hook(struct device *dev, int action) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + + dev_dbg(cs35l56->base.dev, "%s()%d: action: %d\n", __func__, __LINE__, action); + + switch (action) { + case HDA_GEN_PCM_ACT_PREPARE: + if (cs35l56->playing) + break; + + /* If we're suspended: flag that resume should start playback */ + if (cs35l56->suspended) { + cs35l56->playing = true; + break; + } + + cs35l56_hda_play(cs35l56); + break; + case HDA_GEN_PCM_ACT_CLEANUP: + if (!cs35l56->playing) + break; + + cs35l56_hda_pause(cs35l56); + break; + default: + break; + } +} + +static int __maybe_unused cs35l56_hda_runtime_suspend(struct device *dev) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + + if (cs35l56->cs_dsp.booted) + cs_dsp_stop(&cs35l56->cs_dsp); + + return cs35l56_runtime_suspend_common(&cs35l56->base); +} + +static int __maybe_unused cs35l56_hda_runtime_resume(struct device *dev) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + int ret; + + ret = cs35l56_runtime_resume_common(&cs35l56->base, false); + if (ret < 0) + return ret; + + if (cs35l56->cs_dsp.booted) { + ret = cs_dsp_run(&cs35l56->cs_dsp); + if (ret) { + dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret); + goto err; + } + } + + return 0; + +err: + cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE); + regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, + CS35L56_MBOX_CMD_HIBERNATE_NOW); + + regcache_cache_only(cs35l56->base.regmap, true); + + return ret; +} + +static int cs35l56_hda_mixer_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = CS35L56_NUM_INPUT_SRC; + if (uinfo->value.enumerated.item >= CS35L56_NUM_INPUT_SRC) + uinfo->value.enumerated.item = CS35L56_NUM_INPUT_SRC - 1; + strscpy(uinfo->value.enumerated.name, cs35l56_tx_input_texts[uinfo->value.enumerated.item], + sizeof(uinfo->value.enumerated.name)); + + return 0; +} + +static int cs35l56_hda_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data; + unsigned int reg_val; + int i; + + regmap_read(cs35l56->base.regmap, kcontrol->private_value, ®_val); + reg_val &= CS35L56_ASP_TXn_SRC_MASK; + + for (i = 0; i < CS35L56_NUM_INPUT_SRC; ++i) { + if (cs35l56_tx_input_values[i] == reg_val) { + ucontrol->value.enumerated.item[0] = i; + break; + } + } + + return 0; +} + +static int cs35l56_hda_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data; + unsigned int item = ucontrol->value.enumerated.item[0]; + bool changed; + + if (item >= CS35L56_NUM_INPUT_SRC) + return -EINVAL; + + regmap_update_bits_check(cs35l56->base.regmap, kcontrol->private_value, + CS35L56_INPUT_MASK, cs35l56_tx_input_values[item], + &changed); + + return changed; +} + +static int cs35l56_hda_posture_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 = CS35L56_MAIN_POSTURE_MIN; + uinfo->value.integer.max = CS35L56_MAIN_POSTURE_MAX; + return 0; +} + +static int cs35l56_hda_posture_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data; + unsigned int pos; + int ret; + + ret = regmap_read(cs35l56->base.regmap, CS35L56_MAIN_POSTURE_NUMBER, &pos); + if (ret) + return ret; + + ucontrol->value.integer.value[0] = pos; + + return ret; +} + +static int cs35l56_hda_posture_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data; + unsigned long pos = ucontrol->value.integer.value[0]; + bool changed; + int ret; + + if ((pos < CS35L56_MAIN_POSTURE_MIN) || + (pos > CS35L56_MAIN_POSTURE_MAX)) + return -EINVAL; + + ret = regmap_update_bits_check(cs35l56->base.regmap, + CS35L56_MAIN_POSTURE_NUMBER, + CS35L56_MAIN_POSTURE_MASK, + pos, &changed); + if (ret) + return ret; + + return changed; +} + +static const struct { + const char *name; + unsigned int reg; +} cs35l56_hda_mixer_controls[] = { + { "ASP1 TX1 Source", CS35L56_ASP1TX1_INPUT }, + { "ASP1 TX2 Source", CS35L56_ASP1TX2_INPUT }, + { "ASP1 TX3 Source", CS35L56_ASP1TX3_INPUT }, + { "ASP1 TX4 Source", CS35L56_ASP1TX4_INPUT }, +}; + +static const DECLARE_TLV_DB_SCALE(cs35l56_hda_vol_tlv, -10000, 25, 0); + +static int cs35l56_hda_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.step = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = CS35L56_MAIN_RENDER_USER_VOLUME_MAX - + CS35L56_MAIN_RENDER_USER_VOLUME_MIN; + + return 0; +} + +static int cs35l56_hda_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data; + unsigned int raw_vol; + int vol; + int ret; + + ret = regmap_read(cs35l56->base.regmap, CS35L56_MAIN_RENDER_USER_VOLUME, &raw_vol); + + if (ret) + return ret; + + vol = (s16)(raw_vol & 0xFFFF); + vol >>= CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT; + + if (vol & BIT(CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT)) + vol |= ~((int)(BIT(CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT) - 1)); + + ucontrol->value.integer.value[0] = vol - CS35L56_MAIN_RENDER_USER_VOLUME_MIN; + + return 0; +} + +static int cs35l56_hda_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data; + long vol = ucontrol->value.integer.value[0]; + unsigned int raw_vol; + bool changed; + int ret; + + if ((vol < 0) || (vol > (CS35L56_MAIN_RENDER_USER_VOLUME_MAX - + CS35L56_MAIN_RENDER_USER_VOLUME_MIN))) + return -EINVAL; + + raw_vol = (vol + CS35L56_MAIN_RENDER_USER_VOLUME_MIN) << + CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT; + + ret = regmap_update_bits_check(cs35l56->base.regmap, + CS35L56_MAIN_RENDER_USER_VOLUME, + CS35L56_MAIN_RENDER_USER_VOLUME_MASK, + raw_vol, &changed); + if (ret) + return ret; + + return changed; +} + +static void cs35l56_hda_create_controls(struct cs35l56_hda *cs35l56) +{ + struct snd_kcontrol_new ctl_template = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = cs35l56_hda_posture_info, + .get = cs35l56_hda_posture_get, + .put = cs35l56_hda_posture_put, + }; + char name[64]; + int i; + + snprintf(name, sizeof(name), "%s Posture Number", cs35l56->amp_name); + ctl_template.name = name; + cs35l56->posture_ctl = snd_ctl_new1(&ctl_template, cs35l56); + if (snd_ctl_add(cs35l56->codec->card, cs35l56->posture_ctl)) + dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n", ctl_template.name); + + /* Mixer controls */ + ctl_template.info = cs35l56_hda_mixer_info; + ctl_template.get = cs35l56_hda_mixer_get; + ctl_template.put = cs35l56_hda_mixer_put; + + BUILD_BUG_ON(ARRAY_SIZE(cs35l56->mixer_ctl) != ARRAY_SIZE(cs35l56_hda_mixer_controls)); + + for (i = 0; i < ARRAY_SIZE(cs35l56_hda_mixer_controls); ++i) { + snprintf(name, sizeof(name), "%s %s", cs35l56->amp_name, + cs35l56_hda_mixer_controls[i].name); + ctl_template.private_value = cs35l56_hda_mixer_controls[i].reg; + cs35l56->mixer_ctl[i] = snd_ctl_new1(&ctl_template, cs35l56); + if (snd_ctl_add(cs35l56->codec->card, cs35l56->mixer_ctl[i])) { + dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n", + ctl_template.name); + } + } + + ctl_template.info = cs35l56_hda_vol_info; + ctl_template.get = cs35l56_hda_vol_get; + ctl_template.put = cs35l56_hda_vol_put; + ctl_template.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ); + ctl_template.tlv.p = cs35l56_hda_vol_tlv; + snprintf(name, sizeof(name), "%s Speaker Playback Volume", cs35l56->amp_name); + ctl_template.name = name; + cs35l56->volume_ctl = snd_ctl_new1(&ctl_template, cs35l56); + if (snd_ctl_add(cs35l56->codec->card, cs35l56->volume_ctl)) + dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n", ctl_template.name); +} + +static void cs35l56_hda_remove_controls(struct cs35l56_hda *cs35l56) +{ + int i; + + for (i = ARRAY_SIZE(cs35l56->mixer_ctl) - 1; i >= 0; i--) + snd_ctl_remove(cs35l56->codec->card, cs35l56->mixer_ctl[i]); + + snd_ctl_remove(cs35l56->codec->card, cs35l56->posture_ctl); + snd_ctl_remove(cs35l56->codec->card, cs35l56->volume_ctl); +} + +static const struct cs_dsp_client_ops cs35l56_hda_client_ops = { + .control_remove = hda_cs_dsp_control_remove, +}; + +static int cs35l56_hda_request_firmware_file(struct cs35l56_hda *cs35l56, + const struct firmware **firmware, char **filename, + const char *dir, const char *system_name, + const char *amp_name, + const char *filetype) +{ + char *s, c; + int ret = 0; + + if (system_name && amp_name) + *filename = kasprintf(GFP_KERNEL, "%scs35l56%s-%02x-dsp1-misc-%s-%s.%s", dir, + cs35l56->base.secured ? "s" : "", cs35l56->base.rev, + system_name, amp_name, filetype); + else if (system_name) + *filename = kasprintf(GFP_KERNEL, "%scs35l56%s-%02x-dsp1-misc-%s.%s", dir, + cs35l56->base.secured ? "s" : "", cs35l56->base.rev, + system_name, filetype); + else + *filename = kasprintf(GFP_KERNEL, "%scs35l56%s-%02x-dsp1-misc.%s", dir, + cs35l56->base.secured ? "s" : "", cs35l56->base.rev, + filetype); + + if (!*filename) + return -ENOMEM; + + /* + * Make sure that filename is lower-case and any non alpha-numeric + * characters except full stop and forward slash are replaced with + * hyphens. + */ + s = *filename; + while (*s) { + c = *s; + if (isalnum(c)) + *s = tolower(c); + else if (c != '.' && c != '/') + *s = '-'; + s++; + } + + ret = firmware_request_nowarn(firmware, *filename, cs35l56->base.dev); + if (ret) { + dev_dbg(cs35l56->base.dev, "Failed to request '%s'\n", *filename); + kfree(*filename); + *filename = NULL; + return ret; + } + + dev_dbg(cs35l56->base.dev, "Found '%s'\n", *filename); + + return 0; +} + +static const char cirrus_dir[] = "cirrus/"; +static void cs35l56_hda_request_firmware_files(struct cs35l56_hda *cs35l56, + const struct firmware **wmfw_firmware, + char **wmfw_filename, + const struct firmware **coeff_firmware, + char **coeff_filename) +{ + const char *system_name = cs35l56->system_name; + const char *amp_name = cs35l56->amp_name; + int ret; + + if (system_name && amp_name) { + if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename, + cirrus_dir, system_name, amp_name, "wmfw")) { + cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename, + cirrus_dir, system_name, amp_name, "bin"); + return; + } + } + + if (system_name) { + if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename, + cirrus_dir, system_name, NULL, "wmfw")) { + if (amp_name) + cs35l56_hda_request_firmware_file(cs35l56, + coeff_firmware, coeff_filename, + cirrus_dir, system_name, + amp_name, "bin"); + if (!*coeff_firmware) + cs35l56_hda_request_firmware_file(cs35l56, + coeff_firmware, coeff_filename, + cirrus_dir, system_name, + NULL, "bin"); + return; + } + } + + ret = cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename, + cirrus_dir, NULL, NULL, "wmfw"); + if (!ret) { + cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename, + cirrus_dir, NULL, NULL, "bin"); + return; + } + + /* When a firmware file is not found must still search for the coeff files */ + if (system_name) { + if (amp_name) + cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename, + cirrus_dir, system_name, amp_name, "bin"); + if (!*coeff_firmware) + cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename, + cirrus_dir, system_name, NULL, "bin"); + } + + if (!*coeff_firmware) + cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename, + cirrus_dir, NULL, NULL, "bin"); +} + +static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmware, + char *wmfw_filename, + const struct firmware *coeff_firmware, + char *coeff_filename) +{ + if (wmfw_firmware) + release_firmware(wmfw_firmware); + kfree(wmfw_filename); + + if (coeff_firmware) + release_firmware(coeff_firmware); + kfree(coeff_filename); +} + +static void cs35l56_hda_add_dsp_controls(struct cs35l56_hda *cs35l56) +{ + struct hda_cs_dsp_ctl_info info; + + info.device_name = cs35l56->amp_name; + info.fw_type = HDA_CS_DSP_FW_MISC; + info.card = cs35l56->codec->card; + + hda_cs_dsp_add_controls(&cs35l56->cs_dsp, &info); +} + +static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) +{ + const struct firmware *coeff_firmware = NULL; + const struct firmware *wmfw_firmware = NULL; + char *coeff_filename = NULL; + char *wmfw_filename = NULL; + int ret = 0; + + cs35l56_hda_request_firmware_files(cs35l56, &wmfw_firmware, &wmfw_filename, + &coeff_firmware, &coeff_filename); + + /* Nothing to do - no firmware files were found to download */ + if (!wmfw_filename && !coeff_filename) + return 0; + + mutex_lock(&cs35l56->base.irq_lock); + pm_runtime_get_sync(cs35l56->base.dev); + + /* + * When the device is running in secure mode the firmware files can + * only contain insecure tunings and therefore we do not need to + * shutdown the firmware to apply them and can use the lower cost + * reinit sequence instead. + */ + if (!cs35l56->base.secured) { + ret = cs35l56_firmware_shutdown(&cs35l56->base); + if (ret) + goto err; + } + + ret = cs_dsp_power_up(&cs35l56->cs_dsp, wmfw_firmware, wmfw_filename, + coeff_firmware, coeff_filename, "misc"); + if (ret) { + dev_dbg(cs35l56->base.dev, "%s: cs_dsp_power_up ret %d\n", __func__, ret); + goto err; + } + + if (wmfw_filename) + dev_dbg(cs35l56->base.dev, "Loaded WMFW Firmware: %s\n", wmfw_filename); + + if (coeff_filename) + dev_dbg(cs35l56->base.dev, "Loaded Coefficients: %s\n", coeff_filename); + + ret = cs_dsp_run(&cs35l56->cs_dsp); + if (ret) { + dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret); + goto err; + } + + if (cs35l56->base.secured) { + ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT); + if (ret) + goto err; + } else { + /* Reset the device and wait for it to boot */ + cs35l56_system_reset(&cs35l56->base, false); + ret = cs35l56_wait_for_firmware_boot(&cs35l56->base); + if (ret) + goto err; + } + + /* Disable auto-hibernate so that runtime_pm has control */ + ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE); + if (ret) + goto err; + + regcache_mark_dirty(cs35l56->base.regmap); + regcache_sync(cs35l56->base.regmap); + + regmap_clear_bits(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, + CS35L56_FIRMWARE_MISSING); + cs35l56->base.fw_patched = true; +err: + pm_runtime_put(cs35l56->base.dev); + mutex_unlock(&cs35l56->base.irq_lock); + + cs35l56_hda_release_firmware_files(wmfw_firmware, wmfw_filename, + coeff_firmware, coeff_filename); + + return ret; +} + +static int cs35l56_hda_bind(struct device *dev, struct device *master, void *master_data) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + struct hda_component *comps = master_data; + int ret; + + if (!comps || cs35l56->index < 0 || cs35l56->index >= HDA_MAX_COMPONENTS) + return -EINVAL; + + comps = &comps[cs35l56->index]; + if (comps->dev) + return -EBUSY; + + comps->dev = dev; + cs35l56->codec = comps->codec; + strscpy(comps->name, dev_name(dev), sizeof(comps->name)); + comps->playback_hook = cs35l56_hda_playback_hook; + + ret = cs35l56_hda_fw_load(cs35l56); + if (ret) + return ret; + + cs35l56_hda_create_controls(cs35l56); + cs35l56_hda_add_dsp_controls(cs35l56); + +#if IS_ENABLED(CONFIG_SND_DEBUG) + cs35l56->debugfs_root = debugfs_create_dir(dev_name(cs35l56->base.dev), sound_debugfs_root); + cs_dsp_init_debugfs(&cs35l56->cs_dsp, cs35l56->debugfs_root); +#endif + + dev_dbg(cs35l56->base.dev, "Bound\n"); + + return 0; +} + +static void cs35l56_hda_unbind(struct device *dev, struct device *master, void *master_data) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + struct hda_component *comps = master_data; + + cs35l56_hda_remove_controls(cs35l56); + +#if IS_ENABLED(CONFIG_SND_DEBUG) + cs_dsp_cleanup_debugfs(&cs35l56->cs_dsp); + debugfs_remove_recursive(cs35l56->debugfs_root); +#endif + + cs_dsp_remove(&cs35l56->cs_dsp); + + if (comps[cs35l56->index].dev == dev) + memset(&comps[cs35l56->index], 0, sizeof(*comps)); + + dev_dbg(cs35l56->base.dev, "Unbound\n"); +} + +static const struct component_ops cs35l56_hda_comp_ops = { + .bind = cs35l56_hda_bind, + .unbind = cs35l56_hda_unbind, +}; + +static int cs35l56_hda_system_suspend(struct device *dev) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + + if (cs35l56->playing) + cs35l56_hda_pause(cs35l56); + + cs35l56->suspended = true; + + /* + * The interrupt line is normally shared, but after we start suspending + * we can't check if our device is the source of an interrupt, and can't + * clear it. Prevent this race by temporarily disabling the parent irq + * until we reach _no_irq. + */ + if (cs35l56->base.irq) + disable_irq(cs35l56->base.irq); + + return pm_runtime_force_suspend(dev); +} + +static int cs35l56_hda_system_suspend_late(struct device *dev) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + + /* + * RESET is usually shared by all amps so it must not be asserted until + * all driver instances have done their suspend() stage. + */ + if (cs35l56->base.reset_gpio) { + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); + cs35l56_wait_min_reset_pulse(); + } + + return 0; +} + +static int cs35l56_hda_system_suspend_no_irq(struct device *dev) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + + /* Handlers are now disabled so the parent IRQ can safely be re-enabled. */ + if (cs35l56->base.irq) + enable_irq(cs35l56->base.irq); + + return 0; +} + +static int cs35l56_hda_system_resume_no_irq(struct device *dev) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + + /* + * WAKE interrupts unmask if the CS35L56 hibernates, which can cause + * spurious interrupts, and the interrupt line is normally shared. + * We can't check if our device is the source of an interrupt, and can't + * clear it, until it has fully resumed. Prevent this race by temporarily + * disabling the parent irq until we complete resume(). + */ + if (cs35l56->base.irq) + disable_irq(cs35l56->base.irq); + + return 0; +} + +static int cs35l56_hda_system_resume_early(struct device *dev) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + + /* Ensure a spec-compliant RESET pulse. */ + if (cs35l56->base.reset_gpio) { + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); + cs35l56_wait_min_reset_pulse(); + + /* Release shared RESET before drivers start resume(). */ + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1); + cs35l56_wait_control_port_ready(); + } + + return 0; +} + +static int cs35l56_hda_system_resume(struct device *dev) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + int ret; + + /* Undo pm_runtime_force_suspend() before re-enabling the irq */ + ret = pm_runtime_force_resume(dev); + if (cs35l56->base.irq) + enable_irq(cs35l56->base.irq); + + if (ret) + return ret; + + cs35l56->suspended = false; + + ret = cs35l56_is_fw_reload_needed(&cs35l56->base); + dev_dbg(cs35l56->base.dev, "fw_reload_needed: %d\n", ret); + if (ret > 0) { + ret = cs35l56_hda_fw_load(cs35l56); + if (ret) + return ret; + } + + if (cs35l56->playing) + cs35l56_hda_play(cs35l56); + + return 0; +} + +static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int id) +{ + u32 values[HDA_MAX_COMPONENTS]; + struct acpi_device *adev; + const char *property, *sub; + size_t nval; + int i, ret; + + /* + * ACPI_COMPANION isn't available when this driver was instantiated by + * the serial-multi-instantiate driver, so lookup the node by HID + */ + if (!ACPI_COMPANION(cs35l56->base.dev)) { + adev = acpi_dev_get_first_match_dev("CSC3556", NULL, -1); + if (!adev) { + dev_err(cs35l56->base.dev, "Failed to find an ACPI device for %s\n", + dev_name(cs35l56->base.dev)); + return -ENODEV; + } + ACPI_COMPANION_SET(cs35l56->base.dev, adev); + } + + property = "cirrus,dev-index"; + ret = device_property_count_u32(cs35l56->base.dev, property); + if (ret <= 0) + goto err; + + if (ret > ARRAY_SIZE(values)) { + ret = -EINVAL; + goto err; + } + nval = ret; + + ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval); + if (ret) + goto err; + + cs35l56->index = -1; + for (i = 0; i < nval; i++) { + if (values[i] == id) { + cs35l56->index = i; + break; + } + } + if (cs35l56->index == -1) { + dev_err(cs35l56->base.dev, "No index found in %s\n", property); + ret = -ENODEV; + goto err; + } + + sub = acpi_get_subsystem_id(ACPI_HANDLE(cs35l56->base.dev)); + + if (IS_ERR(sub)) { + /* If no ACPI SUB, return 0 and fallback to legacy firmware path, otherwise fail */ + if (PTR_ERR(sub) == -ENODATA) + return 0; + else + return PTR_ERR(sub); + } + + cs35l56->system_name = sub; + + cs35l56->base.reset_gpio = devm_gpiod_get_index_optional(cs35l56->base.dev, + "reset", + cs35l56->index, + GPIOD_OUT_LOW); + if (IS_ERR(cs35l56->base.reset_gpio)) { + ret = PTR_ERR(cs35l56->base.reset_gpio); + + /* + * If RESET is shared the first amp to probe will grab the reset + * line and reset all the amps + */ + if (ret != -EBUSY) + return dev_err_probe(cs35l56->base.dev, ret, "Failed to get reset GPIO\n"); + + dev_info(cs35l56->base.dev, "Reset GPIO busy, assume shared reset\n"); + cs35l56->base.reset_gpio = NULL; + } + + return 0; + +err: + dev_err(cs35l56->base.dev, "Failed property %s: %d\n", property, ret); + + return ret; +} + +int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id) +{ + int ret; + + mutex_init(&cs35l56->base.irq_lock); + dev_set_drvdata(cs35l56->base.dev, cs35l56); + + ret = cs35l56_hda_read_acpi(cs35l56, id); + if (ret) { + dev_err_probe(cs35l56->base.dev, ret, "Platform not supported\n"); + goto err; + } + + cs35l56->amp_name = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, "AMP%d", + cs35l56->index + 1); + if (!cs35l56->amp_name) { + ret = -ENOMEM; + goto err; + } + + cs35l56_init_cs_dsp(&cs35l56->base, &cs35l56->cs_dsp); + cs35l56->cs_dsp.client_ops = &cs35l56_hda_client_ops; + + if (cs35l56->base.reset_gpio) { + dev_dbg(cs35l56->base.dev, "Hard reset\n"); + + /* + * The GPIOD_OUT_LOW to *_gpiod_get_*() will be ignored if the + * ACPI defines a different default state. So explicitly set low. + */ + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); + cs35l56_wait_min_reset_pulse(); + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1); + } + + ret = cs35l56_hw_init(&cs35l56->base); + if (ret < 0) + goto err; + + /* Reset the device and wait for it to boot */ + cs35l56_system_reset(&cs35l56->base, false); + ret = cs35l56_wait_for_firmware_boot(&cs35l56->base); + if (ret) + goto err; + + ret = cs35l56_set_patch(&cs35l56->base); + if (ret) + return ret; + + regcache_mark_dirty(cs35l56->base.regmap); + regcache_sync(cs35l56->base.regmap); + + /* Disable auto-hibernate so that runtime_pm has control */ + ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE); + if (ret) + goto err; + + ret = cs_dsp_halo_init(&cs35l56->cs_dsp); + if (ret) { + dev_err_probe(cs35l56->base.dev, ret, "cs_dsp_halo_init failed\n"); + goto err; + } + + dev_dbg(cs35l56->base.dev, "DSP system name: '%s', amp name: '%s'\n", + cs35l56->system_name, cs35l56->amp_name); + + regmap_multi_reg_write(cs35l56->base.regmap, cs35l56_hda_dai_config, + ARRAY_SIZE(cs35l56_hda_dai_config)); + + /* + * By default only enable one ASP1TXn, where n=amplifier index, + * This prevents multiple amps trying to drive the same slot. + */ + cs35l56->asp_tx_mask = BIT(cs35l56->index); + + pm_runtime_set_autosuspend_delay(cs35l56->base.dev, 3000); + pm_runtime_use_autosuspend(cs35l56->base.dev); + pm_runtime_set_active(cs35l56->base.dev); + pm_runtime_mark_last_busy(cs35l56->base.dev); + pm_runtime_enable(cs35l56->base.dev); + + ret = component_add(cs35l56->base.dev, &cs35l56_hda_comp_ops); + if (ret) { + dev_err(cs35l56->base.dev, "Register component failed: %d\n", ret); + goto pm_err; + } + + cs35l56->base.init_done = true; + + return 0; + +pm_err: + pm_runtime_disable(cs35l56->base.dev); +err: + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_hda_common_probe, SND_HDA_SCODEC_CS35L56); + +void cs35l56_hda_remove(struct device *dev) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + + pm_runtime_get_sync(cs35l56->base.dev); + pm_runtime_disable(cs35l56->base.dev); + + component_del(cs35l56->base.dev, &cs35l56_hda_comp_ops); + + kfree(cs35l56->system_name); + pm_runtime_put_noidle(cs35l56->base.dev); + + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); +} +EXPORT_SYMBOL_NS_GPL(cs35l56_hda_remove, SND_HDA_SCODEC_CS35L56); + +const struct dev_pm_ops cs35l56_hda_pm_ops = { + SET_RUNTIME_PM_OPS(cs35l56_hda_runtime_suspend, cs35l56_hda_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend, cs35l56_hda_system_resume) + LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_late, + cs35l56_hda_system_resume_early) + NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_no_irq, + cs35l56_hda_system_resume_no_irq) +}; +EXPORT_SYMBOL_NS_GPL(cs35l56_hda_pm_ops, SND_HDA_SCODEC_CS35L56); + +MODULE_DESCRIPTION("CS35L56 HDA Driver"); +MODULE_IMPORT_NS(SND_HDA_CS_DSP_CONTROLS); +MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED); +MODULE_AUTHOR("Richard Fitzgerald "); +MODULE_AUTHOR("Simon Trimmer "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(FW_CS_DSP); diff --git a/sound/pci/hda/cs35l56_hda.h b/sound/pci/hda/cs35l56_hda.h new file mode 100644 index 000000000000..6e5bc5397db5 --- /dev/null +++ b/sound/pci/hda/cs35l56_hda.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * HDA audio driver for Cirrus Logic CS35L56 smart amp + * + * Copyright (C) 2023 Cirrus Logic, Inc. and + * Cirrus Logic International Semiconductor Ltd. + */ + +#ifndef __CS35L56_HDA_H__ +#define __CS35L56_HDA_H__ + +#include +#include +#include +#include +#include +#include + +struct dentry; + +struct cs35l56_hda { + struct cs35l56_base base; + struct hda_codec *codec; + + int index; + const char *system_name; + const char *amp_name; + + struct cs_dsp cs_dsp; + bool playing; + bool suspended; + u8 asp_tx_mask; + + struct snd_kcontrol *posture_ctl; + struct snd_kcontrol *volume_ctl; + struct snd_kcontrol *mixer_ctl[4]; + +#if IS_ENABLED(CONFIG_SND_DEBUG) + struct dentry *debugfs_root; +#endif +}; + +extern const struct dev_pm_ops cs35l56_hda_pm_ops; + +int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id); +void cs35l56_hda_remove(struct device *dev); + +#endif /*__CS35L56_HDA_H__*/ diff --git a/sound/pci/hda/cs35l56_hda_i2c.c b/sound/pci/hda/cs35l56_hda_i2c.c new file mode 100644 index 000000000000..83e4acdd89ac --- /dev/null +++ b/sound/pci/hda/cs35l56_hda_i2c.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// CS35L56 HDA audio driver I2C binding +// +// Copyright (C) 2023 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include +#include +#include + +#include "cs35l56_hda.h" + +static int cs35l56_hda_i2c_probe(struct i2c_client *clt) +{ + struct cs35l56_hda *cs35l56; + int ret; + + cs35l56 = devm_kzalloc(&clt->dev, sizeof(*cs35l56), GFP_KERNEL); + if (!cs35l56) + return -ENOMEM; + + cs35l56->base.dev = &clt->dev; + cs35l56->base.can_hibernate = true; + cs35l56->base.regmap = devm_regmap_init_i2c(clt, &cs35l56_regmap_i2c); + if (IS_ERR(cs35l56->base.regmap)) { + ret = PTR_ERR(cs35l56->base.regmap); + dev_err(cs35l56->base.dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + ret = cs35l56_hda_common_probe(cs35l56, clt->addr); + if (ret) + return ret; + ret = cs35l56_irq_request(&cs35l56->base, clt->irq); + if (ret < 0) + cs35l56_hda_remove(cs35l56->base.dev); + + return ret; +} + +static void cs35l56_hda_i2c_remove(struct i2c_client *clt) +{ + cs35l56_hda_remove(&clt->dev); +} + +static const struct i2c_device_id cs35l56_hda_i2c_id[] = { + { "cs35l56-hda", 0 }, + {} +}; + +static struct i2c_driver cs35l56_hda_i2c_driver = { + .driver = { + .name = "cs35l56-hda", + .pm = &cs35l56_hda_pm_ops, + }, + .id_table = cs35l56_hda_i2c_id, + .probe = cs35l56_hda_i2c_probe, + .remove = cs35l56_hda_i2c_remove, +}; +module_i2c_driver(cs35l56_hda_i2c_driver); + +MODULE_DESCRIPTION("HDA CS35L56 I2C driver"); +MODULE_IMPORT_NS(SND_HDA_SCODEC_CS35L56); +MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED); +MODULE_AUTHOR("Richard Fitzgerald "); +MODULE_AUTHOR("Simon Trimmer "); +MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/cs35l56_hda_spi.c b/sound/pci/hda/cs35l56_hda_spi.c new file mode 100644 index 000000000000..756aec342eab --- /dev/null +++ b/sound/pci/hda/cs35l56_hda_spi.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// CS35L56 HDA audio driver SPI binding +// +// Copyright (C) 2023 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include +#include +#include + +#include "cs35l56_hda.h" + +static int cs35l56_hda_spi_probe(struct spi_device *spi) +{ + struct cs35l56_hda *cs35l56; + int ret; + + cs35l56 = devm_kzalloc(&spi->dev, sizeof(*cs35l56), GFP_KERNEL); + if (!cs35l56) + return -ENOMEM; + + cs35l56->base.dev = &spi->dev; + cs35l56->base.regmap = devm_regmap_init_spi(spi, &cs35l56_regmap_spi); + if (IS_ERR(cs35l56->base.regmap)) { + ret = PTR_ERR(cs35l56->base.regmap); + dev_err(cs35l56->base.dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + ret = cs35l56_hda_common_probe(cs35l56, spi->chip_select); + if (ret) + return ret; + ret = cs35l56_irq_request(&cs35l56->base, spi->irq); + if (ret < 0) + cs35l56_hda_remove(cs35l56->base.dev); + + return ret; +} + +static void cs35l56_hda_spi_remove(struct spi_device *spi) +{ + cs35l56_hda_remove(&spi->dev); +} + +static const struct spi_device_id cs35l56_hda_spi_id[] = { + { "cs35l56-hda", 0 }, + {} +}; + +static struct spi_driver cs35l56_hda_spi_driver = { + .driver = { + .name = "cs35l56-hda", + .pm = &cs35l56_hda_pm_ops, + }, + .id_table = cs35l56_hda_spi_id, + .probe = cs35l56_hda_spi_probe, + .remove = cs35l56_hda_spi_remove, +}; +module_spi_driver(cs35l56_hda_spi_driver); + +MODULE_DESCRIPTION("HDA CS35L56 SPI driver"); +MODULE_IMPORT_NS(SND_HDA_SCODEC_CS35L56); +MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED); +MODULE_AUTHOR("Richard Fitzgerald "); +MODULE_AUTHOR("Simon Trimmer "); +MODULE_LICENSE("GPL"); From f54e3474507427bf272bcc79c7c248c7f55d45b4 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 21 Jul 2023 09:50:27 -0700 Subject: [PATCH 235/334] ASoC: codecs: lpass: Log clk_get() failures The LPASS macro drivers all acquire a number of clocks, but give no indication when clk_get() fails, making it hard to identify and debug system configuration issues. Make these drivers provide useful debug information when this happens. Signed-off-by: Bjorn Andersson Reviewed-by: Andrew Halaney Link: https://lore.kernel.org/r/20230721165027.2155528-1-quic_bjorande@quicinc.com Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 10 +++++----- sound/soc/codecs/lpass-tx-macro.c | 10 +++++----- sound/soc/codecs/lpass-va-macro.c | 6 +++--- sound/soc/codecs/lpass-wsa-macro.c | 10 +++++----- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 685ca95ef4a9..29197d34ec09 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -3537,25 +3537,25 @@ static int rx_macro_probe(struct platform_device *pdev) rx->macro = devm_clk_get_optional(dev, "macro"); if (IS_ERR(rx->macro)) - return PTR_ERR(rx->macro); + return dev_err_probe(dev, PTR_ERR(rx->macro), "unable to get macro clock\n"); rx->dcodec = devm_clk_get_optional(dev, "dcodec"); if (IS_ERR(rx->dcodec)) - return PTR_ERR(rx->dcodec); + return dev_err_probe(dev, PTR_ERR(rx->dcodec), "unable to get dcodec clock\n"); rx->mclk = devm_clk_get(dev, "mclk"); if (IS_ERR(rx->mclk)) - return PTR_ERR(rx->mclk); + return dev_err_probe(dev, PTR_ERR(rx->mclk), "unable to get mclk clock\n"); if (flags & LPASS_MACRO_FLAG_HAS_NPL_CLOCK) { rx->npl = devm_clk_get(dev, "npl"); if (IS_ERR(rx->npl)) - return PTR_ERR(rx->npl); + return dev_err_probe(dev, PTR_ERR(rx->npl), "unable to get npl clock\n"); } rx->fsgen = devm_clk_get(dev, "fsgen"); if (IS_ERR(rx->fsgen)) - return PTR_ERR(rx->fsgen); + return dev_err_probe(dev, PTR_ERR(rx->fsgen), "unable to get fsgen clock\n"); rx->pds = lpass_macro_pds_init(dev); if (IS_ERR(rx->pds)) diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index de978c3d70b7..3e33418898e8 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -1967,25 +1967,25 @@ static int tx_macro_probe(struct platform_device *pdev) tx->macro = devm_clk_get_optional(dev, "macro"); if (IS_ERR(tx->macro)) - return PTR_ERR(tx->macro); + return dev_err_probe(dev, PTR_ERR(tx->macro), "unable to get macro clock\n"); tx->dcodec = devm_clk_get_optional(dev, "dcodec"); if (IS_ERR(tx->dcodec)) - return PTR_ERR(tx->dcodec); + return dev_err_probe(dev, PTR_ERR(tx->dcodec), "unable to get dcodec clock\n"); tx->mclk = devm_clk_get(dev, "mclk"); if (IS_ERR(tx->mclk)) - return PTR_ERR(tx->mclk); + return dev_err_probe(dev, PTR_ERR(tx->mclk), "unable to get mclk clock\n"); if (flags & LPASS_MACRO_FLAG_HAS_NPL_CLOCK) { tx->npl = devm_clk_get(dev, "npl"); if (IS_ERR(tx->npl)) - return PTR_ERR(tx->npl); + return dev_err_probe(dev, PTR_ERR(tx->npl), "unable to get npl clock\n"); } tx->fsgen = devm_clk_get(dev, "fsgen"); if (IS_ERR(tx->fsgen)) - return PTR_ERR(tx->fsgen); + return dev_err_probe(dev, PTR_ERR(tx->fsgen), "unable to get fsgen clock\n"); tx->pds = lpass_macro_pds_init(dev); if (IS_ERR(tx->pds)) diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index 74724448da50..b71ef03c4aef 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -1457,15 +1457,15 @@ static int va_macro_probe(struct platform_device *pdev) va->macro = devm_clk_get_optional(dev, "macro"); if (IS_ERR(va->macro)) - return PTR_ERR(va->macro); + return dev_err_probe(dev, PTR_ERR(va->macro), "unable to get macro clock\n"); va->dcodec = devm_clk_get_optional(dev, "dcodec"); if (IS_ERR(va->dcodec)) - return PTR_ERR(va->dcodec); + return dev_err_probe(dev, PTR_ERR(va->dcodec), "unable to get dcodec clock\n"); va->mclk = devm_clk_get(dev, "mclk"); if (IS_ERR(va->mclk)) - return PTR_ERR(va->mclk); + return dev_err_probe(dev, PTR_ERR(va->mclk), "unable to get mclk clock\n"); va->pds = lpass_macro_pds_init(dev); if (IS_ERR(va->pds)) diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 8ba7dc89daaa..ec6859ec0d38 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -2396,25 +2396,25 @@ static int wsa_macro_probe(struct platform_device *pdev) wsa->macro = devm_clk_get_optional(dev, "macro"); if (IS_ERR(wsa->macro)) - return PTR_ERR(wsa->macro); + return dev_err_probe(dev, PTR_ERR(wsa->macro), "unable to get macro clock\n"); wsa->dcodec = devm_clk_get_optional(dev, "dcodec"); if (IS_ERR(wsa->dcodec)) - return PTR_ERR(wsa->dcodec); + return dev_err_probe(dev, PTR_ERR(wsa->dcodec), "unable to get dcodec clock\n"); wsa->mclk = devm_clk_get(dev, "mclk"); if (IS_ERR(wsa->mclk)) - return PTR_ERR(wsa->mclk); + return dev_err_probe(dev, PTR_ERR(wsa->mclk), "unable to get mclk clock\n"); if (flags & LPASS_MACRO_FLAG_HAS_NPL_CLOCK) { wsa->npl = devm_clk_get(dev, "npl"); if (IS_ERR(wsa->npl)) - return PTR_ERR(wsa->npl); + return dev_err_probe(dev, PTR_ERR(wsa->npl), "unable to get npl clock\n"); } wsa->fsgen = devm_clk_get(dev, "fsgen"); if (IS_ERR(wsa->fsgen)) - return PTR_ERR(wsa->fsgen); + return dev_err_probe(dev, PTR_ERR(wsa->fsgen), "unable to get fsgen clock\n"); base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) From fa3efcc36aacdd8ac9372217970d0ed2eb293fcc Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:06 +0100 Subject: [PATCH 236/334] ALSA: cs35l41: Use mbox command to enable speaker output for external boost To enable the speaker output in external boost mode, 2 registers must be set, one after another. The longer the time between the writes of the two registers, the more likely, and more loudly a pop may occur. To minimize this, an mbox command can be used to allow the firmware to perform this action, minimizing any delay between write, thus minimizing any pop or click as a result. The old method will remain when running without firmware. Acked-by: Mark Brown Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20230721151816.2080453-2-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- include/sound/cs35l41.h | 5 ++- sound/pci/hda/cs35l41_hda.c | 9 ++-- sound/soc/codecs/cs35l41-lib.c | 76 +++++++++++++++++++++++++++------- sound/soc/codecs/cs35l41.c | 8 ++-- 4 files changed, 74 insertions(+), 24 deletions(-) diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h index 7239d943942c..1bf757901d02 100644 --- a/include/sound/cs35l41.h +++ b/include/sound/cs35l41.h @@ -829,6 +829,7 @@ enum cs35l41_cspl_mbox_cmd { CSPL_MBOX_CMD_STOP_PRE_REINIT = 4, CSPL_MBOX_CMD_HIBERNATE = 5, CSPL_MBOX_CMD_OUT_OF_HIBERNATE = 6, + CSPL_MBOX_CMD_SPK_OUT_ENABLE = 7, CSPL_MBOX_CMD_UNKNOWN_CMD = -1, CSPL_MBOX_CMD_INVALID_SEQUENCE = -2, }; @@ -901,7 +902,7 @@ int cs35l41_exit_hibernate(struct device *dev, struct regmap *regmap); int cs35l41_init_boost(struct device *dev, struct regmap *regmap, struct cs35l41_hw_cfg *hw_cfg); bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type); -int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type, int enable, - struct completion *pll_lock); +int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l41_boost_type b_type, + int enable, struct completion *pll_lock, bool firmware_running); #endif /* __CS35L41_H */ diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index ce5faa620517..f9c97270db6f 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -514,13 +514,15 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action) break; case HDA_GEN_PCM_ACT_PREPARE: mutex_lock(&cs35l41->fw_mutex); - ret = cs35l41_global_enable(reg, cs35l41->hw_cfg.bst_type, 1, NULL); + ret = cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 1, NULL, + cs35l41->firmware_running); mutex_unlock(&cs35l41->fw_mutex); break; case HDA_GEN_PCM_ACT_CLEANUP: mutex_lock(&cs35l41->fw_mutex); regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute)); - ret = cs35l41_global_enable(reg, cs35l41->hw_cfg.bst_type, 0, NULL); + ret = cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 0, NULL, + cs35l41->firmware_running); mutex_unlock(&cs35l41->fw_mutex); break; case HDA_GEN_PCM_ACT_CLOSE: @@ -672,7 +674,8 @@ static int cs35l41_runtime_suspend(struct device *dev) if (cs35l41->playback_started) { regmap_multi_reg_write(cs35l41->regmap, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute)); - cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0, NULL); + cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0, + NULL, cs35l41->firmware_running); regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT); if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c index 1e4205295a0d..a7556fa33cdd 100644 --- a/sound/soc/codecs/cs35l41-lib.c +++ b/sound/soc/codecs/cs35l41-lib.c @@ -1080,28 +1080,32 @@ static const struct reg_sequence cs35l41_safe_to_reset[] = { { 0x00000040, 0x00000033 }, }; -static const struct reg_sequence cs35l41_active_to_safe[] = { +static const struct reg_sequence cs35l41_active_to_safe_start[] = { { 0x00000040, 0x00000055 }, { 0x00000040, 0x000000AA }, { 0x00007438, 0x00585941 }, { CS35L41_PWR_CTRL1, 0x00000000 }, - { 0x0000742C, 0x00000009, 3000 }, + { 0x0000742C, 0x00000009 }, +}; + +static const struct reg_sequence cs35l41_active_to_safe_end[] = { { 0x00007438, 0x00580941 }, { 0x00000040, 0x000000CC }, { 0x00000040, 0x00000033 }, }; -static const struct reg_sequence cs35l41_safe_to_active[] = { +static const struct reg_sequence cs35l41_safe_to_active_start[] = { { 0x00000040, 0x00000055 }, { 0x00000040, 0x000000AA }, { 0x0000742C, 0x0000000F }, { 0x0000742C, 0x00000079 }, { 0x00007438, 0x00585941 }, - { CS35L41_PWR_CTRL1, 0x00000001, 3000 }, // GLOBAL_EN = 1 + { CS35L41_PWR_CTRL1, 0x00000001 }, // GLOBAL_EN = 1 +}; + +static const struct reg_sequence cs35l41_safe_to_active_en_spk[] = { { 0x0000742C, 0x000000F9 }, { 0x00007438, 0x00580941 }, - { 0x00000040, 0x000000CC }, - { 0x00000040, 0x00000033 }, }; static const struct reg_sequence cs35l41_reset_to_safe[] = { @@ -1188,11 +1192,11 @@ bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type) } EXPORT_SYMBOL_GPL(cs35l41_safe_reset); -int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type, int enable, - struct completion *pll_lock) +int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l41_boost_type b_type, + int enable, struct completion *pll_lock, bool firmware_running) { int ret; - unsigned int gpio1_func, pad_control, pwr_ctrl1, pwr_ctrl3; + unsigned int gpio1_func, pad_control, pwr_ctrl1, pwr_ctrl3, int_status; struct reg_sequence cs35l41_mdsync_down_seq[] = { {CS35L41_PWR_CTRL3, 0}, {CS35L41_GPIO_PAD_CONTROL, 0}, @@ -1204,6 +1208,14 @@ int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type, {CS35L41_PWR_CTRL1, 0x00000001, 3000}, }; + if ((pwr_ctl1_val & CS35L41_GLOBAL_EN_MASK) && enable) { + dev_dbg(dev, "Cannot set Global Enable - already set.\n"); + return 0; + } else if (!(pwr_ctl1_val & CS35L41_GLOBAL_EN_MASK) && !enable) { + dev_dbg(dev, "Cannot unset Global Enable - not set.\n"); + return 0; + } + switch (b_type) { case CS35L41_SHD_BOOST_ACTV: case CS35L41_SHD_BOOST_PASS: @@ -1244,16 +1256,48 @@ int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type, case CS35L41_INT_BOOST: ret = regmap_update_bits(regmap, CS35L41_PWR_CTRL1, CS35L41_GLOBAL_EN_MASK, enable << CS35L41_GLOBAL_EN_SHIFT); + if (ret) { + dev_err(dev, "CS35L41_PWR_CTRL1 set failed: %d\n", ret); + return ret; + } usleep_range(3000, 3100); break; case CS35L41_EXT_BOOST: case CS35L41_EXT_BOOST_NO_VSPK_SWITCH: - if (enable) - ret = regmap_multi_reg_write(regmap, cs35l41_safe_to_active, - ARRAY_SIZE(cs35l41_safe_to_active)); - else - ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe, - ARRAY_SIZE(cs35l41_active_to_safe)); + if (enable) { + /* Test Key is unlocked here */ + ret = regmap_multi_reg_write(regmap, cs35l41_safe_to_active_start, + ARRAY_SIZE(cs35l41_safe_to_active_start)); + if (ret) + return ret; + + usleep_range(3000, 3100); + + if (firmware_running) + ret = cs35l41_set_cspl_mbox_cmd(dev, regmap, + CSPL_MBOX_CMD_SPK_OUT_ENABLE); + else + ret = regmap_multi_reg_write(regmap, cs35l41_safe_to_active_en_spk, + ARRAY_SIZE(cs35l41_safe_to_active_en_spk)); + + /* Lock the test key, it was unlocked during the multi_reg_write */ + cs35l41_test_key_lock(dev, regmap); + } else { + /* Test Key is unlocked here */ + ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe_start, + ARRAY_SIZE(cs35l41_active_to_safe_start)); + if (ret) { + /* Lock the test key, it was unlocked during the multi_reg_write */ + cs35l41_test_key_lock(dev, regmap); + return ret; + } + + usleep_range(3000, 3100); + + /* Test Key is locked here */ + ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe_end, + ARRAY_SIZE(cs35l41_active_to_safe_end)); + } break; default: ret = -EINVAL; @@ -1344,6 +1388,8 @@ static bool cs35l41_check_cspl_mbox_sts(enum cs35l41_cspl_mbox_cmd cmd, return (sts == CSPL_MBOX_STS_RUNNING); case CSPL_MBOX_CMD_STOP_PRE_REINIT: return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT); + case CSPL_MBOX_CMD_SPK_OUT_ENABLE: + return (sts == CSPL_MBOX_STS_RUNNING); default: return false; } diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index 6ac501f008ec..d4e9c9d9b50a 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -500,12 +500,12 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w, cs35l41_pup_patch, ARRAY_SIZE(cs35l41_pup_patch)); - cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 1, - &cs35l41->pll_lock); + ret = cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type, + 1, &cs35l41->pll_lock, cs35l41->dsp.cs_dsp.running); break; case SND_SOC_DAPM_POST_PMD: - cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0, - &cs35l41->pll_lock); + ret = cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type, + 0, &cs35l41->pll_lock, cs35l41->dsp.cs_dsp.running); ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS1, val, val & CS35L41_PDN_DONE_MASK, From f8264c7592088727629e14f396f95ad643847740 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:07 +0100 Subject: [PATCH 237/334] ALSA: cs35l41: Poll for Power Up/Down rather than waiting a fixed delay To ensure the chip has correctly powered up or down before continuing, the driver will now poll a register, rather than wait a fixed delay. Acked-by: Mark Brown Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20230721151816.2080453-3-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/soc/codecs/cs35l41-lib.c | 48 +++++++++++++++++++++++++++++++--- sound/soc/codecs/cs35l41.c | 10 ------- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c index a7556fa33cdd..a9c559a676e7 100644 --- a/sound/soc/codecs/cs35l41-lib.c +++ b/sound/soc/codecs/cs35l41-lib.c @@ -1196,7 +1196,8 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4 int enable, struct completion *pll_lock, bool firmware_running) { int ret; - unsigned int gpio1_func, pad_control, pwr_ctrl1, pwr_ctrl3, int_status; + unsigned int gpio1_func, pad_control, pwr_ctrl1, pwr_ctrl3, int_status, pup_pdn_mask; + unsigned int pwr_ctl1_val; struct reg_sequence cs35l41_mdsync_down_seq[] = { {CS35L41_PWR_CTRL3, 0}, {CS35L41_GPIO_PAD_CONTROL, 0}, @@ -1208,6 +1209,12 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4 {CS35L41_PWR_CTRL1, 0x00000001, 3000}, }; + pup_pdn_mask = enable ? CS35L41_PUP_DONE_MASK : CS35L41_PDN_DONE_MASK; + + ret = regmap_read(regmap, CS35L41_PWR_CTRL1, &pwr_ctl1_val); + if (ret) + return ret; + if ((pwr_ctl1_val & CS35L41_GLOBAL_EN_MASK) && enable) { dev_dbg(dev, "Cannot set Global Enable - already set.\n"); return 0; @@ -1252,6 +1259,15 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4 ret = regmap_multi_reg_write(regmap, cs35l41_mdsync_up_seq, ARRAY_SIZE(cs35l41_mdsync_up_seq)); } + + ret = regmap_read_poll_timeout(regmap, CS35L41_IRQ1_STATUS1, + int_status, int_status & pup_pdn_mask, + 1000, 100000); + if (ret) + dev_err(dev, "Enable(%d) failed: %d\n", enable, ret); + + // Clear PUP/PDN status + regmap_write(regmap, CS35L41_IRQ1_STATUS1, pup_pdn_mask); break; case CS35L41_INT_BOOST: ret = regmap_update_bits(regmap, CS35L41_PWR_CTRL1, CS35L41_GLOBAL_EN_MASK, @@ -1260,7 +1276,15 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4 dev_err(dev, "CS35L41_PWR_CTRL1 set failed: %d\n", ret); return ret; } - usleep_range(3000, 3100); + + ret = regmap_read_poll_timeout(regmap, CS35L41_IRQ1_STATUS1, + int_status, int_status & pup_pdn_mask, + 1000, 100000); + if (ret) + dev_err(dev, "Enable(%d) failed: %d\n", enable, ret); + + /* Clear PUP/PDN status */ + regmap_write(regmap, CS35L41_IRQ1_STATUS1, pup_pdn_mask); break; case CS35L41_EXT_BOOST: case CS35L41_EXT_BOOST_NO_VSPK_SWITCH: @@ -1271,7 +1295,15 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4 if (ret) return ret; - usleep_range(3000, 3100); + ret = regmap_read_poll_timeout(regmap, CS35L41_IRQ1_STATUS1, int_status, + int_status & CS35L41_PUP_DONE_MASK, 1000, 100000); + if (ret) { + dev_err(dev, "Failed waiting for CS35L41_PUP_DONE_MASK: %d\n", ret); + /* Lock the test key, it was unlocked during the multi_reg_write */ + cs35l41_test_key_lock(dev, regmap); + return ret; + } + regmap_write(regmap, CS35L41_IRQ1_STATUS1, CS35L41_PUP_DONE_MASK); if (firmware_running) ret = cs35l41_set_cspl_mbox_cmd(dev, regmap, @@ -1292,7 +1324,15 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4 return ret; } - usleep_range(3000, 3100); + ret = regmap_read_poll_timeout(regmap, CS35L41_IRQ1_STATUS1, int_status, + int_status & CS35L41_PDN_DONE_MASK, 1000, 100000); + if (ret) { + dev_err(dev, "Failed waiting for CS35L41_PDN_DONE_MASK: %d\n", ret); + /* Lock the test key, it was unlocked during the multi_reg_write */ + cs35l41_test_key_lock(dev, regmap); + return ret; + } + regmap_write(regmap, CS35L41_IRQ1_STATUS1, CS35L41_PDN_DONE_MASK); /* Test Key is locked here */ ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe_end, diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index d4e9c9d9b50a..2b3c36f02edb 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -491,7 +491,6 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w, { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component); - unsigned int val; int ret = 0; switch (event) { @@ -507,15 +506,6 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w, ret = cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0, &cs35l41->pll_lock, cs35l41->dsp.cs_dsp.running); - ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS1, - val, val & CS35L41_PDN_DONE_MASK, - 1000, 100000); - if (ret) - dev_warn(cs35l41->dev, "PDN failed: %d\n", ret); - - regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, - CS35L41_PDN_DONE_MASK); - regmap_multi_reg_write_bypassed(cs35l41->regmap, cs35l41_pdn_patch, ARRAY_SIZE(cs35l41_pdn_patch)); From 5299b79ca1a2a9b017b87da08563100b0da98e5b Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:08 +0100 Subject: [PATCH 238/334] ALSA: hda: cs35l41: Check mailbox status of pause command after firmware load Currently, we do not check the return status of the pause command, immediately after we load firmware. If the pause has failed, the firmware is not running. Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20230721151816.2080453-4-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index f9c97270db6f..29f1dce45f1d 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -781,7 +781,12 @@ static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41) goto clean_dsp; } - cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, CSPL_MBOX_CMD_PAUSE); + ret = cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, CSPL_MBOX_CMD_PAUSE); + if (ret) { + dev_err(cs35l41->dev, "Error waiting for DSP to pause: %u\n", ret); + goto clean_dsp; + } + cs35l41->firmware_running = true; return 0; From a3ff564658783e3cd9cc3098da4aebd89fe07d74 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:09 +0100 Subject: [PATCH 239/334] ALSA: hda: cs35l41: Ensure we correctly re-sync regmap before system suspending. In order to properly system suspend, it is necessary to unload the firmware and ensure the chip is ready for shutdown (if necessary). If the system is currently in runtime suspend, it is necessary to wake up the device, and then make it ready. Currently, the wake does not correctly resync the device, which may mean it cannot suspend correctly. Fix this by performaing a resync. Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20230721151816.2080453-5-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index 29f1dce45f1d..f42457147ce4 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -574,21 +574,43 @@ static int cs35l41_hda_channel_map(struct device *dev, unsigned int tx_num, unsi rx_slot); } -static void cs35l41_ready_for_reset(struct cs35l41_hda *cs35l41) +static int cs35l41_ready_for_reset(struct cs35l41_hda *cs35l41) { + int ret = 0; + mutex_lock(&cs35l41->fw_mutex); if (cs35l41->firmware_running) { regcache_cache_only(cs35l41->regmap, false); - cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap); + ret = cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap); + if (ret) { + dev_warn(cs35l41->dev, "Unable to exit Hibernate."); + goto err; + } + + /* Test key needs to be unlocked to allow the OTP settings to re-apply */ + cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap); + ret = regcache_sync(cs35l41->regmap); + cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap); + if (ret) { + dev_err(cs35l41->dev, "Failed to restore register cache: %d\n", ret); + goto err; + } + + if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) + cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, &cs35l41->hw_cfg); + cs35l41_shutdown_dsp(cs35l41); cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type); - - regcache_cache_only(cs35l41->regmap, true); - regcache_mark_dirty(cs35l41->regmap); } +err: + regcache_cache_only(cs35l41->regmap, true); + regcache_mark_dirty(cs35l41->regmap); + mutex_unlock(&cs35l41->fw_mutex); + + return ret; } static int cs35l41_system_suspend(struct device *dev) From f2a58481a5051704390c2d7653b07ab3d97782da Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:10 +0100 Subject: [PATCH 240/334] ALSA: hda: cs35l41: Ensure we pass up any errors during system suspend. There are several steps required to put the system into system suspend. Some of these steps may fail, so the driver should pass up the errors if they occur. Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20230721151816.2080453-6-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index f42457147ce4..d4a11f7b5dbd 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -626,17 +626,22 @@ static int cs35l41_system_suspend(struct device *dev) } ret = pm_runtime_force_suspend(dev); - if (ret) + if (ret) { + dev_err(dev, "System Suspend Failed, unable to runtime suspend: %d\n", ret); return ret; + } /* Shutdown DSP before system suspend */ - cs35l41_ready_for_reset(cs35l41); + ret = cs35l41_ready_for_reset(cs35l41); + + if (ret) + dev_err(dev, "System Suspend Failed, not ready for Reset: %d\n", ret); /* * Reset GPIO may be shared, so cannot reset here. * However beyond this point, amps may be powered down. */ - return 0; + return ret; } static int cs35l41_system_resume(struct device *dev) @@ -659,9 +664,13 @@ static int cs35l41_system_resume(struct device *dev) usleep_range(2000, 2100); ret = pm_runtime_force_resume(dev); + if (ret) { + dev_err(dev, "System Resume Failed: Unable to runtime resume: %d\n", ret); + return ret; + } mutex_lock(&cs35l41->fw_mutex); - if (!ret && cs35l41->request_fw_load && !cs35l41->fw_request_ongoing) { + if (cs35l41->request_fw_load && !cs35l41->fw_request_ongoing) { cs35l41->fw_request_ongoing = true; schedule_work(&cs35l41->fw_load_work); } From a5adbfb60b0299e788189aa8f88d8fa0dafb9d65 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:11 +0100 Subject: [PATCH 241/334] ALSA: hda: cs35l41: Move Play and Pause into separate functions This allows play and pause to be called from multiple places, which is necessary for system suspend and resume. Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20230721151816.2080453-7-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda.c | 131 ++++++++++++++++++++++-------------- 1 file changed, 79 insertions(+), 52 deletions(-) diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index d4a11f7b5dbd..f77583b46b6b 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -483,63 +483,103 @@ static void cs35l41_irq_release(struct cs35l41_hda *cs35l41) cs35l41->irq_errors = 0; } -static void cs35l41_hda_playback_hook(struct device *dev, int action) +static void cs35l41_hda_play_start(struct device *dev) { struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); struct regmap *reg = cs35l41->regmap; - int ret = 0; + + dev_dbg(dev, "Play (Start)\n"); + + if (cs35l41->playback_started) { + dev_dbg(dev, "Playback already started."); + return; + } + + cs35l41->playback_started = true; + + if (cs35l41->firmware_running) { + regmap_multi_reg_write(reg, cs35l41_hda_config_dsp, + ARRAY_SIZE(cs35l41_hda_config_dsp)); + 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) + regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00008001); + +} + +static void cs35l41_hda_play_done(struct device *dev) +{ + struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); + struct regmap *reg = cs35l41->regmap; + + dev_dbg(dev, "Play (Complete)\n"); + + cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 1, NULL, + cs35l41->firmware_running); +} + +static void cs35l41_hda_pause_start(struct device *dev) +{ + struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); + struct regmap *reg = cs35l41->regmap; + + dev_dbg(dev, "Pause (Start)\n"); + + regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute)); + cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 0, NULL, + cs35l41->firmware_running); +} + +static void cs35l41_hda_pause_done(struct device *dev) +{ + struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); + struct regmap *reg = cs35l41->regmap; + + dev_dbg(dev, "Pause (Complete)\n"); + + regmap_update_bits(reg, CS35L41_PWR_CTRL2, CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT); + if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) + regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00000001); + if (cs35l41->firmware_running) { + cs35l41_set_cspl_mbox_cmd(dev, reg, CSPL_MBOX_CMD_PAUSE); + regmap_update_bits(reg, CS35L41_PWR_CTRL2, + CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK, + 0 << CS35L41_VMON_EN_SHIFT | 0 << CS35L41_IMON_EN_SHIFT); + } + cs35l41_irq_release(cs35l41); + cs35l41->playback_started = false; +} + +static void cs35l41_hda_playback_hook(struct device *dev, int action) +{ + struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); switch (action) { case HDA_GEN_PCM_ACT_OPEN: pm_runtime_get_sync(dev); mutex_lock(&cs35l41->fw_mutex); - cs35l41->playback_started = true; - if (cs35l41->firmware_running) { - regmap_multi_reg_write(reg, cs35l41_hda_config_dsp, - ARRAY_SIZE(cs35l41_hda_config_dsp)); - regmap_update_bits(cs35l41->regmap, 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, cs35l41->regmap, - CSPL_MBOX_CMD_RESUME); - } else { - regmap_multi_reg_write(reg, cs35l41_hda_config, - ARRAY_SIZE(cs35l41_hda_config)); - } - ret = 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) - regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00008001); + cs35l41_hda_play_start(dev); mutex_unlock(&cs35l41->fw_mutex); break; case HDA_GEN_PCM_ACT_PREPARE: mutex_lock(&cs35l41->fw_mutex); - ret = cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 1, NULL, - cs35l41->firmware_running); + cs35l41_hda_play_done(dev); mutex_unlock(&cs35l41->fw_mutex); break; case HDA_GEN_PCM_ACT_CLEANUP: mutex_lock(&cs35l41->fw_mutex); - regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute)); - ret = cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 0, NULL, - cs35l41->firmware_running); + cs35l41_hda_pause_start(dev); mutex_unlock(&cs35l41->fw_mutex); break; case HDA_GEN_PCM_ACT_CLOSE: mutex_lock(&cs35l41->fw_mutex); - ret = regmap_update_bits(reg, CS35L41_PWR_CTRL2, - CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT); - if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) - regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00000001); - if (cs35l41->firmware_running) { - cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, - CSPL_MBOX_CMD_PAUSE); - regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, - CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK, - 0 << CS35L41_VMON_EN_SHIFT | 0 << CS35L41_IMON_EN_SHIFT); - } - cs35l41_irq_release(cs35l41); - cs35l41->playback_started = false; + cs35l41_hda_pause_done(dev); mutex_unlock(&cs35l41->fw_mutex); pm_runtime_mark_last_busy(dev); @@ -549,9 +589,6 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action) dev_warn(cs35l41->dev, "Playback action not supported: %d\n", action); break; } - - if (ret) - dev_err(cs35l41->dev, "Regmap access fail: %d\n", ret); } static int cs35l41_hda_channel_map(struct device *dev, unsigned int tx_num, unsigned int *tx_slot, @@ -703,18 +740,8 @@ static int cs35l41_runtime_suspend(struct device *dev) mutex_lock(&cs35l41->fw_mutex); if (cs35l41->playback_started) { - regmap_multi_reg_write(cs35l41->regmap, cs35l41_hda_mute, - ARRAY_SIZE(cs35l41_hda_mute)); - cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0, - NULL, cs35l41->firmware_running); - regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, - CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT); - if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) - regmap_write(cs35l41->regmap, CS35L41_GPIO1_CTRL1, 0x00000001); - regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, - CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK, - 0 << CS35L41_VMON_EN_SHIFT | 0 << CS35L41_IMON_EN_SHIFT); - cs35l41->playback_started = false; + cs35l41_hda_pause_start(dev); + cs35l41_hda_pause_done(dev); } if (cs35l41->firmware_running) { From 4eae4892c5bdef990b4b80997b813e2443d6554c Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:12 +0100 Subject: [PATCH 242/334] ALSA: hda: hda_component: Add pre and post playback hooks to hda_component These hooks can be used to add callbacks that would be run before and after the main playback hooks. These hooks would be called for all amps, before moving on to the next hook, i.e. pre_playback_hook would be called for all amps, before the playback_hook is called for all amps, then finally the post_playback_hook is called for all amps. Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20230721151816.2080453-8-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_component.h | 2 ++ sound/pci/hda/patch_realtek.c | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_component.h b/sound/pci/hda/hda_component.h index 534e845b9cd1..f170aec967c1 100644 --- a/sound/pci/hda/hda_component.h +++ b/sound/pci/hda/hda_component.h @@ -15,5 +15,7 @@ struct hda_component { struct device *dev; char name[HDA_MAX_NAME_SIZE]; struct hda_codec *codec; + void (*pre_playback_hook)(struct device *dev, int action); void (*playback_hook)(struct device *dev, int action); + void (*post_playback_hook)(struct device *dev, int action); }; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e2f8b608de82..7d14f9dbe95e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6700,9 +6700,17 @@ static void comp_generic_playback_hook(struct hda_pcm_stream *hinfo, struct hda_ int i; for (i = 0; i < HDA_MAX_COMPONENTS; i++) { - if (spec->comps[i].dev) + if (spec->comps[i].dev && spec->comps[i].pre_playback_hook) + spec->comps[i].pre_playback_hook(spec->comps[i].dev, action); + } + for (i = 0; i < HDA_MAX_COMPONENTS; i++) { + if (spec->comps[i].dev && spec->comps[i].playback_hook) spec->comps[i].playback_hook(spec->comps[i].dev, action); } + for (i = 0; i < HDA_MAX_COMPONENTS; i++) { + if (spec->comps[i].dev && spec->comps[i].post_playback_hook) + spec->comps[i].post_playback_hook(spec->comps[i].dev, action); + } } struct cs35l41_dev_name { From 01ecc562936439cf6dd08b5f8c6bbed2704d9f9e Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:13 +0100 Subject: [PATCH 243/334] ALSA: hda: cs35l41: Use pre and post playback hooks Use new hooks to ensure separation between play/pause actions, as required by external boost. External Boost on CS35L41 requires the amp to go through a particular sequence of steps. One of these steps involes the setting of a GPIO. This GPIO is connected to one or more of the amps, and it may control the boost for all of the amps. To ensure that the GPIO is set when it is safe to do so, and to ensure that boost is ready for the rest of the sequence to be able to continue, we must ensure that the each part of the sequence is executed for each amp before moving on to the next part of the sequence. Some of the Play and Pause actions have moved from Open to Prepare. This is because Open is not guaranteed to be called again on system resume, whereas Prepare should. Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20230721151816.2080453-9-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda.c | 61 ++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index f77583b46b6b..a482d4752b3f 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -556,37 +556,68 @@ static void cs35l41_hda_pause_done(struct device *dev) cs35l41->playback_started = false; } +static void cs35l41_hda_pre_playback_hook(struct device *dev, int action) +{ + struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); + + switch (action) { + case HDA_GEN_PCM_ACT_CLEANUP: + mutex_lock(&cs35l41->fw_mutex); + cs35l41_hda_pause_start(dev); + mutex_unlock(&cs35l41->fw_mutex); + break; + default: + break; + } +} static void cs35l41_hda_playback_hook(struct device *dev, int action) { struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); switch (action) { case HDA_GEN_PCM_ACT_OPEN: + /* + * All amps must be resumed before we can start playing back. + * This ensures, for external boost, that all amps are in AMP_SAFE mode. + * Do this in HDA_GEN_PCM_ACT_OPEN, since this is run prior to any of the + * other actions. + */ pm_runtime_get_sync(dev); + break; + case HDA_GEN_PCM_ACT_PREPARE: mutex_lock(&cs35l41->fw_mutex); cs35l41_hda_play_start(dev); mutex_unlock(&cs35l41->fw_mutex); break; + case HDA_GEN_PCM_ACT_CLEANUP: + mutex_lock(&cs35l41->fw_mutex); + cs35l41_hda_pause_done(dev); + mutex_unlock(&cs35l41->fw_mutex); + break; + case HDA_GEN_PCM_ACT_CLOSE: + /* + * 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: + break; + } +} + +static void cs35l41_hda_post_playback_hook(struct device *dev, int action) +{ + struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); + + switch (action) { case HDA_GEN_PCM_ACT_PREPARE: mutex_lock(&cs35l41->fw_mutex); cs35l41_hda_play_done(dev); mutex_unlock(&cs35l41->fw_mutex); break; - case HDA_GEN_PCM_ACT_CLEANUP: - mutex_lock(&cs35l41->fw_mutex); - cs35l41_hda_pause_start(dev); - mutex_unlock(&cs35l41->fw_mutex); - break; - case HDA_GEN_PCM_ACT_CLOSE: - mutex_lock(&cs35l41->fw_mutex); - cs35l41_hda_pause_done(dev); - mutex_unlock(&cs35l41->fw_mutex); - - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - break; default: - dev_warn(cs35l41->dev, "Playback action not supported: %d\n", action); break; } } @@ -1037,6 +1068,8 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas ret = cs35l41_create_controls(cs35l41); comps->playback_hook = cs35l41_hda_playback_hook; + comps->pre_playback_hook = cs35l41_hda_pre_playback_hook; + comps->post_playback_hook = cs35l41_hda_post_playback_hook; mutex_unlock(&cs35l41->fw_mutex); From c4d0510b81c430249ee69c0554bb7ce4fa3d539e Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:14 +0100 Subject: [PATCH 244/334] ALSA: hda: cs35l41: Rework System Suspend to ensure correct call separation In order to correctly pause audio on suspend, amps using external boost require parts of the pause sequence to be called for all amps before moving on to the next steps. For example, as part of pausing the audio, the VSPK GPIO must be disabled, but since this GPIO is controlled by one amp, but controls the boost for all amps, it is required to separate the calls. During playback this is achieved by using the pre and post playback hooks, however during system suspend, this is not possible, so to separate the calls, we use both the .prepare and .suspend calls to pause the audio. Currently, for this reason, we do not restart audio on system resume. However, we can support this by relying on the playback hook to resume playback after system suspend. Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20230721151816.2080453-10-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda.c | 40 ++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index a482d4752b3f..70aa819cfbd6 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -595,6 +595,15 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action) mutex_unlock(&cs35l41->fw_mutex); break; case HDA_GEN_PCM_ACT_CLOSE: + mutex_lock(&cs35l41->fw_mutex); + if (!cs35l41->firmware_running && cs35l41->request_fw_load && + !cs35l41->fw_request_ongoing) { + dev_info(dev, "Requesting Firmware Load after HDA_GEN_PCM_ACT_CLOSE\n"); + cs35l41->fw_request_ongoing = true; + schedule_work(&cs35l41->fw_load_work); + } + mutex_unlock(&cs35l41->fw_mutex); + /* * 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. @@ -681,6 +690,25 @@ static int cs35l41_ready_for_reset(struct cs35l41_hda *cs35l41) return ret; } +static int cs35l41_system_suspend_prep(struct device *dev) +{ + struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); + + dev_dbg(cs35l41->dev, "System Suspend Prepare\n"); + + if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) { + dev_err_once(cs35l41->dev, "System Suspend not supported\n"); + return 0; /* don't block the whole system suspend */ + } + + mutex_lock(&cs35l41->fw_mutex); + if (cs35l41->playback_started) + cs35l41_hda_pause_start(dev); + mutex_unlock(&cs35l41->fw_mutex); + + return 0; +} + static int cs35l41_system_suspend(struct device *dev) { struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); @@ -693,6 +721,11 @@ static int cs35l41_system_suspend(struct device *dev) return 0; /* don't block the whole system suspend */ } + mutex_lock(&cs35l41->fw_mutex); + if (cs35l41->playback_started) + cs35l41_hda_pause_done(dev); + mutex_unlock(&cs35l41->fw_mutex); + ret = pm_runtime_force_suspend(dev); if (ret) { dev_err(dev, "System Suspend Failed, unable to runtime suspend: %d\n", ret); @@ -738,6 +771,7 @@ static int cs35l41_system_resume(struct device *dev) } mutex_lock(&cs35l41->fw_mutex); + if (cs35l41->request_fw_load && !cs35l41->fw_request_ongoing) { cs35l41->fw_request_ongoing = true; schedule_work(&cs35l41->fw_load_work); @@ -770,11 +804,6 @@ static int cs35l41_runtime_suspend(struct device *dev) mutex_lock(&cs35l41->fw_mutex); - if (cs35l41->playback_started) { - cs35l41_hda_pause_start(dev); - cs35l41_hda_pause_done(dev); - } - if (cs35l41->firmware_running) { ret = cs35l41_enter_hibernate(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type); @@ -1641,6 +1670,7 @@ EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41); const struct dev_pm_ops cs35l41_hda_pm_ops = { RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume, cs35l41_runtime_idle) + .prepare = cs35l41_system_suspend_prep, SYSTEM_SLEEP_PM_OPS(cs35l41_system_suspend, cs35l41_system_resume) }; EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, SND_HDA_SCODEC_CS35L41); From 7cf5ce66dfda2be444ea668c3d48f732ba4a7fd1 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:15 +0100 Subject: [PATCH 245/334] ALSA: hda: cs35l41: Add device_link between HDA and cs35l41_hda To ensure consistency between the HDA core and the CS35L41 HDA driver, add a device_link between them. This ensures that the HDA core will suspend first, and resume second, meaning the amp driver will not miss any events from the playback hook from the HDA core during system suspend and resume. Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20230721151816.2080453-11-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index 70aa819cfbd6..175378cdf9df 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -1063,6 +1063,7 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas { struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); struct hda_component *comps = master_data; + unsigned int sleep_flags; int ret = 0; if (!comps || cs35l41->index < 0 || cs35l41->index >= HDA_MAX_COMPONENTS) @@ -1102,6 +1103,11 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas mutex_unlock(&cs35l41->fw_mutex); + sleep_flags = lock_system_sleep(); + if (!device_link_add(&comps->codec->core.dev, cs35l41->dev, DL_FLAG_STATELESS)) + 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); @@ -1112,9 +1118,14 @@ static void cs35l41_hda_unbind(struct device *dev, struct device *master, void * { struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); struct hda_component *comps = master_data; + unsigned int sleep_flags; - if (comps[cs35l41->index].dev == dev) + if (comps[cs35l41->index].dev == dev) { memset(&comps[cs35l41->index], 0, sizeof(*comps)); + sleep_flags = lock_system_sleep(); + device_link_remove(&comps->codec->core.dev, cs35l41->dev); + unlock_system_sleep(sleep_flags); + } } static const struct component_ops cs35l41_hda_comp_ops = { From 2d816d4f92086ca0a7b79198794012076b4cab0b Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:16 +0100 Subject: [PATCH 246/334] ALSA: hda: cs35l41: Ensure amp is only unmuted during playback Currently we only mute after playback has finished, and unmute prior to setting global enable. To prevent any possible pops and clicks, mute at probe, and then only unmute after global enable is set. Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20230721151816.2080453-12-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index 175378cdf9df..98feb5ccd586 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -58,8 +58,6 @@ static const struct reg_sequence cs35l41_hda_config[] = { { CS35L41_DSP1_RX3_SRC, 0x00000018 }, // DSP1RX3 SRC = VMON { CS35L41_DSP1_RX4_SRC, 0x00000019 }, // DSP1RX4 SRC = IMON { CS35L41_DSP1_RX5_SRC, 0x00000020 }, // DSP1RX5 SRC = ERRVOL - { CS35L41_AMP_DIG_VOL_CTRL, 0x00008000 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM 0.0 dB - { CS35L41_AMP_GAIN_CTRL, 0x00000084 }, // AMP_GAIN_PCM 4.5 dB }; static const struct reg_sequence cs35l41_hda_config_dsp[] = { @@ -82,6 +80,14 @@ static const struct reg_sequence cs35l41_hda_config_dsp[] = { { CS35L41_DSP1_RX3_SRC, 0x00000018 }, // DSP1RX3 SRC = VMON { CS35L41_DSP1_RX4_SRC, 0x00000019 }, // DSP1RX4 SRC = IMON { CS35L41_DSP1_RX5_SRC, 0x00000029 }, // DSP1RX5 SRC = VBSTMON +}; + +static const struct reg_sequence cs35l41_hda_unmute[] = { + { CS35L41_AMP_DIG_VOL_CTRL, 0x00008000 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM 0.0 dB + { CS35L41_AMP_GAIN_CTRL, 0x00000084 }, // AMP_GAIN_PCM 4.5 dB +}; + +static const struct reg_sequence cs35l41_hda_unmute_dsp[] = { { CS35L41_AMP_DIG_VOL_CTRL, 0x00008000 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM 0.0 dB { CS35L41_AMP_GAIN_CTRL, 0x00000233 }, // AMP_GAIN_PCM = 17.5dB AMP_GAIN_PDM = 19.5dB }; @@ -522,6 +528,13 @@ static void cs35l41_hda_play_done(struct device *dev) cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 1, NULL, cs35l41->firmware_running); + if (cs35l41->firmware_running) { + regmap_multi_reg_write(reg, cs35l41_hda_unmute_dsp, + ARRAY_SIZE(cs35l41_hda_unmute_dsp)); + } else { + regmap_multi_reg_write(reg, cs35l41_hda_unmute, + ARRAY_SIZE(cs35l41_hda_unmute)); + } } static void cs35l41_hda_pause_start(struct device *dev) @@ -1616,6 +1629,11 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i if (ret) goto err; + ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41_hda_mute, + ARRAY_SIZE(cs35l41_hda_mute)); + if (ret) + goto err; + INIT_WORK(&cs35l41->fw_load_work, cs35l41_fw_load_work); mutex_init(&cs35l41->fw_mutex); From 367ef1e1c4b65acc5d789ba00d20197eb66b62f4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 27 Jul 2023 10:16:33 +0300 Subject: [PATCH 247/334] ALSA: hda/cs35l56: Do some clean up on probe error Smatch complains that this return should be a goto: sound/pci/hda/cs35l56_hda.c:910 cs35l56_hda_common_probe() warn: missing unwind goto? The goto error disables cansleep so that seems reasonable. Fixes: 73cfbfa9caea ("ALSA: hda/cs35l56: Add driver for Cirrus Logic CS35L56 amplifier") Signed-off-by: Dan Carpenter Reviewed-by: Richard Fitzgerald Link: https://lore.kernel.org/r/465160f4-b7cf-41d5-931e-d6c9e68fa3c7@moroto.mountain Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l56_hda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index 71e95e64f8a4..4c3279f61b94 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -907,7 +907,7 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id) ret = cs35l56_set_patch(&cs35l56->base); if (ret) - return ret; + goto err; regcache_mark_dirty(cs35l56->base.regmap); regcache_sync(cs35l56->base.regmap); From 44900c3ee4a1047bf896ca4cd9a9c69000f04701 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Thu, 27 Jul 2023 21:53:24 +0000 Subject: [PATCH 248/334] ALSA: xen-front: refactor deprecated strncpy `strncpy` is deprecated for use on NUL-terminated destination strings [1]. A suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on its destination buffer argument which is _not_ always the case for `strncpy`! It should be noted that, in this case, the destination buffer has a length strictly greater than the source string. Moreover, the source string is NUL-terminated (and so is the destination) which means there was no real bug happening here. Nonetheless, this patch would get us one step closer to eliminating the `strncpy` API in the kernel, as its use is too ambiguous. We need to favor less ambiguous replacements such as: strscpy, strscpy_pad, strtomem and strtomem_pad (amongst others). Technically, my patch yields subtly different behavior. The original implementation with `strncpy` would fill the entire destination buffer with null bytes [3] while `strscpy` will leave the junk, uninitialized bytes trailing after the _mandatory_ NUL-termination. So, if somehow `pcm->name` or `card->driver/shortname/longname` require this NUL-padding behavior then `strscpy_pad` should be used. My interpretation, though, is that the aforementioned fields are just fine as NUL-terminated strings. Please correct my assumptions if needed and I'll send in a v2. [1]: www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [2]: manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [3]: https://linux.die.net/man/3/strncpy Link: https://github.com/KSPP/linux/issues/90 Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20230727-sound-xen-v1-1-89dd161351f1@google.com Signed-off-by: Takashi Iwai --- sound/xen/xen_snd_front_alsa.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/xen/xen_snd_front_alsa.c b/sound/xen/xen_snd_front_alsa.c index db917453a473..7a3dfce97c15 100644 --- a/sound/xen/xen_snd_front_alsa.c +++ b/sound/xen/xen_snd_front_alsa.c @@ -783,7 +783,7 @@ static int new_pcm_instance(struct xen_snd_front_card_info *card_info, pcm->info_flags = 0; /* we want to handle all PCM operations in non-atomic context */ pcm->nonatomic = true; - strncpy(pcm->name, "Virtual card PCM", sizeof(pcm->name)); + strscpy(pcm->name, "Virtual card PCM", sizeof(pcm->name)); if (instance_cfg->num_streams_pb) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, @@ -835,9 +835,9 @@ int xen_snd_front_alsa_init(struct xen_snd_front_info *front_info) goto fail; } - strncpy(card->driver, XENSND_DRIVER_NAME, sizeof(card->driver)); - strncpy(card->shortname, cfg->name_short, sizeof(card->shortname)); - strncpy(card->longname, cfg->name_long, sizeof(card->longname)); + strscpy(card->driver, XENSND_DRIVER_NAME, sizeof(card->driver)); + strscpy(card->shortname, cfg->name_short, sizeof(card->shortname)); + strscpy(card->longname, cfg->name_long, sizeof(card->longname)); ret = snd_card_register(card); if (ret < 0) From 2ad27caab44583eb38b71d90a364e5670b4c7c5a Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Thu, 27 Jul 2023 22:09:29 +0000 Subject: [PATCH 249/334] ALSA: bcd2000: refactor deprecated strncpy `strncpy` is deprecated for use on NUL-terminated destination strings [1]. A suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on its destination buffer argument which is _not_ always the case for `strncpy`! It should be noted that, in this case, the destination buffer has a length strictly greater than the source string. Moreover, the source string is NUL-terminated (and so is the destination) which means there was no real bug happening here. Nonetheless, this patch would get us one step closer to eliminating the `strncpy` API in the kernel, as its use is too ambiguous. We need to favor less ambiguous replacements such as: strscpy, strscpy_pad, strtomem and strtomem_pad (amongst others). Technically, my patch yields subtly different behavior. The original implementation with `strncpy` would fill the entire destination buffer with null bytes [3] while `strscpy` will leave the junk, uninitialized bytes trailing after the _mandatory_ NUL-termination. So, if somehow `card->driver` or `card->shortname` require this NUL-padding behavior then `strscpy_pad` should be used. My interpretation, though, is that the aforementioned fields are just fine as NUL-terminated strings. Please correct my assumptions if needed and I'll send in a v2. [1]: www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [2]: manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [3]: https://linux.die.net/man/3/strncpy Link: https://github.com/KSPP/linux/issues/90 Link: https://lore.kernel.org/r/20230727-sound-xen-v1-1-89dd161351f1@google.com (related ALSA patch) Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20230727-sound-usb-bcd2000-v1-1-0dc73684b2f0@google.com Signed-off-by: Takashi Iwai --- sound/usb/bcd2000/bcd2000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/usb/bcd2000/bcd2000.c b/sound/usb/bcd2000/bcd2000.c index 7aec0a95c609..392b4d8e9e76 100644 --- a/sound/usb/bcd2000/bcd2000.c +++ b/sound/usb/bcd2000/bcd2000.c @@ -395,8 +395,8 @@ static int bcd2000_probe(struct usb_interface *interface, snd_card_set_dev(card, &interface->dev); - strncpy(card->driver, "snd-bcd2000", sizeof(card->driver)); - strncpy(card->shortname, "BCD2000", sizeof(card->shortname)); + strscpy(card->driver, "snd-bcd2000", sizeof(card->driver)); + strscpy(card->shortname, "BCD2000", sizeof(card->shortname)); usb_make_path(bcd2k->dev, usb_path, sizeof(usb_path)); snprintf(bcd2k->card->longname, sizeof(bcd2k->card->longname), "Behringer BCD2000 at %s", From 7b6466ad1d7bfa178d28f125d75187c4f6597f2d Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 31 Jul 2023 17:57:18 +0100 Subject: [PATCH 250/334] ALSA: hda/cs35l56: Complete firmware reboot before calling cs_dsp_run() Move the call to cs_dsp_run() in cs35l56_hda_fw_load() so that it is after the CS35L56 has been reset/reinit'd and the regmap cache has been synced. cs_dsp_run() syncs up ALSA control cache values with the DSP memory so this must not be done until the firmware has reinitialized. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230731165726.7940-2-rf@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l56_hda.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index 4c3279f61b94..c3acda2daeeb 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -562,12 +562,6 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) if (coeff_filename) dev_dbg(cs35l56->base.dev, "Loaded Coefficients: %s\n", coeff_filename); - ret = cs_dsp_run(&cs35l56->cs_dsp); - if (ret) { - dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret); - goto err; - } - if (cs35l56->base.secured) { ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT); if (ret) @@ -591,6 +585,11 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) regmap_clear_bits(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, CS35L56_FIRMWARE_MISSING); cs35l56->base.fw_patched = true; + + ret = cs_dsp_run(&cs35l56->cs_dsp); + if (ret) + dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret); + err: pm_runtime_put(cs35l56->base.dev); mutex_unlock(&cs35l56->base.irq_lock); From c36570970a585bc816e15478fde71476f96f5e9c Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 31 Jul 2023 17:57:19 +0100 Subject: [PATCH 251/334] ALSA: hda/cs35l56: Do not mark cache dirty after REINIT Only call regcache_mark_dirty() in cs35l56_hda_fw_load() if the CS35L56 was SYSTEM_RESET. recache_mark_dirty() changes the behaviour of regcache_sync() to write out cache values that are not the default value, and skip cache values that are the default. AUDIO_REINIT does not reset the registers. regcache_mark_dirty() after AUDIO_REINIT could cause the regcache_sync() to sync registers incorrectly because it will assume that all registers have reset to default. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230731165726.7940-3-rf@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l56_hda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index c3acda2daeeb..fda716e0db09 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -569,6 +569,7 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) } else { /* Reset the device and wait for it to boot */ cs35l56_system_reset(&cs35l56->base, false); + regcache_mark_dirty(cs35l56->base.regmap); ret = cs35l56_wait_for_firmware_boot(&cs35l56->base); if (ret) goto err; @@ -579,7 +580,6 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) if (ret) goto err; - regcache_mark_dirty(cs35l56->base.regmap); regcache_sync(cs35l56->base.regmap); regmap_clear_bits(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, From 15c378d66fc5bd00ce7c8ac869624f9a4a29d1d4 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 31 Jul 2023 17:57:20 +0100 Subject: [PATCH 252/334] ALSA: hda/cs35l56: Call cs_dsp_power_down() before reloading firmware When firmware is reloaded after a system resume cs_dsp_power_down() should be called before calling cs_dsp_power_up(). The fw_patched flag should also be cleared and only set again if the firmware download succeeded. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230731165726.7940-4-rf@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l56_hda.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index fda716e0db09..b6b8cb21da75 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -527,6 +527,12 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) char *wmfw_filename = NULL; int ret = 0; + /* Prepare for a new DSP power-up */ + if (cs35l56->base.fw_patched) + cs_dsp_power_down(&cs35l56->cs_dsp); + + cs35l56->base.fw_patched = false; + cs35l56_hda_request_firmware_files(cs35l56, &wmfw_firmware, &wmfw_filename, &coeff_firmware, &coeff_filename); From e5bac77b67082e59f7aceea08a30b5dc66138643 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 31 Jul 2023 17:57:21 +0100 Subject: [PATCH 253/334] ALSA: hda/cs35l56: Always power-up and start cs_dsp Always call cs_dsp_power_up() and cs_dsp_run() in cs35l56_hda_fw_load() even if there aren't any firmware files to download. Also, if there aren't any firmware files to download there is no need to do cs35l56_firmware_shutdown() and cs35l56_system_reset(). If there aren't any firmware files there's no need to write anything to the CS35L56 registers to make it work - it will already be running the ROM firmware. So it's not strictly necessary to start cs_dsp. But it's perfectly ok to call cs_dsp_power_up() and cs_dsp_run() without downloading any firmware. This avoids having to support a state where audio is playing but cs_dsp is not running. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230731165726.7940-5-rf@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l56_hda.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index b6b8cb21da75..2870f82bfa45 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -536,10 +536,6 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) cs35l56_hda_request_firmware_files(cs35l56, &wmfw_firmware, &wmfw_filename, &coeff_firmware, &coeff_filename); - /* Nothing to do - no firmware files were found to download */ - if (!wmfw_filename && !coeff_filename) - return 0; - mutex_lock(&cs35l56->base.irq_lock); pm_runtime_get_sync(cs35l56->base.dev); @@ -549,7 +545,7 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) * shutdown the firmware to apply them and can use the lower cost * reinit sequence instead. */ - if (!cs35l56->base.secured) { + if (!cs35l56->base.secured && (wmfw_firmware || coeff_firmware)) { ret = cs35l56_firmware_shutdown(&cs35l56->base); if (ret) goto err; @@ -572,8 +568,8 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT); if (ret) goto err; - } else { - /* Reset the device and wait for it to boot */ + } else if (wmfw_firmware || coeff_firmware) { + /* If we downloaded firmware, reset the device and wait for it to boot */ cs35l56_system_reset(&cs35l56->base, false); regcache_mark_dirty(cs35l56->base.regmap); ret = cs35l56_wait_for_firmware_boot(&cs35l56->base); From fb78d73dde2d4d91e2372685159d67a43cf7b8f3 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 31 Jul 2023 17:57:22 +0100 Subject: [PATCH 254/334] ALSA: hda/cs35l56: Call cs_dsp_power_down() before calling cs_dsp_remove() In cs35l56_hda_unbind() cs_dsp_power_down() must be called to cleanup before calling cs_dsp_remove cs_dsp_remove(). Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230731165726.7940-6-rf@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l56_hda.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index 2870f82bfa45..e8c41a4a0c40 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -649,6 +649,9 @@ static void cs35l56_hda_unbind(struct device *dev, struct device *master, void * debugfs_remove_recursive(cs35l56->debugfs_root); #endif + if (cs35l56->base.fw_patched) + cs_dsp_power_down(&cs35l56->cs_dsp); + cs_dsp_remove(&cs35l56->cs_dsp); if (comps[cs35l56->index].dev == dev) From 0ba0dfd969926563016e706346a9caba7f5a15ac Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 31 Jul 2023 17:57:23 +0100 Subject: [PATCH 255/334] ALSA: hda/cs35l56: cs_dsp_power_down() on cs35l56_hda_fw_load() error path If cs35l56_hda_fw_load() successfully called cs_dsp_power_up() the error path must balance that with a call to cs_dsp_power_down(). Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230731165726.7940-7-rf@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l56_hda.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index e8c41a4a0c40..803fa2da9ea4 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -567,20 +567,20 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) if (cs35l56->base.secured) { ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT); if (ret) - goto err; + goto err_powered_up; } else if (wmfw_firmware || coeff_firmware) { /* If we downloaded firmware, reset the device and wait for it to boot */ cs35l56_system_reset(&cs35l56->base, false); regcache_mark_dirty(cs35l56->base.regmap); ret = cs35l56_wait_for_firmware_boot(&cs35l56->base); if (ret) - goto err; + goto err_powered_up; } /* Disable auto-hibernate so that runtime_pm has control */ ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE); if (ret) - goto err; + goto err_powered_up; regcache_sync(cs35l56->base.regmap); @@ -592,6 +592,9 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) if (ret) dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret); +err_powered_up: + if (!cs35l56->base.fw_patched) + cs_dsp_power_down(&cs35l56->cs_dsp); err: pm_runtime_put(cs35l56->base.dev); mutex_unlock(&cs35l56->base.irq_lock); From 2f860dd895381c8d120e68526f34fe9b29da4310 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 31 Jul 2023 17:57:24 +0100 Subject: [PATCH 256/334] ALSA: hda/cs35l56: Do not download firmware over existing RAM firmware A RAM firmware can only be downloaded if the CS35L56 is currently running from ROM firmware. The driver must not try to overwrite the RAM if the CS35L56 is already running from that RAM. Firmware can be downloaded in these two cases: - The BIOS has already patched the firmware (secured mode). In this case the firmware files will only contain tunings that are safe to overwrite. - The CS35L56 is running the built-in ROM firmware. After a RAM firmware has been downloaded it can only be cleared by hard resetting CS35L56. Some systems only hard-reset during power-on and do not give the driver control of hard reset. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230731165726.7940-8-rf@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l56_hda.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index 803fa2da9ea4..8f1665d38c92 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -525,6 +525,7 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) const struct firmware *wmfw_firmware = NULL; char *coeff_filename = NULL; char *wmfw_filename = NULL; + unsigned int firmware_missing; int ret = 0; /* Prepare for a new DSP power-up */ @@ -533,11 +534,28 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) cs35l56->base.fw_patched = false; - cs35l56_hda_request_firmware_files(cs35l56, &wmfw_firmware, &wmfw_filename, - &coeff_firmware, &coeff_filename); + pm_runtime_get_sync(cs35l56->base.dev); + + ret = regmap_read(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, &firmware_missing); + if (ret) { + dev_err(cs35l56->base.dev, "Failed to read PROTECTION_STATUS: %d\n", ret); + goto err_pm_put; + } + + firmware_missing &= CS35L56_FIRMWARE_MISSING; + + /* + * Firmware can only be downloaded if the CS35L56 is secured or is + * running from the built-in ROM. If it is secured the BIOS will have + * downloaded firmware, and the wmfw/bin files will only contain + * tunings that are safe to download with the firmware running. + */ + if (cs35l56->base.secured || firmware_missing) { + cs35l56_hda_request_firmware_files(cs35l56, &wmfw_firmware, &wmfw_filename, + &coeff_firmware, &coeff_filename); + } mutex_lock(&cs35l56->base.irq_lock); - pm_runtime_get_sync(cs35l56->base.dev); /* * When the device is running in secure mode the firmware files can @@ -596,11 +614,12 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) if (!cs35l56->base.fw_patched) cs_dsp_power_down(&cs35l56->cs_dsp); err: - pm_runtime_put(cs35l56->base.dev); mutex_unlock(&cs35l56->base.irq_lock); cs35l56_hda_release_firmware_files(wmfw_firmware, wmfw_filename, coeff_firmware, coeff_filename); +err_pm_put: + pm_runtime_put(cs35l56->base.dev); return ret; } From 3106797d2b0b09e7a27f09fac329f1d6e9b35270 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 31 Jul 2023 17:57:25 +0100 Subject: [PATCH 257/334] ALSA: hda/cs35l56: Fail if .bin not found and firmware not patched A tuning patch is always needed to enable the ASP audio port. If the BIOS did not patch the firmware, then it is mandatory to have a .bin file. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230731165726.7940-9-rf@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l56_hda.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index 8f1665d38c92..004740509dbd 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -555,6 +555,16 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) &coeff_firmware, &coeff_filename); } + /* + * If the BIOS didn't patch the firmware a bin file is mandatory to + * enable the ASP· + */ + if (!coeff_firmware && firmware_missing) { + dev_err(cs35l56->base.dev, ".bin file required but not found\n"); + ret = -ENOENT; + goto err_fw_release; + } + mutex_lock(&cs35l56->base.irq_lock); /* @@ -615,7 +625,7 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) cs_dsp_power_down(&cs35l56->cs_dsp); err: mutex_unlock(&cs35l56->base.irq_lock); - +err_fw_release: cs35l56_hda_release_firmware_files(wmfw_firmware, wmfw_filename, coeff_firmware, coeff_filename); err_pm_put: From 8ca3ee6f3f64673f377fc8f5ed163f71181c85ad Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 31 Jul 2023 17:57:26 +0100 Subject: [PATCH 258/334] ALSA: hda/cs35l56: Reject I2C alias addresses The ACPI nodes for CS35L56 can contain an extra I2CSerialBusV2 that is not a real device, it is an alias address. This alias address will not be in the cirrus,dev-index array, so reject any instantions with a device address not found in the array. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230731165726.7940-10-rf@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l56_hda.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index 004740509dbd..76b9c685560b 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -852,8 +852,12 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int id) break; } } + /* + * It's not an error for the ID to be missing: for I2C there can be + * an alias address that is not a real device. So reject silently. + */ if (cs35l56->index == -1) { - dev_err(cs35l56->base.dev, "No index found in %s\n", property); + dev_dbg(cs35l56->base.dev, "No index found in %s\n", property); ret = -ENODEV; goto err; } @@ -891,7 +895,8 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int id) return 0; err: - dev_err(cs35l56->base.dev, "Failed property %s: %d\n", property, ret); + if (ret != -ENODEV) + dev_err(cs35l56->base.dev, "Failed property %s: %d\n", property, ret); return ret; } @@ -904,10 +909,8 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id) dev_set_drvdata(cs35l56->base.dev, cs35l56); ret = cs35l56_hda_read_acpi(cs35l56, id); - if (ret) { - dev_err_probe(cs35l56->base.dev, ret, "Platform not supported\n"); + if (ret) goto err; - } cs35l56->amp_name = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, "AMP%d", cs35l56->index + 1); From fbeb1ec85dc6079b44766e225104bfdc8ea9fe6c Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Tue, 1 Aug 2023 22:45:12 +0800 Subject: [PATCH 259/334] ALSA: usb-audio: Remove unused function declaration Commit 68e67f40b734 ("ALSA: snd-usb: move calls to usb_set_interface") leave this unused declaration. Signed-off-by: Yue Haibing Link: https://lore.kernel.org/r/20230801144512.18716-1-yuehaibing@huawei.com Signed-off-by: Takashi Iwai --- sound/usb/endpoint.h | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index c09f68ce08b1..ba70f52f6860 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -44,7 +44,6 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep); void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, bool keep_pending); void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep); void snd_usb_endpoint_suspend(struct snd_usb_endpoint *ep); -int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep); void snd_usb_endpoint_release(struct snd_usb_endpoint *ep); void snd_usb_endpoint_free_all(struct snd_usb_audio *chip); From d28dc3d87fe298d0bd83c33738c0c09a0e4f7bdb Mon Sep 17 00:00:00 2001 From: Yu Liao Date: Wed, 2 Aug 2023 10:26:49 +0800 Subject: [PATCH 260/334] ALSA: ac97: set variables dev_attr_vendor_id to static sparse reports sound/ac97/bus.c:465:1: sparse: sparse: symbol 'dev_attr_vendor_id' was not declared. Should it be static? This variable is only used in its defining file, so it should be static. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202307242300.Oy0Dp2QI-lkp@intel.com/ Signed-off-by: Yu Liao Link: https://lore.kernel.org/r/20230802022649.2514787-1-liaoyu15@huawei.com Signed-off-by: Takashi Iwai --- sound/ac97/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c index 6067c04ce4c0..3173e9d98927 100644 --- a/sound/ac97/bus.c +++ b/sound/ac97/bus.c @@ -462,7 +462,7 @@ static ssize_t vendor_id_show(struct device *dev, return sysfs_emit(buf, "%08x", codec->vendor_id); } -DEVICE_ATTR_RO(vendor_id); +static DEVICE_ATTR_RO(vendor_id); static struct attribute *ac97_dev_attrs[] = { &dev_attr_vendor_id.attr, From cfad53a99d94478480a734602f14d09c5ec1d2da Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Wed, 2 Aug 2023 13:12:35 +0100 Subject: [PATCH 261/334] ALSA: hda: cs35l41: Print amp configuration after bind Print amp configuration information to be able to confirm ACPI _DSD information (and other useful info) for each amp on each system using CS35L41, without having to get the acpidump. Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20230802121235.467358-1-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index 98feb5ccd586..825e551be9bb 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -1124,6 +1124,13 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); + dev_info(cs35l41->dev, + "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', + cs35l41->firmware_running, cs35l41->speaker_id); + return ret; } From a13b5340aa6892685adf655cd4bfa91a83d5a9d2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:01:01 -0500 Subject: [PATCH 262/334] PCI: add ArrowLake-S PCI ID for Intel HDAudio subsystem. Add part ID to common include file Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802150105.24604-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- include/linux/pci_ids.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 3066660cd39b..a6411aa4c331 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -3058,6 +3058,7 @@ #define PCI_DEVICE_ID_INTEL_HDA_RPL_S 0x7a50 #define PCI_DEVICE_ID_INTEL_HDA_ADL_S 0x7ad0 #define PCI_DEVICE_ID_INTEL_HDA_MTL 0x7e28 +#define PCI_DEVICE_ID_INTEL_HDA_ARL_S 0x7f50 #define PCI_DEVICE_ID_INTEL_SCH_LPC 0x8119 #define PCI_DEVICE_ID_INTEL_SCH_IDE 0x811a #define PCI_DEVICE_ID_INTEL_HDA_POULSBO 0x811b From 3bef0681682296c61f713fdb7989cb11bb836b5f Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 2 Aug 2023 10:01:02 -0500 Subject: [PATCH 263/334] ALSA: hda: add HD Audio PCI ID for Intel Arrow Lake-S Add HD Audio PCI ID for Intel Arrow Lake-S platform. Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Signed-off-by: Kai Vehmanen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230802150105.24604-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 176567f0d0e0..765d95e79861 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2499,6 +2499,8 @@ static const struct pci_device_id azx_ids[] = { { PCI_DEVICE_DATA(INTEL, HDA_MTL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Lunarlake-P */ { PCI_DEVICE_DATA(INTEL, HDA_LNL_P, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + /* Arrow Lake-S */ + { PCI_DEVICE_DATA(INTEL, HDA_ARL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Apollolake (Broxton-P) */ { PCI_DEVICE_DATA(INTEL, HDA_APL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON) }, /* Gemini-Lake */ From 73e6ebf6a21a62429282632eccb8aa4212489b3c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:01:03 -0500 Subject: [PATCH 264/334] ALSA: hda: intel-dsp-cfg: use common include for MeteorLake This was not updated in Commit 0cd0a7c2c599 ("ALSA: intel-dsp-config: Convert to PCI device IDs defines") Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802150105.24604-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/hda/intel-dsp-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index 48bd1fb06f26..1abe65f0ba1b 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -461,7 +461,7 @@ static const struct config_entry config_table[] = { /* Meteorlake-P */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x7e28, + .device = PCI_DEVICE_ID_INTEL_HDA_MTL, }, #endif From d2852b8c045ebd31d753b06f2810df5be30ed56a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:01:04 -0500 Subject: [PATCH 265/334] ALSA: hda: intel-dsp-cfg: add LunarLake support One more PCI ID for the road. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802150105.24604-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/hda/intel-dsp-config.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index 1abe65f0ba1b..dcf2453138a5 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -465,6 +465,14 @@ static const struct config_entry config_table[] = { }, #endif +/* Lunar Lake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_LUNARLAKE) + /* Lunarlake-P */ + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, + .device = PCI_DEVICE_ID_INTEL_HDA_LNL_P, + }, +#endif }; static const struct config_entry *snd_intel_dsp_find_config From 3f8c530fc458142e0db0185f18153d85c4359203 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 2 Aug 2023 10:01:05 -0500 Subject: [PATCH 266/334] ALSA: hda/i915: extend connectivity check to cover Intel ARL Expand the HDA/I915 connectivity check to correctly handle the PCI topology used in some Intel Arrow Lake products. Reviewed-by: Bard Liao Tested-by: "T, Arun" Signed-off-by: Kai Vehmanen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230802150105.24604-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/hda/hdac_i915.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c index 2a451ff4fe6a..b428537f284c 100644 --- a/sound/hda/hdac_i915.c +++ b/sound/hda/hdac_i915.c @@ -75,16 +75,22 @@ static bool connectivity_check(struct pci_dev *i915, struct pci_dev *hdac) if (bus_a == bus_b) return true; + bus_a = bus_a->parent; + bus_b = bus_b->parent; + + /* connected via parent bus (may be NULL!) */ + if (bus_a == bus_b) + return true; + + if (!bus_a || !bus_b) + return false; + /* * on i915 discrete GPUs with embedded HDA audio, the two * devices are connected via 2nd level PCI bridge */ bus_a = bus_a->parent; bus_b = bus_b->parent; - if (!bus_a || !bus_b) - return false; - bus_a = bus_a->parent; - bus_b = bus_b->parent; if (bus_a && bus_a == bus_b) return true; From 205b96e307480e0484894b619c481fac5b6653e6 Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Fri, 4 Aug 2023 15:07:39 +0400 Subject: [PATCH 267/334] ALSA: pcmtest: Move buffer iterator initialization to prepare callback Trigger callback is not the best place for buffer iterator initialization, so move it out to the prepare callback, where it have to be. Minor enhancement: remove blank line. Signed-off-by: Ivan Orlov Link: https://lore.kernel.org/r/20230804110740.9867-1-ivan.orlov0322@gmail.com Signed-off-by: Takashi Iwai --- sound/drivers/pcmtest.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/sound/drivers/pcmtest.c b/sound/drivers/pcmtest.c index 08e14b5eb772..dc7c9c758537 100644 --- a/sound/drivers/pcmtest.c +++ b/sound/drivers/pcmtest.c @@ -92,7 +92,6 @@ MODULE_PARM_DESC(inject_trigger_err, "Inject EINVAL error in the 'trigger' callb module_param(inject_open_err, bool, 0600); MODULE_PARM_DESC(inject_open_err, "Inject EBUSY error in the 'open' callback"); - struct pcmtst { struct snd_pcm *pcm; struct snd_card *card; @@ -405,25 +404,9 @@ static int snd_pcmtst_pcm_close(struct snd_pcm_substream *substream) static int snd_pcmtst_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { - struct snd_pcm_runtime *runtime = substream->runtime; - struct pcmtst_buf_iter *v_iter = runtime->private_data; - if (inject_trigger_err) return -EINVAL; - v_iter->sample_bytes = runtime->sample_bits / 8; - v_iter->period_bytes = frames_to_bytes(runtime, runtime->period_size); - if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED || - runtime->access == SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED) { - v_iter->chan_block = runtime->dma_bytes / runtime->channels; - v_iter->interleaved = false; - } else { - v_iter->interleaved = true; - } - // We want to record RATE * ch_cnt samples per sec, it is rate * sample_bytes * ch_cnt bytes - v_iter->s_rw_ch = runtime->rate / TIMER_PER_SEC; - v_iter->b_rw = v_iter->s_rw_ch * v_iter->sample_bytes * runtime->channels; - return 0; } @@ -454,8 +437,24 @@ static void pcmtst_pdev_release(struct device *dev) static int snd_pcmtst_pcm_prepare(struct snd_pcm_substream *substream) { + struct snd_pcm_runtime *runtime = substream->runtime; + struct pcmtst_buf_iter *v_iter = runtime->private_data; + if (inject_prepare_err) return -EINVAL; + + v_iter->sample_bytes = samples_to_bytes(runtime, 1); + v_iter->period_bytes = snd_pcm_lib_period_bytes(substream); + v_iter->interleaved = true; + if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED || + runtime->access == SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED) { + v_iter->chan_block = snd_pcm_lib_buffer_bytes(substream) / runtime->channels; + v_iter->interleaved = false; + } + // We want to record RATE * ch_cnt samples per sec, it is rate * sample_bytes * ch_cnt bytes + v_iter->s_rw_ch = runtime->rate / TIMER_PER_SEC; + v_iter->b_rw = v_iter->s_rw_ch * v_iter->sample_bytes * runtime->channels; + return 0; } From bba0498bd2d31f958b697d9d8a6b1c106de02e43 Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Fri, 4 Aug 2023 15:07:40 +0400 Subject: [PATCH 268/334] ALSA: pcmtest: Remove redundant definitions Remove redundant definitions of DEVNAME and CARD_NAME, as they're not useful. The former is not used anywhere, and the latter is used only in module parameters descriptions. Signed-off-by: Ivan Orlov Link: https://lore.kernel.org/r/20230804110740.9867-2-ivan.orlov0322@gmail.com Signed-off-by: Takashi Iwai --- sound/drivers/pcmtest.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sound/drivers/pcmtest.c b/sound/drivers/pcmtest.c index dc7c9c758537..7f170429eb8f 100644 --- a/sound/drivers/pcmtest.c +++ b/sound/drivers/pcmtest.c @@ -41,8 +41,6 @@ #include #include -#define DEVNAME "pcmtestd" -#define CARD_NAME "pcm-test-card" #define TIMER_PER_SEC 5 #define TIMER_INTERVAL (HZ / TIMER_PER_SEC) #define DELAY_JIFFIES HZ @@ -74,11 +72,11 @@ static u8 ioctl_reset_test; static struct dentry *driver_debug_dir; module_param(index, int, 0444); -MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard"); +MODULE_PARM_DESC(index, "Index value for pcmtest soundcard"); module_param(id, charp, 0444); -MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard"); +MODULE_PARM_DESC(id, "ID string for pcmtest soundcard"); module_param(enable, bool, 0444); -MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); +MODULE_PARM_DESC(enable, "Enable pcmtest soundcard."); module_param(fill_mode, short, 0600); MODULE_PARM_DESC(fill_mode, "Buffer fill mode: rand(0) or pattern(1)"); module_param(inject_delay, int, 0600); From f95d5efa9f8a468051e20c349c2913720551dfa9 Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Mon, 7 Aug 2023 22:15:13 +0800 Subject: [PATCH 269/334] ALSA: info: Remove unused function declarations These declarations is never used since beginning of git history. Signed-off-by: Yue Haibing Link: https://lore.kernel.org/r/20230807141513.31440-1-yuehaibing@huawei.com Signed-off-by: Takashi Iwai --- include/sound/info.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/sound/info.h b/include/sound/info.h index 7c13bf52cc81..adbc506860d6 100644 --- a/include/sound/info.h +++ b/include/sound/info.h @@ -118,8 +118,6 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, const char *name, struct snd_info_entry *parent); void snd_info_free_entry(struct snd_info_entry *entry); -int snd_info_store_text(struct snd_info_entry *entry); -int snd_info_restore_text(struct snd_info_entry *entry); int snd_info_card_create(struct snd_card *card); int snd_info_card_register(struct snd_card *card); From 3d28c466317b9515810a1f5ec29be394269bcb73 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Mon, 7 Aug 2023 17:49:28 +0000 Subject: [PATCH 270/334] ALSA: hda/tegra: refactor deprecated strncpy `strncpy` is deprecated for use on NUL-terminated destination strings [1]. A suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on its destination buffer argument which is _not_ the case for `strncpy`! It should be noted that the current implementation is unlikely to have a bug because `drv_name` is a string literal with a size of 9 while `card->driver` has a size of 16. However, it is probably worthwhile to switch to a more robust and less ambiguous interface. [1]: www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [2]: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20230807-sound-pci-hda-v1-1-6d9cdcd085ca@google.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_tegra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 39fa036616ce..d967e70a7058 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -379,14 +379,14 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev) } /* driver name */ - strncpy(card->driver, drv_name, sizeof(card->driver)); + strscpy(card->driver, drv_name, sizeof(card->driver)); /* shortname for card */ sname = of_get_property(np, "nvidia,model", NULL); if (!sname) sname = drv_name; if (strlen(sname) > sizeof(card->shortname)) dev_info(card->dev, "truncating shortname for card\n"); - strncpy(card->shortname, sname, sizeof(card->shortname)); + strscpy(card->shortname, sname, sizeof(card->shortname)); /* longname for card */ snprintf(card->longname, sizeof(card->longname), From ff7a0b4016cb349f9148d0bf9c664e604167128c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 9 Aug 2023 09:26:31 +0900 Subject: [PATCH 271/334] ALSA: dice: add stream format parameters for Weiss devices Hard-coded stream format parameters are added for Weiss Engineering FireWire devices. When the device vendor and model match, the parameters are copied into the stream format cache. This allows for setting all supported sampling rates up to 192kHz, and consequently adjusting the number of available I/O channels. Signed-off-by: Rolf Anderegg Signed-off-by: Michele Perrone Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20230809002631.750120-1-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/dice/Makefile | 2 +- sound/firewire/dice/dice-weiss.c | 104 +++++++++++++++++++++++++++++++ sound/firewire/dice/dice.c | 63 +++++++++++++++++++ sound/firewire/dice/dice.h | 1 + 4 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 sound/firewire/dice/dice-weiss.c diff --git a/sound/firewire/dice/Makefile b/sound/firewire/dice/Makefile index a5f3fbf28b8c..bac8712f9014 100644 --- a/sound/firewire/dice/Makefile +++ b/sound/firewire/dice/Makefile @@ -2,5 +2,5 @@ snd-dice-objs := dice-transaction.o dice-stream.o dice-proc.o dice-midi.o \ dice-pcm.o dice-hwdep.o dice.o dice-tcelectronic.o \ dice-alesis.o dice-extension.o dice-mytek.o dice-presonus.o \ - dice-harman.o dice-focusrite.o + dice-harman.o dice-focusrite.o dice-weiss.o obj-$(CONFIG_SND_DICE) += snd-dice.o diff --git a/sound/firewire/dice/dice-weiss.c b/sound/firewire/dice/dice-weiss.c new file mode 100644 index 000000000000..129d43408956 --- /dev/null +++ b/sound/firewire/dice/dice-weiss.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0 +// dice-weiss.c - a part of driver for DICE based devices +// +// Copyright (c) 2023 Rolf Anderegg and Michele Perrone + +#include "dice.h" + +struct dice_weiss_spec { + unsigned int tx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT]; + unsigned int rx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT]; +}; + +// Weiss DAC202: 192kHz 2-channel DAC +static const struct dice_weiss_spec dac202 = { + .tx_pcm_chs = {{2, 2, 2}, {0, 0, 0} }, + .rx_pcm_chs = {{2, 2, 2}, {0, 0, 0} }, +}; + +// Weiss MAN301: 192kHz 2-channel music archive network player +static const struct dice_weiss_spec man301 = { + .tx_pcm_chs = {{2, 2, 2}, {0, 0, 0} }, + .rx_pcm_chs = {{2, 2, 2}, {0, 0, 0} }, +}; + +// Weiss INT202: 192kHz unidirectional 2-channel digital Firewire nterface +static const struct dice_weiss_spec int202 = { + .tx_pcm_chs = {{2, 2, 2}, {0, 0, 0} }, + .rx_pcm_chs = {{2, 2, 2}, {0, 0, 0} }, +}; + +// Weiss INT203: 192kHz bidirectional 2-channel digital Firewire nterface +static const struct dice_weiss_spec int203 = { + .tx_pcm_chs = {{2, 2, 2}, {0, 0, 0} }, + .rx_pcm_chs = {{2, 2, 2}, {0, 0, 0} }, +}; + +// Weiss ADC2: 192kHz A/D converter with microphone preamps and line nputs +static const struct dice_weiss_spec adc2 = { + .tx_pcm_chs = {{2, 2, 2}, {0, 0, 0} }, + .rx_pcm_chs = {{2, 2, 2}, {0, 0, 0} }, +}; + +// Weiss DAC2/Minerva: 192kHz 2-channel DAC +static const struct dice_weiss_spec dac2_minerva = { + .tx_pcm_chs = {{2, 2, 2}, {0, 0, 0} }, + .rx_pcm_chs = {{2, 2, 2}, {0, 0, 0} }, +}; + +// Weiss Vesta: 192kHz 2-channel Firewire to AES/EBU interface +static const struct dice_weiss_spec vesta = { + .tx_pcm_chs = {{2, 2, 2}, {0, 0, 0} }, + .rx_pcm_chs = {{2, 2, 2}, {0, 0, 0} }, +}; + +// Weiss AFI1: 192kHz 24-channel Firewire to ADAT or AES/EBU interface +static const struct dice_weiss_spec afi1 = { + .tx_pcm_chs = {{24, 16, 8}, {0, 0, 0} }, + .rx_pcm_chs = {{24, 16, 8}, {0, 0, 0} }, +}; + +int snd_dice_detect_weiss_formats(struct snd_dice *dice) +{ + static const struct { + u32 model_id; + const struct dice_weiss_spec *spec; + } *entry, entries[] = { + {0x000007, &dac202}, + {0x000008, &dac202}, // Maya edition: same audio I/O as DAC202. + {0x000006, &int202}, + {0x00000a, &int203}, + {0x00000b, &man301}, + {0x000001, &adc2}, + {0x000003, &dac2_minerva}, + {0x000002, &vesta}, + {0x000004, &afi1}, + }; + struct fw_csr_iterator it; + int key, val, model_id; + int i; + + model_id = 0; + fw_csr_iterator_init(&it, dice->unit->directory); + while (fw_csr_iterator_next(&it, &key, &val)) { + if (key == CSR_MODEL) { + model_id = val; + break; + } + } + + for (i = 0; i < ARRAY_SIZE(entries); ++i) { + entry = entries + i; + if (entry->model_id == model_id) + break; + } + if (i == ARRAY_SIZE(entries)) + return -ENODEV; + + memcpy(dice->tx_pcm_chs, entry->spec->tx_pcm_chs, + MAX_STREAMS * SND_DICE_RATE_MODE_COUNT * sizeof(unsigned int)); + memcpy(dice->rx_pcm_chs, entry->spec->rx_pcm_chs, + MAX_STREAMS * SND_DICE_RATE_MODE_COUNT * sizeof(unsigned int)); + + return 0; +} diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 6c93e6e4982c..d362e4251c68 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -392,6 +392,69 @@ static const struct ieee1394_device_id dice_id_table[] = { .model_id = 0x0000de, .driver_data = (kernel_ulong_t)snd_dice_detect_focusrite_pro40_tcd3070_formats, }, + // Weiss DAC202: 192kHz 2-channel DAC + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_WEISS, + .model_id = 0x000007, + .driver_data = (kernel_ulong_t)snd_dice_detect_weiss_formats, + }, + // Weiss DAC202: 192kHz 2-channel DAC (Maya edition) + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_WEISS, + .model_id = 0x000008, + .driver_data = (kernel_ulong_t)snd_dice_detect_weiss_formats, + }, + // Weiss MAN301: 192kHz 2-channel music archive network player + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_WEISS, + .model_id = 0x00000b, + .driver_data = (kernel_ulong_t)snd_dice_detect_weiss_formats, + }, + // Weiss INT202: 192kHz unidirectional 2-channel digital Firewire face + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_WEISS, + .model_id = 0x000006, + .driver_data = (kernel_ulong_t)snd_dice_detect_weiss_formats, + }, + // Weiss INT203: 192kHz bidirectional 2-channel digital Firewire face + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_WEISS, + .model_id = 0x00000a, + .driver_data = (kernel_ulong_t)snd_dice_detect_weiss_formats, + }, + // Weiss ADC2: 192kHz A/D converter with microphone preamps and inputs + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_WEISS, + .model_id = 0x000001, + .driver_data = (kernel_ulong_t)snd_dice_detect_weiss_formats, + }, + // Weiss DAC2/Minerva: 192kHz 2-channel DAC + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_WEISS, + .model_id = 0x000003, + .driver_data = (kernel_ulong_t)snd_dice_detect_weiss_formats, + }, + // Weiss Vesta: 192kHz 2-channel Firewire to AES/EBU interface + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_WEISS, + .model_id = 0x000002, + .driver_data = (kernel_ulong_t)snd_dice_detect_weiss_formats, + }, + // Weiss AFI1: 192kHz 24-channel Firewire to ADAT or AES/EBU face + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_WEISS, + .model_id = 0x000004, + .driver_data = (kernel_ulong_t)snd_dice_detect_weiss_formats, + }, { .match_flags = IEEE1394_MATCH_VERSION, .version = DICE_INTERFACE, diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index 674f7d552c2e..4c0ad7335998 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -232,5 +232,6 @@ int snd_dice_detect_mytek_formats(struct snd_dice *dice); int snd_dice_detect_presonus_formats(struct snd_dice *dice); int snd_dice_detect_harman_formats(struct snd_dice *dice); int snd_dice_detect_focusrite_pro40_tcd3070_formats(struct snd_dice *dice); +int snd_dice_detect_weiss_formats(struct snd_dice *dice); #endif From ef4ba63f12b03532378395a8611f2f6e22ece67b Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Tue, 15 Aug 2023 17:10:33 +0100 Subject: [PATCH 272/334] ALSA: hda: cs35l41: Support systems with missing _DSD properties Some systems using CS35L41 with HDA were released without some required _DSD properties in ACPI. To support these special cases, add an api to configure the correct properties for systems with this issue. This initial commit moves the no _DSD support for Lenovo Legion Laptops (CLSA0100, CLSA0101) into a new framework which can be extended to support additional laptops in the future. Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20230815161033.3519-1-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/Makefile | 2 +- sound/pci/hda/cs35l41_hda.c | 65 ++++++------------------- sound/pci/hda/cs35l41_hda.h | 1 + sound/pci/hda/cs35l41_hda_property.c | 73 ++++++++++++++++++++++++++++ sound/pci/hda/cs35l41_hda_property.h | 18 +++++++ 5 files changed, 108 insertions(+), 51 deletions(-) create mode 100644 sound/pci/hda/cs35l41_hda_property.c create mode 100644 sound/pci/hda/cs35l41_hda_property.h diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index c6e6509e7b8e..5506255be895 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -28,7 +28,7 @@ snd-hda-codec-via-objs := patch_via.o snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o # side codecs -snd-hda-scodec-cs35l41-objs := cs35l41_hda.o +snd-hda-scodec-cs35l41-objs := cs35l41_hda.o cs35l41_hda_property.o snd-hda-scodec-cs35l41-i2c-objs := cs35l41_hda_i2c.o snd-hda-scodec-cs35l41-spi-objs := cs35l41_hda_spi.o snd-hda-scodec-cs35l56-objs := cs35l56_hda.o diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index 825e551be9bb..f9b77353c266 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -19,6 +19,7 @@ #include "hda_component.h" #include "cs35l41_hda.h" #include "hda_cs_dsp_ctl.h" +#include "cs35l41_hda_property.h" #define CS35L41_FIRMWARE_ROOT "cirrus/" #define CS35L41_PART "cs35l41" @@ -1315,8 +1316,7 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41) return cs35l41_hda_channel_map(cs35l41->dev, 0, NULL, 1, &hw_cfg->spk_pos); } -static int cs35l41_get_speaker_id(struct device *dev, int amp_index, - int num_amps, int fixed_gpio_id) +int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int fixed_gpio_id) { struct gpio_desc *speaker_id_desc; int speaker_id = -ENODEV; @@ -1370,49 +1370,6 @@ static int cs35l41_get_speaker_id(struct device *dev, int amp_index, return speaker_id; } -/* - * Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work. - * And devices created by serial-multi-instantiate don't have their device struct - * pointing to the correct fwnode, so acpi_dev must be used here. - * And devm functions expect that the device requesting the resource has the correct - * fwnode. - */ -static int cs35l41_no_acpi_dsd(struct cs35l41_hda *cs35l41, struct device *physdev, int id, - const char *hid) -{ - struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg; - - /* check I2C address to assign the index */ - cs35l41->index = id == 0x40 ? 0 : 1; - cs35l41->channel_index = 0; - cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH); - cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2); - hw_cfg->spk_pos = cs35l41->index; - hw_cfg->gpio2.func = CS35L41_INTERRUPT; - hw_cfg->gpio2.valid = true; - hw_cfg->valid = true; - - if (strncmp(hid, "CLSA0100", 8) == 0) { - hw_cfg->bst_type = CS35L41_EXT_BOOST_NO_VSPK_SWITCH; - } else if (strncmp(hid, "CLSA0101", 8) == 0) { - hw_cfg->bst_type = CS35L41_EXT_BOOST; - hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH; - hw_cfg->gpio1.valid = true; - } else { - /* - * Note: CLSA010(0/1) are special cases which use a slightly different design. - * All other HIDs e.g. CSC3551 require valid ACPI _DSD properties to be supported. - */ - dev_err(cs35l41->dev, "Error: ACPI _DSD Properties are missing for HID %s.\n", hid); - hw_cfg->valid = false; - hw_cfg->gpio1.valid = false; - hw_cfg->gpio2.valid = false; - return -EINVAL; - } - - return 0; -} - static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id) { struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg; @@ -1438,12 +1395,17 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i sub = NULL; cs35l41->acpi_subsystem_id = sub; + ret = cs35l41_add_dsd_properties(cs35l41, physdev, id, hid); + if (!ret) { + dev_info(cs35l41->dev, "Using extra _DSD properties, bypassing _DSD in ACPI\n"); + goto put_physdev; + } + property = "cirrus,dev-index"; ret = device_property_count_u32(physdev, property); - if (ret <= 0) { - ret = cs35l41_no_acpi_dsd(cs35l41, physdev, id, hid); - goto err_put_physdev; - } + if (ret <= 0) + goto err; + if (ret > ARRAY_SIZE(values)) { ret = -EINVAL; goto err; @@ -1533,7 +1495,10 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i err: dev_err(cs35l41->dev, "Failed property %s: %d\n", property, ret); -err_put_physdev: + hw_cfg->valid = false; + hw_cfg->gpio1.valid = false; + hw_cfg->gpio2.valid = false; +put_physdev: put_device(physdev); return ret; diff --git a/sound/pci/hda/cs35l41_hda.h b/sound/pci/hda/cs35l41_hda.h index bdb35f3be68a..b93bf762976e 100644 --- a/sound/pci/hda/cs35l41_hda.h +++ b/sound/pci/hda/cs35l41_hda.h @@ -83,5 +83,6 @@ extern const struct dev_pm_ops cs35l41_hda_pm_ops; int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq, struct regmap *regmap); void cs35l41_hda_remove(struct device *dev); +int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int fixed_gpio_id); #endif /*__CS35L41_HDA_H__*/ diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c new file mode 100644 index 000000000000..673f23257a09 --- /dev/null +++ b/sound/pci/hda/cs35l41_hda_property.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// CS35L41 ALSA HDA Property driver +// +// Copyright 2023 Cirrus Logic, Inc. +// +// Author: Stefan Binding + +#include +#include +#include "cs35l41_hda_property.h" + +/* + * Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work. + * And devices created by serial-multi-instantiate don't have their device struct + * pointing to the correct fwnode, so acpi_dev must be used here. + * And devm functions expect that the device requesting the resource has the correct + * fwnode. + */ +static int lenovo_legion_no_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id, + const char *hid) +{ + struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg; + + /* check I2C address to assign the index */ + cs35l41->index = id == 0x40 ? 0 : 1; + cs35l41->channel_index = 0; + cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH); + cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2); + hw_cfg->spk_pos = cs35l41->index; + hw_cfg->gpio2.func = CS35L41_INTERRUPT; + hw_cfg->gpio2.valid = true; + hw_cfg->valid = true; + + if (strcmp(hid, "CLSA0100") == 0) { + hw_cfg->bst_type = CS35L41_EXT_BOOST_NO_VSPK_SWITCH; + } else if (strcmp(hid, "CLSA0101") == 0) { + hw_cfg->bst_type = CS35L41_EXT_BOOST; + hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH; + hw_cfg->gpio1.valid = true; + } + + return 0; +} + +struct cs35l41_prop_model { + const char *hid; + const char *ssid; + int (*add_prop)(struct cs35l41_hda *cs35l41, struct device *physdev, int id, + const char *hid); +}; + +const struct cs35l41_prop_model cs35l41_prop_model_table[] = { + { "CLSA0100", NULL, lenovo_legion_no_acpi }, + { "CLSA0101", NULL, lenovo_legion_no_acpi }, + {} +}; + +int cs35l41_add_dsd_properties(struct cs35l41_hda *cs35l41, struct device *physdev, int id, + const char *hid) +{ + const struct cs35l41_prop_model *model; + + for (model = cs35l41_prop_model_table; model->hid > 0; model++) { + if (!strcmp(model->hid, hid) && + (!model->ssid || + (cs35l41->acpi_subsystem_id && + !strcmp(model->ssid, cs35l41->acpi_subsystem_id)))) + return model->add_prop(cs35l41, physdev, id, hid); + } + + return -ENOENT; +} diff --git a/sound/pci/hda/cs35l41_hda_property.h b/sound/pci/hda/cs35l41_hda_property.h new file mode 100644 index 000000000000..fd834042e2fd --- /dev/null +++ b/sound/pci/hda/cs35l41_hda_property.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * CS35L41 ALSA HDA Property driver + * + * Copyright 2023 Cirrus Logic, Inc. + * + * Author: Stefan Binding + */ + +#ifndef CS35L41_HDA_PROP_H +#define CS35L41_HDA_PROP_H + +#include +#include "cs35l41_hda.h" + +int cs35l41_add_dsd_properties(struct cs35l41_hda *cs35l41, struct device *physdev, int id, + const char *hid); +#endif /* CS35L41_HDA_PROP_H */ From 409896794380c1dc0d596bbb9255e583a94d9a00 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 08:35:25 +0200 Subject: [PATCH 273/334] ALSA: hda: cs35l41: Fix the loop check in cs35l41_add_dsd_properties model->hid is a pointer, and should be rather NULL-checked in the loop of cs35l41_prop_model_table. Fixes: ef4ba63f12b0 ("ALSA: hda: cs35l41: Support systems with missing _DSD properties") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202308160506.8lCEeFDG-lkp@intel.com/ Link: https://lore.kernel.org/r/20230816063525.23009-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda_property.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c index 673f23257a09..48dcc3f1ef88 100644 --- a/sound/pci/hda/cs35l41_hda_property.c +++ b/sound/pci/hda/cs35l41_hda_property.c @@ -61,7 +61,7 @@ int cs35l41_add_dsd_properties(struct cs35l41_hda *cs35l41, struct device *physd { const struct cs35l41_prop_model *model; - for (model = cs35l41_prop_model_table; model->hid > 0; model++) { + for (model = cs35l41_prop_model_table; model->hid; model++) { if (!strcmp(model->hid, hid) && (!model->ssid || (cs35l41->acpi_subsystem_id && From 905240d169ebe4b879628b4a05316332803a3c3d Mon Sep 17 00:00:00 2001 From: Brady Norander Date: Tue, 15 Aug 2023 09:52:46 -0400 Subject: [PATCH 274/334] ALSA: hda: intel-dsp-cfg: Add Chromebook quirk to ADL/RPL AlderLake and RaptorLake Chromebooks currently use the HDA driver by default. Add a quirk to use the SOF driver on these platforms, which is needed for functional internal audio. Signed-off-by: Brady Norander Acked-by: Pierre-Louis Bossart Acked-by: Curtis Malainey Link: https://lore.kernel.org/r/ZNuDLk5hgmfKrZg6@arch Signed-off-by: Takashi Iwai --- sound/hda/intel-dsp-config.c | 60 +++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index dcf2453138a5..24a948baf1bc 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -167,10 +167,10 @@ static const struct config_entry config_table[] = { #endif /* - * CoffeeLake, CannonLake, CometLake, IceLake, TigerLake use legacy - * HDAudio driver except for Google Chromebooks and when DMICs are - * present. Two cases are required since Coreboot does not expose NHLT - * tables. + * CoffeeLake, CannonLake, CometLake, IceLake, TigerLake, AlderLake, + * RaptorLake use legacy HDAudio driver except for Google Chromebooks + * and when DMICs are present. Two cases are required since Coreboot + * does not expose NHLT tables. * * When the Chromebook quirk is not present, it's based on information * that no such device exists. When the quirk is present, it could be @@ -408,6 +408,19 @@ static const struct config_entry config_table[] = { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .device = PCI_DEVICE_ID_INTEL_HDA_RPL_S, }, + { + .flags = FLAG_SOF, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {} + } + }, { .flags = FLAG_SOF, .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P, @@ -434,14 +447,53 @@ static const struct config_entry config_table[] = { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .device = PCI_DEVICE_ID_INTEL_HDA_ADL_M, }, + { + .flags = FLAG_SOF, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_N, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {} + } + }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .device = PCI_DEVICE_ID_INTEL_HDA_ADL_N, }, + { + .flags = FLAG_SOF, + .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {} + } + }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0, }, + { + .flags = FLAG_SOF, + .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {} + } + }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1, From 2e6f979037d5ae35c0ed38e2b63e9876eb7bc65f Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 17 Aug 2023 09:42:52 +0800 Subject: [PATCH 275/334] ALSA: hda: cs35l41: change cs35l41_prop_model to static cs35l41_prop_model is only used in cs35l41_hda_property.c now, change it to static. Fixes: ef4ba63f12b0 ("ALSA: hda: cs35l41: Support systems with missing _DSD properties") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20230817014252.1511232-1-yangyingliang@huawei.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda_property.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c index 48dcc3f1ef88..9b5a1d61575e 100644 --- a/sound/pci/hda/cs35l41_hda_property.c +++ b/sound/pci/hda/cs35l41_hda_property.c @@ -50,7 +50,7 @@ struct cs35l41_prop_model { const char *hid); }; -const struct cs35l41_prop_model cs35l41_prop_model_table[] = { +static const struct cs35l41_prop_model cs35l41_prop_model_table[] = { { "CLSA0100", NULL, lenovo_legion_no_acpi }, { "CLSA0101", NULL, lenovo_legion_no_acpi }, {} From 7f018db19bf7cb5ba3e39ed9e51c8c5f2488dfb0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 18:02:44 +0200 Subject: [PATCH 276/334] ALSA: core: Introduce snd_device_alloc() Introduce a new helper, snd_device_alloc(), for allocating a struct device that is bound with the sound class. It's a replacement of snd_device_initialize(). Reviewed-by: Jaroslav Kysela Signed-off-by: Curtis Malainey Tested-by: Curtis Malainey Link: https://lore.kernel.org/r/20230816160252.23396-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/core.h | 1 + sound/core/init.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/sound/core.h b/include/sound/core.h index f6e0dd648b80..f986fcc5f18f 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -239,6 +239,7 @@ extern struct dentry *sound_debugfs_root; void snd_request_card(int card); +int snd_device_alloc(struct device **dev_p, struct snd_card *card); void snd_device_initialize(struct device *dev, struct snd_card *card); int snd_register_device(int type, struct snd_card *card, int dev, diff --git a/sound/core/init.c b/sound/core/init.c index baef2688d0cf..a4de9f00d90f 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -134,6 +134,37 @@ void snd_device_initialize(struct device *dev, struct snd_card *card) } EXPORT_SYMBOL_GPL(snd_device_initialize); +/* the default release callback set in snd_device_alloc() */ +static void default_release_alloc(struct device *dev) +{ + kfree(dev); +} + +/** + * snd_device_alloc - Allocate and initialize struct device for sound devices + * @dev_p: pointer to store the allocated device + * @card: card to assign, optional + * + * For releasing the allocated device, call put_device(). + */ +int snd_device_alloc(struct device **dev_p, struct snd_card *card) +{ + struct device *dev; + + *dev_p = NULL; + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + device_initialize(dev); + if (card) + dev->parent = &card->card_dev; + dev->class = &sound_class; + dev->release = default_release_alloc; + *dev_p = dev; + return 0; +} +EXPORT_SYMBOL_GPL(snd_device_alloc); + static int snd_card_init(struct snd_card *card, struct device *parent, int idx, const char *xid, struct module *module, size_t extra_size); From 6a66b01de48855d92450904ccfafda9d692efbb9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 18:02:45 +0200 Subject: [PATCH 277/334] ALSA: control: Don't embed ctl_dev Embedding the ctl_dev in the snd_card object may result in UAF when the delayed kobj release is used; at the delayed kobj release, it still accesses the struct device itself while the card memory (that embeds the struct device) may be already gone. As a workaround, detach the struct device from the card object by allocating via the new snd_device_alloc() helper. The rest are just replacing ctl_dev access to the pointer. This is based on the fix Curtis posted initially. In this patch, the changes are split and use the new helper function instead. Link: https://lore.kernel.org/r/20230801171928.1460120-1-cujomalainey@chromium.org Reviewed-by: Jaroslav Kysela Signed-off-by: Curtis Malainey Tested-by: Curtis Malainey Link: https://lore.kernel.org/r/20230816160252.23396-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/core.h | 2 +- sound/core/control.c | 14 ++++++++------ sound/core/control_led.c | 4 ++-- sound/usb/media.c | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/include/sound/core.h b/include/sound/core.h index f986fcc5f18f..f3f6b720a278 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -96,7 +96,7 @@ struct snd_card { private data */ struct list_head devices; /* devices */ - struct device ctl_dev; /* control device */ + struct device *ctl_dev; /* control device */ unsigned int last_numid; /* last used numeric ID */ struct rw_semaphore controls_rwsem; /* controls lock (list and values) */ rwlock_t ctl_files_rwlock; /* ctl_files list lock */ diff --git a/sound/core/control.c b/sound/core/control.c index e13e9d6b3b89..59c8658966d4 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -2389,7 +2389,7 @@ static int snd_ctl_dev_register(struct snd_device *device) int err; err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1, - &snd_ctl_f_ops, card, &card->ctl_dev); + &snd_ctl_f_ops, card, card->ctl_dev); if (err < 0) return err; down_read(&card->controls_rwsem); @@ -2425,7 +2425,7 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) up_read(&snd_ctl_layer_rwsem); up_read(&card->controls_rwsem); - return snd_unregister_device(&card->ctl_dev); + return snd_unregister_device(card->ctl_dev); } /* @@ -2447,7 +2447,7 @@ static int snd_ctl_dev_free(struct snd_device *device) xa_destroy(&card->ctl_hash); #endif up_write(&card->controls_rwsem); - put_device(&card->ctl_dev); + put_device(card->ctl_dev); return 0; } @@ -2469,12 +2469,14 @@ int snd_ctl_create(struct snd_card *card) if (snd_BUG_ON(card->number < 0 || card->number >= SNDRV_CARDS)) return -ENXIO; - snd_device_initialize(&card->ctl_dev, card); - dev_set_name(&card->ctl_dev, "controlC%d", card->number); + err = snd_device_alloc(&card->ctl_dev, card); + if (err < 0) + return err; + dev_set_name(card->ctl_dev, "controlC%d", card->number); err = snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops); if (err < 0) - put_device(&card->ctl_dev); + put_device(card->ctl_dev); return err; } diff --git a/sound/core/control_led.c b/sound/core/control_led.c index 67fc2a1dcf7a..a78eb48927c7 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -688,7 +688,7 @@ static void snd_ctl_led_sysfs_add(struct snd_card *card) goto cerr; led->cards[card->number] = led_card; snprintf(link_name, sizeof(link_name), "led-%s", led->name); - WARN(sysfs_create_link(&card->ctl_dev.kobj, &led_card->dev.kobj, link_name), + WARN(sysfs_create_link(&card->ctl_dev->kobj, &led_card->dev.kobj, link_name), "can't create symlink to controlC%i device\n", card->number); WARN(sysfs_create_link(&led_card->dev.kobj, &card->card_dev.kobj, "card"), "can't create symlink to card%i\n", card->number); @@ -714,7 +714,7 @@ static void snd_ctl_led_sysfs_remove(struct snd_card *card) if (!led_card) continue; snprintf(link_name, sizeof(link_name), "led-%s", led->name); - sysfs_remove_link(&card->ctl_dev.kobj, link_name); + sysfs_remove_link(&card->ctl_dev->kobj, link_name); sysfs_remove_link(&led_card->dev.kobj, "card"); device_unregister(&led_card->dev); led->cards[card->number] = NULL; diff --git a/sound/usb/media.c b/sound/usb/media.c index 840f42cb9272..6d11fedb4632 100644 --- a/sound/usb/media.c +++ b/sound/usb/media.c @@ -163,7 +163,7 @@ void snd_media_stop_pipeline(struct snd_usb_substream *subs) static int snd_media_mixer_init(struct snd_usb_audio *chip) { - struct device *ctl_dev = &chip->card->ctl_dev; + struct device *ctl_dev = chip->card->ctl_dev; struct media_intf_devnode *ctl_intf; struct usb_mixer_interface *mixer; struct media_device *mdev = chip->media_dev; From bc41a7228cedc39395d032b2502975e53b7a9180 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 18:02:46 +0200 Subject: [PATCH 278/334] ALSA: pcm: Don't embed device So far we use the embedded struct device for each PCM substreams in struct snd_pcm. This may result in UAF when the delayed kobj release is used; each corresponding struct device is still accessed at the (delayed) device release, while the snd_pcm object may be already gone. As a workaround, detach the struct device from the snd_pcm object by allocating via the new snd_device_alloc() helper. A caveat is that we store the PCM substream pointer to drvdata since the device resume and others require the access to it. This patch is based on the fix Curtis posted initially. In this patch, the changes are split and use the new helper function instead. Link: https://lore.kernel.org/r/20230801171928.1460120-1-cujomalainey@chromium.org Reviewed-by: Jaroslav Kysela Signed-off-by: Curtis Malainey Tested-by: Curtis Malainey Link: https://lore.kernel.org/r/20230816160252.23396-4-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 2 +- sound/aoa/soundbus/i2sbus/pcm.c | 4 ++-- sound/core/pcm.c | 22 +++++++++++++--------- sound/usb/media.c | 2 +- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 19f564606ac4..0243a13e9ac4 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -510,7 +510,7 @@ struct snd_pcm_str { #endif #endif struct snd_kcontrol *chmap_kctl; /* channel-mapping controls */ - struct device dev; + struct device *dev; }; struct snd_pcm { diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c index a9e502a6cdeb..3680eb6eabc9 100644 --- a/sound/aoa/soundbus/i2sbus/pcm.c +++ b/sound/aoa/soundbus/i2sbus/pcm.c @@ -972,7 +972,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, goto out_put_ci_module; snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, &i2sbus_playback_ops); - dev->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].dev.parent = + dev->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK]->dev.parent = &dev->ofdev.dev; i2sdev->out.created = 1; } @@ -989,7 +989,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, goto out_put_ci_module; snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, &i2sbus_record_ops); - dev->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].dev.parent = + dev->pcm->streams[SNDRV_PCM_STREAM_CAPTURE]->dev.parent = &dev->ofdev.dev; i2sdev->in.created = 1; } diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 1c0bb3a07bff..20bb2d7c8d4b 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -604,7 +604,7 @@ static const struct attribute_group *pcm_dev_attr_groups[]; #ifdef CONFIG_PM_SLEEP static int do_pcm_suspend(struct device *dev) { - struct snd_pcm_str *pstr = container_of(dev, struct snd_pcm_str, dev); + struct snd_pcm_str *pstr = dev_get_drvdata(dev); if (!pstr->pcm->no_device_suspend) snd_pcm_suspend_all(pstr->pcm); @@ -650,11 +650,14 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) if (!substream_count) return 0; - snd_device_initialize(&pstr->dev, pcm->card); - pstr->dev.groups = pcm_dev_attr_groups; - pstr->dev.type = &pcm_dev_type; - dev_set_name(&pstr->dev, "pcmC%iD%i%c", pcm->card->number, pcm->device, + err = snd_device_alloc(&pstr->dev, pcm->card); + if (err < 0) + return err; + dev_set_name(pstr->dev, "pcmC%iD%i%c", pcm->card->number, pcm->device, stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c'); + pstr->dev->groups = pcm_dev_attr_groups; + pstr->dev->type = &pcm_dev_type; + dev_set_drvdata(pstr->dev, pstr); if (!pcm->internal) { err = snd_pcm_stream_proc_init(pstr); @@ -845,7 +848,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) #endif free_chmap(pstr); if (pstr->substream_count) - put_device(&pstr->dev); + put_device(pstr->dev); } #if IS_ENABLED(CONFIG_SND_PCM_OSS) @@ -1015,7 +1018,7 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) static ssize_t pcm_class_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct snd_pcm_str *pstr = container_of(dev, struct snd_pcm_str, dev); + struct snd_pcm_str *pstr = dev_get_drvdata(dev); struct snd_pcm *pcm = pstr->pcm; const char *str; static const char *strs[SNDRV_PCM_CLASS_LAST + 1] = { @@ -1076,7 +1079,7 @@ static int snd_pcm_dev_register(struct snd_device *device) /* register pcm */ err = snd_register_device(devtype, pcm->card, pcm->device, &snd_pcm_f_ops[cidx], pcm, - &pcm->streams[cidx].dev); + pcm->streams[cidx].dev); if (err < 0) { list_del_init(&pcm->list); goto unlock; @@ -1123,7 +1126,8 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) pcm_call_notify(pcm, n_disconnect); for (cidx = 0; cidx < 2; cidx++) { - snd_unregister_device(&pcm->streams[cidx].dev); + if (pcm->streams[cidx].dev) + snd_unregister_device(pcm->streams[cidx].dev); free_chmap(&pcm->streams[cidx]); } mutex_unlock(&pcm->open_mutex); diff --git a/sound/usb/media.c b/sound/usb/media.c index 6d11fedb4632..d48db6f3ae65 100644 --- a/sound/usb/media.c +++ b/sound/usb/media.c @@ -35,7 +35,7 @@ int snd_media_stream_init(struct snd_usb_substream *subs, struct snd_pcm *pcm, { struct media_device *mdev; struct media_ctl *mctl; - struct device *pcm_dev = &pcm->streams[stream].dev; + struct device *pcm_dev = pcm->streams[stream].dev; u32 intf_type; int ret = 0; u16 mixer_pad; From 897c8882df5875fe0bbc3e93ee8e9ba4a2c6ca0d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 18:02:47 +0200 Subject: [PATCH 279/334] ALSA: hwdep: Don't embed device Like control and PCM devices, it's better to avoid the embedded struct device for hwdep (although it's more or less well working), too. Change it to allocate via snd_device_alloc(), and free the memory at the common snd_hwdep_free(). Reviewed-by: Jaroslav Kysela Signed-off-by: Curtis Malainey Tested-by: Curtis Malainey Link: https://lore.kernel.org/r/20230816160252.23396-5-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/hwdep.h | 2 +- sound/core/hwdep.c | 38 +++++++++++++++++++++----------------- sound/pci/hda/hda_hwdep.c | 4 ++-- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/include/sound/hwdep.h b/include/sound/hwdep.h index 8d6cdb254039..b0da633184cd 100644 --- a/include/sound/hwdep.h +++ b/include/sound/hwdep.h @@ -53,7 +53,7 @@ struct snd_hwdep { wait_queue_head_t open_wait; void *private_data; void (*private_free) (struct snd_hwdep *hwdep); - struct device dev; + struct device *dev; struct mutex open_mutex; int used; /* reference counter */ diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index e95fa275c289..de7476034f2c 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -338,9 +338,14 @@ static const struct file_operations snd_hwdep_f_ops = .mmap = snd_hwdep_mmap, }; -static void release_hwdep_device(struct device *dev) +static void snd_hwdep_free(struct snd_hwdep *hwdep) { - kfree(container_of(dev, struct snd_hwdep, dev)); + if (!hwdep) + return; + if (hwdep->private_free) + hwdep->private_free(hwdep); + put_device(hwdep->dev); + kfree(hwdep); } /** @@ -382,16 +387,20 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device, if (id) strscpy(hwdep->id, id, sizeof(hwdep->id)); - snd_device_initialize(&hwdep->dev, card); - hwdep->dev.release = release_hwdep_device; - dev_set_name(&hwdep->dev, "hwC%iD%i", card->number, device); + err = snd_device_alloc(&hwdep->dev, card); + if (err < 0) { + snd_hwdep_free(hwdep); + return err; + } + + dev_set_name(hwdep->dev, "hwC%iD%i", card->number, device); #ifdef CONFIG_SND_OSSEMUL hwdep->oss_type = -1; #endif err = snd_device_new(card, SNDRV_DEV_HWDEP, hwdep, &ops); if (err < 0) { - put_device(&hwdep->dev); + snd_hwdep_free(hwdep); return err; } @@ -403,12 +412,7 @@ EXPORT_SYMBOL(snd_hwdep_new); static int snd_hwdep_dev_free(struct snd_device *device) { - struct snd_hwdep *hwdep = device->device_data; - if (!hwdep) - return 0; - if (hwdep->private_free) - hwdep->private_free(hwdep); - put_device(&hwdep->dev); + snd_hwdep_free(device->device_data); return 0; } @@ -426,9 +430,9 @@ static int snd_hwdep_dev_register(struct snd_device *device) list_add_tail(&hwdep->list, &snd_hwdep_devices); err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device, - &snd_hwdep_f_ops, hwdep, &hwdep->dev); + &snd_hwdep_f_ops, hwdep, hwdep->dev); if (err < 0) { - dev_err(&hwdep->dev, "unable to register\n"); + dev_err(hwdep->dev, "unable to register\n"); list_del(&hwdep->list); mutex_unlock(®ister_mutex); return err; @@ -439,12 +443,12 @@ static int snd_hwdep_dev_register(struct snd_device *device) if (hwdep->oss_type >= 0) { if (hwdep->oss_type == SNDRV_OSS_DEVICE_TYPE_DMFM && hwdep->device) - dev_warn(&hwdep->dev, + dev_warn(hwdep->dev, "only hwdep device 0 can be registered as OSS direct FM device!\n"); else if (snd_register_oss_device(hwdep->oss_type, card, hwdep->device, &snd_hwdep_f_ops, hwdep) < 0) - dev_warn(&hwdep->dev, + dev_warn(hwdep->dev, "unable to register OSS compatibility device\n"); else hwdep->ossreg = 1; @@ -471,7 +475,7 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device) if (hwdep->ossreg) snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device); #endif - snd_unregister_device(&hwdep->dev); + snd_unregister_device(hwdep->dev); list_del_init(&hwdep->list); mutex_unlock(&hwdep->open_mutex); mutex_unlock(®ister_mutex); diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 125e97fe0b1c..727f39acedfc 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -114,8 +114,8 @@ int snd_hda_create_hwdep(struct hda_codec *codec) #endif /* for sysfs */ - hwdep->dev.groups = snd_hda_dev_attr_groups; - dev_set_drvdata(&hwdep->dev, codec); + hwdep->dev->groups = snd_hda_dev_attr_groups; + dev_set_drvdata(hwdep->dev, codec); return 0; } From ea29a02fd802d8df8202819f0a50d4ebb960bb2a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 18:02:48 +0200 Subject: [PATCH 280/334] ALSA: rawmidi: Don't embed device This patch detaches the struct device from the snd_rawmidi object by allocating via snd_device_alloc(), just like done for other devices. Reviewed-by: Jaroslav Kysela Signed-off-by: Curtis Malainey Tested-by: Curtis Malainey Link: https://lore.kernel.org/r/20230816160252.23396-6-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/rawmidi.h | 2 +- sound/core/rawmidi.c | 29 +++++++++++++---------------- sound/core/ump.c | 8 ++++---- 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index b0197b1d1fe4..f31cabf0158c 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -135,7 +135,7 @@ struct snd_rawmidi { struct mutex open_mutex; wait_queue_head_t open_wait; - struct device dev; + struct device *dev; struct snd_info_entry *proc_entry; diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 2d3cec908154..ba06484ac4aa 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -44,11 +44,11 @@ static LIST_HEAD(snd_rawmidi_devices); static DEFINE_MUTEX(register_mutex); #define rmidi_err(rmidi, fmt, args...) \ - dev_err(&(rmidi)->dev, fmt, ##args) + dev_err((rmidi)->dev, fmt, ##args) #define rmidi_warn(rmidi, fmt, args...) \ - dev_warn(&(rmidi)->dev, fmt, ##args) + dev_warn((rmidi)->dev, fmt, ##args) #define rmidi_dbg(rmidi, fmt, args...) \ - dev_dbg(&(rmidi)->dev, fmt, ##args) + dev_dbg((rmidi)->dev, fmt, ##args) struct snd_rawmidi_status32 { s32 stream; @@ -1877,11 +1877,6 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi, return 0; } -static void release_rawmidi_device(struct device *dev) -{ - kfree(container_of(dev, struct snd_rawmidi, dev)); -} - /* used for both rawmidi and ump */ int snd_rawmidi_init(struct snd_rawmidi *rmidi, struct snd_card *card, char *id, int device, @@ -1906,12 +1901,13 @@ int snd_rawmidi_init(struct snd_rawmidi *rmidi, if (id != NULL) strscpy(rmidi->id, id, sizeof(rmidi->id)); - snd_device_initialize(&rmidi->dev, card); - rmidi->dev.release = release_rawmidi_device; + err = snd_device_alloc(&rmidi->dev, card); + if (err < 0) + return err; if (rawmidi_is_ump(rmidi)) - dev_set_name(&rmidi->dev, "umpC%iD%i", card->number, device); + dev_set_name(rmidi->dev, "umpC%iD%i", card->number, device); else - dev_set_name(&rmidi->dev, "midiC%iD%i", card->number, device); + dev_set_name(rmidi->dev, "midiC%iD%i", card->number, device); err = snd_rawmidi_alloc_substreams(rmidi, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT], @@ -1996,7 +1992,8 @@ int snd_rawmidi_free(struct snd_rawmidi *rmidi) snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]); if (rmidi->private_free) rmidi->private_free(rmidi); - put_device(&rmidi->dev); + put_device(rmidi->dev); + kfree(rmidi); return 0; } EXPORT_SYMBOL_GPL(snd_rawmidi_free); @@ -2038,7 +2035,7 @@ static int snd_rawmidi_dev_register(struct snd_device *device) err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device, - &snd_rawmidi_f_ops, rmidi, &rmidi->dev); + &snd_rawmidi_f_ops, rmidi, rmidi->dev); if (err < 0) { rmidi_err(rmidi, "unable to register\n"); goto error; @@ -2103,7 +2100,7 @@ static int snd_rawmidi_dev_register(struct snd_device *device) return 0; error_unregister: - snd_unregister_device(&rmidi->dev); + snd_unregister_device(rmidi->dev); error: mutex_lock(®ister_mutex); list_del(&rmidi->list); @@ -2142,7 +2139,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) rmidi->ossreg = 0; } #endif /* CONFIG_SND_OSSEMUL */ - snd_unregister_device(&rmidi->dev); + snd_unregister_device(rmidi->dev); mutex_unlock(&rmidi->open_mutex); mutex_unlock(®ister_mutex); return 0; diff --git a/sound/core/ump.c b/sound/core/ump.c index 246348766ec1..fbe2892e72fd 100644 --- a/sound/core/ump.c +++ b/sound/core/ump.c @@ -13,10 +13,10 @@ #include #include -#define ump_err(ump, fmt, args...) dev_err(&(ump)->core.dev, fmt, ##args) -#define ump_warn(ump, fmt, args...) dev_warn(&(ump)->core.dev, fmt, ##args) -#define ump_info(ump, fmt, args...) dev_info(&(ump)->core.dev, fmt, ##args) -#define ump_dbg(ump, fmt, args...) dev_dbg(&(ump)->core.dev, fmt, ##args) +#define ump_err(ump, fmt, args...) dev_err((ump)->core.dev, fmt, ##args) +#define ump_warn(ump, fmt, args...) dev_warn((ump)->core.dev, fmt, ##args) +#define ump_info(ump, fmt, args...) dev_info((ump)->core.dev, fmt, ##args) +#define ump_dbg(ump, fmt, args...) dev_dbg((ump)->core.dev, fmt, ##args) static int snd_ump_dev_register(struct snd_rawmidi *rmidi); static int snd_ump_dev_unregister(struct snd_rawmidi *rmidi); From b53a41ee9c7281d961a29a3524bcaacfc9020dd5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 18:02:49 +0200 Subject: [PATCH 281/334] ALSA: compress: Don't embed device Embedding the struct device to snd_compr object may result in UAF when the delayed kobj release is used. Like other devices, let's detach the struct device from the snd_compr by allocating dynamically via snd_device_alloc(). Reviewed-by: Jaroslav Kysela Signed-off-by: Curtis Malainey Tested-by: Curtis Malainey Link: https://lore.kernel.org/r/20230816160252.23396-7-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/compress_driver.h | 2 +- sound/core/compress_offload.c | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index d91289c6f00e..bcf872c17dd3 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -148,7 +148,7 @@ struct snd_compr_ops { */ struct snd_compr { const char *name; - struct device dev; + struct device *dev; struct snd_compr_ops *ops; void *private_data; struct snd_card *card; diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 30f73097447b..619371aa9964 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -546,7 +546,7 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream, if (stream->runtime->dma_buffer_p) { if (buffer_size > stream->runtime->dma_buffer_p->bytes) - dev_err(&stream->device->dev, + dev_err(stream->device->dev, "Not enough DMA buffer"); else buffer = stream->runtime->dma_buffer_p->area; @@ -1070,7 +1070,7 @@ static int snd_compress_dev_register(struct snd_device *device) /* register compressed device */ ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card, compr->device, - &snd_compr_file_ops, compr, &compr->dev); + &snd_compr_file_ops, compr, compr->dev); if (ret < 0) { pr_err("snd_register_device failed %d\n", ret); return ret; @@ -1084,7 +1084,7 @@ static int snd_compress_dev_disconnect(struct snd_device *device) struct snd_compr *compr; compr = device->device_data; - snd_unregister_device(&compr->dev); + snd_unregister_device(compr->dev); return 0; } @@ -1158,7 +1158,7 @@ static int snd_compress_dev_free(struct snd_device *device) compr = device->device_data; snd_compress_proc_done(compr); - put_device(&compr->dev); + put_device(compr->dev); return 0; } @@ -1189,12 +1189,16 @@ int snd_compress_new(struct snd_card *card, int device, snd_compress_set_id(compr, id); - snd_device_initialize(&compr->dev, card); - dev_set_name(&compr->dev, "comprC%iD%i", card->number, device); + ret = snd_device_alloc(&compr->dev, card); + if (ret) + return ret; + dev_set_name(compr->dev, "comprC%iD%i", card->number, device); ret = snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops); if (ret == 0) snd_compress_proc_init(compr); + else + put_device(compr->dev); return ret; } From 911fcb76e39e3b85507bae7ccf78af7fc09acdb8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 18:02:50 +0200 Subject: [PATCH 282/334] ALSA: timer: Create device with snd_device_alloc() Align with the other components, and use snd_device_alloc() for the new sound device for timer, too. No functional changes. Reviewed-by: Jaroslav Kysela Signed-off-by: Curtis Malainey Tested-by: Curtis Malainey Link: https://lore.kernel.org/r/20230816160252.23396-8-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/timer.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sound/core/timer.c b/sound/core/timer.c index 9d0d2a5c2e15..e6e551d4a29e 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -2301,7 +2301,7 @@ static void snd_timer_free_all(void) snd_timer_free(timer); } -static struct device timer_dev; +static struct device *timer_dev; /* * ENTRY functions @@ -2311,8 +2311,10 @@ static int __init alsa_timer_init(void) { int err; - snd_device_initialize(&timer_dev, NULL); - dev_set_name(&timer_dev, "timer"); + err = snd_device_alloc(&timer_dev, NULL); + if (err < 0) + return err; + dev_set_name(timer_dev, "timer"); #ifdef SNDRV_OSS_INFO_DEV_TIMERS snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1, @@ -2326,7 +2328,7 @@ static int __init alsa_timer_init(void) } err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0, - &snd_timer_f_ops, NULL, &timer_dev); + &snd_timer_f_ops, NULL, timer_dev); if (err < 0) { pr_err("ALSA: unable to register timer device (%i)\n", err); snd_timer_free_all(); @@ -2337,15 +2339,15 @@ static int __init alsa_timer_init(void) return 0; put_timer: - put_device(&timer_dev); + put_device(timer_dev); return err; } static void __exit alsa_timer_exit(void) { - snd_unregister_device(&timer_dev); + snd_unregister_device(timer_dev); snd_timer_free_all(); - put_device(&timer_dev); + put_device(timer_dev); snd_timer_proc_done(); #ifdef SNDRV_OSS_INFO_DEV_TIMERS snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1); From 2419891e3ffdd50b17fb3aca49accc8e64b1f363 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 18:02:51 +0200 Subject: [PATCH 283/334] ALSA: seq: Create device with snd_device_alloc() Align with the other components, and use snd_device_alloc() for the new sound device for sequencer, too. No functional changes. Reviewed-by: Jaroslav Kysela Signed-off-by: Curtis Malainey Tested-by: Curtis Malainey Link: https://lore.kernel.org/r/20230816160252.23396-9-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/seq/seq_clientmgr.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index e3f9ea67d019..42a705141050 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -2721,7 +2721,7 @@ static const struct file_operations snd_seq_f_ops = .compat_ioctl = snd_seq_ioctl_compat, }; -static struct device seq_dev; +static struct device *seq_dev; /* * register sequencer device @@ -2730,15 +2730,17 @@ int __init snd_sequencer_device_init(void) { int err; - snd_device_initialize(&seq_dev, NULL); - dev_set_name(&seq_dev, "seq"); + err = snd_device_alloc(&seq_dev, NULL); + if (err < 0) + return err; + dev_set_name(seq_dev, "seq"); mutex_lock(®ister_mutex); err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0, - &snd_seq_f_ops, NULL, &seq_dev); + &snd_seq_f_ops, NULL, seq_dev); mutex_unlock(®ister_mutex); if (err < 0) { - put_device(&seq_dev); + put_device(seq_dev); return err; } @@ -2752,6 +2754,6 @@ int __init snd_sequencer_device_init(void) */ void snd_sequencer_device_done(void) { - snd_unregister_device(&seq_dev); - put_device(&seq_dev); + snd_unregister_device(seq_dev); + put_device(seq_dev); } From 01ed7f3535a2c59d27cb7e78cf62eb81d2bbf2ec Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 18:02:52 +0200 Subject: [PATCH 284/334] ALSA: core: Drop snd_device_initialize() Now all users of snd_device_intialize() are gone, let's drop it. Reviewed-by: Jaroslav Kysela Signed-off-by: Curtis Malainey Tested-by: Curtis Malainey Link: https://lore.kernel.org/r/20230816160252.23396-10-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/core.h | 1 - sound/core/init.c | 23 ----------------------- 2 files changed, 24 deletions(-) diff --git a/include/sound/core.h b/include/sound/core.h index f3f6b720a278..dfef0c9d4b9f 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -240,7 +240,6 @@ extern struct dentry *sound_debugfs_root; void snd_request_card(int card); int snd_device_alloc(struct device **dev_p, struct snd_card *card); -void snd_device_initialize(struct device *dev, struct snd_card *card); int snd_register_device(int type, struct snd_card *card, int dev, const struct file_operations *f_ops, diff --git a/sound/core/init.c b/sound/core/init.c index a4de9f00d90f..d61bde1225f2 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -111,29 +111,6 @@ static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int), return mask; /* unchanged */ } -/* the default release callback set in snd_device_initialize() below; - * this is just NOP for now, as almost all jobs are already done in - * dev_free callback of snd_device chain instead. - */ -static void default_release(struct device *dev) -{ -} - -/** - * snd_device_initialize - Initialize struct device for sound devices - * @dev: device to initialize - * @card: card to assign, optional - */ -void snd_device_initialize(struct device *dev, struct snd_card *card) -{ - device_initialize(dev); - if (card) - dev->parent = &card->card_dev; - dev->class = &sound_class; - dev->release = default_release; -} -EXPORT_SYMBOL_GPL(snd_device_initialize); - /* the default release callback set in snd_device_alloc() */ static void default_release_alloc(struct device *dev) { From a707885aff6cfa4f2abcb33ca684044afe4e632c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 18 Aug 2023 09:09:13 +0200 Subject: [PATCH 285/334] ALSA: aoa: Fix typos in PCM fix patch There was typos in the previous fix for PCM to detach the struct device that caused build errors. Corrected here. Fixes: bc41a7228ced ("ALSA: pcm: Don't embed device") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202308181347.q3XPr3Lm-lkp@intel.com/ Link: https://lore.kernel.org/r/20230818070913.23336-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/aoa/soundbus/i2sbus/pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c index 3680eb6eabc9..07df5cc0f2d7 100644 --- a/sound/aoa/soundbus/i2sbus/pcm.c +++ b/sound/aoa/soundbus/i2sbus/pcm.c @@ -972,7 +972,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, goto out_put_ci_module; snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, &i2sbus_playback_ops); - dev->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK]->dev.parent = + dev->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].dev->parent = &dev->ofdev.dev; i2sdev->out.created = 1; } @@ -989,7 +989,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, goto out_put_ci_module; snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, &i2sbus_record_ops); - dev->pcm->streams[SNDRV_PCM_STREAM_CAPTURE]->dev.parent = + dev->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].dev->parent = &dev->ofdev.dev; i2sdev->in.created = 1; } From 828b871ac11a2a7d7c061e2a29a0f0a1225c694a Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Thu, 17 Aug 2023 17:37:39 +0800 Subject: [PATCH 286/334] ALSA: Make SND_PCMTEST depend on DEBUG_FS Since pcmtest is a test module that manipulates or gets notification via debugfs, without DEBUG_FS it can not work fine. So make SND_PCMTEST depend on DEBUG_FS. Signed-off-by: Ruan Jinjie Acked-by: Ivan Orlov Link: https://lore.kernel.org/r/20230817093740.1732738-1-ruanjinjie@huawei.com Signed-off-by: Takashi Iwai --- sound/drivers/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 41c171468c1e..6debd8e95cb7 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -111,6 +111,7 @@ config SND_ALOOP config SND_PCMTEST tristate "Virtual PCM test driver" + depends on DEBUG_FS select SND_PCM help Say 'Y' or 'M' to include support for the Virtual PCM test driver. From 3babae915f4c15d76a5134e55806a1c1588e2865 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Fri, 18 Aug 2023 16:58:35 +0800 Subject: [PATCH 287/334] ALSA: hda/tas2781: Add tas2781 HDA driver Integrate tas2781 configs for Lenovo Laptops. All of the tas2781s in the laptop will be aggregated as one audio device. The code support realtek as the primary codec. Rename "struct cs35l41_dev_name" to "struct scodec_dev_name" for all other side codecs instead of the certain one. Signed-off-by: Shenghao Ding Link: https://lore.kernel.org/r/20230818085836.1442-1-shenghao-ding@ti.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 88 +++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index a6585afb7707..8f2f1a0c48d4 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6729,7 +6729,7 @@ static void comp_generic_playback_hook(struct hda_pcm_stream *hinfo, struct hda_ } } -struct cs35l41_dev_name { +struct scodec_dev_name { const char *bus; const char *hid; int index; @@ -6738,7 +6738,7 @@ struct cs35l41_dev_name { /* match the device name in a slightly relaxed manner */ static int comp_match_cs35l41_dev_name(struct device *dev, void *data) { - struct cs35l41_dev_name *p = data; + struct scodec_dev_name *p = data; const char *d = dev_name(dev); int n = strlen(p->bus); char tmp[32]; @@ -6754,12 +6754,32 @@ static int comp_match_cs35l41_dev_name(struct device *dev, void *data) return !strcmp(d + n, tmp); } +static int comp_match_tas2781_dev_name(struct device *dev, + void *data) +{ + struct scodec_dev_name *p = data; + const char *d = dev_name(dev); + int n = strlen(p->bus); + char tmp[32]; + + /* check the bus name */ + if (strncmp(d, p->bus, n)) + return 0; + /* skip the bus number */ + if (isdigit(d[n])) + n++; + /* the rest must be exact matching */ + snprintf(tmp, sizeof(tmp), "-%s:00", p->hid); + + return !strcmp(d + n, tmp); +} + static void cs35l41_generic_fixup(struct hda_codec *cdc, int action, const char *bus, const char *hid, int count) { struct device *dev = hda_codec_dev(cdc); struct alc_spec *spec = cdc->spec; - struct cs35l41_dev_name *rec; + struct scodec_dev_name *rec; int ret, i; switch (action) { @@ -6787,6 +6807,41 @@ static void cs35l41_generic_fixup(struct hda_codec *cdc, int action, const char } } +static void tas2781_generic_fixup(struct hda_codec *cdc, int action, + const char *bus, const char *hid) +{ + struct device *dev = hda_codec_dev(cdc); + struct alc_spec *spec = cdc->spec; + struct scodec_dev_name *rec; + int ret; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + rec = devm_kmalloc(dev, sizeof(*rec), GFP_KERNEL); + if (!rec) + return; + rec->bus = bus; + rec->hid = hid; + rec->index = 0; + spec->comps[0].codec = cdc; + component_match_add(dev, &spec->match, + comp_match_tas2781_dev_name, rec); + ret = component_master_add_with_match(dev, &comp_master_ops, + spec->match); + if (ret) + codec_err(cdc, + "Fail to register component aggregator %d\n", + ret); + else + spec->gen.pcm_playback_hook = + comp_generic_playback_hook; + break; + case HDA_FIXUP_ACT_FREE: + component_master_del(dev, &comp_master_ops); + break; + } +} + static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action) { cs35l41_generic_fixup(cdc, action, "i2c", "CSC3551", 2); @@ -6814,6 +6869,12 @@ static void alc287_fixup_legion_16ithg6_speakers(struct hda_codec *cdc, const st cs35l41_generic_fixup(cdc, action, "i2c", "CLSA0101", 2); } +static void tas2781_fixup_i2c(struct hda_codec *cdc, + const struct hda_fixup *fix, int action) +{ + tas2781_generic_fixup(cdc, action, "i2c", "TIAS2781"); +} + /* for alc295_fixup_hp_top_speakers */ #include "hp_x360_helper.c" @@ -7239,6 +7300,7 @@ enum { ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS, ALC236_FIXUP_DELL_DUAL_CODECS, ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI, + ALC287_FIXUP_TAS2781_I2C, }; /* A special fixup for Lenovo C940 and Yoga Duet 7; @@ -9317,6 +9379,12 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_THINKPAD_ACPI, }, + [ALC287_FIXUP_TAS2781_I2C] = { + .type = HDA_FIXUP_FUNC, + .v.func = tas2781_fixup_i2c, + .chained = true, + .chain_id = ALC269_FIXUP_THINKPAD_ACPI, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -9890,6 +9958,20 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3853, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3855, "Legion 7 16ITHG6", ALC287_FIXUP_LEGION_16ITHG6), SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), + SND_PCI_QUIRK(0x17aa, 0x387d, "Yoga S780-16 pro Quad AAC", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x387e, "Yoga S780-16 pro Quad YC", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x3881, "YB9 dual powe mode2 YC", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x3884, "Y780 YG DUAL", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x3886, "Y780 VECO DUAL", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x38a7, "Y780P AMD YG dual", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x38a8, "Y780P AMD VECO dual", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x38ba, "Yoga S780-14.5 Air AMD quad YC", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x38bb, "Yoga S780-14.5 Air AMD quad AAC", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x38be, "Yoga S980-14.5 proX YC Dual", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x38bf, "Yoga S980-14.5 proX LX Dual", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x38c3, "Y980 DUAL", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x38cb, "Y790 YG DUAL", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x38cd, "Y790 VECO DUAL", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI), From 5be27f1e3ec98975c18a91e220d4847d0dec9671 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Fri, 18 Aug 2023 16:58:36 +0800 Subject: [PATCH 288/334] ALSA: hda/tas2781: Add tas2781 HDA driver Create tas2781 side codec HDA driver for Lenovo Laptops. The quantity of the speakers has been define in ACPI. All of the tas2781s in the laptop will be aggregated as one audio speaker. The code supports realtek codec as the primary codec. Code offers several controls for digtial/analog gain setting during playback, and other for eq params setting in case of different audio profiles, such as music, voice, movie, etc. [ adjusted patch to be applied to the latest for-next branch -- tiwai ] Signed-off-by: Shenghao Ding Link: https://lore.kernel.org/r/20230818085836.1442-2-shenghao-ding@ti.com Signed-off-by: Takashi Iwai --- sound/pci/hda/Kconfig | 15 + sound/pci/hda/Makefile | 2 + sound/pci/hda/tas2781_hda_i2c.c | 858 ++++++++++++++++++++++++++++++++ 3 files changed, 875 insertions(+) create mode 100644 sound/pci/hda/tas2781_hda_i2c.c diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index dd6922267a4b..91db5f8f00b6 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -161,6 +161,21 @@ config SND_HDA_SCODEC_CS35L56_SPI Say Y or M here to include CS35L56 amplifier support with SPI control. +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 SND_SOC + select SND_SOC_TAS2781_COMLIB + select SND_SOC_TAS2781_FMWLIB + select CRC32_SARWATE + 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_CODEC_REALTEK tristate "Build Realtek HD-audio codec support" select SND_HDA_GENERIC diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 5506255be895..f00fc9ed6096 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -35,6 +35,7 @@ snd-hda-scodec-cs35l56-objs := cs35l56_hda.o snd-hda-scodec-cs35l56-i2c-objs := cs35l56_hda_i2c.o snd-hda-scodec-cs35l56-spi-objs := cs35l56_hda_spi.o snd-hda-cs-dsp-ctls-objs := hda_cs_dsp_ctl.o +snd-hda-scodec-tas2781-i2c-objs := tas2781_hda_i2c.o # common driver obj-$(CONFIG_SND_HDA) := snd-hda-codec.o @@ -62,6 +63,7 @@ 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_CS_DSP_CONTROLS) += snd-hda-cs-dsp-ctls.o +obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_I2C) += snd-hda-scodec-tas2781-i2c.o # this must be the last entry after codec drivers; # otherwise the codec patches won't be hooked before the PCI probe diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c new file mode 100644 index 000000000000..35dafc4aec4f --- /dev/null +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -0,0 +1,858 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// TAS2781 HDA I2C driver +// +// Copyright 2023 Texas Instruments, Inc. +// +// Author: Shenghao Ding + +#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_component.h" +#include "hda_jack.h" +#include "hda_generic.h" + +#define TASDEVICE_SPEAKER_CALIBRATION_SIZE 20 + +/* No standard control callbacks for SNDRV_CTL_ELEM_IFACE_CARD + * Define two controls, one is Volume control callbacks, the other is + * flag setting control callbacks. + */ + +/* Volume control callbacks for tas2781 */ +#define ACARD_SINGLE_RANGE_EXT_TLV(xname, xreg, xshift, xmin, xmax, xinvert, \ + xhandler_get, xhandler_put, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = (xname),\ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ + SNDRV_CTL_ELEM_ACCESS_READWRITE,\ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw_range, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = (unsigned long)&(struct soc_mixer_control) \ + {.reg = xreg, .rreg = xreg, .shift = xshift, \ + .rshift = xshift, .min = xmin, .max = xmax, \ + .invert = xinvert} } + +/* Flag control callbacks for tas2781 */ +#define ACARD_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = xname, \ + .info = snd_ctl_boolean_mono_info, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = xdata } + +enum calib_data { + R0_VAL = 0, + INV_R0, + R0LOW, + POWER, + TLIM, + CALIB_MAX +}; + +static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data) +{ + struct tasdevice_priv *tas_priv = data; + struct acpi_resource_i2c_serialbus *sb; + + if (i2c_acpi_get_i2c_resource(ares, &sb)) { + if (tas_priv->ndev < TASDEVICE_MAX_CHANNELS && + sb->slave_address != TAS2781_GLOBAL_ADDR) { + tas_priv->tasdevice[tas_priv->ndev].dev_addr = + (unsigned int)sb->slave_address; + tas_priv->ndev++; + } + } + return 1; +} + +static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid) +{ + struct acpi_device *adev; + struct device *physdev; + LIST_HEAD(resources); + const char *sub; + int ret; + + adev = acpi_dev_get_first_match_dev(hid, NULL, -1); + if (!adev) { + dev_err(p->dev, + "Failed to find an ACPI device for %s\n", hid); + return -ENODEV; + } + + ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p); + if (ret < 0) + goto err; + + acpi_dev_free_resource_list(&resources); + strscpy(p->dev_name, hid, sizeof(p->dev_name)); + physdev = get_device(acpi_get_first_physical_node(adev)); + acpi_dev_put(adev); + + /* No side-effect to the playback even if subsystem_id is NULL*/ + sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); + if (IS_ERR(sub)) + sub = NULL; + + p->acpi_subsystem_id = sub; + + put_device(physdev); + + return 0; + +err: + dev_err(p->dev, "read acpi error, ret: %d\n", ret); + put_device(physdev); + + return ret; +} + +static void tas2781_hda_playback_hook(struct device *dev, int action) +{ + struct tasdevice_priv *tas_priv = dev_get_drvdata(dev); + + dev_dbg(tas_priv->dev, "%s: action = %d\n", __func__, action); + switch (action) { + case HDA_GEN_PCM_ACT_OPEN: + pm_runtime_get_sync(dev); + mutex_lock(&tas_priv->codec_lock); + tasdevice_tuning_switch(tas_priv, 0); + mutex_unlock(&tas_priv->codec_lock); + break; + case HDA_GEN_PCM_ACT_CLOSE: + mutex_lock(&tas_priv->codec_lock); + tasdevice_tuning_switch(tas_priv, 1); + mutex_unlock(&tas_priv->codec_lock); + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + break; + default: + dev_dbg(tas_priv->dev, "Playback action not supported: %d\n", + action); + break; + } +} + +static int tasdevice_info_profile(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1; + + return 0; +} + +static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id; + + return 0; +} + +static int tasdevice_hda_clamp(int val, int max) +{ + if (val > max) + val = max; + + if (val < 0) + val = 0; + return val; +} + +static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + int nr_profile = ucontrol->value.integer.value[0]; + int max = tas_priv->rcabin.ncfgs - 1; + int val, ret = 0; + + val = tasdevice_hda_clamp(nr_profile, max); + + if (tas_priv->rcabin.profile_cfg_id != val) { + tas_priv->rcabin.profile_cfg_id = val; + ret = 1; + } + + return ret; +} + +static int tasdevice_info_programs(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + struct tasdevice_fw *tas_fw = tas_priv->fmw; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = tas_fw->nr_programs - 1; + + return 0; +} + +static int tasdevice_info_config(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + struct tasdevice_fw *tas_fw = tas_priv->fmw; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = tas_fw->nr_configurations - 1; + + return 0; +} + +static int tasdevice_program_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = tas_priv->cur_prog; + + return 0; +} + +static int tasdevice_program_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + struct tasdevice_fw *tas_fw = tas_priv->fmw; + int nr_program = ucontrol->value.integer.value[0]; + int max = tas_fw->nr_programs - 1; + int val, ret = 0; + + val = tasdevice_hda_clamp(nr_program, max); + + if (tas_priv->cur_prog != val) { + tas_priv->cur_prog = val; + ret = 1; + } + + return ret; +} + +static int tasdevice_config_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = tas_priv->cur_conf; + + return 0; +} + +static int tasdevice_config_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + struct tasdevice_fw *tas_fw = tas_priv->fmw; + int nr_config = ucontrol->value.integer.value[0]; + int max = tas_fw->nr_configurations - 1; + int val, ret = 0; + + val = tasdevice_hda_clamp(nr_config, max); + + if (tas_priv->cur_conf != val) { + tas_priv->cur_conf = val; + ret = 1; + } + + return ret; +} + +/* + * tas2781_digital_getvol - get the volum control + * @kcontrol: control pointer + * @ucontrol: User data + * Customer Kcontrol for tas2781 is primarily for regmap booking, paging + * depends on internal regmap mechanism. + * tas2781 contains book and page two-level register map, especially + * book switching will set the register BXXP00R7F, after switching to the + * correct book, then leverage the mechanism for paging to access the + * register. + */ +static int tas2781_digital_getvol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + return tasdevice_digital_getvol(tas_priv, ucontrol, mc); +} + +static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + return tasdevice_amp_getvol(tas_priv, ucontrol, mc); +} + +static int tas2781_digital_putvol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + /* The check of the given value is in tasdevice_digital_putvol. */ + return tasdevice_digital_putvol(tas_priv, ucontrol, mc); +} + +static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + /* The check of the given value is in tasdevice_amp_putvol. */ + return tasdevice_amp_putvol(tas_priv, ucontrol, mc); +} + +static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status; + dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__, + tas_priv->force_fwload_status ? "ON" : "OFF"); + + return 0; +} + +static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + bool change, val = (bool)ucontrol->value.integer.value[0]; + + if (tas_priv->force_fwload_status == val) + change = false; + else { + change = true; + tas_priv->force_fwload_status = val; + } + dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__, + tas_priv->force_fwload_status ? "ON" : "OFF"); + + return change; +} + +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, + tas2781_amp_putvol, amp_vol_tlv), + ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain", TAS2781_DVC_LVL, + 0, 0, 200, 1, tas2781_digital_getvol, + tas2781_digital_putvol, dvc_tlv), + ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0, + tas2781_force_fwload_get, tas2781_force_fwload_put), +}; + +static const struct snd_kcontrol_new tas2781_prof_ctrl = { + .name = "Speaker Profile Id", + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .info = tasdevice_info_profile, + .get = tasdevice_get_profile_id, + .put = tasdevice_set_profile_id, +}; + +static const struct snd_kcontrol_new tas2781_dsp_prog_ctrl = { + .name = "Speaker Program Id", + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .info = tasdevice_info_programs, + .get = tasdevice_program_get, + .put = tasdevice_program_put, +}; + +static const struct snd_kcontrol_new tas2781_dsp_conf_ctrl = { + .name = "Speaker Config Id", + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .info = tasdevice_info_config, + .get = tasdevice_config_get, + .put = tasdevice_config_put, +}; + +static void tas2781_apply_calib(struct tasdevice_priv *tas_priv) +{ + static const unsigned char page_array[CALIB_MAX] = { + 0x17, 0x18, 0x18, 0x0d, 0x18 + }; + static const unsigned char rgno_array[CALIB_MAX] = { + 0x74, 0x0c, 0x14, 0x3c, 0x7c + }; + unsigned char *data; + int i, j, rc; + + for (i = 0; i < tas_priv->ndev; i++) { + data = tas_priv->cali_data.data + + i * TASDEVICE_SPEAKER_CALIBRATION_SIZE; + for (j = 0; j < CALIB_MAX; j++) { + rc = tasdevice_dev_bulk_write(tas_priv, i, + TASDEVICE_REG(0, page_array[j], rgno_array[j]), + &(data[4 * j]), 4); + if (rc < 0) + dev_err(tas_priv->dev, + "chn %d calib %d bulk_wr err = %d\n", + i, j, rc); + } + } +} + +/* Update the calibrate data, including speaker impedance, f0, etc, into algo. + * Calibrate data is done by manufacturer in the factory. These data are used + * by Algo for calucating the speaker temperature, speaker membrance excursion + * and f0 in real time during playback. + */ +static int tas2781_save_calibration(struct tasdevice_priv *tas_priv) +{ + efi_guid_t efi_guid = EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, + 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3); + static efi_char16_t efi_name[] = L"CALI_DATA"; + struct tm *tm = &tas_priv->tm; + unsigned int attr, crc; + unsigned int *tmp_val; + efi_status_t status; + + /* Lenovo devices */ + if (tas_priv->catlog_id == LENOVO) + efi_guid = EFI_GUID(0x1f52d2a1, 0xbb3a, 0x457d, 0xbc, 0x09, + 0x43, 0xa3, 0xf4, 0x31, 0x0a, 0x92); + + tas_priv->cali_data.total_sz = 0; + /* Get real size of UEFI variable */ + status = efi.get_variable(efi_name, &efi_guid, &attr, + &tas_priv->cali_data.total_sz, tas_priv->cali_data.data); + if (status == EFI_BUFFER_TOO_SMALL) { + /* Allocate data buffer of data_size bytes */ + tas_priv->cali_data.data = devm_kzalloc(tas_priv->dev, + tas_priv->cali_data.total_sz, GFP_KERNEL); + if (!tas_priv->cali_data.data) + return -ENOMEM; + /* Get variable contents into buffer */ + status = efi.get_variable(efi_name, &efi_guid, &attr, + &tas_priv->cali_data.total_sz, + tas_priv->cali_data.data); + if (status != EFI_SUCCESS) + return -EINVAL; + } + + tmp_val = (unsigned int *)tas_priv->cali_data.data; + + crc = crc32(~0, tas_priv->cali_data.data, 84) ^ ~0; + dev_dbg(tas_priv->dev, "cali crc 0x%08x PK tmp_val 0x%08x\n", + crc, tmp_val[21]); + + if (crc == tmp_val[21]) { + time64_to_tm(tmp_val[20], 0, tm); + dev_dbg(tas_priv->dev, "%4ld-%2d-%2d, %2d:%2d:%2d\n", + tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + tas2781_apply_calib(tas_priv); + } else + tas_priv->cali_data.total_sz = 0; + + return 0; +} + +static void tasdev_fw_ready(const struct firmware *fmw, void *context) +{ + struct tasdevice_priv *tas_priv = context; + struct hda_codec *codec = tas_priv->codec; + int i, 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; + + ret = snd_ctl_add(codec->card, + snd_ctl_new1(&tas2781_prof_ctrl, tas_priv)); + 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++) { + ret = snd_ctl_add(codec->card, + snd_ctl_new1(&tas2781_snd_controls[i], tas_priv)); + if (ret) { + dev_err(tas_priv->dev, + "Failed to add KControl %s = %d\n", + tas2781_snd_controls[i].name, ret); + goto out; + } + } + + tasdevice_dsp_remove(tas_priv); + + tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; + scnprintf(tas_priv->coef_binaryname, 64, "TAS2XXX%04X.bin", + codec->core.subsystem_id & 0xffff); + ret = tasdevice_dsp_parser(tas_priv); + if (ret) { + dev_err(tas_priv->dev, "dspfw load %s error\n", + tas_priv->coef_binaryname); + tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; + goto out; + } + + ret = snd_ctl_add(codec->card, + snd_ctl_new1(&tas2781_dsp_prog_ctrl, tas_priv)); + if (ret) { + dev_err(tas_priv->dev, + "Failed to add KControl %s = %d\n", + tas2781_dsp_prog_ctrl.name, ret); + goto out; + } + + ret = snd_ctl_add(codec->card, + snd_ctl_new1(&tas2781_dsp_conf_ctrl, tas_priv)); + if (ret) { + dev_err(tas_priv->dev, + "Failed to add KControl %s = %d\n", + tas2781_dsp_conf_ctrl.name, ret); + goto out; + } + + tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK; + tasdevice_prmg_load(tas_priv, 0); + + /* If calibrated data occurs error, dsp will still works with default + * calibrated data inside algo. + */ + tas2781_save_calibration(tas_priv); + +out: + if (tas_priv->fw_state == TASDEVICE_DSP_FW_FAIL) { + /*If DSP FW fail, kcontrol won't be created */ + tasdevice_config_info_remove(tas_priv); + tasdevice_dsp_remove(tas_priv); + } + mutex_unlock(&tas_priv->codec_lock); + if (fmw) + release_firmware(fmw); + pm_runtime_mark_last_busy(tas_priv->dev); + pm_runtime_put_autosuspend(tas_priv->dev); +} + +static int tas2781_hda_bind(struct device *dev, struct device *master, + void *master_data) +{ + struct tasdevice_priv *tas_priv = dev_get_drvdata(dev); + struct hda_component *comps = master_data; + struct hda_codec *codec; + unsigned int subid; + int ret; + + if (!comps || tas_priv->index < 0 || + tas_priv->index >= HDA_MAX_COMPONENTS) + return -EINVAL; + + comps = &comps[tas_priv->index]; + if (comps->dev) + return -EBUSY; + + codec = comps->codec; + subid = codec->core.subsystem_id >> 16; + + switch (subid) { + case 0x17aa: + tas_priv->catlog_id = LENOVO; + break; + default: + tas_priv->catlog_id = OTHERS; + break; + } + + pm_runtime_get_sync(dev); + + comps->dev = dev; + + strscpy(comps->name, dev_name(dev), sizeof(comps->name)); + + ret = tascodec_init(tas_priv, codec, tasdev_fw_ready); + if (ret) + return ret; + + comps->playback_hook = tas2781_hda_playback_hook; + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return 0; +} + +static void tas2781_hda_unbind(struct device *dev, + struct device *master, void *master_data) +{ + struct tasdevice_priv *tas_priv = dev_get_drvdata(dev); + struct hda_component *comps = master_data; + + if (comps[tas_priv->index].dev == dev) + memset(&comps[tas_priv->index], 0, sizeof(*comps)); + + tasdevice_config_info_remove(tas_priv); + tasdevice_dsp_remove(tas_priv); + + tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; +} + +static const struct component_ops tas2781_hda_comp_ops = { + .bind = tas2781_hda_bind, + .unbind = tas2781_hda_unbind, +}; + +static void tas2781_hda_remove(struct device *dev) +{ + struct tasdevice_priv *tas_priv = dev_get_drvdata(dev); + + pm_runtime_get_sync(tas_priv->dev); + pm_runtime_disable(tas_priv->dev); + + component_del(tas_priv->dev, &tas2781_hda_comp_ops); + + pm_runtime_put_noidle(tas_priv->dev); + + tasdevice_remove(tas_priv); +} + +static int tas2781_hda_i2c_probe(struct i2c_client *clt) +{ + struct tasdevice_priv *tas_priv; + const char *device_name; + int ret; + + if (strstr(dev_name(&clt->dev), "TIAS2781")) + device_name = "TIAS2781"; + else + return -ENODEV; + + tas_priv = tasdevice_kzalloc(clt); + if (!tas_priv) + return -ENOMEM; + + tas_priv->irq_info.irq = clt->irq; + ret = tas2781_read_acpi(tas_priv, device_name); + if (ret) + return dev_err_probe(tas_priv->dev, ret, + "Platform not supported\n"); + + ret = tasdevice_init(tas_priv); + if (ret) + goto err; + + 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); + + pm_runtime_put_autosuspend(tas_priv->dev); + + ret = component_add(tas_priv->dev, &tas2781_hda_comp_ops); + if (ret) { + dev_err(tas_priv->dev, "Register component failed: %d\n", ret); + pm_runtime_disable(tas_priv->dev); + goto err; + } + + tas2781_reset(tas_priv); +err: + if (ret) + tas2781_hda_remove(&clt->dev); + return ret; +} + +static void tas2781_hda_i2c_remove(struct i2c_client *clt) +{ + tas2781_hda_remove(&clt->dev); +} + +static int tas2781_runtime_suspend(struct device *dev) +{ + struct tasdevice_priv *tas_priv = dev_get_drvdata(dev); + int i; + + dev_dbg(tas_priv->dev, "Runtime Suspend\n"); + + mutex_lock(&tas_priv->codec_lock); + + if (tas_priv->playback_started) { + tasdevice_tuning_switch(tas_priv, 1); + tas_priv->playback_started = false; + } + + for (i = 0; i < tas_priv->ndev; i++) { + tas_priv->tasdevice[i].cur_book = -1; + tas_priv->tasdevice[i].cur_prog = -1; + tas_priv->tasdevice[i].cur_conf = -1; + } + + regcache_cache_only(tas_priv->regmap, true); + regcache_mark_dirty(tas_priv->regmap); + + mutex_unlock(&tas_priv->codec_lock); + + return 0; +} + +static int tas2781_runtime_resume(struct device *dev) +{ + struct tasdevice_priv *tas_priv = dev_get_drvdata(dev); + unsigned long calib_data_sz = + tas_priv->ndev * TASDEVICE_SPEAKER_CALIBRATION_SIZE; + int ret; + + dev_dbg(tas_priv->dev, "Runtime Resume\n"); + + mutex_lock(&tas_priv->codec_lock); + + regcache_cache_only(tas_priv->regmap, false); + ret = regcache_sync(tas_priv->regmap); + if (ret) { + dev_err(tas_priv->dev, + "Failed to restore register cache: %d\n", ret); + goto out; + } + + tasdevice_prmg_load(tas_priv, tas_priv->cur_prog); + + /* If calibrated data occurs error, dsp will still works with default + * calibrated data inside algo. + */ + if (tas_priv->cali_data.total_sz > calib_data_sz) + tas2781_apply_calib(tas_priv); + +out: + mutex_unlock(&tas_priv->codec_lock); + + return ret; +} + +static int tas2781_system_suspend(struct device *dev) +{ + struct tasdevice_priv *tas_priv = dev_get_drvdata(dev); + int ret; + + dev_dbg(tas_priv->dev, "System Suspend\n"); + + ret = pm_runtime_force_suspend(dev); + if (ret) + return ret; + + /* Shutdown chip before system suspend */ + regcache_cache_only(tas_priv->regmap, false); + tasdevice_tuning_switch(tas_priv, 1); + regcache_cache_only(tas_priv->regmap, true); + regcache_mark_dirty(tas_priv->regmap); + + /* + * Reset GPIO may be shared, so cannot reset here. + * However beyond this point, amps may be powered down. + */ + return 0; +} + +static int tas2781_system_resume(struct device *dev) +{ + struct tasdevice_priv *tas_priv = dev_get_drvdata(dev); + unsigned long calib_data_sz = + tas_priv->ndev * TASDEVICE_SPEAKER_CALIBRATION_SIZE; + int i, ret; + + dev_dbg(tas_priv->dev, "System Resume\n"); + + ret = pm_runtime_force_resume(dev); + if (ret) + return ret; + + mutex_lock(&tas_priv->codec_lock); + + for (i = 0; i < tas_priv->ndev; i++) { + tas_priv->tasdevice[i].cur_book = -1; + tas_priv->tasdevice[i].cur_prog = -1; + tas_priv->tasdevice[i].cur_conf = -1; + } + tas2781_reset(tas_priv); + tasdevice_prmg_load(tas_priv, tas_priv->cur_prog); + + /* If calibrated data occurs error, dsp will still work with default + * calibrated data inside algo. + */ + if (tas_priv->cali_data.total_sz > calib_data_sz) + tas2781_apply_calib(tas_priv); + mutex_unlock(&tas_priv->codec_lock); + + return 0; +} + +static const struct dev_pm_ops tas2781_hda_pm_ops = { + RUNTIME_PM_OPS(tas2781_runtime_suspend, tas2781_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(tas2781_system_suspend, tas2781_system_resume) +}; + +static const struct i2c_device_id tas2781_hda_i2c_id[] = { + { "tas2781-hda", 0 }, + {} +}; + +static const struct acpi_device_id tas2781_acpi_hda_match[] = { + {"TIAS2781", 0 }, + {} +}; +MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match); + +static struct i2c_driver tas2781_hda_i2c_driver = { + .driver = { + .name = "tas2781-hda", + .acpi_match_table = tas2781_acpi_hda_match, + .pm = &tas2781_hda_pm_ops, + }, + .id_table = tas2781_hda_i2c_id, + .probe_new = tas2781_hda_i2c_probe, + .remove = tas2781_hda_i2c_remove, +}; +module_i2c_driver(tas2781_hda_i2c_driver); + +MODULE_DESCRIPTION("TAS2781 HDA Driver"); +MODULE_AUTHOR("Shenghao Ding, TI, "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(SND_SOC_TAS2781_FMWLIB); From 70e969eb235ee6a030ff140b1852b598bf66f9c8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:12 +0200 Subject: [PATCH 289/334] iov_iter: Export import_ubuf() Export import_ubuf() to be used in sound subsystem for generic memory handling as Linus suggested. It's used for constructing an iov_iter of a single segment user-space copy for PCM data. Cc: Alexander Viro Link: https://lore.kernel.org/r/CAHk-=wh-mUL6mp4chAc6E_UjwpPLyCPRCJK+iB4ZMD2BqjwGHA@mail.gmail.com Link: https://lore.kernel.org/r/20230815190136.8987-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- lib/iov_iter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/iov_iter.c b/lib/iov_iter.c index e4dc809d1075..3743bbcbbb89 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -1544,6 +1544,7 @@ int import_ubuf(int rw, void __user *buf, size_t len, struct iov_iter *i) iov_iter_ubuf(i, rw, buf, len); return 0; } +EXPORT_SYMBOL_GPL(import_ubuf); /** * iov_iter_restore() - Restore a &struct iov_iter to the same state as when From cf393babb37a1679a1ec1d864df1090353465e23 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:13 +0200 Subject: [PATCH 290/334] ALSA: pcm: Add copy ops with iov_iter iov_iter is a universal interface to copy the data chunk from/to user-space and kernel in a unified manner. This API can fit for ALSA PCM copy ops, too; we had to split to copy_user and copy_kernel in the past, and those can be unified to a single ops with iov_iter. This patch adds a new PCM copy ops that passes iov_iter for copying both kernel and user-space in the same way. This patch touches only the ALSA PCM core part, and the actual users will be replaced in the following patches. The expansion of iov_iter is done in the PCM core right before calling each copy callback. It's a bit suboptimal, but I took this now as it's the most straightforward replacement. The more conversion to iov_iter in the caller side is a TODO for future. As of now, the old copy_user and copy_kernel ops are still kept. Once after all users are converted, we'll drop the old copy_user and copy_kernel ops, too. Link: https://lore.kernel.org/r/20230815190136.8987-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 3 ++ sound/core/pcm_lib.c | 111 ++++++++++++++++++++++++---------------- sound/core/pcm_native.c | 2 +- 3 files changed, 71 insertions(+), 45 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 0243a13e9ac4..6d6ec51ddfc1 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -16,6 +16,7 @@ #include #include #include +#include #define snd_pcm_substream_chip(substream) ((substream)->private_data) #define snd_pcm_chip(pcm) ((pcm)->private_data) @@ -68,6 +69,8 @@ struct snd_pcm_ops { struct snd_pcm_audio_tstamp_report *audio_tstamp_report); int (*fill_silence)(struct snd_pcm_substream *substream, int channel, unsigned long pos, unsigned long bytes); + int (*copy)(struct snd_pcm_substream *substream, int channel, + unsigned long pos, struct iov_iter *iter, unsigned long bytes); int (*copy_user)(struct snd_pcm_substream *substream, int channel, unsigned long pos, void __user *buf, unsigned long bytes); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 9c121a921b04..3303914c58ea 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1973,10 +1973,11 @@ static int wait_for_avail(struct snd_pcm_substream *substream, typedef int (*pcm_transfer_f)(struct snd_pcm_substream *substream, int channel, unsigned long hwoff, - void *buf, unsigned long bytes); + struct iov_iter *iter, unsigned long bytes); typedef int (*pcm_copy_f)(struct snd_pcm_substream *, snd_pcm_uframes_t, void *, - snd_pcm_uframes_t, snd_pcm_uframes_t, pcm_transfer_f); + snd_pcm_uframes_t, snd_pcm_uframes_t, pcm_transfer_f, + bool); /* calculate the target DMA-buffer position to be written/read */ static void *get_dma_ptr(struct snd_pcm_runtime *runtime, @@ -1986,32 +1987,24 @@ static void *get_dma_ptr(struct snd_pcm_runtime *runtime, channel * (runtime->dma_bytes / runtime->channels); } -/* default copy_user ops for write; used for both interleaved and non- modes */ +/* default copy ops for write; used for both interleaved and non- modes */ static int default_write_copy(struct snd_pcm_substream *substream, int channel, unsigned long hwoff, - void *buf, unsigned long bytes) + struct iov_iter *iter, unsigned long bytes) { - if (copy_from_user(get_dma_ptr(substream->runtime, channel, hwoff), - (void __user *)buf, bytes)) + if (!copy_from_iter(get_dma_ptr(substream->runtime, channel, hwoff), + bytes, iter)) return -EFAULT; return 0; } -/* default copy_kernel ops for write */ -static int default_write_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long hwoff, - void *buf, unsigned long bytes) -{ - memcpy(get_dma_ptr(substream->runtime, channel, hwoff), buf, bytes); - return 0; -} - /* fill silence instead of copy data; called as a transfer helper * from __snd_pcm_lib_write() or directly from noninterleaved_copy() when * a NULL buffer is passed */ static int fill_silence(struct snd_pcm_substream *substream, int channel, - unsigned long hwoff, void *buf, unsigned long bytes) + unsigned long hwoff, struct iov_iter *iter, + unsigned long bytes) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -2027,25 +2020,54 @@ static int fill_silence(struct snd_pcm_substream *substream, int channel, return 0; } -/* default copy_user ops for read; used for both interleaved and non- modes */ +/* default copy ops for read; used for both interleaved and non- modes */ static int default_read_copy(struct snd_pcm_substream *substream, int channel, unsigned long hwoff, - void *buf, unsigned long bytes) + struct iov_iter *iter, unsigned long bytes) { - if (copy_to_user((void __user *)buf, - get_dma_ptr(substream->runtime, channel, hwoff), - bytes)) + if (!copy_to_iter(get_dma_ptr(substream->runtime, channel, hwoff), + bytes, iter)) return -EFAULT; return 0; } -/* default copy_kernel ops for read */ -static int default_read_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long hwoff, - void *buf, unsigned long bytes) +/* a wrapper for calling old copy_kernel or copy_user ops */ +static int call_old_copy(struct snd_pcm_substream *substream, + int channel, unsigned long hwoff, + struct iov_iter *iter, unsigned long bytes) { - memcpy(buf, get_dma_ptr(substream->runtime, channel, hwoff), bytes); - return 0; + if (iov_iter_is_kvec(iter)) + return substream->ops->copy_kernel(substream, channel, hwoff, + iter_iov_addr(iter), bytes); + else + return substream->ops->copy_user(substream, channel, hwoff, + iter_iov_addr(iter), bytes); +} + +/* call transfer with the filled iov_iter */ +static int do_transfer(struct snd_pcm_substream *substream, int c, + unsigned long hwoff, void *data, unsigned long bytes, + pcm_transfer_f transfer, bool in_kernel) +{ + struct iov_iter iter; + int err, type; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + type = ITER_SOURCE; + else + type = ITER_DEST; + + if (in_kernel) { + struct kvec kvec = { data, bytes }; + + iov_iter_kvec(&iter, type, &kvec, 1, bytes); + return transfer(substream, c, hwoff, &iter, bytes); + } + + err = import_ubuf(type, (__force void __user *)data, bytes, &iter); + if (err) + return err; + return transfer(substream, c, hwoff, &iter, bytes); } /* call transfer function with the converted pointers and sizes; @@ -2055,7 +2077,8 @@ static int interleaved_copy(struct snd_pcm_substream *substream, snd_pcm_uframes_t hwoff, void *data, snd_pcm_uframes_t off, snd_pcm_uframes_t frames, - pcm_transfer_f transfer) + pcm_transfer_f transfer, + bool in_kernel) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -2063,7 +2086,9 @@ static int interleaved_copy(struct snd_pcm_substream *substream, hwoff = frames_to_bytes(runtime, hwoff); off = frames_to_bytes(runtime, off); frames = frames_to_bytes(runtime, frames); - return transfer(substream, 0, hwoff, data + off, frames); + + return do_transfer(substream, 0, hwoff, data + off, frames, transfer, + in_kernel); } /* call transfer function with the converted pointers and sizes for each @@ -2073,7 +2098,8 @@ static int noninterleaved_copy(struct snd_pcm_substream *substream, snd_pcm_uframes_t hwoff, void *data, snd_pcm_uframes_t off, snd_pcm_uframes_t frames, - pcm_transfer_f transfer) + pcm_transfer_f transfer, + bool in_kernel) { struct snd_pcm_runtime *runtime = substream->runtime; int channels = runtime->channels; @@ -2091,8 +2117,8 @@ static int noninterleaved_copy(struct snd_pcm_substream *substream, if (!data || !*bufs) err = fill_silence(substream, c, hwoff, NULL, frames); else - err = transfer(substream, c, hwoff, *bufs + off, - frames); + err = do_transfer(substream, c, hwoff, *bufs + off, + frames, transfer, in_kernel); if (err < 0) return err; } @@ -2108,10 +2134,10 @@ static int fill_silence_frames(struct snd_pcm_substream *substream, if (substream->runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || substream->runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) return interleaved_copy(substream, off, NULL, 0, frames, - fill_silence); + fill_silence, true); else return noninterleaved_copy(substream, off, NULL, 0, frames, - fill_silence); + fill_silence, true); } /* sanity-check for read/write methods */ @@ -2121,7 +2147,7 @@ static int pcm_sanity_check(struct snd_pcm_substream *substream) if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; - if (snd_BUG_ON(!substream->ops->copy_user && !runtime->dma_area)) + if (snd_BUG_ON(!substream->ops->copy && !substream->ops->copy_user && !runtime->dma_area)) return -EINVAL; if (runtime->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; @@ -2226,15 +2252,12 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, transfer = fill_silence; else return -EINVAL; - } else if (in_kernel) { - if (substream->ops->copy_kernel) - transfer = substream->ops->copy_kernel; - else - transfer = is_playback ? - default_write_copy_kernel : default_read_copy_kernel; } else { - if (substream->ops->copy_user) - transfer = (pcm_transfer_f)substream->ops->copy_user; + if (substream->ops->copy) + transfer = substream->ops->copy; + else if ((in_kernel && substream->ops->copy_kernel) || + (!in_kernel && substream->ops->copy_user)) + transfer = call_old_copy; else transfer = is_playback ? default_write_copy : default_read_copy; @@ -2307,7 +2330,7 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, if (!is_playback) snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_CPU); err = writer(substream, appl_ofs, data, offset, frames, - transfer); + transfer, in_kernel); if (is_playback) snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); snd_pcm_stream_lock_irq(substream); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 95fc56e403b1..34efd4d198d6 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -809,7 +809,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, runtime->boundary *= 2; /* clear the buffer for avoiding possible kernel info leaks */ - if (runtime->dma_area && !substream->ops->copy_user) { + if (runtime->dma_area && !substream->ops->copy && !substream->ops->copy_user) { size_t size = runtime->dma_bytes; if (runtime->info & SNDRV_PCM_INFO_MMAP) From 561b4fa9c1111292ec975a04ecd8372ac0256e1e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:14 +0200 Subject: [PATCH 291/334] ALSA: core: Add memory copy helpers between iov_iter and iomem Add two more helpers for copying memory between iov_iter and iomem, which will be used by the new PCM copy ops in a few drivers. The existing helpers became wrappers of those now. Note that copy_from/to_iter() returns the copied bytes, hence the error condition is adjusted accordingly. Link: https://lore.kernel.org/r/20230815190136.8987-4-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 5 ++++ sound/core/memory.c | 56 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 6d6ec51ddfc1..1f6df47eb500 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -1559,6 +1559,11 @@ static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format) #define pcm_dbg(pcm, fmt, args...) \ dev_dbg((pcm)->card->dev, fmt, ##args) +/* helpers for copying between iov_iter and iomem */ +int copy_to_iter_fromio(struct iov_iter *itert, const void __iomem *src, + size_t count); +int copy_from_iter_toio(void __iomem *dst, struct iov_iter *iter, size_t count); + struct snd_pcm_status64 { snd_pcm_state_t state; /* stream state */ u8 rsvd[4]; diff --git a/sound/core/memory.c b/sound/core/memory.c index 5d894dc32f7d..2d2d0094c897 100644 --- a/sound/core/memory.c +++ b/sound/core/memory.c @@ -9,6 +9,7 @@ #include #include #include +#include /** * copy_to_user_fromio - copy data from mmio-space to user-space @@ -21,9 +22,30 @@ * Return: Zero if successful, or non-zero on failure. */ int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size_t count) +{ + struct iov_iter iter; + + if (import_ubuf(ITER_DEST, dst, count, &iter)) + return -EFAULT; + return copy_to_iter_fromio(&iter, (const void __iomem *)src, count); +} +EXPORT_SYMBOL(copy_to_user_fromio); + +/** + * copy_to_iter_fromio - copy data from mmio-space to iov_iter + * @dst: the destination iov_iter + * @src: the source pointer on mmio + * @count: the data size to copy in bytes + * + * Copies the data from mmio-space to iov_iter. + * + * Return: Zero if successful, or non-zero on failure. + */ +int copy_to_iter_fromio(struct iov_iter *dst, const void __iomem *src, + size_t count) { #if defined(__i386__) || defined(CONFIG_SPARC32) - return copy_to_user(dst, (const void __force*)src, count) ? -EFAULT : 0; + return copy_to_iter((const void __force *)src, count, dst) == count ? 0 : -EFAULT; #else char buf[256]; while (count) { @@ -31,16 +53,15 @@ int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size if (c > sizeof(buf)) c = sizeof(buf); memcpy_fromio(buf, (void __iomem *)src, c); - if (copy_to_user(dst, buf, c)) + if (copy_to_iter(buf, c, dst) != c) return -EFAULT; count -= c; - dst += c; src += c; } return 0; #endif } -EXPORT_SYMBOL(copy_to_user_fromio); +EXPORT_SYMBOL(copy_to_iter_fromio); /** * copy_from_user_toio - copy data from user-space to mmio-space @@ -53,23 +74,42 @@ EXPORT_SYMBOL(copy_to_user_fromio); * Return: Zero if successful, or non-zero on failure. */ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size_t count) +{ + struct iov_iter iter; + + if (import_ubuf(ITER_SOURCE, (void __user *)src, count, &iter)) + return -EFAULT; + return copy_from_iter_toio((void __iomem *)dst, &iter, count); +} +EXPORT_SYMBOL(copy_from_user_toio); + +/** + * copy_from_iter_toio - copy data from iov_iter to mmio-space + * @dst: the destination pointer on mmio-space + * @src: the source iov_iter + * @count: the data size to copy in bytes + * + * Copies the data from iov_iter to mmio-space. + * + * Return: Zero if successful, or non-zero on failure. + */ +int copy_from_iter_toio(void __iomem *dst, struct iov_iter *src, size_t count) { #if defined(__i386__) || defined(CONFIG_SPARC32) - return copy_from_user((void __force *)dst, src, count) ? -EFAULT : 0; + return copy_from_iter((void __force *)dst, count, src) == count ? 0 : -EFAULT; #else char buf[256]; while (count) { size_t c = count; if (c > sizeof(buf)) c = sizeof(buf); - if (copy_from_user(buf, src, c)) + if (copy_from_iter(buf, c, src) != c) return -EFAULT; memcpy_toio(dst, buf, c); count -= c; dst += c; - src += c; } return 0; #endif } -EXPORT_SYMBOL(copy_from_user_toio); +EXPORT_SYMBOL(copy_from_iter_toio); From 526a19b3e3ea7cde61c8ac0dcb2796756ef4fa16 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:15 +0200 Subject: [PATCH 292/334] ALSA: dummy: Convert to generic PCM copy ops This patch converts the dummy driver code to use the new unified PCM copy callback. As dummy driver doesn't do anything in the callback, it's just a simple replacement. Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230815190136.8987-5-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/drivers/dummy.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 9c17b49a2ae1..4317677ba24a 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -626,14 +626,7 @@ static int alloc_fake_buffer(void) static int dummy_pcm_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *dst, unsigned long bytes) -{ - return 0; /* do nothing */ -} - -static int dummy_pcm_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void *dst, unsigned long bytes) + struct iov_iter *iter, unsigned long bytes) { return 0; /* do nothing */ } @@ -667,8 +660,7 @@ static const struct snd_pcm_ops dummy_pcm_ops_no_buf = { .prepare = dummy_pcm_prepare, .trigger = dummy_pcm_trigger, .pointer = dummy_pcm_pointer, - .copy_user = dummy_pcm_copy, - .copy_kernel = dummy_pcm_copy_kernel, + .copy = dummy_pcm_copy, .fill_silence = dummy_pcm_silence, .page = dummy_pcm_page, }; From e2964cd7ef58bd97f7acd5340e71d6b7e260fb2d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:16 +0200 Subject: [PATCH 293/334] ALSA: gus: Convert to generic PCM copy ops This patch converts the GUS driver code to use the new unified PCM copy callback. It's a straightforward conversion from *_user() to *_iter() variants. Note that copy_from/to_iter() returns the copied bytes, hence the error condition is adjusted accordingly. Link: https://lore.kernel.org/r/20230815190136.8987-6-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/isa/gus/gus_pcm.c | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index 388db5fb65bd..850544725da7 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c @@ -369,7 +369,7 @@ static int playback_copy_ack(struct snd_pcm_substream *substream, static int snd_gf1_pcm_playback_copy(struct snd_pcm_substream *substream, int voice, unsigned long pos, - void __user *src, unsigned long count) + struct iov_iter *src, unsigned long count) { struct snd_pcm_runtime *runtime = substream->runtime; struct gus_pcm_private *pcmp = runtime->private_data; @@ -379,27 +379,11 @@ static int snd_gf1_pcm_playback_copy(struct snd_pcm_substream *substream, bpos = get_bpos(pcmp, voice, pos, len); if (bpos < 0) return pos; - if (copy_from_user(runtime->dma_area + bpos, src, len)) + if (copy_from_iter(runtime->dma_area + bpos, len, src) != len) return -EFAULT; return playback_copy_ack(substream, bpos, len); } -static int snd_gf1_pcm_playback_copy_kernel(struct snd_pcm_substream *substream, - int voice, unsigned long pos, - void *src, unsigned long count) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct gus_pcm_private *pcmp = runtime->private_data; - unsigned int len = count; - int bpos; - - bpos = get_bpos(pcmp, voice, pos, len); - if (bpos < 0) - return pos; - memcpy(runtime->dma_area + bpos, src, len); - return playback_copy_ack(substream, bpos, len); -} - static int snd_gf1_pcm_playback_silence(struct snd_pcm_substream *substream, int voice, unsigned long pos, unsigned long count) @@ -830,8 +814,7 @@ static const struct snd_pcm_ops snd_gf1_pcm_playback_ops = { .prepare = snd_gf1_pcm_playback_prepare, .trigger = snd_gf1_pcm_playback_trigger, .pointer = snd_gf1_pcm_playback_pointer, - .copy_user = snd_gf1_pcm_playback_copy, - .copy_kernel = snd_gf1_pcm_playback_copy_kernel, + .copy = snd_gf1_pcm_playback_copy, .fill_silence = snd_gf1_pcm_playback_silence, }; From 9d0fdc602de9d4368ce58da158725d2c43765fd1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:17 +0200 Subject: [PATCH 294/334] ALSA: emu8000: Convert to generic PCM copy ops This patch converts the SB Emu8000 driver code to use the new unified PCM copy callback. The conversion is a bit complicated because of many open code in emu8000_pcm.c. GET_VAL() and LOOP_WRITE() macros were rewritten / simplified with copy_from_iter(). As copy_from_iter() updates the internal offset value, we can drop the corresponding part, too. Link: https://lore.kernel.org/r/20230815190136.8987-7-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/isa/sb/emu8000_pcm.c | 74 +++++++++----------------------------- 1 file changed, 16 insertions(+), 58 deletions(-) diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c index c8afc4347c54..c05935c2edc4 100644 --- a/sound/isa/sb/emu8000_pcm.c +++ b/sound/isa/sb/emu8000_pcm.c @@ -409,39 +409,25 @@ do { \ return -EAGAIN;\ } while (0) -enum { - COPY_USER, COPY_KERNEL, FILL_SILENCE, -}; - -#define GET_VAL(sval, buf, mode) \ +#define GET_VAL(sval, iter) \ do { \ - switch (mode) { \ - case FILL_SILENCE: \ + if (!iter) \ sval = 0; \ - break; \ - case COPY_KERNEL: \ - sval = *buf++; \ - break; \ - default: \ - if (get_user(sval, (unsigned short __user *)buf)) \ - return -EFAULT; \ - buf++; \ - break; \ - } \ + else if (copy_from_iter(&sval, 2, iter) != 2) \ + return -EFAULT; \ } while (0) #ifdef USE_NONINTERLEAVE -#define LOOP_WRITE(rec, offset, _buf, count, mode) \ +#define LOOP_WRITE(rec, offset, iter, count) \ do { \ struct snd_emu8000 *emu = (rec)->emu; \ - unsigned short *buf = (__force unsigned short *)(_buf); \ snd_emu8000_write_wait(emu, 1); \ EMU8000_SMALW_WRITE(emu, offset); \ while (count > 0) { \ unsigned short sval; \ CHECK_SCHEDULER(); \ - GET_VAL(sval, buf, mode); \ + GET_VAL(sval, iter); \ EMU8000_SMLD_WRITE(emu, sval); \ count--; \ } \ @@ -450,27 +436,14 @@ enum { /* copy one channel block */ static int emu8k_pcm_copy(struct snd_pcm_substream *subs, int voice, unsigned long pos, - void __user *src, unsigned long count) + struct iov_iter *src, unsigned long count) { struct snd_emu8k_pcm *rec = subs->runtime->private_data; /* convert to word unit */ pos = (pos << 1) + rec->loop_start[voice]; count <<= 1; - LOOP_WRITE(rec, pos, src, count, COPY_USER); - return 0; -} - -static int emu8k_pcm_copy_kernel(struct snd_pcm_substream *subs, - int voice, unsigned long pos, - void *src, unsigned long count) -{ - struct snd_emu8k_pcm *rec = subs->runtime->private_data; - - /* convert to word unit */ - pos = (pos << 1) + rec->loop_start[voice]; - count <<= 1; - LOOP_WRITE(rec, pos, src, count, COPY_KERNEL); + LOOP_WRITE(rec, pos, src, count); return 0; } @@ -483,16 +456,15 @@ static int emu8k_pcm_silence(struct snd_pcm_substream *subs, /* convert to word unit */ pos = (pos << 1) + rec->loop_start[voice]; count <<= 1; - LOOP_WRITE(rec, pos, NULL, count, FILL_SILENCE); + LOOP_WRITE(rec, pos, USER_SOCKPTR(NULL), count); return 0; } #else /* interleave */ -#define LOOP_WRITE(rec, pos, _buf, count, mode) \ +#define LOOP_WRITE(rec, pos, iter, count) \ do { \ struct snd_emu8000 *emu = rec->emu; \ - unsigned short *buf = (__force unsigned short *)(_buf); \ snd_emu8000_write_wait(emu, 1); \ EMU8000_SMALW_WRITE(emu, pos + rec->loop_start[0]); \ if (rec->voices > 1) \ @@ -500,11 +472,11 @@ static int emu8k_pcm_silence(struct snd_pcm_substream *subs, while (count > 0) { \ unsigned short sval; \ CHECK_SCHEDULER(); \ - GET_VAL(sval, buf, mode); \ + GET_VAL(sval, iter); \ EMU8000_SMLD_WRITE(emu, sval); \ if (rec->voices > 1) { \ CHECK_SCHEDULER(); \ - GET_VAL(sval, buf, mode); \ + GET_VAL(sval, iter); \ EMU8000_SMRD_WRITE(emu, sval); \ } \ count--; \ @@ -518,27 +490,14 @@ static int emu8k_pcm_silence(struct snd_pcm_substream *subs, */ static int emu8k_pcm_copy(struct snd_pcm_substream *subs, int voice, unsigned long pos, - void __user *src, unsigned long count) + struct iov_iter *src, unsigned long count) { struct snd_emu8k_pcm *rec = subs->runtime->private_data; /* convert to frames */ pos = bytes_to_frames(subs->runtime, pos); count = bytes_to_frames(subs->runtime, count); - LOOP_WRITE(rec, pos, src, count, COPY_USER); - return 0; -} - -static int emu8k_pcm_copy_kernel(struct snd_pcm_substream *subs, - int voice, unsigned long pos, - void *src, unsigned long count) -{ - struct snd_emu8k_pcm *rec = subs->runtime->private_data; - - /* convert to frames */ - pos = bytes_to_frames(subs->runtime, pos); - count = bytes_to_frames(subs->runtime, count); - LOOP_WRITE(rec, pos, src, count, COPY_KERNEL); + LOOP_WRITE(rec, pos, src, count); return 0; } @@ -550,7 +509,7 @@ static int emu8k_pcm_silence(struct snd_pcm_substream *subs, /* convert to frames */ pos = bytes_to_frames(subs->runtime, pos); count = bytes_to_frames(subs->runtime, count); - LOOP_WRITE(rec, pos, NULL, count, FILL_SILENCE); + LOOP_WRITE(rec, pos, NULL, count); return 0; } #endif @@ -666,8 +625,7 @@ static const struct snd_pcm_ops emu8k_pcm_ops = { .prepare = emu8k_pcm_prepare, .trigger = emu8k_pcm_trigger, .pointer = emu8k_pcm_pointer, - .copy_user = emu8k_pcm_copy, - .copy_kernel = emu8k_pcm_copy_kernel, + .copy = emu8k_pcm_copy, .fill_silence = emu8k_pcm_silence, }; From 07ee02a2e12e1b97bdd04fa3e42a67380a60054e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:18 +0200 Subject: [PATCH 295/334] ALSA: es1938: Convert to generic PCM copy ops This patch converts the es1938 driver code to use the new unified PCM copy callback. It's a straightforward conversion from *_user() to *_iter() variants in most parts. Note that copy_from/to_iter() returns the copied bytes, hence the error condition is adjusted accordingly. Link: https://lore.kernel.org/r/20230815190136.8987-8-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/es1938.c | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index e34ec6f89e7e..ec598ba1a883 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -824,7 +824,7 @@ static snd_pcm_uframes_t snd_es1938_playback_pointer(struct snd_pcm_substream *s static int snd_es1938_capture_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *dst, unsigned long count) + struct iov_iter *dst, unsigned long count) { struct snd_pcm_runtime *runtime = substream->runtime; struct es1938 *chip = snd_pcm_substream_chip(substream); @@ -832,36 +832,17 @@ static int snd_es1938_capture_copy(struct snd_pcm_substream *substream, if (snd_BUG_ON(pos + count > chip->dma1_size)) return -EINVAL; if (pos + count < chip->dma1_size) { - if (copy_to_user(dst, runtime->dma_area + pos + 1, count)) + if (copy_to_iter(runtime->dma_area + pos + 1, count, dst) != count) return -EFAULT; } else { - if (copy_to_user(dst, runtime->dma_area + pos + 1, count - 1)) + if (copy_to_iter(runtime->dma_area + pos + 1, count - 1, dst) != count - 1) return -EFAULT; - if (put_user(runtime->dma_area[0], - ((unsigned char __user *)dst) + count - 1)) + if (copy_to_iter(runtime->dma_area, 1, dst) != 1) return -EFAULT; } return 0; } -static int snd_es1938_capture_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void *dst, unsigned long count) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct es1938 *chip = snd_pcm_substream_chip(substream); - - if (snd_BUG_ON(pos + count > chip->dma1_size)) - return -EINVAL; - if (pos + count < chip->dma1_size) { - memcpy(dst, runtime->dma_area + pos + 1, count); - } else { - memcpy(dst, runtime->dma_area + pos + 1, count - 1); - runtime->dma_area[0] = *((unsigned char *)dst + count - 1); - } - return 0; -} - /* ---------------------------------------------------------------------- * Audio1 Capture (ADC) * ----------------------------------------------------------------------*/ @@ -987,8 +968,7 @@ static const struct snd_pcm_ops snd_es1938_capture_ops = { .prepare = snd_es1938_capture_prepare, .trigger = snd_es1938_capture_trigger, .pointer = snd_es1938_capture_pointer, - .copy_user = snd_es1938_capture_copy, - .copy_kernel = snd_es1938_capture_copy_kernel, + .copy = snd_es1938_capture_copy, }; static int snd_es1938_new_pcm(struct es1938 *chip, int device) From 49aa6ed94c5ee3a85fd503748e2df3a432c2a0ec Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:19 +0200 Subject: [PATCH 296/334] ALSA: korg1212: Convert to generic PCM copy ops This patch converts the korg1212 driver code to use the new unified PCM copy callback. The open-coded conditional memory copies are replaced with simpler copy_from/to_iter() calls. Note that copy_from/to_iter() returns the copied bytes, hence the error condition is adjusted accordingly. Link: https://lore.kernel.org/r/20230815190136.8987-9-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/korg1212/korg1212.c | 50 +++++++++-------------------------- 1 file changed, 12 insertions(+), 38 deletions(-) diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 33b4f95d65b3..5c2cac201a28 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -1285,8 +1285,7 @@ static int snd_korg1212_silence(struct snd_korg1212 *korg1212, int pos, int coun } static int snd_korg1212_copy_to(struct snd_pcm_substream *substream, - void __user *dst, int pos, int count, - bool in_kernel) + struct iov_iter *dst, int pos, int count) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream); @@ -1306,24 +1305,20 @@ static int snd_korg1212_copy_to(struct snd_pcm_substream *substream, #if K1212_DEBUG_LEVEL > 0 if ( (void *) src < (void *) korg1212->recordDataBufsPtr || (void *) src > (void *) korg1212->recordDataBufsPtr[8].bufferData ) { - printk(KERN_DEBUG "K1212_DEBUG: snd_korg1212_copy_to KERNEL EFAULT, src=%p dst=%p iter=%d\n", src, dst, i); + printk(KERN_DEBUG "K1212_DEBUG: snd_korg1212_copy_to KERNEL EFAULT, src=%p dst=%p iter=%d\n", src, dst->kvec.iov_base, i); return -EFAULT; } #endif - if (in_kernel) - memcpy((__force void *)dst, src, size); - else if (copy_to_user(dst, src, size)) + if (copy_to_iter(src, size, dst) != size) return -EFAULT; src++; - dst += size; } return 0; } static int snd_korg1212_copy_from(struct snd_pcm_substream *substream, - void __user *src, int pos, int count, - bool in_kernel) + struct iov_iter *src, int pos, int count) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream); @@ -1345,16 +1340,13 @@ static int snd_korg1212_copy_from(struct snd_pcm_substream *substream, #if K1212_DEBUG_LEVEL > 0 if ( (void *) dst < (void *) korg1212->playDataBufsPtr || (void *) dst > (void *) korg1212->playDataBufsPtr[8].bufferData ) { - printk(KERN_DEBUG "K1212_DEBUG: snd_korg1212_copy_from KERNEL EFAULT, src=%p dst=%p iter=%d\n", src, dst, i); + printk(KERN_DEBUG "K1212_DEBUG: snd_korg1212_copy_from KERNEL EFAULT, src=%p dst=%p iter=%d\n", src->kvec.iov_base, dst, i); return -EFAULT; } #endif - if (in_kernel) - memcpy(dst, (__force void *)src, size); - else if (copy_from_user(dst, src, size)) + if (copy_from_iter(dst, size, src) != size) return -EFAULT; dst++; - src += size; } return 0; @@ -1642,17 +1634,9 @@ static snd_pcm_uframes_t snd_korg1212_capture_pointer(struct snd_pcm_substream * static int snd_korg1212_playback_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *src, unsigned long count) + struct iov_iter *src, unsigned long count) { - return snd_korg1212_copy_from(substream, src, pos, count, false); -} - -static int snd_korg1212_playback_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void *src, unsigned long count) -{ - return snd_korg1212_copy_from(substream, (void __user *)src, - pos, count, true); + return snd_korg1212_copy_from(substream, src, pos, count); } static int snd_korg1212_playback_silence(struct snd_pcm_substream *substream, @@ -1670,17 +1654,9 @@ static int snd_korg1212_playback_silence(struct snd_pcm_substream *substream, static int snd_korg1212_capture_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *dst, unsigned long count) + struct iov_iter *dst, unsigned long count) { - return snd_korg1212_copy_to(substream, dst, pos, count, false); -} - -static int snd_korg1212_capture_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void *dst, unsigned long count) -{ - return snd_korg1212_copy_to(substream, (void __user *)dst, - pos, count, true); + return snd_korg1212_copy_to(substream, dst, pos, count); } static const struct snd_pcm_ops snd_korg1212_playback_ops = { @@ -1691,8 +1667,7 @@ static const struct snd_pcm_ops snd_korg1212_playback_ops = { .prepare = snd_korg1212_prepare, .trigger = snd_korg1212_trigger, .pointer = snd_korg1212_playback_pointer, - .copy_user = snd_korg1212_playback_copy, - .copy_kernel = snd_korg1212_playback_copy_kernel, + .copy = snd_korg1212_playback_copy, .fill_silence = snd_korg1212_playback_silence, }; @@ -1704,8 +1679,7 @@ static const struct snd_pcm_ops snd_korg1212_capture_ops = { .prepare = snd_korg1212_prepare, .trigger = snd_korg1212_trigger, .pointer = snd_korg1212_capture_pointer, - .copy_user = snd_korg1212_capture_copy, - .copy_kernel = snd_korg1212_capture_copy_kernel, + .copy = snd_korg1212_capture_copy, }; /* From 75bd8e3f4c812aa64e9b162cf094087552105f4e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:20 +0200 Subject: [PATCH 297/334] ALSA: nm256: Convert to generic PCM copy ops This patch converts the nm256 driver code to use the new unified PCM copy callback. It's a straightforward conversion from *_user() to *_iter() variants. Link: https://lore.kernel.org/r/20230815190136.8987-10-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/nm256/nm256.c | 42 ++++++----------------------------------- 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index f99a1e96e923..34f90829e656 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -691,26 +691,12 @@ snd_nm256_playback_silence(struct snd_pcm_substream *substream, static int snd_nm256_playback_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *src, unsigned long count) + struct iov_iter *src, unsigned long count) { struct snd_pcm_runtime *runtime = substream->runtime; struct nm256_stream *s = runtime->private_data; - if (copy_from_user_toio(s->bufptr + pos, src, count)) - return -EFAULT; - return 0; -} - -static int -snd_nm256_playback_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void *src, unsigned long count) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct nm256_stream *s = runtime->private_data; - - memcpy_toio(s->bufptr + pos, src, count); - return 0; + return copy_from_iter_toio(s->bufptr + pos, src, count); } /* @@ -719,26 +705,12 @@ snd_nm256_playback_copy_kernel(struct snd_pcm_substream *substream, static int snd_nm256_capture_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *dst, unsigned long count) + struct iov_iter *dst, unsigned long count) { struct snd_pcm_runtime *runtime = substream->runtime; struct nm256_stream *s = runtime->private_data; - if (copy_to_user_fromio(dst, s->bufptr + pos, count)) - return -EFAULT; - return 0; -} - -static int -snd_nm256_capture_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void *dst, unsigned long count) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct nm256_stream *s = runtime->private_data; - - memcpy_fromio(dst, s->bufptr + pos, count); - return 0; + return copy_to_iter_fromio(dst, s->bufptr + pos, count); } #endif /* !__i386__ */ @@ -909,8 +881,7 @@ static const struct snd_pcm_ops snd_nm256_playback_ops = { .trigger = snd_nm256_playback_trigger, .pointer = snd_nm256_playback_pointer, #ifndef __i386__ - .copy_user = snd_nm256_playback_copy, - .copy_kernel = snd_nm256_playback_copy_kernel, + .copy = snd_nm256_playback_copy, .fill_silence = snd_nm256_playback_silence, #endif .mmap = snd_pcm_lib_mmap_iomem, @@ -924,8 +895,7 @@ static const struct snd_pcm_ops snd_nm256_capture_ops = { .trigger = snd_nm256_capture_trigger, .pointer = snd_nm256_capture_pointer, #ifndef __i386__ - .copy_user = snd_nm256_capture_copy, - .copy_kernel = snd_nm256_capture_copy_kernel, + .copy = snd_nm256_capture_copy, #endif .mmap = snd_pcm_lib_mmap_iomem, }; From 50496aa216d564fb24783e1c94a2a12c0ef303a6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:21 +0200 Subject: [PATCH 298/334] ALSA: rme32: Convert to generic PCM copy ops This patch converts the rme32 driver code to use the new unified PCM copy callback. It's a straightforward conversion from *_user() to *_iter() variants. Link: https://lore.kernel.org/r/20230815190136.8987-11-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/rme32.c | 50 +++++++++++------------------------------------ 1 file changed, 11 insertions(+), 39 deletions(-) diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 9c0ac025e143..02144bbee6d5 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -252,48 +252,24 @@ static int snd_rme32_playback_silence(struct snd_pcm_substream *substream, /* copy callback for halfduplex mode */ static int snd_rme32_playback_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *src, unsigned long count) + struct iov_iter *src, unsigned long count) { struct rme32 *rme32 = snd_pcm_substream_chip(substream); - if (copy_from_user_toio(rme32->iobase + RME32_IO_DATA_BUFFER + pos, - src, count)) - return -EFAULT; - return 0; -} - -static int snd_rme32_playback_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void *src, unsigned long count) -{ - struct rme32 *rme32 = snd_pcm_substream_chip(substream); - - memcpy_toio(rme32->iobase + RME32_IO_DATA_BUFFER + pos, src, count); - return 0; + return copy_from_iter_toio(rme32->iobase + RME32_IO_DATA_BUFFER + pos, + src, count); } /* copy callback for halfduplex mode */ static int snd_rme32_capture_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *dst, unsigned long count) + struct iov_iter *dst, unsigned long count) { struct rme32 *rme32 = snd_pcm_substream_chip(substream); - if (copy_to_user_fromio(dst, - rme32->iobase + RME32_IO_DATA_BUFFER + pos, - count)) - return -EFAULT; - return 0; -} - -static int snd_rme32_capture_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void *dst, unsigned long count) -{ - struct rme32 *rme32 = snd_pcm_substream_chip(substream); - - memcpy_fromio(dst, rme32->iobase + RME32_IO_DATA_BUFFER + pos, count); - return 0; + return copy_to_iter_fromio(dst, + rme32->iobase + RME32_IO_DATA_BUFFER + pos, + count); } /* @@ -1194,8 +1170,7 @@ static const struct snd_pcm_ops snd_rme32_playback_spdif_ops = { .prepare = snd_rme32_playback_prepare, .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_playback_pointer, - .copy_user = snd_rme32_playback_copy, - .copy_kernel = snd_rme32_playback_copy_kernel, + .copy = snd_rme32_playback_copy, .fill_silence = snd_rme32_playback_silence, .mmap = snd_pcm_lib_mmap_iomem, }; @@ -1207,8 +1182,7 @@ static const struct snd_pcm_ops snd_rme32_capture_spdif_ops = { .prepare = snd_rme32_capture_prepare, .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_capture_pointer, - .copy_user = snd_rme32_capture_copy, - .copy_kernel = snd_rme32_capture_copy_kernel, + .copy = snd_rme32_capture_copy, .mmap = snd_pcm_lib_mmap_iomem, }; @@ -1219,8 +1193,7 @@ static const struct snd_pcm_ops snd_rme32_playback_adat_ops = { .prepare = snd_rme32_playback_prepare, .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_playback_pointer, - .copy_user = snd_rme32_playback_copy, - .copy_kernel = snd_rme32_playback_copy_kernel, + .copy = snd_rme32_playback_copy, .fill_silence = snd_rme32_playback_silence, .mmap = snd_pcm_lib_mmap_iomem, }; @@ -1232,8 +1205,7 @@ static const struct snd_pcm_ops snd_rme32_capture_adat_ops = { .prepare = snd_rme32_capture_prepare, .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_capture_pointer, - .copy_user = snd_rme32_capture_copy, - .copy_kernel = snd_rme32_capture_copy_kernel, + .copy = snd_rme32_capture_copy, .mmap = snd_pcm_lib_mmap_iomem, }; From c3abdf06a9e51d8e4cf97bc58b4b966a254b560f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:22 +0200 Subject: [PATCH 299/334] ALSA: rme96: Convert to generic PCM copy ops This patch converts the rme96 driver code to use the new unified PCM copy callback. It's a straightforward conversion from *_user() to *_iter() variants. Link: https://lore.kernel.org/r/20230815190136.8987-12-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/rme96.c | 42 ++++++++---------------------------------- 1 file changed, 8 insertions(+), 34 deletions(-) diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index bccb7e0d3d11..6b5ffb18197b 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -320,48 +320,26 @@ snd_rme96_playback_silence(struct snd_pcm_substream *substream, static int snd_rme96_playback_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *src, unsigned long count) + struct iov_iter *src, unsigned long count) { struct rme96 *rme96 = snd_pcm_substream_chip(substream); - return copy_from_user_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + pos, + return copy_from_iter_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + pos, src, count); } -static int -snd_rme96_playback_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void *src, unsigned long count) -{ - struct rme96 *rme96 = snd_pcm_substream_chip(substream); - - memcpy_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + pos, src, count); - return 0; -} - static int snd_rme96_capture_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *dst, unsigned long count) + struct iov_iter *dst, unsigned long count) { struct rme96 *rme96 = snd_pcm_substream_chip(substream); - return copy_to_user_fromio(dst, + return copy_to_iter_fromio(dst, rme96->iobase + RME96_IO_REC_BUFFER + pos, count); } -static int -snd_rme96_capture_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void *dst, unsigned long count) -{ - struct rme96 *rme96 = snd_pcm_substream_chip(substream); - - memcpy_fromio(dst, rme96->iobase + RME96_IO_REC_BUFFER + pos, count); - return 0; -} - /* * Digital output capabilities (S/PDIF) */ @@ -1518,8 +1496,7 @@ static const struct snd_pcm_ops snd_rme96_playback_spdif_ops = { .prepare = snd_rme96_playback_prepare, .trigger = snd_rme96_playback_trigger, .pointer = snd_rme96_playback_pointer, - .copy_user = snd_rme96_playback_copy, - .copy_kernel = snd_rme96_playback_copy_kernel, + .copy = snd_rme96_playback_copy, .fill_silence = snd_rme96_playback_silence, .mmap = snd_pcm_lib_mmap_iomem, }; @@ -1531,8 +1508,7 @@ static const struct snd_pcm_ops snd_rme96_capture_spdif_ops = { .prepare = snd_rme96_capture_prepare, .trigger = snd_rme96_capture_trigger, .pointer = snd_rme96_capture_pointer, - .copy_user = snd_rme96_capture_copy, - .copy_kernel = snd_rme96_capture_copy_kernel, + .copy = snd_rme96_capture_copy, .mmap = snd_pcm_lib_mmap_iomem, }; @@ -1543,8 +1519,7 @@ static const struct snd_pcm_ops snd_rme96_playback_adat_ops = { .prepare = snd_rme96_playback_prepare, .trigger = snd_rme96_playback_trigger, .pointer = snd_rme96_playback_pointer, - .copy_user = snd_rme96_playback_copy, - .copy_kernel = snd_rme96_playback_copy_kernel, + .copy = snd_rme96_playback_copy, .fill_silence = snd_rme96_playback_silence, .mmap = snd_pcm_lib_mmap_iomem, }; @@ -1556,8 +1531,7 @@ static const struct snd_pcm_ops snd_rme96_capture_adat_ops = { .prepare = snd_rme96_capture_prepare, .trigger = snd_rme96_capture_trigger, .pointer = snd_rme96_capture_pointer, - .copy_user = snd_rme96_capture_copy, - .copy_kernel = snd_rme96_capture_copy_kernel, + .copy = snd_rme96_capture_copy, .mmap = snd_pcm_lib_mmap_iomem, }; From 90ed231177d3ca88b8a424e7c9e344a3e4577bbe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:23 +0200 Subject: [PATCH 300/334] ALSA: hdsp: Convert to generic PCM copy ops This patch converts the hdsp driver code to use the new unified PCM copy callback. It's a straightforward conversion from *_user() to *_iter() variants. Note that copy_from/to_iter() returns the copied bytes, hence the error condition is adjusted accordingly. Link: https://lore.kernel.org/r/20230815190136.8987-13-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdsp.c | 42 ++++++---------------------------------- 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 65add92c88aa..e7d1b43471a2 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -3961,7 +3961,7 @@ static signed char *hdsp_channel_buffer_location(struct hdsp *hdsp, static int snd_hdsp_playback_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *src, unsigned long count) + struct iov_iter *src, unsigned long count) { struct hdsp *hdsp = snd_pcm_substream_chip(substream); signed char *channel_buf; @@ -3972,28 +3972,14 @@ static int snd_hdsp_playback_copy(struct snd_pcm_substream *substream, channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel); if (snd_BUG_ON(!channel_buf)) return -EIO; - if (copy_from_user(channel_buf + pos, src, count)) + if (copy_from_iter(channel_buf + pos, count, src) != count) return -EFAULT; return 0; } -static int snd_hdsp_playback_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void *src, unsigned long count) -{ - struct hdsp *hdsp = snd_pcm_substream_chip(substream); - signed char *channel_buf; - - channel_buf = hdsp_channel_buffer_location(hdsp, substream->pstr->stream, channel); - if (snd_BUG_ON(!channel_buf)) - return -EIO; - memcpy(channel_buf + pos, src, count); - return 0; -} - static int snd_hdsp_capture_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *dst, unsigned long count) + struct iov_iter *dst, unsigned long count) { struct hdsp *hdsp = snd_pcm_substream_chip(substream); signed char *channel_buf; @@ -4004,25 +3990,11 @@ static int snd_hdsp_capture_copy(struct snd_pcm_substream *substream, channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel); if (snd_BUG_ON(!channel_buf)) return -EIO; - if (copy_to_user(dst, channel_buf + pos, count)) + if (copy_to_iter(channel_buf + pos, count, dst) != count) return -EFAULT; return 0; } -static int snd_hdsp_capture_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void *dst, unsigned long count) -{ - struct hdsp *hdsp = snd_pcm_substream_chip(substream); - signed char *channel_buf; - - channel_buf = hdsp_channel_buffer_location(hdsp, substream->pstr->stream, channel); - if (snd_BUG_ON(!channel_buf)) - return -EIO; - memcpy(dst, channel_buf + pos, count); - return 0; -} - static int snd_hdsp_hw_silence(struct snd_pcm_substream *substream, int channel, unsigned long pos, unsigned long count) @@ -4950,8 +4922,7 @@ static const struct snd_pcm_ops snd_hdsp_playback_ops = { .prepare = snd_hdsp_prepare, .trigger = snd_hdsp_trigger, .pointer = snd_hdsp_hw_pointer, - .copy_user = snd_hdsp_playback_copy, - .copy_kernel = snd_hdsp_playback_copy_kernel, + .copy = snd_hdsp_playback_copy, .fill_silence = snd_hdsp_hw_silence, }; @@ -4963,8 +4934,7 @@ static const struct snd_pcm_ops snd_hdsp_capture_ops = { .prepare = snd_hdsp_prepare, .trigger = snd_hdsp_trigger, .pointer = snd_hdsp_hw_pointer, - .copy_user = snd_hdsp_capture_copy, - .copy_kernel = snd_hdsp_capture_copy_kernel, + .copy = snd_hdsp_capture_copy, }; static int snd_hdsp_create_hwdep(struct snd_card *card, struct hdsp *hdsp) From 2098765e952714d01a5cd615f5a80733762097c0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:24 +0200 Subject: [PATCH 301/334] ALSA: rme9652: Convert to generic PCM copy ops This patch converts the rme9652 driver code to use the new unified PCM copy callback. It's a straightforward conversion from *_user() to *_iter() variants. Note that copy_from/to_iter() returns the copied bytes, hence the error condition is adjusted accordingly. Link: https://lore.kernel.org/r/20230815190136.8987-14-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/rme9652/rme9652.c | 46 +++++-------------------------------- 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index e7c320afefe8..d066c70ae160 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -1844,7 +1844,7 @@ static signed char *rme9652_channel_buffer_location(struct snd_rme9652 *rme9652, static int snd_rme9652_playback_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *src, unsigned long count) + struct iov_iter *src, unsigned long count) { struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); signed char *channel_buf; @@ -1857,30 +1857,14 @@ static int snd_rme9652_playback_copy(struct snd_pcm_substream *substream, channel); if (snd_BUG_ON(!channel_buf)) return -EIO; - if (copy_from_user(channel_buf + pos, src, count)) + if (copy_from_iter(channel_buf + pos, count, src) != count) return -EFAULT; return 0; } -static int snd_rme9652_playback_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void *src, unsigned long count) -{ - struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); - signed char *channel_buf; - - channel_buf = rme9652_channel_buffer_location(rme9652, - substream->pstr->stream, - channel); - if (snd_BUG_ON(!channel_buf)) - return -EIO; - memcpy(channel_buf + pos, src, count); - return 0; -} - static int snd_rme9652_capture_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *dst, unsigned long count) + struct iov_iter *dst, unsigned long count) { struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); signed char *channel_buf; @@ -1893,27 +1877,11 @@ static int snd_rme9652_capture_copy(struct snd_pcm_substream *substream, channel); if (snd_BUG_ON(!channel_buf)) return -EIO; - if (copy_to_user(dst, channel_buf + pos, count)) + if (copy_to_iter(channel_buf + pos, count, dst) != count) return -EFAULT; return 0; } -static int snd_rme9652_capture_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void *dst, unsigned long count) -{ - struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); - signed char *channel_buf; - - channel_buf = rme9652_channel_buffer_location(rme9652, - substream->pstr->stream, - channel); - if (snd_BUG_ON(!channel_buf)) - return -EIO; - memcpy(dst, channel_buf + pos, count); - return 0; -} - static int snd_rme9652_hw_silence(struct snd_pcm_substream *substream, int channel, unsigned long pos, unsigned long count) @@ -2370,8 +2338,7 @@ static const struct snd_pcm_ops snd_rme9652_playback_ops = { .prepare = snd_rme9652_prepare, .trigger = snd_rme9652_trigger, .pointer = snd_rme9652_hw_pointer, - .copy_user = snd_rme9652_playback_copy, - .copy_kernel = snd_rme9652_playback_copy_kernel, + .copy = snd_rme9652_playback_copy, .fill_silence = snd_rme9652_hw_silence, }; @@ -2383,8 +2350,7 @@ static const struct snd_pcm_ops snd_rme9652_capture_ops = { .prepare = snd_rme9652_prepare, .trigger = snd_rme9652_trigger, .pointer = snd_rme9652_hw_pointer, - .copy_user = snd_rme9652_capture_copy, - .copy_kernel = snd_rme9652_capture_copy_kernel, + .copy = snd_rme9652_capture_copy, }; static int snd_rme9652_create_pcm(struct snd_card *card, From 2f432f4702134fac27677f13aba69ed830984f75 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:25 +0200 Subject: [PATCH 302/334] ALSA: sh: Convert to generic PCM copy ops This patch converts the sh_dac_audio driver code to use the new unified PCM copy callback. It's a straightforward conversion from *_user() to *_iter() variants. Link: https://lore.kernel.org/r/20230815190136.8987-15-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/sh/sh_dac_audio.c | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c index 8cf571955c9d..95ba3abd4e47 100644 --- a/sound/sh/sh_dac_audio.c +++ b/sound/sh/sh_dac_audio.c @@ -158,12 +158,12 @@ static int snd_sh_dac_pcm_trigger(struct snd_pcm_substream *substream, int cmd) static int snd_sh_dac_pcm_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *src, unsigned long count) + struct iov_iter *src, unsigned long count) { /* channel is not used (interleaved data) */ struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); - if (copy_from_user_toio(chip->data_buffer + pos, src, count)) + if (copy_from_iter_toio(chip->data_buffer + pos, src, count)) return -EFAULT; chip->buffer_end = chip->data_buffer + pos + count; @@ -175,24 +175,6 @@ static int snd_sh_dac_pcm_copy(struct snd_pcm_substream *substream, return 0; } -static int snd_sh_dac_pcm_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void *src, unsigned long count) -{ - /* channel is not used (interleaved data) */ - struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); - - memcpy_toio(chip->data_buffer + pos, src, count); - chip->buffer_end = chip->data_buffer + pos + count; - - if (chip->empty) { - chip->empty = 0; - dac_audio_start_timer(chip); - } - - return 0; -} - static int snd_sh_dac_pcm_silence(struct snd_pcm_substream *substream, int channel, unsigned long pos, unsigned long count) @@ -227,8 +209,7 @@ static const struct snd_pcm_ops snd_sh_dac_pcm_ops = { .prepare = snd_sh_dac_pcm_prepare, .trigger = snd_sh_dac_pcm_trigger, .pointer = snd_sh_dac_pcm_pointer, - .copy_user = snd_sh_dac_pcm_copy, - .copy_kernel = snd_sh_dac_pcm_copy_kernel, + .copy = snd_sh_dac_pcm_copy, .fill_silence = snd_sh_dac_pcm_silence, .mmap = snd_pcm_lib_mmap_iomem, }; From 390244f5ba355a97ff9764d9946fe37eb1b195ce Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:26 +0200 Subject: [PATCH 303/334] ALSA: xen: Convert to generic PCM copy ops This patch converts the xen frontend driver code to use the new unified PCM copy callback. It's a straightforward conversion from *_user() to *_iter() variants. Note that copy_from/to_iter() returns the copied bytes, hence the error condition is adjusted accordingly. Cc: Oleksandr Andrushchenko Cc: xen-devel@lists.xenproject.org Link: https://lore.kernel.org/r/20230815190136.8987-16-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/xen/xen_snd_front_alsa.c | 56 +++++++--------------------------- 1 file changed, 11 insertions(+), 45 deletions(-) diff --git a/sound/xen/xen_snd_front_alsa.c b/sound/xen/xen_snd_front_alsa.c index 7a3dfce97c15..31b5dc0f34d2 100644 --- a/sound/xen/xen_snd_front_alsa.c +++ b/sound/xen/xen_snd_front_alsa.c @@ -602,38 +602,24 @@ static snd_pcm_uframes_t alsa_pointer(struct snd_pcm_substream *substream) return (snd_pcm_uframes_t)atomic_read(&stream->hw_ptr); } -static int alsa_pb_copy_user(struct snd_pcm_substream *substream, - int channel, unsigned long pos, void __user *src, - unsigned long count) +static int alsa_pb_copy(struct snd_pcm_substream *substream, + int channel, unsigned long pos, struct iov_iter *src, + unsigned long count) { struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); if (unlikely(pos + count > stream->buffer_sz)) return -EINVAL; - if (copy_from_user(stream->buffer + pos, src, count)) + if (copy_from_iter(stream->buffer + pos, count, src) != count) return -EFAULT; return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count); } -static int alsa_pb_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, void *src, - unsigned long count) -{ - struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); - - if (unlikely(pos + count > stream->buffer_sz)) - return -EINVAL; - - memcpy(stream->buffer + pos, src, count); - - return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count); -} - -static int alsa_cap_copy_user(struct snd_pcm_substream *substream, - int channel, unsigned long pos, void __user *dst, - unsigned long count) +static int alsa_cap_copy(struct snd_pcm_substream *substream, + int channel, unsigned long pos, struct iov_iter *dst, + unsigned long count) { struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); int ret; @@ -645,26 +631,8 @@ static int alsa_cap_copy_user(struct snd_pcm_substream *substream, if (ret < 0) return ret; - return copy_to_user(dst, stream->buffer + pos, count) ? - -EFAULT : 0; -} - -static int alsa_cap_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, void *dst, - unsigned long count) -{ - struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); - int ret; - - if (unlikely(pos + count > stream->buffer_sz)) - return -EINVAL; - - ret = xen_snd_front_stream_read(&stream->evt_pair->req, pos, count); - if (ret < 0) - return ret; - - memcpy(dst, stream->buffer + pos, count); - + if (copy_to_iter(stream->buffer + pos, count, dst) != count) + return -EFAULT; return 0; } @@ -697,8 +665,7 @@ static const struct snd_pcm_ops snd_drv_alsa_playback_ops = { .prepare = alsa_prepare, .trigger = alsa_trigger, .pointer = alsa_pointer, - .copy_user = alsa_pb_copy_user, - .copy_kernel = alsa_pb_copy_kernel, + .copy = alsa_pb_copy, .fill_silence = alsa_pb_fill_silence, }; @@ -710,8 +677,7 @@ static const struct snd_pcm_ops snd_drv_alsa_capture_ops = { .prepare = alsa_prepare, .trigger = alsa_trigger, .pointer = alsa_pointer, - .copy_user = alsa_cap_copy_user, - .copy_kernel = alsa_cap_copy_kernel, + .copy = alsa_cap_copy, }; static int new_pcm_instance(struct xen_snd_front_card_info *card_info, From 62da99b56f0b43435896c4a5eca050631c99ce4f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:27 +0200 Subject: [PATCH 304/334] ALSA: pcmtest: Update comment about PCM copy ops Just an update of a comment mentioning the old PCM callbacks to correct to the new PCM copy ops. Link: https://lore.kernel.org/r/20230815190136.8987-17-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/drivers/pcmtest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/drivers/pcmtest.c b/sound/drivers/pcmtest.c index 7f170429eb8f..27cbb9d38f08 100644 --- a/sound/drivers/pcmtest.c +++ b/sound/drivers/pcmtest.c @@ -227,7 +227,7 @@ static void check_buf_block(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runti /* * Fill buffer in the non-interleaved mode. The order of samples is C0, ..., C0, C1, ..., C1, C2... - * The channel buffers lay in the DMA buffer continuously (see default copy_user and copy_kernel + * The channel buffers lay in the DMA buffer continuously (see default copy * handlers in the pcm_lib.c file). * * Here we increment the DMA buffer position every time we write a byte to any channel 'buffer'. From 44f08b67f2d2c699f2b1784d2aacdf3760a09cc5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:28 +0200 Subject: [PATCH 305/334] media: solo6x10: Convert to generic PCM copy ops This patch converts the solo6x10 driver code to use the new unified PCM copy callback. It's a straightforward conversion from *_user() to *_iter() variants. As copy_to_iter() updates the internal offest at each write, we can drop the dst counter update in the loop, too. Note that copy_to_iter() returns the copied bytes, hence the error condition is adjusted accordingly. Acked-by: Ismael Luceno Acked-by: Hans Verkuil Cc: Bluecherry Maintainers Cc: Anton Sviridenko Cc: Andrey Utkin Cc: Mauro Carvalho Chehab Cc: linux-media@vger.kernel.org Link: https://lore.kernel.org/r/20230815190136.8987-18-tiwai@suse.de Signed-off-by: Takashi Iwai --- drivers/media/pci/solo6x10/solo6x10-g723.c | 39 ++++------------------ 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c index 6cebad665565..1db9f40ee0c0 100644 --- a/drivers/media/pci/solo6x10/solo6x10-g723.c +++ b/drivers/media/pci/solo6x10/solo6x10-g723.c @@ -204,9 +204,9 @@ static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss) return idx * G723_FRAMES_PER_PAGE; } -static int snd_solo_pcm_copy_user(struct snd_pcm_substream *ss, int channel, - unsigned long pos, void __user *dst, - unsigned long count) +static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel, + unsigned long pos, struct iov_iter *dst, + unsigned long count) { struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); struct solo_dev *solo_dev = solo_pcm->solo_dev; @@ -223,35 +223,9 @@ static int snd_solo_pcm_copy_user(struct snd_pcm_substream *ss, int channel, if (err) return err; - if (copy_to_user(dst, solo_pcm->g723_buf, G723_PERIOD_BYTES)) + if (copy_to_iter(solo_pcm->g723_buf, G723_PERIOD_BYTES, dst) != + G723_PERIOD_BYTES) return -EFAULT; - dst += G723_PERIOD_BYTES; - } - - return 0; -} - -static int snd_solo_pcm_copy_kernel(struct snd_pcm_substream *ss, int channel, - unsigned long pos, void *dst, - unsigned long count) -{ - struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); - struct solo_dev *solo_dev = solo_pcm->solo_dev; - int err, i; - - for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) { - int page = (pos / G723_FRAMES_PER_PAGE) + i; - - err = solo_p2m_dma_t(solo_dev, 0, solo_pcm->g723_dma, - SOLO_G723_EXT_ADDR(solo_dev) + - (page * G723_PERIOD_BLOCK) + - (ss->number * G723_PERIOD_BYTES), - G723_PERIOD_BYTES, 0, 0); - if (err) - return err; - - memcpy(dst, solo_pcm->g723_buf, G723_PERIOD_BYTES); - dst += G723_PERIOD_BYTES; } return 0; @@ -263,8 +237,7 @@ static const struct snd_pcm_ops snd_solo_pcm_ops = { .prepare = snd_solo_pcm_prepare, .trigger = snd_solo_pcm_trigger, .pointer = snd_solo_pcm_pointer, - .copy_user = snd_solo_pcm_copy_user, - .copy_kernel = snd_solo_pcm_copy_kernel, + .copy = snd_solo_pcm_copy, }; static int snd_solo_capture_volume_info(struct snd_kcontrol *kcontrol, From 66201cacc33d740057bd64af6371ad846cff376f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:29 +0200 Subject: [PATCH 306/334] ASoC: component: Add generic PCM copy ops For following the ALSA PCM core change, a new PCM copy ops is added toe ASoC component framework: snd_soc_component_driver receives the copy ops, and snd_soc_pcm_component_copy() helper is provided. This also fixes a long-standing potential bug where the ASoC driver covers only copy_user PCM callback and misses the copy from kernel pointers (such as OSS PCM layer), too. As of this patch, the old copy_user is still kept, but it'll be dropped later after all drivers are converted. Reviewed-by: Mark Brown Link: https://lore.kernel.org/r/20230815190136.8987-19-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/soc-component.h | 7 +++++++ sound/soc/soc-component.c | 18 ++++++++++++++++++ sound/soc/soc-pcm.c | 4 +++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 87f248a06271..8040f001f2fb 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -141,6 +141,10 @@ struct snd_soc_component_driver { struct snd_pcm_substream *substream, int channel, unsigned long pos, void __user *buf, unsigned long bytes); + int (*copy)(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int channel, + unsigned long pos, struct iov_iter *buf, + unsigned long bytes); struct page *(*page)(struct snd_soc_component *component, struct snd_pcm_substream *substream, unsigned long offset); @@ -512,6 +516,9 @@ int snd_soc_pcm_component_sync_stop(struct snd_pcm_substream *substream); int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, int channel, unsigned long pos, void __user *buf, unsigned long bytes); +int snd_soc_pcm_component_copy(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + struct iov_iter *buf, unsigned long bytes); struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, unsigned long offset); int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 4356cc320fea..ffa2dd8a21ba 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -1052,6 +1052,24 @@ int snd_soc_pcm_component_sync_stop(struct snd_pcm_substream *substream) return 0; } +int snd_soc_pcm_component_copy(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + struct iov_iter *buf, unsigned long bytes) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_component *component; + int i; + + /* FIXME. it returns 1st copy now */ + for_each_rtd_components(rtd, i, component) + if (component->driver->copy) + return soc_component_ret(component, + component->driver->copy(component, substream, + channel, pos, buf, bytes)); + + return -EINVAL; +} + int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, int channel, unsigned long pos, void __user *buf, unsigned long bytes) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 8896227e4fb7..71403da28d37 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2973,7 +2973,9 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->ops.ioctl = snd_soc_pcm_component_ioctl; if (drv->sync_stop) rtd->ops.sync_stop = snd_soc_pcm_component_sync_stop; - if (drv->copy_user) + if (drv->copy) + rtd->ops.copy = snd_soc_pcm_component_copy; + else if (drv->copy_user) rtd->ops.copy_user = snd_soc_pcm_component_copy_user; if (drv->page) rtd->ops.page = snd_soc_pcm_component_page; From 95396d83e96cc1b7887562d07ff0324c11e744db Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:30 +0200 Subject: [PATCH 307/334] ASoC: mediatek: Convert to generic PCM copy ops This patch converts the mediatek BT SCO driver code to use the new unified PCM copy callback. It's a straightforward conversion from *_user() to *_iter() variants. As copy_form/to_iter() updates the internal offset at each read/write, we can drop the cur_*_idx counter in the loop, too. Note that copy_from/to_iter() returns the copied bytes, hence the error condition is adjusted accordingly. Reviewed-by: Mark Brown Link: https://lore.kernel.org/r/20230815190136.8987-20-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/soc/mediatek/common/mtk-btcvsd.c | 27 ++++++++++---------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c index 1ba0633e542f..c12d170fa1de 100644 --- a/sound/soc/mediatek/common/mtk-btcvsd.c +++ b/sound/soc/mediatek/common/mtk-btcvsd.c @@ -696,11 +696,10 @@ static int wait_for_bt_irq(struct mtk_btcvsd_snd *bt, } static ssize_t mtk_btcvsd_snd_read(struct mtk_btcvsd_snd *bt, - char __user *buf, + struct iov_iter *buf, size_t count) { ssize_t read_size = 0, read_count = 0, cur_read_idx, cont; - unsigned int cur_buf_ofs = 0; unsigned long avail; unsigned long flags; unsigned int packet_size = bt->rx->packet_size; @@ -743,10 +742,9 @@ static ssize_t mtk_btcvsd_snd_read(struct mtk_btcvsd_snd *bt, if (read_size > cont) read_size = cont; - if (copy_to_user(buf + cur_buf_ofs, - bt->rx_packet_buf + cur_read_idx, - read_size)) { - dev_warn(bt->dev, "%s(), copy_to_user fail\n", + if (copy_to_iter(bt->rx_packet_buf + cur_read_idx, + read_size, buf) != read_size) { + dev_warn(bt->dev, "%s(), copy_to_iter fail\n", __func__); return -EFAULT; } @@ -756,7 +754,6 @@ static ssize_t mtk_btcvsd_snd_read(struct mtk_btcvsd_snd *bt, spin_unlock_irqrestore(&bt->rx_lock, flags); read_count += read_size; - cur_buf_ofs += read_size; count -= read_size; } @@ -777,11 +774,10 @@ static ssize_t mtk_btcvsd_snd_read(struct mtk_btcvsd_snd *bt, } static ssize_t mtk_btcvsd_snd_write(struct mtk_btcvsd_snd *bt, - char __user *buf, + struct iov_iter *buf, size_t count) { int written_size = count, avail, cur_write_idx, write_size, cont; - unsigned int cur_buf_ofs = 0; unsigned long flags; unsigned int packet_size = bt->tx->packet_size; @@ -835,11 +831,9 @@ static ssize_t mtk_btcvsd_snd_write(struct mtk_btcvsd_snd *bt, if (write_size > cont) write_size = cont; - if (copy_from_user(bt->tx_packet_buf + - cur_write_idx, - buf + cur_buf_ofs, - write_size)) { - dev_warn(bt->dev, "%s(), copy_from_user fail\n", + if (copy_from_iter(bt->tx_packet_buf + cur_write_idx, + write_size, buf) != write_size) { + dev_warn(bt->dev, "%s(), copy_from_iter fail\n", __func__); return -EFAULT; } @@ -847,7 +841,6 @@ static ssize_t mtk_btcvsd_snd_write(struct mtk_btcvsd_snd *bt, spin_lock_irqsave(&bt->tx_lock, flags); bt->tx->packet_w += write_size / packet_size; spin_unlock_irqrestore(&bt->tx_lock, flags); - cur_buf_ofs += write_size; count -= write_size; } @@ -1033,7 +1026,7 @@ static snd_pcm_uframes_t mtk_pcm_btcvsd_pointer( static int mtk_pcm_btcvsd_copy(struct snd_soc_component *component, struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *buf, unsigned long count) + struct iov_iter *buf, unsigned long count) { struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); @@ -1274,7 +1267,7 @@ static const struct snd_soc_component_driver mtk_btcvsd_snd_platform = { .prepare = mtk_pcm_btcvsd_prepare, .trigger = mtk_pcm_btcvsd_trigger, .pointer = mtk_pcm_btcvsd_pointer, - .copy_user = mtk_pcm_btcvsd_copy, + .copy = mtk_pcm_btcvsd_copy, }; static int mtk_btcvsd_snd_probe(struct platform_device *pdev) From ce2d8ed8d809e70e1eb260b2e02a7be0ba0c0211 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:31 +0200 Subject: [PATCH 308/334] ASoC: qcom: Convert to generic PCM copy ops This patch converts the qcom lpass driver code to use the new unified PCM copy callback. It's a straightforward conversion from *_user() to *_iter() variants. Note that copy_from/to_iter() returns the copied bytes, hence the error condition is adjusted accordingly. Reviewed-by: Mark Brown Cc: Srinivas Kandagatla Cc: Banajit Goswami Link: https://lore.kernel.org/r/20230815190136.8987-21-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/soc/qcom/lpass-platform.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index ef5cb40b2d9b..990d7c33f90f 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -1219,7 +1219,8 @@ static int lpass_platform_pcmops_resume(struct snd_soc_component *component) static int lpass_platform_copy(struct snd_soc_component *component, struct snd_pcm_substream *substream, int channel, - unsigned long pos, void __user *buf, unsigned long bytes) + unsigned long pos, struct iov_iter *buf, + unsigned long bytes) { struct snd_pcm_runtime *rt = substream->runtime; unsigned int dai_id = component->id; @@ -1230,16 +1231,16 @@ static int lpass_platform_copy(struct snd_soc_component *component, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (is_cdc_dma_port(dai_id)) { - ret = copy_from_user_toio(dma_buf, buf, bytes); + ret = copy_from_iter_toio(dma_buf, buf, bytes); } else { - if (copy_from_user((void __force *)dma_buf, buf, bytes)) + if (copy_from_iter((void __force *)dma_buf, bytes, buf) != bytes) ret = -EFAULT; } } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { if (is_cdc_dma_port(dai_id)) { - ret = copy_to_user_fromio(buf, dma_buf, bytes); + ret = copy_to_iter_fromio(buf, dma_buf, bytes); } else { - if (copy_to_user(buf, (void __force *)dma_buf, bytes)) + if (copy_to_iter((void __force *)dma_buf, bytes, buf) != bytes) ret = -EFAULT; } } @@ -1260,7 +1261,7 @@ static const struct snd_soc_component_driver lpass_component_driver = { .pcm_construct = lpass_platform_pcm_new, .suspend = lpass_platform_pcmops_suspend, .resume = lpass_platform_pcmops_resume, - .copy_user = lpass_platform_copy, + .copy = lpass_platform_copy, }; From 56b00d10ffd4dcd6b068c2290ffabf0ae2d49789 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:32 +0200 Subject: [PATCH 309/334] ASoC: dmaengine: Convert to generic PCM copy ops This patch converts the ASoC dmaenging driver code to use the new unified PCM copy callback. It's a straightforward conversion from *_user() to *_iter() variants. The process callback is still using the direct pointer as of now, but it'll be converted in the next patch. Note that copy_from/to_iter() returns the copied bytes, hence the error condition is adjusted accordingly. Reviewed-by: Mark Brown Cc: Lars-Peter Clausen Link: https://lore.kernel.org/r/20230815190136.8987-22-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/soc/soc-generic-dmaengine-pcm.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 3b99f619e37e..f2cb75781566 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -287,10 +287,10 @@ static snd_pcm_uframes_t dmaengine_pcm_pointer( return snd_dmaengine_pcm_pointer(substream); } -static int dmaengine_copy_user(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - int channel, unsigned long hwoff, - void __user *buf, unsigned long bytes) +static int dmaengine_copy(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + int channel, unsigned long hwoff, + struct iov_iter *buf, unsigned long bytes) { struct snd_pcm_runtime *runtime = substream->runtime; struct dmaengine_pcm *pcm = soc_component_to_pcm(component); @@ -300,19 +300,20 @@ static int dmaengine_copy_user(struct snd_soc_component *component, bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; void *dma_ptr = runtime->dma_area + hwoff + channel * (runtime->dma_bytes / runtime->channels); + void *ptr = (void __force *)iter_iov_addr(buf); if (is_playback) - if (copy_from_user(dma_ptr, buf, bytes)) + if (copy_from_iter(dma_ptr, bytes, buf) != bytes) return -EFAULT; if (process) { - int ret = process(substream, channel, hwoff, (__force void *)buf, bytes); + int ret = process(substream, channel, hwoff, ptr, bytes); if (ret < 0) return ret; } if (!is_playback) - if (copy_to_user(buf, dma_ptr, bytes)) + if (copy_to_iter(dma_ptr, bytes, buf) != bytes) return -EFAULT; return 0; @@ -337,7 +338,7 @@ static const struct snd_soc_component_driver dmaengine_pcm_component_process = { .hw_params = dmaengine_pcm_hw_params, .trigger = dmaengine_pcm_trigger, .pointer = dmaengine_pcm_pointer, - .copy_user = dmaengine_copy_user, + .copy = dmaengine_copy, .pcm_construct = dmaengine_pcm_new, }; From 9bebd65443c1379f6643397bf4854d6f80a8358c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:33 +0200 Subject: [PATCH 310/334] ASoC: dmaengine: Use iov_iter for process callback, too Along with the conversion to PCM copy ops, use the iov_iter for the pointer to be passed to the dmaengine process callback, too. It avoids the direct reference of iter_iov_addr(), and it can potentially help for the drivers to access memory properly (although both atmel and stm drivers don't use the given buffer address at all for now). Reviewed-by: Mark Brown Cc: Lars-Peter Clausen Cc: Claudiu Beznea Cc: Olivier Moysan Cc: Arnaud Pouliquen Link: https://lore.kernel.org/r/20230815190136.8987-23-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/dmaengine_pcm.h | 2 +- sound/soc/atmel/mchp-pdmc.c | 2 +- sound/soc/soc-generic-dmaengine-pcm.c | 5 ++--- sound/soc/stm/stm32_sai_sub.c | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 2df54cf02cb3..c9a8bce9a785 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -142,7 +142,7 @@ struct snd_dmaengine_pcm_config { struct snd_pcm_substream *substream); int (*process)(struct snd_pcm_substream *substream, int channel, unsigned long hwoff, - void *buf, unsigned long bytes); + struct iov_iter *buf, unsigned long bytes); dma_filter_fn compat_filter_fn; struct device *dma_dev; const char *chan_names[SNDRV_PCM_STREAM_LAST + 1]; diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c index 1a069f4cdcda..911bc334b41e 100644 --- a/sound/soc/atmel/mchp-pdmc.c +++ b/sound/soc/atmel/mchp-pdmc.c @@ -954,7 +954,7 @@ static int mchp_pdmc_dt_init(struct mchp_pdmc *dd) /* used to clean the channel index found on RHR's MSB */ static int mchp_pdmc_process(struct snd_pcm_substream *substream, int channel, unsigned long hwoff, - void *buf, unsigned long bytes) + struct iov_iter *buf, unsigned long bytes) { struct snd_pcm_runtime *runtime = substream->runtime; u8 *dma_ptr = runtime->dma_area + hwoff + diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index f2cb75781566..ff2166525dbc 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -296,18 +296,17 @@ static int dmaengine_copy(struct snd_soc_component *component, struct dmaengine_pcm *pcm = soc_component_to_pcm(component); int (*process)(struct snd_pcm_substream *substream, int channel, unsigned long hwoff, - void *buf, unsigned long bytes) = pcm->config->process; + struct iov_iter *buf, unsigned long bytes) = pcm->config->process; bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; void *dma_ptr = runtime->dma_area + hwoff + channel * (runtime->dma_bytes / runtime->channels); - void *ptr = (void __force *)iter_iov_addr(buf); if (is_playback) if (copy_from_iter(dma_ptr, bytes, buf) != bytes) return -EFAULT; if (process) { - int ret = process(substream, channel, hwoff, ptr, bytes); + int ret = process(substream, channel, hwoff, buf, bytes); if (ret < 0) return ret; } diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 271ec5b3378d..39f9b4654fa2 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1233,7 +1233,7 @@ static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = { static int stm32_sai_pcm_process_spdif(struct snd_pcm_substream *substream, int channel, unsigned long hwoff, - void *buf, unsigned long bytes) + struct iov_iter *buf, unsigned long bytes) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); From 36fc349aeeaf964bf842e4afd397c009b7daab4f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:34 +0200 Subject: [PATCH 311/334] ALSA: doc: Update description for the new PCM copy ops Update the documentation about the PCM copy callbacks. The update was kept minimalistic, just correcting the use of copy_user ops with the single copy ops, and drop/update the text mentioning the copy_kernel. Link: https://lore.kernel.org/r/20230815190136.8987-24-tiwai@suse.de Signed-off-by: Takashi Iwai --- .../kernel-api/writing-an-alsa-driver.rst | 58 ++++++------------- 1 file changed, 19 insertions(+), 39 deletions(-) diff --git a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst index 4335c98b3d82..cd421856409e 100644 --- a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst +++ b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst @@ -2018,8 +2018,8 @@ sleeping poll threads, etc. This callback is also atomic by default. -copy_user, copy_kernel and fill_silence ops -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +copy and fill_silence ops +~~~~~~~~~~~~~~~~~~~~~~~~~ These callbacks are not mandatory, and can be omitted in most cases. These callbacks are used when the hardware buffer cannot be in the @@ -3444,8 +3444,8 @@ external hardware buffer in interrupts (or in tasklets, preferably). The first case works fine if the external hardware buffer is large enough. This method doesn't need any extra buffers and thus is more -efficient. You need to define the ``copy_user`` and ``copy_kernel`` -callbacks for the data transfer, in addition to the ``fill_silence`` +efficient. You need to define the ``copy`` callback +for the data transfer, in addition to the ``fill_silence`` callback for playback. However, there is a drawback: it cannot be mmapped. The examples are GUS's GF1 PCM or emu8000's wavetable PCM. @@ -3458,22 +3458,22 @@ Another case is when the chip uses a PCI memory-map region for the buffer instead of the host memory. In this case, mmap is available only on certain architectures like the Intel one. In non-mmap mode, the data cannot be transferred as in the normal way. Thus you need to define the -``copy_user``, ``copy_kernel`` and ``fill_silence`` callbacks as well, +``copy`` and ``fill_silence`` callbacks as well, as in the cases above. Examples are found in ``rme32.c`` and ``rme96.c``. -The implementation of the ``copy_user``, ``copy_kernel`` and +The implementation of the ``copy`` and ``silence`` callbacks depends upon whether the hardware supports -interleaved or non-interleaved samples. The ``copy_user`` callback is +interleaved or non-interleaved samples. The ``copy`` callback is defined like below, a bit differently depending on whether the direction is playback or capture:: - static int playback_copy_user(struct snd_pcm_substream *substream, + static int playback_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *src, unsigned long count); - static int capture_copy_user(struct snd_pcm_substream *substream, + struct iov_iter *src, unsigned long count); + static int capture_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *dst, unsigned long count); + struct iov_iter *dst, unsigned long count); In the case of interleaved samples, the second argument (``channel``) is not used. The third argument (``pos``) specifies the position in bytes. @@ -3490,18 +3490,17 @@ of data (``count``) at the specified pointer (``src``) to the specified offset (``pos``) in the hardware buffer. When coded like memcpy-like way, the copy would look like:: - my_memcpy_from_user(my_buffer + pos, src, count); + my_memcpy_from_iter(my_buffer + pos, src, count); For the capture direction, you copy the given amount of data (``count``) at the specified offset (``pos``) in the hardware buffer to the specified pointer (``dst``):: - my_memcpy_to_user(dst, my_buffer + pos, count); + my_memcpy_to_iter(dst, my_buffer + pos, count); -Here the functions are named ``from_user`` and ``to_user`` because -it's the user-space buffer that is passed to these callbacks. That -is, the callback is supposed to copy data from/to the user-space -directly to/from the hardware buffer. +The given ``src`` or ``dst`` a struct iov_iter pointer containing the +pointer and the size. Use the existing helpers to copy or access the +data as defined in ``linux/uio.h``. Careful readers might notice that these callbacks receive the arguments in bytes, not in frames like other callbacks. It's because @@ -3519,25 +3518,6 @@ the given user-space buffer, but only for the given channel. For details, please check ``isa/gus/gus_pcm.c`` or ``pci/rme9652/rme9652.c`` as examples. -The above callbacks are the copies from/to the user-space buffer. There -are some cases where we want to copy from/to the kernel-space buffer -instead. In such a case, the ``copy_kernel`` callback is called. It'd -look like:: - - static int playback_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void *src, unsigned long count); - static int capture_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void *dst, unsigned long count); - -As found easily, the only difference is that the buffer pointer is -without a ``__user`` prefix; that is, a kernel-buffer pointer is passed -in the fourth argument. Correspondingly, the implementation would be -a version without the user-copy, such as:: - - my_memcpy(my_buffer + pos, src, count); - Usually for the playback, another callback ``fill_silence`` is defined. It's implemented in a similar way as the copy callbacks above:: @@ -3545,10 +3525,10 @@ above:: static int silence(struct snd_pcm_substream *substream, int channel, unsigned long pos, unsigned long count); -The meanings of arguments are the same as in the ``copy_user`` and -``copy_kernel`` callbacks, although there is no buffer pointer +The meanings of arguments are the same as in the ``copy`` callback, +although there is no buffer pointer argument. In the case of interleaved samples, the channel argument has -no meaning, as for the ``copy_*`` callbacks. +no meaning, as for the ``copy`` callback. The role of the ``fill_silence`` callback is to set the given amount (``count``) of silence data at the specified offset (``pos``) in the From 205d3e030a02b18a6bc1ca590965871a803163f2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:35 +0200 Subject: [PATCH 312/334] ASoC: pcm: Drop obsoleted PCM copy_user ops Now all ASoC users have been replaced to use the new PCM copy ops, let's drop the obsoleted copy_user ops and its helper function. Reviewed-by: Mark Brown Link: https://lore.kernel.org/r/20230815190136.8987-25-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/soc-component.h | 7 ------- sound/soc/soc-component.c | 20 -------------------- sound/soc/soc-pcm.c | 2 -- 3 files changed, 29 deletions(-) diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 8040f001f2fb..17bea3144551 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -137,10 +137,6 @@ struct snd_soc_component_driver { struct timespec64 *audio_ts, struct snd_pcm_audio_tstamp_config *audio_tstamp_config, struct snd_pcm_audio_tstamp_report *audio_tstamp_report); - int (*copy_user)(struct snd_soc_component *component, - struct snd_pcm_substream *substream, int channel, - unsigned long pos, void __user *buf, - unsigned long bytes); int (*copy)(struct snd_soc_component *component, struct snd_pcm_substream *substream, int channel, unsigned long pos, struct iov_iter *buf, @@ -513,9 +509,6 @@ int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream); int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg); int snd_soc_pcm_component_sync_stop(struct snd_pcm_substream *substream); -int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void __user *buf, unsigned long bytes); int snd_soc_pcm_component_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, struct iov_iter *buf, unsigned long bytes); diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index ffa2dd8a21ba..f18406dfa1e4 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -1070,26 +1070,6 @@ int snd_soc_pcm_component_copy(struct snd_pcm_substream *substream, return -EINVAL; } -int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void __user *buf, unsigned long bytes) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_component *component; - int i; - - /* FIXME. it returns 1st copy now */ - for_each_rtd_components(rtd, i, component) - if (component->driver->copy_user) - return soc_component_ret( - component, - component->driver->copy_user( - component, substream, channel, - pos, buf, bytes)); - - return -EINVAL; -} - struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, unsigned long offset) { diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 71403da28d37..ae02d1d80c88 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2975,8 +2975,6 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->ops.sync_stop = snd_soc_pcm_component_sync_stop; if (drv->copy) rtd->ops.copy = snd_soc_pcm_component_copy; - else if (drv->copy_user) - rtd->ops.copy_user = snd_soc_pcm_component_copy_user; if (drv->page) rtd->ops.page = snd_soc_pcm_component_page; if (drv->mmap) From 6c0217b11066b9bcd6d8f1f8bd11c0610e536e04 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:36 +0200 Subject: [PATCH 313/334] ALSA: pcm: Drop obsoleted PCM copy_user and copy_kernel ops Finally all users have been converted to the new PCM copy ops, let's drop the obsoleted copy_kernel and copy_user ops completely. Link: https://lore.kernel.org/r/20230815190136.8987-26-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 5 ----- sound/core/pcm_lib.c | 18 +----------------- sound/core/pcm_native.c | 2 +- 3 files changed, 2 insertions(+), 23 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 1f6df47eb500..2a815373dac1 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -71,11 +71,6 @@ struct snd_pcm_ops { unsigned long pos, unsigned long bytes); int (*copy)(struct snd_pcm_substream *substream, int channel, unsigned long pos, struct iov_iter *iter, unsigned long bytes); - int (*copy_user)(struct snd_pcm_substream *substream, int channel, - unsigned long pos, void __user *buf, - unsigned long bytes); - int (*copy_kernel)(struct snd_pcm_substream *substream, int channel, - unsigned long pos, void *buf, unsigned long bytes); struct page *(*page)(struct snd_pcm_substream *substream, unsigned long offset); int (*mmap)(struct snd_pcm_substream *substream, struct vm_area_struct *vma); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 3303914c58ea..4859fb1caec9 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2031,19 +2031,6 @@ static int default_read_copy(struct snd_pcm_substream *substream, return 0; } -/* a wrapper for calling old copy_kernel or copy_user ops */ -static int call_old_copy(struct snd_pcm_substream *substream, - int channel, unsigned long hwoff, - struct iov_iter *iter, unsigned long bytes) -{ - if (iov_iter_is_kvec(iter)) - return substream->ops->copy_kernel(substream, channel, hwoff, - iter_iov_addr(iter), bytes); - else - return substream->ops->copy_user(substream, channel, hwoff, - iter_iov_addr(iter), bytes); -} - /* call transfer with the filled iov_iter */ static int do_transfer(struct snd_pcm_substream *substream, int c, unsigned long hwoff, void *data, unsigned long bytes, @@ -2147,7 +2134,7 @@ static int pcm_sanity_check(struct snd_pcm_substream *substream) if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; - if (snd_BUG_ON(!substream->ops->copy && !substream->ops->copy_user && !runtime->dma_area)) + if (snd_BUG_ON(!substream->ops->copy && !runtime->dma_area)) return -EINVAL; if (runtime->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; @@ -2255,9 +2242,6 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, } else { if (substream->ops->copy) transfer = substream->ops->copy; - else if ((in_kernel && substream->ops->copy_kernel) || - (!in_kernel && substream->ops->copy_user)) - transfer = call_old_copy; else transfer = is_playback ? default_write_copy : default_read_copy; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 34efd4d198d6..bd9ddf412b46 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -809,7 +809,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, runtime->boundary *= 2; /* clear the buffer for avoiding possible kernel info leaks */ - if (runtime->dma_area && !substream->ops->copy && !substream->ops->copy_user) { + if (runtime->dma_area && !substream->ops->copy) { size_t size = runtime->dma_bytes; if (runtime->info & SNDRV_PCM_INFO_MMAP) From 9f533734640649883cd1f4d4ebb024858d49a0b6 Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Fri, 18 Aug 2023 20:48:52 +0800 Subject: [PATCH 314/334] ALSA: asihpi: Remove unused declarations These are not implemented, so can remove them. Signed-off-by: Yue Haibing Link: https://lore.kernel.org/r/20230818124852.51468-1-yuehaibing@huawei.com Signed-off-by: Takashi Iwai --- sound/pci/asihpi/hpi.h | 16 ---------------- sound/pci/asihpi/hpi_internal.h | 5 ----- 2 files changed, 21 deletions(-) diff --git a/sound/pci/asihpi/hpi.h b/sound/pci/asihpi/hpi.h index 3aebec763fb8..04a5cf6572cd 100644 --- a/sound/pci/asihpi/hpi.h +++ b/sound/pci/asihpi/hpi.h @@ -1191,19 +1191,6 @@ u16 hpi_adapter_set_mode_ex(u16 adapter_index, u32 adapter_mode, u16 hpi_adapter_get_mode(u16 adapter_index, u32 *padapter_mode); -u16 hpi_adapter_get_assert2(u16 adapter_index, u16 *p_assert_count, - char *psz_assert, u32 *p_param1, u32 *p_param2, - u32 *p_dsp_string_addr, u16 *p_processor_id); - -u16 hpi_adapter_test_assert(u16 adapter_index, u16 assert_id); - -u16 hpi_adapter_enable_capability(u16 adapter_index, u16 capability, u32 key); - -u16 hpi_adapter_self_test(u16 adapter_index); - -u16 hpi_adapter_debug_read(u16 adapter_index, u32 dsp_address, char *p_bytes, - int *count_bytes); - u16 hpi_adapter_set_property(u16 adapter_index, u16 property, u16 paramter1, u16 paramter2); @@ -1488,9 +1475,6 @@ u16 hpi_pad_get_program_type(u32 h_control, u32 *ppTY); u16 hpi_pad_get_rdsPI(u32 h_control, u32 *ppI); -u16 hpi_pad_get_program_type_string(u32 h_control, const u32 data_type, - const u32 pTY, char *psz_string, const u32 string_length); - /****************************/ /* AES/EBU Receiver control */ /****************************/ diff --git a/sound/pci/asihpi/hpi_internal.h b/sound/pci/asihpi/hpi_internal.h index 6859d51389f5..e569e3b33b8e 100644 --- a/sound/pci/asihpi/hpi_internal.h +++ b/sound/pci/asihpi/hpi_internal.h @@ -1394,17 +1394,12 @@ u32 hpi_indexes_to_handle(const char c_object, const u16 adapter_index, void hpi_send_recv(struct hpi_message *phm, struct hpi_response *phr); /* used in PnP OS/driver */ -u16 hpi_subsys_create_adapter(const struct hpi_resource *p_resource, - u16 *pw_adapter_index); - u16 hpi_outstream_host_buffer_get_info(u32 h_outstream, u8 **pp_buffer, struct hpi_hostbuffer_status **pp_status); u16 hpi_instream_host_buffer_get_info(u32 h_instream, u8 **pp_buffer, struct hpi_hostbuffer_status **pp_status); -u16 hpi_adapter_restart(u16 adapter_index); - /* The following 3 functions were last declared in header files for driver 3.10. HPI_ControlQuery() used to be the recommended way From f286620b5dc974fe281d8feed6e228fd2f39d013 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 21 Aug 2023 09:00:03 +0100 Subject: [PATCH 315/334] ALSA: hda/realtek: Fix spelling mistake "powe" -> "power" There is a spelling mistake in a quirk entry. Fix it. Signed-off-by: Colin Ian King Fixes: 3babae915f4c ("ALSA: hda/tas2781: Add tas2781 HDA driver") Link: https://lore.kernel.org/r/20230821080003.16678-1-colin.i.king@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8f2f1a0c48d4..e294f3b0c9d1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9960,7 +9960,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), SND_PCI_QUIRK(0x17aa, 0x387d, "Yoga S780-16 pro Quad AAC", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x387e, "Yoga S780-16 pro Quad YC", ALC287_FIXUP_TAS2781_I2C), - SND_PCI_QUIRK(0x17aa, 0x3881, "YB9 dual powe mode2 YC", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x3881, "YB9 dual power mode2 YC", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x3884, "Y780 YG DUAL", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x3886, "Y780 VECO DUAL", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x38a7, "Y780P AMD YG dual", ALC287_FIXUP_TAS2781_I2C), From 5fadc941d07530d681f3b7ec91e56d8445bc3825 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 21 Aug 2023 13:18:57 +0200 Subject: [PATCH 316/334] ALSA: usb-audio: Fix init call orders for UAC1 There have been reports of USB-audio driver spewing errors at the probe time on a few devices like Jabra and Logitech. The suggested fix there couldn't be applied as is, unfortunately, because it'll likely break other devices. But, the patch suggested an interesting point: looking at the current init code in stream.c, one may notice that it does initialize differently from the device setup in endpoint.c. Namely, for UAC1, we should call snd_usb_init_pitch() and snd_usb_init_sample_rate() after setting the interface, while the init sequence at parsing calls them before setting the interface blindly. This patch changes the init sequence at parsing for UAC1 (and other devices that need a similar behavior) to be aligned with the rest of the code, setting the interface at first. And, this fixes the long-standing problems on a few UAC1 devices like Jabra / Logitech, as reported, too. Reported-and-tested-by: Joakim Tjernlund Closes: https://lore.kernel.org/r/202bbbc0f51522e8545783c4c5577d12a8e2d56d.camel@infinera.com Cc: Link: https://lore.kernel.org/r/20230821111857.28926-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/stream.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sound/usb/stream.c b/sound/usb/stream.c index f10f4e6d3fb8..3d4add94e367 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -1093,6 +1093,7 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int i, altno, err, stream; struct audioformat *fp = NULL; struct snd_usb_power_domain *pd = NULL; + bool set_iface_first; int num, protocol; dev = chip->dev; @@ -1223,11 +1224,19 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, return err; } + set_iface_first = false; + if (protocol == UAC_VERSION_1 || + (chip->quirk_flags & QUIRK_FLAG_SET_IFACE_FIRST)) + set_iface_first = true; + /* try to set the interface... */ usb_set_interface(chip->dev, iface_no, 0); + if (set_iface_first) + usb_set_interface(chip->dev, iface_no, altno); snd_usb_init_pitch(chip, fp); snd_usb_init_sample_rate(chip, fp, fp->rate_max); - usb_set_interface(chip->dev, iface_no, altno); + if (!set_iface_first) + usb_set_interface(chip->dev, iface_no, altno); } return 0; } From 1c80cc055b3f9fb72606d58c27eb2486c4b919a7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 20 Aug 2023 19:26:34 +0200 Subject: [PATCH 317/334] ALSA: hda/tas2781: Fix acpi device refcount leak at tas2781_read_acpi() The error path at tas2781_read_acpi() doesn't release the acpi_device adev but releases another device physdev instead. This results in a refcount leak. Fix it by replacing with the right object. Fixes: 5be27f1e3ec9 ("ALSA: hda/tas2781: Add tas2781 HDA driver") Reported-by: Pierre-Louis Bossart Closes: https://lore.kernel.org/r/9f910785-e856-1539-e3e4-c9817af5fe67@linux.intel.com Link: https://lore.kernel.org/r/20230820172635.22236-1-tiwai@suse.de 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 35dafc4aec4f..0968ae915fd0 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -118,7 +118,7 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid) err: dev_err(p->dev, "read acpi error, ret: %d\n", ret); - put_device(physdev); + acpi_dev_put(adev); return ret; } From 17a1eab7b70d85fc5711f37bb6e530b771736bb7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 20 Aug 2023 19:26:35 +0200 Subject: [PATCH 318/334] ALSA: hda/tas2781: Fix PM refcount unbalance at tas2781_hda_bind() The error path of tas2781_hda_bind() needs to release PM refcount as well. Modify the code flow to handle properly. Fixes: 5be27f1e3ec9 ("ALSA: hda/tas2781: Add tas2781 HDA driver") Reported-by: Pierre-Louis Bossart Closes: https://lore.kernel.org/r/9f910785-e856-1539-e3e4-c9817af5fe67@linux.intel.com Link: https://lore.kernel.org/r/20230820172635.22236-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/tas2781_hda_i2c.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index 0968ae915fd0..aa9ce3837336 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -608,15 +608,13 @@ static int tas2781_hda_bind(struct device *dev, struct device *master, strscpy(comps->name, dev_name(dev), sizeof(comps->name)); ret = tascodec_init(tas_priv, codec, tasdev_fw_ready); - if (ret) - return ret; - - comps->playback_hook = tas2781_hda_playback_hook; + if (!ret) + comps->playback_hook = tas2781_hda_playback_hook; pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); - return 0; + return ret; } static void tas2781_hda_unbind(struct device *dev, From 581523ee3652ea6c1012b2ccbb8588c9c77ef4bb Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Wed, 23 Aug 2023 15:39:56 +0100 Subject: [PATCH 319/334] ALSA: hda: cs35l41: Override the _DSD for HP Zbook Fury 17 G9 to correct boost type CS35L41 HDA driver requires ACPI to contain correct _DSD properties to correctly configure the device. Whilst the HP Zbook Fury 17 G9 contains valid _DSD properties, the boost type has been configured incorrectly in the _DSD for this laptop. We can override these properties to fix the boost type. Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20230823143956.755758-1-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda_property.c | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c index 9b5a1d61575e..b62a4e6968e2 100644 --- a/sound/pci/hda/cs35l41_hda_property.c +++ b/sound/pci/hda/cs35l41_hda_property.c @@ -43,6 +43,37 @@ static int lenovo_legion_no_acpi(struct cs35l41_hda *cs35l41, struct device *phy return 0; } +/* + * Device 103C89C6 does have _DSD, however it is setup to use the wrong boost type. + * We can override the _DSD to correct the boost type here. + * Since this laptop has valid ACPI, we do not need to handle cs-gpios, since that already exists + * in the ACPI. + */ +static int hp_vision_acpi_fix(struct cs35l41_hda *cs35l41, struct device *physdev, int id, + const char *hid) +{ + struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg; + + dev_info(cs35l41->dev, "Adding DSD properties for %s\n", cs35l41->acpi_subsystem_id); + + cs35l41->index = id; + cs35l41->channel_index = 0; + cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 1, GPIOD_OUT_HIGH); + cs35l41->speaker_id = -ENOENT; + hw_cfg->spk_pos = cs35l41->index ? 1 : 0; // right:left + hw_cfg->gpio1.func = CS35L41_NOT_USED; + hw_cfg->gpio1.valid = true; + hw_cfg->gpio2.func = CS35L41_INTERRUPT; + hw_cfg->gpio2.valid = true; + hw_cfg->bst_type = CS35L41_INT_BOOST; + hw_cfg->bst_ind = 1000; + hw_cfg->bst_ipk = 4500; + hw_cfg->bst_cap = 24; + hw_cfg->valid = true; + + return 0; +} + struct cs35l41_prop_model { const char *hid; const char *ssid; @@ -53,6 +84,7 @@ struct cs35l41_prop_model { static const struct cs35l41_prop_model cs35l41_prop_model_table[] = { { "CLSA0100", NULL, lenovo_legion_no_acpi }, { "CLSA0101", NULL, lenovo_legion_no_acpi }, + { "CSC3551", "103C89C6", hp_vision_acpi_fix }, {} }; From 93dc18e11b1ab2d485b69f91c973e6b83e47ebd0 Mon Sep 17 00:00:00 2001 From: SungHwan Jung Date: Wed, 23 Aug 2023 20:40:51 +0900 Subject: [PATCH 320/334] ALSA: hda/realtek: Add quirk for HP Victus 16-d1xxx to enable mute LED This quirk enables mute LED on HP Victus 16-d1xxx (8A25) laptops, which use ALC245 codec. Signed-off-by: SungHwan Jung Link: https://lore.kernel.org/r/20230823114051.3921-1-onenowy@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 54e17791c6a8..afc63d367fd5 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4639,6 +4639,22 @@ static void alc236_fixup_hp_mute_led_coefbit2(struct hda_codec *codec, } } +static void alc245_fixup_hp_mute_led_coefbit(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->mute_led_polarity = 0; + spec->mute_led_coef.idx = 0x0b; + spec->mute_led_coef.mask = 3 << 2; + spec->mute_led_coef.on = 2 << 2; + spec->mute_led_coef.off = 1 << 2; + snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set); + } +} + /* turn on/off mic-mute LED per capture hook by coef bit */ static int coef_micmute_led_set(struct led_classdev *led_cdev, enum led_brightness brightness) @@ -7301,6 +7317,7 @@ enum { ALC236_FIXUP_DELL_DUAL_CODECS, ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI, ALC287_FIXUP_TAS2781_I2C, + ALC245_FIXUP_HP_MUTE_LED_COEFBIT, }; /* A special fixup for Lenovo C940 and Yoga Duet 7; @@ -9385,6 +9402,10 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_THINKPAD_ACPI, }, + [ALC245_FIXUP_HP_MUTE_LED_COEFBIT] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc245_fixup_hp_mute_led_coefbit, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -9658,6 +9679,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x89c6, "Zbook Fury 17 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x89ca, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x89d3, "HP EliteBook 645 G9 (MB 89D2)", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8a25, "HP Victus 16-d1xxx (MB 8A25)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), SND_PCI_QUIRK(0x103c, 0x8a78, "HP Dev One", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x103c, 0x8aa0, "HP ProBook 440 G9 (MB 8A9E)", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8aa3, "HP ProBook 450 G9 (MB 8AA1)", ALC236_FIXUP_HP_GPIO_LED), From 22459ef3a9dea5249c250b30046c3b31cc684da9 Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Tue, 22 Aug 2023 19:05:41 +0400 Subject: [PATCH 321/334] ALSA: pcmtest: Add support for pcm pausing Add pause push/release support to the virtual PCM test driver. Add 'suspend' boolean field to the pcmtst_buf_iter structure, so we can pause the timer without shutting it down. Update the trigger callback handler correspondingly. Extract buffer initialization to the 'reset_buf_iterator' function since it is used in multiple places now. Signed-off-by: Ivan Orlov Link: https://lore.kernel.org/r/20230822150541.8450-1-ivan.orlov0322@gmail.com Signed-off-by: Takashi Iwai --- sound/drivers/pcmtest.c | 49 ++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/sound/drivers/pcmtest.c b/sound/drivers/pcmtest.c index 27cbb9d38f08..b59b78a09224 100644 --- a/sound/drivers/pcmtest.c +++ b/sound/drivers/pcmtest.c @@ -108,6 +108,7 @@ struct pcmtst_buf_iter { size_t total_bytes; // Total bytes read/written size_t chan_block; // Bytes in one channel buffer when non-interleaved struct snd_pcm_substream *substream; + bool suspend; // We need to pause timer without shutting it down struct timer_list timer_instance; }; @@ -115,7 +116,8 @@ static struct snd_pcm_hardware snd_pcmtst_hw = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_NONINTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID), + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_8000_48000, .rate_min = 8000, @@ -346,6 +348,9 @@ static void timer_timeout(struct timer_list *data) v_iter = from_timer(v_iter, data, timer_instance); substream = v_iter->substream; + if (v_iter->suspend) + return; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !v_iter->is_buf_corrupted) check_buf_block(v_iter, substream->runtime); else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) @@ -358,7 +363,9 @@ static void timer_timeout(struct timer_list *data) v_iter->period_pos %= v_iter->period_bytes; snd_pcm_period_elapsed(substream); } - mod_timer(&v_iter->timer_instance, jiffies + TIMER_INTERVAL + inject_delay); + + if (!v_iter->suspend) + mod_timer(&v_iter->timer_instance, jiffies + TIMER_INTERVAL + inject_delay); } static int snd_pcmtst_pcm_open(struct snd_pcm_substream *substream) @@ -373,19 +380,15 @@ static int snd_pcmtst_pcm_open(struct snd_pcm_substream *substream) if (!v_iter) return -ENOMEM; + v_iter->substream = substream; runtime->hw = snd_pcmtst_hw; runtime->private_data = v_iter; - v_iter->substream = substream; - v_iter->buf_pos = 0; - v_iter->is_buf_corrupted = false; - v_iter->period_pos = 0; - v_iter->total_bytes = 0; playback_capture_test = 0; ioctl_reset_test = 0; timer_setup(&v_iter->timer_instance, timer_timeout, 0); - mod_timer(&v_iter->timer_instance, jiffies + TIMER_INTERVAL); + return 0; } @@ -400,10 +403,40 @@ static int snd_pcmtst_pcm_close(struct snd_pcm_substream *substream) return 0; } +static inline void reset_buf_iterator(struct pcmtst_buf_iter *v_iter) +{ + v_iter->buf_pos = 0; + v_iter->is_buf_corrupted = false; + v_iter->period_pos = 0; + v_iter->total_bytes = 0; +} + +static inline void start_pcmtest_timer(struct pcmtst_buf_iter *v_iter) +{ + v_iter->suspend = false; + mod_timer(&v_iter->timer_instance, jiffies + TIMER_INTERVAL); +} + static int snd_pcmtst_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { + struct pcmtst_buf_iter *v_iter = substream->runtime->private_data; + if (inject_trigger_err) return -EINVAL; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + reset_buf_iterator(v_iter); + start_pcmtest_timer(v_iter); + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + start_pcmtest_timer(v_iter); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + // We can't call timer_shutdown_sync here, as it is forbidden to sleep here + v_iter->suspend = true; + break; + } return 0; } From 67de40c9df94037769967ba28c7d951afb45b7fb Mon Sep 17 00:00:00 2001 From: Su Hui Date: Wed, 23 Aug 2023 10:52:13 +0800 Subject: [PATCH 322/334] ALSA: ac97: Fix possible error value of *rac97 Before committing 79597c8bf64c, *rac97 always be NULL if there is an error. When error happens, make sure *rac97 is NULL is safer. For examble, in snd_vortex_mixer(): err = snd_ac97_mixer(pbus, &ac97, &vortex->codec); vortex->isquad = ((vortex->codec == NULL) ? 0 : (vortex->codec->ext_id&0x80)); If error happened but vortex->codec isn't NULL, this may cause some problems. Move the judgement order to be clearer and better. Fixes: 79597c8bf64c ("ALSA: ac97: Fix possible NULL dereference in snd_ac97_mixer") Suggested-by: Christophe JAILLET Acked-by: Christophe JAILLET Signed-off-by: Su Hui Link: https://lore.kernel.org/r/20230823025212.1000961-1-suhui@nfschina.com Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_codec.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 80a65b8ad7b9..25f93e56cfc7 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -2069,10 +2069,9 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, .dev_disconnect = snd_ac97_dev_disconnect, }; - if (!rac97) - return -EINVAL; - if (snd_BUG_ON(!bus || !template)) + if (snd_BUG_ON(!bus || !template || !rac97)) return -EINVAL; + *rac97 = NULL; if (snd_BUG_ON(template->num >= 4)) return -EINVAL; if (bus->codec[template->num]) From 5f11dd938fe7657899ca79b2ffc4d708e43f4737 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 24 Aug 2023 09:51:05 +0200 Subject: [PATCH 323/334] ALSA: usb-audio: Attach legacy rawmidi after probing all UMP EPs The legacy rawmidi devices are the shadows of the main UMP devices, hence it's better to initialize them after all UMP Endpoints are parsed. Then, at the moment the legacy rawmidi is created, we already know the static flag or the proper EP name string, and we can fill those information at UMP core side instead of fiddling the attributes at a later point. Fixes: ec362b63c4b5 ("ALSA: usb-audio: Enable the legacy raw MIDI support") Link: https://lore.kernel.org/r/20230824075108.29958-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/ump.c | 2 ++ sound/usb/midi2.c | 15 ++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/sound/core/ump.c b/sound/core/ump.c index fbe2892e72fd..b72b6dc36e0b 100644 --- a/sound/core/ump.c +++ b/sound/core/ump.c @@ -1150,6 +1150,8 @@ int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump, if (output) snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_ump_legacy_output_ops); + snprintf(rmidi->name, sizeof(rmidi->name), "%s (MIDI 1.0)", + ump->info.name); rmidi->info_flags = ump->core.info_flags & ~SNDRV_RAWMIDI_INFO_UMP; rmidi->ops = &snd_ump_legacy_ops; rmidi->private_data = ump; diff --git a/sound/usb/midi2.c b/sound/usb/midi2.c index ee2835741479..a27e244650c8 100644 --- a/sound/usb/midi2.c +++ b/sound/usb/midi2.c @@ -990,7 +990,7 @@ static int parse_midi_2_0(struct snd_usb_midi2_interface *umidi) } } - return attach_legacy_rawmidi(umidi); + return 0; } /* is the given interface for MIDI 2.0? */ @@ -1059,12 +1059,6 @@ static void set_fallback_rawmidi_names(struct snd_usb_midi2_interface *umidi) usb_string(dev, dev->descriptor.iSerialNumber, ump->info.product_id, sizeof(ump->info.product_id)); -#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) - if (ump->legacy_rmidi && !*ump->legacy_rmidi->name) - snprintf(ump->legacy_rmidi->name, - sizeof(ump->legacy_rmidi->name), - "%s (MIDI 1.0)", ump->info.name); -#endif } } @@ -1157,6 +1151,13 @@ int snd_usb_midi_v2_create(struct snd_usb_audio *chip, } set_fallback_rawmidi_names(umidi); + + err = attach_legacy_rawmidi(umidi); + if (err < 0) { + usb_audio_err(chip, "Failed to create legacy rawmidi\n"); + goto error; + } + return 0; error: From 1761f4cc114af531020ea190df6a24dd288a8221 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 24 Aug 2023 09:51:06 +0200 Subject: [PATCH 324/334] ALSA: ump: Fill group names for legacy rawmidi substreams To make it clearer which legacy substream corresponds to which UMP group, fill the subname field of each substream object with the group number and the endpoint name, e.g. "Group 1 (My Device)". Ideally speaking, we should have some better link information to the derived UMP, but it's another feature extension. Fixes: 0b5288f5fe63 ("ALSA: ump: Add legacy raw MIDI support") Link: https://lore.kernel.org/r/20230824075108.29958-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/ump.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/core/ump.c b/sound/core/ump.c index b72b6dc36e0b..d5d72473d999 100644 --- a/sound/core/ump.c +++ b/sound/core/ump.c @@ -1123,6 +1123,16 @@ static void process_legacy_input(struct snd_ump_endpoint *ump, const u32 *src, spin_unlock_irqrestore(&ump->legacy_locks[dir], flags); } +static void fill_substream_names(struct snd_ump_endpoint *ump, + struct snd_rawmidi *rmidi, int dir) +{ + struct snd_rawmidi_substream *s; + + list_for_each_entry(s, &rmidi->streams[dir].substreams, list) + snprintf(s->name, sizeof(s->name), "Group %d (%s)", + s->number + 1, ump->info.name); +} + int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump, char *id, int device) { @@ -1156,6 +1166,11 @@ int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump, rmidi->ops = &snd_ump_legacy_ops; rmidi->private_data = ump; ump->legacy_rmidi = rmidi; + if (input) + fill_substream_names(ump, rmidi, SNDRV_RAWMIDI_STREAM_INPUT); + if (output) + fill_substream_names(ump, rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT); + ump_dbg(ump, "Created a legacy rawmidi #%d (%s)\n", device, id); return 0; } From b2bcbd031d34d1ba1f491b9152474cf9f6d4d51b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 24 Aug 2023 09:51:07 +0200 Subject: [PATCH 325/334] ALSA: ump: Don't create unused substreams for static blocks When the UMP Endpoint is declared as "static", that is, no dynamic reassignment of UMP Groups, it makes little sense to expose always all 16 groups with 16 substreams. Many of those substreams are disabled groups, hence they are useless, but applications don't know it and try to open / access all those substreams unnecessarily. This patch limits the number of UMP legacy rawmidi substreams only to the active groups. The behavior is changed only for the static endpoint (i.e. devices without UMP v1.1 feature implemented or with the static block flag is set). Fixes: 0b5288f5fe63 ("ALSA: ump: Add legacy raw MIDI support") Link: https://lore.kernel.org/r/20230824075108.29958-4-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/ump.h | 1 + sound/core/ump.c | 43 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/include/sound/ump.h b/include/sound/ump.h index 44d2c2fd021d..91238dabe307 100644 --- a/include/sound/ump.h +++ b/include/sound/ump.h @@ -45,6 +45,7 @@ struct snd_ump_endpoint { spinlock_t legacy_locks[2]; struct snd_rawmidi *legacy_rmidi; struct snd_rawmidi_substream *legacy_substreams[2][SNDRV_UMP_MAX_GROUPS]; + unsigned char legacy_mapping[SNDRV_UMP_MAX_GROUPS]; /* for legacy output; need to open the actual substream unlike input */ int legacy_out_opens; diff --git a/sound/core/ump.c b/sound/core/ump.c index d5d72473d999..cd192bec227a 100644 --- a/sound/core/ump.c +++ b/sound/core/ump.c @@ -984,7 +984,7 @@ static int snd_ump_legacy_open(struct snd_rawmidi_substream *substream) { struct snd_ump_endpoint *ump = substream->rmidi->private_data; int dir = substream->stream; - int group = substream->number; + int group = ump->legacy_mapping[substream->number]; int err; mutex_lock(&ump->open_mutex); @@ -1016,7 +1016,7 @@ static int snd_ump_legacy_close(struct snd_rawmidi_substream *substream) { struct snd_ump_endpoint *ump = substream->rmidi->private_data; int dir = substream->stream; - int group = substream->number; + int group = ump->legacy_mapping[substream->number]; mutex_lock(&ump->open_mutex); spin_lock_irq(&ump->legacy_locks[dir]); @@ -1123,6 +1123,34 @@ static void process_legacy_input(struct snd_ump_endpoint *ump, const u32 *src, spin_unlock_irqrestore(&ump->legacy_locks[dir], flags); } +/* Fill ump->legacy_mapping[] for groups to be used for legacy rawmidi */ +static int fill_legacy_mapping(struct snd_ump_endpoint *ump) +{ + struct snd_ump_block *fb; + unsigned int group_maps = 0; + int i, num; + + if (ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS) { + list_for_each_entry(fb, &ump->block_list, list) { + for (i = 0; i < fb->info.num_groups; i++) + group_maps |= 1U << (fb->info.first_group + i); + } + if (!group_maps) + ump_info(ump, "No UMP Group is found in FB\n"); + } + + /* use all groups for non-static case */ + if (!group_maps) + group_maps = (1U << SNDRV_UMP_MAX_GROUPS) - 1; + + num = 0; + for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) + if (group_maps & (1U << i)) + ump->legacy_mapping[num++] = i; + + return num; +} + static void fill_substream_names(struct snd_ump_endpoint *ump, struct snd_rawmidi *rmidi, int dir) { @@ -1130,7 +1158,7 @@ static void fill_substream_names(struct snd_ump_endpoint *ump, list_for_each_entry(s, &rmidi->streams[dir].substreams, list) snprintf(s->name, sizeof(s->name), "Group %d (%s)", - s->number + 1, ump->info.name); + ump->legacy_mapping[s->number] + 1, ump->info.name); } int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump, @@ -1138,16 +1166,19 @@ int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump, { struct snd_rawmidi *rmidi; bool input, output; - int err; + int err, num; - ump->out_cvts = kcalloc(16, sizeof(*ump->out_cvts), GFP_KERNEL); + ump->out_cvts = kcalloc(SNDRV_UMP_MAX_GROUPS, + sizeof(*ump->out_cvts), GFP_KERNEL); if (!ump->out_cvts) return -ENOMEM; + num = fill_legacy_mapping(ump); + input = ump->core.info_flags & SNDRV_RAWMIDI_INFO_INPUT; output = ump->core.info_flags & SNDRV_RAWMIDI_INFO_OUTPUT; err = snd_rawmidi_new(ump->core.card, id, device, - output ? 16 : 0, input ? 16 : 0, + output ? num : 0, input ? num : 0, &rmidi); if (err < 0) { kfree(ump->out_cvts); From e240cff9e6e9bada3ced7e088de1d6f8088c2c3a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 24 Aug 2023 09:51:08 +0200 Subject: [PATCH 326/334] ALSA: documentation: Add description for USB MIDI 2.0 gadget driver The USB MIDI 2.0 gadget driver is now supported for 6.6 kernel, and here we show a brief instruction how to enable and use it. Link: https://lore.kernel.org/r/20230824075108.29958-5-tiwai@suse.de Signed-off-by: Takashi Iwai --- Documentation/sound/designs/midi-2.0.rst | 188 +++++++++++++++++++++++ 1 file changed, 188 insertions(+) diff --git a/Documentation/sound/designs/midi-2.0.rst b/Documentation/sound/designs/midi-2.0.rst index 27d0d3dea1b0..3b08b98354f8 100644 --- a/Documentation/sound/designs/midi-2.0.rst +++ b/Documentation/sound/designs/midi-2.0.rst @@ -376,3 +376,191 @@ Sequencer API Extensions name and attributes accordingly, and notifies the changes via the announcement to the ALSA sequencer system port, similarly like the normal port change notification. + + +MIDI2 USB Gadget Function Driver +================================ + +The latest kernel contains the support for USB MIDI 2.0 gadget +function driver, which can be used for prototyping and debugging MIDI +2.0 features. + +`CONFIG_USB_GADGET`, `CONFIG_USB_CONFIGFS` and +`CONFIG_USB_CONFIGFS_F_MIDI2` need to be enabled for the MIDI2 gadget +driver. + +In addition, for using a gadget driver, you need a working UDC driver. +In the example below, we use `dummy_hcd` driver (enabled via +`CONFIG_USB_DUMMY_HCD`) that is available on PC and VM for debugging +purpose. There are other UDC drivers depending on the platform, and +those can be used for a real device, instead, too. + +At first, on a system to run the gadget, load `libcomposite` module:: + + % modprobe libcomposite + +and you'll have `usb_gadget` subdirectory under configfs space +(typically `/sys/kernel/config` on modern OS). Then create a gadget +instance and add configurations there, for example:: + + % cd /sys/kernel/config + % mkdir usb_gadget/g1 + + % cd usb_gadget/g1 + % mkdir configs/c.1 + % mkdir functions/midi2.usb0 + + % echo 0x0004 > idProduct + % echo 0x17b3 > idVendor + % mkdir strings/0x409 + % echo "ACME Enterprises" > strings/0x409/manufacturer + % echo "ACMESynth" > strings/0x409/product + % echo "ABCD12345" > strings/0x409/serialnumber + + % mkdir configs/c.1/strings/0x409 + % echo "Monosynth" > configs/c.1/strings/0x409/configuration + % echo 120 > configs/c.1/MaxPower + +At this point, there must be a subdirectory `ep.0`, and that is the +configuration for a UMP Endpoint. You can fill the Endpoint +information like:: + + % echo "ACMESynth" > functions/midi2.usb0/iface_name + % echo "ACMESynth" > functions/midi2.usb0/ep.0/ep_name + % echo "ABCD12345" > functions/midi2.usb0/ep.0/product_id + % echo 0x0123 > functions/midi2.usb0/ep.0/family + % echo 0x4567 > functions/midi2.usb0/ep.0/model + % echo 0x123456 > functions/midi2.usb0/ep.0/manufacturer + % echo 0x12345678 > functions/midi2.usb0/ep.0/sw_revision + +The default MIDI protocol can be set either 1 or 2:: + + % echo 2 > functions/midi2.usb0/ep.0/protocol + +And, you can find a subdirectory `block.0` under this Endpoint +subdirectory. This defines the Function Block information:: + + % echo "Monosynth" > functions/midi2.usb0/ep.0/block.0/name + % echo 0 > functions/midi2.usb0/ep.0/block.0/first_group + % echo 1 > functions/midi2.usb0/ep.0/block.0/num_groups + +Finally, link the configuration and enable it:: + + % ln -s functions/midi2.usb0 configs/c.1 + % echo dummy_udc.0 > UDC + +where `dummy_udc.0` is an example case and it differs depending on the +system. You can find the UDC instances in `/sys/class/udc` and pass +the found name instead:: + + % ls /sys/class/udc + dummy_udc.0 + +Now, the MIDI 2.0 gadget device is enabled, and the gadget host +creates a new sound card instance containing a UMP rawmidi device by +`f_midi2` driver:: + + % cat /proc/asound/cards + .... + 1 [Gadget ]: f_midi2 - MIDI 2.0 Gadget + MIDI 2.0 Gadget + +And on the connected host, a similar card should appear, too, but with +the card and device names given in the configfs above:: + + % cat /proc/asound/cards + .... + 2 [ACMESynth ]: USB-Audio - ACMESynth + ACME Enterprises ACMESynth at usb-dummy_hcd.0-1, high speed + +You can play a MIDI file on the gadget side:: + + % aplaymidi -p 20:1 to_host.mid + +and this will appear as an input from a MIDI device on the connected +host:: + + % aseqdump -p 20:0 -u 2 + +Vice versa, a playback on the connected host will work as an input on +the gadget, too. + +Each Function Block may have different direction and UI-hint, +specified via `direction` and `ui_hint` attributes. +Passing `1` is for input-only, `2` for out-only and `3` for +bidirectional (the default value). For example:: + + % echo 2 > functions/midi2.usb0/ep.0/block.0/direction + % echo 2 > functions/midi2.usb0/ep.0/block.0/ui_hint + +When you need more than one Function Blocks, you can create +subdirectories `block.1`, `block.2`, etc dynamically, and configure +them in the configuration procedure above before linking. +For example, to create a second Function Block for a keyboard:: + + % mkdir functions/midi2.usb0/ep.0/block.1 + % echo "Keyboard" > functions/midi2.usb0/ep.0/block.1/name + % echo 1 > functions/midi2.usb0/ep.0/block.1/first_group + % echo 1 > functions/midi2.usb0/ep.0/block.1/num_groups + % echo 1 > functions/midi2.usb0/ep.0/block.1/direction + % echo 1 > functions/midi2.usb0/ep.0/block.1/ui_hint + +The `block.*` subdirectories can be removed dynamically, too (except +for `block.0` which is persistent). + +For assigning a Function Block for MIDI 1.0 I/O, set up in `is_midi1` +attribute. 1 is for MIDI 1.0, and 2 is for MIDI 1.0 with low speed +connection:: + + % echo 2 > functions/midi2.usb0/ep.0/block.1/is_midi1 + +For disabling the processing of UMP Stream messages in the gadget +driver, pass `0` to `process_ump attribute in the top-level config:: + + % echo 0 > functions/midi2.usb0/process_ump + +The MIDI 1.0 interface at altset 0 is supported by the gadget driver, +too. When MIDI 1.0 interface is selected by the connected host, the +UMP I/O on the gadget is translated from/to USB MIDI 1.0 packets +accordingly while the gadget driver keeps communicating with the +user-space over UMP rawmidi. + +MIDI 1.0 ports are set up from the config in each Function Block. +For example:: + + % echo 0 > functions/midi2.usb0/ep.0/block.0/midi1_first_group + % echo 1 > functions/midi2.usb0/ep.0/block.0/midi1_num_groups + +The configuration above will enable the Group 1 (the index 0) for MIDI +1.0 interface. Note that those groups must be in the groups defined +for the Function Block itself. + +The gadget driver supports more than one UMP Endpoints, too. +Similarly like the Function Blocks, you can create a new subdirectory +`ep.1` (but under the card top-level config) to enable a new Endpoint:: + + % mkdir functions/midi2.usb0/ep.1 + +and create a new Function Block there. For example, to create 4 +Groups for the Function Block of this new Endpoint:: + + % mkdir functions/midi2.usb0/ep.1/block.0 + % echo 4 > functions/midi2.usb0/ep.1/block.0/num_groups + +Now, you'll have 4 rawmidi devices in total: the first two are UMP +rawmidi devices for Endpoint 0 and Endpoint 1, and other two for the +legacy MIDI 1.0 rawmidi devices corresponding to both EP 0 and EP 1. + +The current altsetting on the gadget can be informed via a control +element "Operation Mode" with `RAWMIDI` iface. e.g. you can read it +via `amixer` program running on the gadget host like:: + + % amixer -c1 cget iface=RAWMIDI,name='Operation Mode' + ; type=INTEGER,access=r--v----,values=1,min=0,max=2,step=0 + : values=2 + +The value (shown in the second returned line with `: values=`) +indicates 1 for MIDI 1.0 (altset 0), 2 for MIDI 2.0 (altset 1) and 0 +for unset. + +As of now, the configurations can't be changed after binding. From ed81cb9e05170646650359d729fb7e7afa4cb2ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 24 Aug 2023 22:02:19 +0200 Subject: [PATCH 327/334] ALSA: hda/tas2781: Switch back to use struct i2c_driver's .probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit struct i2c_driver::probe_new is about to go away. Switch the driver to use the probe callback with the same prototype. Signed-off-by: Uwe Kleine-König Fixes: 5be27f1e3ec9 ("ALSA: hda/tas2781: Add tas2781 HDA driver") Link: https://lore.kernel.org/r/20230824200219.9569-1-u.kleine-koenig@pengutronix.de 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 aa9ce3837336..37114fd61a38 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -845,7 +845,7 @@ static struct i2c_driver tas2781_hda_i2c_driver = { .pm = &tas2781_hda_pm_ops, }, .id_table = tas2781_hda_i2c_id, - .probe_new = tas2781_hda_i2c_probe, + .probe = tas2781_hda_i2c_probe, .remove = tas2781_hda_i2c_remove, }; module_i2c_driver(tas2781_hda_i2c_driver); From c99c26b16c1544534ebd6a5f27a034f3e44d2597 Mon Sep 17 00:00:00 2001 From: Fabian Vogt Date: Thu, 24 Aug 2023 20:39:48 +0200 Subject: [PATCH 328/334] ALSA: hda/realtek: Add quirk for mute LEDs on HP ENVY x360 15-eu0xxx The LED for the mic mute button is controlled by GPIO2. The mute button LED is slightly more complex, it's controlled by two bits in coeff 0x0b. Signed-off-by: Fabian Vogt Link: https://lore.kernel.org/r/2693091.mvXUDI8C0e@fabians-envy Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index afc63d367fd5..a07df6f92960 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7318,6 +7318,7 @@ enum { ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI, ALC287_FIXUP_TAS2781_I2C, ALC245_FIXUP_HP_MUTE_LED_COEFBIT, + ALC245_FIXUP_HP_X360_MUTE_LEDS, }; /* A special fixup for Lenovo C940 and Yoga Duet 7; @@ -9406,6 +9407,12 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc245_fixup_hp_mute_led_coefbit, }, + [ALC245_FIXUP_HP_X360_MUTE_LEDS] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc245_fixup_hp_mute_led_coefbit, + .chained = true, + .chain_id = ALC245_FIXUP_HP_GPIO_LED + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -9648,6 +9655,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8870, "HP ZBook Fury 15.6 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x8873, "HP ZBook Studio 15.6 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x887a, "HP Laptop 15s-eq2xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), + SND_PCI_QUIRK(0x103c, 0x888a, "HP ENVY x360 Convertible 15-eu0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS), SND_PCI_QUIRK(0x103c, 0x888d, "HP ZBook Power 15.6 inch G8 Mobile Workstation PC", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8895, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED), SND_PCI_QUIRK(0x103c, 0x8896, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_MUTE_LED), From a3ca016af1c3318bf8640aae3afea57179c6a130 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 25 Aug 2023 11:23:51 +0200 Subject: [PATCH 329/334] ALSA: doc: Fix missing backquote in midi-2.0.rst Fix the missing missing backquote that caused a sphinx warning: Documentation/sound/designs/midi-2.0.rst:517: WARNING: Inline interpreted text or phrase reference start-string without end-string. Fixes: e240cff9e6e9 ("ALSA: documentation: Add description for USB MIDI 2.0 gadget driver") Reported-by: Stephen Rothwell Closes: https://lore.kernel.org/r/20230825152957.18c54ae2@canb.auug.org.au Link: https://lore.kernel.org/r/20230825092351.11780-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- Documentation/sound/designs/midi-2.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/sound/designs/midi-2.0.rst b/Documentation/sound/designs/midi-2.0.rst index 3b08b98354f8..45987f256b97 100644 --- a/Documentation/sound/designs/midi-2.0.rst +++ b/Documentation/sound/designs/midi-2.0.rst @@ -515,7 +515,7 @@ connection:: % echo 2 > functions/midi2.usb0/ep.0/block.1/is_midi1 For disabling the processing of UMP Stream messages in the gadget -driver, pass `0` to `process_ump attribute in the top-level config:: +driver, pass `0` to `process_ump` attribute in the top-level config:: % echo 0 > functions/midi2.usb0/process_ump From 61698d3fbdcd36b65ab524183c73de8bc0693a1f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 25 Aug 2023 11:28:19 +0200 Subject: [PATCH 330/334] ALSA: hda: Add missing dependency on CONFIG_EFI for Cirrus/TI sub-codecs The CS35L41 and TAS2781 sub-codecs depend on CONFIG_EFI, as they have the code accessing efi variable directly. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202308250621.1lwt7PtZ-lkp@intel.com/ Fixes: 5be27f1e3ec9 ("ALSA: hda/tas2781: Add tas2781 HDA driver") Link: https://lore.kernel.org/r/20230825092819.12340-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 91db5f8f00b6..0d7502d6e060 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -104,6 +104,7 @@ 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 @@ -119,6 +120,7 @@ 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 @@ -165,6 +167,7 @@ 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_SOC_TAS2781_COMLIB select SND_SOC_TAS2781_FMWLIB From 4aa69d64e43edb51a4ecff7d301e9f881eb2d3f5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 26 Aug 2023 09:21:51 +0200 Subject: [PATCH 331/334] ALSA: ump: Fix -Wformat-truncation warnings Filling the rawmidi name and substream name can be truncated, and this leads to spurious compiler warnings due to -Wformat-truncation. Although the truncation is the expected behavior, it'd be better to truncate the string within "(...)" This patch puts the precision specifies to each %s for fitting the words within the size-limited strings. Fixes: 5f11dd938fe7 ("ALSA: usb-audio: Attach legacy rawmidi after probing all UMP EPs") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202308251844.1FuQYsql-lkp@intel.com/ Link: https://lore.kernel.org/r/20230826072151.23408-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/ump.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/core/ump.c b/sound/core/ump.c index cd192bec227a..3bef1944e955 100644 --- a/sound/core/ump.c +++ b/sound/core/ump.c @@ -1157,7 +1157,7 @@ static void fill_substream_names(struct snd_ump_endpoint *ump, struct snd_rawmidi_substream *s; list_for_each_entry(s, &rmidi->streams[dir].substreams, list) - snprintf(s->name, sizeof(s->name), "Group %d (%s)", + snprintf(s->name, sizeof(s->name), "Group %d (%.16s)", ump->legacy_mapping[s->number] + 1, ump->info.name); } @@ -1191,7 +1191,7 @@ int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump, if (output) snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_ump_legacy_output_ops); - snprintf(rmidi->name, sizeof(rmidi->name), "%s (MIDI 1.0)", + snprintf(rmidi->name, sizeof(rmidi->name), "%.68s (MIDI 1.0)", ump->info.name); rmidi->info_flags = ump->core.info_flags & ~SNDRV_RAWMIDI_INFO_UMP; rmidi->ops = &snd_ump_legacy_ops; From d945ef3627e4cc9b7b1b548bcc7541fffc43eb10 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sat, 26 Aug 2023 00:21:55 +0200 Subject: [PATCH 332/334] ALSA: emu10k1: de-duplicate audigy-mixer.rst vs. sb-live-mixer.rst Let the MANUALS/PATENTS section of the former simply refer to the latter - there is no point in duplicating this information with little value to end users. Signed-off-by: Oswald Buddenhagen Link: https://lore.kernel.org/r/20230825222157.170978-1-oswald.buddenhagen@gmx.de Signed-off-by: Takashi Iwai --- Documentation/sound/cards/audigy-mixer.rst | 67 +--------------------- 1 file changed, 1 insertion(+), 66 deletions(-) diff --git a/Documentation/sound/cards/audigy-mixer.rst b/Documentation/sound/cards/audigy-mixer.rst index ea66b50a2b03..51cc7ac034ce 100644 --- a/Documentation/sound/cards/audigy-mixer.rst +++ b/Documentation/sound/cards/audigy-mixer.rst @@ -303,69 +303,4 @@ The channel mapping is following: MANUALS/PATENTS =============== -ftp://opensource.creative.com/pub/doc -------------------------------------- - -Note that the site is defunct, but the documents are available -from various other locations. - -LM4545.pdf - AC97 Codec - -m2049.pdf - The EMU10K1 Digital Audio Processor - -hog63.ps - FX8010 - A DSP Chip Architecture for Audio Effects - - -WIPO Patents ------------- - -WO 9901813 (A1) - Audio Effects Processor with multiple asynchronous streams - (Jan. 14, 1999) - -WO 9901814 (A1) - Processor with Instruction Set for Audio Effects (Jan. 14, 1999) - -WO 9901953 (A1) - Audio Effects Processor having Decoupled Instruction - Execution and Audio Data Sequencing (Jan. 14, 1999) - - -US Patents (https://www.uspto.gov/) ------------------------------------ - -US 5925841 - Digital Sampling Instrument employing cache memory (Jul. 20, 1999) - -US 5928342 - Audio Effects Processor integrated on a single chip - with a multiport memory onto which multiple asynchronous - digital sound samples can be concurrently loaded - (Jul. 27, 1999) - -US 5930158 - Processor with Instruction Set for Audio Effects (Jul. 27, 1999) - -US 6032235 - Memory initialization circuit (Tram) (Feb. 29, 2000) - -US 6138207 - Interpolation looping of audio samples in cache connected to - system bus with prioritization and modification of bus transfers - in accordance with loop ends and minimum block sizes - (Oct. 24, 2000) - -US 6151670 - Method for conserving memory storage using a - pool of short term memory registers - (Nov. 21, 2000) - -US 6195715 - Interrupt control for multiple programs communicating with - a common interrupt by associating programs to GP registers, - defining interrupt register, polling GP registers, and invoking - callback routine associated with defined interrupt register - (Feb. 27, 2001) +See sb-live-mixer.rst. From 13890a6a87475f2437f90ac65d32d665bb49b19d Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sat, 26 Aug 2023 00:21:56 +0200 Subject: [PATCH 333/334] ALSA: emu10k1: more documentation updates - Clarify the data flows. For SB Live! I fixed only the most obvious point ("from" vs. "for"). - Mention 7.1 side channels on Audigy. - Be unspecific about the output DACs on Audigy, as lots of variants actually exist (see emu_chip_details table). Signed-off-by: Oswald Buddenhagen Link: https://lore.kernel.org/r/20230825222157.170978-2-oswald.buddenhagen@gmx.de Signed-off-by: Takashi Iwai --- Documentation/sound/cards/audigy-mixer.rst | 130 ++++++++++---------- Documentation/sound/cards/sb-live-mixer.rst | 24 ++-- 2 files changed, 77 insertions(+), 77 deletions(-) diff --git a/Documentation/sound/cards/audigy-mixer.rst b/Documentation/sound/cards/audigy-mixer.rst index 51cc7ac034ce..7ebaacb6df3d 100644 --- a/Documentation/sound/cards/audigy-mixer.rst +++ b/Documentation/sound/cards/audigy-mixer.rst @@ -46,157 +46,158 @@ FX-bus name='PCM Front Playback Volume',index=0 ---------------------------------------- -This control is used to attenuate samples for left and right front PCM FX-bus +This control is used to attenuate samples from left and right front PCM FX-bus accumulators. ALSA uses accumulators 8 and 9 for left and right front PCM -samples for 5.1 playback. The result samples are forwarded to the front DAC PCM -slots of the Philips DAC. +samples for 5.1 playback. The result samples are forwarded to the front speakers. name='PCM Surround Playback Volume',index=0 ------------------------------------------- -This control is used to attenuate samples for left and right surround PCM FX-bus +This control is used to attenuate samples from left and right surround PCM FX-bus accumulators. ALSA uses accumulators 2 and 3 for left and right surround PCM -samples for 5.1 playback. The result samples are forwarded to the surround DAC PCM -slots of the Philips DAC. +samples for 5.1 playback. The result samples are forwarded to the surround (rear) +speakers. + +name='PCM Side Playback Volume',index=0 +--------------------------------------- +This control is used to attenuate samples from left and right side PCM FX-bus +accumulators. ALSA uses accumulators 14 and 15 for left and right side PCM +samples for 7.1 playback. The result samples are forwarded to the side speakers. name='PCM Center Playback Volume',index=0 ----------------------------------------- -This control is used to attenuate samples for center PCM FX-bus accumulator. -ALSA uses accumulator 6 for center PCM sample for 5.1 playback. The result sample -is forwarded to the center DAC PCM slot of the Philips DAC. +This control is used to attenuate samples from center PCM FX-bus accumulator. +ALSA uses accumulator 6 for center PCM samples for 5.1 playback. The result +samples are forwarded to the center speaker. name='PCM LFE Playback Volume',index=0 -------------------------------------- This control is used to attenuate sample for LFE PCM FX-bus accumulator. -ALSA uses accumulator 7 for LFE PCM sample for 5.1 playback. The result sample -is forwarded to the LFE DAC PCM slot of the Philips DAC. +ALSA uses accumulator 7 for LFE PCM samples for 5.1 playback. The result +samples are forwarded to the subwoofer. name='PCM Playback Volume',index=0 ---------------------------------- -This control is used to attenuate samples for left and right PCM FX-bus +This control is used to attenuate samples from left and right PCM FX-bus accumulators. ALSA uses accumulators 0 and 1 for left and right PCM samples for -stereo playback. The result samples are forwarded to the front DAC PCM slots -of the Philips DAC. +stereo playback. The result samples are forwarded to the front speakers. name='PCM Capture Volume',index=0 --------------------------------- -This control is used to attenuate samples for left and right PCM FX-bus -accumulator. ALSA uses accumulators 0 and 1 for left and right PCM. -The result is forwarded to the ADC capture FIFO (thus to the standard capture -PCM device). +This control is used to attenuate samples from left and right PCM FX-bus +accumulators. ALSA uses accumulators 0 and 1 for left and right PCM samples for +stereo playback. The result is forwarded to the standard capture PCM device. name='Music Playback Volume',index=0 ------------------------------------ -This control is used to attenuate samples for left and right MIDI FX-bus +This control is used to attenuate samples from left and right MIDI FX-bus accumulators. ALSA uses accumulators 4 and 5 for left and right MIDI samples. -The result samples are forwarded to the front DAC PCM slots of the AC97 codec. +The result samples are forwarded to the virtual stereo mixer. name='Music Capture Volume',index=0 ----------------------------------- -These controls are used to attenuate samples for left and right MIDI FX-bus -accumulator. ALSA uses accumulators 4 and 5 for left and right PCM. -The result is forwarded to the ADC capture FIFO (thus to the standard capture -PCM device). +These controls are used to attenuate samples from left and right MIDI FX-bus +accumulator. ALSA uses accumulators 4 and 5 for left and right MIDI samples. +The result is forwarded to the standard capture PCM device. name='Mic Playback Volume',index=0 ---------------------------------- -This control is used to attenuate samples for left and right Mic input. -For Mic input is used AC97 codec. The result samples are forwarded to -the front DAC PCM slots of the Philips DAC. Samples are forwarded to Mic -capture FIFO (device 1 - 16bit/8KHz mono) too without volume control. +This control is used to attenuate samples from left and right Mic input of +the AC97 codec. The result samples are forwarded to the virtual stereo mixer. name='Mic Capture Volume',index=0 --------------------------------- -This control is used to attenuate samples for left and right Mic input. -The result is forwarded to the ADC capture FIFO (thus to the standard capture -PCM device). +This control is used to attenuate samples from left and right Mic input of +the AC97 codec. The result is forwarded to the standard capture PCM device. + +The original samples are also forwarded to the Mic capture PCM device (device 1; +16bit/8KHz mono) without volume control. name='Audigy CD Playback Volume',index=0 ---------------------------------------- This control is used to attenuate samples from left and right IEC958 TTL digital inputs (usually used by a CDROM drive). The result samples are -forwarded to the front DAC PCM slots of the Philips DAC. +forwarded to the virtual stereo mixer. name='Audigy CD Capture Volume',index=0 --------------------------------------- This control is used to attenuate samples from left and right IEC958 TTL -digital inputs (usually used by a CDROM drive). The result samples are -forwarded to the ADC capture FIFO (thus to the standard capture PCM device). +digital inputs (usually used by a CDROM drive). The result is forwarded +to the standard capture PCM device. name='IEC958 Optical Playback Volume',index=0 --------------------------------------------- This control is used to attenuate samples from left and right IEC958 optical -digital input. The result samples are forwarded to the front DAC PCM slots -of the Philips DAC. +digital input. The result samples are forwarded to the virtual stereo mixer. name='IEC958 Optical Capture Volume',index=0 -------------------------------------------- This control is used to attenuate samples from left and right IEC958 optical -digital inputs. The result samples are forwarded to the ADC capture FIFO -(thus to the standard capture PCM device). +digital inputs. The result is forwarded to the standard capture PCM device. name='Line2 Playback Volume',index=0 ------------------------------------ This control is used to attenuate samples from left and right I2S ADC -inputs (on the AudigyDrive). The result samples are forwarded to the front -DAC PCM slots of the Philips DAC. +inputs (on the AudigyDrive). The result samples are forwarded to the virtual +stereo mixer. name='Line2 Capture Volume',index=1 ----------------------------------- This control is used to attenuate samples from left and right I2S ADC -inputs (on the AudigyDrive). The result samples are forwarded to the ADC -capture FIFO (thus to the standard capture PCM device). +inputs (on the AudigyDrive). The result is forwarded to the standard capture +PCM device. name='Analog Mix Playback Volume',index=0 ----------------------------------------- This control is used to attenuate samples from left and right I2S ADC -inputs from Philips ADC. The result samples are forwarded to the front -DAC PCM slots of the Philips DAC. This contains mix from analog sources -like CD, Line In, Aux, .... +inputs from Philips ADC. The result samples are forwarded to the virtual +stereo mixer. This contains mix from analog sources like CD, Line In, Aux, .... name='Analog Mix Capture Volume',index=1 ---------------------------------------- This control is used to attenuate samples from left and right I2S ADC -inputs Philips ADC. The result samples are forwarded to the ADC -capture FIFO (thus to the standard capture PCM device). +inputs Philips ADC. The result is forwarded to the standard capture PCM device. name='Aux2 Playback Volume',index=0 ----------------------------------- This control is used to attenuate samples from left and right I2S ADC -inputs (on the AudigyDrive). The result samples are forwarded to the front -DAC PCM slots of the Philips DAC. +inputs (on the AudigyDrive). The result samples are forwarded to the virtual +stereo mixer. name='Aux2 Capture Volume',index=1 ---------------------------------- This control is used to attenuate samples from left and right I2S ADC -inputs (on the AudigyDrive). The result samples are forwarded to the ADC -capture FIFO (thus to the standard capture PCM device). +inputs (on the AudigyDrive). The result is forwarded to the standard capture +PCM device. name='Front Playback Volume',index=0 ------------------------------------ -All stereo signals are mixed together and mirrored to surround, center and LFE. -This control is used to attenuate samples for left and right front speakers of -this mix. +This control is used to attenuate samples from the virtual stereo mixer. +The result samples are forwarded to the front speakers. name='Surround Playback Volume',index=0 --------------------------------------- -All stereo signals are mixed together and mirrored to surround, center and LFE. -This control is used to attenuate samples for left and right surround speakers of -this mix. +This control is used to attenuate samples from the virtual stereo mixer. +The result samples are forwarded to the surround (rear) speakers. + +name='Side Playback Volume',index=0 +----------------------------------- +This control is used to attenuate samples from the virtual stereo mixer. +The result samples are forwarded to the side speakers. name='Center Playback Volume',index=0 ------------------------------------- -All stereo signals are mixed together and mirrored to surround, center and LFE. -This control is used to attenuate sample for center speaker of this mix. +This control is used to attenuate samples from the virtual stereo mixer. +The result samples are forwarded to the center speaker. name='LFE Playback Volume',index=0 ---------------------------------- -All stereo signals are mixed together and mirrored to surround, center and LFE. -This control is used to attenuate sample for LFE speaker of this mix. +This control is used to attenuate samples from the virtual stereo mixer. +The result samples are forwarded to the subwoofer. name='Tone Control - Switch',index=0 ------------------------------------ -This control turns the tone control on or off. The samples for front, rear -and center / LFE outputs are affected. +This control turns the tone control on or off. The samples forwarded to +the speaker outputs are affected. name='Tone Control - Bass',index=0 ---------------------------------- @@ -212,8 +213,7 @@ The closest value to pure signal is 20. name='Master Playback Volume',index=0 ------------------------------------- -This control is used to attenuate samples for front, surround, center and -LFE outputs. +This control is used to attenuate samples forwarded to the speaker outputs. name='IEC958 Optical Raw Playback Switch',index=0 ------------------------------------------------- diff --git a/Documentation/sound/cards/sb-live-mixer.rst b/Documentation/sound/cards/sb-live-mixer.rst index 4dd9bfe01bd8..27667f58aae1 100644 --- a/Documentation/sound/cards/sb-live-mixer.rst +++ b/Documentation/sound/cards/sb-live-mixer.rst @@ -61,61 +61,61 @@ FX-bus ``name='Wave Playback Volume',index=0`` --------------------------------------- -This control is used to attenuate samples for left and right PCM FX-bus +This control is used to attenuate samples from left and right PCM FX-bus accumulators. ALSA uses accumulators 0 and 1 for left and right PCM samples. The result samples are forwarded to the front DAC PCM slots of the AC97 codec. ``name='Wave Surround Playback Volume',index=0`` ------------------------------------------------ -This control is used to attenuate samples for left and right PCM FX-bus +This control is used to attenuate samples from left and right PCM FX-bus accumulators. ALSA uses accumulators 0 and 1 for left and right PCM samples. The result samples are forwarded to the rear I2S DACs. These DACs operates separately (they are not inside the AC97 codec). ``name='Wave Center Playback Volume',index=0`` ---------------------------------------------- -This control is used to attenuate samples for left and right PCM FX-bus +This control is used to attenuate samples from left and right PCM FX-bus accumulators. ALSA uses accumulators 0 and 1 for left and right PCM samples. The result is mixed to mono signal (single channel) and forwarded to the ??rear?? right DAC PCM slot of the AC97 codec. ``name='Wave LFE Playback Volume',index=0`` ------------------------------------------- -This control is used to attenuate samples for left and right PCM FX-bus +This control is used to attenuate samples from left and right PCM FX-bus accumulators. ALSA uses accumulators 0 and 1 for left and right PCM. The result is mixed to mono signal (single channel) and forwarded to the ??rear?? left DAC PCM slot of the AC97 codec. ``name='Wave Capture Volume',index=0``, ``name='Wave Capture Switch',index=0`` ------------------------------------------------------------------------------ -These controls are used to attenuate samples for left and right PCM FX-bus +These controls are used to attenuate samples from left and right PCM FX-bus accumulator. ALSA uses accumulators 0 and 1 for left and right PCM. The result is forwarded to the ADC capture FIFO (thus to the standard capture PCM device). ``name='Synth Playback Volume',index=0`` ---------------------------------------- -This control is used to attenuate samples for left and right MIDI FX-bus +This control is used to attenuate samples from left and right MIDI FX-bus accumulators. ALSA uses accumulators 4 and 5 for left and right MIDI samples. The result samples are forwarded to the front DAC PCM slots of the AC97 codec. ``name='Synth Capture Volume',index=0``, ``name='Synth Capture Switch',index=0`` -------------------------------------------------------------------------------- -These controls are used to attenuate samples for left and right MIDI FX-bus -accumulator. ALSA uses accumulators 4 and 5 for left and right PCM. +These controls are used to attenuate samples from left and right MIDI FX-bus +accumulator. ALSA uses accumulators 4 and 5 for left and right MIDI samples. The result is forwarded to the ADC capture FIFO (thus to the standard capture PCM device). ``name='Surround Playback Volume',index=0`` ------------------------------------------- -This control is used to attenuate samples for left and right rear PCM FX-bus +This control is used to attenuate samples from left and right rear PCM FX-bus accumulators. ALSA uses accumulators 2 and 3 for left and right rear PCM samples. The result samples are forwarded to the rear I2S DACs. These DACs operate separately (they are not inside the AC97 codec). ``name='Surround Capture Volume',index=0``, ``name='Surround Capture Switch',index=0`` -------------------------------------------------------------------------------------- -These controls are used to attenuate samples for left and right rear PCM FX-bus +These controls are used to attenuate samples from left and right rear PCM FX-bus accumulators. ALSA uses accumulators 2 and 3 for left and right rear PCM samples. The result is forwarded to the ADC capture FIFO (thus to the standard capture PCM device). @@ -134,7 +134,7 @@ to the ??rear?? left DAC PCM slot of the AC97 codec. ``name='AC97 Playback Volume',index=0`` --------------------------------------- -This control is used to attenuate samples for left and right front ADC PCM slots +This control is used to attenuate samples from left and right front ADC PCM slots of the AC97 codec. The result samples are forwarded to the front DAC PCM slots of the AC97 codec. @@ -145,7 +145,7 @@ slots of the AC97 codec. ``name='AC97 Capture Volume',index=0`` -------------------------------------- -This control is used to attenuate samples for left and right front ADC PCM slots +This control is used to attenuate samples from left and right front ADC PCM slots of the AC97 codec. The result is forwarded to the ADC capture FIFO (thus to the standard capture PCM device). From 0982e519df6a3fa2dd6858217547460238e47e70 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sat, 26 Aug 2023 00:21:57 +0200 Subject: [PATCH 334/334] ALSA: emu10k1: add separate documentation for E-MU cards They are sufficiently different from Sound Blasters. Signed-off-by: Oswald Buddenhagen Link: https://lore.kernel.org/r/20230825222157.170978-3-oswald.buddenhagen@gmx.de Signed-off-by: Takashi Iwai --- Documentation/sound/cards/emu-mixer.rst | 226 ++++++++++++++++++++++++ Documentation/sound/cards/index.rst | 1 + 2 files changed, 227 insertions(+) create mode 100644 Documentation/sound/cards/emu-mixer.rst diff --git a/Documentation/sound/cards/emu-mixer.rst b/Documentation/sound/cards/emu-mixer.rst new file mode 100644 index 000000000000..d87a6338d3d8 --- /dev/null +++ b/Documentation/sound/cards/emu-mixer.rst @@ -0,0 +1,226 @@ +================================================== +E-MU Digital Audio System mixer / default DSP code +================================================== + +This document covers the E-MU 0404/1010/1212/1616/1820 PCI/PCI-e/CardBus +cards. + +These cards use regular EMU10K2 (SoundBlaster Audigy) chips, but with an +alternative front-end geared towards semi-professional studio recording. + +This document is based on audigy-mixer.rst. + + +Hardware compatibility +====================== + +The EMU10K2 chips have a very short capture FIFO, which makes recording +unreliable if the card's PCI bus requests are not handled with the +appropriate priority. +This is the case on more modern motherboards, where the PCI bus is only a +secondary peripheral, rather than the actual arbiter of device access. +In particular, I got recording glitches during simultaneous playback on an +Intel DP55 board (memory controller in the CPU), but had success with an +Intel DP45 board (memory controller in the north bridge). + +The PCI Express variants of these cards (which have a PCI bridge on board, +but are otherwise identical) may be less problematic. + + +Driver capabilities +=================== + +This driver supports only 16-bit 44.1/48 kHz operation. The multi-channel +device (see emu10k1-jack.rst) additionally supports 24-bit capture. + +A patchset to enhance the driver is available from `a GitHub repository +`_. +Its multi-channel device supports 24-bit for both playback and capture, +and also supports full 88.2/96/176.4/192 kHz operation. +It is not going to be upstreamed due to a fundamental disagreement about +what constitutes a good user experience. + + +Digital mixer controls +====================== + +Note that the controls work as attenuators: the maximum value is the neutral +position leaving the signal unchanged. Note that if the same destination is +mentioned in multiple controls, the signal is accumulated and can be clipped +(set to maximal or minimal value without checking for overflow). + +Explanation of used abbreviations: + +DAC + digital to analog converter +ADC + analog to digital converter +LFE + low frequency effects (used as subwoofer signal) +IEC958 + S/PDIF +FX-bus + the EMU10K2 chip has an effect bus containing 64 accumulators. + Each of the synthesizer voices can feed its output to these accumulators + and the DSP microcontroller can operate with the resulting sum. + +name='Clock Source',index=0 +--------------------------- +This control allows switching the word clock between interally generated +44.1 or 48 kHz, or a number of external sources. + +Note: the sources for the 1616 CardBus card are unclear. Please report your +findings. + +name='Clock Fallback',index=0 +----------------------------- +This control determines the internal clock which the card switches to when +the selected external clock source is/becomes invalid. + +name='DAC1 0202 14dB PAD',index=0, etc. +--------------------------------------- +Output attenuation controls. Not available on 0404 cards. + +name='ADC1 14dB PAD 0202',index=0, etc. +--------------------------------------- +Input attenuation controls. Not available on 0404 cards. + +name='Optical Output Mode',index=0 +---------------------------------- +Switches the TOSLINK output port between S/PDIF and ADAT. +Not available on 0404 cards (fixed to S/PDIF). + +name='Optical Input Mode',index=0 +--------------------------------- +Switches the TOSLINK input port between S/PDIF and ADAT. +Not available on 0404 cards (fixed to S/PDIF). + +name='PCM Front Playback Volume',index=0 +---------------------------------------- +This control is used to attenuate samples from left and right front PCM FX-bus +accumulators. ALSA uses accumulators 8 and 9 for left and right front PCM +samples for 5.1 playback. The result samples are forwarded to the DSP 0 & 1 +playback channels. + +name='PCM Surround Playback Volume',index=0 +------------------------------------------- +This control is used to attenuate samples from left and right surround PCM FX-bus +accumulators. ALSA uses accumulators 2 and 3 for left and right surround PCM +samples for 5.1 playback. The result samples are forwarded to the DSP 2 & 3 +playback channels. + +name='PCM Side Playback Volume',index=0 +--------------------------------------- +This control is used to attenuate samples from left and right side PCM FX-bus +accumulators. ALSA uses accumulators 14 and 15 for left and right side PCM +samples for 7.1 playback. The result samples are forwarded to the DSP 6 & 7 +playback channels. + +name='PCM Center Playback Volume',index=0 +----------------------------------------- +This control is used to attenuate samples from the center PCM FX-bus accumulator. +ALSA uses accumulator 6 for center PCM samples for 5.1 playback. The result samples +are forwarded to the DSP 4 playback channel. + +name='PCM LFE Playback Volume',index=0 +-------------------------------------- +This control is used to attenuate samples from the LFE PCM FX-bus accumulator. +ALSA uses accumulator 7 for LFE PCM samples for 5.1 playback. The result samples +are forwarded to the DSP 5 playback channel. + +name='PCM Playback Volume',index=0 +---------------------------------- +This control is used to attenuate samples from left and right PCM FX-bus +accumulators. ALSA uses accumulators 0 and 1 for left and right PCM samples for +stereo playback. The result samples are forwarded to the virtual stereo mixer. + +name='PCM Capture Volume',index=0 +--------------------------------- +This control is used to attenuate samples from left and right PCM FX-bus +accumulators. ALSA uses accumulators 0 and 1 for left and right PCM. +The result is forwarded to the standard capture PCM device. + +name='Music Playback Volume',index=0 +------------------------------------ +This control is used to attenuate samples from left and right MIDI FX-bus +accumulators. ALSA uses accumulators 4 and 5 for left and right MIDI samples. +The result samples are forwarded to the virtual stereo mixer. + +name='Music Capture Volume',index=0 +----------------------------------- +These controls are used to attenuate samples from left and right MIDI FX-bus +accumulator. ALSA uses accumulators 4 and 5 for left and right MIDI samples. +The result is forwarded to the standard capture PCM device. + +name='Front Playback Volume',index=0 +------------------------------------ +This control is used to attenuate samples from the virtual stereo mixer. +The result samples are forwarded to the DSP 0 & 1 playback channels. + +name='Surround Playback Volume',index=0 +--------------------------------------- +This control is used to attenuate samples from the virtual stereo mixer. +The result samples are forwarded to the DSP 2 & 3 playback channels. + +name='Side Playback Volume',index=0 +----------------------------------- +This control is used to attenuate samples from the virtual stereo mixer. +The result samples are forwarded to the DSP 6 & 7 playback channels. + +name='Center Playback Volume',index=0 +------------------------------------- +This control is used to attenuate samples from the virtual stereo mixer. +The result samples are forwarded to the DSP 4 playback channel. + +name='LFE Playback Volume',index=0 +---------------------------------- +This control is used to attenuate samples from the virtual stereo mixer. +The result samples are forwarded to the DSP 5 playback channel. + +name='Tone Control - Switch',index=0 +------------------------------------ +This control turns the tone control on or off. The samples forwarded to +the DSP playback channels are affected. + +name='Tone Control - Bass',index=0 +---------------------------------- +This control sets the bass intensity. There is no neutral value!! +When the tone control code is activated, the samples are always modified. +The closest value to pure signal is 20. + +name='Tone Control - Treble',index=0 +------------------------------------ +This control sets the treble intensity. There is no neutral value!! +When the tone control code is activated, the samples are always modified. +The closest value to pure signal is 20. + +name='Master Playback Volume',index=0 +------------------------------------- +This control is used to attenuate samples for all DSP playback channels. + +name='EMU Capture Volume',index=0 +---------------------------------- +This control is used to attenuate samples from the DSP 0 & 1 capture channels. +The result is forwarded to the standard capture PCM device. + +name='DAC Left',index=0, etc. +----------------------------- +Select the source for the given physical audio output. These may be physical +inputs, playback channels (DSP xx, specified as a decimal number), or silence. + +name='DSP x',index=0 +-------------------- +Select the source for the given capture channel (specified as a hexadecimal +digit). Same options as for the physical audio outputs. + + +PCM stream related controls +=========================== + +These controls are described in audigy-mixer.rst. + + +MANUALS/PATENTS +=============== + +See sb-live-mixer.rst. diff --git a/Documentation/sound/cards/index.rst b/Documentation/sound/cards/index.rst index 49c1f2f688f8..e68bbb13c384 100644 --- a/Documentation/sound/cards/index.rst +++ b/Documentation/sound/cards/index.rst @@ -8,6 +8,7 @@ Card-Specific Information cmipci sb-live-mixer audigy-mixer + emu-mixer emu10k1-jack via82xx-mixer audiophile-usb