From 2222214749a9969e09454b9ba7febfdfb09c1c8d Mon Sep 17 00:00:00 2001 From: yixuanjiang Date: Mon, 19 Jun 2023 11:31:27 +0800 Subject: ASoC: soc-compress: Fix deadlock in soc_compr_open_fe Modify the error handling flow by release lock. The require mutex will keep holding if open fail. Fixes: aa9ff6a4955f ("ASoC: soc-compress: Reposition and add pcm_mutex") Signed-off-by: yixuanjiang Link: https://lore.kernel.org/r/20230619033127.2522477-1-yixuanjiang@google.com Signed-off-by: Mark Brown --- sound/soc/soc-compress.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index d8715db5e415..2117fd61cf8f 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -194,6 +194,7 @@ open_err: snd_soc_dai_compr_shutdown(cpu_dai, cstream, 1); out: dpcm_path_put(&list); + snd_soc_dpcm_mutex_unlock(fe); be_err: fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; snd_soc_card_mutex_unlock(fe->card); -- cgit v1.2.3 From a9e7c964cea4fb1541cc81a11d1b2fd135f4cf38 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 21 Jun 2023 16:32:29 +0100 Subject: ASoC: cs43130: Fix numerator/denominator mixup In converting to using the standard u16_fract type, commit [1] made the obvious mistake and failed to take account of the difference in numerator and denominator ordering, breaking all uses of the cs43130 codec. Fix it. [1] commit e14bd35ef446 ("ASoC: cs43130: Re-use generic struct u16_fract") Fixes: e14bd35ef446 ("ASoC: cs43130: Re-use generic struct u16_fract") Signed-off-by: Phil Elwell Reviewed-by: Andy Shevchenko Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20230621153229.1944132-1-phil@raspberrypi.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs43130.h | 138 ++++++++++++++++++++++----------------------- 1 file changed, 69 insertions(+), 69 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs43130.h b/sound/soc/codecs/cs43130.h index 1dd893674313..90e8895275e7 100644 --- a/sound/soc/codecs/cs43130.h +++ b/sound/soc/codecs/cs43130.h @@ -381,88 +381,88 @@ struct cs43130_clk_gen { /* frm_size = 16 */ static const struct cs43130_clk_gen cs43130_16_clk_gen[] = { - { 22579200, 32000, .v = { 441, 10, }, }, - { 22579200, 44100, .v = { 32, 1, }, }, - { 22579200, 48000, .v = { 147, 5, }, }, - { 22579200, 88200, .v = { 16, 1, }, }, - { 22579200, 96000, .v = { 147, 10, }, }, - { 22579200, 176400, .v = { 8, 1, }, }, - { 22579200, 192000, .v = { 147, 20, }, }, - { 22579200, 352800, .v = { 4, 1, }, }, - { 22579200, 384000, .v = { 147, 40, }, }, - { 24576000, 32000, .v = { 48, 1, }, }, - { 24576000, 44100, .v = { 5120, 147, }, }, - { 24576000, 48000, .v = { 32, 1, }, }, - { 24576000, 88200, .v = { 2560, 147, }, }, - { 24576000, 96000, .v = { 16, 1, }, }, - { 24576000, 176400, .v = { 1280, 147, }, }, - { 24576000, 192000, .v = { 8, 1, }, }, - { 24576000, 352800, .v = { 640, 147, }, }, - { 24576000, 384000, .v = { 4, 1, }, }, + { 22579200, 32000, .v = { 10, 441, }, }, + { 22579200, 44100, .v = { 1, 32, }, }, + { 22579200, 48000, .v = { 5, 147, }, }, + { 22579200, 88200, .v = { 1, 16, }, }, + { 22579200, 96000, .v = { 10, 147, }, }, + { 22579200, 176400, .v = { 1, 8, }, }, + { 22579200, 192000, .v = { 20, 147, }, }, + { 22579200, 352800, .v = { 1, 4, }, }, + { 22579200, 384000, .v = { 40, 147, }, }, + { 24576000, 32000, .v = { 1, 48, }, }, + { 24576000, 44100, .v = { 147, 5120, }, }, + { 24576000, 48000, .v = { 1, 32, }, }, + { 24576000, 88200, .v = { 147, 2560, }, }, + { 24576000, 96000, .v = { 1, 16, }, }, + { 24576000, 176400, .v = { 147, 1280, }, }, + { 24576000, 192000, .v = { 1, 8, }, }, + { 24576000, 352800, .v = { 147, 640, }, }, + { 24576000, 384000, .v = { 1, 4, }, }, }; /* frm_size = 32 */ static const struct cs43130_clk_gen cs43130_32_clk_gen[] = { - { 22579200, 32000, .v = { 441, 20, }, }, - { 22579200, 44100, .v = { 16, 1, }, }, - { 22579200, 48000, .v = { 147, 10, }, }, - { 22579200, 88200, .v = { 8, 1, }, }, - { 22579200, 96000, .v = { 147, 20, }, }, - { 22579200, 176400, .v = { 4, 1, }, }, - { 22579200, 192000, .v = { 147, 40, }, }, - { 22579200, 352800, .v = { 2, 1, }, }, - { 22579200, 384000, .v = { 147, 80, }, }, - { 24576000, 32000, .v = { 24, 1, }, }, - { 24576000, 44100, .v = { 2560, 147, }, }, - { 24576000, 48000, .v = { 16, 1, }, }, - { 24576000, 88200, .v = { 1280, 147, }, }, - { 24576000, 96000, .v = { 8, 1, }, }, - { 24576000, 176400, .v = { 640, 147, }, }, - { 24576000, 192000, .v = { 4, 1, }, }, - { 24576000, 352800, .v = { 320, 147, }, }, - { 24576000, 384000, .v = { 2, 1, }, }, + { 22579200, 32000, .v = { 20, 441, }, }, + { 22579200, 44100, .v = { 1, 16, }, }, + { 22579200, 48000, .v = { 10, 147, }, }, + { 22579200, 88200, .v = { 1, 8, }, }, + { 22579200, 96000, .v = { 20, 147, }, }, + { 22579200, 176400, .v = { 1, 4, }, }, + { 22579200, 192000, .v = { 40, 147, }, }, + { 22579200, 352800, .v = { 1, 2, }, }, + { 22579200, 384000, .v = { 80, 147, }, }, + { 24576000, 32000, .v = { 1, 24, }, }, + { 24576000, 44100, .v = { 147, 2560, }, }, + { 24576000, 48000, .v = { 1, 16, }, }, + { 24576000, 88200, .v = { 147, 1280, }, }, + { 24576000, 96000, .v = { 1, 8, }, }, + { 24576000, 176400, .v = { 147, 640, }, }, + { 24576000, 192000, .v = { 1, 4, }, }, + { 24576000, 352800, .v = { 147, 320, }, }, + { 24576000, 384000, .v = { 1, 2, }, }, }; /* frm_size = 48 */ static const struct cs43130_clk_gen cs43130_48_clk_gen[] = { - { 22579200, 32000, .v = { 147, 100, }, }, - { 22579200, 44100, .v = { 32, 3, }, }, - { 22579200, 48000, .v = { 49, 5, }, }, - { 22579200, 88200, .v = { 16, 3, }, }, - { 22579200, 96000, .v = { 49, 10, }, }, - { 22579200, 176400, .v = { 8, 3, }, }, - { 22579200, 192000, .v = { 49, 20, }, }, - { 22579200, 352800, .v = { 4, 3, }, }, - { 22579200, 384000, .v = { 49, 40, }, }, - { 24576000, 32000, .v = { 16, 1, }, }, - { 24576000, 44100, .v = { 5120, 441, }, }, - { 24576000, 48000, .v = { 32, 3, }, }, - { 24576000, 88200, .v = { 2560, 441, }, }, - { 24576000, 96000, .v = { 16, 3, }, }, - { 24576000, 176400, .v = { 1280, 441, }, }, - { 24576000, 192000, .v = { 8, 3, }, }, - { 24576000, 352800, .v = { 640, 441, }, }, - { 24576000, 384000, .v = { 4, 3, }, }, + { 22579200, 32000, .v = { 100, 147, }, }, + { 22579200, 44100, .v = { 3, 32, }, }, + { 22579200, 48000, .v = { 5, 49, }, }, + { 22579200, 88200, .v = { 3, 16, }, }, + { 22579200, 96000, .v = { 10, 49, }, }, + { 22579200, 176400, .v = { 3, 8, }, }, + { 22579200, 192000, .v = { 20, 49, }, }, + { 22579200, 352800, .v = { 3, 4, }, }, + { 22579200, 384000, .v = { 40, 49, }, }, + { 24576000, 32000, .v = { 1, 16, }, }, + { 24576000, 44100, .v = { 441, 5120, }, }, + { 24576000, 48000, .v = { 3, 32, }, }, + { 24576000, 88200, .v = { 441, 2560, }, }, + { 24576000, 96000, .v = { 3, 16, }, }, + { 24576000, 176400, .v = { 441, 1280, }, }, + { 24576000, 192000, .v = { 3, 8, }, }, + { 24576000, 352800, .v = { 441, 640, }, }, + { 24576000, 384000, .v = { 3, 4, }, }, }; /* frm_size = 64 */ static const struct cs43130_clk_gen cs43130_64_clk_gen[] = { - { 22579200, 32000, .v = { 441, 40, }, }, - { 22579200, 44100, .v = { 8, 1, }, }, - { 22579200, 48000, .v = { 147, 20, }, }, - { 22579200, 88200, .v = { 4, 1, }, }, - { 22579200, 96000, .v = { 147, 40, }, }, - { 22579200, 176400, .v = { 2, 1, }, }, - { 22579200, 192000, .v = { 147, 80, }, }, + { 22579200, 32000, .v = { 40, 441, }, }, + { 22579200, 44100, .v = { 1, 8, }, }, + { 22579200, 48000, .v = { 20, 147, }, }, + { 22579200, 88200, .v = { 1, 4, }, }, + { 22579200, 96000, .v = { 40, 147, }, }, + { 22579200, 176400, .v = { 1, 2, }, }, + { 22579200, 192000, .v = { 80, 147, }, }, { 22579200, 352800, .v = { 1, 1, }, }, - { 24576000, 32000, .v = { 12, 1, }, }, - { 24576000, 44100, .v = { 1280, 147, }, }, - { 24576000, 48000, .v = { 8, 1, }, }, - { 24576000, 88200, .v = { 640, 147, }, }, - { 24576000, 96000, .v = { 4, 1, }, }, - { 24576000, 176400, .v = { 320, 147, }, }, - { 24576000, 192000, .v = { 2, 1, }, }, - { 24576000, 352800, .v = { 160, 147, }, }, + { 24576000, 32000, .v = { 1, 12, }, }, + { 24576000, 44100, .v = { 147, 1280, }, }, + { 24576000, 48000, .v = { 1, 8, }, }, + { 24576000, 88200, .v = { 147, 640, }, }, + { 24576000, 96000, .v = { 1, 4, }, }, + { 24576000, 176400, .v = { 147, 320, }, }, + { 24576000, 192000, .v = { 1, 2, }, }, + { 24576000, 352800, .v = { 147, 160, }, }, { 24576000, 384000, .v = { 1, 1, }, }, }; -- cgit v1.2.3 From d900d9a435ca95a386f49424f3689cd17ec201da Mon Sep 17 00:00:00 2001 From: Sheetal Date: Thu, 22 Jun 2023 17:04:09 +0530 Subject: ASoC: tegra: Fix SFC conversion for few rates Sample rate conversions for rates greater than 48kHz are found to be failing. It means x->y conversions fail when either x or y is greater than 48kHz. This happens because, tegra210_sfc_rate_to_idx() returns incorrect index for rates greater than 48kHz. This actually depends on the tegra210_sfc_rates[] array and it is not in sync with frequency values of SFC TX/RX register. To be precise, 64kHz entry is missing in above array defined in the driver. Due to this wrong index is returned and this results in incorrect programming of coefficients. To fix this, align the tegra210_sfc_rates[] array with SFC register specification and thus add 64kHz entry to it. Also, the coefficient table is updated to reflect that none of the conversions are supported for 64kHz. Fixes: b2f74ec53a6c ("ASoC: tegra: Add Tegra210 based SFC driver") Cc: stable@vger.kernel.org Signed-off-by: Sheetal Reviewed-by: Mohan Kumar D Reviewed-by: Sameer Pujar Link: https://lore.kernel.org/r/Message-Id: <1687433656-7892-2-git-send-email-spujar@nvidia.com> Signed-off-by: Mark Brown --- sound/soc/tegra/tegra210_sfc.c | 31 ++++++++++++++++++++++++++++++- sound/soc/tegra/tegra210_sfc.h | 4 ++-- 2 files changed, 32 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/tegra/tegra210_sfc.c b/sound/soc/tegra/tegra210_sfc.c index e9df1ffc8a58..c2240babd601 100644 --- a/sound/soc/tegra/tegra210_sfc.c +++ b/sound/soc/tegra/tegra210_sfc.c @@ -2,7 +2,7 @@ // // tegra210_sfc.c - Tegra210 SFC driver // -// Copyright (c) 2021 NVIDIA CORPORATION. All rights reserved. +// Copyright (c) 2021-2023 NVIDIA CORPORATION. All rights reserved. #include #include @@ -42,6 +42,7 @@ static const int tegra210_sfc_rates[TEGRA210_SFC_NUM_RATES] = { 32000, 44100, 48000, + 64000, 88200, 96000, 176400, @@ -2857,6 +2858,7 @@ static s32 *coef_addr_table[TEGRA210_SFC_NUM_RATES][TEGRA210_SFC_NUM_RATES] = { coef_8to32, coef_8to44, coef_8to48, + UNSUPP_CONV, coef_8to88, coef_8to96, UNSUPP_CONV, @@ -2872,6 +2874,7 @@ static s32 *coef_addr_table[TEGRA210_SFC_NUM_RATES][TEGRA210_SFC_NUM_RATES] = { coef_11to32, coef_11to44, coef_11to48, + UNSUPP_CONV, coef_11to88, coef_11to96, UNSUPP_CONV, @@ -2887,6 +2890,7 @@ static s32 *coef_addr_table[TEGRA210_SFC_NUM_RATES][TEGRA210_SFC_NUM_RATES] = { coef_16to32, coef_16to44, coef_16to48, + UNSUPP_CONV, coef_16to88, coef_16to96, coef_16to176, @@ -2902,6 +2906,7 @@ static s32 *coef_addr_table[TEGRA210_SFC_NUM_RATES][TEGRA210_SFC_NUM_RATES] = { coef_22to32, coef_22to44, coef_22to48, + UNSUPP_CONV, coef_22to88, coef_22to96, coef_22to176, @@ -2917,6 +2922,7 @@ static s32 *coef_addr_table[TEGRA210_SFC_NUM_RATES][TEGRA210_SFC_NUM_RATES] = { coef_24to32, coef_24to44, coef_24to48, + UNSUPP_CONV, coef_24to88, coef_24to96, coef_24to176, @@ -2932,6 +2938,7 @@ static s32 *coef_addr_table[TEGRA210_SFC_NUM_RATES][TEGRA210_SFC_NUM_RATES] = { BYPASS_CONV, coef_32to44, coef_32to48, + UNSUPP_CONV, coef_32to88, coef_32to96, coef_32to176, @@ -2947,6 +2954,7 @@ static s32 *coef_addr_table[TEGRA210_SFC_NUM_RATES][TEGRA210_SFC_NUM_RATES] = { coef_44to32, BYPASS_CONV, coef_44to48, + UNSUPP_CONV, coef_44to88, coef_44to96, coef_44to176, @@ -2962,11 +2970,28 @@ static s32 *coef_addr_table[TEGRA210_SFC_NUM_RATES][TEGRA210_SFC_NUM_RATES] = { coef_48to32, coef_48to44, BYPASS_CONV, + UNSUPP_CONV, coef_48to88, coef_48to96, coef_48to176, coef_48to192, }, + /* Convertions from 64 kHz */ + { + UNSUPP_CONV, + UNSUPP_CONV, + UNSUPP_CONV, + UNSUPP_CONV, + UNSUPP_CONV, + UNSUPP_CONV, + UNSUPP_CONV, + UNSUPP_CONV, + UNSUPP_CONV, + UNSUPP_CONV, + UNSUPP_CONV, + UNSUPP_CONV, + UNSUPP_CONV, + }, /* Convertions from 88.2 kHz */ { coef_88to8, @@ -2977,6 +3002,7 @@ static s32 *coef_addr_table[TEGRA210_SFC_NUM_RATES][TEGRA210_SFC_NUM_RATES] = { coef_88to32, coef_88to44, coef_88to48, + UNSUPP_CONV, BYPASS_CONV, coef_88to96, coef_88to176, @@ -2991,6 +3017,7 @@ static s32 *coef_addr_table[TEGRA210_SFC_NUM_RATES][TEGRA210_SFC_NUM_RATES] = { coef_96to32, coef_96to44, coef_96to48, + UNSUPP_CONV, coef_96to88, BYPASS_CONV, coef_96to176, @@ -3006,6 +3033,7 @@ static s32 *coef_addr_table[TEGRA210_SFC_NUM_RATES][TEGRA210_SFC_NUM_RATES] = { coef_176to32, coef_176to44, coef_176to48, + UNSUPP_CONV, coef_176to88, coef_176to96, BYPASS_CONV, @@ -3021,6 +3049,7 @@ static s32 *coef_addr_table[TEGRA210_SFC_NUM_RATES][TEGRA210_SFC_NUM_RATES] = { coef_192to32, coef_192to44, coef_192to48, + UNSUPP_CONV, coef_192to88, coef_192to96, coef_192to176, diff --git a/sound/soc/tegra/tegra210_sfc.h b/sound/soc/tegra/tegra210_sfc.h index 5a6b66e297d8..a4c993d79403 100644 --- a/sound/soc/tegra/tegra210_sfc.h +++ b/sound/soc/tegra/tegra210_sfc.h @@ -2,7 +2,7 @@ /* * tegra210_sfc.h - Definitions for Tegra210 SFC driver * - * Copyright (c) 2021 NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2021-2023 NVIDIA CORPORATION. All rights reserved. * */ @@ -47,7 +47,7 @@ #define TEGRA210_SFC_EN_SHIFT 0 #define TEGRA210_SFC_EN (1 << TEGRA210_SFC_EN_SHIFT) -#define TEGRA210_SFC_NUM_RATES 12 +#define TEGRA210_SFC_NUM_RATES 13 /* Fields in TEGRA210_SFC_COEF_RAM */ #define TEGRA210_SFC_COEF_RAM_EN BIT(0) -- cgit v1.2.3 From 5512ffd9f39832f312b7f903703ac39d6367fe8a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 30 Jun 2023 20:21:52 +0300 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From c3d42d7baf6b4032171270e3df001fb946493452 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 30 Jun 2023 20:21:53 +0300 Subject: 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(-) (limited to 'sound') 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"); -- cgit v1.2.3 From 043bb9c012ee7d092a477159cc66dbdf62fd2666 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 30 Jun 2023 20:21:54 +0300 Subject: 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(-) (limited to 'sound') 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 */ -- cgit v1.2.3 From ea1c1019a88d88cf0a7d6892f594b72ddb3b8c0b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 30 Jun 2023 20:21:55 +0300 Subject: 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 | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'sound') 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 -- cgit v1.2.3 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: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 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: 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(-) (limited to 'sound') 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 @@ err_pm_disable: 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); -- cgit v1.2.3 From be7dc10ab0bc247c2abbdefdaa9d5196df88e9d1 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 29 Jun 2023 13:24:42 +0200 Subject: 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(-) (limited to 'sound') 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 { -- cgit v1.2.3 From c30d10aeb398cf71662cb8c6b0090ed9ab38dd8e Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 29 Jun 2023 13:24:43 +0200 Subject: 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(+) (limited to 'sound') 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; -- cgit v1.2.3 From 32e40c8d6ff920354fde36299198c80e7a7d3b76 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 29 Jun 2023 13:24:44 +0200 Subject: 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 (limited to 'sound') 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"); -- cgit v1.2.3 From d55bb0f1c1a365c42d8b4032cb965a255692a400 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 29 Jun 2023 13:24:45 +0200 Subject: 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(+) (limited to 'sound') 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", + }, {}, }; -- cgit v1.2.3 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: 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 (limited to 'sound') 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"); -- cgit v1.2.3 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: 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(+) (limited to 'sound') 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", -- cgit v1.2.3 From 27cd41698de49c8afbcc148a0d76c35da3271519 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 29 Jun 2023 13:24:48 +0200 Subject: 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(-) (limited to 'sound') 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; -- cgit v1.2.3 From 7012fa7d56b7b3e100e4ff0c8d8d7a183f09130d Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 29 Jun 2023 13:24:49 +0200 Subject: 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(-) (limited to 'sound') 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 = { -- cgit v1.2.3 From fd9965235099fc4cccd94f82a371192bf7645a3e Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Thu, 29 Jun 2023 15:43:47 +0800 Subject: 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(-) (limited to 'sound') 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)) -- cgit v1.2.3 From e61b415515d3db57dce3af3e4a0441f08d8d8f15 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:05 +0530 Subject: 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 (limited to 'sound') 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 @@ disable_pci: 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); -- cgit v1.2.3 From 7ad6fb9dd1ca63f9f36e413036f36f075cdaec4a Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:06 +0530 Subject: 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(+) (limited to 'sound') 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 */ -- cgit v1.2.3 From fc11d3266dc7ed386efe91c20d09780bbded1f03 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:07 +0530 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From 7a83903022dc3bd5214f6bdde8132c66015ab538 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:08 +0530 Subject: 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(-) (limited to 'sound') 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 { -- cgit v1.2.3 From 088a40980efbc2c449b72f0f2c7ebd82f71d08e2 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:09 +0530 Subject: 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(+) (limited to 'sound') 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 @@ disable_pci: 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); -- cgit v1.2.3 From c8786ac7bb374276b1c2b545b4a6be3b230be7cb Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:10 +0530 Subject: 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(+) (limited to 'sound') 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 { -- cgit v1.2.3 From a8d1316a264f36c2ffe798e42d6b415dc377851e Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:11 +0530 Subject: 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(-) (limited to 'sound') 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) { -- cgit v1.2.3 From 7373e6bee60cdac36a134897164885b2257a02ac Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:12 +0530 Subject: 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(+) (limited to 'sound') 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]; -- cgit v1.2.3 From e3a96e441e05bbf599ce70c2a03e7acd55b275ee Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:13 +0530 Subject: 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(-) (limited to 'sound') 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 */ -- cgit v1.2.3 From 5debf4ae138c81321832d41203483696cac1c580 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Mon, 26 Jun 2023 19:25:14 +0530 Subject: 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(-) (limited to 'sound') 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; -- cgit v1.2.3 From a04616321f50bc389cd8d19a6d300d3c3f1be77b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 3 Jul 2023 16:52:11 +0300 Subject: 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(-) (limited to 'sound') 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); } /** -- cgit v1.2.3 From a0cb05cb70b469198ad86c0b13b02cbba3ecd8fd Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Thu, 6 Jul 2023 00:47:58 +0300 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From 3dd26e27ccb4f18b4d25c0a49e1888eca9c6a724 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Thu, 6 Jul 2023 00:47:59 +0300 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From dba22efd0d177a23c6da2a161e9a1ad29718924c Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Thu, 6 Jul 2023 00:48:00 +0300 Subject: 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 | 137 ++++++++++++++++++++++++++++++++++--- 2 files changed, 132 insertions(+), 10 deletions(-) (limited to 'sound') 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 = &acp5x_8821_35l41_card; + 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; + } 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); -- cgit v1.2.3 From 4b526b3278becdf1f2bfd375078f5db469f8a6bb Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Fri, 7 Jul 2023 17:37:27 +0530 Subject: 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(+) (limited to 'sound') 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 { -- cgit v1.2.3 From ac91c8c89782d7d0781120a74c9bd939e3ce2831 Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Fri, 7 Jul 2023 17:37:28 +0530 Subject: 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(+) (limited to 'sound') 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 { -- cgit v1.2.3 From ef51cddf014b3e4909e9656025d1f7c2b4cc4117 Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Fri, 7 Jul 2023 17:37:29 +0530 Subject: 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(+) (limited to 'sound') 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; -- cgit v1.2.3 From 197b1f7f0df183db332b6b8851a29c8bc901571d Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Fri, 7 Jul 2023 17:37:30 +0530 Subject: 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(+) (limited to 'sound') 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) -- cgit v1.2.3 From 1d298ad822178d365b53eac298c1752730505306 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 23 Jun 2023 10:58:29 +0200 Subject: 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 (limited to 'sound') 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"); -- cgit v1.2.3 From 6d8ad35d119ca4c9c6fdf83faa733102c4a63f4b Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 23 Jun 2023 10:58:30 +0200 Subject: 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(-) (limited to 'sound') 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; -- cgit v1.2.3 From 2b48d170fb9965dda9d41edcb0bbfc9ee4c6584f Mon Sep 17 00:00:00 2001 From: Mastan Katragadda Date: Fri, 30 Jun 2023 12:35:43 +0530 Subject: 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 | 34 +++++++++++++++------------------- sound/soc/sof/amd/acp.h | 4 ++-- 2 files changed, 17 insertions(+), 21 deletions(-) (limited to 'sound') 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) { + u32 data = 0; + pci_write_config_dword(dev, 0x60, smn_addr); - pci_read_config_dword(dev, 0x64, data); + pci_read_config_dword(dev, 0x64, &data); - return 0; + 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 -- cgit v1.2.3 From 521d675d2497f890e881dc48e954a1559460e97c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 21 Jun 2023 02:18:10 +0000 Subject: 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(-) (limited to 'sound') 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. -- cgit v1.2.3 From 0e66a2c694096abc54ed58b3be654103f155ea43 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 21 Jun 2023 02:18:17 +0000 Subject: 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(-) (limited to 'sound') 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; } /** -- cgit v1.2.3 From 7f6ecc220272dff53b7cec0ae2a863eefcb5335b Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 5 Jul 2023 12:23:48 +0800 Subject: 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(+) (limited to 'sound') 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, }; -- cgit v1.2.3 From 82770b76abae2ff9d70f354a61983b921e63bae1 Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Sun, 25 Jun 2023 14:54:12 +0800 Subject: 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(-) (limited to 'sound') 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); } -- cgit v1.2.3 From 065aa861b1243704b329a6d8407d8399614df6bd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 29 Jun 2023 23:52:20 +0000 Subject: 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(-) (limited to 'sound') 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; } -- cgit v1.2.3 From 209fb30ee1c7edc6807ac94f98c9ce78b4891aed Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 21 Jun 2023 16:07:50 +0800 Subject: 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(-) (limited to 'sound') 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; -- cgit v1.2.3 From 24e04c94bebc4144f790a21a93d090cf9673acd9 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Sun, 25 Jun 2023 09:05:47 +0800 Subject: 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(-) (limited to 'sound') 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), -- cgit v1.2.3 From 221acc16aee16eb246bad32a6b9014021218b7cd Mon Sep 17 00:00:00 2001 From: Maxim Kochetkov Date: Thu, 22 Jun 2023 23:00:29 +0300 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From c70064b96f509daa78f57992aeabcf274fb2fed4 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 30 Jun 2023 21:48:36 -0700 Subject: 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(+) (limited to 'sound') 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" -- cgit v1.2.3 From c7a0f10b885164e4804dc144c375076c2e0d39f6 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 5 Jul 2023 12:29:31 +0800 Subject: 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(+) (limited to 'sound') 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, -- cgit v1.2.3 From fbb64eedf5a3a98071ee75808cfc1367d1e75783 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 10 Jul 2023 08:59:55 +0200 Subject: 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 --- 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 ++++++ 4 files changed, 38 insertions(+), 30 deletions(-) (limited to 'sound') 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, -- cgit v1.2.3 From 6657fcc91db9b01fcbc4f8de0659e10cabd7ce2f Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Thu, 13 Jul 2023 03:14:23 +0800 Subject: 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 ++++++++++++++++++++++- sound/soc/intel/common/soc-acpi-intel-jsl-match.c | 12 ++++ 3 files changed, 93 insertions(+), 4 deletions(-) (limited to 'sound') 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); -- cgit v1.2.3 From deb1200f6eb634a6e4d08ada953b72be1e8adcfa Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 12 Jul 2023 16:57:48 +0200 Subject: 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(-) (limited to 'sound') 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 = { -- cgit v1.2.3 From 67192cc0f0263847ab3ccdcfe90989624a0c7fe3 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 12 Jul 2023 16:57:49 +0200 Subject: 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(-) (limited to 'sound') 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); } -- cgit v1.2.3 From 52beea42d825321a7ded656f14f5672b290dbd16 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:50 +0100 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From 625ea9e6d5c4509634b49a8e7436ea3248220e9e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:51 +0100 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From b7fea0e30fbdc4c5cba6edbf5e5b8aabd0a5660a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:52 +0100 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From da27e493ce9394134deecfbecfd46c8836141191 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:53 +0100 Subject: 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(-) (limited to 'sound') 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), }; -- cgit v1.2.3 From e0e3bb187bfba6ec2a0bd1b7d36fdacb6a8e3010 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:54 +0100 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From 97e3b4845d389c8e309e13445bc02ad01fdbda7a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:55 +0100 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From 3841ff1bacccc253c48c2c4a2c5e087dfae4b51e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:56 +0100 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From a0a4cef897b550cf4beaf3fcb1742c3dc895f5f8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:57 +0100 Subject: 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(-) (limited to 'sound') 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), }; -- cgit v1.2.3 From c05c32dd82a602e5b75c3e473e55e7b6325a1967 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:58 +0100 Subject: 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(-) (limited to 'sound') 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, }; -- cgit v1.2.3 From 07e835e35b5dc7e1906e2dbd6d72cb9336846ba6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 00:13:59 +0100 Subject: 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(-) (limited to 'sound') 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), }; -- cgit v1.2.3 From 6d2a87ddd9c2488732ca422476a9417ca312f75a Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 13 Jul 2023 14:51:06 +0800 Subject: 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(-) (limited to 'sound') 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 = { -- cgit v1.2.3 From df43fba7c75545094639be42a85502634f075a19 Mon Sep 17 00:00:00 2001 From: Min-Hua Chen Date: Thu, 13 Jul 2023 23:17:43 +0800 Subject: 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(-) (limited to 'sound') 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) { -- cgit v1.2.3 From 678a0bbe158076805843f6a58aa09b365fc43871 Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Thu, 13 Jul 2023 11:59:52 +0400 Subject: 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(+) (limited to 'sound') 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; -- cgit v1.2.3 From f9d1b819307c242f2e648f16a05c0f908c525616 Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Thu, 13 Jul 2023 11:59:53 +0400 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From 083912c240de0c5f797da0443f5a99e87b75fcb3 Mon Sep 17 00:00:00 2001 From: Zhu Ning Date: Fri, 14 Jul 2023 11:24:49 +0800 Subject: 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(-) (limited to 'sound') 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 + -- cgit v1.2.3 From 7e9f28398a6e226d4c31cb0e5501a36f37fa139d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:51:08 -0600 Subject: 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(-) (limited to 'sound') 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 -- cgit v1.2.3 From 272aedb250cff93c2c25d19db9f4691329238f98 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 19:29:32 +0100 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From 8caeeb54d8283601eab27f6d0ca727476cba7f1c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 19:29:33 +0100 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From daf95b06a0615d8b2a6716d14a3b8605b90f1ed2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 19:29:34 +0100 Subject: 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(-) (limited to 'sound') 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), -- cgit v1.2.3 From e1de05805133d2f2803001b4804d010b6812ca4a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 19:29:35 +0100 Subject: 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(-) (limited to 'sound') 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), -- cgit v1.2.3 From 60f38a592efe08e5ced454e8a05f6814e6e221ec Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Fri, 14 Jul 2023 17:29:13 +0800 Subject: 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(+) (limited to 'sound') 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); -- cgit v1.2.3 From 1a74b21ce59f4343e8bf64ec4c20bcbbaea96c5f Mon Sep 17 00:00:00 2001 From: V sujith kumar Reddy Date: Thu, 13 Jul 2023 18:27:07 +0530 Subject: 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 (limited to 'sound') 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 @@ out: 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 -- cgit v1.2.3 From 5e1c5df5048b320adffcb03e0cdfc6027364ed30 Mon Sep 17 00:00:00 2001 From: V sujith kumar Reddy Date: Thu, 13 Jul 2023 18:27:08 +0530 Subject: 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(+) (limited to 'sound') 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); -- cgit v1.2.3 From 8278aa8edb4037ca5050a1b0bf32b38ef9fa59bc Mon Sep 17 00:00:00 2001 From: V sujith kumar Reddy Date: Thu, 13 Jul 2023 18:27:09 +0530 Subject: 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(+) (limited to 'sound') 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 = { -- cgit v1.2.3 From 09f75f098105d65c37915e41a6ed3a75ec3ecfc7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Jul 2023 10:19:53 +0900 Subject: 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 --- sound/soc/soc-core.c | 62 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 15 deletions(-) (limited to 'sound') 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 -- cgit v1.2.3 From 45655ec69cb954d7fa594054bec33d6d5b99f8d5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Jul 2023 10:20:00 +0900 Subject: 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 --- sound/soc/soc-core.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) (limited to 'sound') 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) -- cgit v1.2.3 From 442ae56cf5c007faaf7440d4aa018c62e5761157 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Jul 2023 10:20:06 +0900 Subject: 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 --- sound/soc/soc-core.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'sound') 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) { -- cgit v1.2.3 From 988bad5ee4d7138d26081f3661779b63725605d8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Jul 2023 10:20:11 +0900 Subject: 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 --- sound/soc/generic/simple-card-utils.c | 2 +- sound/soc/soc-core.c | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'sound') 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, -- cgit v1.2.3 From bbde4a30c6b18dd034dcce41612907dc64817175 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Jul 2023 10:20:17 +0900 Subject: 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 --- sound/soc/soc-core.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'sound') 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) -- cgit v1.2.3 From 90de551c1bf0c78ca5cd10c5ff424dee4d44cb1c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Jul 2023 10:20:22 +0900 Subject: 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 --- sound/soc/generic/audio-graph-card.c | 2 +- sound/soc/generic/audio-graph-card2.c | 2 +- sound/soc/generic/simple-card-utils.c | 21 ++++++++++++++++++--- 3 files changed, 20 insertions(+), 5 deletions(-) (limited to 'sound') 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; -- cgit v1.2.3 From 970dc991b2aaf22cdd497bf66c8fbb13c28c7de4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Jul 2023 10:20:28 +0900 Subject: 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(-) (limited to 'sound') 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; -- cgit v1.2.3 From 7562539e15f1376577d7b62e904b509d17c4bc3f Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 11 Jul 2023 11:48:41 +0800 Subject: 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(-) (limited to 'sound') 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; -- cgit v1.2.3 From c8b04f008fc33ab2b902a1780c205810d157c849 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 11 Jul 2023 11:48:42 +0800 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From e1537b59633cc0e30305e498ba9eead45e762910 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 11 Jul 2023 11:48:43 +0800 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From 97b19db1cfb34303101a3f30c26ef0e2ede07d89 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 11 Jul 2023 11:48:44 +0800 Subject: 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(-) (limited to 'sound') 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; -- cgit v1.2.3 From 976201dd5f597b7c25b9fc5ebeee382b5e6bf8fb Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 11 Jul 2023 11:48:45 +0800 Subject: 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(-) (limited to 'sound') 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; -- cgit v1.2.3 From c960b012ec4747265f0392a31570045d3f982447 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sat, 15 Jul 2023 18:07:38 +0200 Subject: 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 --- sound/pci/emu10k1/emu10k1.c | 1 + sound/pci/emu10k1/emu10k1_main.c | 30 +++++++++++++++++++++++++++++- sound/pci/emu10k1/emumixer.c | 12 ++++++++---- 3 files changed, 38 insertions(+), 5 deletions(-) (limited to 'sound') 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, -- cgit v1.2.3 From 9034ff11693b0246ef0e2bd5b69b2686c429070f Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sat, 15 Jul 2023 18:08:38 +0200 Subject: 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(-) (limited to 'sound') 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 -- cgit v1.2.3 From 6d68d9cba1d0d1ee628a783eb9e7d38a0c3691b8 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sat, 15 Jul 2023 18:08:39 +0200 Subject: 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(-) (limited to 'sound') 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 -- cgit v1.2.3 From 8b30cdbe0b911562fc1496078162dc9547b69be5 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Thu, 13 Jul 2023 18:25:12 -0400 Subject: 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(+) (limited to 'sound') 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"); -- cgit v1.2.3 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: 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(-) (limited to 'sound') 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, } -- cgit v1.2.3 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: 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(-) (limited to 'sound') 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 }, -- cgit v1.2.3 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: 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(-) (limited to 'sound') 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; } -- cgit v1.2.3 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: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 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: 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 --- sound/soc/intel/skylake/skl-pcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') 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); -- cgit v1.2.3 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: 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 | 117 ++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 63 deletions(-) (limited to 'sound') 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, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS, }, - /* Alderlake-M */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51cc, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_M, }, - /* Alderlake-N */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x54c8, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_N, }, - /* RaptorLake-P */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51ca, + .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51cb, + .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1, }, - /* RaptorLake-M */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51ce, + .device = PCI_DEVICE_ID_INTEL_HDA_RPL_M, }, - /* RaptorLake-PX */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51cf, + .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; } -- cgit v1.2.3 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: 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(-) (limited to 'sound') 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, } }; -- cgit v1.2.3 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: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 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: 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(-) (limited to 'sound') 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), {}, }; -- cgit v1.2.3 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: 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(-) (limited to 'sound') 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, } }; -- cgit v1.2.3 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: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 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: 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(-) (limited to 'sound') 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, } }; -- cgit v1.2.3 From 317af09e296f70e4fb55b17f49655e103a794172 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:14 +0100 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From 78138627acc014dc3a23cb6f29f53a025544743f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:15 +0100 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From f9ad18b24c24b06820fcd72975f1b08b1d466168 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:16 +0100 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From faa48c9bdaa1625b008d07ce08660d56f198592c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:17 +0100 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From b5a0e5e4bf96de3d34f3d36afc32b3e9cd0376c2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:18 +0100 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From b0a0e231abb5c3753d479d49d62308c7a1b20838 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:19 +0100 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From 7a2827ad082cb70bb7884e5630b58503e41b2932 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:20 +0100 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From 99d2c7b8e50458bb620bb7b3d2ed809484a7ecd3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:21 +0100 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From cb8ac2658f8ae2a3a921b0c4f3400922e361597f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:22 +0100 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From e3753fd3b362e01c9faabbea4412d6eae24cfdff Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:23 +0100 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From a4ccfe889dfe1eb1b6304402169b140fc329f535 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:24 +0100 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From 4c04586a7962598933313fd08f19ed76138c1fd9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:25 +0100 Subject: 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(-) (limited to 'sound') 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), }; -- cgit v1.2.3 From 4f2e3688abee076f49b78b5d4fca67bb37dbe375 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:26 +0100 Subject: 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(-) (limited to 'sound') 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[] = { -- cgit v1.2.3 From 1a37aa4195e2169f2ad6d74608bfcaa95697c9f8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:27 +0100 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From b028b1efe7103e5a2a01d7ca087fd43c2d4977e6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:28 +0100 Subject: 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(-) (limited to 'sound') 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), }; -- cgit v1.2.3 From d3c4ba7dbe15e5268ba07f2dcefafd274d110e80 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:29 +0100 Subject: 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(-) (limited to 'sound') 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, }; -- cgit v1.2.3 From 247c6960bfdabeae5088b4ecf5e06a68b1ae492a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:30 +0100 Subject: 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(-) (limited to 'sound') 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, }; -- cgit v1.2.3 From 43bc153d2e684dcbd23311899c136b183ba21840 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:31 +0100 Subject: 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(-) (limited to 'sound') 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, }; -- cgit v1.2.3 From 368a233bc3cf590bea7f27774cc94ff121addd65 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:32 +0100 Subject: 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(-) (limited to 'sound') 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, }; -- cgit v1.2.3 From 9a2abf70e2635a59fde1806994387a79fb351308 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:33 +0100 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From 59bd5113d8ca0765e8f12307a4b1ac0e3daa91f4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:34 +0100 Subject: 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(-) (limited to 'sound') 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), }; -- cgit v1.2.3 From ee8169f94985e5c88d2c4e9daed0b5f8345032b1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:35 +0100 Subject: 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(-) (limited to 'sound') 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, }; -- cgit v1.2.3 From 5dd4ddde85586f4b53be219f27cac2cd15e02417 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:36 +0100 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From ef1589123dbb7102b49f9997c5b31b0721aff242 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:37 +0100 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From 3c884cb5c28c45197b81bbdcf2d41a37649ee895 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:38 +0100 Subject: 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(-) (limited to 'sound') 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), }; -- cgit v1.2.3 From 7aa7ab713b71fddc71603b9b3c9ab963fd9831a4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:39 +0100 Subject: 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(-) (limited to 'sound') 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, }; -- cgit v1.2.3 From 080c82a56659fd5cbf811007193bf04d3c31922e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:40 +0100 Subject: 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(-) (limited to 'sound') 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, }; -- cgit v1.2.3 From 200ba27767702c11f965e619b43ebfe9989a1996 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:41 +0100 Subject: 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(-) (limited to 'sound') 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), }; -- cgit v1.2.3 From 2c609c6b42c911df772d97c4ddf10d9374607e0c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:42 +0100 Subject: 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(-) (limited to 'sound') 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, }; -- cgit v1.2.3 From 7de380eeba5b616a4bf08acbbc5aa6e76bcb4299 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:43 +0100 Subject: 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(-) (limited to 'sound') 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), }; -- cgit v1.2.3 From 9bd4bc4cb48927d581ff2886bf701bfdb4735724 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:44 +0100 Subject: 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(-) (limited to 'sound') 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), }; -- cgit v1.2.3 From 11e1354036391054f496aa4c4e724e160dfcded2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:45 +0100 Subject: 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(-) (limited to 'sound') 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, }; -- cgit v1.2.3 From d643047ec77ed17fef7b2ce76ecd5e88b3b5f7d8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:46 +0100 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From 3a17f8d71bba92538165a5b55f095b7cb0e71529 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:47 +0100 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From 3aceedcda294273bedf7af7836e2457a98836b09 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:48 +0100 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From 663aa3325f5b971596b08c768bc705cc6f49dd18 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:49 +0100 Subject: 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(-) (limited to 'sound') 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), }; -- cgit v1.2.3 From ae394355be78c6be4da1a6f18da8b588215aaa2c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:50 +0100 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From a4b6c6ec975c9f871cbde1f30a554665475498ef Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:51 +0100 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From 9bed789c4f14bd607892ff31d9164b5ed544ebaf Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:52 +0100 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From 6066d156a3a36139feb0c80645dddadae2ddaf01 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:53 +0100 Subject: 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(-) (limited to 'sound') 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), }; -- cgit v1.2.3 From 97f93367cd735813aa5bf0d7ef64c956a7ac8013 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:54 +0100 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From 5891932208f76375940a2a96b113fd328b70ddd1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:55 +0100 Subject: 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(-) (limited to 'sound') 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), }; -- cgit v1.2.3 From 20dbc7a892ffe6aa20a4b1eaf0353cdf4c762fcb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:56 +0100 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From 2fa0213ed798bee59fa815171d3855dcc133a416 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:57 +0100 Subject: 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(-) (limited to 'sound') 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), }; -- cgit v1.2.3 From fb60b65a65b038f1881a3f1a0146c07e22f647d0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:58 +0100 Subject: 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(-) (limited to 'sound') 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), }; -- cgit v1.2.3 From 7e510925e00d1daea10f9474505b4f1b9ec24433 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:13:59 +0100 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From 2e3a4ee07211b047881b3f2e944453cdd4deaf96 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:14:00 +0100 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From 8bfb4c81b9c896448e5d7229f1849bd0ad7c2f20 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Jul 2023 01:14:01 +0100 Subject: 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(-) (limited to 'sound') 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), -- cgit v1.2.3 From c1325a2d5182f263f2edbc6e0c1e581e4c5d5a95 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 18 Jul 2023 10:04:18 +0300 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From 512d092d78823f9813f4af38090b33c454137a4c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Jul 2023 01:28:44 +0100 Subject: 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(-) (limited to 'sound') 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 -- cgit v1.2.3 From b7dc237ef8b0897f5750a738d2c57469909a6a15 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Jul 2023 01:28:46 +0100 Subject: 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 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'sound') 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 -- cgit v1.2.3 From df4167d658d45946677f91d84e9d40570c875cb8 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 18 Jul 2023 15:46:25 +0100 Subject: 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 --- sound/soc/codecs/cs35l56-shared.c | 38 ++++++++++++++++---------------------- sound/soc/codecs/cs35l56.c | 5 +++-- 2 files changed, 19 insertions(+), 24 deletions(-) (limited to 'sound') 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 @@ post_soft_reset: 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); -- cgit v1.2.3 From 4edc07fc7fe1a9eec1a4ebc518d2dec222382f43 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 19 Jul 2023 15:08:37 +0200 Subject: 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(+) (limited to 'sound') 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. -- cgit v1.2.3 From 30019d220cf9ec4df4e5f5d9082baf5519516018 Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Thu, 6 Jul 2023 14:41:23 +0800 Subject: 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(+) (limited to 'sound') 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] = { -- cgit v1.2.3 From 82e7c8b93a0614b1725e0ea11d0a77b04e058716 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Wed, 5 Jul 2023 21:03:22 +0200 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From 65bc25b8d0904e0aff66b1c3a9dd4c0dcb8efbf1 Mon Sep 17 00:00:00 2001 From: Matus Gajdos Date: Wed, 19 Jul 2023 18:31:53 +0200 Subject: 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(-) (limited to 'sound') 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 @@ out: 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 | \ -- cgit v1.2.3 From d4e99962d16ce60ac9ecf995489dc60d7854f1bd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:12:54 +0200 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From d8b366c40638d5aedad74646707b2b04b7342210 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:12:56 +0200 Subject: 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(-) (limited to 'sound') 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; -- cgit v1.2.3 From 192c4cccd015f52c94d0420eb5d7305a1ca28998 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:12:57 +0200 Subject: 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(-) (limited to 'sound') 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 */ -- cgit v1.2.3 From 8320ba0ce534dea603b7ba22f484ee39ef2ce746 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:12:58 +0200 Subject: 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(+) (limited to 'sound') 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; -- cgit v1.2.3 From a3bee62e90d8fdfdbd325323106de00b3e3a729f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:12:59 +0200 Subject: 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(-) (limited to 'sound') 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); } /** -- cgit v1.2.3 From 6723670a483501497dc339ae37676525245a913a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:13:01 +0200 Subject: 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 --- sound/core/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') 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; -- cgit v1.2.3 From b1e055f67611daf098e27e8731386eeb5257bde3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:13:02 +0200 Subject: 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 --- 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 +- 5 files changed, 58 insertions(+), 27 deletions(-) (limited to 'sound') 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; -- cgit v1.2.3 From 9c2cc5652e4390bd4492433d96ad4caa785b09de Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:13:03 +0200 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From 3315cf95834fb5d612f6a5eb718c3620b80dd05e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Jul 2023 16:13:04 +0200 Subject: 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(-) (limited to 'sound') 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; -- cgit v1.2.3 From 97f29c1a6143762626f4f9bd9fc2f8a2282b9dcd Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 18 Jul 2023 13:40:16 +0200 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From 5c0f9652da47061ed3f7815c1dfeb205c545ce54 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 18 Jul 2023 13:40:17 +0200 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From 7affe6fd2a3a75ad0f052bc7e9965b38807bb113 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:20:59 +0200 Subject: 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(-) (limited to 'sound') 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); } -- cgit v1.2.3 From f45828d464566140ee18089d0255199ba06db24a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:21:00 +0200 Subject: 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(-) (limited to 'sound') 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) { -- cgit v1.2.3 From aa9e91806517399da497f4d38912c66ca44ed2f7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:21:01 +0200 Subject: 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(-) (limited to 'sound') 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; -- cgit v1.2.3 From 5f2a937bd15614ad1836aacea06c6a1f49734859 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:21:02 +0200 Subject: 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(-) (limited to 'sound') 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; -- cgit v1.2.3 From 171c983027c7790d44902531e7e90ab01bee3b17 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:21:03 +0200 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From 233913c0bc60cf2ce68d5399da430b872c813a5e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:21:04 +0200 Subject: 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(-) (limited to 'sound') 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; -- cgit v1.2.3 From a16ea09d2254a03dca61818c884a6c36233f63dc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:21:05 +0200 Subject: 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(-) (limited to 'sound') 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)); -- cgit v1.2.3 From b6ba0aa46138a9dd0ebad718f761814d6071605d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:21:06 +0200 Subject: 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(-) (limited to 'sound') 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; } -- cgit v1.2.3 From ca141fe31df06fd5769e3d1d41e2a7b68b308243 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:21:07 +0200 Subject: 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(-) (limited to 'sound') 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 -- cgit v1.2.3 From ebc1bfebdacab9e7fd77eec2c5dbcef73980ab00 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Jul 2023 10:21:08 +0200 Subject: 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(-) (limited to 'sound') 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 */ -- cgit v1.2.3 From ae07eb9bf23e1a52cdb28222a71eb014131018d8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Jul 2023 09:16:40 +0200 Subject: 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 --- sound/core/vmaster.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'sound') 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 */ -- cgit v1.2.3 From 1caf64d91f72321191f7dc24d8e950222acc9bfa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Jul 2023 09:16:41 +0200 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From b7bb11fa361f4319b1bbf7cc390ef4dd83236be3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Jul 2023 09:16:42 +0200 Subject: 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(-) (limited to 'sound') 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"); -- cgit v1.2.3 From 157ac57073bc33396ed719bfdcdccb72798a822d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Jul 2023 09:16:43 +0200 Subject: 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(-) (limited to 'sound') 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 */ -- cgit v1.2.3 From 8cf2e3b1961e59dabc75e9e917d58439164a8f84 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 21 Jul 2023 16:24:02 +0800 Subject: 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(+) (limited to 'sound') 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[] = { -- cgit v1.2.3 From 3c851b6384729d60b968cd37a03382bf50acb92b Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 21 Jul 2023 16:57:21 +0300 Subject: 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(-) (limited to 'sound') 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), -- cgit v1.2.3 From 6d37a07fdcf9431124cdbf030fbea99c4f352ead Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 21 Jul 2023 16:57:22 +0300 Subject: 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(+) (limited to 'sound') 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), -- cgit v1.2.3 From 898673b905b9318489430663083f629bc38c7461 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Fri, 21 Jul 2023 14:21:10 +0100 Subject: 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 --- 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 +- 6 files changed, 256 insertions(+), 258 deletions(-) (limited to 'sound') 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 @@ post_soft_reset: 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); -- cgit v1.2.3 From cf6e7486de80b680fe178a6517dd7c4166a12dbc Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Fri, 21 Jul 2023 14:21:11 +0100 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From 0a2e49230f7f1796aa79c532426d56e8739ee4b1 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Fri, 21 Jul 2023 14:21:12 +0100 Subject: 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(-) (limited to 'sound') 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 @@ err: } 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); -- cgit v1.2.3 From 8a731fd37f8b33026e545f5ee5cdd7b9a837cbeb Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Fri, 21 Jul 2023 14:21:13 +0100 Subject: 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 --- sound/soc/codecs/cs35l56-shared.c | 208 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/cs35l56.c | 203 ------------------------------------- 2 files changed, 208 insertions(+), 203 deletions(-) (limited to 'sound') 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 @@ err: } 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); -- cgit v1.2.3 From 9974d5b57697770cba2a99c6fe925d01152cd544 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 21 Jul 2023 14:21:14 +0100 Subject: 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 --- 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 - 4 files changed, 124 insertions(+), 120 deletions(-) (limited to 'sound') 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,131 +849,19 @@ 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); -} - -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; + return cs35l56_runtime_resume_common(&cs35l56->base, false); } -EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, SND_SOC_CS35L56_CORE); int cs35l56_system_suspend(struct device *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); -- cgit v1.2.3 From 22e51dbb257a218e43de42764b5bdc5302f27cd1 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 21 Jul 2023 14:21:15 +0100 Subject: 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 --- sound/soc/codecs/cs35l56-shared.c | 18 ++++++++++++++++-- sound/soc/codecs/cs35l56.c | 11 +---------- 2 files changed, 17 insertions(+), 12 deletions(-) (limited to 'sound') 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 @@ err: } 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); -- cgit v1.2.3 From 84851aa055c890f2ea731a128e8feb64520c2c8e Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 21 Jul 2023 14:21:16 +0100 Subject: 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 --- sound/soc/codecs/cs35l56-shared.c | 79 +++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/cs35l56.c | 71 +---------------------------------- 2 files changed, 81 insertions(+), 69 deletions(-) (limited to 'sound') 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"); - 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"); + ret = cs35l56_hw_init(&cs35l56->base); + if (ret < 0) 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; -- cgit v1.2.3 From f32a2bcbc092d60ba8a1b00a22607b220d53a25e Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Fri, 21 Jul 2023 14:21:17 +0100 Subject: 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 --- sound/soc/codecs/cs35l56-shared.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'sound') 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 -- cgit v1.2.3 From 444dfa0912639fb2431553e8e54d2b35fdf590c2 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Fri, 21 Jul 2023 14:21:18 +0100 Subject: 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 --- sound/soc/codecs/cs35l56-shared.c | 26 ++++++++++++++++++++++++++ sound/soc/codecs/cs35l56.c | 17 +---------------- 2 files changed, 27 insertions(+), 16 deletions(-) (limited to 'sound') 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) { -- cgit v1.2.3 From 64e05321506261b737abdbfc7a82144f30d0a925 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 21 Jul 2023 14:21:19 +0100 Subject: 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(+) (limited to 'sound') 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 { -- cgit v1.2.3 From 73cfbfa9caea8eda54b4c6e49a9555533660aa1e Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Fri, 21 Jul 2023 14:21:20 +0100 Subject: 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 (limited to 'sound') 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"); -- cgit v1.2.3 From f54e3474507427bf272bcc79c7c248c7f55d45b4 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 21 Jul 2023 09:50:27 -0700 Subject: 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(-) (limited to 'sound') 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)) -- cgit v1.2.3 From fa3efcc36aacdd8ac9372217970d0ed2eb293fcc Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:06 +0100 Subject: 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 --- sound/pci/hda/cs35l41_hda.c | 9 +++-- sound/soc/codecs/cs35l41-lib.c | 76 +++++++++++++++++++++++++++++++++--------- sound/soc/codecs/cs35l41.c | 8 ++--- 3 files changed, 71 insertions(+), 22 deletions(-) (limited to 'sound') 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, -- cgit v1.2.3 From f8264c7592088727629e14f396f95ad643847740 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:07 +0100 Subject: 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(-) (limited to 'sound') 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)); -- cgit v1.2.3 From 5299b79ca1a2a9b017b87da08563100b0da98e5b Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:08 +0100 Subject: 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(-) (limited to 'sound') 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; -- cgit v1.2.3 From a3ff564658783e3cd9cc3098da4aebd89fe07d74 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:09 +0100 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From f2a58481a5051704390c2d7653b07ab3d97782da Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:10 +0100 Subject: 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(-) (limited to 'sound') 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); } -- cgit v1.2.3 From a5adbfb60b0299e788189aa8f88d8fa0dafb9d65 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:11 +0100 Subject: 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(-) (limited to 'sound') 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) { -- cgit v1.2.3 From 4eae4892c5bdef990b4b80997b813e2443d6554c Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:12 +0100 Subject: 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(-) (limited to 'sound') 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 { -- cgit v1.2.3 From 01ecc562936439cf6dd08b5f8c6bbed2704d9f9e Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:13 +0100 Subject: 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 | 53 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 10 deletions(-) (limited to 'sound') 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); - mutex_lock(&cs35l41->fw_mutex); - cs35l41_hda_play_start(dev); - mutex_unlock(&cs35l41->fw_mutex); break; case HDA_GEN_PCM_ACT_PREPARE: mutex_lock(&cs35l41->fw_mutex); - cs35l41_hda_play_done(dev); + 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_start(dev); + cs35l41_hda_pause_done(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); - + /* + * 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: - dev_warn(cs35l41->dev, "Playback action not supported: %d\n", action); + 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; + default: 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); -- cgit v1.2.3 From c4d0510b81c430249ee69c0554bb7ce4fa3d539e Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:14 +0100 Subject: 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(-) (limited to 'sound') 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 @@ err: 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); -- cgit v1.2.3 From 7cf5ce66dfda2be444ea668c3d48f732ba4a7fd1 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:15 +0100 Subject: 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(-) (limited to 'sound') 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 = { -- cgit v1.2.3 From 2d816d4f92086ca0a7b79198794012076b4cab0b Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 21 Jul 2023 16:18:16 +0100 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From 4005d1ba0a7e5cf32f669bf0014dca0dd12c2a44 Mon Sep 17 00:00:00 2001 From: Peter Suti Date: Thu, 13 Jul 2023 11:52:58 +0200 Subject: ASoC: soc-dai: don't call PCM audio ops if the stream is not supported PCM audio ops may be called when the stream is not supported. We should not call the ops in that case to avoid unexpected behavior. hw_params is handled already in soc-pcm.c [0] https://lore.kernel.org/alsa-devel/ae06b00a-f3f7-f9d1-0b58-4d71f3394416@linux.intel.com/T/#t Signed-off-by: Peter Suti Link: https://lore.kernel.org/r/20230713095258.3393827-1-peter.suti@streamunlimited.com Signed-off-by: Mark Brown --- sound/soc/soc-dai.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 02dd64dea179..73a97ac6ccb8 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -424,6 +424,9 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai, { int ret = 0; + if (!snd_soc_dai_stream_valid(dai, substream->stream)) + return 0; + if (dai->driver->ops && dai->driver->ops->startup) ret = dai->driver->ops->startup(substream, dai); @@ -439,6 +442,9 @@ void snd_soc_dai_shutdown(struct snd_soc_dai *dai, struct snd_pcm_substream *substream, int rollback) { + if (!snd_soc_dai_stream_valid(dai, substream->stream)) + return; + if (rollback && !soc_dai_mark_match(dai, substream, startup)) return; @@ -603,6 +609,8 @@ int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream) int i, ret; for_each_rtd_dais(rtd, i, dai) { + if (!snd_soc_dai_stream_valid(dai, substream->stream)) + continue; if (dai->driver->ops && dai->driver->ops->prepare) { ret = dai->driver->ops->prepare(substream, dai); @@ -619,6 +627,9 @@ static int soc_dai_trigger(struct snd_soc_dai *dai, { int ret = 0; + if (!snd_soc_dai_stream_valid(dai, substream->stream)) + return 0; + if (dai->driver->ops && dai->driver->ops->trigger) ret = dai->driver->ops->trigger(substream, cmd, dai); -- cgit v1.2.3 From 4ddad00c609bdcd6635537d3acb9bd57a5fc79e6 Mon Sep 17 00:00:00 2001 From: Zhu Ning Date: Mon, 17 Jul 2023 11:32:19 +0800 Subject: ASoC: codecs: ES8326: Change Hp_detect register names The old register naming method is confusing. The reg 0x57 decides the default headset hardware connection type, and the reg 0xfb is the headset detection status register, which changes during headset insertion. Change the name to ES8326_HPDET_TYPE and ES8326_HPDET_STA. Signed-off-by: Zhu Ning Link: https://lore.kernel.org/r/20230717033223.42506-1-zhuning0077@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 10 +++++----- sound/soc/codecs/es8326.h | 13 ++++++++----- 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index a7fbb758eeee..b62fff48f70c 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -159,7 +159,7 @@ static const struct snd_soc_dapm_route es8326_dapm_routes[] = { }; static const struct regmap_range es8326_volatile_ranges[] = { - regmap_reg_range(ES8326_HP_DETECT, ES8326_HP_DETECT), + regmap_reg_range(ES8326_HPDET_STA, ES8326_HPDET_STA), }; static const struct regmap_access_table es8326_volatile_table = { @@ -519,7 +519,7 @@ static void es8326_jack_button_handler(struct work_struct *work) return; mutex_lock(&es8326->lock); - iface = snd_soc_component_read(comp, ES8326_HP_DETECT); + iface = snd_soc_component_read(comp, ES8326_HPDET_STA); switch (iface) { case 0x93: /* pause button detected */ @@ -578,7 +578,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) unsigned int iface; mutex_lock(&es8326->lock); - iface = snd_soc_component_read(comp, ES8326_HP_DETECT); + iface = snd_soc_component_read(comp, ES8326_HPDET_STA); dev_dbg(comp->dev, "gpio flag %#04x", iface); if ((iface & ES8326_HPINSERT_FLAG) == 0) { /* Jack unplugged or spurious IRQ */ @@ -651,7 +651,7 @@ static int es8326_resume(struct snd_soc_component *component) regmap_write(es8326->regmap, ES8326_ADC1_SRC, es8326->mic1_src); regmap_write(es8326->regmap, ES8326_ADC2_SRC, es8326->mic2_src); regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88); - regmap_write(es8326->regmap, ES8326_HP_DET, + regmap_write(es8326->regmap, ES8326_HPDET_TYPE, ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol); regmap_write(es8326->regmap, ES8326_INT_SOURCE, es8326->interrupt_src); regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk); @@ -743,7 +743,7 @@ static void es8326_enable_jack_detect(struct snd_soc_component *component, mutex_lock(&es8326->lock); if (es8326->jd_inverted) - snd_soc_component_update_bits(component, ES8326_HP_DET, + snd_soc_component_update_bits(component, ES8326_HPDET_TYPE, ES8326_HP_DET_JACK_POL, ~es8326->jack_pol); es8326->jack = jack; diff --git a/sound/soc/codecs/es8326.h b/sound/soc/codecs/es8326.h index 3f8f7da58062..cd04d11a88d9 100644 --- a/sound/soc/codecs/es8326.h +++ b/sound/soc/codecs/es8326.h @@ -73,15 +73,19 @@ #define ES8326_DRC_RECOVERY 0x53 #define ES8326_DRC_WINSIZE 0x54 #define ES8326_HPJACK_TIMER 0x56 -#define ES8326_HP_DET 0x57 +#define ES8326_HPDET_TYPE 0x57 #define ES8326_INT_SOURCE 0x58 #define ES8326_INTOUT_IO 0x59 #define ES8326_SDINOUT1_IO 0x5A #define ES8326_SDINOUT23_IO 0x5B #define ES8326_JACK_PULSE 0x5C +#define ES8326_HP_MISC 0xF7 +#define ES8326_CTIA_OMTP_STA 0xF8 #define ES8326_PULLUP_CTL 0xF9 -#define ES8326_HP_DETECT 0xFB +#define ES8326_CSM_I2C_STA 0xFA +#define ES8326_HPDET_STA 0xFB +#define ES8326_CSM_MUTE_STA 0xFC #define ES8326_CHIP_ID1 0xFD #define ES8326_CHIP_ID2 0xFE #define ES8326_CHIP_VERSION 0xFF @@ -146,7 +150,7 @@ #define ES8326_ADC3_SHIFT 0 #define ES8326_ADC4_SHIFT 3 -/* ES8326_HP_DET */ +/* ES8326_HPDET_TYPE */ #define ES8326_HP_DET_SRC_PIN27 (1 << 5) #define ES8326_HP_DET_SRC_PIN9 (1 << 4) #define ES8326_HP_DET_JACK_POL (1 << 3) @@ -174,7 +178,7 @@ #define ES8326_SDINOUT2_SHIFT 4 #define ES8326_SDINOUT3_SHIFT 0 -/* ES8326_HP_DETECT */ +/* ES8326_HPDET_STA */ #define ES8326_HPINSERT_FLAG (1 << 1) #define ES8326_HPBUTTON_FLAG (1 << 0) @@ -182,4 +186,3 @@ #define ES8326_VERSION_B (1 << 0) #endif - -- cgit v1.2.3 From f1230a27c14b4d05e1d6af02be55c617b53728a4 Mon Sep 17 00:00:00 2001 From: Zhu Ning Date: Mon, 17 Jul 2023 11:32:20 +0800 Subject: ASoC: codecs: ES8326: Change Volatile Reg function The new calibration and headphone detection function require reading new volatile registers. Add them in the volatile register function. Signed-off-by: Zhu Ning Link: https://lore.kernel.org/r/20230717033223.42506-2-zhuning0077@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index b62fff48f70c..9f4408dcf3af 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -158,20 +158,25 @@ static const struct snd_soc_dapm_route es8326_dapm_routes[] = { {"HPOR", NULL, "RHPMIX"}, }; -static const struct regmap_range es8326_volatile_ranges[] = { - regmap_reg_range(ES8326_HPDET_STA, ES8326_HPDET_STA), -}; - -static const struct regmap_access_table es8326_volatile_table = { - .yes_ranges = es8326_volatile_ranges, - .n_yes_ranges = ARRAY_SIZE(es8326_volatile_ranges), -}; +static bool es8326_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ES8326_HPL_OFFSET_INI: + case ES8326_HPR_OFFSET_INI: + case ES8326_HPDET_STA: + case ES8326_CTIA_OMTP_STA: + case ES8326_CSM_MUTE_STA: + return true; + default: + return false; + } +} static const struct regmap_config es8326_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = 0xff, - .volatile_table = &es8326_volatile_table, + .volatile_reg = es8326_volatile_register, .cache_type = REGCACHE_RBTREE, }; -- cgit v1.2.3 From ac20a73d765c0374f5e7b5d0f2f43c4598d69c66 Mon Sep 17 00:00:00 2001 From: Zhu Ning Date: Mon, 17 Jul 2023 11:32:21 +0800 Subject: ASoC: codecs: ES8326: Fix power-up sequence Old power-up sequence causes large pop noise during start-up. Using a new sequence instead. Also, the registers are now reset to default value in suspend function. Signed-off-by: Zhu Ning Link: https://lore.kernel.org/r/20230717033223.42506-3-zhuning0077@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 95 +++++++++++++++++++++++++++++++++-------------- sound/soc/codecs/es8326.h | 10 ++++- 2 files changed, 77 insertions(+), 28 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index 9f4408dcf3af..ffb61a3cbfe4 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -638,40 +638,77 @@ out: static int es8326_resume(struct snd_soc_component *component) { struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); - unsigned int reg; regcache_cache_only(es8326->regmap, false); regcache_sync(es8326->regmap); + /* reset internal clock state */ + regmap_write(es8326->regmap, ES8326_RESET, 0x1f); + regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x0E); + usleep_range(10000, 15000); + regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88); + /* set headphone default type and detect pin */ + regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x81); + regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05); + + /* set internal oscillator as clock source of headpone cp */ + regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x84); regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_ON); - /* Two channel ADC */ - regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x02); + /* clock manager reset release */ + regmap_write(es8326->regmap, ES8326_RESET, 0x17); + /* set headphone detection as half scan mode */ + regmap_write(es8326->regmap, ES8326_HP_MISC, 0x08); + regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x00); + + /* enable headphone driver */ + regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa7); + usleep_range(2000, 5000); + regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xab); + usleep_range(2000, 5000); + regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xbb); + usleep_range(2000, 5000); + regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa1); + regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00); - regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x1F); - regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xC8); - regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x88); - regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x20); + regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xc4); + regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x81); + regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x00); + + /* turn off headphone out */ + regmap_write(es8326->regmap, ES8326_HP_CAL, 0x00); + /* set ADC and DAC in low power mode */ + regmap_write(es8326->regmap, ES8326_ANA_LP, 0xf0); + + /* force micbias on */ + regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0x4f); regmap_write(es8326->regmap, ES8326_SYS_BIAS, 0x08); - regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x22); - regmap_write(es8326->regmap, ES8326_ADC1_SRC, es8326->mic1_src); - regmap_write(es8326->regmap, ES8326_ADC2_SRC, es8326->mic2_src); - regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88); - regmap_write(es8326->regmap, ES8326_HPDET_TYPE, - ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol); - regmap_write(es8326->regmap, ES8326_INT_SOURCE, es8326->interrupt_src); - regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk); + regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F); + /* select vdda as micbias source */ + regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x23); + /* set dac dsmclip = 1 */ + regmap_write(es8326->regmap, ES8326_DAC_DSM, 0x08); + regmap_write(es8326->regmap, ES8326_DAC_VPPSCALE, 0x15); + + regmap_write(es8326->regmap, ES8326_INT_SOURCE, + (ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON)); + regmap_write(es8326->regmap, ES8326_INTOUT_IO, + es8326->interrupt_clk); + regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, + (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT)); + regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT); + + regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x3b); regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON); - snd_soc_component_update_bits(component, ES8326_PGAGAIN, - ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL); - - regmap_read(es8326->regmap, ES8326_CHIP_VERSION, ®); - if ((reg & ES8326_VERSION_B) == 1) { - regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0xDD); - regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F); - regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x0F); - /* enable button detect */ - regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xA0); - } + regmap_update_bits(es8326->regmap, ES8326_PGAGAIN, ES8326_MIC_SEL_MASK, + ES8326_MIC1_SEL); + + regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE, ES8326_MUTE_MASK, + ES8326_MUTE); + + regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x80 | + ((es8326->version == ES8326_VERSION_B) ? + (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol) : + (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol | 0x04))); es8326_irq(es8326->irq, es8326); return 0; @@ -688,6 +725,10 @@ static int es8326_suspend(struct snd_soc_component *component) regcache_cache_only(es8326->regmap, true); regcache_mark_dirty(es8326->regmap); + /* reset register value to default */ + regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x01); + usleep_range(1000, 3000); + regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x00); return 0; } @@ -717,7 +758,7 @@ static int es8326_probe(struct snd_soc_component *component) ret = device_property_read_u8(component->dev, "everest,jack-pol", &es8326->jack_pol); if (ret != 0) { dev_dbg(component->dev, "jack-pol return %d", ret); - es8326->jack_pol = ES8326_HP_DET_BUTTON_POL | ES8326_HP_TYPE_OMTP; + es8326->jack_pol = ES8326_HP_TYPE_AUTO; } dev_dbg(component->dev, "jack-pol %x", es8326->jack_pol); diff --git a/sound/soc/codecs/es8326.h b/sound/soc/codecs/es8326.h index cd04d11a88d9..90a08351d6ac 100644 --- a/sound/soc/codecs/es8326.h +++ b/sound/soc/codecs/es8326.h @@ -160,6 +160,13 @@ #define ES8326_HP_TYPE_AUTO (1 << 0) #define ES8326_HP_TYPE_AUTO_INV (0 << 0) +/* ES8326_INT_SOURCE */ +#define ES8326_INT_SRC_DAC_MOZ (1 << 0) +#define ES8326_INT_SRC_ADC_MOZ (1 << 1) +#define ES8326_INT_SRC_BUTTON (1 << 2) +#define ES8326_INT_SRC_PIN9 (1 << 3) +#define ES8326_INT_SRC_PIN27 (1 << 4) + /* ES8326_SDINOUT1_IO */ #define ES8326_IO_INPUT (0 << 0) #define ES8326_IO_SDIN_SLOT0 (1 << 0) @@ -183,6 +190,7 @@ #define ES8326_HPBUTTON_FLAG (1 << 0) /* ES8326_CHIP_VERSION 0xFF */ -#define ES8326_VERSION_B (1 << 0) +#define ES8326_VERSION (1 << 0) +#define ES8326_VERSION_B (3 << 0) #endif -- cgit v1.2.3 From 0663286e58e6f611f3578b5e63e1faa576d139fd Mon Sep 17 00:00:00 2001 From: Zhu Ning Date: Mon, 17 Jul 2023 11:32:22 +0800 Subject: ASOC: codecs: ES8326: Add calibration support for version_b Version_b requires a new way of calibrating headset offset. A new calibration function is added. Signed-off-by: Zhu Ning Link: https://lore.kernel.org/r/20230717033223.42506-4-zhuning0077@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 83 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index ffb61a3cbfe4..8ffabc8cd33e 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -388,6 +388,7 @@ 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); + unsigned int offset_l, offset_r; if (mute) { regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF); @@ -398,10 +399,16 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction) if (!es8326->calibrated) { regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_FORCE_CAL); msleep(30); + regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF); + regmap_read(es8326->regmap, ES8326_HPL_OFFSET_INI, &offset_l); + regmap_read(es8326->regmap, ES8326_HPR_OFFSET_INI, &offset_r); + regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c); + regmap_write(es8326->regmap, ES8326_HPL_OFFSET_INI, offset_l); + regmap_write(es8326->regmap, ES8326_HPR_OFFSET_INI, offset_r); 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_VOL, 0x80); regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_ON); regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE, ES8326_MUTE_MASK, ~(ES8326_MUTE)); @@ -420,15 +427,17 @@ static int es8326_set_bias_level(struct snd_soc_component *codec, ret = clk_prepare_enable(es8326->mclk); if (ret) return ret; - regmap_write(es8326->regmap, ES8326_RESET, ES8326_PWRUP_SEQ_EN); - regmap_write(es8326->regmap, ES8326_INTOUT_IO, 0x45); + + regmap_write(es8326->regmap, ES8326_RESET, 0x9f); + msleep(20); + regmap_update_bits(es8326->regmap, ES8326_DAC_DSM, 0x01, 0x00); + regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk); regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT)); - regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT); - regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05); - regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x02); + regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x0E); regmap_write(es8326->regmap, ES8326_PGA_PDN, 0x40); - regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0xAA); + regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x00); + regmap_update_bits(es8326->regmap, ES8326_CLK_CTL, 0x20, 0x20); regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON); break; case SND_SOC_BIAS_PREPARE: @@ -437,15 +446,10 @@ static int es8326_set_bias_level(struct snd_soc_component *codec, break; case SND_SOC_BIAS_OFF: clk_disable_unprepare(es8326->mclk); - regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x11); - regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_OFF); - regmap_write(es8326->regmap, ES8326_PGA_PDN, 0xF8); + regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x3b); regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x00); - regmap_write(es8326->regmap, ES8326_INT_SOURCE, 0x08); + regmap_update_bits(es8326->regmap, ES8326_CLK_CTL, 0x20, 0x00); regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, ES8326_IO_INPUT); - regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT); - regmap_write(es8326->regmap, ES8326_RESET, - ES8326_CODEC_RESET | ES8326_PWRUP_SEQ_EN); break; } @@ -635,6 +639,54 @@ out: return IRQ_HANDLED; } +static int es8326_calibrate(struct snd_soc_component *component) +{ + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); + unsigned int reg; + unsigned int offset_l, offset_r; + + regmap_read(es8326->regmap, ES8326_CHIP_VERSION, ®); + es8326->version = reg; + + if ((es8326->version == ES8326_VERSION_B) && (es8326->calibrated == false)) { + dev_dbg(component->dev, "ES8326_VERSION_B, calibrating\n"); + regmap_write(es8326->regmap, ES8326_CLK_INV, 0xc0); + regmap_write(es8326->regmap, ES8326_CLK_DIV1, 0x01); + regmap_write(es8326->regmap, ES8326_CLK_DLL, 0x30); + regmap_write(es8326->regmap, ES8326_CLK_MUX, 0xed); + regmap_write(es8326->regmap, ES8326_CLK_TRI, 0xc1); + regmap_write(es8326->regmap, ES8326_DAC_MUTE, 0x03); + regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7f); + regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x33); + regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x88); + regmap_write(es8326->regmap, ES8326_HP_VOL, 0x80); + regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c); + regmap_write(es8326->regmap, ES8326_RESET, 0xc0); + usleep_range(15000, 20000); + + regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, ES8326_HP_OFF); + regmap_read(es8326->regmap, ES8326_CSM_MUTE_STA, ®); + if ((reg & 0xf0) != 0x40) + msleep(50); + + regmap_write(es8326->regmap, ES8326_HP_CAL, 0xd4); + msleep(200); + regmap_write(es8326->regmap, ES8326_HP_CAL, 0x4d); + msleep(200); + regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF); + regmap_read(es8326->regmap, ES8326_HPL_OFFSET_INI, &offset_l); + regmap_read(es8326->regmap, ES8326_HPR_OFFSET_INI, &offset_r); + regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c); + regmap_write(es8326->regmap, ES8326_HPL_OFFSET_INI, offset_l); + regmap_write(es8326->regmap, ES8326_HPR_OFFSET_INI, offset_r); + regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00); + + es8326->calibrated = true; + } + + return 0; +} + static int es8326_resume(struct snd_soc_component *component) { struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); @@ -673,7 +725,8 @@ static int es8326_resume(struct snd_soc_component *component) regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xc4); regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x81); regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x00); - + /* calibrate for B version */ + es8326_calibrate(component); /* turn off headphone out */ regmap_write(es8326->regmap, ES8326_HP_CAL, 0x00); /* set ADC and DAC in low power mode */ -- cgit v1.2.3 From 04f96c9340463aae20d2511a3d6cb0b005b07d24 Mon Sep 17 00:00:00 2001 From: Zhu Ning Date: Mon, 17 Jul 2023 11:32:23 +0800 Subject: ASoC: codecs: ES8326: Update jact detection function The old jack detection function only supports fixed OMTP/CTIA hardware connection. The new one supports auto OMTP/CTIA headset detection Signed-off-by: Zhu Ning Link: https://lore.kernel.org/r/20230717033223.42506-5-zhuning0077@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 109 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 89 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index 8ffabc8cd33e..6c263086c44d 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -41,6 +41,8 @@ struct es8326_priv { bool calibrated; int version; + int hp; + int jack_remove_retry; }; static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9550, 50, 0); @@ -535,6 +537,7 @@ static void es8326_jack_button_handler(struct work_struct *work) cur_button = SND_JACK_BTN_0; break; case 0x6f: + case 0x4b: /* button volume up */ cur_button = SND_JACK_BTN_1; break; @@ -543,6 +546,7 @@ static void es8326_jack_button_handler(struct work_struct *work) cur_button = SND_JACK_BTN_2; break; case 0x1e: + case 0xe2: /* button released or not pressed */ cur_button = 0; break; @@ -552,20 +556,20 @@ static void es8326_jack_button_handler(struct work_struct *work) if ((prev_button == cur_button) && (cur_button != 0)) { press_count++; - if (press_count > 10) { - /* report a press every 500ms */ + if (press_count > 3) { + /* report a press every 120ms */ snd_soc_jack_report(es8326->jack, cur_button, SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2); press_count = 0; } button_to_report = cur_button; queue_delayed_work(system_wq, &es8326->button_press_work, - msecs_to_jiffies(50)); + msecs_to_jiffies(35)); } else if (prev_button != cur_button) { /* mismatch, detect again */ prev_button = cur_button; queue_delayed_work(system_wq, &es8326->button_press_work, - msecs_to_jiffies(50)); + msecs_to_jiffies(35)); } else { /* released or no pressed */ if (button_to_report != 0) { @@ -589,32 +593,96 @@ static void es8326_jack_detect_handler(struct work_struct *work) mutex_lock(&es8326->lock); iface = snd_soc_component_read(comp, ES8326_HPDET_STA); dev_dbg(comp->dev, "gpio flag %#04x", iface); + + if (es8326->jack_remove_retry == 1) { + if (iface & ES8326_HPINSERT_FLAG) + es8326->jack_remove_retry = 2; + else + es8326->jack_remove_retry = 0; + + dev_dbg(comp->dev, "remove event check, set HPJACK_POL normal, cnt = %d\n", + es8326->jack_remove_retry); + /* + * Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event + */ + regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, + ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ? + ~es8326->jack_pol : es8326->jack_pol)); + goto exit; + } + if ((iface & ES8326_HPINSERT_FLAG) == 0) { /* Jack unplugged or spurious IRQ */ - dev_dbg(comp->dev, "No headset detected"); + dev_dbg(comp->dev, "No headset detected\n"); + es8326_disable_micbias(es8326->component); if (es8326->jack->status & SND_JACK_HEADPHONE) { + dev_dbg(comp->dev, "Report hp remove event\n"); snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET); - snd_soc_component_write(comp, ES8326_ADC1_SRC, es8326->mic2_src); - es8326_disable_micbias(comp); + /* mute adc when mic path switch */ + regmap_write(es8326->regmap, ES8326_ADC_SCALE, 0x33); + regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x44); + regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x66); + es8326->hp = 0; + } + regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01); + /* + * Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event + */ + if (es8326->jack_remove_retry == 0) { + es8326->jack_remove_retry = 1; + dev_dbg(comp->dev, "remove event check, invert HPJACK_POL, cnt = %d\n", + es8326->jack_remove_retry); + regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, + ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ? + es8326->jack_pol : ~es8326->jack_pol)); + + } else { + es8326->jack_remove_retry = 0; } } else if ((iface & ES8326_HPINSERT_FLAG) == ES8326_HPINSERT_FLAG) { + es8326->jack_remove_retry = 0; + if (es8326->hp == 0) { + dev_dbg(comp->dev, "First insert, start OMTP/CTIA type check\n"); + /* + * set auto-check mode, then restart jack_detect_work after 100ms. + * Don't report jack status. + */ + regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01); + usleep_range(50000, 70000); + regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00); + queue_delayed_work(system_wq, &es8326->jack_detect_work, + msecs_to_jiffies(100)); + es8326->hp = 1; + goto exit; + } if (es8326->jack->status & SND_JACK_HEADSET) { /* detect button */ + dev_dbg(comp->dev, "button pressed\n"); queue_delayed_work(system_wq, &es8326->button_press_work, 10); + goto exit; + } + if ((iface & ES8326_HPBUTTON_FLAG) == 0x01) { + dev_dbg(comp->dev, "Headphone detected\n"); + snd_soc_jack_report(es8326->jack, + SND_JACK_HEADPHONE, SND_JACK_HEADSET); } else { - if ((iface & ES8326_HPBUTTON_FLAG) == 0x00) { - dev_dbg(comp->dev, "Headset detected"); - snd_soc_jack_report(es8326->jack, - SND_JACK_HEADSET, SND_JACK_HEADSET); - snd_soc_component_write(comp, - ES8326_ADC1_SRC, es8326->mic1_src); - } else { - dev_dbg(comp->dev, "Headphone detected"); - snd_soc_jack_report(es8326->jack, - SND_JACK_HEADPHONE, SND_JACK_HEADSET); - } + dev_dbg(comp->dev, "Headset detected\n"); + snd_soc_jack_report(es8326->jack, + SND_JACK_HEADSET, SND_JACK_HEADSET); + + regmap_write(es8326->regmap, ES8326_ADC_SCALE, 0x33); + regmap_update_bits(es8326->regmap, ES8326_PGA_PDN, + 0x08, 0x08); + regmap_update_bits(es8326->regmap, ES8326_PGAGAIN, + 0x80, 0x80); + regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x00); + regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x00); + regmap_update_bits(es8326->regmap, ES8326_PGA_PDN, + 0x08, 0x00); + usleep_range(10000, 15000); } } +exit: mutex_unlock(&es8326->lock); } @@ -633,7 +701,7 @@ static irqreturn_t es8326_irq(int irq, void *dev_id) msecs_to_jiffies(10)); else queue_delayed_work(system_wq, &es8326->jack_detect_work, - msecs_to_jiffies(300)); + msecs_to_jiffies(600)); out: return IRQ_HANDLED; @@ -763,7 +831,8 @@ static int es8326_resume(struct snd_soc_component *component) (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol) : (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol | 0x04))); - es8326_irq(es8326->irq, es8326); + es8326->jack_remove_retry = 0; + es8326->hp = 0; return 0; } -- cgit v1.2.3 From 2b7aecd58528551e6e3da58091ff7ceb4718e6be Mon Sep 17 00:00:00 2001 From: Derek Fang Date: Tue, 18 Jul 2023 16:42:38 +0800 Subject: ASoC: rt1017: Add RT1017 SDCA amplifier driver This is the initial amplifier driver for rt1017 SDCA version. Signed-off-by: Derek Fang Link: https://lore.kernel.org/r/20230718084238.3692-1-derek.fang@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 6 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt1017-sdca-sdw.c | 824 +++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt1017-sdca-sdw.h | 188 +++++++++ 4 files changed, 1020 insertions(+) create mode 100644 sound/soc/codecs/rt1017-sdca-sdw.c create mode 100644 sound/soc/codecs/rt1017-sdca-sdw.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 88c3dbe47d71..8aba442d1978 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -184,6 +184,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT1015 imply SND_SOC_RT1015P imply SND_SOC_RT1016 + imply SND_SOC_RT1017_SDCA_SDW imply SND_SOC_RT1019 imply SND_SOC_RT1305 imply SND_SOC_RT1308 @@ -1428,6 +1429,11 @@ config SND_SOC_RT1016 tristate depends on I2C +config SND_SOC_RT1017_SDCA_SDW + tristate "Realtek RT1017 SDCA Codec - SDW" + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + config SND_SOC_RT1019 tristate depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 32dcc6de58bd..be367839cfa4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -205,6 +205,7 @@ snd-soc-rt1011-objs := rt1011.o snd-soc-rt1015-objs := rt1015.o snd-soc-rt1015p-objs := rt1015p.o snd-soc-rt1016-objs := rt1016.o +snd-soc-rt1017-sdca-objs := rt1017-sdca-sdw.o snd-soc-rt1019-objs := rt1019.o snd-soc-rt1305-objs := rt1305.o snd-soc-rt1308-objs := rt1308.o @@ -583,6 +584,7 @@ obj-$(CONFIG_SND_SOC_RT1011) += snd-soc-rt1011.o obj-$(CONFIG_SND_SOC_RT1015) += snd-soc-rt1015.o obj-$(CONFIG_SND_SOC_RT1015P) += snd-soc-rt1015p.o obj-$(CONFIG_SND_SOC_RT1016) += snd-soc-rt1016.o +obj-$(CONFIG_SND_SOC_RT1017_SDCA_SDW) += snd-soc-rt1017-sdca.o obj-$(CONFIG_SND_SOC_RT1019) += snd-soc-rt1019.o obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c new file mode 100644 index 000000000000..7295f44c77eb --- /dev/null +++ b/sound/soc/codecs/rt1017-sdca-sdw.c @@ -0,0 +1,824 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt1017-sdca-sdw.c -- rt1017 SDCA ALSA SoC amplifier audio driver +// +// Copyright(c) 2023 Realtek Semiconductor Corp. +// +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt1017-sdca-sdw.h" + +static bool rt1017_sdca_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2f55: + case 0x3206: + case 0xc000: + case 0xc001: + case 0xc022: + case 0xc030: + case 0xc104: + case 0xc10b: + case 0xc10c: + case 0xc110: + case 0xc112: + case 0xc300: + case 0xc301: + case 0xc318: + case 0xc325 ... 0xc328: + case 0xc331: + case 0xc340: + case 0xc350 ... 0xc351: + case 0xc500: + case 0xc502: + case 0xc504: + case 0xc507: + case 0xc509: + case 0xc510: + case 0xc512: + case 0xc518: + case 0xc51b: + case 0xc51d: + case 0xc520: + case 0xc540 ... 0xc542: + case 0xc550 ... 0xc552: + case 0xc600: + case 0xc602: + case 0xc612: + case 0xc622: + case 0xc632: + case 0xc642: + case 0xc651: + case 0xca00: + case 0xca09 ... 0xca0c: + case 0xca0e ... 0xca0f: + case 0xca10 ... 0xca11: + case 0xca16 ... 0xca17: + case 0xcb00: + case 0xcc00: + case 0xcc02: + case 0xd017: + case 0xd01a ... 0xd01c: + case 0xd101: + case 0xd20c: + case 0xd300: + case 0xd370: + case 0xd500: + case 0xd545 ... 0xd548: + case 0xd5a5 ... 0xd5a8: + case 0xd5aa ... 0xd5ad: + case 0xda04 ... 0xda07: + case 0xda09 ... 0xda0a: + case 0xda0c ... 0xda0f: + case 0xda11 ... 0xda14: + case 0xda16 ... 0xda19: + case 0xdab6 ... 0xdabb: + case 0xdb09 ... 0xdb0a: + case 0xdb14: + + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21, + RT1017_SDCA_CTL_UDMPU_CLUSTER, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU, + RT1017_SDCA_CTL_FU_MUTE, 0x01): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_XU22, + RT1017_SDCA_CTL_BYPASS, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_SAPU29, + RT1017_SDCA_CTL_PROT_STAT, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21, + RT1017_SDCA_CTL_FS_INDEX, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23, + RT1017_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE22, + RT1017_SDCA_CTL_REQ_POWER_STATE, 0): + return true; + default: + return false; + } +} + +static bool rt1017_sdca_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2f55: + case 0xc000: + case 0xc022: + case 0xc351: + case 0xc518: + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_SAPU29, + RT1017_SDCA_CTL_PROT_STAT, 0): + return true; + default: + return false; + } +} + +static const struct reg_sequence rt1017_blind_write[] = { + { 0xc001, 0x43 }, + { 0x2f55, 0x02 }, + { 0x3206, 0x80 }, + { 0x005f, 0x7f }, + { 0xd101, 0xa0 }, + { 0xc112, 0xc0 }, + { 0xc104, 0xaa }, + { 0xc110, 0x59 }, + { 0xc112, 0xc0 }, + { 0xc340, 0x80 }, + { 0xd017, 0x2c }, + { 0xd01a, 0xc8 }, + { 0xd01b, 0xcf }, + { 0xd01c, 0x0c }, + { 0xd20c, 0x14 }, + { 0xdb09, 0x0f }, + { 0xdb0a, 0x7f }, + { 0xdb14, 0x03 }, + { 0xcb00, 0x31 }, + { 0xc318, 0x44 }, + { 0xc325, 0xce }, + { 0xc326, 0x13 }, + { 0xc327, 0x5f }, + { 0xc328, 0xf3 }, + { 0xc350, 0xe1 }, + { 0xc351, 0x88 }, + { 0xc030, 0x14 }, + { 0xc331, 0xf2 }, + { 0xc551, 0x0f }, + { 0xc552, 0xff }, + { 0xc651, 0xc0 }, + { 0xc550, 0xd0 }, + { 0xc612, 0x00 }, + { 0xc622, 0x00 }, + { 0xc632, 0x00 }, + { 0xc642, 0x00 }, + { 0xc602, 0xf0 }, + { 0xc600, 0xd0 }, + { 0xcc02, 0x78 }, + { 0xcc00, 0x90 }, + { 0xc300, 0x3f }, + { 0xc301, 0x1d }, + { 0xc10b, 0x2e }, + { 0xc10c, 0x36 }, + + { 0xd5a5, 0x00 }, + { 0xd5a6, 0x6a }, + { 0xd5a7, 0xaa }, + { 0xd5a8, 0xaa }, + { 0xd5aa, 0x00 }, + { 0xd5ab, 0x16 }, + { 0xd5ac, 0xdb }, + { 0xd5ad, 0x6d }, + { 0xd545, 0x09 }, + { 0xd546, 0x30 }, + { 0xd547, 0xf0 }, + { 0xd548, 0xf0 }, + { 0xd500, 0x20 }, + { 0xc504, 0x3f }, + { 0xc540, 0x00 }, + { 0xc541, 0x0a }, + { 0xc542, 0x1a }, + { 0xc512, 0x00 }, + { 0xc520, 0x40 }, + { 0xc51b, 0x7f }, + { 0xc51d, 0x0f }, + { 0xc500, 0x40 }, + { 0xc502, 0xde }, + { 0xc507, 0x05 }, + { 0xc509, 0x05 }, + { 0xc510, 0x40 }, + { 0xc518, 0xc0 }, + { 0xc500, 0xc0 }, + + { 0xda0c, 0x00 }, + { 0xda0d, 0x0b }, + { 0xda0e, 0x55 }, + { 0xda0f, 0x55 }, + { 0xda04, 0x00 }, + { 0xda05, 0x51 }, + { 0xda06, 0xeb }, + { 0xda07, 0x85 }, + { 0xca16, 0x0f }, + { 0xca17, 0x00 }, + { 0xda09, 0x5d }, + { 0xda0a, 0xc0 }, + { 0xda11, 0x26 }, + { 0xda12, 0x66 }, + { 0xda13, 0x66 }, + { 0xda14, 0x66 }, + { 0xda16, 0x79 }, + { 0xda17, 0x99 }, + { 0xda18, 0x99 }, + { 0xda19, 0x99 }, + { 0xca09, 0x00 }, + { 0xca0a, 0x07 }, + { 0xca0b, 0x89 }, + { 0xca0c, 0x61 }, + { 0xca0e, 0x00 }, + { 0xca0f, 0x03 }, + { 0xca10, 0xc4 }, + { 0xca11, 0xb0 }, + { 0xdab6, 0x00 }, + { 0xdab7, 0x01 }, + { 0xdab8, 0x00 }, + { 0xdab9, 0x00 }, + { 0xdaba, 0x00 }, + { 0xdabb, 0x00 }, + { 0xd017, 0x0e }, + { 0xca00, 0xcd }, + { 0xc022, 0x84 }, +}; + +#define RT1017_MAX_REG_NUM 0x4108ffff + +static const struct regmap_config rt1017_sdca_regmap = { + .reg_bits = 32, + .val_bits = 8, + .readable_reg = rt1017_sdca_readable_register, + .volatile_reg = rt1017_sdca_volatile_register, + .max_register = RT1017_MAX_REG_NUM, + .reg_defaults = rt1017_sdca_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rt1017_sdca_reg_defaults), + .cache_type = REGCACHE_MAPLE, + .use_single_read = true, + .use_single_write = true, +}; + +static int rt1017_sdca_read_prop(struct sdw_slave *slave) +{ + struct sdw_slave_prop *prop = &slave->prop; + int nval; + int i, j; + u32 bit; + unsigned long addr; + struct sdw_dpn_prop *dpn; + + prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; + prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; + + prop->paging_support = true; + + /* first we need to allocate memory for set bits in port lists + * port = 1 for AMP playback + * port = 2 for IV capture + */ + prop->source_ports = BIT(2); /* BITMAP: 00000100 */ + prop->sink_ports = BIT(1); /* BITMAP: 00000010 */ + + nval = hweight32(prop->source_ports); + prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->src_dpn_prop), GFP_KERNEL); + if (!prop->src_dpn_prop) + return -ENOMEM; + + i = 0; + dpn = prop->src_dpn_prop; + addr = prop->source_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].type = SDW_DPN_FULL; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* do this again for sink now */ + nval = hweight32(prop->sink_ports); + prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->sink_dpn_prop), GFP_KERNEL); + if (!prop->sink_dpn_prop) + return -ENOMEM; + + j = 0; + dpn = prop->sink_dpn_prop; + addr = prop->sink_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[j].num = bit; + dpn[j].type = SDW_DPN_FULL; + dpn[j].simple_ch_prep_sm = true; + dpn[j].ch_prep_timeout = 10; + j++; + } + + /* set the timeout values */ + prop->clk_stop_timeout = 64; + + return 0; +} + +static int rt1017_sdca_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev); + + if (rt1017->hw_init) + return 0; + + if (rt1017->first_hw_init) { + regcache_cache_only(rt1017->regmap, false); + regcache_cache_bypass(rt1017->regmap, true); + } else { + /* + * PM runtime is only enabled when a Slave reports as Attached + */ + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(&slave->dev, 3000); + pm_runtime_use_autosuspend(&slave->dev); + + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(&slave->dev); + + pm_runtime_enable(&slave->dev); + } + + pm_runtime_get_noresume(&slave->dev); + + /* sw reset */ + regmap_write(rt1017->regmap, 0xc000, 0x02); + + /* initial settings - blind write */ + regmap_multi_reg_write(rt1017->regmap, rt1017_blind_write, + ARRAY_SIZE(rt1017_blind_write)); + + if (rt1017->first_hw_init) { + regcache_cache_bypass(rt1017->regmap, false); + regcache_mark_dirty(rt1017->regmap); + } else + rt1017->first_hw_init = true; + + /* Mark Slave initialization complete */ + rt1017->hw_init = true; + + pm_runtime_mark_last_busy(&slave->dev); + pm_runtime_put_autosuspend(&slave->dev); + + dev_dbg(&slave->dev, "hw_init complete\n"); + return 0; +} + +static int rt1017_sdca_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(&slave->dev); + + if (status == SDW_SLAVE_UNATTACHED) + rt1017->hw_init = false; + + /* + * Perform initialization only if slave status is present and + * hw_init flag is false + */ + if (rt1017->hw_init || status != SDW_SLAVE_ATTACHED) + return 0; + + /* perform I/O transfers required for Slave initialization */ + return rt1017_sdca_io_init(&slave->dev, slave); +} + +static const char * const rt1017_rx_data_ch_select[] = { + "Bypass", + "CN1", + "CN2", + "CN3", + "CN4", + "(1+2)/2", + "(1+3)/2", + "(1+4)/2", + "(2+3)/2", + "(2+4)/2", + "(3+4)/2", +}; + +static SOC_ENUM_SINGLE_DECL(rt1017_rx_data_ch_enum, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21, + RT1017_SDCA_CTL_UDMPU_CLUSTER, 0), + 0, rt1017_rx_data_ch_select); + +static const struct snd_kcontrol_new rt1017_sdca_controls[] = { + /* UDMPU Cluster Selection */ + SOC_ENUM("RX Channel Select", rt1017_rx_data_ch_enum), +}; + +static const struct snd_kcontrol_new rt1017_sto_dac = + SOC_DAPM_SINGLE("Switch", + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU, RT1017_SDCA_CTL_FU_MUTE, 0x1), + 0, 1, 1); + +static int rt1017_sdca_pde23_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt1017->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23, + RT1017_SDCA_CTL_REQ_POWER_STATE, 0), + ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt1017->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23, + RT1017_SDCA_CTL_REQ_POWER_STATE, 0), + ps3); + break; + default: + break; + } + return 0; +} + +static int rt1017_sdca_classd_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(rt1017->regmap, RT1017_PWM_TRIM_1, + RT1017_PWM_FREQ_CTL_SRC_SEL_MASK, RT1017_PWM_FREQ_CTL_SRC_SEL_REG); + regmap_write(rt1017->regmap, RT1017_CLASSD_INT_1, 0x10); + break; + default: + break; + } + + return 0; +} + +static int rt1017_sdca_feedback_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_update_bits(rt1017->regmap, 0xd017, 0x1f, 0x08); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(rt1017->regmap, 0xd017, 0x1f, 0x09); + break; + default: + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt1017_sdca_dapm_widgets[] = { + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT_E("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0, + rt1017_sdca_feedback_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* Digital Interface */ + SND_SOC_DAPM_SWITCH("DAC", SND_SOC_NOPM, 0, 0, &rt1017_sto_dac), + + /* Output Lines */ + SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0, + rt1017_sdca_classd_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_OUTPUT("SPO"), + + SND_SOC_DAPM_SUPPLY("PDE23", SND_SOC_NOPM, 0, 0, + rt1017_sdca_pde23_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_PGA("I Sense", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("V Sense", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SIGGEN("I Gen"), + SND_SOC_DAPM_SIGGEN("V Gen"), +}; + +static const struct snd_soc_dapm_route rt1017_sdca_dapm_routes[] = { + + { "DAC", "Switch", "DP1RX" }, + { "CLASS D", NULL, "DAC" }, + { "CLASS D", NULL, "PDE23" }, + { "SPO", NULL, "CLASS D" }, + + { "I Sense", NULL, "I Gen" }, + { "V Sense", NULL, "V Gen" }, + { "I Sense", NULL, "PDE23" }, + { "V Sense", NULL, "PDE23" }, + { "DP2TX", NULL, "I Sense" }, + { "DP2TX", NULL, "V Sense" }, +}; + +static struct sdw_slave_ops rt1017_sdca_slave_ops = { + .read_prop = rt1017_sdca_read_prop, + .update_status = rt1017_sdca_update_status, +}; + +static int rt1017_sdca_component_probe(struct snd_soc_component *component) +{ + int ret; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + +static void rt1017_sdca_component_remove(struct snd_soc_component *component) +{ + struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(rt1017->regmap, true); +} + +static const struct snd_soc_component_driver soc_sdca_component_rt1017 = { + .probe = rt1017_sdca_component_probe, + .remove = rt1017_sdca_component_remove, + .controls = rt1017_sdca_controls, + .num_controls = ARRAY_SIZE(rt1017_sdca_controls), + .dapm_widgets = rt1017_sdca_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt1017_sdca_dapm_widgets), + .dapm_routes = rt1017_sdca_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt1017_sdca_dapm_routes), + .endianness = 1, +}; + +static int rt1017_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, + int direction) +{ + snd_soc_dai_dma_data_set(dai, direction, sdw_stream); + + return 0; +} + +static void rt1017_sdca_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + snd_soc_dai_set_dma_data(dai, substream, NULL); +} + +static int rt1017_sdca_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); + struct sdw_stream_config stream_config; + struct sdw_port_config port_config; + enum sdw_data_direction direction; + struct sdw_stream_runtime *sdw_stream; + int retval, port, num_channels, ch_mask; + unsigned int sampling_rate; + + dev_dbg(dai->dev, "%s %s", __func__, dai->name); + sdw_stream = snd_soc_dai_get_dma_data(dai, substream); + + if (!sdw_stream) + return -EINVAL; + + if (!rt1017->sdw_slave) + return -EINVAL; + + /* SoundWire specific configuration */ + /* port 1 for playback */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + direction = SDW_DATA_DIR_RX; + port = 1; + } else { + direction = SDW_DATA_DIR_TX; + port = 2; + } + + num_channels = params_channels(params); + ch_mask = (1 << num_channels) - 1; + + stream_config.frame_rate = params_rate(params); + stream_config.ch_count = num_channels; + stream_config.bps = snd_pcm_format_width(params_format(params)); + stream_config.direction = direction; + + port_config.ch_mask = ch_mask; + port_config.num = port; + + dev_dbg(dai->dev, "frame_rate %d, ch_count %d, bps %d, direction %d, ch_mask %d, port: %d\n", + params_rate(params), num_channels, snd_pcm_format_width(params_format(params)), + direction, ch_mask, port); + + retval = sdw_stream_add_slave(rt1017->sdw_slave, &stream_config, + &port_config, 1, sdw_stream); + if (retval) { + dev_err(dai->dev, "Unable to configure port\n"); + return retval; + } + + /* sampling rate configuration */ + switch (params_rate(params)) { + case 44100: + sampling_rate = RT1017_SDCA_RATE_44100HZ; + break; + case 48000: + sampling_rate = RT1017_SDCA_RATE_48000HZ; + break; + case 96000: + sampling_rate = RT1017_SDCA_RATE_96000HZ; + break; + case 192000: + sampling_rate = RT1017_SDCA_RATE_192000HZ; + break; + default: + dev_err(component->dev, "Rate %d is not supported\n", + params_rate(params)); + return -EINVAL; + } + + /* set sampling frequency */ + regmap_write(rt1017->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21, + RT1017_SDCA_CTL_FS_INDEX, 0), + sampling_rate); + + return 0; +} + +static int rt1017_sdca_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); + struct sdw_stream_runtime *sdw_stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!rt1017->sdw_slave) + return -EINVAL; + + sdw_stream_remove_slave(rt1017->sdw_slave, sdw_stream); + return 0; +} + +static const struct snd_soc_dai_ops rt1017_sdca_ops = { + .hw_params = rt1017_sdca_pcm_hw_params, + .hw_free = rt1017_sdca_pcm_hw_free, + .set_stream = rt1017_sdca_set_sdw_stream, + .shutdown = rt1017_sdca_shutdown, +}; + +#define RT1017_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define RT1017_FORMATS (SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_driver rt1017_sdca_dai[] = { + { + .name = "rt1017-aif", + .playback = { + .stream_name = "DP1 Playback", + .channels_min = 1, + .channels_max = 1, + .rates = RT1017_STEREO_RATES, + .formats = RT1017_FORMATS, + }, + .capture = { + .stream_name = "DP2 Capture", + .channels_min = 1, + .channels_max = 1, + .rates = RT1017_STEREO_RATES, + .formats = RT1017_FORMATS, + }, + .ops = &rt1017_sdca_ops, + }, +}; + +static int rt1017_sdca_init(struct device *dev, struct regmap *regmap, + struct sdw_slave *slave) +{ + struct rt1017_sdca_priv *rt1017; + int ret; + + rt1017 = devm_kzalloc(dev, sizeof(*rt1017), GFP_KERNEL); + if (!rt1017) + return -ENOMEM; + + dev_set_drvdata(dev, rt1017); + rt1017->sdw_slave = slave; + rt1017->regmap = regmap; + + /* + * Mark hw_init to false + * HW init will be performed when device reports present + */ + rt1017->hw_init = false; + rt1017->first_hw_init = false; + + ret = devm_snd_soc_register_component(dev, + &soc_sdca_component_rt1017, + rt1017_sdca_dai, + ARRAY_SIZE(rt1017_sdca_dai)); + + return ret; +} + +static int rt1017_sdca_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct regmap *regmap; + + /* Regmap Initialization */ + regmap = devm_regmap_init_sdw(slave, &rt1017_sdca_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return rt1017_sdca_init(&slave->dev, regmap, slave); +} + +static int rt1017_sdca_sdw_remove(struct sdw_slave *slave) +{ + struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(&slave->dev); + + if (rt1017->first_hw_init) + pm_runtime_disable(&slave->dev); + + return 0; +} + +static const struct sdw_device_id rt1017_sdca_id[] = { + SDW_SLAVE_ENTRY_EXT(0x025d, 0x1017, 0x3, 0x1, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, rt1017_sdca_id); + +static int __maybe_unused rt1017_sdca_dev_suspend(struct device *dev) +{ + struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev); + + if (!rt1017->hw_init) + return 0; + + regcache_cache_only(rt1017->regmap, true); + + return 0; +} + +#define RT1017_PROBE_TIMEOUT 5000 + +static int __maybe_unused rt1017_sdca_dev_resume(struct device *dev) +{ + struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev); + unsigned long time; + + if (!rt1017->first_hw_init) + return 0; + + if (!slave->unattach_request) + goto regmap_sync; + + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(RT1017_PROBE_TIMEOUT)); + if (!time) { + dev_err(&slave->dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + + return -ETIMEDOUT; + } + +regmap_sync: + slave->unattach_request = 0; + regcache_cache_only(rt1017->regmap, false); + regcache_sync(rt1017->regmap); + + return 0; +} + +static const struct dev_pm_ops rt1017_sdca_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt1017_sdca_dev_suspend, rt1017_sdca_dev_resume) + SET_RUNTIME_PM_OPS(rt1017_sdca_dev_suspend, rt1017_sdca_dev_resume, NULL) +}; + +static struct sdw_driver rt1017_sdca_sdw_driver = { + .driver = { + .name = "rt1017-sdca", + .owner = THIS_MODULE, + .pm = &rt1017_sdca_pm, + }, + .probe = rt1017_sdca_sdw_probe, + .remove = rt1017_sdca_sdw_remove, + .ops = &rt1017_sdca_slave_ops, + .id_table = rt1017_sdca_id, +}; +module_sdw_driver(rt1017_sdca_sdw_driver); + +MODULE_DESCRIPTION("ASoC RT1017 driver SDCA SDW"); +MODULE_AUTHOR("Derek Fang "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt1017-sdca-sdw.h b/sound/soc/codecs/rt1017-sdca-sdw.h new file mode 100644 index 000000000000..5968b9a7d124 --- /dev/null +++ b/sound/soc/codecs/rt1017-sdca-sdw.h @@ -0,0 +1,188 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt1017-sdca-sdw.h -- RT1017 SDCA ALSA SoC audio driver header + * + * Copyright(c) 2023 Realtek Semiconductor Corp. + */ + +#ifndef __RT1017_SDW_H__ +#define __RT1017_SDW_H__ + +#include +#include +#include +#include +#include + +/* RT1017 SDCA Control - function number */ +#define FUNC_NUM_SMART_AMP 0x04 + +/* RT1017 SDCA entity */ +#define RT1017_SDCA_ENT_PDE23 0x31 +#define RT1017_SDCA_ENT_PDE22 0x33 +#define RT1017_SDCA_ENT_CS21 0x21 +#define RT1017_SDCA_ENT_SAPU29 0x29 +#define RT1017_SDCA_ENT_XU22 0x22 +#define RT1017_SDCA_ENT_FU 0x03 +#define RT1017_SDCA_ENT_UDMPU21 0x02 + +/* RT1017 SDCA control */ +#define RT1017_SDCA_CTL_FS_INDEX 0x10 +#define RT1017_SDCA_CTL_REQ_POWER_STATE 0x01 +#define RT1017_SDCA_CTL_PROT_STAT 0x11 +#define RT1017_SDCA_CTL_BYPASS 0x01 +#define RT1017_SDCA_CTL_FU_MUTE 0x01 +#define RT1017_SDCA_CTL_FU_VOLUME 0x02 +#define RT1017_SDCA_CTL_UDMPU_CLUSTER 0x10 + + +#define RT1017_CLASSD_INT_1 0xd300 +#define RT1017_PWM_TRIM_1 0xd370 + + +#define RT1017_PWM_FREQ_CTL_SRC_SEL_MASK (0x3 << 2) +#define RT1017_PWM_FREQ_CTL_SRC_SEL_EFUSE (0x2 << 2) +#define RT1017_PWM_FREQ_CTL_SRC_SEL_REG (0x0 << 2) + +enum { + RT1017_SDCA_RATE_44100HZ = 0x8, + RT1017_SDCA_RATE_48000HZ = 0x9, + RT1017_SDCA_RATE_96000HZ = 0xb, + RT1017_SDCA_RATE_192000HZ = 0xd, +}; + +struct rt1017_sdca_priv { + struct snd_soc_component *component; + struct regmap *regmap; + struct sdw_slave *sdw_slave; + struct sdw_bus_params params; + bool hw_init; + bool first_hw_init; +}; + +static const struct reg_default rt1017_sdca_reg_defaults[] = { + { 0x3206, 0x00 }, + { 0xc001, 0x43 }, + { 0xc030, 0x54 }, + { 0xc104, 0x8a }, + { 0xc10b, 0x2f }, + { 0xc10c, 0x2f }, + { 0xc110, 0x49 }, + { 0xc112, 0x10 }, + { 0xc300, 0xff }, + { 0xc301, 0xdd }, + { 0xc318, 0x40 }, + { 0xc325, 0x00 }, + { 0xc326, 0x00 }, + { 0xc327, 0x00 }, + { 0xc328, 0x02 }, + { 0xc331, 0xb2 }, + { 0xc340, 0x02 }, + { 0xc350, 0x21 }, + { 0xc500, 0x00 }, + { 0xc502, 0x00 }, + { 0xc504, 0x3f }, + { 0xc507, 0x1f }, + { 0xc509, 0x1f }, + { 0xc510, 0x40 }, + { 0xc512, 0x00 }, + { 0xc518, 0x02 }, + { 0xc51b, 0x7f }, + { 0xc51d, 0x0f }, + { 0xc520, 0x00 }, + { 0xc540, 0x80 }, + { 0xc541, 0x00 }, + { 0xc542, 0x0a }, + { 0xc550, 0x80 }, + { 0xc551, 0x0f }, + { 0xc552, 0xff }, + { 0xc600, 0x10 }, + { 0xc602, 0x83 }, + { 0xc612, 0x40 }, + { 0xc622, 0x40 }, + { 0xc632, 0x40 }, + { 0xc642, 0x40 }, + { 0xc651, 0x00 }, + { 0xca00, 0xc1 }, + { 0xca09, 0x00 }, + { 0xca0a, 0x51 }, + { 0xca0b, 0xeb }, + { 0xca0c, 0x85 }, + { 0xca0e, 0x00 }, + { 0xca0f, 0x10 }, + { 0xca10, 0x62 }, + { 0xca11, 0x4d }, + { 0xca16, 0x0f }, + { 0xca17, 0x00 }, + { 0xcb00, 0x10 }, + { 0xcc00, 0x10 }, + { 0xcc02, 0x0b }, + { 0xd017, 0x09 }, + { 0xd01a, 0x00 }, + { 0xd01b, 0x00 }, + { 0xd01c, 0x00 }, + { 0xd101, 0xa0 }, + { 0xd20c, 0x14 }, + { 0xd300, 0x0f }, + { 0xd370, 0x18 }, + { 0xd500, 0x00 }, + { 0xd545, 0x0b }, + { 0xd546, 0xf9 }, + { 0xd547, 0xb2 }, + { 0xd548, 0xa9 }, + { 0xd5a5, 0x00 }, + { 0xd5a6, 0x00 }, + { 0xd5a7, 0x00 }, + { 0xd5a8, 0x00 }, + { 0xd5aa, 0x00 }, + { 0xd5ab, 0x00 }, + { 0xd5ac, 0x00 }, + { 0xd5ad, 0x00 }, + { 0xda04, 0x03 }, + { 0xda05, 0x33 }, + { 0xda06, 0x33 }, + { 0xda07, 0x33 }, + { 0xda09, 0x5d }, + { 0xda0a, 0xc0 }, + { 0xda0c, 0x00 }, + { 0xda0d, 0x01 }, + { 0xda0e, 0x5d }, + { 0xda0f, 0x86 }, + { 0xda11, 0x20 }, + { 0xda12, 0x00 }, + { 0xda13, 0x00 }, + { 0xda14, 0x00 }, + { 0xda16, 0x7f }, + { 0xda17, 0xff }, + { 0xda18, 0xff }, + { 0xda19, 0xff }, + { 0xdab6, 0x00 }, + { 0xdab7, 0x01 }, + { 0xdab8, 0x00 }, + { 0xdab9, 0x01 }, + { 0xdaba, 0x00 }, + { 0xdabb, 0x01 }, + { 0xdb09, 0x0f }, + { 0xdb0a, 0xff }, + { 0xdb14, 0x00 }, + + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21, + RT1017_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU, + RT1017_SDCA_CTL_FU_MUTE, 0x01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_XU22, + RT1017_SDCA_CTL_BYPASS, 0), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21, + RT1017_SDCA_CTL_FS_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23, + RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE22, + RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, +}; + +static const struct reg_default rt1017_sdca_mbq_defaults[] = { + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU, + RT1017_SDCA_CTL_FU_VOLUME, 0x01), 0x00 }, +}; + +#endif /* __RT1017_SDW_H__ */ -- cgit v1.2.3 From df8d014edd646692302f3e8ef0bd63a041f4547f Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 25 Jul 2023 20:09:17 +0800 Subject: ASoC: cs42l51: change cs42l51_of_match to static cs42l51_of_match is only used in cs42l51-i2c.c now, change it to static. Signed-off-by: Yang Yingliang Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20230725120917.513064-1-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l51-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c index e7db7bcd0296..5ed2ef83dcdb 100644 --- a/sound/soc/codecs/cs42l51-i2c.c +++ b/sound/soc/codecs/cs42l51-i2c.c @@ -19,7 +19,7 @@ static struct i2c_device_id cs42l51_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_id); -const struct of_device_id cs42l51_of_match[] = { +static const struct of_device_id cs42l51_of_match[] = { { .compatible = "cirrus,cs42l51", }, { } }; -- cgit v1.2.3 From f6500ec12c1ec745fbec20fd4734b832bbfd4aac Mon Sep 17 00:00:00 2001 From: "justinstitt@google.com" Date: Tue, 25 Jul 2023 22:08:38 +0000 Subject: ASoC: intel: avs: refactor strncpy usage in topology `strncpy` is deprecated for use on NUL-terminated destination strings [1]. A suitable replacement is `strscpy` [2]. There are some hopes that someday the `strncpy` api could be ripped out due to the vast number of suitable replacements (strscpy, strscpy_pad, strtomem, strtomem_pad, strlcpy) [1]. [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 Link: https://github.com/KSPP/linux/issues/90 Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20230725-sound-soc-intel-avs-remove-deprecated-strncpy-v1-1-6357a1f8e9cf@google.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/topology.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c index cdb4ec500261..45d0eb2a8e71 100644 --- a/sound/soc/intel/avs/topology.c +++ b/sound/soc/intel/avs/topology.c @@ -1388,12 +1388,12 @@ static int avs_route_load(struct snd_soc_component *comp, int index, port = __ffs(mach->mach_params.i2s_link_mask); snprintf(buf, len, route->source, port); - strncpy((char *)route->source, buf, len); + strscpy((char *)route->source, buf, len); snprintf(buf, len, route->sink, port); - strncpy((char *)route->sink, buf, len); + strscpy((char *)route->sink, buf, len); if (route->control) { snprintf(buf, len, route->control, port); - strncpy((char *)route->control, buf, len); + strscpy((char *)route->control, buf, len); } } -- cgit v1.2.3 From 8744776363c370b0eeb0ed50cb0212d7826639b7 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 26 Jul 2023 09:10:51 +0000 Subject: ASoC: rt1316: fix key tone missing This patch adds a control that there are three options to control the digital volume output. The user could select "immediately" to make volume updates immediately and avoid key tone missing issues. In default, the driver selects that the volume update when a zero-crossing with a soft ramp. Signed-off-by: Shuming Fan Reported-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20230726091051.658754-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1316-sdw.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index 721821d9e9af..10a53c8d4874 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -424,6 +424,15 @@ static SOC_ENUM_SINGLE_DECL(rt1316_rx_data_ch_enum, SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0), 0, rt1316_rx_data_ch_select); +static const char * const rt1316_dac_output_vol_select[] = { + "immediately", + "zero crossing", + "zero crossing with soft ramp", +}; + +static SOC_ENUM_SINGLE_DECL(rt1316_dac_vol_ctl_enum, + 0xc010, 6, rt1316_dac_output_vol_select); + static const struct snd_kcontrol_new rt1316_snd_controls[] = { /* I2S Data Channel Selection */ @@ -442,6 +451,9 @@ static const struct snd_kcontrol_new rt1316_snd_controls[] = { /* IV mixer Control */ SOC_DOUBLE("Isense Mixer Switch", 0xc605, 2, 0, 1, 1), SOC_DOUBLE("Vsense Mixer Switch", 0xc605, 3, 1, 1, 1), + + /* DAC Output Volume Control */ + SOC_ENUM("DAC Output Vol Control", rt1316_dac_vol_ctl_enum), }; static const struct snd_kcontrol_new rt1316_sto_dac = -- cgit v1.2.3 From c17bd30d0ba5ca59266771cdfc387f26271a7042 Mon Sep 17 00:00:00 2001 From: YingKun Meng Date: Wed, 26 Jul 2023 19:05:16 +0800 Subject: ASoC: loongson: drop of_match_ptr for OF device id The ASoC Sound Card driver can be compile tested with !CONFIG_OF making 'loongson_asoc_dt_ids' unused: sound/soc/loongson/loongson_card.c:200:34: warning: unused variable 'loongson_asoc_dt_ids' [-Wunused-const-variable] As krzysztof advice, we drop of_match_ptr so the device id can also be used on ACPI. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202307242008.xqdjgk04-lkp@intel.com Fixes: d24028606e76 ("ASoC: loongson: Add Loongson ASoC Sound Card Support") Signed-off-by: YingKun Meng Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230726110516.703342-1-mengyingkun@loongson.cn Signed-off-by: Mark Brown --- sound/soc/loongson/loongson_card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/loongson/loongson_card.c b/sound/soc/loongson/loongson_card.c index 9ded16329747..406ee8db1a3c 100644 --- a/sound/soc/loongson/loongson_card.c +++ b/sound/soc/loongson/loongson_card.c @@ -208,7 +208,7 @@ static struct platform_driver loongson_audio_driver = { .driver = { .name = "loongson-asoc-card", .pm = &snd_soc_pm_ops, - .of_match_table = of_match_ptr(loongson_asoc_dt_ids), + .of_match_table = loongson_asoc_dt_ids, }, }; module_platform_driver(loongson_audio_driver); -- cgit v1.2.3 From 5befe22b3eebd07b334b2917f6d14ce7ee4c8404 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Wed, 26 Jul 2023 18:16:20 +0200 Subject: ASoC: fsl: fsl_qmc_audio: Fix snd_pcm_format_t values handling Running sparse on fsl_qmc_audio (make C=1) raises the following warnings: fsl_qmc_audio.c:387:26: warning: restricted snd_pcm_format_t degrades to integer fsl_qmc_audio.c:389:59: warning: incorrect type in argument 1 (different base types) fsl_qmc_audio.c:389:59: expected restricted snd_pcm_format_t [usertype] format fsl_qmc_audio.c:389:59: got unsigned int [assigned] i fsl_qmc_audio.c:564:26: warning: restricted snd_pcm_format_t degrades to integer fsl_qmc_audio.c:569:50: warning: incorrect type in argument 1 (different base types) fsl_qmc_audio.c:569:50: expected restricted snd_pcm_format_t [usertype] format fsl_qmc_audio.c:569:50: got int [assigned] i fsl_qmc_audio.c:573:62: warning: incorrect type in argument 1 (different base types) fsl_qmc_audio.c:573:62: expected restricted snd_pcm_format_t [usertype] format fsl_qmc_audio.c:573:62: got int [assigned] i These warnings are due to snd_pcm_format_t values handling done in the driver. Some macros and functions exist to handle safely these values. Use dedicated macros and functions to remove these warnings. Fixes: 075c7125b11c ("ASoC: fsl: Add support for QMC audio") Signed-off-by: Herve Codina Link: https://lore.kernel.org/r/20230726161620.495298-1-herve.codina@bootlin.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_qmc_audio.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c index 7cbb8e4758cc..56d6b0b039a2 100644 --- a/sound/soc/fsl/fsl_qmc_audio.c +++ b/sound/soc/fsl/fsl_qmc_audio.c @@ -372,8 +372,8 @@ static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai, struct snd_mask *f_old = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); unsigned int channels = params_channels(params); unsigned int slot_width; + snd_pcm_format_t format; struct snd_mask f_new; - unsigned int i; if (!channels || channels > nb_ts) { dev_err(qmc_dai->dev, "channels %u not supported\n", @@ -384,10 +384,10 @@ static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai, slot_width = (nb_ts / channels) * 8; snd_mask_none(&f_new); - for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { - if (snd_mask_test(f_old, i)) { - if (snd_pcm_format_physical_width(i) <= slot_width) - snd_mask_set(&f_new, i); + pcm_for_each_format(format) { + if (snd_mask_test_format(f_old, format)) { + if (snd_pcm_format_physical_width(format) <= slot_width) + snd_mask_set_format(&f_new, format); } } @@ -551,26 +551,26 @@ static const struct snd_soc_dai_ops qmc_dai_ops = { static u64 qmc_audio_formats(u8 nb_ts) { - u64 formats; - unsigned int chan_width; unsigned int format_width; - int i; + unsigned int chan_width; + snd_pcm_format_t format; + u64 formats_mask; if (!nb_ts) return 0; - formats = 0; + formats_mask = 0; chan_width = nb_ts * 8; - for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { + pcm_for_each_format(format) { /* * Support format other than little-endian (ie big-endian or * without endianness such as 8bit formats) */ - if (snd_pcm_format_little_endian(i) == 1) + if (snd_pcm_format_little_endian(format) == 1) continue; /* Support physical width multiple of 8bit */ - format_width = snd_pcm_format_physical_width(i); + format_width = snd_pcm_format_physical_width(format); if (format_width == 0 || format_width % 8) continue; @@ -581,9 +581,9 @@ static u64 qmc_audio_formats(u8 nb_ts) if (format_width > chan_width || chan_width % format_width) continue; - formats |= (1ULL << i); + formats_mask |= pcm_format_to_bits(format); } - return formats; + return formats_mask; } static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *np, -- cgit v1.2.3 From 367ef1e1c4b65acc5d789ba00d20197eb66b62f4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 27 Jul 2023 10:16:33 +0300 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From c8af46580b0f5300bb3df16b89f795f255cbcb65 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 19:44:27 +0100 Subject: ASoC: sta32x: 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 sta32x driver to use the more modern data structure. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230712-asoc-st-maple-v1-1-46eab2c0ce23@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/sta32x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 4a694d0bfd68..34ffd32ab9dc 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -1022,7 +1022,7 @@ static const struct regmap_config sta32x_regmap = { .max_register = STA32X_FDRC2, .reg_defaults = sta32x_regs, .num_reg_defaults = ARRAY_SIZE(sta32x_regs), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .wr_table = &sta32x_write_regs, .rd_table = &sta32x_read_regs, .volatile_table = &sta32x_volatile_regs, -- cgit v1.2.3 From 87256942e90242ec7ddeeba9f6b9433f01eec9be Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 19:44:28 +0100 Subject: ASoC: sta350: 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 sta350 driver to use the more modern data structure. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230712-asoc-st-maple-v1-2-46eab2c0ce23@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/sta350.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index d05f3fd57661..e4a9e9241c60 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c @@ -1065,7 +1065,7 @@ static const struct regmap_config sta350_regmap = { .max_register = STA350_MISC2, .reg_defaults = sta350_regs, .num_reg_defaults = ARRAY_SIZE(sta350_regs), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .wr_table = &sta350_write_regs, .rd_table = &sta350_read_regs, .volatile_table = &sta350_volatile_regs, -- cgit v1.2.3 From 35959958df14542c68b0d0c1a7906838323fcbeb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 19:44:29 +0100 Subject: ASoC: sta529: 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 sta529 driver to use the more modern data structure. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230712-asoc-st-maple-v1-3-46eab2c0ce23@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/sta529.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 0ac08478ddac..eedafef775e5 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -331,7 +331,7 @@ static const struct regmap_config sta529_regmap = { .max_register = STA529_MAX_REGISTER, .readable_reg = sta529_readable, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = sta529_reg_defaults, .num_reg_defaults = ARRAY_SIZE(sta529_reg_defaults), }; -- cgit v1.2.3 From 4810c775484b373ec5c1c75f53bb9a09ba96a7ef Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 19:44:30 +0100 Subject: ASoC: stac9766: 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 stac9766 driver to use the more modern data structure. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230712-asoc-st-maple-v1-4-46eab2c0ce23@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/stac9766.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 1824a71fe053..2f9f10a4dfed 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -67,7 +67,7 @@ static const struct regmap_config stac9766_regmap_config = { .reg_stride = 2, .val_bits = 16, .max_register = 0x78, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = regmap_ac97_default_volatile, -- cgit v1.2.3 From 66b1abc17c9d9e4af58098b9d6b8d7ade961e195 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 19:44:31 +0100 Subject: ASoC: sti-sas: 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 sti-sas driver to use the more modern data structure. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230712-asoc-st-maple-v1-5-46eab2c0ce23@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/sti-sas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index 99545bcb2ba9..c421906a0694 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -316,7 +316,7 @@ static const struct regmap_config stih407_sas_regmap = { .reg_defaults = stih407_sas_reg_defaults, .num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults), .volatile_reg = sti_sas_volatile_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_read = sti_sas_read_reg, .reg_write = sti_sas_write_reg, }; -- cgit v1.2.3 From 8f59c7ed230784ca914c98e250c65768b71d5de4 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Thu, 27 Jul 2023 10:16:32 +0800 Subject: ASoC: rt1017: Remove unused function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function are defined in the rt1017-sdca-sdw.h file, but not called elsewhere, so delete the unused functions. sound/soc/codecs/rt1017-sdca-sdw.h:183:33: warning: ‘rt1017_sdca_mbq_defaults’ defined but not used. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=5998 Signed-off-by: Jiapeng Chong Link: https://lore.kernel.org/r/20230727021632.88912-1-jiapeng.chong@linux.alibaba.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1017-sdca-sdw.h | 5 ----- 1 file changed, 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1017-sdca-sdw.h b/sound/soc/codecs/rt1017-sdca-sdw.h index 5968b9a7d124..4932b5dbe3c0 100644 --- a/sound/soc/codecs/rt1017-sdca-sdw.h +++ b/sound/soc/codecs/rt1017-sdca-sdw.h @@ -180,9 +180,4 @@ static const struct reg_default rt1017_sdca_reg_defaults[] = { RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, }; -static const struct reg_default rt1017_sdca_mbq_defaults[] = { - { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU, - RT1017_SDCA_CTL_FU_VOLUME, 0x01), 0x00 }, -}; - #endif /* __RT1017_SDW_H__ */ -- cgit v1.2.3 From a9a65b87a5553a4ecabad7093ef6a1088bb71b88 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Thu, 27 Jul 2023 22:46:13 +0000 Subject: ASoC: 88pm860x: 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`! In this case, though, there was care taken to ensure that the destination buffer would be NUL-terminated. The destination buffer is zero-initialized and each `pm860x->name[i]` has a size of `MAX_NAME_LENGTH + 1`. This means that there is unlikely to be a bug here. However, in an attempt to eliminate the usage of the `strncpy` API as well as disambiguate implementations, replacements such as: `strscpy`, `strscpy_pad`, `strtomem` and `strtomem_pad` should be preferred. We are able to eliminate the need for `len + 1` since `strscpy` guarantees NUL-termination for its destination buffer as per its implementation [3]: | /* Hit buffer length without finding a NUL; force NUL-termination. */ | if (res) | dest[res-1] = '\0'; [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://elixir.bootlin.com/linux/v6.3/source/lib/string.c#L183 Link: https://github.com/KSPP/linux/issues/90 Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20230727-sound-soc-codecs-v1-1-562fa2836bf4@google.com Signed-off-by: Mark Brown --- sound/soc/codecs/88pm860x-codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 3574c68e0dda..d99b674d574b 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -143,7 +143,7 @@ struct pm860x_priv { struct pm860x_det det; int irq[4]; - unsigned char name[4][MAX_NAME_LEN+1]; + unsigned char name[4][MAX_NAME_LEN]; }; /* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */ @@ -1373,7 +1373,7 @@ static int pm860x_codec_probe(struct platform_device *pdev) return -EINVAL; } pm860x->irq[i] = res->start + chip->irq_base; - strncpy(pm860x->name[i], res->name, MAX_NAME_LEN); + strscpy(pm860x->name[i], res->name, MAX_NAME_LEN); } ret = devm_snd_soc_register_component(&pdev->dev, -- cgit v1.2.3 From 7eb10bfbbae6025cb7b4bba3db0c1281eac05862 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Thu, 27 Jul 2023 22:26:41 +0000 Subject: ASoC: fsl_micfil: 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`! In this case, though, there was great care taken to ensure that the destination buffer would be NUL-terminated through the use of `len - 1` ensuring that the previously zero-initialized buffer would not overwrite the last NUL byte. This means that there's no bug here. However, `strscpy` will add a mandatory NUL byte to the destination buffer as promised by the following `strscpy` implementation [3]: | /* Hit buffer length without finding a NUL; force NUL-termination. */ | if (res) | dest[res-1] = '\0'; This means we can lose the `- 1` which clears up whats happening here. All the while, we get one step closer to eliminating the ambiguous `strncpy` api in favor of its less ambiguous replacement like `strscpy`, `strscpy_pad`, `strtomem` and `strtomem_pad` amongst others. [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://elixir.bootlin.com/linux/v6.3/source/lib/string.c#L183 Link: https://github.com/KSPP/linux/issues/90 Signed-off-by: Justin Stitt Acked-by: Shengjiu Wang Link: https://lore.kernel.org/r/20230727-sound-soc-fsl-v1-1-4fc0ed7e0366@google.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_micfil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 3f08082a55be..fe28b27e50d0 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -1044,7 +1044,7 @@ static int fsl_micfil_probe(struct platform_device *pdev) return -ENOMEM; micfil->pdev = pdev; - strncpy(micfil->name, np->name, sizeof(micfil->name) - 1); + strscpy(micfil->name, np->name, sizeof(micfil->name)); micfil->soc = of_device_get_match_data(&pdev->dev); -- cgit v1.2.3 From 44900c3ee4a1047bf896ca4cd9a9c69000f04701 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Thu, 27 Jul 2023 21:53:24 +0000 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From 2ad27caab44583eb38b71d90a364e5670b4c7c5a Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Thu, 27 Jul 2023 22:09:29 +0000 Subject: 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(-) (limited to 'sound') 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", -- cgit v1.2.3 From 8897a1475f278eb36d76df9684466b17b8dd4cab Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 24 Jul 2023 00:21:22 +0000 Subject: ASoC: rsnd: use DAI driver ID instead of DAI ID Current rsnd is using DAI ID to get own priv data without setting driver->id. It was no problem for Single Component, but will be problem in case of Multi Component, because it is not a DAI serial number. struct snd_soc_dai *snd_soc_register_dai(...) { ... if (dai_drv->id) dai->id = dai_drv->id; else dai->id = component->num_dai; ... } This patch sets driver->id, and get serial number. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87wmyqb1mm.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 6a522e6dd85a..f3f17b784025 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1378,6 +1378,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, drv->name = rdai->name; drv->ops = &rsnd_soc_dai_ops; drv->pcm_new = rsnd_pcm_new; + drv->id = dai_i; io_playback->rdai = rdai; io_capture->rdai = rdai; -- cgit v1.2.3 From 6328489c135b60380b9e12b4d23854433e96a8b0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 24 Jul 2023 00:21:31 +0000 Subject: ASoC: rsnd: cleanup rsnd_dai_of_node() It calls rsnd_dai_of_node() to know it was called from Audio Graph Card/Card2, or from Simple Audio Card. And after that, it gets number of related DAIs. To be more simple code, this patch merges these. This is prepare for multi Component support. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87v8eab1md.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f3f17b784025..a87d7fa55f7b 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1261,7 +1261,7 @@ int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name } static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv, - int *is_graph) + int *nr, int *is_graph) { struct device *dev = rsnd_priv_to_dev(priv); struct device_node *np = dev->of_node; @@ -1274,22 +1274,30 @@ static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv, * parse both previous dai (= rcar_sound,dai), and * graph dai (= ports/port) */ + + /* + * Simple-Card + */ dai_node = of_get_child_by_name(np, RSND_NODE_DAI); if (dai_node) { + *nr = of_get_child_count(dai_node); ret = dai_node; goto of_node_compatible; } - ret = np; - + /* + * Audio-Graph-Card + */ dai_node = of_graph_get_next_endpoint(np, NULL); - if (dai_node) - goto of_node_graph; + if (dai_node) { + *nr = of_graph_get_endpoint_count(np); + *is_graph = 1; + ret = np; + goto of_node_compatible; + } return NULL; -of_node_graph: - *is_graph = 1; of_node_compatible: of_node_put(dai_node); @@ -1447,16 +1455,11 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) struct snd_soc_dai_driver *rdrv; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_dai *rdai; - int nr; + int nr = 0; int is_graph; int dai_i; - dai_node = rsnd_dai_of_node(priv, &is_graph); - if (is_graph) - nr = of_graph_get_endpoint_count(dai_node); - else - nr = of_get_child_count(dai_node); - + dai_node = rsnd_dai_of_node(priv, &nr, &is_graph); if (!nr) return -EINVAL; -- cgit v1.2.3 From 547b02f74e4ac1e7d295a6266d5bc93a647cd4ac Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 24 Jul 2023 00:21:39 +0000 Subject: ASoC: rsnd: enable multi Component support for Audio Graph Card/Card2 +-- Basic Board ---------+ |+--------+ +------+| || CPU ch0| <--> |CodecA|| || ch1| <-+ +------+| |+--------+ | | +-------------|----------+ +-- expansion board -----+ | | +------+| | +->|CodecB|| | +------+| +------------------------+ In above HW connection case, we intuitively think we want to handle these as "2 Sound Cards". card0,0: CPU-ch0 - CodecA card1,0: CPU-ch1 - CodecB But, we needed to handle it as "1 big Sound Card", because of Component vs Card limitation. card0,0: CPU-ch0 - CodecA card0,1: CPU-ch1 - CodecB This patch enables multi Component to handle multi Cards. To support it, it needs - Fill dai_args for each DAI on snd_soc_dai_driver - Parse DT for each Component (Simple Card/Audio Graph Card) Ex) Simple Card rcar_sound { ... /* Component0 */ rcar_sound,dai@0 { ... }; /* Component1 */ rcar_sound,dai@1 { ... }; }; Ex) Audio Graph Card/Card2 rcar_sound { /* Component0 */ ports@0 { ... }; /* Component1 */ ports@1 { ... }; }; Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87tttub1m4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 134 ++++++++++++++++++++++++++++++++--------------- sound/soc/sh/rcar/rsnd.h | 4 ++ 2 files changed, 95 insertions(+), 43 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index a87d7fa55f7b..9f3d97bc177a 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1260,13 +1260,13 @@ int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name return i; } -static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv, - int *nr, int *is_graph) +static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph) { struct device *dev = rsnd_priv_to_dev(priv); struct device_node *np = dev->of_node; - struct device_node *dai_node; - struct device_node *ret; + struct device_node *ports, *node; + int nr = 0; + int i = 0; *is_graph = 0; @@ -1278,30 +1278,47 @@ static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv, /* * Simple-Card */ - dai_node = of_get_child_by_name(np, RSND_NODE_DAI); - if (dai_node) { - *nr = of_get_child_count(dai_node); - ret = dai_node; - goto of_node_compatible; + node = of_get_child_by_name(np, RSND_NODE_DAI); + if (!node) + goto audio_graph; + + of_node_put(node); + + for_each_child_of_node(np, node) { + if (!of_node_name_eq(node, RSND_NODE_DAI)) + continue; + + priv->component_dais[i] = of_get_child_count(node); + nr += priv->component_dais[i]; + i++; + if (i >= RSND_MAX_COMPONENT) { + dev_info(dev, "reach to max component\n"); + break; + } } + return nr; + +audio_graph: /* * Audio-Graph-Card */ - dai_node = of_graph_get_next_endpoint(np, NULL); - if (dai_node) { - *nr = of_graph_get_endpoint_count(np); - *is_graph = 1; - ret = np; - goto of_node_compatible; + for_each_child_of_node(np, ports) { + if (!of_node_name_eq(ports, "ports") && + !of_node_name_eq(ports, "port")) + continue; + priv->component_dais[i] = of_graph_get_endpoint_count(ports); + nr += priv->component_dais[i]; + i++; + if (i >= RSND_MAX_COMPONENT) { + dev_info(dev, "reach to max component\n"); + break; + } } - return NULL; - -of_node_compatible: - of_node_put(dai_node); + *is_graph = 1; - return ret; + return nr; } @@ -1365,6 +1382,8 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd, static void __rsnd_dai_probe(struct rsnd_priv *priv, struct device_node *dai_np, + struct device_node *node_np, + uint32_t node_arg, int dai_i) { struct rsnd_dai_stream *io_playback; @@ -1382,11 +1401,17 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i); + /* for multi Component */ + rdai->dai_args.np = node_np; + rdai->dai_args.args_count = 1; + rdai->dai_args.args[0] = node_arg; + rdai->priv = priv; drv->name = rdai->name; drv->ops = &rsnd_soc_dai_ops; drv->pcm_new = rsnd_pcm_new; drv->id = dai_i; + drv->dai_args = &rdai->dai_args; io_playback->rdai = rdai; io_capture->rdai = rdai; @@ -1450,16 +1475,15 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, static int rsnd_dai_probe(struct rsnd_priv *priv) { - struct device_node *dai_node; - struct device_node *dai_np; struct snd_soc_dai_driver *rdrv; struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *np = dev->of_node; struct rsnd_dai *rdai; int nr = 0; int is_graph; int dai_i; - dai_node = rsnd_dai_of_node(priv, &nr, &is_graph); + nr = rsnd_dai_of_node(priv, &is_graph); if (!nr) return -EINVAL; @@ -1477,26 +1501,42 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) */ dai_i = 0; if (is_graph) { - for_each_endpoint_of_node(dai_node, dai_np) { - __rsnd_dai_probe(priv, dai_np, dai_i); - if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) { - rdai = rsnd_rdai_get(priv, dai_i); - - rsnd_parse_connect_graph(priv, &rdai->playback, dai_np); - rsnd_parse_connect_graph(priv, &rdai->capture, dai_np); + struct device_node *ports; + struct device_node *dai_np; + + for_each_child_of_node(np, ports) { + if (!of_node_name_eq(ports, "ports") && + !of_node_name_eq(ports, "port")) + continue; + for_each_endpoint_of_node(ports, dai_np) { + __rsnd_dai_probe(priv, dai_np, dai_np, 0, dai_i); + if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) { + rdai = rsnd_rdai_get(priv, dai_i); + + rsnd_parse_connect_graph(priv, &rdai->playback, dai_np); + rsnd_parse_connect_graph(priv, &rdai->capture, dai_np); + } + dai_i++; } - dai_i++; } } else { - for_each_child_of_node(dai_node, dai_np) { - __rsnd_dai_probe(priv, dai_np, dai_i); - if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) { - rdai = rsnd_rdai_get(priv, dai_i); + struct device_node *node; + struct device_node *dai_np; + + for_each_child_of_node(np, node) { + if (!of_node_name_eq(node, RSND_NODE_DAI)) + continue; - rsnd_parse_connect_simple(priv, &rdai->playback, dai_np); - rsnd_parse_connect_simple(priv, &rdai->capture, dai_np); + for_each_child_of_node(node, dai_np) { + __rsnd_dai_probe(priv, dai_np, np, dai_i, dai_i); + if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) { + rdai = rsnd_rdai_get(priv, dai_i); + + rsnd_parse_connect_simple(priv, &rdai->playback, dai_np); + rsnd_parse_connect_simple(priv, &rdai->capture, dai_np); + } + dai_i++; } - dai_i++; } } @@ -1926,6 +1966,7 @@ static int rsnd_probe(struct platform_device *pdev) rsnd_dai_probe, }; int ret, i; + int ci; /* * init priv data @@ -1962,11 +2003,18 @@ static int rsnd_probe(struct platform_device *pdev) /* * asoc register */ - ret = devm_snd_soc_register_component(dev, &rsnd_soc_component, - priv->daidrv, rsnd_rdai_nr(priv)); - if (ret < 0) { - dev_err(dev, "cannot snd dai register\n"); - goto exit_snd_probe; + ci = 0; + for (i = 0; priv->component_dais[i] > 0; i++) { + int nr = priv->component_dais[i]; + + ret = devm_snd_soc_register_component(dev, &rsnd_soc_component, + priv->daidrv + ci, nr); + if (ret < 0) { + dev_err(dev, "cannot snd component register\n"); + goto exit_snd_probe; + } + + ci += nr; } pm_runtime_enable(dev); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 239705d52517..43c0d675cc34 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -545,6 +545,7 @@ struct rsnd_dai { struct rsnd_dai_stream capture; struct rsnd_priv *priv; struct snd_pcm_hw_constraint_list constraint; + struct of_phandle_args dai_args; int max_channels; /* 2ch - 16ch */ int ssi_lane; /* 1lane - 4lane */ @@ -702,6 +703,9 @@ struct rsnd_priv { struct snd_soc_dai_driver *daidrv; struct rsnd_dai *rdai; int rdai_nr; + +#define RSND_MAX_COMPONENT 3 + int component_dais[RSND_MAX_COMPONENT]; }; #define rsnd_priv_to_pdev(priv) ((priv)->pdev) -- cgit v1.2.3 From 0169cc3f200cbd737a57592fc478b24ff3cec3c5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 31 Jul 2023 11:47:02 +0100 Subject: ASoC: wm8960: Read initial MCLK rate from clock API When we have a MCLK provided by the clock API read the rate at startup and store it so that there's something set before the machine driver has done clocking configuration (eg, if it only configures clocking based on sample rate). Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230731-asoc-wm8960-clk-v1-1-69f9ffa2b10a@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index c2bd9ef41ebb..d4bc97088354 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -1429,6 +1429,14 @@ static int wm8960_i2c_probe(struct i2c_client *i2c) if (IS_ERR(wm8960->mclk)) { if (PTR_ERR(wm8960->mclk) == -EPROBE_DEFER) return -EPROBE_DEFER; + } else { + ret = clk_get_rate(wm8960->mclk); + if (ret >= 0) { + wm8960->freq_in = ret; + } else { + dev_err(&i2c->dev, "Failed to read MCLK rate: %d\n", + ret); + } } wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap); -- cgit v1.2.3 From 2bbc2df46e67be1a26b9c2b18a581b83e17ccb19 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 31 Jul 2023 11:47:03 +0100 Subject: ASoC: wm8960: Make automatic the default clocking mode The wm8960 driver supports an automatic clocking mode which will use the MCLK directly where possible and fall back to the PLL if there is no suitable configuration directly using the MCLK. Clock 0 will be used by the generic cards when configuring things, currently this is a MCLK only mode but using AUTO mode would be more functional. Since the driver still prefers to use MCLK directly where possible there should be no negative impact on systems which are able to use MCLK directly. As far as I can see nothing is using the system clock as part of the ABI, the only reference I can see to a mode in a machine driver is the Freescale i.MX card which uses the automatic mode with an explicit in kernel call using the constant so will be unaffected. Acked-by: Charles Keepax Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230731-asoc-wm8960-clk-v1-2-69f9ffa2b10a@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8960.h b/sound/soc/codecs/wm8960.h index 63ba6c03c488..e8ff33b188e9 100644 --- a/sound/soc/codecs/wm8960.h +++ b/sound/soc/codecs/wm8960.h @@ -77,9 +77,9 @@ #define WM8960_SYSCLK_DIV_1 (0 << 1) #define WM8960_SYSCLK_DIV_2 (2 << 1) -#define WM8960_SYSCLK_MCLK (0 << 0) +#define WM8960_SYSCLK_AUTO (0 << 0) #define WM8960_SYSCLK_PLL (1 << 0) -#define WM8960_SYSCLK_AUTO (2 << 0) +#define WM8960_SYSCLK_MCLK (2 << 0) #define WM8960_DAC_DIV_1 (0 << 3) #define WM8960_DAC_DIV_1_5 (1 << 3) -- cgit v1.2.3 From 36eb986845a8ca87c1f7f91976fad53ee249ae8c Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 31 Jul 2023 18:34:19 +0800 Subject: ASoC: Intel: maxim-common: get codec number from ACPI table We implement a helper function to get number of codecs from ACPI subsystem instead of using quirk flag in machine driver. Also refactor module interface by adding max_98390_dai_link() function. On the sof_rt5682 machine driver side, we remove the quirk flag SOF_MAX98390_TWEETER_SPEAKER_PRESENT and use the new interface of max98390 to setup dai link. Signed-off-by: Brent Lu Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230731103419.2536036-2-brent.lu@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_maxim_common.c | 170 ++++++++++++++++++------------ sound/soc/intel/boards/sof_maxim_common.h | 21 ++-- sound/soc/intel/boards/sof_rt5682.c | 37 +------ 3 files changed, 111 insertions(+), 117 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index 112e89951da0..628b6d5d3ee4 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -11,6 +12,18 @@ #include #include "sof_maxim_common.h" +/* helper function to get the number of specific codec */ +static unsigned int get_num_codecs(const char *hid) +{ + struct acpi_device *adev; + unsigned int dev_num = 0; + + for_each_acpi_dev_match(adev, hid, NULL, -1) + dev_num++; + + return dev_num; +} + #define MAX_98373_PIN_NAME 16 const struct snd_soc_dapm_route max_98373_dapm_routes[] = { @@ -168,17 +181,6 @@ static struct snd_soc_codec_conf max_98390_codec_conf[] = { .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME), .name_prefix = "Left", }, -}; - -static struct snd_soc_codec_conf max_98390_4spk_codec_conf[] = { - { - .dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME), - .name_prefix = "Right", - }, - { - .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME), - .name_prefix = "Left", - }, { .dlc = COMP_CODEC_CONF(MAX_98390_DEV2_NAME), .name_prefix = "Tweeter Right", @@ -189,19 +191,7 @@ static struct snd_soc_codec_conf max_98390_4spk_codec_conf[] = { }, }; -struct snd_soc_dai_link_component max_98390_components[] = { - { - .name = MAX_98390_DEV0_NAME, - .dai_name = MAX_98390_CODEC_DAI, - }, - { - .name = MAX_98390_DEV1_NAME, - .dai_name = MAX_98390_CODEC_DAI, - }, -}; -EXPORT_SYMBOL_NS(max_98390_components, SND_SOC_INTEL_SOF_MAXIM_COMMON); - -struct snd_soc_dai_link_component max_98390_4spk_components[] = { +static struct snd_soc_dai_link_component max_98390_components[] = { { .name = MAX_98390_DEV0_NAME, .dai_name = MAX_98390_CODEC_DAI, @@ -219,62 +209,56 @@ struct snd_soc_dai_link_component max_98390_4spk_components[] = { .dai_name = MAX_98390_CODEC_DAI, }, }; -EXPORT_SYMBOL_NS(max_98390_4spk_components, SND_SOC_INTEL_SOF_MAXIM_COMMON); + +static const struct { + unsigned int tx; + unsigned int rx; +} max_98390_tdm_mask[] = { + {.tx = 0x01, .rx = 0x3}, + {.tx = 0x02, .rx = 0x3}, + {.tx = 0x04, .rx = 0x3}, + {.tx = 0x08, .rx = 0x3}, +}; static int max_98390_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; - int i; + int i, ret; for_each_rtd_codec_dais(rtd, i, codec_dai) { - if (i >= ARRAY_SIZE(max_98390_4spk_components)) { + if (i >= ARRAY_SIZE(max_98390_tdm_mask)) { dev_err(codec_dai->dev, "invalid codec index %d\n", i); return -ENODEV; } - if (!strcmp(codec_dai->component->name, MAX_98390_DEV0_NAME)) { - /* DEV0 tdm slot configuration Right */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x01, 3, 4, 32); - } - if (!strcmp(codec_dai->component->name, MAX_98390_DEV1_NAME)) { - /* DEV1 tdm slot configuration Left */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x02, 3, 4, 32); - } - - if (!strcmp(codec_dai->component->name, MAX_98390_DEV2_NAME)) { - /* DEVi2 tdm slot configuration Tweeter Right */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x04, 3, 4, 32); - } - if (!strcmp(codec_dai->component->name, MAX_98390_DEV3_NAME)) { - /* DEV3 tdm slot configuration Tweeter Left */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x08, 3, 4, 32); + ret = snd_soc_dai_set_tdm_slot(codec_dai, max_98390_tdm_mask[i].tx, + max_98390_tdm_mask[i].rx, 4, + params_width(params)); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", + ret); + return ret; } } return 0; } -int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd) +static int max_98390_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID); int ret; - /* add regular speakers dapm route */ - ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes, - ARRAY_SIZE(max_98390_dapm_routes)); - if (ret) { - dev_err(rtd->dev, "unable to add Left/Right Speaker dapm, ret %d\n", ret); - return ret; - } - - /* add widgets/controls/dapm for tweeter speakers */ - if (acpi_dev_present("MX98390", "3", -1)) { + switch (num_codecs) { + case 4: + /* add widgets/controls/dapm for tweeter speakers */ ret = snd_soc_dapm_new_controls(&card->dapm, max_98390_tt_dapm_widgets, ARRAY_SIZE(max_98390_tt_dapm_widgets)); - if (ret) { - dev_err(rtd->dev, "unable to add tweeter dapm controls, ret %d\n", ret); + dev_err(rtd->dev, "unable to add tweeter dapm widgets, ret %d\n", + ret); /* Don't need to add routes if widget addition failed */ return ret; } @@ -282,33 +266,79 @@ int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd) ret = snd_soc_add_card_controls(card, max_98390_tt_kcontrols, ARRAY_SIZE(max_98390_tt_kcontrols)); if (ret) { - dev_err(rtd->dev, "unable to add tweeter card controls, ret %d\n", ret); + dev_err(rtd->dev, "unable to add tweeter controls, ret %d\n", + ret); return ret; } ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_tt_dapm_routes, ARRAY_SIZE(max_98390_tt_dapm_routes)); - if (ret) - dev_err(rtd->dev, - "unable to add Tweeter Left/Right Speaker dapm, ret %d\n", ret); + if (ret) { + dev_err(rtd->dev, "unable to add tweeter dapm routes, ret %d\n", + ret); + return ret; + } + + fallthrough; + case 2: + /* add regular speakers dapm route */ + ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes, + ARRAY_SIZE(max_98390_dapm_routes)); + if (ret) { + dev_err(rtd->dev, "unable to add dapm routes, ret %d\n", + ret); + return ret; + } + break; + default: + dev_err(rtd->dev, "invalid codec number %d\n", num_codecs); + return -EINVAL; } + return ret; } -EXPORT_SYMBOL_NS(max_98390_spk_codec_init, SND_SOC_INTEL_SOF_MAXIM_COMMON); -const struct snd_soc_ops max_98390_ops = { +static const struct snd_soc_ops max_98390_ops = { .hw_params = max_98390_hw_params, }; -EXPORT_SYMBOL_NS(max_98390_ops, SND_SOC_INTEL_SOF_MAXIM_COMMON); -void max_98390_set_codec_conf(struct snd_soc_card *card, int ch) +void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link) +{ + unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID); + + link->codecs = max_98390_components; + + switch (num_codecs) { + case 2: + case 4: + link->num_codecs = num_codecs; + break; + default: + dev_err(dev, "invalid codec number %d for %s\n", num_codecs, + MAX_98390_ACPI_HID); + break; + } + + link->init = max_98390_init; + link->ops = &max_98390_ops; +} +EXPORT_SYMBOL_NS(max_98390_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON); + +void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card) { - if (ch == ARRAY_SIZE(max_98390_4spk_codec_conf)) { - card->codec_conf = max_98390_4spk_codec_conf; - card->num_configs = ARRAY_SIZE(max_98390_4spk_codec_conf); - } else { - card->codec_conf = max_98390_codec_conf; - card->num_configs = ARRAY_SIZE(max_98390_codec_conf); + unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID); + + card->codec_conf = max_98390_codec_conf; + + switch (num_codecs) { + case 2: + case 4: + card->num_configs = num_codecs; + break; + default: + dev_err(dev, "invalid codec number %d for %s\n", num_codecs, + MAX_98390_ACPI_HID); + break; } } EXPORT_SYMBOL_NS(max_98390_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON); diff --git a/sound/soc/intel/boards/sof_maxim_common.h b/sound/soc/intel/boards/sof_maxim_common.h index 7a8c53049e4d..a095b47b856b 100644 --- a/sound/soc/intel/boards/sof_maxim_common.h +++ b/sound/soc/intel/boards/sof_maxim_common.h @@ -27,18 +27,15 @@ int max_98373_trigger(struct snd_pcm_substream *substream, int cmd); /* * Maxim MAX98390 */ -#define MAX_98390_CODEC_DAI "max98390-aif1" -#define MAX_98390_DEV0_NAME "i2c-MX98390:00" -#define MAX_98390_DEV1_NAME "i2c-MX98390:01" -#define MAX_98390_DEV2_NAME "i2c-MX98390:02" -#define MAX_98390_DEV3_NAME "i2c-MX98390:03" - -extern struct snd_soc_dai_link_component max_98390_components[2]; -extern struct snd_soc_dai_link_component max_98390_4spk_components[4]; -extern const struct snd_soc_ops max_98390_ops; - -void max_98390_set_codec_conf(struct snd_soc_card *card, int ch); -int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd); +#define MAX_98390_ACPI_HID "MX98390" +#define MAX_98390_CODEC_DAI "max98390-aif1" +#define MAX_98390_DEV0_NAME "i2c-" MAX_98390_ACPI_HID ":00" +#define MAX_98390_DEV1_NAME "i2c-" MAX_98390_ACPI_HID ":01" +#define MAX_98390_DEV2_NAME "i2c-" MAX_98390_ACPI_HID ":02" +#define MAX_98390_DEV3_NAME "i2c-" MAX_98390_ACPI_HID ":03" + +void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link); +void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card); /* * Maxim MAX98357A/MAX98360A diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index b4f07bdcf8b4..0af1e0c3a9db 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -59,7 +59,6 @@ #define SOF_SSP_BT_OFFLOAD_PRESENT BIT(22) #define SOF_RT5682S_HEADPHONE_CODEC_PRESENT BIT(23) #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) @@ -195,23 +194,6 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { SOF_RT5682_SSP_AMP(2) | SOF_RT5682_NUM_HDMIDEV(4)), }, - { - .callback = sof_rt5682_quirk_cb, - .matches = { - DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"), - DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S_4SPK"), - }, - .driver_data = (void *)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_SPEAKER_AMP_PRESENT | - SOF_MAX98390_SPEAKER_AMP_PRESENT | - SOF_MAX98390_TWEETER_SPEAKER_PRESENT | - SOF_RT5682_SSP_AMP(1) | - SOF_RT5682_NUM_HDMIDEV(4) | - SOF_BT_OFFLOAD_SSP(2) | - SOF_SSP_BT_OFFLOAD_PRESENT), - - }, { .callback = sof_rt5682_quirk_cb, .matches = { @@ -850,17 +832,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, sof_rt1011_dai_link(&links[id]); } else if (sof_rt5682_quirk & SOF_MAX98390_SPEAKER_AMP_PRESENT) { - if (sof_rt5682_quirk & - SOF_MAX98390_TWEETER_SPEAKER_PRESENT) { - links[id].codecs = max_98390_4spk_components; - links[id].num_codecs = ARRAY_SIZE(max_98390_4spk_components); - } else { - links[id].codecs = max_98390_components; - links[id].num_codecs = ARRAY_SIZE(max_98390_components); - } - links[id].init = max_98390_spk_codec_init; - links[id].ops = &max_98390_ops; - + max_98390_dai_link(dev, &links[id]); } else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) { links[id].codecs = &rt5650_components[1]; links[id].num_codecs = 1; @@ -1019,12 +991,7 @@ static int sof_audio_probe(struct platform_device *pdev) else if (sof_rt5682_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) sof_rt1015p_codec_conf(&sof_audio_card_rt5682); else if (sof_rt5682_quirk & SOF_MAX98390_SPEAKER_AMP_PRESENT) { - if (sof_rt5682_quirk & SOF_MAX98390_TWEETER_SPEAKER_PRESENT) - max_98390_set_codec_conf(&sof_audio_card_rt5682, - ARRAY_SIZE(max_98390_4spk_components)); - else - max_98390_set_codec_conf(&sof_audio_card_rt5682, - ARRAY_SIZE(max_98390_components)); + max_98390_set_codec_conf(&pdev->dev, &sof_audio_card_rt5682); } if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) -- cgit v1.2.3 From 390e7066db29b985c5142513955797c1166b623a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:37:41 -0500 Subject: ASoC: SOF: sof-client-probes-ipc4: add checks to prevent static analysis warnings make KCFLAGS='-fanalyzer' sound/soc/sof/ reports several NULL pointer dereference paths. sof_ipc4_probe_get_module_info() can return a NULL value, but it's only tested in the init state. Static analyzers cannot know the probe state machine and hence flags a potential issue for all calls of that function. Squelch these errors by adding the same check consistently. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Daniel Baluta Reviewed-by: Yaochun Hung Link: https://lore.kernel.org/r/20230731213748.440285-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-client-probes-ipc4.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/sof-client-probes-ipc4.c b/sound/soc/sof/sof-client-probes-ipc4.c index ea21ef176c42..c56a85854d92 100644 --- a/sound/soc/sof/sof-client-probes-ipc4.c +++ b/sound/soc/sof/sof-client-probes-ipc4.c @@ -146,6 +146,9 @@ static int ipc4_probes_deinit(struct sof_client_dev *cdev) struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev); struct sof_ipc4_msg msg; + if (!mentry) + return -ENODEV; + msg.primary = mentry->id; msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_DELETE_INSTANCE); msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); @@ -197,6 +200,9 @@ static int ipc4_probes_points_add(struct sof_client_dev *cdev, struct sof_ipc4_msg msg; int i, ret; + if (!mentry) + return -ENODEV; + /* The sof_probe_point_desc and sof_ipc4_probe_point structs * are of same size and even the integers are the same in the * same order, and similar meaning, but since there is no @@ -247,6 +253,9 @@ static int ipc4_probes_points_remove(struct sof_client_dev *cdev, u32 *probe_point_ids; int i, ret; + if (!mentry) + return -ENODEV; + probe_point_ids = kcalloc(num_buffer_id, sizeof(*probe_point_ids), GFP_KERNEL); if (!probe_point_ids) -- cgit v1.2.3 From e44222c213678d6ef646d72cbb9a2eda52f6dc22 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:37:42 -0500 Subject: ASoC: SOF: ipc3: add checks to prevent static analysis warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit make KCFLAGS='-fanalyzer' sound/soc/sof/ reports an issue with memcpy: sound/soc/sof/ipc3.c: In function ‘ipc3_wait_tx_done’: sound/soc/sof/ipc3.c:309:33: error: use of NULL ‘reply_data’ where non-null expected [CWE-476] [-Werror=analyzer-null-argument] 309 | memcpy(reply_data, msg->reply_data, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 310 | msg->reply_size); The finding is legit with this call: return sof_ipc3_tx_msg(sdev, &pm_ctx, sizeof(pm_ctx), NULL, 0, false); Static analysis has no way of knowing that the reply will be zero-sized. Add a check to only do the memcpy if the reply size is not zero and the destination pointer is not NULL. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Daniel Baluta Reviewed-by: Yaochun Hung Link: https://lore.kernel.org/r/20230731213748.440285-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index 2c5aac31e8b0..09834205b119 100644 --- a/sound/soc/sof/ipc3.c +++ b/sound/soc/sof/ipc3.c @@ -312,7 +312,7 @@ static int ipc3_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data) } else { if (sof_debug_check_flag(SOF_DBG_PRINT_IPC_SUCCESS_LOGS)) ipc3_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd); - if (msg->reply_size) + if (reply_data && msg->reply_size) /* copy the data returned from DSP */ memcpy(reply_data, msg->reply_data, msg->reply_size); -- cgit v1.2.3 From 55cb3dc271d81f1982c949a2ac483a6daf613b92 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:37:43 -0500 Subject: ASoC: SOF: topology: simplify code to prevent static analysis warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit make KCFLAGS='-fanalyzer' sound/soc/sof/intel/ reports a possible NULL pointer dereference. sound/soc/sof/topology.c:1136:21: error: dereference of NULL ‘w’ [CWE-476] [-Werror=analyzer-null-dereference] 1136 | strcmp(w->sname, rtd->dai_link->stream_name)) The code is rather confusing and can be simplified to make static analysis happy. No functionality change. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Daniel Baluta Reviewed-by: Yaochun Hung Link: https://lore.kernel.org/r/20230731213748.440285-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 698129dccc7d..3866dd3cba69 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1117,10 +1117,11 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp, { struct snd_soc_card *card = scomp->card; struct snd_soc_pcm_runtime *rtd; + const char *sname = w->sname; struct snd_soc_dai *cpu_dai; int i, stream; - if (!w->sname) + if (!sname) return; if (w->id == snd_soc_dapm_dai_out) @@ -1133,7 +1134,7 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp, list_for_each_entry(rtd, &card->rtd_list, list) { /* does stream match DAI link ? */ if (!rtd->dai_link->stream_name || - strcmp(w->sname, rtd->dai_link->stream_name)) + strcmp(sname, rtd->dai_link->stream_name)) continue; for_each_rtd_cpu_dais(rtd, i, cpu_dai) -- cgit v1.2.3 From 64778b022e629b8ffa97d23a9adbf670aa3bb1d8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:37:46 -0500 Subject: ASoC: Intel: bdw_rt286: add checks to avoid static analysis warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit snd_soc_card_get_codec_dai() can return NULL, but that value is not checked for, leading to false-positive static analysis warnings sound/soc/intel/boards/bdw_rt286.c:190:16: error: dereference of NULL ‘codec_dai’ [CWE-476] [-Werror=analyzer-null-dereference] 190 | return snd_soc_component_set_jack(codec_dai->component, NULL, NULL); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ‘card_suspend_pre’: event 1 | | 190 | return snd_soc_component_set_jack(codec_dai->component, NULL, NULL); | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (1) dereference of NULL ‘codec_dai’ This NULL dereference cannot happen, the codec-dai "rt286-aif1" must exists otherwise the card would not be created. Static analysis cannot know that however so we might as well squelch this report. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Daniel Baluta Reviewed-by: Yaochun Hung Link: https://lore.kernel.org/r/20230731213748.440285-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bdw_rt286.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/bdw_rt286.c b/sound/soc/intel/boards/bdw_rt286.c index b7687a93a923..036579331d8f 100644 --- a/sound/soc/intel/boards/bdw_rt286.c +++ b/sound/soc/intel/boards/bdw_rt286.c @@ -187,6 +187,9 @@ static int card_suspend_pre(struct snd_soc_card *card) { struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1"); + if (!codec_dai) + return 0; + return snd_soc_component_set_jack(codec_dai->component, NULL, NULL); } @@ -194,6 +197,9 @@ static int card_resume_post(struct snd_soc_card *card) { struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1"); + if (!codec_dai) + return 0; + return snd_soc_component_set_jack(codec_dai->component, &card_headset, NULL); } -- cgit v1.2.3 From 71d76768fbe72aa70dd61d5714a5579dc4ca61cb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:37:47 -0500 Subject: ASoC: Intel: atom: remove static analysis false positive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit make KCFLAGS='-fanalyzer' sound/soc/intel/atom/ reports a possible NULL pointer dereference. sound/soc/intel/atom/sst/sst_stream.c:221:40: error: dereference of NULL ‘block’ [CWE-476] [-Werror=analyzer-null-dereference] 221 | unsigned char *r = block->data; This is a false-positive, the GCC analyzer generated that report by considering if (bytes->block) as true in some cases and false in others. We can simplify the code and use a local variable so that static analysis does not try to look for cases where bytes->block can be modified concurrently. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Daniel Baluta Reviewed-by: Yaochun Hung Link: https://lore.kernel.org/r/20230731213748.440285-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_stream.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index 862a19ae5429..288221db7323 100644 --- a/sound/soc/intel/atom/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -173,10 +173,11 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, u32 length; int pvt_id, ret = 0; struct sst_block *block = NULL; + u8 bytes_block = bytes->block; dev_dbg(sst_drv_ctx->dev, "type:%u ipc_msg:%u block:%u task_id:%u pipe: %#x length:%#x\n", - bytes->type, bytes->ipc_msg, bytes->block, bytes->task_id, + bytes->type, bytes->ipc_msg, bytes_block, bytes->task_id, bytes->pipe_id, bytes->len); if (sst_create_ipc_msg(&msg, true)) @@ -185,12 +186,12 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, pvt_id = sst_assign_pvt_id(sst_drv_ctx); sst_fill_header_mrfld(&msg->mrfld_header, bytes->ipc_msg, bytes->task_id, 1, pvt_id); - msg->mrfld_header.p.header_high.part.res_rqd = bytes->block; + msg->mrfld_header.p.header_high.part.res_rqd = bytes_block; length = bytes->len; msg->mrfld_header.p.header_low_payload = length; dev_dbg(sst_drv_ctx->dev, "length is %d\n", length); memcpy(msg->mailbox_data, &bytes->bytes, bytes->len); - if (bytes->block) { + if (bytes_block) { block = sst_create_block(sst_drv_ctx, bytes->ipc_msg, pvt_id); if (block == NULL) { kfree(msg); @@ -203,7 +204,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, dev_dbg(sst_drv_ctx->dev, "msg->mrfld_header.p.header_low_payload:%d", msg->mrfld_header.p.header_low_payload); - if (bytes->block) { + if (bytes_block) { ret = sst_wait_timeout(sst_drv_ctx, block); if (ret) { dev_err(sst_drv_ctx->dev, "fw returned err %d\n", ret); @@ -216,7 +217,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, * copy the reply and send back * we need to update only sz and payload */ - if (bytes->block) { + if (bytes_block) { unsigned char *r = block->data; dev_dbg(sst_drv_ctx->dev, "read back %d bytes", @@ -224,7 +225,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, memcpy(bytes->bytes, r, bytes->len); } } - if (bytes->block) + if (bytes_block) sst_free_block(sst_drv_ctx, block); out: test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id); -- cgit v1.2.3 From 871861f6ad6d43b49caade3f42b9d40ca1413e79 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:37:48 -0500 Subject: ASoC: amd: acp5x-mach:add checks to avoid static analysis warnings snd_soc_card_get_codec_dai() can return NULL, but that value is not checked for, leading to static analysis warnings. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Daniel Baluta Reviewed-by: Yaochun Hung Link: https://lore.kernel.org/r/20230731213748.440285-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/amd/vangogh/acp5x-mach.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/amd/vangogh/acp5x-mach.c b/sound/soc/amd/vangogh/acp5x-mach.c index 125a8e93478d..eda464545866 100644 --- a/sound/soc/amd/vangogh/acp5x-mach.c +++ b/sound/soc/amd/vangogh/acp5x-mach.c @@ -170,6 +170,9 @@ static int acp5x_nau8821_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai = snd_soc_card_get_codec_dai(card, ACP5X_NAU8821_DAI_NAME); int ret, bclk; + if (!dai) + return -EINVAL; + ret = snd_soc_dai_set_sysclk(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); -- cgit v1.2.3 From e63e2810edd229e320249dc85c20c22f4894919e Mon Sep 17 00:00:00 2001 From: Balamurugan C Date: Mon, 31 Jul 2023 16:42:35 -0500 Subject: ASoC: Intel: soc-acpi: Add entry for rt711-sdca-sdw at link 0 in RPL match table Adding RT711 sdca SDW codec support with SDW0 link for RPL RVP platforms Reviewed-by: Bard Liao Signed-off-by: Balamurugan C Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-rpl-match.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c index 302a08018572..99dc76c99f0d 100644 --- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -308,6 +308,15 @@ static const struct snd_soc_acpi_link_adr rpl_sdw_rt1316_link12_rt714_link0[] = {} }; +static const struct snd_soc_acpi_link_adr rpl_sdca_rvp[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_sdca_0_adr), + .adr_d = rt711_sdca_0_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr rplp_crb[] = { { .mask = BIT(2), @@ -413,6 +422,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-rpl-rt711-l0.tplg", }, + { + .link_mask = 0x1, /* link0 required */ + .links = rpl_sdca_rvp, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-rpl-rt711-l0.tplg", + }, { .link_mask = 0x4, /* link2 required */ .links = rplp_crb, -- cgit v1.2.3 From 26d9726f667e18134bfc77a3e4e0da7518a8b180 Mon Sep 17 00:00:00 2001 From: Terry Cheong Date: Mon, 31 Jul 2023 16:42:36 -0500 Subject: ASoC: Intel: sof_rt5682: add RPL support for MAX98357A speaker Adding support back to RPL devices that lost audio after the RPL/ADL split. The hardware configuration is: SSP0: 10EC5682/RTL5682 codec SSP2: MAX98357A amplifier Reviewed-by: Bard Liao Signed-off-by: Terry Cheong Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_rt5682.c | 8 ++++++++ sound/soc/intel/common/soc-acpi-intel-rpl-match.c | 12 ++++++++++++ 2 files changed, 20 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 0af1e0c3a9db..a5af6ae79933 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -1163,6 +1163,14 @@ static const struct platform_device_id board_ids[] = { SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, + { + .name = "rpl_mx98357_rt5682", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(2) | + SOF_RT5682_NUM_HDMIDEV(4)), + }, { .name = "rpl_mx98360_rt5682", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c index 99dc76c99f0d..4eefdb2dd45c 100644 --- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -331,6 +331,11 @@ static const struct snd_soc_acpi_codecs rpl_rt5682_hp = { .codecs = {"10EC5682", "RTL5682"}, }; +static const struct snd_soc_acpi_codecs rpl_max98357a_amp = { + .num_codecs = 1, + .codecs = {"MX98357A"} +}; + static const struct snd_soc_acpi_codecs rpl_max98360a_amp = { .num_codecs = 1, .codecs = {"MX98360A"}, @@ -347,6 +352,13 @@ static const struct snd_soc_acpi_codecs rpl_rt1019p_amp = { }; struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { + { + .comp_ids = &rpl_rt5682_hp, + .drv_name = "rpl_mx98357_rt5682", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &rpl_max98357a_amp, + .sof_tplg_filename = "sof-rpl-max98357a-rt5682.tplg", + }, { .comp_ids = &rpl_rt5682_hp, .drv_name = "rpl_mx98360_rt5682", -- cgit v1.2.3 From f3c37847c704c5d398fa6808c77e4f7c997c0abb Mon Sep 17 00:00:00 2001 From: apoorv Date: Mon, 31 Jul 2023 16:42:37 -0500 Subject: ASoC: Intel: sof_rt5682 add support for HDMI_In capture Adding support for 2 streams of HDMI-In capture via I2S with rt5682s codec variant Reviewed-by: CBM Reviewed-by: Bard Liao Signed-off-by: apoorv Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_rt5682.c | 47 +++++++++++++++++++++++ sound/soc/intel/common/soc-acpi-intel-adl-match.c | 7 ++++ 2 files changed, 54 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index a5af6ae79933..fae091b9b55c 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -62,6 +62,11 @@ #define SOF_RT1019_SPEAKER_AMP_PRESENT BIT(26) #define SOF_RT5650_HEADPHONE_CODEC_PRESENT BIT(27) +/* HDMI capture*/ +#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 27 +#define SOF_SSP_HDMI_CAPTURE_PRESENT_MASK (GENMASK(30, 27)) +#define SOF_HDMI_CAPTURE_SSP_MASK(quirk) \ + (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | @@ -670,6 +675,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, struct snd_soc_dai_link_component *cpus; struct snd_soc_dai_link *links; int i, id = 0; + int hdmi_id_offset = 0; links = devm_kcalloc(dev, sof_audio_card_rt5682.num_links, sizeof(struct snd_soc_dai_link), GFP_KERNEL); @@ -891,6 +897,34 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].num_cpus = 1; } + /* HDMI-In SSP */ + if (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) { + unsigned long hdmi_in_ssp = (sof_rt5682_quirk & + SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >> + SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; + int port = 0; + + for_each_set_bit(port, &hdmi_in_ssp, 32) { + links[id].cpus = &cpus[id]; + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d Pin", port); + if (!links[id].cpus->dai_name) + return NULL; + links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port); + if (!links[id].name) + return NULL; + links[id].id = id + hdmi_id_offset; + links[id].codecs = &asoc_dummy_dlc; + links[id].num_codecs = 1; + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].dpcm_capture = 1; + links[id].no_pcm = 1; + links[id].num_cpus = 1; + id++; + } + } + return links; devm_err: return NULL; @@ -997,6 +1031,11 @@ static int sof_audio_probe(struct platform_device *pdev) if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) sof_audio_card_rt5682.num_links++; + if (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) + sof_audio_card_rt5682.num_links += + hweight32((sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >> + SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT); + dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp, dmic_be_num, hdmi_num, ctx->idisp_codec); if (!dai_links) @@ -1163,6 +1202,14 @@ static const struct platform_device_id board_ids[] = { SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, + { + .name = "adl_rt5682_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(1) | + SOF_RT5682_NUM_HDMIDEV(3) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_HDMI_CAPTURE_SSP_MASK(0x5)), + }, { .name = "rpl_mx98357_rt5682", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c index bcd66e0094b4..8e995edf4c10 100644 --- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c @@ -568,6 +568,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { .quirk_data = &adl_max98390_amp, .sof_tplg_filename = "sof-adl-max98390-rt5682.tplg", }, + { + .comp_ids = &adl_rt5682_rt5682s_hp, + .drv_name = "adl_rt5682_c1_h02", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &adl_lt6911_hdmi, + .sof_tplg_filename = "sof-adl-rt5682-ssp1-hdmi-ssp02.tplg", + }, { .comp_ids = &adl_rt5682_rt5682s_hp, .drv_name = "adl_rt5682", -- cgit v1.2.3 From a14aded9299187bb17ef90700eb2cf1120ef5885 Mon Sep 17 00:00:00 2001 From: Uday M Bhat Date: Mon, 31 Jul 2023 16:42:38 -0500 Subject: ASoC: Intel: sof_sdw: Update BT offload config for soundwire config For soundwire config, SSP1 is used for BT offload. This is enabled in sof_sdw_quirk_table Reviewed-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Signed-off-by: Uday M Bhat Signed-off-by: Jairaj Arava Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index dbee8c98ff01..b811446be4cd 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -467,7 +467,9 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Google"), DMI_MATCH(DMI_PRODUCT_NAME, "Rex"), }, - .driver_data = (void *)(SOF_SDW_PCH_DMIC), + .driver_data = (void *)(SOF_SDW_PCH_DMIC | + SOF_BT_OFFLOAD_SSP(1) | + SOF_SSP_BT_OFFLOAD_PRESENT), }, /* LunarLake devices */ { -- cgit v1.2.3 From 4b68ce6912fd87b1743eb2e66aeba81cae2067fe Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:42:39 -0500 Subject: ASoC: Intel: sof_sdw: reorder SoundWire codecs in Kconfig No functionality change, just sort Realtek codecs using increasing part IDs. Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 1fe830af2b84..141fba0f8c70 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -671,12 +671,12 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH select SND_SOC_RT711_SDCA_SDW select SND_SOC_RT712_SDCA_SDW select SND_SOC_RT712_SDCA_DMIC_SDW + select SND_SOC_RT715_SDW + select SND_SOC_RT715_SDCA_SDW select SND_SOC_RT1308_SDW select SND_SOC_RT1308 select SND_SOC_RT1316_SDW select SND_SOC_RT1318_SDW - select SND_SOC_RT715_SDW - select SND_SOC_RT715_SDCA_SDW select SND_SOC_RT5682_SDW select SND_SOC_CS42L42_SDW select SND_SOC_DMIC -- cgit v1.2.3 From 3390d4ed823e716618095c16ad6792f33cc66190 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:42:40 -0500 Subject: ASoC: Intel: sof_sdw: allow mockup amplifier to provide feedback The capture setting are missing and preventing topologies with feedback from loading. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index b811446be4cd..7e43be46cfa8 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -942,10 +942,10 @@ static struct sof_sdw_codec_info codec_info_list[] = { .version_id = 0, .dais = { { - .direction = {true, false}, + .direction = {true, true}, .dai_name = "sdw-mockup-aif1", .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, + .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, .init = NULL, }, }, -- cgit v1.2.3 From 616bee2c06ca1cd24631ae0db1b4cba1d6b9ad25 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 31 Jul 2023 16:42:41 -0500 Subject: ASoC: Intel: sof_sdw: rename link_id to be_id The link_id parameter in create_sdw_dailink is actually the BE link id. Rename it to be_id to be consistent with the caller and less confusion. No functionality change. Reviewed-by: Rander Wang Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 7e43be46cfa8..acaedd3b2224 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1354,7 +1354,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, const struct snd_soc_acpi_link_adr *link, int *cpu_id, bool *group_generated, struct snd_soc_codec_conf *codec_conf, - int codec_count, int *link_id, + int codec_count, int *be_id, int *codec_conf_index, bool *ignore_pch_dmic, bool append_dai_type, @@ -1433,9 +1433,9 @@ static int create_sdw_dailink(struct snd_soc_card *card, if (!codec_info->dais[dai_index].direction[stream]) continue; - *link_id = codec_info->dais[dai_index].dailink[stream]; - if (*link_id < 0) { - dev_err(dev, "Invalid dailink id %d\n", *link_id); + *be_id = codec_info->dais[dai_index].dailink[stream]; + if (*be_id < 0) { + dev_err(dev, "Invalid dailink id %d\n", *be_id); return -EINVAL; } @@ -1492,7 +1492,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); capture = (stream == SNDRV_PCM_STREAM_CAPTURE); - init_dai_link(dev, dai_links + *link_index, (*link_id)++, name, + init_dai_link(dev, dai_links + *link_index, (*be_id)++, name, playback, capture, cpus + *cpu_id, cpu_dai_num, codecs, codec_num, -- cgit v1.2.3 From 0cc85f2bfbcb84754ee6cd43a6fb9953f18cd2dc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:42:42 -0500 Subject: ASoC: Intel: sof_sdw: add support for SKU 0AFE Yet another missing configuration, with the standard configuration link0: rt711-sdca link 1 and 2: rt1316-sdca link3: rt714-sdca Link: https://github.com/thesofproject/sof/issues/7799 Reviewed-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index acaedd3b2224..ffb0cd0700c4 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -307,6 +307,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { .driver_data = (void *)(SOF_SDW_TGL_HDMI | SOF_SDW_FOUR_SPK), }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2 | + SOF_SDW_FOUR_SPK), + }, { .callback = sof_sdw_quirk_cb, .matches = { -- cgit v1.2.3 From 1d1062382b1807679e9001d79704112525576057 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:43 -0500 Subject: ASoC: intel: sof_sdw: Use consistent variable naming for links The driver makes extensive use of both ACPI link and ASoC DAI link structs, often referring to both with the variable name link. Make the code a little easier to follow by consistently using adr_link for the ACPI bits and dai_links for the ASoC bits. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 118 ++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 58 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index ffb0cd0700c4..6f65f45bded6 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1021,10 +1021,10 @@ static inline int find_codec_info_acpi(const u8 *acpi_id) * Since some sdw slaves may be aggregated, the CPU DAI number * may be larger than the number of BE dailinks. */ -static int get_sdw_dailink_info(struct device *dev, const struct snd_soc_acpi_link_adr *links, +static int get_sdw_dailink_info(struct device *dev, + const struct snd_soc_acpi_link_adr *adr_link, int *sdw_be_num, int *sdw_cpu_dai_num) { - const struct snd_soc_acpi_link_adr *link; bool group_visited[SDW_MAX_GROUPS]; bool no_aggregation; int i; @@ -1034,27 +1034,27 @@ static int get_sdw_dailink_info(struct device *dev, const struct snd_soc_acpi_li *sdw_cpu_dai_num = 0; *sdw_be_num = 0; - if (!links) + if (!adr_link) return -EINVAL; for (i = 0; i < SDW_MAX_GROUPS; i++) group_visited[i] = false; - for (link = links; link->num_adr; link++) { + for (; adr_link->num_adr; adr_link++) { const struct snd_soc_acpi_endpoint *endpoint; struct sof_sdw_codec_info *codec_info; int codec_index; int stream; u64 adr; - for (i = 0; i < link->num_adr; i++) { - adr = link->adr_d[i].adr; + for (i = 0; i < adr_link->num_adr; i++) { + adr = adr_link->adr_d[i].adr; codec_index = find_codec_info_part(adr); if (codec_index < 0) return codec_index; codec_info = &codec_info_list[codec_index]; - endpoint = link->adr_d[i].endpoints; + endpoint = adr_link->adr_d[i].endpoints; for (j = 0; j < codec_info->dai_num; j++) { /* count DAI number for playback and capture */ @@ -1102,7 +1102,7 @@ static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links dai_links->ops = ops; } -static bool is_unique_device(const struct snd_soc_acpi_link_adr *link, +static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, unsigned int sdw_version, unsigned int mfg_id, unsigned int part_id, @@ -1112,7 +1112,7 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *link, { int i; - for (i = 0; i < link->num_adr; i++) { + for (i = 0; i < adr_link->num_adr; i++) { unsigned int sdw1_version, mfg1_id, part1_id, class1_id; u64 adr; @@ -1120,7 +1120,7 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *link, if (i == index_in_link) continue; - adr = link->adr_d[i].adr; + adr = adr_link->adr_d[i].adr; sdw1_version = SDW_VERSION(adr); mfg1_id = SDW_MFG_ID(adr); @@ -1138,7 +1138,7 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *link, } static int create_codec_dai_name(struct device *dev, - const struct snd_soc_acpi_link_adr *link, + const struct snd_soc_acpi_link_adr *adr_link, struct snd_soc_dai_link_component *codec, int offset, struct snd_soc_codec_conf *codec_conf, @@ -1151,19 +1151,19 @@ static int create_codec_dai_name(struct device *dev, int i; /* sanity check */ - if (*codec_conf_index + link->num_adr - adr_index > codec_count) { + if (*codec_conf_index + adr_link->num_adr - adr_index > codec_count) { dev_err(dev, "codec_conf: out-of-bounds access requested\n"); return -EINVAL; } - for (i = adr_index; i < link->num_adr; i++) { + for (i = adr_index; i < adr_link->num_adr; i++) { unsigned int sdw_version, unique_id, mfg_id; unsigned int link_id, part_id, class_id; int codec_index, comp_index; char *codec_str; u64 adr; - adr = link->adr_d[i].adr; + adr = adr_link->adr_d[i].adr; sdw_version = SDW_VERSION(adr); link_id = SDW_DISCO_LINK_ID(adr); @@ -1173,7 +1173,7 @@ static int create_codec_dai_name(struct device *dev, class_id = SDW_CLASS_ID(adr); comp_index = i - adr_index + offset; - if (is_unique_device(link, sdw_version, mfg_id, part_id, + if (is_unique_device(adr_link, sdw_version, mfg_id, part_id, class_id, i)) { codec_str = "sdw:%01x:%04x:%04x:%02x"; codec[comp_index].name = @@ -1204,7 +1204,7 @@ static int create_codec_dai_name(struct device *dev, codec_info_list[codec_index].dais[dai_index].dai_name; codec_conf[*codec_conf_index].dlc = codec[comp_index]; - codec_conf[*codec_conf_index].name_prefix = link->adr_d[i].name_prefix; + codec_conf[*codec_conf_index].name_prefix = adr_link->adr_d[i].name_prefix; ++*codec_conf_index; } @@ -1213,7 +1213,7 @@ static int create_codec_dai_name(struct device *dev, } static int set_codec_init_func(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, + const struct snd_soc_acpi_link_adr *adr_link, struct snd_soc_dai_link *dai_links, bool playback, int group_id, int adr_index, int dai_index) { @@ -1224,34 +1224,35 @@ static int set_codec_init_func(struct snd_soc_card *card, * Initialize the codec. If codec is part of an aggregated * group (group_id>0), initialize all codecs belonging to * same group. - * The first link should start with link->adr_d[adr_index] + * The first link should start with adr_link->adr_d[adr_index] * because that is the device that we want to initialize and * we should end immediately if it is not aggregated (group_id=0) */ - for ( ; i < link->num_adr; i++) { + for ( ; i < adr_link->num_adr; i++) { int codec_index; - codec_index = find_codec_info_part(link->adr_d[i].adr); + codec_index = find_codec_info_part(adr_link->adr_d[i].adr); if (codec_index < 0) return codec_index; /* The group_id is > 0 iff the codec is aggregated */ - if (link->adr_d[i].endpoints->group_id != group_id) + if (adr_link->adr_d[i].endpoints->group_id != group_id) continue; if (codec_info_list[codec_index].dais[dai_index].init) codec_info_list[codec_index].dais[dai_index].init(card, - link, + adr_link, dai_links, &codec_info_list[codec_index], playback); if (!group_id) return 0; } + i = 0; - link++; - } while (link->mask); + adr_link++; + } while (adr_link->mask); return 0; } @@ -1361,7 +1362,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, struct snd_soc_dai_link *dai_links, int sdw_be_num, int sdw_cpu_dai_num, struct snd_soc_dai_link_component *cpus, - const struct snd_soc_acpi_link_adr *link, + const struct snd_soc_acpi_link_adr *adr_link, int *cpu_id, bool *group_generated, struct snd_soc_codec_conf *codec_conf, int codec_count, int *be_id, @@ -1371,7 +1372,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int adr_index, int dai_index) { - const struct snd_soc_acpi_link_adr *link_next; + const struct snd_soc_acpi_link_adr *adr_link_next; struct snd_soc_dai_link_component *codecs; struct sof_sdw_codec_info *codec_info; int cpu_dai_id[SDW_MAX_CPU_DAIS]; @@ -1385,7 +1386,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int ret; int k; - ret = get_slave_info(link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, + ret = get_slave_info(adr_link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, &group_id, group_generated, adr_index); if (ret) return ret; @@ -1395,20 +1396,20 @@ static int create_sdw_dailink(struct snd_soc_card *card, return -ENOMEM; /* generate codec name on different links in the same group */ - for (link_next = link; link_next && link_next->num_adr && - i < cpu_dai_num; link_next++) { + for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr && + i < cpu_dai_num; adr_link_next++) { const struct snd_soc_acpi_endpoint *endpoints; - endpoints = link_next->adr_d->endpoints; + endpoints = adr_link_next->adr_d->endpoints; if (group_id && (!endpoints->aggregated || endpoints->group_id != group_id)) continue; /* skip the link excluded by this processed group */ - if (cpu_dai_id[i] != ffs(link_next->mask) - 1) + if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) continue; - ret = create_codec_dai_name(dev, link_next, codecs, codec_idx, + ret = create_codec_dai_name(dev, adr_link_next, codecs, codec_idx, codec_conf, codec_count, codec_conf_index, adr_index, dai_index); if (ret < 0) @@ -1416,11 +1417,11 @@ static int create_sdw_dailink(struct snd_soc_card *card, /* check next link to create codec dai in the processed group */ i++; - codec_idx += link_next->num_adr; + codec_idx += adr_link_next->num_adr; } /* find codec info to create BE DAI */ - codec_index = find_codec_info_part(link->adr_d[adr_index].adr); + codec_index = find_codec_info_part(adr_link->adr_d[adr_index].adr); if (codec_index < 0) return codec_index; codec_info = &codec_info_list[codec_index]; @@ -1516,7 +1517,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, set_dailink_map(sdw_codec_ch_maps, codec_num, cpu_dai_num); dai_links[*link_index].codec_ch_maps = sdw_codec_ch_maps; - ret = set_codec_init_func(card, link, dai_links + (*link_index)++, + ret = set_codec_init_func(card, adr_link, dai_links + (*link_index)++, playback, group_id, adr_index, dai_index); if (ret < 0) { dev_err(dev, "failed to init codec %d", codec_index); @@ -1589,7 +1590,7 @@ static int sof_card_dai_links_create(struct device *dev, int codec_conf_index = 0; bool group_generated[SDW_MAX_GROUPS]; int ssp_codec_index, ssp_mask; - struct snd_soc_dai_link *links; + struct snd_soc_dai_link *dai_links; int num_links, link_index = 0; char *name, *cpu_name; int total_cpu_dai_num; @@ -1650,14 +1651,14 @@ static int sof_card_dai_links_create(struct device *dev, /* allocate BE dailinks */ num_links = comp_num + sdw_be_num; - links = devm_kcalloc(dev, num_links, sizeof(*links), GFP_KERNEL); + dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL); /* allocated CPU DAIs */ total_cpu_dai_num = comp_num + sdw_cpu_dai_num; cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus), GFP_KERNEL); - if (!links || !cpus) + if (!dai_links || !cpus) return -ENOMEM; /* SDW */ @@ -1731,9 +1732,9 @@ out: return codec_index; for (j = 0; j < codec_info_list[codec_index].dai_num ; j++) { - ret = create_sdw_dailink(card, dev, &link_index, links, sdw_be_num, - sdw_cpu_dai_num, cpus, adr_link, - &cpu_id, group_generated, + ret = create_sdw_dailink(card, dev, &link_index, dai_links, + sdw_be_num, sdw_cpu_dai_num, cpus, + adr_link, &cpu_id, group_generated, codec_conf, codec_conf_count, &be_id, &codec_conf_index, &ignore_pch_dmic, append_dai_type, i, j); @@ -1785,13 +1786,13 @@ SSP: playback = info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK]; capture = info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE]; - init_dai_link(dev, links + link_index, be_id, name, + init_dai_link(dev, dai_links + link_index, be_id, name, playback, capture, cpus + cpu_id, 1, ssp_components, 1, NULL, info->ops); - ret = info->dais[0].init(card, NULL, links + link_index, info, 0); + ret = info->dais[0].init(card, NULL, dai_links + link_index, info, 0); if (ret < 0) return ret; @@ -1806,7 +1807,7 @@ DMIC: goto HDMI; } cpus[cpu_id].dai_name = "DMIC01 Pin"; - init_dai_link(dev, links + link_index, be_id, "dmic01", + init_dai_link(dev, dai_links + link_index, be_id, "dmic01", 0, 1, // DMIC only supports capture cpus + cpu_id, 1, dmic_component, 1, @@ -1814,7 +1815,7 @@ DMIC: INC_ID(be_id, cpu_id, link_index); cpus[cpu_id].dai_name = "DMIC16k Pin"; - init_dai_link(dev, links + link_index, be_id, "dmic16k", + init_dai_link(dev, dai_links + link_index, be_id, "dmic16k", 0, 1, // DMIC only supports capture cpus + cpu_id, 1, dmic_component, 1, @@ -1857,7 +1858,7 @@ HDMI: return -ENOMEM; cpus[cpu_id].dai_name = cpu_name; - init_dai_link(dev, links + link_index, be_id, name, + init_dai_link(dev, dai_links + link_index, be_id, name, 1, 0, // HDMI only supports playback cpus + cpu_id, 1, idisp_components + i, 1, @@ -1878,11 +1879,11 @@ HDMI: return -ENOMEM; cpus[cpu_id].dai_name = cpu_name; - init_dai_link(dev, links + link_index, be_id, name, 1, 1, - cpus + cpu_id, 1, &asoc_dummy_dlc, 1, NULL, NULL); + init_dai_link(dev, dai_links + link_index, be_id, name, 1, 1, + cpus + cpu_id, 1, &asoc_dummy_dlc, 1, NULL, NULL); } - card->dai_link = links; + card->dai_link = dai_links; card->num_links = num_links; card->codec_conf = codec_conf; @@ -1925,15 +1926,15 @@ static struct snd_soc_card card_sof_sdw = { static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card, const char *dai_name) { - struct snd_soc_dai_link *link; + struct snd_soc_dai_link *dai_link; int i; int j; - for_each_card_prelinks(card, i, link) { - for (j = 0; j < link->num_codecs; j++) { + for_each_card_prelinks(card, i, dai_link) { + for (j = 0; j < dai_link->num_codecs; j++) { /* Check each codec in a link */ - if (!strcmp(link->codecs[j].dai_name, dai_name)) - return link; + if (!strcmp(dai_link->codecs[j].dai_name, dai_name)) + return dai_link; } } return NULL; @@ -1941,7 +1942,7 @@ static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card static void mc_dailink_exit_loop(struct snd_soc_card *card) { - struct snd_soc_dai_link *link; + struct snd_soc_dai_link *dai_link; int ret; int i, j; @@ -1954,10 +1955,11 @@ static void mc_dailink_exit_loop(struct snd_soc_card *card) * We don't need to call .exit function if there is no matched * dai link found. */ - link = mc_find_codec_dai_used(card, codec_info_list[i].dais[j].dai_name); - if (link) { + dai_link = mc_find_codec_dai_used(card, + codec_info_list[i].dais[j].dai_name); + if (dai_link) { /* Do the .exit function if the codec dai is used in the link */ - ret = codec_info_list[i].dais[j].exit(card, link); + ret = codec_info_list[i].dais[j].exit(card, dai_link); if (ret) dev_warn(card->dev, "codec exit failed %d\n", -- cgit v1.2.3 From 4fc16d21b7abb969935162d8b01fba21496cf513 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:44 -0500 Subject: ASoC: intel: sof_sdw: Rename codec_idx to codec_dlc_index Having two local variables called codec_idx and codec_index, that refer to different things is a little confusing. Rename codec_idx to codec_dlc_index to indicate it points into the dai_link_component array. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-11-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 6f65f45bded6..0743bf04aa88 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1378,7 +1378,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int cpu_dai_id[SDW_MAX_CPU_DAIS]; int cpu_dai_num, cpu_dai_index; unsigned int group_id; - int codec_idx = 0; + int codec_dlc_index = 0; int codec_index; int codec_num; int stream; @@ -1409,7 +1409,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) continue; - ret = create_codec_dai_name(dev, adr_link_next, codecs, codec_idx, + ret = create_codec_dai_name(dev, adr_link_next, codecs, codec_dlc_index, codec_conf, codec_count, codec_conf_index, adr_index, dai_index); if (ret < 0) @@ -1417,7 +1417,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, /* check next link to create codec dai in the processed group */ i++; - codec_idx += adr_link_next->num_adr; + codec_dlc_index += adr_link_next->num_adr; } /* find codec info to create BE DAI */ -- cgit v1.2.3 From 08f62f6291bae6e0cc5f3f50e4e1043e6a270e80 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:45 -0500 Subject: ASoC: intel: sof_sdw: Remove some extra line breaks Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-12-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 0743bf04aa88..4f7ef83c21c5 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -523,7 +523,6 @@ int sdw_prepare(struct snd_pcm_substream *substream) dai = asoc_rtd_to_cpu(rtd, 0); sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); - if (IS_ERR(sdw_stream)) { dev_err(rtd->dev, "no stream found for DAI %s", dai->name); return PTR_ERR(sdw_stream); @@ -543,7 +542,6 @@ int sdw_trigger(struct snd_pcm_substream *substream, int cmd) dai = asoc_rtd_to_cpu(rtd, 0); sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); - if (IS_ERR(sdw_stream)) { dev_err(rtd->dev, "no stream found for DAI %s", dai->name); return PTR_ERR(sdw_stream); @@ -631,7 +629,6 @@ int sdw_hw_free(struct snd_pcm_substream *substream) dai = asoc_rtd_to_cpu(rtd, 0); sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); - if (IS_ERR(sdw_stream)) { dev_err(rtd->dev, "no stream found for DAI %s", dai->name); return PTR_ERR(sdw_stream); @@ -1107,8 +1104,7 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, unsigned int mfg_id, unsigned int part_id, unsigned int class_id, - int index_in_link - ) + int index_in_link) { int i; @@ -1232,7 +1228,6 @@ static int set_codec_init_func(struct snd_soc_card *card, int codec_index; codec_index = find_codec_info_part(adr_link->adr_d[i].adr); - if (codec_index < 0) return codec_index; -- cgit v1.2.3 From 18c45cb362fcd6918548a4e11128304aa634acf3 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:46 -0500 Subject: ASoC: intel: sof_sdw: Use a module device table A module device table is generally preferred over hard coding a MODULE_ALIAS. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-13-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 4f7ef83c21c5..6b55bcdccccc 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -2045,6 +2045,12 @@ static void mc_remove(struct platform_device *pdev) mc_dailink_exit_loop(card); } +static const struct platform_device_id mc_id_table[] = { + { "sof_sdw", }, + {} +}; +MODULE_DEVICE_TABLE(platform, mc_id_table); + static struct platform_driver sof_sdw_driver = { .driver = { .name = "sof_sdw", @@ -2052,6 +2058,7 @@ static struct platform_driver sof_sdw_driver = { }, .probe = mc_probe, .remove_new = mc_remove, + .id_table = mc_id_table, }; module_platform_driver(sof_sdw_driver); @@ -2061,6 +2068,5 @@ MODULE_AUTHOR("Bard Liao "); MODULE_AUTHOR("Rander Wang "); MODULE_AUTHOR("Pierre-Louis Bossart "); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:sof_sdw"); MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); -- cgit v1.2.3 From 31a54f78ad1d294432d63e9f72db08dc14cca432 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:47 -0500 Subject: ASoC: intel: sof_sdw: Simplify find_codec_info_acpi Use a return rather than a break and an additional range check. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-14-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 6b55bcdccccc..d3222f40d798 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1003,14 +1003,10 @@ static inline int find_codec_info_acpi(const u8 *acpi_id) return -EINVAL; for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) - if (!memcmp(codec_info_list[i].acpi_id, acpi_id, - ACPI_ID_LEN)) - break; - - if (i == ARRAY_SIZE(codec_info_list)) - return -EINVAL; + if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN)) + return i; - return i; + return -EINVAL; } /* -- cgit v1.2.3 From fad1a9eff67d34b6f90cf4d1d2f1dc2632dfeeb4 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:48 -0500 Subject: ASoC: intel: sof_sdw: Constify parameter to find_codec_part_info The address passed to find_codec_part_info should be const. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-15-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index d3222f40d798..fc67029b3a64 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -974,7 +974,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { }, }; -static inline int find_codec_info_part(u64 adr) +static inline int find_codec_info_part(const u64 adr) { unsigned int part_id, sdw_version; int i; -- cgit v1.2.3 From 855e69f4ff9d726df4c8c47e7b40934fdb49d9c5 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:49 -0500 Subject: ASoC: intel: sof_sdw: Minor tidy up of mc_probe Shuffle things around to group operations a little more, and consistently use card->dev. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-16-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index fc67029b3a64..d4f2711b6f26 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1964,34 +1964,34 @@ static void mc_dailink_exit_loop(struct snd_soc_card *card) static int mc_probe(struct platform_device *pdev) { struct snd_soc_card *card = &card_sof_sdw; - struct snd_soc_acpi_mach *mach; + struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); struct mc_private *ctx; int amp_num = 0, i; int ret; - dev_dbg(&pdev->dev, "Entry\n"); + card->dev = &pdev->dev; + + dev_dbg(card->dev, "Entry\n"); - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + ctx = devm_kzalloc(card->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + snd_soc_card_set_drvdata(card, ctx); + dmi_check_system(sof_sdw_quirk_table); if (quirk_override != -1) { - dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n", + dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", sof_sdw_quirk, quirk_override); sof_sdw_quirk = quirk_override; } - log_quirks(&pdev->dev); - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - card->dev = &pdev->dev; - snd_soc_card_set_drvdata(card, ctx); + log_quirks(card->dev); - mach = pdev->dev.platform_data; - ret = sof_card_dai_links_create(&pdev->dev, mach, - card); + ret = sof_card_dai_links_create(card->dev, mach, card); if (ret < 0) return ret; @@ -2022,7 +2022,7 @@ static int mc_probe(struct platform_device *pdev) card->long_name = sdw_card_long_name; /* Register the card */ - ret = devm_snd_soc_register_card(&pdev->dev, card); + ret = devm_snd_soc_register_card(card->dev, card); if (ret) { dev_err(card->dev, "snd_soc_register_card failed %d\n", ret); mc_dailink_exit_loop(card); -- cgit v1.2.3 From febac07b4c69242d7870944457c3a1158ab97bdc Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:50 -0500 Subject: ASoC: intel: sof_sdw: Remove redundant parameters in dai creation Pull the device and mach struct out of the card rather than explicitly passing to sof_card_dai_links_create. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-17-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index d4f2711b6f26..dc5337ea75da 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1348,8 +1348,7 @@ static void set_dailink_map(struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_m static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; -static int create_sdw_dailink(struct snd_soc_card *card, - struct device *dev, int *link_index, +static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, struct snd_soc_dai_link *dai_links, int sdw_be_num, int sdw_cpu_dai_num, struct snd_soc_dai_link_component *cpus, @@ -1363,6 +1362,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int adr_index, int dai_index) { + struct device *dev = card->dev; const struct snd_soc_acpi_link_adr *adr_link_next; struct snd_soc_dai_link_component *codecs; struct sof_sdw_codec_info *codec_info; @@ -1563,10 +1563,10 @@ static int sof_card_codec_conf_alloc(struct device *dev, return 0; } -static int sof_card_dai_links_create(struct device *dev, - struct snd_soc_acpi_mach *mach, - struct snd_soc_card *card) +static int sof_card_dai_links_create(struct snd_soc_card *card) { + struct device *dev = card->dev; + struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); int ssp_num, sdw_be_num = 0, hdmi_num = 0, dmic_num; struct mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_dai_link_component *idisp_components; @@ -1723,7 +1723,7 @@ out: return codec_index; for (j = 0; j < codec_info_list[codec_index].dai_num ; j++) { - ret = create_sdw_dailink(card, dev, &link_index, dai_links, + ret = create_sdw_dailink(card, &link_index, dai_links, sdw_be_num, sdw_cpu_dai_num, cpus, adr_link, &cpu_id, group_generated, codec_conf, codec_conf_count, @@ -1991,7 +1991,7 @@ static int mc_probe(struct platform_device *pdev) log_quirks(card->dev); - ret = sof_card_dai_links_create(card->dev, mach, card); + ret = sof_card_dai_links_create(card); if (ret < 0) return ret; -- cgit v1.2.3 From 8673e68b594684fac53398ec5783a6c8469a07a1 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:51 -0500 Subject: ASoC: intel: sof_sdw: Move amp_num initialisation to mc_probe The amp_num member of the info struct is zeroed at the start of sof_card_dai_links_create, but then summed in mc_probe after sof_card_dai_links_create is called. It is a little clearer to hoist the initialisation out of sof_card_dai_links_create so it is on the same level as the summation. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-18-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index dc5337ea75da..1a60965439dd 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1599,10 +1599,6 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) if (ret < 0) return ret; - /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) - codec_info_list[i].amp_num = 0; - if (mach_params->codec_mask & IDISP_CODEC_MASK) { ctx->idisp_codec = true; @@ -1991,6 +1987,10 @@ static int mc_probe(struct platform_device *pdev) log_quirks(card->dev); + /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ + for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) + codec_info_list[i].amp_num = 0; + ret = sof_card_dai_links_create(card); if (ret < 0) return ret; -- cgit v1.2.3 From 656dd91a3a1ca27a02d9a79d1720b2ca40d272cf Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 31 Jul 2023 16:42:52 -0500 Subject: ASoC: Intel: sof_sdw: break earlier when a adr link contains different codecs create_codec_dai_name() is used to create codec component's information in different adr links. We can and should break before we do anything. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-19-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 1a60965439dd..846ba8e1515c 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1157,6 +1157,15 @@ static int create_codec_dai_name(struct device *dev, adr = adr_link->adr_d[i].adr; + codec_index = find_codec_info_part(adr); + if (codec_index < 0) + return codec_index; + if (_codec_index != -1 && codec_index != _codec_index) { + dev_dbg(dev, "Different devices on the same sdw link\n"); + break; + } + _codec_index = codec_index; + sdw_version = SDW_VERSION(adr); link_id = SDW_DISCO_LINK_ID(adr); unique_id = SDW_UNIQUE_ID(adr); @@ -1183,15 +1192,6 @@ static int create_codec_dai_name(struct device *dev, if (!codec[comp_index].name) return -ENOMEM; - codec_index = find_codec_info_part(adr); - if (codec_index < 0) - return codec_index; - if (_codec_index != -1 && codec_index != _codec_index) { - dev_dbg(dev, "Different devices on the same sdw link\n"); - break; - } - _codec_index = codec_index; - codec[comp_index].dai_name = codec_info_list[codec_index].dais[dai_index].dai_name; -- cgit v1.2.3 From 009582008182bc0a2956d245fd0362e036f31dfe Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:53 -0500 Subject: ASoC: intel: sof_sdw: Allow direct specification of CODEC name Add support for MFD based CODEC drivers, by allowing the CODEC name to not be the SoundWire device directly. Signed-off-by: Charles Keepax Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-20-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 6 +++++- sound/soc/intel/boards/sof_sdw_common.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 846ba8e1515c..e6faed2b99b2 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1174,7 +1174,11 @@ static int create_codec_dai_name(struct device *dev, class_id = SDW_CLASS_ID(adr); comp_index = i - adr_index + offset; - if (is_unique_device(adr_link, sdw_version, mfg_id, part_id, + if (codec_info_list[codec_index].codec_name) { + codec[comp_index].name = + devm_kstrdup(dev, codec_info_list[codec_index].codec_name, + GFP_KERNEL); + } else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id, class_id, i)) { codec_str = "sdw:%01x:%04x:%04x:%02x"; codec[comp_index].name = diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index 37402170d5f9..fe234b98eb64 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -80,6 +80,7 @@ struct sof_sdw_dai_info { struct sof_sdw_codec_info { const int part_id; const int version_id; + const char *codec_name; int amp_num; const u8 acpi_id[ACPI_ID_LEN]; const bool ignore_pch_dmic; -- cgit v1.2.3 From 4754e29c779fe2a2677ba62896daf4bf980602a1 Mon Sep 17 00:00:00 2001 From: Chao Song Date: Mon, 31 Jul 2023 16:42:54 -0500 Subject: ASoC: Intel: sof_sdw: add cs35l56 codec info Add cs35l56 support in sof_sdw machine driver. Reviewed-by: Rander Wang Signed-off-by: Chao Song Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-21-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 1 + sound/soc/intel/boards/Makefile | 2 +- sound/soc/intel/boards/sof_sdw.c | 13 +++++++++ sound/soc/intel/boards/sof_sdw_common.h | 6 +++++ sound/soc/intel/boards/sof_sdw_cs_amp.c | 47 +++++++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/boards/sof_sdw_cs_amp.c (limited to 'sound') diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 141fba0f8c70..0ae6eecc8851 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -679,6 +679,7 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH select SND_SOC_RT1318_SDW select SND_SOC_RT5682_SDW select SND_SOC_CS42L42_SDW + select SND_SOC_CS35L56_SDW select SND_SOC_DMIC select SND_SOC_INTEL_HDA_DSP_COMMON select SND_SOC_INTEL_SOF_MAXIM_COMMON diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 931415d9cf6f..a570b5b40f22 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -42,7 +42,7 @@ snd-soc-sof-sdw-objs += sof_sdw.o \ sof_sdw_rt711.o sof_sdw_rt_sdca_jack_common.o \ sof_sdw_rt712_sdca.o sof_sdw_rt715.o \ sof_sdw_rt715_sdca.o sof_sdw_dmic.o \ - sof_sdw_cs42l42.o \ + sof_sdw_cs42l42.o sof_sdw_cs_amp.o \ sof_sdw_hdmi.o obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_SOF_CS42L42_MACH) += snd-soc-sof_cs42l42.o diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index e6faed2b99b2..5dbfcd88ab3c 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -903,6 +903,19 @@ static struct sof_sdw_codec_info codec_info_list[] = { }, .dai_num = 1, }, + { + .part_id = 0x3556, + .dais = { + { + .direction = {true, true}, + .dai_name = "cs35l56-sdw1", + .dai_type = SOF_SDW_DAI_TYPE_AMP, + .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, + .init = sof_sdw_cs_amp_init, + }, + }, + .dai_num = 1, + }, { .part_id = 0x4242, .dais = { diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index fe234b98eb64..2f4fe6bc3d5d 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -206,4 +206,10 @@ int sof_sdw_cs42l42_init(struct snd_soc_card *card, struct sof_sdw_codec_info *info, bool playback); +/* CS AMP support */ +int sof_sdw_cs_amp_init(struct snd_soc_card *card, + const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback); #endif diff --git a/sound/soc/intel/boards/sof_sdw_cs_amp.c b/sound/soc/intel/boards/sof_sdw_cs_amp.c new file mode 100644 index 000000000000..98f6546f484b --- /dev/null +++ b/sound/soc/intel/boards/sof_sdw_cs_amp.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2023 Intel Corporation + +/* + * sof_sdw_cs_amp - Helpers to handle CS35L56 from generic machine driver + */ + +#include +#include +#include +#include +#include "sof_sdw_common.h" + +#define CODEC_NAME_SIZE 8 + +static int cs_spk_init(struct snd_soc_pcm_runtime *rtd) +{ + const char *dai_name = rtd->dai_link->codecs->dai_name; + struct snd_soc_card *card = rtd->card; + char codec_name[CODEC_NAME_SIZE]; + + snprintf(codec_name, CODEC_NAME_SIZE, "%s", dai_name); + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s spk:%s", + card->components, codec_name); + if (!card->components) + return -ENOMEM; + + return 0; +} + + +int sof_sdw_cs_amp_init(struct snd_soc_card *card, + const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback) +{ + /* Count amp number and do init on playback link only. */ + if (!playback) + return 0; + + info->amp_num++; + dai_links->init = cs_spk_init; + + return 0; +} -- cgit v1.2.3 From 98a7a1143f83289a84cba6dab60a4531cc4dfae2 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:55 -0500 Subject: ASoC: intel: sof_sdw: Clean up DAI link counting The counting of each of the types of DAI link is a bit messy with things added onto an intermediate variable as it goes along. Re-order things a little to keep the order consistent with the rest of the function and simplify the process down to a variable for each type of DAI and then sum them at the end. Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-22-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 61 +++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 32 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 5dbfcd88ab3c..dc6ea21b3341 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1584,12 +1584,12 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) { struct device *dev = card->dev; struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); - int ssp_num, sdw_be_num = 0, hdmi_num = 0, dmic_num; + int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, hdmi_num = 0, bt_num = 0; struct mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_dai_link_component *idisp_components; struct snd_soc_dai_link_component *ssp_components; - struct snd_soc_acpi_mach_params *mach_params; - const struct snd_soc_acpi_link_adr *adr_link; + struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; + const struct snd_soc_acpi_link_adr *adr_link = mach_params->links; struct snd_soc_dai_link_component *cpus; struct snd_soc_codec_conf *codec_conf; bool append_dai_type = false; @@ -1606,26 +1606,19 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) int i, j, be_id = 0; int codec_index; int cpu_id = 0; - int comp_num; int ret; - mach_params = &mach->mach_params; - /* allocate codec conf, will be populated when dailinks are created */ ret = sof_card_codec_conf_alloc(dev, mach_params, &codec_conf, &codec_conf_count); if (ret < 0) return ret; - if (mach_params->codec_mask & IDISP_CODEC_MASK) { - ctx->idisp_codec = true; - - if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) - hdmi_num = SOF_TGL_HDMI_COUNT; - else - hdmi_num = SOF_PRE_TGL_HDMI_COUNT; + ret = get_sdw_dailink_info(dev, adr_link, &sdw_be_num, &sdw_cpu_dai_num); + if (ret < 0) { + dev_err(dev, "failed to get sdw link info %d\n", ret); + return ret; } - ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); /* * on generic tgl platform, I2S or sdw mode is supported * based on board rework. A ACPI device is registered in @@ -1633,36 +1626,40 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) * Here check ACPI ID to confirm I2S is supported. */ ssp_codec_index = find_codec_info_acpi(mach->id); - ssp_num = ssp_codec_index >= 0 ? hweight_long(ssp_mask) : 0; - comp_num = hdmi_num + ssp_num; + if (ssp_codec_index >= 0) { + ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); + ssp_num = hweight_long(ssp_mask); + } - ret = get_sdw_dailink_info(dev, mach_params->links, - &sdw_be_num, &sdw_cpu_dai_num); - if (ret < 0) { - dev_err(dev, "failed to get sdw link info %d", ret); - return ret; + if (mach_params->codec_mask & IDISP_CODEC_MASK) { + ctx->idisp_codec = true; + + if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) + hdmi_num = SOF_TGL_HDMI_COUNT; + else + hdmi_num = SOF_PRE_TGL_HDMI_COUNT; } /* enable dmic01 & dmic16k */ - dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0; - comp_num += dmic_num; + if (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) + dmic_num = 2; if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) - comp_num++; + bt_num = 1; - dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d", sdw_be_num, ssp_num, - dmic_num, ctx->idisp_codec ? hdmi_num : 0); + dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n", + sdw_be_num, ssp_num, dmic_num, hdmi_num, bt_num); /* allocate BE dailinks */ - num_links = comp_num + sdw_be_num; + num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num; dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL); + if (!dai_links) + return -ENOMEM; /* allocated CPU DAIs */ - total_cpu_dai_num = comp_num + sdw_cpu_dai_num; - cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus), - GFP_KERNEL); - - if (!dai_links || !cpus) + total_cpu_dai_num = sdw_cpu_dai_num + ssp_num + dmic_num + hdmi_num + bt_num; + cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus), GFP_KERNEL); + if (!cpus) return -ENOMEM; /* SDW */ -- cgit v1.2.3 From a386162e7dc2c8bc1be2777b1c6d41156f69b210 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:56 -0500 Subject: ASoC: intel: sof_sdw: Merge codec_conf_alloc into dailink_info Rename get_sdw_dailink_info to simply get_dailink_info and have it also return the number of codecs present. Then hoist the allocation of the codec conf structure up into sof_card_dai_links_create. This saves an extra loop through the adr_link array, allows us to get rid of sof_card_codec_conf_alloc and makes the allocation more explicit. Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-23-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 75 ++++++++++++---------------------------- 1 file changed, 23 insertions(+), 52 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index dc6ea21b3341..25644eff5251 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1027,9 +1027,9 @@ static inline int find_codec_info_acpi(const u8 *acpi_id) * Since some sdw slaves may be aggregated, the CPU DAI number * may be larger than the number of BE dailinks. */ -static int get_sdw_dailink_info(struct device *dev, - const struct snd_soc_acpi_link_adr *adr_link, - int *sdw_be_num, int *sdw_cpu_dai_num) +static int get_dailink_info(struct device *dev, + const struct snd_soc_acpi_link_adr *adr_link, + int *sdw_be_num, int *sdw_cpu_dai_num, int *codecs_num) { bool group_visited[SDW_MAX_GROUPS]; bool no_aggregation; @@ -1058,8 +1058,17 @@ static int get_sdw_dailink_info(struct device *dev, codec_index = find_codec_info_part(adr); if (codec_index < 0) return codec_index; + codec_info = &codec_info_list[codec_index]; + *codecs_num += codec_info->dai_num; + + if (!adr_link->adr_d[i].name_prefix) { + dev_err(dev, "codec 0x%llx does not have a name prefix\n", + adr_link->adr_d[i].adr); + return -EINVAL; + } + endpoint = adr_link->adr_d[i].endpoints; for (j = 0; j < codec_info->dai_num; j++) { @@ -1540,46 +1549,6 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, #define IDISP_CODEC_MASK 0x4 -static int sof_card_codec_conf_alloc(struct device *dev, - struct snd_soc_acpi_mach_params *mach_params, - struct snd_soc_codec_conf **codec_conf, - int *codec_conf_count) -{ - const struct snd_soc_acpi_link_adr *adr_link; - struct snd_soc_codec_conf *c_conf; - int num_codecs = 0; - int codec_index; - int i; - - adr_link = mach_params->links; - if (!adr_link) - return -EINVAL; - - /* generate DAI links by each sdw link */ - for (; adr_link->num_adr; adr_link++) { - for (i = 0; i < adr_link->num_adr; i++) { - if (!adr_link->adr_d[i].name_prefix) { - dev_err(dev, "codec 0x%llx does not have a name prefix\n", - adr_link->adr_d[i].adr); - return -EINVAL; - } - codec_index = find_codec_info_part(adr_link->adr_d[i].adr); - if (codec_index < 0) - return codec_index; - num_codecs += codec_info_list[codec_index].dai_num; - } - } - - c_conf = devm_kzalloc(dev, num_codecs * sizeof(*c_conf), GFP_KERNEL); - if (!c_conf) - return -ENOMEM; - - *codec_conf = c_conf; - *codec_conf_count = num_codecs; - - return 0; -} - static int sof_card_dai_links_create(struct snd_soc_card *card) { struct device *dev = card->dev; @@ -1594,7 +1563,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) struct snd_soc_codec_conf *codec_conf; bool append_dai_type = false; bool ignore_pch_dmic = false; - int codec_conf_count; + int codec_conf_num = 0; int codec_conf_index = 0; bool group_generated[SDW_MAX_GROUPS]; int ssp_codec_index, ssp_mask; @@ -1608,12 +1577,8 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) int cpu_id = 0; int ret; - /* allocate codec conf, will be populated when dailinks are created */ - ret = sof_card_codec_conf_alloc(dev, mach_params, &codec_conf, &codec_conf_count); - if (ret < 0) - return ret; - - ret = get_sdw_dailink_info(dev, adr_link, &sdw_be_num, &sdw_cpu_dai_num); + ret = get_dailink_info(dev, adr_link, &sdw_be_num, &sdw_cpu_dai_num, + &codec_conf_num); if (ret < 0) { dev_err(dev, "failed to get sdw link info %d\n", ret); return ret; @@ -1662,6 +1627,12 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) if (!cpus) return -ENOMEM; + /* allocate codec conf, will be populated when dailinks are created */ + codec_conf = devm_kcalloc(dev, codec_conf_num, sizeof(*codec_conf), + GFP_KERNEL); + if (!codec_conf) + return -ENOMEM; + /* SDW */ if (!sdw_be_num) goto SSP; @@ -1736,7 +1707,7 @@ out: ret = create_sdw_dailink(card, &link_index, dai_links, sdw_be_num, sdw_cpu_dai_num, cpus, adr_link, &cpu_id, group_generated, - codec_conf, codec_conf_count, + codec_conf, codec_conf_num, &be_id, &codec_conf_index, &ignore_pch_dmic, append_dai_type, i, j); if (ret < 0) { @@ -1888,7 +1859,7 @@ HDMI: card->num_links = num_links; card->codec_conf = codec_conf; - card->num_configs = codec_conf_count; + card->num_configs = codec_conf_num; return 0; } -- cgit v1.2.3 From a60ed3b738705dbcb4afce9a24af00e2671edf19 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 31 Jul 2023 16:42:57 -0500 Subject: ASoC: intel: sof_sdw: Move group_generated logic Hoist the handling logic for group_generated up to the sof_card_dai_links_create level. This avoids the need to pass the array through multiple levels of functions. Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731214257.444605-24-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 25644eff5251..fd27e211211b 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1291,7 +1291,7 @@ static int set_codec_init_func(struct snd_soc_card *card, static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, struct device *dev, int *cpu_dai_id, int *cpu_dai_num, int *codec_num, unsigned int *group_id, - bool *group_generated, int adr_index) + int adr_index) { const struct snd_soc_acpi_adr_device *adr_d; const struct snd_soc_acpi_link_adr *adr_next; @@ -1351,11 +1351,6 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, } } - /* - * indicate CPU DAIs for this group have been generated - * to avoid generating CPU DAIs for this group again. - */ - group_generated[*group_id] = true; *cpu_dai_num = index; return 0; @@ -1379,8 +1374,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, int sdw_be_num, int sdw_cpu_dai_num, struct snd_soc_dai_link_component *cpus, const struct snd_soc_acpi_link_adr *adr_link, - int *cpu_id, bool *group_generated, - struct snd_soc_codec_conf *codec_conf, + int *cpu_id, struct snd_soc_codec_conf *codec_conf, int codec_count, int *be_id, int *codec_conf_index, bool *ignore_pch_dmic, @@ -1404,7 +1398,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, int k; ret = get_slave_info(adr_link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, - &group_id, group_generated, adr_index); + &group_id, adr_index); if (ret) return ret; @@ -1559,13 +1553,14 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) struct snd_soc_dai_link_component *ssp_components; struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; const struct snd_soc_acpi_link_adr *adr_link = mach_params->links; + bool aggregation = !(sof_sdw_quirk & SOF_SDW_NO_AGGREGATION); struct snd_soc_dai_link_component *cpus; struct snd_soc_codec_conf *codec_conf; bool append_dai_type = false; bool ignore_pch_dmic = false; int codec_conf_num = 0; int codec_conf_index = 0; - bool group_generated[SDW_MAX_GROUPS]; + bool group_generated[SDW_MAX_GROUPS] = { }; int ssp_codec_index, ssp_mask; struct snd_soc_dai_link *dai_links; int num_links, link_index = 0; @@ -1641,14 +1636,6 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) if (!adr_link) return -EINVAL; - /* - * SoundWire Slaves aggregated in the same group may be - * located on different hardware links. Clear array to indicate - * CPU DAIs for this group have not been generated. - */ - for (i = 0; i < SDW_MAX_GROUPS; i++) - group_generated[i] = false; - for (i = 0; i < SDW_MAX_LINKS; i++) sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE; @@ -1706,7 +1693,7 @@ out: for (j = 0; j < codec_info_list[codec_index].dai_num ; j++) { ret = create_sdw_dailink(card, &link_index, dai_links, sdw_be_num, sdw_cpu_dai_num, cpus, - adr_link, &cpu_id, group_generated, + adr_link, &cpu_id, codec_conf, codec_conf_num, &be_id, &codec_conf_index, &ignore_pch_dmic, append_dai_type, i, j); @@ -1715,6 +1702,9 @@ out: return ret; } } + + if (aggregation && endpoint->aggregated) + group_generated[endpoint->group_id] = true; } } -- cgit v1.2.3 From 799d9933ba47d9b679637fa17454ed81ac353f52 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:32:37 -0500 Subject: ASoC: SOF: Intel: start simplify the signature of link_slaves_found() Start removing Intel-specific arguments to make that function usable by other SOC vendors. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230731213242.434594-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 64bebe1a72bb..6d9fafb58581 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1433,13 +1433,11 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, SDW_MFG_ID_MASK | SDW_PART_ID_MASK)) /* Check if all Slaves defined on the link can be found */ -static bool link_slaves_found(struct snd_sof_dev *sdev, +static bool link_slaves_found(struct device *dev, const struct snd_soc_acpi_link_adr *link, - struct sdw_intel_ctx *sdw) + struct sdw_intel_slave_id *ids, + int num_slaves) { - struct hdac_bus *bus = sof_to_bus(sdev); - struct sdw_intel_slave_id *ids = sdw->ids; - int num_slaves = sdw->num_slaves; unsigned int part_id, link_id, unique_id, mfg_id, version; int i, j, k; @@ -1487,19 +1485,16 @@ static bool link_slaves_found(struct snd_sof_dev *sdev, unique_id = SDW_UNIQUE_ID(adr); if (reported_part_count == 1 || ids[j].id.unique_id == unique_id) { - dev_dbg(bus->dev, "found %x at link %d\n", - part_id, link_id); + dev_dbg(dev, "found %x at link %d\n", part_id, link_id); break; } } else { - dev_dbg(bus->dev, "part %x reported %d expected %d on link %d, skipping\n", + dev_dbg(dev, "part %x reported %d expected %d on link %d, skipping\n", part_id, reported_part_count, expected_part_count, link_id); } } if (j == num_slaves) { - dev_dbg(bus->dev, - "Slave %x not found\n", - part_id); + dev_dbg(dev, "Slave %x not found\n", part_id); return false; } } @@ -1549,7 +1544,7 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev * Try next machine if any expected Slaves * are not found on this link. */ - if (!link_slaves_found(sdev, link, hdev->sdw)) + if (!link_slaves_found(sdev->dev, link, hdev->sdw->ids, hdev->sdw->num_slaves)) break; } /* Found if all Slaves are checked */ -- cgit v1.2.3 From bb29a33c4b4da9c11e021b9a257ae2944ccaff01 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:32:38 -0500 Subject: ASoC: soc-acpi: move link_slaves_found() Move existing function in common library to make sure the code can be reused by other SoC vendors. No functionality change outside of the move and added prefix. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230731213242.434594-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-acpi.c | 73 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.c | 76 ++--------------------------------------------- 2 files changed, 76 insertions(+), 73 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c index 142476f1396f..9319e9b2a033 100644 --- a/sound/soc/soc-acpi.c +++ b/sound/soc/soc-acpi.c @@ -125,5 +125,78 @@ struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) } EXPORT_SYMBOL_GPL(snd_soc_acpi_codec_list); +#define SDW_CODEC_ADR_MASK(_adr) ((_adr) & (SDW_DISCO_LINK_ID_MASK | SDW_VERSION_MASK | \ + SDW_MFG_ID_MASK | SDW_PART_ID_MASK)) + +/* Check if all Slaves defined on the link can be found */ +bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev, + const struct snd_soc_acpi_link_adr *link, + struct sdw_extended_slave_id *ids, + int num_slaves) +{ + unsigned int part_id, link_id, unique_id, mfg_id, version; + int i, j, k; + + for (i = 0; i < link->num_adr; i++) { + u64 adr = link->adr_d[i].adr; + int reported_part_count = 0; + + mfg_id = SDW_MFG_ID(adr); + part_id = SDW_PART_ID(adr); + link_id = SDW_DISCO_LINK_ID(adr); + version = SDW_VERSION(adr); + + for (j = 0; j < num_slaves; j++) { + /* find out how many identical parts were reported on that link */ + if (ids[j].link_id == link_id && + ids[j].id.part_id == part_id && + ids[j].id.mfg_id == mfg_id && + ids[j].id.sdw_version == version) + reported_part_count++; + } + + for (j = 0; j < num_slaves; j++) { + int expected_part_count = 0; + + if (ids[j].link_id != link_id || + ids[j].id.part_id != part_id || + ids[j].id.mfg_id != mfg_id || + ids[j].id.sdw_version != version) + continue; + + /* find out how many identical parts are expected */ + for (k = 0; k < link->num_adr; k++) { + u64 adr2 = link->adr_d[k].adr; + + if (SDW_CODEC_ADR_MASK(adr2) == SDW_CODEC_ADR_MASK(adr)) + expected_part_count++; + } + + if (reported_part_count == expected_part_count) { + /* + * we have to check unique id + * if there is more than one + * Slave on the link + */ + unique_id = SDW_UNIQUE_ID(adr); + if (reported_part_count == 1 || + ids[j].id.unique_id == unique_id) { + dev_dbg(dev, "found %x at link %d\n", part_id, link_id); + break; + } + } else { + dev_dbg(dev, "part %x reported %d expected %d on link %d, skipping\n", + part_id, reported_part_count, expected_part_count, link_id); + } + } + if (j == num_slaves) { + dev_dbg(dev, "Slave %x not found\n", part_id); + return false; + } + } + return true; +} +EXPORT_SYMBOL_GPL(snd_soc_acpi_sdw_link_slaves_found); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("ALSA SoC ACPI module"); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 6d9fafb58581..a77c0a52dcad 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1429,78 +1429,6 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) -#define SDW_CODEC_ADR_MASK(_adr) ((_adr) & (SDW_DISCO_LINK_ID_MASK | SDW_VERSION_MASK | \ - SDW_MFG_ID_MASK | SDW_PART_ID_MASK)) - -/* Check if all Slaves defined on the link can be found */ -static bool link_slaves_found(struct device *dev, - const struct snd_soc_acpi_link_adr *link, - struct sdw_intel_slave_id *ids, - int num_slaves) -{ - unsigned int part_id, link_id, unique_id, mfg_id, version; - int i, j, k; - - for (i = 0; i < link->num_adr; i++) { - u64 adr = link->adr_d[i].adr; - int reported_part_count = 0; - - mfg_id = SDW_MFG_ID(adr); - part_id = SDW_PART_ID(adr); - link_id = SDW_DISCO_LINK_ID(adr); - version = SDW_VERSION(adr); - - for (j = 0; j < num_slaves; j++) { - /* find out how many identical parts were reported on that link */ - if (ids[j].link_id == link_id && - ids[j].id.part_id == part_id && - ids[j].id.mfg_id == mfg_id && - ids[j].id.sdw_version == version) - reported_part_count++; - } - - for (j = 0; j < num_slaves; j++) { - int expected_part_count = 0; - - if (ids[j].link_id != link_id || - ids[j].id.part_id != part_id || - ids[j].id.mfg_id != mfg_id || - ids[j].id.sdw_version != version) - continue; - - /* find out how many identical parts are expected */ - for (k = 0; k < link->num_adr; k++) { - u64 adr2 = link->adr_d[k].adr; - - if (SDW_CODEC_ADR_MASK(adr2) == SDW_CODEC_ADR_MASK(adr)) - expected_part_count++; - } - - if (reported_part_count == expected_part_count) { - /* - * we have to check unique id - * if there is more than one - * Slave on the link - */ - unique_id = SDW_UNIQUE_ID(adr); - if (reported_part_count == 1 || - ids[j].id.unique_id == unique_id) { - dev_dbg(dev, "found %x at link %d\n", part_id, link_id); - break; - } - } else { - dev_dbg(dev, "part %x reported %d expected %d on link %d, skipping\n", - part_id, reported_part_count, expected_part_count, link_id); - } - } - if (j == num_slaves) { - dev_dbg(dev, "Slave %x not found\n", part_id); - return false; - } - } - return true; -} - static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev) { struct snd_sof_pdata *pdata = sdev->pdata; @@ -1544,7 +1472,9 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev * Try next machine if any expected Slaves * are not found on this link. */ - if (!link_slaves_found(sdev->dev, link, hdev->sdw->ids, hdev->sdw->num_slaves)) + if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link, + hdev->sdw->ids, + hdev->sdw->num_slaves)) break; } /* Found if all Slaves are checked */ -- cgit v1.2.3 From cf35ab3d58c65a924ef8caf5c40e5849d4aa253e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 16:32:39 -0500 Subject: ASoC: soc-acpi: improve log messagesin link_slaves_found() use 'part_id' to follow MIPI/SoundWire wording and use more consistent %#x format. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230731213242.434594-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-acpi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c index 9319e9b2a033..6d693b2ad5a3 100644 --- a/sound/soc/soc-acpi.c +++ b/sound/soc/soc-acpi.c @@ -181,16 +181,16 @@ bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev, unique_id = SDW_UNIQUE_ID(adr); if (reported_part_count == 1 || ids[j].id.unique_id == unique_id) { - dev_dbg(dev, "found %x at link %d\n", part_id, link_id); + dev_dbg(dev, "found part_id %#x at link %d\n", part_id, link_id); break; } } else { - dev_dbg(dev, "part %x reported %d expected %d on link %d, skipping\n", + dev_dbg(dev, "part_id %#x reported %d expected %d on link %d, skipping\n", part_id, reported_part_count, expected_part_count, link_id); } } if (j == num_slaves) { - dev_dbg(dev, "Slave %x not found\n", part_id); + dev_dbg(dev, "Slave part_id %#x not found\n", part_id); return false; } } -- cgit v1.2.3 From ed19c4a9b1024c4069d3d9f4daa3eb26a622069d Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Mon, 31 Jul 2023 16:32:40 -0500 Subject: ASoC: SOF: ipc3: update dai_link_fixup for SOF_DAI_MEDIATEK_AFE For MediaTek AFE, DAI DMA can support different bitwidths compared to the BE DAI. Therefore, it is preferable to obtain the BE frame format from the DAI_CONFIG. Reviewed-by: Yaochun Hung Reviewed-by: Daniel Baluta Signed-off-by: Trevor Wu Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230731213242.434594-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc3-pcm.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index 304faf6425ab..cb58ee8c158a 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -309,6 +309,23 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = private->dai_config->afe.channels; channels->max = private->dai_config->afe.channels; + snd_mask_none(fmt); + + switch (private->dai_config->afe.format) { + case SOF_IPC_FRAME_S16_LE: + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); + break; + case SOF_IPC_FRAME_S24_4LE: + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + break; + case SOF_IPC_FRAME_S32_LE: + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); + break; + default: + dev_err(component->dev, "Not available format!\n"); + return -EINVAL; + } + dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max); dev_dbg(component->dev, "channels_min: %d channels_max: %d\n", channels->min, channels->max); -- cgit v1.2.3 From 7b6466ad1d7bfa178d28f125d75187c4f6597f2d Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 31 Jul 2023 17:57:18 +0100 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From c36570970a585bc816e15478fde71476f96f5e9c Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 31 Jul 2023 17:57:19 +0100 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From 15c378d66fc5bd00ce7c8ac869624f9a4a29d1d4 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 31 Jul 2023 17:57:20 +0100 Subject: 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(+) (limited to 'sound') 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); -- cgit v1.2.3 From e5bac77b67082e59f7aceea08a30b5dc66138643 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 31 Jul 2023 17:57:21 +0100 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From fb78d73dde2d4d91e2372685159d67a43cf7b8f3 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 31 Jul 2023 17:57:22 +0100 Subject: 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(+) (limited to 'sound') 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) -- cgit v1.2.3 From 0ba0dfd969926563016e706346a9caba7f5a15ac Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 31 Jul 2023 17:57:23 +0100 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From 2f860dd895381c8d120e68526f34fe9b29da4310 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 31 Jul 2023 17:57:24 +0100 Subject: 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(-) (limited to 'sound') 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 @@ 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); cs35l56_hda_release_firmware_files(wmfw_firmware, wmfw_filename, coeff_firmware, coeff_filename); +err_pm_put: + pm_runtime_put(cs35l56->base.dev); return ret; } -- cgit v1.2.3 From 3106797d2b0b09e7a27f09fac329f1d6e9b35270 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 31 Jul 2023 17:57:25 +0100 Subject: 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(-) (limited to 'sound') 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 @@ err_powered_up: 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: -- cgit v1.2.3 From 8ca3ee6f3f64673f377fc8f5ed163f71181c85ad Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 31 Jul 2023 17:57:26 +0100 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From fbeb1ec85dc6079b44766e225104bfdc8ea9fe6c Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Tue, 1 Aug 2023 22:45:12 +0800 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From d28dc3d87fe298d0bd83c33738c0c09a0e4f7bdb Mon Sep 17 00:00:00 2001 From: Yu Liao Date: Wed, 2 Aug 2023 10:26:49 +0800 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From 51d765f79c8d8016df906afd05410f8bc14167ac Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Wed, 2 Aug 2023 13:21:15 +0800 Subject: ASoC: fsl_micfil: Add new registers and new bit definition MICFIL IP is upgraded on i.MX93 platform. These new registers and new bit definition are added to complete the register list. Signed-off-by: Chancel Liu Acked-by: Shengjiu Wang Link: https://lore.kernel.org/r/20230802052117.1293029-2-chancel.liu@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_micfil.c | 6 ++++++ sound/soc/fsl/fsl_micfil.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index fe28b27e50d0..784188181542 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -825,6 +825,9 @@ static bool fsl_micfil_readable_reg(struct device *dev, unsigned int reg) case REG_MICFIL_DC_CTRL: case REG_MICFIL_OUT_CTRL: case REG_MICFIL_OUT_STAT: + case REG_MICFIL_FSYNC_CTRL: + case REG_MICFIL_VERID: + case REG_MICFIL_PARAM: case REG_MICFIL_VAD0_CTRL1: case REG_MICFIL_VAD0_CTRL2: case REG_MICFIL_VAD0_STAT: @@ -849,6 +852,7 @@ static bool fsl_micfil_writeable_reg(struct device *dev, unsigned int reg) case REG_MICFIL_DC_CTRL: case REG_MICFIL_OUT_CTRL: case REG_MICFIL_OUT_STAT: /* Write 1 to Clear */ + case REG_MICFIL_FSYNC_CTRL: case REG_MICFIL_VAD0_CTRL1: case REG_MICFIL_VAD0_CTRL2: case REG_MICFIL_VAD0_STAT: /* Write 1 to Clear */ @@ -873,6 +877,8 @@ static bool fsl_micfil_volatile_reg(struct device *dev, unsigned int reg) case REG_MICFIL_DATACH5: case REG_MICFIL_DATACH6: case REG_MICFIL_DATACH7: + case REG_MICFIL_VERID: + case REG_MICFIL_PARAM: case REG_MICFIL_VAD0_STAT: case REG_MICFIL_VAD0_NDATA: return true; diff --git a/sound/soc/fsl/fsl_micfil.h b/sound/soc/fsl/fsl_micfil.h index 9237a1c4cb8f..b3c392ef5daf 100644 --- a/sound/soc/fsl/fsl_micfil.h +++ b/sound/soc/fsl/fsl_micfil.h @@ -24,6 +24,9 @@ #define REG_MICFIL_DC_CTRL 0x64 #define REG_MICFIL_OUT_CTRL 0x74 #define REG_MICFIL_OUT_STAT 0x7C +#define REG_MICFIL_FSYNC_CTRL 0x80 +#define REG_MICFIL_VERID 0x84 +#define REG_MICFIL_PARAM 0x88 #define REG_MICFIL_VAD0_CTRL1 0x90 #define REG_MICFIL_VAD0_CTRL2 0x94 #define REG_MICFIL_VAD0_STAT 0x98 @@ -39,6 +42,8 @@ #define MICFIL_CTRL1_DBG BIT(28) #define MICFIL_CTRL1_SRES BIT(27) #define MICFIL_CTRL1_DBGE BIT(26) +#define MICFIL_CTRL1_DECFILS BIT(20) +#define MICFIL_CTRL1_FSYNCEN BIT(16) #define MICFIL_CTRL1_DISEL_DISABLE 0 #define MICFIL_CTRL1_DISEL_DMA 1 @@ -82,6 +87,29 @@ #define MICFIL_DC_CUTOFF_152Hz 2 #define MICFIL_DC_BYPASS 3 +/* MICFIL VERID Register -- REG_MICFIL_VERID */ +#define MICFIL_VERID_MAJOR_SHIFT 24 +#define MICFIL_VERID_MAJOR_MASK GENMASK(31, 24) +#define MICFIL_VERID_MINOR_SHIFT 16 +#define MICFIL_VERID_MINOR_MASK GENMASK(23, 16) +#define MICFIL_VERID_FEATURE_SHIFT 0 +#define MICFIL_VERID_FEATURE_MASK GENMASK(15, 0) + +/* MICFIL PARAM Register -- REG_MICFIL_PARAM */ +#define MICFIL_PARAM_NUM_HWVAD_SHIFT 24 +#define MICFIL_PARAM_NUM_HWVAD_MASK GENMASK(27, 24) +#define MICFIL_PARAM_HWVAD_ZCD BIT(19) +#define MICFIL_PARAM_HWVAD_ENERGY_MODE BIT(17) +#define MICFIL_PARAM_HWVAD BIT(16) +#define MICFIL_PARAM_DC_OUT_BYPASS BIT(11) +#define MICFIL_PARAM_DC_IN_BYPASS BIT(10) +#define MICFIL_PARAM_LOW_POWER BIT(9) +#define MICFIL_PARAM_FIL_OUT_WIDTH BIT(8) +#define MICFIL_PARAM_FIFO_PTRWID_SHIFT 4 +#define MICFIL_PARAM_FIFO_PTRWID_MASK GENMASK(7, 4) +#define MICFIL_PARAM_NPAIR_SHIFT 0 +#define MICFIL_PARAM_NPAIR_MASK GENMASK(3, 0) + /* MICFIL HWVAD0 Control 1 Register -- REG_MICFIL_VAD0_CTRL1*/ #define MICFIL_VAD0_CTRL1_CHSEL GENMASK(26, 24) #define MICFIL_VAD0_CTRL1_CICOSR GENMASK(19, 16) -- cgit v1.2.3 From 367365051b06e172c91172e3273eea72988ce8f6 Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Wed, 2 Aug 2023 13:21:16 +0800 Subject: ASoC: fsl_micfil: Add fsl_micfil_use_verid function fsl_micfil_use_verid() can help to parse the version info in VERID and PARAM registers. Since the two registers are added only on i.MX93 platform, a member flag called use_verid is introduced to soc data structure which indicates acquiring MICFIL version. Signed-off-by: Chancel Liu Acked-by: Shengjiu Wang Link: https://lore.kernel.org/r/20230802052117.1293029-3-chancel.liu@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_micfil.c | 76 ++++++++++++++++++++++++++++++++++++++++++++-- sound/soc/fsl/fsl_micfil.h | 36 ++++++++++++++++++++++ 2 files changed, 110 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 784188181542..ad8b39081739 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -56,6 +56,8 @@ struct fsl_micfil { int vad_init_mode; int vad_enabled; int vad_detected; + struct fsl_micfil_verid verid; + struct fsl_micfil_param param; }; struct fsl_micfil_soc_data { @@ -64,6 +66,7 @@ struct fsl_micfil_soc_data { unsigned int dataline; bool imx; bool use_edma; + bool use_verid; u64 formats; }; @@ -90,6 +93,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx93 = { .dataline = 0xf, .formats = SNDRV_PCM_FMTBIT_S32_LE, .use_edma = true, + .use_verid = true, }; static const struct of_device_id fsl_micfil_dt_ids[] = { @@ -356,6 +360,49 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = { SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL), }; +static int fsl_micfil_use_verid(struct device *dev) +{ + struct fsl_micfil *micfil = dev_get_drvdata(dev); + unsigned int val; + int ret; + + if (!micfil->soc->use_verid) + return 0; + + ret = regmap_read(micfil->regmap, REG_MICFIL_VERID, &val); + if (ret < 0) + return ret; + + dev_dbg(dev, "VERID: 0x%016X\n", val); + + micfil->verid.version = val & + (MICFIL_VERID_MAJOR_MASK | MICFIL_VERID_MINOR_MASK); + micfil->verid.version >>= MICFIL_VERID_MINOR_SHIFT; + micfil->verid.feature = val & MICFIL_VERID_FEATURE_MASK; + + ret = regmap_read(micfil->regmap, REG_MICFIL_PARAM, &val); + if (ret < 0) + return ret; + + dev_dbg(dev, "PARAM: 0x%016X\n", val); + + micfil->param.hwvad_num = (val & MICFIL_PARAM_NUM_HWVAD_MASK) >> + MICFIL_PARAM_NUM_HWVAD_SHIFT; + micfil->param.hwvad_zcd = val & MICFIL_PARAM_HWVAD_ZCD; + micfil->param.hwvad_energy_mode = val & MICFIL_PARAM_HWVAD_ENERGY_MODE; + micfil->param.hwvad = val & MICFIL_PARAM_HWVAD; + micfil->param.dc_out_bypass = val & MICFIL_PARAM_DC_OUT_BYPASS; + micfil->param.dc_in_bypass = val & MICFIL_PARAM_DC_IN_BYPASS; + micfil->param.low_power = val & MICFIL_PARAM_LOW_POWER; + micfil->param.fil_out_width = val & MICFIL_PARAM_FIL_OUT_WIDTH; + micfil->param.fifo_ptrwid = (val & MICFIL_PARAM_FIFO_PTRWID_MASK) >> + MICFIL_PARAM_FIFO_PTRWID_SHIFT; + micfil->param.npair = (val & MICFIL_PARAM_NPAIR_MASK) >> + MICFIL_PARAM_NPAIR_SHIFT; + + return 0; +} + /* The SRES is a self-negated bit which provides the CPU with the * capability to initialize the PDM Interface module through the * slave-bus interface. This bit always reads as zero, and this @@ -1037,6 +1084,9 @@ static irqreturn_t hwvad_err_isr(int irq, void *devid) return IRQ_HANDLED; } +static int fsl_micfil_runtime_suspend(struct device *dev); +static int fsl_micfil_runtime_resume(struct device *dev); + static int fsl_micfil_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1156,6 +1206,25 @@ static int fsl_micfil_probe(struct platform_device *pdev) platform_set_drvdata(pdev, micfil); pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = fsl_micfil_runtime_resume(&pdev->dev); + if (ret) + goto err_pm_disable; + } + + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) + goto err_pm_get_sync; + + /* Get micfil version */ + ret = fsl_micfil_use_verid(&pdev->dev); + if (ret < 0) + dev_warn(&pdev->dev, "Error reading MICFIL version: %d\n", ret); + + ret = pm_runtime_put_sync(&pdev->dev); + if (ret < 0 && ret != -ENOSYS) + goto err_pm_get_sync; + regcache_cache_only(micfil->regmap, true); /* @@ -1180,6 +1249,9 @@ static int fsl_micfil_probe(struct platform_device *pdev) return ret; +err_pm_get_sync: + if (!pm_runtime_status_suspended(&pdev->dev)) + fsl_micfil_runtime_suspend(&pdev->dev); err_pm_disable: pm_runtime_disable(&pdev->dev); @@ -1191,7 +1263,7 @@ static void fsl_micfil_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -static int __maybe_unused fsl_micfil_runtime_suspend(struct device *dev) +static int fsl_micfil_runtime_suspend(struct device *dev) { struct fsl_micfil *micfil = dev_get_drvdata(dev); @@ -1203,7 +1275,7 @@ static int __maybe_unused fsl_micfil_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused fsl_micfil_runtime_resume(struct device *dev) +static int fsl_micfil_runtime_resume(struct device *dev) { struct fsl_micfil *micfil = dev_get_drvdata(dev); int ret; diff --git a/sound/soc/fsl/fsl_micfil.h b/sound/soc/fsl/fsl_micfil.h index b3c392ef5daf..231a52aff024 100644 --- a/sound/soc/fsl/fsl_micfil.h +++ b/sound/soc/fsl/fsl_micfil.h @@ -174,4 +174,40 @@ #define MICFIL_HWVAD_ENVELOPE_MODE 0 #define MICFIL_HWVAD_ENERGY_MODE 1 +/** + * struct fsl_micfil_verid - version id data + * @version: version number + * @feature: feature specification number + */ +struct fsl_micfil_verid { + u32 version; + u32 feature; +}; + +/** + * struct fsl_micfil_param - parameter data + * @hwvad_num: the number of HWVADs + * @hwvad_zcd: HWVAD zero-cross detector is active + * @hwvad_energy_mode: HWVAD energy mode is active + * @hwvad: HWVAD is active + * @dc_out_bypass: points out if the output DC remover is disabled + * @dc_in_bypass: points out if the input DC remover is disabled + * @low_power: low power decimation filter + * @fil_out_width: filter output width + * @fifo_ptrwid: FIFO pointer width + * @npair: number of microphone pairs + */ +struct fsl_micfil_param { + u32 hwvad_num; + bool hwvad_zcd; + bool hwvad_energy_mode; + bool hwvad; + bool dc_out_bypass; + bool dc_in_bypass; + bool low_power; + bool fil_out_width; + u32 fifo_ptrwid; + u32 npair; +}; + #endif /* _FSL_MICFIL_H */ -- cgit v1.2.3 From a38a4090e2c400c6c49c584cda6f28c73c08f5f1 Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Wed, 2 Aug 2023 13:21:17 +0800 Subject: ASoC: fsl_micfil: Use SET_SYSTEM_SLEEP_PM_OPS to simplify PM Use SET_SYSTEM_SLEEP_PM_OPS to simplify suspend and resume function. fsl_micfil_suspend() and fsl_micfil_resume() can be deleted. Signed-off-by: Chancel Liu Acked-by: Shengjiu Wang Link: https://lore.kernel.org/r/20230802052117.1293029-4-chancel.liu@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_micfil.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index ad8b39081739..b07c27c780d9 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -1297,26 +1297,12 @@ static int fsl_micfil_runtime_resume(struct device *dev) return 0; } -static int __maybe_unused fsl_micfil_suspend(struct device *dev) -{ - pm_runtime_force_suspend(dev); - - return 0; -} - -static int __maybe_unused fsl_micfil_resume(struct device *dev) -{ - pm_runtime_force_resume(dev); - - return 0; -} - static const struct dev_pm_ops fsl_micfil_pm_ops = { SET_RUNTIME_PM_OPS(fsl_micfil_runtime_suspend, fsl_micfil_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(fsl_micfil_suspend, - fsl_micfil_resume) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static struct platform_driver fsl_micfil_driver = { -- cgit v1.2.3 From cfad53a99d94478480a734602f14d09c5ec1d2da Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Wed, 2 Aug 2023 13:12:35 +0100 Subject: 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(+) (limited to 'sound') 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; } -- cgit v1.2.3 From 248c74bf42c16262f95f26523683334686a26263 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 3 Aug 2023 10:39:08 +0200 Subject: ASoC: mediatek: mt8186: Remove unused mutex. The mutex mutex_request_dram has no user. Remove mutex_request_dram. Signed-off-by: Sebastian Andrzej Siewior Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230803083908.9DxbPvOK@linutronix.de Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8186/mt8186-afe-clk.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c index 539e3a023bc4..70ec101890d3 100644 --- a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c +++ b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c @@ -13,8 +13,6 @@ #include "mt8186-afe-clk.h" #include "mt8186-audsys-clk.h" -static DEFINE_MUTEX(mutex_request_dram); - static const char *aud_clks[CLK_NUM] = { [CLK_AFE] = "aud_afe_clk", [CLK_DAC] = "aud_dac_clk", -- cgit v1.2.3 From 3bef0681682296c61f713fdb7989cb11bb836b5f Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 2 Aug 2023 10:01:02 -0500 Subject: 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(+) (limited to 'sound') 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 */ -- cgit v1.2.3 From 73e6ebf6a21a62429282632eccb8aa4212489b3c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:01:03 -0500 Subject: 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(-) (limited to 'sound') 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 -- cgit v1.2.3 From d2852b8c045ebd31d753b06f2810df5be30ed56a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:01:04 -0500 Subject: 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(+) (limited to 'sound') 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 -- cgit v1.2.3 From 3f8c530fc458142e0db0185f18153d85c4359203 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 2 Aug 2023 10:01:05 -0500 Subject: 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(-) (limited to 'sound') 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,14 +75,20 @@ static bool connectivity_check(struct pci_dev *i915, struct pci_dev *hdac) if (bus_a == bus_b) return true; - /* - * 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; + + /* 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_a == bus_b) -- cgit v1.2.3 From 1d54134df47684ee29d4d4bbe28174a4282389e0 Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Thu, 3 Aug 2023 15:50:28 +0800 Subject: ASoC: SOF: mediatek: mt8186 modify dram type as non-cache To prevent incorrect access between the host and DSP sides, we need to modify DRAM as a non-cache memory type. Additionally, we can retrieve the size of shared DMA from the device tree. Signed-off-by: Trevor Wu Reviewed-by: Yaochun Hung Reviewed-by: Kuan-Hsun Cheng Link: https://lore.kernel.org/r/20230803075028.32170-1-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8186/mt8186.c | 40 +++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index 3e0ea0e109e2..f587edf9e0a7 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -111,6 +111,14 @@ static int platform_parse_resource(struct platform_device *pdev, void *data) dev_dbg(dev, "DMA %pR\n", &res); + adsp->pa_shared_dram = (phys_addr_t)res.start; + adsp->shared_size = resource_size(&res); + if (adsp->pa_shared_dram & DRAM_REMAP_MASK) { + dev_err(dev, "adsp shared dma memory(%#x) is not 4K-aligned\n", + (u32)adsp->pa_shared_dram); + return -EINVAL; + } + ret = of_reserved_mem_device_init(dev); if (ret) { dev_err(dev, "of_reserved_mem_device_init failed\n"); @@ -244,23 +252,18 @@ static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data) { struct device *dev = &pdev->dev; struct mtk_adsp_chip_info *adsp = data; - u32 shared_size; /* remap shared-dram base to be non-cachable */ - shared_size = TOTAL_SIZE_SHARED_DRAM_FROM_TAIL; - adsp->pa_shared_dram = adsp->pa_dram + adsp->dramsize - shared_size; - if (adsp->va_dram) { - adsp->shared_dram = adsp->va_dram + DSP_DRAM_SIZE - shared_size; - } else { - adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram, - shared_size); - if (!adsp->shared_dram) { - dev_err(dev, "ioremap failed for shared DRAM\n"); - return -ENOMEM; - } + adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram, + adsp->shared_size); + if (!adsp->shared_dram) { + dev_err(dev, "failed to ioremap base %pa size %#x\n", + adsp->shared_dram, adsp->shared_size); + return -ENOMEM; } - dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n", - adsp->shared_dram, &adsp->pa_shared_dram, shared_size); + + dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n", + adsp->shared_dram, &adsp->pa_shared_dram, adsp->shared_size); return 0; } @@ -307,9 +310,12 @@ static int mt8186_dsp_probe(struct snd_sof_dev *sdev) return -ENOMEM; } - sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, - priv->adsp->pa_dram, - priv->adsp->dramsize); + priv->adsp->va_sram = sdev->bar[SOF_FW_BLK_TYPE_IRAM]; + + sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap(sdev->dev, + priv->adsp->pa_dram, + priv->adsp->dramsize); + if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) { dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n", &priv->adsp->pa_dram, priv->adsp->dramsize); -- cgit v1.2.3 From 422f10adc3eb5a7ff8567bf6e6590a4e4fa756c3 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 3 Aug 2023 18:55:06 -0300 Subject: ASoC: wm8960: Add support for the power supplies WM8960 has the following power supplies: - AVDD - DBVDD - DCVDD - SPKVDD1 - SPKVDD1 Add support for them. Signed-off-by: Fabio Estevam Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20230803215506.142922-2-festevam@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index d4bc97088354..0a50180750e8 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -120,6 +120,15 @@ static bool wm8960_volatile(struct device *dev, unsigned int reg) } } +#define WM8960_NUM_SUPPLIES 5 +static const char *wm8960_supply_names[WM8960_NUM_SUPPLIES] = { + "DCVDD", + "DBVDD", + "AVDD", + "SPKVDD1", + "SPKVDD2", +}; + struct wm8960_priv { struct clk *mclk; struct regmap *regmap; @@ -137,6 +146,7 @@ struct wm8960_priv { bool is_stream_in_use[2]; struct wm8960_data pdata; ktime_t dsch_start; + struct regulator_bulk_data supplies[WM8960_NUM_SUPPLIES]; }; #define wm8960_reset(c) regmap_write(c, WM8960_RESET, 0) @@ -1417,6 +1427,7 @@ static int wm8960_i2c_probe(struct i2c_client *i2c) { struct wm8960_data *pdata = dev_get_platdata(&i2c->dev); struct wm8960_priv *wm8960; + unsigned int i; int ret; u8 val; @@ -1439,6 +1450,23 @@ static int wm8960_i2c_probe(struct i2c_client *i2c) } } + for (i = 0; i < ARRAY_SIZE(wm8960->supplies); i++) + wm8960->supplies[i].supply = wm8960_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8960->supplies), + wm8960->supplies); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(wm8960->supplies), + wm8960->supplies); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap); if (IS_ERR(wm8960->regmap)) return PTR_ERR(wm8960->regmap); @@ -1505,7 +1533,11 @@ static int wm8960_i2c_probe(struct i2c_client *i2c) } static void wm8960_i2c_remove(struct i2c_client *client) -{} +{ + struct wm8960_priv *wm8960 = i2c_get_clientdata(client); + + regulator_bulk_disable(ARRAY_SIZE(wm8960->supplies), wm8960->supplies); +} static const struct i2c_device_id wm8960_i2c_id[] = { { "wm8960", 0 }, -- cgit v1.2.3 From 9606cda3501ae5d1a865d839ee5dbae9552a7b37 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Fri, 4 Aug 2023 16:54:02 +0800 Subject: ASoC: ti: davinci-evm: simplify the code with module_platform_driver The init/exit() of driver only calls platform_driver_register/unregister, it can be simpilfied with module_platform_driver. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20230804085402.1328033-1-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-evm.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/ti/davinci-evm.c b/sound/soc/ti/davinci-evm.c index 983d69b951b0..544cb3da50eb 100644 --- a/sound/soc/ti/davinci-evm.c +++ b/sound/soc/ti/davinci-evm.c @@ -257,18 +257,7 @@ static struct platform_driver davinci_evm_driver = { }, }; -static int __init evm_init(void) -{ - return platform_driver_register(&davinci_evm_driver); -} - -static void __exit evm_exit(void) -{ - platform_driver_unregister(&davinci_evm_driver); -} - -module_init(evm_init); -module_exit(evm_exit); +module_platform_driver(davinci_evm_driver); MODULE_AUTHOR("Vladimir Barinov"); MODULE_DESCRIPTION("TI DAVINCI EVM ASoC driver"); -- cgit v1.2.3 From 3f3d66ba998fb079c1239430e96e3b138bc63166 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:14 -0500 Subject: ASoC: SoundWire codecs: return error status in probe For some reason the first batch of SoundWire codec drivers squelch errors in the SoundWire probe callback. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1308-sdw.c | 4 +--- sound/soc/codecs/rt5682-sdw.c | 4 +--- sound/soc/codecs/rt700-sdw.c | 4 +--- sound/soc/codecs/rt711-sdw.c | 4 +--- sound/soc/codecs/rt715-sdw.c | 4 +--- 5 files changed, 5 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index f43520ca3187..a7740549d35c 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -715,9 +715,7 @@ static int rt1308_sdw_probe(struct sdw_slave *slave, if (IS_ERR(regmap)) return PTR_ERR(regmap); - rt1308_sdw_init(&slave->dev, regmap, slave); - - return 0; + return rt1308_sdw_init(&slave->dev, regmap, slave); } static int rt1308_sdw_remove(struct sdw_slave *slave) diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 4968a8c0064d..7d53dd62ce17 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -674,9 +674,7 @@ static int rt5682_sdw_probe(struct sdw_slave *slave, if (IS_ERR(regmap)) return -EINVAL; - rt5682_sdw_init(&slave->dev, regmap, slave); - - return 0; + return rt5682_sdw_init(&slave->dev, regmap, slave); } static int rt5682_sdw_remove(struct sdw_slave *slave) diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index 8b28e47775cc..53e7973e0bf9 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -452,9 +452,7 @@ static int rt700_sdw_probe(struct sdw_slave *slave, if (IS_ERR(regmap)) return PTR_ERR(regmap); - rt700_init(&slave->dev, sdw_regmap, regmap, slave); - - return 0; + return rt700_init(&slave->dev, sdw_regmap, regmap, slave); } static int rt700_sdw_remove(struct sdw_slave *slave) diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index 33dced388f9e..530d1ae32c04 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -453,9 +453,7 @@ static int rt711_sdw_probe(struct sdw_slave *slave, if (IS_ERR(regmap)) return PTR_ERR(regmap); - rt711_init(&slave->dev, sdw_regmap, regmap, slave); - - return 0; + return rt711_init(&slave->dev, sdw_regmap, regmap, slave); } static int rt711_sdw_remove(struct sdw_slave *slave) diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index 6db87442b783..d09b3061096d 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -508,9 +508,7 @@ static int rt715_sdw_probe(struct sdw_slave *slave, if (IS_ERR(regmap)) return PTR_ERR(regmap); - rt715_init(&slave->dev, sdw_regmap, regmap, slave); - - return 0; + return rt715_init(&slave->dev, sdw_regmap, regmap, slave); } static int rt715_sdw_remove(struct sdw_slave *slave) -- cgit v1.2.3 From 49ae74abc76b2d9be4777e7ac833674fa4749071 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:15 -0500 Subject: ASoC: SoundWire codecs: make regmap cache-only in probe The SoundWire bus may start after the probe where the SoundWire ASoC components are registered. This creates a time window where the card can be created and the registers be accessed. As discussed on the mailing list, we can't really control when codecs are enumerated and initialized, but we can make sure the access to the codecs is cached until the hardware is accessible. This patch configures regcache_cache_only() with a 'true' parameter in the probe function, and a 'false' parameter in the io_init routine. The rt5682 is handled through a different patch due to its specific cache handling. Link: https://lore.kernel.org/alsa-devel/20230503144102.242240-1-krzysztof.kozlowski@linaro.org/ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98363.c | 7 ++++--- sound/soc/codecs/max98373-sdw.c | 7 ++++--- sound/soc/codecs/rt1308-sdw.c | 7 ++++--- sound/soc/codecs/rt1316-sdw.c | 4 +++- sound/soc/codecs/rt1318-sdw.c | 4 +++- sound/soc/codecs/rt700.c | 7 ++++--- sound/soc/codecs/rt711-sdca.c | 8 ++++++-- sound/soc/codecs/rt711.c | 7 ++++--- sound/soc/codecs/rt712-sdca-dmic.c | 7 +++++-- sound/soc/codecs/rt712-sdca.c | 7 +++++-- sound/soc/codecs/rt715-sdca.c | 7 +++++++ sound/soc/codecs/rt715.c | 4 ++++ 12 files changed, 53 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c index b5c69bba0e48..80a1cb482183 100644 --- a/sound/soc/codecs/max98363.c +++ b/sound/soc/codecs/max98363.c @@ -160,10 +160,9 @@ static int max98363_io_init(struct sdw_slave *slave) struct max98363_priv *max98363 = dev_get_drvdata(dev); int ret, reg; - if (max98363->first_hw_init) { - regcache_cache_only(max98363->regmap, false); + regcache_cache_only(max98363->regmap, false); + if (max98363->first_hw_init) regcache_cache_bypass(max98363->regmap, true); - } /* * PM runtime is only enabled when a Slave reports as Attached @@ -409,6 +408,8 @@ static int max98363_init(struct sdw_slave *slave, struct regmap *regmap) max98363->regmap = regmap; max98363->slave = slave; + regcache_cache_only(max98363->regmap, true); + max98363->hw_init = false; max98363->first_hw_init = false; diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index df92242af960..92d2b872f9f8 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -361,10 +361,9 @@ static int max98373_io_init(struct sdw_slave *slave) struct device *dev = &slave->dev; struct max98373_priv *max98373 = dev_get_drvdata(dev); - if (max98373->first_hw_init) { - regcache_cache_only(max98373->regmap, false); + regcache_cache_only(max98373->regmap, false); + if (max98373->first_hw_init) regcache_cache_bypass(max98373->regmap, true); - } /* * PM runtime is only enabled when a Slave reports as Attached @@ -753,6 +752,8 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap) max98373->regmap = regmap; max98373->slave = slave; + regcache_cache_only(max98373->regmap, true); + max98373->cache_num = ARRAY_SIZE(max98373_sdw_cache_reg); max98373->cache = devm_kcalloc(dev, max98373->cache_num, sizeof(*max98373->cache), diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index a7740549d35c..2c4e5330c2df 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -218,10 +218,9 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) if (rt1308->hw_init) return 0; - if (rt1308->first_hw_init) { - regcache_cache_only(rt1308->regmap, false); + regcache_cache_only(rt1308->regmap, false); + if (rt1308->first_hw_init) regcache_cache_bypass(rt1308->regmap, true); - } /* * PM runtime is only enabled when a Slave reports as Attached @@ -688,6 +687,8 @@ static int rt1308_sdw_init(struct device *dev, struct regmap *regmap, rt1308->sdw_slave = slave; rt1308->regmap = regmap; + regcache_cache_only(rt1308->regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index 10a53c8d4874..57abbe2de7cf 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -272,8 +272,8 @@ static int rt1316_io_init(struct device *dev, struct sdw_slave *slave) if (rt1316->hw_init) return 0; + regcache_cache_only(rt1316->regmap, false); if (rt1316->first_hw_init) { - regcache_cache_only(rt1316->regmap, false); regcache_cache_bypass(rt1316->regmap, true); } else { /* @@ -674,6 +674,8 @@ static int rt1316_sdw_init(struct device *dev, struct regmap *regmap, rt1316->sdw_slave = slave; rt1316->regmap = regmap; + regcache_cache_only(rt1316->regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c index 16d750102c8c..d7803342f5c2 100644 --- a/sound/soc/codecs/rt1318-sdw.c +++ b/sound/soc/codecs/rt1318-sdw.c @@ -408,8 +408,8 @@ static int rt1318_io_init(struct device *dev, struct sdw_slave *slave) if (rt1318->hw_init) return 0; + regcache_cache_only(rt1318->regmap, false); if (rt1318->first_hw_init) { - regcache_cache_only(rt1318->regmap, false); regcache_cache_bypass(rt1318->regmap, true); } else { /* @@ -752,6 +752,8 @@ static int rt1318_sdw_init(struct device *dev, struct regmap *regmap, rt1318->sdw_slave = slave; rt1318->regmap = regmap; + regcache_cache_only(rt1318->regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index a04b9246256b..b774349dfdae 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -1099,6 +1099,8 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap, rt700->sdw_regmap = sdw_regmap; rt700->regmap = regmap; + regcache_cache_only(rt700->regmap, true); + mutex_init(&rt700->disable_irq_lock); INIT_DELAYED_WORK(&rt700->jack_detect_work, @@ -1132,10 +1134,9 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave) if (rt700->hw_init) return 0; - if (rt700->first_hw_init) { - regcache_cache_only(rt700->regmap, false); + regcache_cache_only(rt700->regmap, false); + if (rt700->first_hw_init) regcache_cache_bypass(rt700->regmap, true); - } /* * PM runtime is only enabled when a Slave reports as Attached diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index 07640d2f6e56..bd0f5e05874b 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -1406,6 +1406,9 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap, rt711->regmap = regmap; rt711->mbq_regmap = mbq_regmap; + regcache_cache_only(rt711->regmap, true); + regcache_cache_only(rt711->mbq_regmap, true); + mutex_init(&rt711->calibrate_mutex); mutex_init(&rt711->disable_irq_lock); @@ -1500,10 +1503,11 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave) if (rt711->hw_init) return 0; + regcache_cache_only(rt711->regmap, false); + regcache_cache_only(rt711->mbq_regmap, false); + if (rt711->first_hw_init) { - regcache_cache_only(rt711->regmap, false); regcache_cache_bypass(rt711->regmap, true); - regcache_cache_only(rt711->mbq_regmap, false); regcache_cache_bypass(rt711->mbq_regmap, true); } else { /* diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index af53cbcc7bf2..0ca955e2f4e7 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -1183,6 +1183,8 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap, rt711->sdw_regmap = sdw_regmap; rt711->regmap = regmap; + regcache_cache_only(rt711->regmap, true); + mutex_init(&rt711->calibrate_mutex); mutex_init(&rt711->disable_irq_lock); @@ -1219,10 +1221,9 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave) if (rt711->hw_init) return 0; - if (rt711->first_hw_init) { - regcache_cache_only(rt711->regmap, false); + regcache_cache_only(rt711->regmap, false); + if (rt711->first_hw_init) regcache_cache_bypass(rt711->regmap, true); - } /* * PM runtime is only enabled when a Slave reports as Attached diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c index 869cc7bfd178..0102bad0b66a 100644 --- a/sound/soc/codecs/rt712-sdca-dmic.c +++ b/sound/soc/codecs/rt712-sdca-dmic.c @@ -182,10 +182,10 @@ static int rt712_sdca_dmic_io_init(struct device *dev, struct sdw_slave *slave) if (rt712->hw_init) return 0; + regcache_cache_only(rt712->regmap, false); + regcache_cache_only(rt712->mbq_regmap, false); if (rt712->first_hw_init) { - regcache_cache_only(rt712->regmap, false); regcache_cache_bypass(rt712->regmap, true); - regcache_cache_only(rt712->mbq_regmap, false); regcache_cache_bypass(rt712->mbq_regmap, true); } else { /* @@ -777,6 +777,9 @@ static int rt712_sdca_dmic_init(struct device *dev, struct regmap *regmap, rt712->regmap = regmap; rt712->mbq_regmap = mbq_regmap; + regcache_cache_only(rt712->regmap, true); + regcache_cache_only(rt712->mbq_regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c index 89d245655ca4..88f6c895722e 100644 --- a/sound/soc/codecs/rt712-sdca.c +++ b/sound/soc/codecs/rt712-sdca.c @@ -1183,6 +1183,9 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap, rt712->regmap = regmap; rt712->mbq_regmap = mbq_regmap; + regcache_cache_only(rt712->regmap, true); + regcache_cache_only(rt712->mbq_regmap, true); + mutex_init(&rt712->calibrate_mutex); mutex_init(&rt712->disable_irq_lock); @@ -1224,10 +1227,10 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) if (rt712->hw_init) return 0; + regcache_cache_only(rt712->regmap, false); + regcache_cache_only(rt712->mbq_regmap, false); if (rt712->first_hw_init) { - regcache_cache_only(rt712->regmap, false); regcache_cache_bypass(rt712->regmap, true); - regcache_cache_only(rt712->mbq_regmap, false); regcache_cache_bypass(rt712->mbq_regmap, true); } else { /* diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c index b989f907784b..176340a43446 100644 --- a/sound/soc/codecs/rt715-sdca.c +++ b/sound/soc/codecs/rt715-sdca.c @@ -977,6 +977,10 @@ int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap, rt715->regmap = regmap; rt715->mbq_regmap = mbq_regmap; rt715->hw_sdw_ver = slave->id.sdw_version; + + regcache_cache_only(rt715->regmap, true); + regcache_cache_only(rt715->mbq_regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -1000,6 +1004,9 @@ int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave) if (rt715->hw_init) return 0; + regcache_cache_only(rt715->regmap, false); + regcache_cache_only(rt715->mbq_regmap, false); + /* * PM runtime is only enabled when a Slave reports as Attached */ diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 6c2e165dd621..1bd2fe8aa625 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -984,6 +984,8 @@ int rt715_init(struct device *dev, struct regmap *sdw_regmap, rt715->regmap = regmap; rt715->sdw_regmap = sdw_regmap; + regcache_cache_only(rt715->regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -1006,6 +1008,8 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave) if (rt715->hw_init) return 0; + regcache_cache_only(rt715->regmap, false); + /* * PM runtime is only enabled when a Slave reports as Attached */ -- cgit v1.2.3 From 6ab18105029ca3d739dd4c5c18638c7c6d568bbb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:16 -0500 Subject: ASoC: rt5682-sdw: make regmap cache-only in probe The RT5682 needs specific attention: there are two regmap in rt5682_priv struct, one is sdw_regmap which is for IO transfer, and the other is used for registers control. We need to set both regmaps when we set cache only. Because if we set rt5682->sdw_regmap only, rt5682->regmap won't set/get the right value when it call regmap_write/read(rt5682->sdw_regmap, ...). If we set rt5682->regmap only, regmap_write(rt5682->sdw_regmap, ...) is used in rt5682_clock_config which will be called by the ..bus_config ops. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230802153629.53576-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682-sdw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 7d53dd62ce17..6726458cf329 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -322,6 +322,9 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap, return ret; } + regcache_cache_only(rt5682->sdw_regmap, true); + regcache_cache_only(rt5682->regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -352,6 +355,11 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave) if (rt5682->hw_init) return 0; + regcache_cache_only(rt5682->sdw_regmap, false); + regcache_cache_only(rt5682->regmap, false); + if (rt5682->first_hw_init) + regcache_cache_bypass(rt5682->regmap, true); + /* * PM runtime is only enabled when a Slave reports as Attached */ @@ -371,11 +379,6 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave) pm_runtime_get_noresume(&slave->dev); - if (rt5682->first_hw_init) { - regcache_cache_only(rt5682->regmap, false); - regcache_cache_bypass(rt5682->regmap, true); - } - while (loop > 0) { regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val); if (val == DEVICE_ID) @@ -705,6 +708,7 @@ static int __maybe_unused rt5682_dev_suspend(struct device *dev) cancel_delayed_work_sync(&rt5682->jack_detect_work); + regcache_cache_only(rt5682->sdw_regmap, true); regcache_cache_only(rt5682->regmap, true); regcache_mark_dirty(rt5682->regmap); @@ -769,6 +773,7 @@ static int __maybe_unused rt5682_dev_resume(struct device *dev) regmap_sync: slave->unattach_request = 0; + regcache_cache_only(rt5682->sdw_regmap, false); regcache_cache_only(rt5682->regmap, false); regcache_sync(rt5682->regmap); -- cgit v1.2.3 From a8590dd73d9f7fd955ac24a8e210d0721d5c10af Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:17 -0500 Subject: ASoC: rt711: enable pm_runtime in probe, keep status as 'suspended' In stress cases involving module insertion/removal followed by playback/capture, it can happen that capture/playback is started before the codec enumeration completes. The codec driver registers its components with the ASoC framework during the probe stage, so there is currently no way for the card creation to wait for the codec enumeration/initialization to complete. In addition, when the capture/playback starts, the ASoC framework uses pm_runtime_get_sync() to properly refcount and power-manage devices. This is problematic in the SoundWire case because pm_runtime is enabled during the enumeration/initialization stage, so pm_runtime_get_sync() will return -EACCESS which is ignored. Additional errors will happen when setting the pm_runtime status as 'active' because the parent is not properly resumed, resulting in an error such as: "rt711 sdw:0:025d:0711:00: runtime PM trying to activate child device sdw:0:025d:0711:00 but parent (sdw-master-0) is not active" This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. Closes: https://github.com/thesofproject/linux/issues/4328 Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt711-sdw.c | 3 +-- sound/soc/codecs/rt711.c | 40 +++++++++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index 530d1ae32c04..3f5773310ae8 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -466,8 +466,7 @@ static int rt711_sdw_remove(struct sdw_slave *slave) cancel_work_sync(&rt711->calibration_work); } - if (rt711->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); mutex_destroy(&rt711->calibrate_mutex); mutex_destroy(&rt711->disable_irq_lock); diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index 0ca955e2f4e7..66eaed13b0d6 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -462,6 +462,10 @@ static int rt711_set_jack_detect(struct snd_soc_component *component, rt711->hs_jack = hs_jack; + /* we can only resume if the device was initialized at least once */ + if (!rt711->first_hw_init) + return 0; + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0) { if (ret != -EACCES) { @@ -941,6 +945,9 @@ static int rt711_probe(struct snd_soc_component *component) rt711_parse_dt(rt711, &rt711->slave->dev); rt711->component = component; + if (!rt711->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -1206,8 +1213,25 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap, &soc_codec_dev_rt711, rt711_dai, ARRAY_SIZE(rt711_dai)); + if (ret < 0) + return ret; + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); - dev_dbg(&slave->dev, "%s\n", __func__); + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); return ret; } @@ -1226,22 +1250,12 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_bypass(rt711->regmap, true); /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - if (!rt711->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - + if (!rt711->first_hw_init) /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); - } - pm_runtime_get_noresume(&slave->dev); rt711_reset(rt711->regmap); -- cgit v1.2.3 From 0c321fb857707ef68ffdb4f9672beb664e6679cc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:18 -0500 Subject: ASoC: rt711-sdca: enable pm_runtime in probe, keep status as 'suspended' In stress cases involving module insertion/removal followed by playback/capture, it can happen that capture/playback is started before the codec enumeration completes. The codec driver registers its components with the ASoC framework during the probe stage, so there is currently no way for the card creation to wait for the codec enumeration/initialization to complete. In addition, when the capture/playback starts, the ASoC framework uses pm_runtime_get_sync() to properly refcount and power-manage devices. This is problematic in the SoundWire case because pm_runtime is enabled during the enumeration/initialization stage, so pm_runtime_get_sync() will return -EACCESS which is ignored. Additional errors will happen when setting the pm_runtime status as 'active' because the parent is not properly resumed, resulting in an error such as: "rt711 sdw:0:025d:0711:00: runtime PM trying to activate child device sdw:0:025d:0711:00 but parent (sdw-master-0) is not active" This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. Closes: https://github.com/thesofproject/linux/issues/4328 Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt711-sdca-sdw.c | 3 +-- sound/soc/codecs/rt711-sdca.c | 40 +++++++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c index 23f23f714b39..935e597022d3 100644 --- a/sound/soc/codecs/rt711-sdca-sdw.c +++ b/sound/soc/codecs/rt711-sdca-sdw.c @@ -366,8 +366,7 @@ static int rt711_sdca_sdw_remove(struct sdw_slave *slave) cancel_delayed_work_sync(&rt711->jack_btn_check_work); } - if (rt711->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); mutex_destroy(&rt711->calibrate_mutex); mutex_destroy(&rt711->disable_irq_lock); diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index bd0f5e05874b..447154cb6010 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -507,6 +507,10 @@ static int rt711_sdca_set_jack_detect(struct snd_soc_component *component, rt711->hs_jack = hs_jack; + /* we can only resume if the device was initialized at least once */ + if (!rt711->first_hw_init) + return 0; + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0) { if (ret != -EACCES) { @@ -1215,6 +1219,9 @@ static int rt711_sdca_probe(struct snd_soc_component *component) rt711_sdca_parse_dt(rt711, &rt711->slave->dev); rt711->component = component; + if (!rt711->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -1434,9 +1441,27 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap, rt711_sdca_dai, ARRAY_SIZE(rt711_sdca_dai)); - dev_dbg(&slave->dev, "%s\n", __func__); + if (ret < 0) + return ret; - return ret; + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); + + return 0; } static void rt711_sdca_vd0_io_init(struct rt711_sdca_priv *rt711) @@ -1511,20 +1536,11 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_bypass(rt711->mbq_regmap, true); } else { /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); } pm_runtime_get_noresume(&slave->dev); -- cgit v1.2.3 From 6b8f8c5e6ffbd431d6cf40584dc8d3027f7e99b3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:19 -0500 Subject: ASoC: rt700: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt700-sdw.c | 3 +-- sound/soc/codecs/rt700.c | 39 ++++++++++++++++++++++++++------------- 2 files changed, 27 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index 53e7973e0bf9..52c33d56b143 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -464,8 +464,7 @@ static int rt700_sdw_remove(struct sdw_slave *slave) cancel_delayed_work_sync(&rt700->jack_btn_check_work); } - if (rt700->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index b774349dfdae..0ebf344a1b60 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -320,6 +320,10 @@ static int rt700_set_jack_detect(struct snd_soc_component *component, rt700->hs_jack = hs_jack; + /* we can only resume if the device was initialized at least once */ + if (!rt700->first_hw_init) + return 0; + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0) { if (ret != -EACCES) { @@ -823,6 +827,9 @@ static int rt700_probe(struct snd_soc_component *component) rt700->component = component; + if (!rt700->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -1119,10 +1126,26 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap, &soc_codec_dev_rt700, rt700_dai, ARRAY_SIZE(rt700_dai)); + if (ret < 0) + return ret; + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ dev_dbg(&slave->dev, "%s\n", __func__); - return ret; + return 0; } int rt700_io_init(struct device *dev, struct sdw_slave *slave) @@ -1141,20 +1164,10 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave) /* * PM runtime is only enabled when a Slave reports as Attached */ - if (!rt700->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - - /* update count of parent 'active' children */ + if (!rt700->first_hw_init) + /* PM runtime status is marked as 'active' only when a Slave reports as Attached */ pm_runtime_set_active(&slave->dev); - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); - } - pm_runtime_get_noresume(&slave->dev); /* reset */ -- cgit v1.2.3 From f3da2ed110e2884b29151313eee52947b786e1a7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:20 -0500 Subject: ASoC: rt1712-sdca: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt712-sdca-sdw.c | 3 +-- sound/soc/codecs/rt712-sdca.c | 38 ++++++++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c index 6bc50396a0f6..6b644a89c589 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.c +++ b/sound/soc/codecs/rt712-sdca-sdw.c @@ -363,8 +363,7 @@ static int rt712_sdca_sdw_remove(struct sdw_slave *slave) cancel_delayed_work_sync(&rt712->jack_btn_check_work); } - if (rt712->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); mutex_destroy(&rt712->calibrate_mutex); mutex_destroy(&rt712->disable_irq_lock); diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c index 88f6c895722e..7077ff6ba1f4 100644 --- a/sound/soc/codecs/rt712-sdca.c +++ b/sound/soc/codecs/rt712-sdca.c @@ -453,6 +453,9 @@ static int rt712_sdca_set_jack_detect(struct snd_soc_component *component, rt712->hs_jack = hs_jack; + if (!rt712->first_hw_init) + return 0; + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0) { if (ret != -EACCES) { @@ -960,6 +963,9 @@ static int rt712_sdca_probe(struct snd_soc_component *component) rt712_sdca_parse_dt(rt712, &rt712->slave->dev); rt712->component = component; + if (!rt712->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -1210,10 +1216,27 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap, else ret = devm_snd_soc_register_component(dev, &soc_sdca_dev_rt712, rt712_sdca_dai, 1); + if (ret < 0) + return ret; - dev_dbg(&slave->dev, "%s\n", __func__); + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); - return ret; + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); + + return 0; } int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) @@ -1234,20 +1257,11 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_bypass(rt712->mbq_regmap, true); } else { /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); } pm_runtime_get_noresume(&slave->dev); -- cgit v1.2.3 From 8d890ecef1ef6e2e81f1709d54f6843846cfd15f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:21 -0500 Subject: ASoC: rt712-sdca-dmic: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt712-sdca-dmic.c | 40 +++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c index 0102bad0b66a..ba08d03e717c 100644 --- a/sound/soc/codecs/rt712-sdca-dmic.c +++ b/sound/soc/codecs/rt712-sdca-dmic.c @@ -189,20 +189,11 @@ static int rt712_sdca_dmic_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_bypass(rt712->mbq_regmap, true); } else { /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); } pm_runtime_get_noresume(&slave->dev); @@ -608,6 +599,9 @@ static int rt712_sdca_dmic_probe(struct snd_soc_component *component) rt712->component = component; + if (!rt712->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -794,10 +788,27 @@ static int rt712_sdca_dmic_init(struct device *dev, struct regmap *regmap, &soc_sdca_dev_rt712_dmic, rt712_sdca_dmic_dai, ARRAY_SIZE(rt712_sdca_dmic_dai)); + if (ret < 0) + return ret; - dev_dbg(&slave->dev, "%s\n", __func__); + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); - return ret; + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); + + return 0; } @@ -957,10 +968,7 @@ static int rt712_sdca_dmic_sdw_probe(struct sdw_slave *slave, static int rt712_sdca_dmic_sdw_remove(struct sdw_slave *slave) { - struct rt712_sdca_dmic_priv *rt712 = dev_get_drvdata(&slave->dev); - - if (rt712->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } -- cgit v1.2.3 From 279be5919560d9f3afea1940bfd261297eecfa0c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:22 -0500 Subject: ASoC: rt715: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt715-sdw.c | 5 +---- sound/soc/codecs/rt715.c | 37 ++++++++++++++++++++++++------------- 2 files changed, 25 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index d09b3061096d..21f37babd148 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -513,10 +513,7 @@ static int rt715_sdw_probe(struct sdw_slave *slave, static int rt715_sdw_remove(struct sdw_slave *slave) { - struct rt715_priv *rt715 = dev_get_drvdata(&slave->dev); - - if (rt715->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 1bd2fe8aa625..79416bb48814 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -740,8 +740,12 @@ static int rt715_set_bias_level(struct snd_soc_component *component, static int rt715_probe(struct snd_soc_component *component) { + struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); int ret; + if (!rt715->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -997,8 +1001,25 @@ int rt715_init(struct device *dev, struct regmap *sdw_regmap, &soc_codec_dev_rt715, rt715_dai, ARRAY_SIZE(rt715_dai)); + if (ret < 0) + return ret; - return ret; + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + return 0; } int rt715_io_init(struct device *dev, struct sdw_slave *slave) @@ -1011,22 +1032,12 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_only(rt715->regmap, false); /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - if (!rt715->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - + if (!rt715->first_hw_init) /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); - } - pm_runtime_get_noresume(&slave->dev); /* Mute nid=08h/09h */ -- cgit v1.2.3 From e4a3b8cf40713d6511391de3286ccba38998756b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:23 -0500 Subject: ASoC: rt715-sdca: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-11-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt715-sdca-sdw.c | 5 +---- sound/soc/codecs/rt715-sdca.c | 34 ++++++++++++++++++++++++---------- 2 files changed, 25 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c index df10916bab46..ab54a67a27eb 100644 --- a/sound/soc/codecs/rt715-sdca-sdw.c +++ b/sound/soc/codecs/rt715-sdca-sdw.c @@ -193,10 +193,7 @@ static int rt715_sdca_sdw_probe(struct sdw_slave *slave, static int rt715_sdca_sdw_remove(struct sdw_slave *slave) { - struct rt715_sdca_priv *rt715 = dev_get_drvdata(&slave->dev); - - if (rt715->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c index 176340a43446..9fa96fd83d4a 100644 --- a/sound/soc/codecs/rt715-sdca.c +++ b/sound/soc/codecs/rt715-sdca.c @@ -761,8 +761,12 @@ static const struct snd_soc_dapm_route rt715_sdca_audio_map[] = { static int rt715_sdca_probe(struct snd_soc_component *component) { + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); int ret; + if (!rt715->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -992,6 +996,25 @@ int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap, &soc_codec_dev_rt715_sdca, rt715_sdca_dai, ARRAY_SIZE(rt715_sdca_dai)); + if (ret < 0) + return ret; + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); return ret; } @@ -1008,21 +1031,12 @@ int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_only(rt715->mbq_regmap, false); /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ if (!rt715->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); - rt715->first_hw_init = true; } -- cgit v1.2.3 From 1772552eb304f3229309f66e2762e835955e2307 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:24 -0500 Subject: ASoC: rt1308-sdw: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-12-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1308-sdw.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index 2c4e5330c2df..c98cd7abef6a 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -223,22 +223,12 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_bypass(rt1308->regmap, true); /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - if (!rt1308->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - + if (!rt1308->first_hw_init) /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); - } - pm_runtime_get_noresume(&slave->dev); /* sw reset */ @@ -625,6 +615,9 @@ static int rt1308_sdw_component_probe(struct snd_soc_component *component) rt1308->component = component; rt1308_sdw_parse_dt(rt1308, &rt1308->sdw_slave->dev); + if (!rt1308->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -700,10 +693,27 @@ static int rt1308_sdw_init(struct device *dev, struct regmap *regmap, &soc_component_sdw_rt1308, rt1308_sdw_dai, ARRAY_SIZE(rt1308_sdw_dai)); + if (ret < 0) + return ret; - dev_dbg(&slave->dev, "%s\n", __func__); + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); - return ret; + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); + + return 0; } static int rt1308_sdw_probe(struct sdw_slave *slave, @@ -721,10 +731,7 @@ static int rt1308_sdw_probe(struct sdw_slave *slave, static int rt1308_sdw_remove(struct sdw_slave *slave) { - struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev); - - if (rt1308->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } -- cgit v1.2.3 From 64bae6732b2d3364ce4954015c84b4959f7d6e0f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:25 -0500 Subject: ASoC: rt1316-sdw: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-13-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1316-sdw.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index 57abbe2de7cf..47511f70119a 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -277,20 +277,11 @@ static int rt1316_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_bypass(rt1316->regmap, true); } else { /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); } pm_runtime_get_noresume(&slave->dev); @@ -607,6 +598,9 @@ static int rt1316_sdw_component_probe(struct snd_soc_component *component) rt1316->component = component; rt1316_sdw_parse_dt(rt1316, &rt1316->sdw_slave->dev); + if (!rt1316->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -687,10 +681,27 @@ static int rt1316_sdw_init(struct device *dev, struct regmap *regmap, &soc_component_sdw_rt1316, rt1316_sdw_dai, ARRAY_SIZE(rt1316_sdw_dai)); + if (ret < 0) + return ret; - dev_dbg(&slave->dev, "%s\n", __func__); + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); - return ret; + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); + + return 0; } static int rt1316_sdw_probe(struct sdw_slave *slave, @@ -708,10 +719,7 @@ static int rt1316_sdw_probe(struct sdw_slave *slave, static int rt1316_sdw_remove(struct sdw_slave *slave) { - struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(&slave->dev); - - if (rt1316->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } -- cgit v1.2.3 From df93dfa2b4d0f0e2ac2f73f78582a3830659d00e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:26 -0500 Subject: ASoC: rt1318-sdw: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-14-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1318-sdw.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c index d7803342f5c2..ff364bde4a08 100644 --- a/sound/soc/codecs/rt1318-sdw.c +++ b/sound/soc/codecs/rt1318-sdw.c @@ -413,20 +413,10 @@ static int rt1318_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_bypass(rt1318->regmap, true); } else { /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); } pm_runtime_get_noresume(&slave->dev); @@ -686,6 +676,9 @@ static int rt1318_sdw_component_probe(struct snd_soc_component *component) rt1318->component = component; + if (!rt1318->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); dev_dbg(&rt1318->sdw_slave->dev, "%s pm_runtime_resume, ret=%d", __func__, ret); if (ret < 0 && ret != -EACCES) @@ -765,8 +758,25 @@ static int rt1318_sdw_init(struct device *dev, struct regmap *regmap, &soc_component_sdw_rt1318, rt1318_sdw_dai, ARRAY_SIZE(rt1318_sdw_dai)); + if (ret < 0) + return ret; + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); - dev_dbg(&slave->dev, "%s\n", __func__); + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); return ret; } @@ -786,10 +796,7 @@ static int rt1318_sdw_probe(struct sdw_slave *slave, static int rt1318_sdw_remove(struct sdw_slave *slave) { - struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev); - - if (rt1318->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } -- cgit v1.2.3 From 4af11e11defc200439a75a7957b03f3da37e46b2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:27 -0500 Subject: ASoC: rt5682-sdw: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-15-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682-sdw.c | 37 ++++++++++++++++++++++--------------- sound/soc/codecs/rt5682.c | 3 +++ 2 files changed, 25 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 6726458cf329..dfb702d1b3d4 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -339,7 +339,25 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap, ret = devm_snd_soc_register_component(dev, &rt5682_soc_component_dev, rt5682_dai, ARRAY_SIZE(rt5682_dai)); - dev_dbg(&slave->dev, "%s\n", __func__); + if (ret < 0) + return ret; + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); return ret; } @@ -361,22 +379,12 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave) regcache_cache_bypass(rt5682->regmap, true); /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - if (!rt5682->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - + if (!rt5682->first_hw_init) /* update count of parent 'active' children */ pm_runtime_set_active(&slave->dev); - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(&slave->dev); - - pm_runtime_enable(&slave->dev); - } - pm_runtime_get_noresume(&slave->dev); while (loop > 0) { @@ -687,8 +695,7 @@ static int rt5682_sdw_remove(struct sdw_slave *slave) if (rt5682->hw_init) cancel_delayed_work_sync(&rt5682->jack_detect_work); - if (rt5682->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 5d992543b791..694c581070d9 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -1017,6 +1017,9 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component, rt5682->hs_jack = hs_jack; + if (rt5682->is_sdw && !rt5682->first_hw_init) + return 0; + if (!hs_jack) { regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2, RT5682_JD1_EN_MASK, RT5682_JD1_DIS); -- cgit v1.2.3 From d6ce285641cfb506b6942818e06270fb091b8fe3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:28 -0500 Subject: ASoC: max98363: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-16-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98363.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c index 80a1cb482183..9e3873e56e6d 100644 --- a/sound/soc/codecs/max98363.c +++ b/sound/soc/codecs/max98363.c @@ -165,22 +165,12 @@ static int max98363_io_init(struct sdw_slave *slave) regcache_cache_bypass(max98363->regmap, true); /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - if (!max98363->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(dev, 3000); - pm_runtime_use_autosuspend(dev); - + if (!max98363->first_hw_init) /* update count of parent 'active' children */ pm_runtime_set_active(dev); - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(dev); - - pm_runtime_enable(dev); - } - pm_runtime_get_noresume(dev); ret = regmap_read(max98363->regmap, MAX98363_R21FF_REV_ID, ®); @@ -417,10 +407,26 @@ static int max98363_init(struct sdw_slave *slave, struct regmap *regmap) ret = devm_snd_soc_register_component(dev, &soc_codec_dev_max98363, max98363_dai, ARRAY_SIZE(max98363_dai)); - if (ret < 0) + if (ret < 0) { dev_err(dev, "Failed to register codec: %d\n", ret); + return ret; + } - return ret; + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + return 0; } static int max98363_sdw_probe(struct sdw_slave *slave, -- cgit v1.2.3 From b48f324f89ab8ee62c3448ef19445a1b292e02d3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Aug 2023 10:36:29 -0500 Subject: ASoC: max98373-sdw: enable pm_runtime in probe, keep status as 'suspended' This patch suggests enabling pm_runtime during the probe, but marking the device as 'active' only after it is enumerated. That will force a dependency between the card and the codec, pm_runtime_get_sync() will have to wait for the codec device to resume and hence implicitly wait for the enumeration/initialization to be completed. In the nominal case where the codec device is already active the get_sync() would only perform a ref-count increase. The changes are directly inspired by RT711 and RT711-sdca changes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230802153629.53576-17-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98373-sdw.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index 92d2b872f9f8..b5cb951af570 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -366,22 +366,12 @@ static int max98373_io_init(struct sdw_slave *slave) regcache_cache_bypass(max98373->regmap, true); /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - if (!max98373->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(dev, 3000); - pm_runtime_use_autosuspend(dev); - + if (!max98373->first_hw_init) /* update count of parent 'active' children */ pm_runtime_set_active(dev); - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(dev); - - pm_runtime_enable(dev); - } - pm_runtime_get_noresume(dev); /* Software Reset */ @@ -774,10 +764,27 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap) ret = devm_snd_soc_register_component(dev, &soc_codec_dev_max98373_sdw, max98373_sdw_dai, ARRAY_SIZE(max98373_sdw_dai)); - if (ret < 0) + if (ret < 0) { dev_err(dev, "Failed to register codec: %d\n", ret); + return ret; + } - return ret; + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + return 0; } static int max98373_update_status(struct sdw_slave *slave, @@ -835,10 +842,7 @@ static int max98373_sdw_probe(struct sdw_slave *slave, static int max98373_sdw_remove(struct sdw_slave *slave) { - struct max98373_priv *max98373 = dev_get_drvdata(&slave->dev); - - if (max98373->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } -- cgit v1.2.3 From 5532a1cfedda10ec0c5e9edbb8089e6165b532fe Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:11 +0300 Subject: ASoC: amd: acp-da7219-max98357a: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The DA7219 codec used here can detect Headphones, Headset Mic and Line Out connections. Expose each to userspace as kcontrols and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-2-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/acp-da7219-max98357a.c | 41 +++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index 7464ca2b596c..9e3133bec2b1 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -28,6 +28,21 @@ #define RT5682_PLL_FREQ (48000 * 512) static struct snd_soc_jack cz_jack; +static struct snd_soc_jack_pin cz_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, +}; + static struct clk *da7219_dai_wclk; static struct clk *da7219_dai_bclk; static struct clk *rt5682_dai_wclk; @@ -66,11 +81,13 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd) if (IS_ERR(da7219_dai_bclk)) return PTR_ERR(da7219_dai_bclk); - 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, - &cz_jack); + ret = snd_soc_card_jack_new_pins(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, + &cz_jack, + cz_jack_pins, + ARRAY_SIZE(cz_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; @@ -146,11 +163,13 @@ static int cz_rt5682_init(struct snd_soc_pcm_runtime *rtd) if (IS_ERR(rt5682_dai_bclk)) return PTR_ERR(rt5682_dai_bclk); - 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, - &cz_jack); + ret = snd_soc_card_jack_new_pins(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, + &cz_jack, + cz_jack_pins, + ARRAY_SIZE(cz_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; @@ -631,6 +650,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { static const struct snd_soc_dapm_widget cz_widgets[] = { SND_SOC_DAPM_HP("Headphones", NULL), SND_SOC_DAPM_SPK("Speakers", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Int Mic", NULL), }; @@ -654,6 +674,7 @@ static const struct snd_soc_dapm_route cz_rt5682_audio_route[] = { static const struct snd_kcontrol_new cz_mc_controls[] = { SOC_DAPM_PIN_SWITCH("Headphones"), SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Line Out"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Int Mic"), }; -- cgit v1.2.3 From 596c92fb77a0402b3f2d3ebd36ef6c6aec45faf5 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:12 +0300 Subject: ASoC: amd: acp-rt5645: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5645 codec used here can detect Headphone and Headset Mic connections. Expose both to userspace as kcontrols. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-3-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/acp-rt5645.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/amd/acp-rt5645.c b/sound/soc/amd/acp-rt5645.c index 532aa98a2241..c8ed1e0b1ccd 100644 --- a/sound/soc/amd/acp-rt5645.c +++ b/sound/soc/amd/acp-rt5645.c @@ -42,6 +42,16 @@ #define CZ_PLAT_CLK 24000000 static struct snd_soc_jack cz_jack; +static struct snd_soc_jack_pin cz_jack_pins[] = { + { + .pin = "Headphones", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; static int cz_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -76,11 +86,13 @@ static int cz_init(struct snd_soc_pcm_runtime *rtd) codec = asoc_rtd_to_codec(rtd, 0)->component; card = rtd->card; - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &cz_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &cz_jack, + cz_jack_pins, + ARRAY_SIZE(cz_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; -- cgit v1.2.3 From 7ac3404c2e21ff6b717fd9ac2f7b352e0149f7bd Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:13 +0300 Subject: ASoC: amd: acp: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5682, RT5682s, NAU8825 and NAU8821 codecs used here can detect Headphone and Headset Mic connections. Expose both to userspace as kcontrols and add the necessary widgets. Split the jack and pin structs per-codec to accommodate for per-codec differences. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-4-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-mach-common.c | 226 +++++++++++++++++++++++++++++------- 1 file changed, 182 insertions(+), 44 deletions(-) (limited to 'sound') diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index ff5cbc4a6427..f3abaa182fbb 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -28,7 +28,6 @@ #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 @@ -52,8 +51,6 @@ const struct dmi_system_id acp_quirk_table[] = { }; EXPORT_SYMBOL_GPL(acp_quirk_table); -static struct snd_soc_jack pco_jack; - static const unsigned int channels[] = { DUAL_CHANNEL, }; @@ -87,6 +84,28 @@ static int acp_clk_enable(struct acp_card_drvdata *drvdata, SND_SOC_DAILINK_DEF(rt5682, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", "rt5682-aif1"))); +static struct snd_soc_jack rt5682_jack; +static struct snd_soc_jack_pin rt5682_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static const struct snd_kcontrol_new rt5682_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget rt5682_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + static const struct snd_soc_dapm_route rt5682_map[] = { { "Headphone Jack", NULL, "HPOL" }, { "Headphone Jack", NULL, "HPOR" }, @@ -110,22 +129,38 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd) drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk"); drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk"); - 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, - &pco_jack); + ret = snd_soc_dapm_new_controls(&card->dapm, rt5682_widgets, + ARRAY_SIZE(rt5682_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, rt5682_controls, + ARRAY_SIZE(rt5682_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new_pins(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, + &rt5682_jack, + rt5682_jack_pins, + ARRAY_SIZE(rt5682_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; } - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - ret = snd_soc_component_set_jack(component, &pco_jack, NULL); + ret = snd_soc_component_set_jack(component, &rt5682_jack, NULL); if (ret) { dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); return ret; @@ -275,6 +310,28 @@ static const struct snd_soc_ops acp_card_rt5682_ops = { SND_SOC_DAILINK_DEF(rt5682s, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RTL5682:00", "rt5682s-aif1"))); +static struct snd_soc_jack rt5682s_jack; +static struct snd_soc_jack_pin rt5682s_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static const struct snd_kcontrol_new rt5682s_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget rt5682s_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + static const struct snd_soc_dapm_route rt5682s_map[] = { { "Headphone Jack", NULL, "HPOL" }, { "Headphone Jack", NULL, "HPOR" }, @@ -299,22 +356,38 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd) drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk"); } - 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, - &pco_jack); + ret = snd_soc_dapm_new_controls(&card->dapm, rt5682s_widgets, + ARRAY_SIZE(rt5682s_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, rt5682s_controls, + ARRAY_SIZE(rt5682s_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new_pins(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, + &rt5682s_jack, + rt5682s_jack_pins, + ARRAY_SIZE(rt5682s_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; } - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - ret = snd_soc_component_set_jack(component, &pco_jack, NULL); + ret = snd_soc_component_set_jack(component, &rt5682s_jack, NULL); if (ret) { dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); return ret; @@ -762,6 +835,28 @@ static const struct snd_soc_ops acp_max98388_ops = { SND_SOC_DAILINK_DEF(nau8825, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00", "nau8825-hifi"))); +static struct snd_soc_jack nau8825_jack; +static struct snd_soc_jack_pin nau8825_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static const struct snd_kcontrol_new nau8825_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget nau8825_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + static const struct snd_soc_dapm_route nau8825_map[] = { { "Headphone Jack", NULL, "HPOL" }, { "Headphone Jack", NULL, "HPOR" }, @@ -780,22 +875,38 @@ static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd) if (drvdata->hs_codec_id != NAU8825) return -EINVAL; - ret = snd_soc_card_jack_new(card, "Headset Jack", + ret = snd_soc_dapm_new_controls(&card->dapm, nau8825_widgets, + ARRAY_SIZE(nau8825_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, nau8825_controls, + ARRAY_SIZE(nau8825_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new_pins(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, - &pco_jack); + &nau8825_jack, + nau8825_jack_pins, + ARRAY_SIZE(nau8825_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; } - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - ret = snd_soc_component_set_jack(component, &pco_jack, NULL); + ret = snd_soc_component_set_jack(component, &nau8825_jack, NULL); if (ret) { dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); return ret; @@ -921,8 +1032,25 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, return ret; } +static struct snd_soc_jack nau8821_jack; +static struct snd_soc_jack_pin nau8821_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static const struct snd_kcontrol_new nau8821_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + static const struct snd_soc_dapm_widget nau8821_widgets[] = { - SND_SOC_DAPM_HP("Headphone jack", NULL), + 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, @@ -932,12 +1060,12 @@ static const struct snd_soc_dapm_widget nau8821_widgets[] = { 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" }, + { "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" }, + { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, { "Int Mic", NULL, "Platform Clock" }, }; @@ -966,21 +1094,31 @@ static int acp_8821_init(struct snd_soc_pcm_runtime *rtd) 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); + ret = snd_soc_add_card_controls(card, nau8821_controls, + ARRAY_SIZE(nau8821_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new_pins(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, + &nau8821_jack, + nau8821_jack_pins, + ARRAY_SIZE(nau8821_jack_pins)); 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); + snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + nau8821_enable_jack_detect(component, &nau8821_jack); return snd_soc_dapm_add_routes(&rtd->card->dapm, nau8821_audio_route, ARRAY_SIZE(nau8821_audio_route)); -- cgit v1.2.3 From 00c7ee820895c9563b7780f84f1b9420cbfbe6c7 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:14 +0300 Subject: ASoC: amd: acp3x-rt5682-max9836: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5682, RT1015 and RT1015p codecs used here can detect Headphone and Headset Mic connections. Expose the former two to userspace as kcontrols. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-5-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/acp3x-rt5682-max9836.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/amd/acp3x-rt5682-max9836.c b/sound/soc/amd/acp3x-rt5682-max9836.c index 0543dda75b99..3bf7e1e83c36 100644 --- a/sound/soc/amd/acp3x-rt5682-max9836.c +++ b/sound/soc/amd/acp3x-rt5682-max9836.c @@ -28,6 +28,17 @@ #define DUAL_CHANNEL 2 static struct snd_soc_jack pco_jack; +static struct snd_soc_jack_pin pco_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static struct clk *rt5682_dai_wclk; static struct clk *rt5682_dai_bclk; static struct gpio_desc *dmic_sel; @@ -86,11 +97,13 @@ static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd) rt5682_dai_wclk = clk_get(component->dev, "rt5682-dai-wclk"); rt5682_dai_bclk = clk_get(component->dev, "rt5682-dai-bclk"); - 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, - &pco_jack); + ret = snd_soc_card_jack_new_pins(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, + &pco_jack, + pco_jack_pins, + ARRAY_SIZE(pco_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; -- cgit v1.2.3 From c699fc46f45bab70a831a56e95d6f6c6e51ac7be Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:15 +0300 Subject: ASoC: Intel: avs: da7219: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The DA7219 codec used here can detect Headphones, Headset Mic and Line Out connections. Expose each to userspace as kcontrols and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-6-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/da7219.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c index 964a763732ab..85014d98f7e8 100644 --- a/sound/soc/intel/avs/boards/da7219.c +++ b/sound/soc/intel/avs/boards/da7219.c @@ -22,6 +22,7 @@ static const struct snd_kcontrol_new card_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static int platform_clock_control(struct snd_soc_dapm_widget *w, @@ -55,6 +56,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, static const struct snd_soc_dapm_widget card_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU), }; @@ -68,6 +70,22 @@ static const struct snd_soc_dapm_route card_base_routes[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, +}; + +static const struct snd_soc_jack_pin card_headset_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime) @@ -75,7 +93,9 @@ static int avs_da7219_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 snd_soc_jack *jack; + int num_pins; int clk_freq; int ret; @@ -91,14 +111,20 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime) return ret; } + 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; + /* * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3 | SND_JACK_LINEOUT, 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 | SND_JACK_LINEOUT, + jack, pins, num_pins); if (ret) { dev_err(card->dev, "Headset Jack creation failed: %d\n", ret); return ret; -- cgit v1.2.3 From 92d7071f751a863fe22aaf8cfdd94f96749e0aa5 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:16 +0300 Subject: ASoC: Intel: bxt_da7219_max98357a: Map missing Line Out jack kcontrol Commit bbdd4ea2190b4 ("ASoC: Intel: bxt_da7219_max98357a: remap jack pins") maps kcontrols for Headphone and Headset Mic jacks for this driver so that PulseAudio and PipeWire can handle detection events for these peripherals. The DA7219 codec used here can also distinguish between Headphone and Line Out connections that go into the same physical port. Expose the latter to userspace as a kcontrol as well and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-7-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index c593995facaa..cbfff466c5c8 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -90,6 +90,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, static const struct snd_kcontrol_new broxton_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static const struct snd_kcontrol_new max98357a_controls[] = { @@ -104,6 +105,7 @@ static const struct snd_kcontrol_new max98390_controls[] = { static const struct snd_soc_dapm_widget broxton_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_SPK("HDMI1", NULL), SND_SOC_DAPM_SPK("HDMI2", NULL), @@ -150,6 +152,7 @@ static const struct snd_soc_dapm_route audio_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, }; static const struct snd_soc_dapm_route max98357a_routes[] = { @@ -194,6 +197,10 @@ static struct snd_soc_jack_pin jack_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd, -- cgit v1.2.3 From 4e06382c0d275fa1e365ca2ee9b2286b7c49b07f Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:17 +0300 Subject: ASoC: Intel: bytcr_wm5102: Map missing Line Out jack kcontrol Commit ecd77d494ec9 ("ASoC: Intel: bytcr_wm5102: Add jack detect support") maps kcontrols for Headphone and Headset Mic jacks for this driver so that PulseAudio and PipeWire can handle jack detection events for these peripherals. The WM5102 codec used here can also distinguish between Headphone and Line Out connections that go into the same physical port. Expose the latter to userspace as a kcontrol as well and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-8-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_wm5102.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c index f2382d4cb76f..5c9e06ed1a53 100644 --- a/sound/soc/intel/boards/bytcr_wm5102.c +++ b/sound/soc/intel/boards/bytcr_wm5102.c @@ -131,6 +131,7 @@ static const struct snd_soc_dapm_widget byt_wm5102_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Internal Mic", NULL), SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_LINE("Line Out", 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), @@ -144,6 +145,7 @@ static const struct snd_soc_dapm_route byt_wm5102_audio_map[] = { {"Headset Mic", NULL, "Platform Clock"}, {"Internal Mic", NULL, "Platform Clock"}, {"Speaker", NULL, "Platform Clock"}, + {"Line Out", NULL, "Platform Clock"}, {"Speaker", NULL, "SPKOUTLP"}, {"Speaker", NULL, "SPKOUTLN"}, @@ -177,6 +179,7 @@ static const struct snd_kcontrol_new byt_wm5102_controls[] = { SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Internal Mic"), SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static struct snd_soc_jack_pin byt_wm5102_pins[] = { @@ -188,6 +191,10 @@ static struct snd_soc_jack_pin byt_wm5102_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime) -- cgit v1.2.3 From da09176f1f04baae467c97a4dc8b6d9fa5cd11b8 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:18 +0300 Subject: ASoC: Intel: kbl_da7219_max98357a: Map missing Line Out jack kcontrol Commit c2065d43ae85 ("ASoC: Intel: kbl_da7219_max98357a: remap jack pins") maps kcontrols for Headphone and Headset Mic jacks for this driver so that PulseAudio and PipeWire can handle jack detection events for these peripherals. The DA7219 codec used here can also distinguish between Headphone and Line Out connections that go into the same physical port. Expose the latter to userspace as a kcontrol as well and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-9-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/kbl_da7219_max98357a.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c index 18365ce6bcba..97149513076f 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98357a.c +++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c @@ -83,12 +83,14 @@ static const struct snd_kcontrol_new kabylake_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Spk"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static const struct snd_soc_dapm_widget kabylake_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Spk", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_SPK("HDMI1", NULL), SND_SOC_DAPM_SPK("HDMI2", NULL), @@ -107,6 +109,10 @@ static struct snd_soc_jack_pin jack_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static const struct snd_soc_dapm_route kabylake_map[] = { @@ -147,6 +153,7 @@ static const struct snd_soc_dapm_route kabylake_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, }; static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, -- cgit v1.2.3 From 2830bfdbe90b0bf6170f88ca0803fa72e1b1e506 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:19 +0300 Subject: ASoC: Intel: kbl_da7219_max98927: Map missing Line Out jack kcontrol Commit b9f53b9fc14e ("ASoC: Intel: kbl_da7219_max98927: remap jack pins") maps kcontrols for Headphone and Headset Mic jacks for this driver so that PulseAudio and PipeWire can handle jack detection events for these peripherals. The DA7219 codec used here can also distinguish between Headphone and Line Out connections that go into the same physical port. Expose the latter to userspace as a kcontrol as well and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-10-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/kbl_da7219_max98927.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index ad4223fee0c5..a1f8234c77bd 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -102,6 +102,7 @@ static const struct snd_kcontrol_new kabylake_controls[] = { SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Left Spk"), SOC_DAPM_PIN_SWITCH("Right Spk"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static const struct snd_soc_dapm_widget kabylake_widgets[] = { @@ -109,6 +110,7 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Left Spk", NULL), SND_SOC_DAPM_SPK("Right Spk", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_SPK("HDMI1", NULL), SND_SOC_DAPM_SPK("HDMI2", NULL), @@ -127,6 +129,10 @@ static struct snd_soc_jack_pin jack_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_MICROPHONE, + }, }; static const struct snd_soc_dapm_route kabylake_map[] = { @@ -182,6 +188,7 @@ static const struct snd_soc_dapm_route kabylake_ssp1_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, }; static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, -- cgit v1.2.3 From 7265089ade245d062fe8f9938261656ff2a49633 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:20 +0300 Subject: ASoC: Intel: sof_da7219_max98373: Map missing Line Out jack kcontrol Commit 2913bb1f6830 ("ASoC: Intel: sof_da7219_max98373: remap jack pins") maps kcontrols for Headphone and Headset Mic jacks for this driver so that PulseAudio and PipeWire can handle jack detection events for these peripherals. The DA7219 codec used here can also distinguish between Headphone and Line Out connections that go into the same physical port. Expose the latter to userspace as a kcontrol as well and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-11-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_da7219_max98373.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_da7219_max98373.c b/sound/soc/intel/boards/sof_da7219_max98373.c index 740aa11cb019..bbd47e7e4343 100644 --- a/sound/soc/intel/boards/sof_da7219_max98373.c +++ b/sound/soc/intel/boards/sof_da7219_max98373.c @@ -65,6 +65,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, static const struct snd_kcontrol_new controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), SOC_DAPM_PIN_SWITCH("Left Spk"), SOC_DAPM_PIN_SWITCH("Right Spk"), }; @@ -72,6 +73,7 @@ static const struct snd_kcontrol_new controls[] = { static const struct snd_kcontrol_new m98360a_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), SOC_DAPM_PIN_SWITCH("Spk"), }; @@ -79,6 +81,7 @@ static const struct snd_kcontrol_new m98360a_controls[] = { static const struct snd_soc_dapm_widget widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_SPK("Left Spk", NULL), SND_SOC_DAPM_SPK("Right Spk", NULL), @@ -98,6 +101,7 @@ static const struct snd_soc_dapm_route audio_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, { "Left Spk", NULL, "Left BE_OUT" }, { "Right Spk", NULL, "Right BE_OUT" }, @@ -110,6 +114,7 @@ static const struct snd_soc_dapm_route audio_map[] = { static const struct snd_soc_dapm_widget max98360a_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_SPK("Spk", NULL), @@ -128,6 +133,7 @@ static const struct snd_soc_dapm_route max98360a_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, {"Spk", NULL, "Speaker"}, @@ -144,6 +150,10 @@ static struct snd_soc_jack_pin jack_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static struct snd_soc_jack headset; -- cgit v1.2.3 From 105e84586bfcbe8e48e386936899c4eb8c00be71 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:21 +0300 Subject: ASoC: imx-es8328: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. It seems to have a single detection GPIO pin used to report everything as a Headset. But it has widgets for Headphone and Mic Jack, so expose both to userspace as kcontrols. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-12-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-es8328.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c index 85bd36fb68a2..6f0d031c1d5f 100644 --- a/sound/soc/fsl/imx-es8328.c +++ b/sound/soc/fsl/imx-es8328.c @@ -37,6 +37,16 @@ static struct snd_soc_jack_gpio headset_jack_gpios[] = { }; static struct snd_soc_jack headset_jack; +static struct snd_soc_jack_pin headset_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, +}; static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd) { @@ -46,9 +56,11 @@ static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd) /* Headphone jack detection */ if (gpio_is_valid(data->jack_gpio)) { - ret = snd_soc_card_jack_new(rtd->card, "Headphone", - SND_JACK_HEADPHONE | SND_JACK_BTN_0, - &headset_jack); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headphone", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &headset_jack, + headset_jack_pins, + ARRAY_SIZE(headset_jack_pins)); if (ret) return ret; @@ -68,6 +80,11 @@ static const struct snd_soc_dapm_widget imx_es8328_dapm_widgets[] = { SND_SOC_DAPM_REGULATOR_SUPPLY("audio-amp", 1, 0), }; +static const struct snd_kcontrol_new imx_es8328_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Mic Jack"), +}; + static int imx_es8328_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -183,6 +200,8 @@ static int imx_es8328_probe(struct platform_device *pdev) data->card.dev = dev; data->card.dapm_widgets = imx_es8328_dapm_widgets; data->card.num_dapm_widgets = ARRAY_SIZE(imx_es8328_dapm_widgets); + data->card.controls = imx_es8328_controls; + data->card.num_controls = ARRAY_SIZE(imx_es8328_controls); ret = snd_soc_of_parse_card_name(&data->card, "model"); if (ret) { dev_err(dev, "Unable to parse card name\n"); -- cgit v1.2.3 From 73864428ba983bc35e1efabc2e3ec04c6d87c67c Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:22 +0300 Subject: ASoC: mediatek: mt8173-max98090: Configure jack as a Headset jack This driver has correctly mapped jack kcontrols for Headphone and Headset Mic. However, it is configuring the jack to only care about Headphone events. The MAX98090 codec used here can detect both connections, so configure the jack as such. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-13-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173/mt8173-max98090.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c index c2b0619b6158..bfb2094758ff 100644 --- a/sound/soc/mediatek/mt8173/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c @@ -70,7 +70,7 @@ static int mt8173_max98090_init(struct snd_soc_pcm_runtime *runtime) struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component; /* enable jack detection */ - ret = snd_soc_card_jack_new_pins(card, "Headphone", SND_JACK_HEADPHONE, + ret = snd_soc_card_jack_new_pins(card, "Headphone", SND_JACK_HEADSET, &mt8173_max98090_jack, mt8173_max98090_jack_pins, ARRAY_SIZE(mt8173_max98090_jack_pins)); -- cgit v1.2.3 From 87eb19815fa53220602fa40b77f7e3504bf6b476 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:23 +0300 Subject: ASoC: mediatek: mt8173-rt5650-rt5514: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5645 codec used here can detect Headphone and Headset Mic connections. Expose each to userspace as kcontrols. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-14-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index f803f121659d..e502cd1670ba 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -40,6 +40,17 @@ static const struct snd_kcontrol_new mt8173_rt5650_rt5514_controls[] = { SOC_DAPM_PIN_SWITCH("Headset Mic"), }; +static struct snd_soc_jack_pin mt8173_rt5650_rt5514_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int mt8173_rt5650_rt5514_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -82,11 +93,13 @@ static int mt8173_rt5650_rt5514_init(struct snd_soc_pcm_runtime *runtime) RT5645_CLK_SEL_I2S1_ASRC); /* enable jack detection */ - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &mt8173_rt5650_rt5514_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &mt8173_rt5650_rt5514_jack, + mt8173_rt5650_rt5514_jack_pins, + ARRAY_SIZE(mt8173_rt5650_rt5514_jack_pins)); if (ret) { dev_err(card->dev, "Can't new Headset Jack %d\n", ret); return ret; -- cgit v1.2.3 From 8badca99caf0cc843341e3ffa87d24f9caa206c9 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:24 +0300 Subject: ASoC: mediatek: mt8173-rt5650-rt5676: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5645 codec used here can detect Headphone and Headset Mic connections. Expose both to userspace as kcontrols. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-15-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index 8794720cea3a..ffb094284bfb 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -44,6 +44,17 @@ static const struct snd_kcontrol_new mt8173_rt5650_rt5676_controls[] = { SOC_DAPM_PIN_SWITCH("Headset Mic"), }; +static struct snd_soc_jack_pin mt8173_rt5650_rt5676_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int mt8173_rt5650_rt5676_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -95,11 +106,13 @@ static int mt8173_rt5650_rt5676_init(struct snd_soc_pcm_runtime *runtime) RT5677_CLK_SEL_I2S2_ASRC); /* enable jack detection */ - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &mt8173_rt5650_rt5676_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &mt8173_rt5650_rt5676_jack, + mt8173_rt5650_rt5676_jack_pins, + ARRAY_SIZE(mt8173_rt5650_rt5676_jack_pins)); if (ret) { dev_err(card->dev, "Can't new Headset Jack %d\n", ret); return ret; -- cgit v1.2.3 From 0ef5533f7b54419f5b108d6004f56c6de78f026d Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:25 +0300 Subject: ASoC: mediatek: mt8173-rt5650: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5645 codec used here can detect Headphone and Headset Mic connections. Expose both to userspace as kcontrols. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-16-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173/mt8173-rt5650.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index 3ece4b5eaca2..18cf84bb25c7 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -54,6 +54,17 @@ static const struct snd_kcontrol_new mt8173_rt5650_controls[] = { SOC_DAPM_PIN_SWITCH("Headset Mic"), }; +static struct snd_soc_jack_pin mt8173_rt5650_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -128,11 +139,13 @@ static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime) } /* enable jack detection */ - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &mt8173_rt5650_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &mt8173_rt5650_jack, + mt8173_rt5650_jack_pins, + ARRAY_SIZE(mt8173_rt5650_jack_pins)); if (ret) { dev_err(card->dev, "Can't new Headset Jack %d\n", ret); return ret; -- cgit v1.2.3 From 9c7388baa2053f333dc524814be4d95f0c2c8ae7 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:26 +0300 Subject: ASoC: mediatek: mt8183-da7219-max98357: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The DA7219 codec used here can detect Headphones, Headset Mic and Line Out connections. Expose each to userspace as kcontrols and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-17-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c | 43 ++++++++++++++++++---- 1 file changed, 36 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index 87bb04846991..701fbcc0f2c9 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -29,6 +29,21 @@ struct mt8183_da7219_max98357_priv { struct snd_soc_jack headset_jack, hdmi_jack; }; +static struct snd_soc_jack_pin mt8183_da7219_max98357_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, +}; + static int mt8183_mt6358_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -572,13 +587,15 @@ mt8183_da7219_max98357_headset_init(struct snd_soc_component *component) snd_soc_card_get_drvdata(component->card); /* Enable Headset and 4 Buttons Jack detection */ - ret = snd_soc_card_jack_new(component->card, - "Headset Jack", - SND_JACK_HEADSET | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | - SND_JACK_LINEOUT, - &priv->headset_jack); + ret = snd_soc_card_jack_new_pins(component->card, + "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | + SND_JACK_LINEOUT, + &priv->headset_jack, + mt8183_da7219_max98357_jack_pins, + ARRAY_SIZE(mt8183_da7219_max98357_jack_pins)); if (ret) return ret; @@ -609,12 +626,18 @@ static struct snd_soc_codec_conf mt6358_codec_conf[] = { }; static const struct snd_kcontrol_new mt8183_da7219_max98357_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static const struct snd_soc_dapm_widget mt8183_da7219_max98357_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Speakers", NULL), + SND_SOC_DAPM_SPK("Line Out", NULL), SND_SOC_DAPM_PINCTRL("TDM_OUT_PINCTRL", "aud_tdm_out_on", "aud_tdm_out_off"), }; @@ -657,14 +680,20 @@ static struct snd_soc_codec_conf mt8183_da7219_rt1015_codec_conf[] = { }; static const struct snd_kcontrol_new mt8183_da7219_rt1015_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Left Spk"), SOC_DAPM_PIN_SWITCH("Right Spk"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static const struct snd_soc_dapm_widget mt8183_da7219_rt1015_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Left Spk", NULL), SND_SOC_DAPM_SPK("Right Spk", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_PINCTRL("TDM_OUT_PINCTRL", "aud_tdm_out_on", "aud_tdm_out_off"), }; -- cgit v1.2.3 From 09a22368bb87a90a447d901e7f5bf2037f321769 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:27 +0300 Subject: ASoC: mediatek: mt8183-mt6358-ts3a227-max98357: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The TS3A227 component used here can detect Headphones and Headset Mic connections. Expose each to userspace as kcontrols and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-18-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- .../mt8183/mt8183-mt6358-ts3a227-max98357.c | 53 +++++++++++++++++++--- 1 file changed, 47 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index ce9aedde7e1e..850f4d949d97 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -592,11 +592,38 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { }, }; +static const +struct snd_kcontrol_new mt8183_mt6358_ts3a227_max98357_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const +struct snd_soc_dapm_widget mt8183_mt6358_ts3a227_max98357_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static struct snd_soc_jack_pin mt8183_mt6358_ts3a227_max98357_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static struct snd_soc_card mt8183_mt6358_ts3a227_max98357_card = { .name = "mt8183_mt6358_ts3a227_max98357", .owner = THIS_MODULE, .dai_link = mt8183_mt6358_ts3a227_dai_links, .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links), + .controls = mt8183_mt6358_ts3a227_max98357_snd_controls, + .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls), + .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets), }; static struct snd_soc_card mt8183_mt6358_ts3a227_max98357b_card = { @@ -604,6 +631,10 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_max98357b_card = { .owner = THIS_MODULE, .dai_link = mt8183_mt6358_ts3a227_dai_links, .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links), + .controls = mt8183_mt6358_ts3a227_max98357_snd_controls, + .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls), + .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets), }; static struct snd_soc_codec_conf mt8183_mt6358_ts3a227_rt1015_amp_conf[] = { @@ -624,6 +655,10 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015_card = { .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links), .codec_conf = mt8183_mt6358_ts3a227_rt1015_amp_conf, .num_configs = ARRAY_SIZE(mt8183_mt6358_ts3a227_rt1015_amp_conf), + .controls = mt8183_mt6358_ts3a227_max98357_snd_controls, + .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls), + .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets), }; static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015p_card = { @@ -631,6 +666,10 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015p_card = { .owner = THIS_MODULE, .dai_link = mt8183_mt6358_ts3a227_dai_links, .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links), + .controls = mt8183_mt6358_ts3a227_max98357_snd_controls, + .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls), + .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets), }; static int @@ -641,12 +680,14 @@ mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *component) snd_soc_card_get_drvdata(component->card); /* Enable Headset and 4 Buttons Jack detection */ - ret = snd_soc_card_jack_new(component->card, - "Headset Jack", - SND_JACK_HEADSET | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &priv->headset_jack); + ret = snd_soc_card_jack_new_pins(component->card, + "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &priv->headset_jack, + mt8183_mt6358_ts3a227_max98357_jack_pins, + ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_jack_pins)); if (ret) return ret; -- cgit v1.2.3 From 26de9cc1b96eecfe9fb9c672272665e97c3cdc59 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:28 +0300 Subject: ASoC: mediatek: mt8186-mt6366-da7219-max98357: Map missing jack kcontrols Commit 8e9867486806 ("ASoC: mediatek: mt8186-da7219: Expose individual headset jack pins") maps kcontrols for Headphone and Headset Mic jacks for this driver so that PulseAudio and PipeWire can handle jack detection events for these peripherals. The DA7219 codec used here can also distinguish between Headphone and Line Out connections that go into the same physical port. Expose the latter to userspace as a kcontrol as well and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-19-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c index 0432f9d89020..aa8e00bba19b 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c @@ -46,6 +46,10 @@ static struct snd_soc_jack_pin mt8186_jack_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static struct snd_soc_codec_conf mt8186_mt6366_da7219_max98357_codec_conf[] = { @@ -964,6 +968,7 @@ mt8186_mt6366_da7219_max98357_widgets[] = { SND_SOC_DAPM_SPK("Speakers", NULL), SND_SOC_DAPM_HP("Headphones", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_OUTPUT("HDMI1"), SND_SOC_DAPM_MIXER(SOF_DMA_DL1, SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER(SOF_DMA_DL2, SND_SOC_NOPM, 0, 0, NULL, 0), @@ -996,6 +1001,7 @@ mt8186_mt6366_da7219_max98357_controls[] = { SOC_DAPM_PIN_SWITCH("Speakers"), SOC_DAPM_PIN_SWITCH("Headphones"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), SOC_DAPM_PIN_SWITCH("HDMI1"), }; -- cgit v1.2.3 From 45bda58af84ffd5c951267f848c8dc10ea485c06 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:29 +0300 Subject: ASoC: qcom: apq8016_sbc: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. It seems to support detecting Headphone and Headset Mic connections. Expose each to userspace as a kcontrol and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-20-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/qcom/apq8016_sbc.c | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index e54b8961112f..6de533d45e7d 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -44,6 +44,17 @@ struct apq8016_sbc_data { #define DEFAULT_MCLK_RATE 9600000 #define MI2S_BCLK_RATE 1536000 +static struct snd_soc_jack_pin apq8016_sbc_jack_pins[] = { + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, +}; + static int apq8016_dai_init(struct snd_soc_pcm_runtime *rtd, int mi2s) { struct snd_soc_dai *codec_dai; @@ -90,13 +101,15 @@ static int apq8016_dai_init(struct snd_soc_pcm_runtime *rtd, int mi2s) if (!pdata->jack_setup) { struct snd_jack *jack; - rval = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | - SND_JACK_HEADPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | - SND_JACK_BTN_4, - &pdata->jack); + rval = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_HEADPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | + SND_JACK_BTN_4, + &pdata->jack, + apq8016_sbc_jack_pins, + ARRAY_SIZE(apq8016_sbc_jack_pins)); if (rval < 0) { dev_err(card->dev, "Unable to add Headphone Jack\n"); @@ -255,8 +268,14 @@ static void msm8916_qdsp6_add_ops(struct snd_soc_card *card) } } -static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = { +static const struct snd_kcontrol_new apq8016_sbc_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Mic Jack"), +}; +static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), SND_SOC_DAPM_MIC("Handset Mic", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Secondary Mic", NULL), @@ -285,6 +304,8 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev) card->owner = THIS_MODULE; card->dapm_widgets = apq8016_sbc_dapm_widgets; card->num_dapm_widgets = ARRAY_SIZE(apq8016_sbc_dapm_widgets); + card->controls = apq8016_sbc_snd_controls; + card->num_controls = ARRAY_SIZE(apq8016_sbc_snd_controls); ret = qcom_snd_parse_of(card); if (ret) -- cgit v1.2.3 From 883bfefca437c9061686fa8d092d5a8fa04d06c8 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:30 +0300 Subject: ASoC: qcom: sc7180: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5682 and RT5682s codecs used here can detect Headphone and Headset Mic connections. Expose each to userspace as a kcontrol. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-21-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/qcom/sc7180.c | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c index f5f7c64b23a2..57c5f35dfcc5 100644 --- a/sound/soc/qcom/sc7180.c +++ b/sound/soc/qcom/sc7180.c @@ -42,6 +42,17 @@ static void sc7180_jack_free(struct snd_jack *jack) snd_soc_component_set_jack(component, NULL, NULL); } +static struct snd_soc_jack_pin sc7180_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int sc7180_headset_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; @@ -51,13 +62,14 @@ static int sc7180_headset_init(struct snd_soc_pcm_runtime *rtd) struct snd_jack *jack; int rval; - rval = snd_soc_card_jack_new( - card, "Headset Jack", - SND_JACK_HEADSET | - SND_JACK_HEADPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pdata->hs_jack); + rval = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_HEADPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &pdata->hs_jack, + sc7180_jack_pins, + ARRAY_SIZE(sc7180_jack_pins)); if (rval < 0) { dev_err(card->dev, "Unable to add Headset Jack\n"); @@ -297,6 +309,11 @@ static const struct snd_soc_dapm_widget sc7180_snd_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), }; +static const struct snd_kcontrol_new sc7180_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + static const struct snd_soc_dapm_widget sc7180_adau7002_snd_widgets[] = { SND_SOC_DAPM_MIC("DMIC", NULL), }; @@ -320,6 +337,11 @@ static const struct snd_soc_dapm_widget sc7180_snd_dual_mic_widgets[] = { SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0, &sc7180_dmic_mux_control), }; +static const struct snd_kcontrol_new sc7180_snd_dual_mic_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + static const struct snd_soc_dapm_route sc7180_snd_dual_mic_audio_route[] = { {"Dmic Mux", "Front Mic", "DMIC"}, {"Dmic Mux", "Rear Mic", "DMIC"}, @@ -348,10 +370,14 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev) card->dev = dev; card->dapm_widgets = sc7180_snd_widgets; card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_widgets); + card->controls = sc7180_snd_controls; + card->num_controls = ARRAY_SIZE(sc7180_snd_controls); if (of_property_read_bool(dev->of_node, "dmic-gpios")) { card->dapm_widgets = sc7180_snd_dual_mic_widgets, card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_dual_mic_widgets), + card->controls = sc7180_snd_dual_mic_controls, + card->num_controls = ARRAY_SIZE(sc7180_snd_dual_mic_controls), card->dapm_routes = sc7180_snd_dual_mic_audio_route, card->num_dapm_routes = ARRAY_SIZE(sc7180_snd_dual_mic_audio_route), data->dmic_sel = devm_gpiod_get(&pdev->dev, "dmic", GPIOD_OUT_LOW); -- cgit v1.2.3 From 4ab959e5a11624805983909d18ca7f653bab748c Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:31 +0300 Subject: ASoC: qcom: sc7280: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5682 and RT5682s codecs used here can detect Headphone and Headset Mic connections. Expose each to userspace as a kcontrol. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-22-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/qcom/sc7280.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/sc7280.c b/sound/soc/qcom/sc7280.c index 787dd49e03f6..43010e4e2242 100644 --- a/sound/soc/qcom/sc7280.c +++ b/sound/soc/qcom/sc7280.c @@ -43,6 +43,17 @@ static void sc7280_jack_free(struct snd_jack *jack) snd_soc_component_set_jack(component, NULL, NULL); } +static struct snd_soc_jack_pin sc7280_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; @@ -54,13 +65,15 @@ static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd) int rval, i; if (!pdata->jack_setup) { - rval = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_MECHANICAL | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | - SND_JACK_BTN_4 | SND_JACK_BTN_5, - &pdata->hs_jack); + rval = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_MECHANICAL | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | + SND_JACK_BTN_4 | SND_JACK_BTN_5, + &pdata->hs_jack, + sc7280_jack_pins, + ARRAY_SIZE(sc7280_jack_pins)); if (rval < 0) { dev_err(card->dev, "Unable to add Headset Jack\n"); @@ -361,6 +374,11 @@ static const struct snd_soc_dapm_widget sc7280_snd_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), }; +static const struct snd_kcontrol_new sc7280_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + static int sc7280_snd_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -396,6 +414,8 @@ static int sc7280_snd_platform_probe(struct platform_device *pdev) card->dapm_widgets = sc7280_snd_widgets; card->num_dapm_widgets = ARRAY_SIZE(sc7280_snd_widgets); + card->controls = sc7280_snd_controls; + card->num_controls = ARRAY_SIZE(sc7280_snd_controls); ret = qcom_snd_parse_of(card); if (ret) -- cgit v1.2.3 From 242372d64e5ee39be518672abd7b797d5cd9521b Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:32 +0300 Subject: ASoC: qcom: sdm845: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5663 codec used here can detect Headphone and Headset Mic connections. Expose each to userspace as a kcontrol. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-23-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/qcom/sdm845.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 02612af714a8..29d23fe5dfa2 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -42,6 +42,17 @@ struct sdm845_snd_data { struct sdw_stream_runtime *sruntime[AFE_PORT_MAX]; }; +static struct snd_soc_jack_pin sdm845_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28}; static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream, @@ -242,12 +253,14 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd) if (!pdata->jack_setup) { - rval = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | - SND_JACK_HEADPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pdata->jack); + rval = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_HEADPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &pdata->jack, + sdm845_jack_pins, + ARRAY_SIZE(sdm845_jack_pins)); if (rval < 0) { dev_err(card->dev, "Unable to add Headphone Jack\n"); @@ -539,6 +552,11 @@ static const struct snd_soc_dapm_widget sdm845_snd_widgets[] = { SND_SOC_DAPM_MIC("Int Mic", NULL), }; +static const struct snd_kcontrol_new sdm845_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + static void sdm845_add_ops(struct snd_soc_card *card) { struct snd_soc_dai_link *link; @@ -572,6 +590,8 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev) card->driver_name = DRIVER_NAME; card->dapm_widgets = sdm845_snd_widgets; card->num_dapm_widgets = ARRAY_SIZE(sdm845_snd_widgets); + card->controls = sdm845_snd_controls; + card->num_controls = ARRAY_SIZE(sdm845_snd_controls); card->dev = dev; card->owner = THIS_MODULE; dev_set_drvdata(dev, card); -- cgit v1.2.3 From d60e810a0fa83692116293b4b798ab0273668108 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:33 +0300 Subject: ASoC: rk3399-gru-sound: Map missing Line Out jack kcontrol Commit d0508b4f1604 ("ASoC: rk3399_gru_sound: Add DAPM pins, kcontrols for jack detection") maps kcontrols for Headphones and Headset Mic jacks for this driver so that PulseAudio and PipeWire can handle insertion events for these peripherals. The DA7219 codec used here can also distinguish between Headphone and Line Out connections that go into the same physical port. Expose the latter to userspace as a kcontrol as well and add the necessary widget. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-24-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/rockchip/rk3399_gru_sound.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c index 5e52e9d60d44..0f704d22d21b 100644 --- a/sound/soc/rockchip/rk3399_gru_sound.c +++ b/sound/soc/rockchip/rk3399_gru_sound.c @@ -41,13 +41,17 @@ static struct snd_soc_jack_pin rockchip_sound_jack_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, - + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphones", NULL), SND_SOC_DAPM_SPK("Speakers", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_MIC("Int Mic", NULL), SND_SOC_DAPM_LINE("HDMI", NULL), }; @@ -56,6 +60,7 @@ static const struct snd_kcontrol_new rockchip_controls[] = { SOC_DAPM_PIN_SWITCH("Headphones"), SOC_DAPM_PIN_SWITCH("Speakers"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), SOC_DAPM_PIN_SWITCH("Int Mic"), SOC_DAPM_PIN_SWITCH("HDMI"), }; -- cgit v1.2.3 From 24127e5a07a8eac754be50f537df891ebdadf1b8 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:34 +0300 Subject: ASoC: rockchip: rockchip_rt5645: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5645 codec used here supports detecting Headphone and Headset Mic connections. Expose both to userspace as kcontrols. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-25-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_rt5645.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c index e73a342b7953..ef9fdf0386cb 100644 --- a/sound/soc/rockchip/rockchip_rt5645.c +++ b/sound/soc/rockchip/rockchip_rt5645.c @@ -22,6 +22,16 @@ #define DRV_NAME "rockchip-snd-rt5645" static struct snd_soc_jack headset_jack; +static struct snd_soc_jack_pin headset_jack_pins[] = { + { + .pin = "Headphones", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; static const struct snd_soc_dapm_widget rk_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphones", NULL), @@ -103,11 +113,13 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime) int ret; /* Enable Headset and 4 Buttons Jack detection */ - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &headset_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &headset_jack, + headset_jack_pins, + ARRAY_SIZE(headset_jack_pins)); if (ret) { dev_err(card->dev, "New Headset Jack failed! (%d)\n", ret); return ret; -- cgit v1.2.3 From 4d87362f017ea16b6035906613a1c29095a6134f Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:35 +0300 Subject: ASoC: samsung: littlemill: Map missing jack kcontrols This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The WM8958 codec used here can detect Headphone and Headset Mic connections. Expose each to userspace as a kcontrol and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-26-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/samsung/littlemill.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c index 5d8118e69359..fafadcef234e 100644 --- a/sound/soc/samsung/littlemill.c +++ b/sound/soc/samsung/littlemill.c @@ -225,12 +225,15 @@ static int bbclk_ev(struct snd_soc_dapm_widget *w, } static const struct snd_kcontrol_new controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("WM1250 Input"), SOC_DAPM_PIN_SWITCH("WM1250 Output"), }; static const struct snd_soc_dapm_widget widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_HP("Headset Mic", NULL), SND_SOC_DAPM_MIC("AMIC", NULL), SND_SOC_DAPM_MIC("DMIC", NULL), @@ -255,6 +258,16 @@ static const struct snd_soc_dapm_route audio_paths[] = { }; static struct snd_soc_jack littlemill_headset; +static struct snd_soc_jack_pin littlemill_headset_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; static int littlemill_late_probe(struct snd_soc_card *card) { @@ -281,12 +294,14 @@ static int littlemill_late_probe(struct snd_soc_card *card) if (ret < 0) return ret; - ret = snd_soc_card_jack_new(card, "Headset", - SND_JACK_HEADSET | SND_JACK_MECHANICAL | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | - SND_JACK_BTN_4 | SND_JACK_BTN_5, - &littlemill_headset); + ret = snd_soc_card_jack_new_pins(card, "Headset", + SND_JACK_HEADSET | SND_JACK_MECHANICAL | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | + SND_JACK_BTN_4 | SND_JACK_BTN_5, + &littlemill_headset, + littlemill_headset_pins, + ARRAY_SIZE(littlemill_headset_pins)); if (ret) return ret; -- cgit v1.2.3 From c9d3401844fa6ec6fa924859dca95bac38b1e1ff Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:36 +0300 Subject: ASoC: samsung: lowland: Split Line Out jack kcontrol from Headphone This driver has correctly mapped jack kcontrols for Headphone and Headset Mic. However, it is also mapping Line Out jack detection events to the Headphone kcontrol. The WM5100 codec used here can distinguish Line Out connections from Headphone connections. Decouple the two, expose Line Out to userspace as an independent kcontrol and add the necessary widget. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-27-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/samsung/lowland.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c index 106770be6fc5..a79df871ea13 100644 --- a/sound/soc/samsung/lowland.c +++ b/sound/soc/samsung/lowland.c @@ -22,12 +22,16 @@ static struct snd_soc_jack lowland_headset; static struct snd_soc_jack_pin lowland_headset_pins[] = { { .pin = "Headphone", - .mask = SND_JACK_HEADPHONE | SND_JACK_LINEOUT, + .mask = SND_JACK_HEADPHONE, }, { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd) @@ -140,11 +144,13 @@ static const struct snd_kcontrol_new controls[] = { SOC_DAPM_PIN_SWITCH("WM1250 Input"), SOC_DAPM_PIN_SWITCH("WM1250 Output"), SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static const struct snd_soc_dapm_widget widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_SPK("Main Speaker", NULL), -- cgit v1.2.3 From d27224a45e5457ad89195d92decdd57596253428 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 2 Aug 2023 20:57:37 +0300 Subject: ASoC: samsung: midas_wm1811: Map missing jack kcontrols This driver does not map jack pins to kcontrols that PulseAudio/PipeWire need to handle jack detection events. The WM1811 codec used here seems to support detecting Headphone and Headset Mic connections. Expose each to userspace as a kcontrol and add the necessary widgets. Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230802175737.263412-28-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/samsung/midas_wm1811.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c index 6931b9a45b3e..44b32f5cddca 100644 --- a/sound/soc/samsung/midas_wm1811.c +++ b/sound/soc/samsung/midas_wm1811.c @@ -38,6 +38,17 @@ struct midas_priv { struct snd_soc_jack headset_jack; }; +static struct snd_soc_jack_pin headset_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int midas_start_fll1(struct snd_soc_pcm_runtime *rtd, unsigned int rate) { struct snd_soc_card *card = rtd->card; @@ -246,6 +257,7 @@ static const struct snd_kcontrol_new midas_controls[] = { SOC_DAPM_PIN_SWITCH("Main Mic"), SOC_DAPM_PIN_SWITCH("Sub Mic"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("FM In"), }; @@ -261,6 +273,7 @@ static const struct snd_soc_dapm_widget midas_dapm_widgets[] = { SND_SOC_DAPM_LINE("HDMI", NULL), SND_SOC_DAPM_LINE("FM In", midas_fm_set), + SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Main Mic", midas_mic_bias), SND_SOC_DAPM_MIC("Sub Mic", midas_submic_bias), @@ -305,11 +318,13 @@ static int midas_late_probe(struct snd_soc_card *card) return ret; } - ret = snd_soc_card_jack_new(card, "Headset", - SND_JACK_HEADSET | SND_JACK_MECHANICAL | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5, - &priv->headset_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset", + SND_JACK_HEADSET | SND_JACK_MECHANICAL | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5, + &priv->headset_jack, + headset_jack_pins, + ARRAY_SIZE(headset_jack_pins)); if (ret) return ret; -- cgit v1.2.3 From ddef7518e76d832ab9f6d0430ad28cc0e04c083a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 30 Jul 2023 22:18:25 +0200 Subject: ASoC: codecs: max9892x: Unify interleave mode OF property MAX98926 and MAX98927 are quite similar and use the same bindings, although drivers were not implementing them in the same way: MAX98926 has boolean "interleave-mode" but MAX98927 has uint32 "interleave_mode". Unify them under maxim,interleave-mode, already used in other Maxim device. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230730201826.70453-2-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/max98926.c | 3 ++- sound/soc/codecs/max98927.c | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index bdc508e23e59..922ce0dc4e60 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -528,7 +528,8 @@ static int max98926_i2c_probe(struct i2c_client *i2c) "Failed to allocate regmap: %d\n", ret); goto err_out; } - if (of_property_read_bool(i2c->dev.of_node, "interleave-mode")) + if (of_property_read_bool(i2c->dev.of_node, "maxim,interleave-mode") || + of_property_read_bool(i2c->dev.of_node, "interleave-mode")) max98926->interleave_mode = true; if (!of_property_read_u32(i2c->dev.of_node, "vmon-slot-no", &value)) { diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index 0aaf2e6ae78d..e20aa5b1bce9 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -879,14 +879,14 @@ static int max98927_i2c_probe(struct i2c_client *i2c) i2c_set_clientdata(i2c, max98927); /* update interleave mode info */ - if (!of_property_read_u32(i2c->dev.of_node, - "interleave_mode", &value)) { - if (value > 0) - max98927->interleave_mode = true; - else - max98927->interleave_mode = false; - } else - max98927->interleave_mode = false; + if (of_property_read_bool(i2c->dev.of_node, "maxim,interleave-mode")) { + max98927->interleave_mode = true; + } else { + if (!of_property_read_u32(i2c->dev.of_node, "interleave_mode", + &value)) + if (value > 0) + max98927->interleave_mode = true; + } /* regmap initialization */ max98927->regmap -- cgit v1.2.3 From 38b288ab454f9aecf7b717974028f57f5243dc5a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 30 Jul 2023 22:18:26 +0200 Subject: ASoC: codecs: max9892x: Reformat to coding style Reformat the code to match Linuxn coding style: re-indent continued lines and stop too-early line wrapping, drop unneeded {} brackets. No functional impact. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230730201826.70453-3-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/max98927.c | 341 ++++++++++++++++++-------------------------- 1 file changed, 137 insertions(+), 204 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index e20aa5b1bce9..776f23d38ac5 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -162,10 +162,8 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } - regmap_update_bits(max98927->regmap, - MAX98927_R0021_PCM_MASTER_MODE, - MAX98927_PCM_MASTER_MODE_MASK, - mode); + regmap_update_bits(max98927->regmap, MAX98927_R0021_PCM_MASTER_MODE, + MAX98927_PCM_MASTER_MODE_MASK, mode); switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: @@ -178,10 +176,8 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } - regmap_update_bits(max98927->regmap, - MAX98927_R0020_PCM_MODE_CFG, - MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE, - invert); + regmap_update_bits(max98927->regmap, MAX98927_R0020_PCM_MODE_CFG, + MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE, invert); /* interface format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -207,36 +203,31 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) if (!use_pdm) { /* pcm channel configuration */ - regmap_update_bits(max98927->regmap, - MAX98927_R0018_PCM_RX_EN_A, - MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, - MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN); + regmap_update_bits(max98927->regmap, MAX98927_R0018_PCM_RX_EN_A, + MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, + MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN); regmap_update_bits(max98927->regmap, - MAX98927_R0020_PCM_MODE_CFG, - MAX98927_PCM_MODE_CFG_FORMAT_MASK, - format << MAX98927_PCM_MODE_CFG_FORMAT_SHIFT); + MAX98927_R0020_PCM_MODE_CFG, + MAX98927_PCM_MODE_CFG_FORMAT_MASK, + format << MAX98927_PCM_MODE_CFG_FORMAT_SHIFT); - regmap_update_bits(max98927->regmap, - MAX98927_R003B_SPK_SRC_SEL, - MAX98927_SPK_SRC_MASK, 0); + regmap_update_bits(max98927->regmap, MAX98927_R003B_SPK_SRC_SEL, + MAX98927_SPK_SRC_MASK, 0); - regmap_update_bits(max98927->regmap, - MAX98927_R0035_PDM_RX_CTRL, - MAX98927_PDM_RX_EN_MASK, 0); + regmap_update_bits(max98927->regmap, MAX98927_R0035_PDM_RX_CTRL, + MAX98927_PDM_RX_EN_MASK, 0); } else { /* pdm channel configuration */ - regmap_update_bits(max98927->regmap, - MAX98927_R0035_PDM_RX_CTRL, - MAX98927_PDM_RX_EN_MASK, 1); + regmap_update_bits(max98927->regmap, MAX98927_R0035_PDM_RX_CTRL, + MAX98927_PDM_RX_EN_MASK, 1); - regmap_update_bits(max98927->regmap, - MAX98927_R003B_SPK_SRC_SEL, - MAX98927_SPK_SRC_MASK, 3); + regmap_update_bits(max98927->regmap, MAX98927_R003B_SPK_SRC_SEL, + MAX98927_SPK_SRC_MASK, 3); - regmap_update_bits(max98927->regmap, - MAX98927_R0018_PCM_RX_EN_A, - MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, 0); + regmap_update_bits(max98927->regmap, MAX98927_R0018_PCM_RX_EN_A, + MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, + 0); } return 0; } @@ -283,9 +274,9 @@ static int max98927_set_clock(struct max98927_priv *max98927, return -EINVAL; } regmap_update_bits(max98927->regmap, - MAX98927_R0021_PCM_MASTER_MODE, - MAX98927_PCM_MASTER_MODE_MCLK_MASK, - i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT); + MAX98927_R0021_PCM_MASTER_MODE, + MAX98927_PCM_MASTER_MODE_MCLK_MASK, + i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT); } if (!max98927->tdm_mode) { @@ -298,9 +289,8 @@ static int max98927_set_clock(struct max98927_priv *max98927, } regmap_update_bits(max98927->regmap, - MAX98927_R0022_PCM_CLK_SETUP, - MAX98927_PCM_CLK_SETUP_BSEL_MASK, - value); + MAX98927_R0022_PCM_CLK_SETUP, + MAX98927_PCM_CLK_SETUP_BSEL_MASK, value); } return 0; } @@ -333,9 +323,8 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream, max98927->ch_size = snd_pcm_format_width(params_format(params)); - regmap_update_bits(max98927->regmap, - MAX98927_R0020_PCM_MODE_CFG, - MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); + regmap_update_bits(max98927->regmap, MAX98927_R0020_PCM_MODE_CFG, + MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); dev_dbg(component->dev, "format supported %d", params_format(params)); @@ -375,27 +364,24 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream, goto err; } /* set DAI_SR to correct LRCLK frequency */ - regmap_update_bits(max98927->regmap, - MAX98927_R0023_PCM_SR_SETUP1, - MAX98927_PCM_SR_SET1_SR_MASK, - sampling_rate); - regmap_update_bits(max98927->regmap, - MAX98927_R0024_PCM_SR_SETUP2, - MAX98927_PCM_SR_SET2_SR_MASK, - sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT); + regmap_update_bits(max98927->regmap, MAX98927_R0023_PCM_SR_SETUP1, + MAX98927_PCM_SR_SET1_SR_MASK, sampling_rate); + regmap_update_bits(max98927->regmap, MAX98927_R0024_PCM_SR_SETUP2, + MAX98927_PCM_SR_SET2_SR_MASK, + sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT); /* set sampling rate of IV */ if (max98927->interleave_mode && sampling_rate > MAX98927_PCM_SR_SET1_SR_16000) regmap_update_bits(max98927->regmap, - MAX98927_R0024_PCM_SR_SETUP2, - MAX98927_PCM_SR_SET2_IVADC_SR_MASK, - sampling_rate - 3); + MAX98927_R0024_PCM_SR_SETUP2, + MAX98927_PCM_SR_SET2_IVADC_SR_MASK, + sampling_rate - 3); else regmap_update_bits(max98927->regmap, - MAX98927_R0024_PCM_SR_SETUP2, - MAX98927_PCM_SR_SET2_IVADC_SR_MASK, - sampling_rate); + MAX98927_R0024_PCM_SR_SETUP2, + MAX98927_PCM_SR_SET2_IVADC_SR_MASK, + sampling_rate); return max98927_set_clock(max98927, params); err: return -EINVAL; @@ -420,10 +406,8 @@ static int max98927_dai_tdm_slot(struct snd_soc_dai *dai, return -EINVAL; } - regmap_update_bits(max98927->regmap, - MAX98927_R0022_PCM_CLK_SETUP, - MAX98927_PCM_CLK_SETUP_BSEL_MASK, - bsel); + regmap_update_bits(max98927->regmap, MAX98927_R0022_PCM_CLK_SETUP, + MAX98927_PCM_CLK_SETUP_BSEL_MASK, bsel); /* Channel size configuration */ switch (slot_width) { @@ -442,33 +426,26 @@ static int max98927_dai_tdm_slot(struct snd_soc_dai *dai, return -EINVAL; } - regmap_update_bits(max98927->regmap, - MAX98927_R0020_PCM_MODE_CFG, - MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); + regmap_update_bits(max98927->regmap, MAX98927_R0020_PCM_MODE_CFG, + MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); /* Rx slot configuration */ - regmap_write(max98927->regmap, - MAX98927_R0018_PCM_RX_EN_A, - rx_mask & 0xFF); - regmap_write(max98927->regmap, - MAX98927_R0019_PCM_RX_EN_B, - (rx_mask & 0xFF00) >> 8); + regmap_write(max98927->regmap, MAX98927_R0018_PCM_RX_EN_A, + rx_mask & 0xFF); + regmap_write(max98927->regmap, MAX98927_R0019_PCM_RX_EN_B, + (rx_mask & 0xFF00) >> 8); /* Tx slot configuration */ - regmap_write(max98927->regmap, - MAX98927_R001A_PCM_TX_EN_A, - tx_mask & 0xFF); - regmap_write(max98927->regmap, - MAX98927_R001B_PCM_TX_EN_B, - (tx_mask & 0xFF00) >> 8); + regmap_write(max98927->regmap, MAX98927_R001A_PCM_TX_EN_A, + tx_mask & 0xFF); + regmap_write(max98927->regmap, MAX98927_R001B_PCM_TX_EN_B, + (tx_mask & 0xFF00) >> 8); /* Tx slot Hi-Z configuration */ - regmap_write(max98927->regmap, - MAX98927_R001C_PCM_TX_HIZ_CTRL_A, - ~tx_mask & 0xFF); - regmap_write(max98927->regmap, - MAX98927_R001D_PCM_TX_HIZ_CTRL_B, - (~tx_mask & 0xFF00) >> 8); + regmap_write(max98927->regmap, MAX98927_R001C_PCM_TX_HIZ_CTRL_A, + ~tx_mask & 0xFF); + regmap_write(max98927->regmap, MAX98927_R001D_PCM_TX_HIZ_CTRL_B, + (~tx_mask & 0xFF00) >> 8); return 0; } @@ -506,20 +483,16 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w, max98927->tdm_mode = false; break; case SND_SOC_DAPM_POST_PMU: - regmap_update_bits(max98927->regmap, - MAX98927_R003A_AMP_EN, - MAX98927_AMP_EN_MASK, 1); - regmap_update_bits(max98927->regmap, - MAX98927_R00FF_GLOBAL_SHDN, - MAX98927_GLOBAL_EN_MASK, 1); + regmap_update_bits(max98927->regmap, MAX98927_R003A_AMP_EN, + MAX98927_AMP_EN_MASK, 1); + regmap_update_bits(max98927->regmap, MAX98927_R00FF_GLOBAL_SHDN, + MAX98927_GLOBAL_EN_MASK, 1); break; case SND_SOC_DAPM_POST_PMD: - regmap_update_bits(max98927->regmap, - MAX98927_R00FF_GLOBAL_SHDN, - MAX98927_GLOBAL_EN_MASK, 0); - regmap_update_bits(max98927->regmap, - MAX98927_R003A_AMP_EN, - MAX98927_AMP_EN_MASK, 0); + regmap_update_bits(max98927->regmap, MAX98927_R00FF_GLOBAL_SHDN, + MAX98927_GLOBAL_EN_MASK, 0); + regmap_update_bits(max98927->regmap, MAX98927_R003A_AMP_EN, + MAX98927_AMP_EN_MASK, 0); break; default: return 0; @@ -532,8 +505,8 @@ static const char * const max98927_switch_text[] = { static const struct soc_enum dai_sel_enum = SOC_ENUM_SINGLE(MAX98927_R0025_PCM_TO_SPK_MONOMIX_A, - MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT, - 3, max98927_switch_text); + MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT, 3, + max98927_switch_text); static const struct snd_kcontrol_new max98927_dai_controls = SOC_DAPM_ENUM("DAI Sel", dai_sel_enum); @@ -543,17 +516,17 @@ static const struct snd_kcontrol_new max98927_vi_control = static const struct snd_soc_dapm_widget max98927_dapm_widgets[] = { SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", MAX98927_R003A_AMP_EN, - 0, 0, max98927_dac_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + 0, 0, max98927_dac_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0, - &max98927_dai_controls), + &max98927_dai_controls), SND_SOC_DAPM_OUTPUT("BE_OUT"), SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture", 0, - MAX98927_R003E_MEAS_EN, 0, 0), + MAX98927_R003E_MEAS_EN, 0, 0), SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture", 0, - MAX98927_R003E_MEAS_EN, 1, 0), + MAX98927_R003E_MEAS_EN, 1, 0), SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0, - &max98927_vi_control), + &max98927_vi_control), SND_SOC_DAPM_SIGGEN("VMON"), SND_SOC_DAPM_SIGGEN("IMON"), }; @@ -623,20 +596,19 @@ static SOC_ENUM_SINGLE_DECL(max98927_current_limit, max98927_current_limit_text); static const struct snd_kcontrol_new max98927_snd_controls[] = { - SOC_SINGLE_TLV("Speaker Volume", MAX98927_R003C_SPK_GAIN, - 0, 6, 0, - max98927_spk_tlv), + SOC_SINGLE_TLV("Speaker Volume", MAX98927_R003C_SPK_GAIN, 0, 6, 0, + max98927_spk_tlv), SOC_SINGLE_TLV("Digital Volume", MAX98927_R0036_AMP_VOL_CTRL, - 0, (1<component = component; /* Software Reset */ - regmap_write(max98927->regmap, - MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET); + regmap_write(max98927->regmap, MAX98927_R0100_SOFT_RESET, + MAX98927_SOFT_RESET); /* IV default slot configuration */ - regmap_write(max98927->regmap, - MAX98927_R001C_PCM_TX_HIZ_CTRL_A, - 0xFF); - regmap_write(max98927->regmap, - MAX98927_R001D_PCM_TX_HIZ_CTRL_B, - 0xFF); - regmap_write(max98927->regmap, - MAX98927_R0025_PCM_TO_SPK_MONOMIX_A, - 0x80); - regmap_write(max98927->regmap, - MAX98927_R0026_PCM_TO_SPK_MONOMIX_B, - 0x1); + regmap_write(max98927->regmap, MAX98927_R001C_PCM_TX_HIZ_CTRL_A, 0xFF); + regmap_write(max98927->regmap, MAX98927_R001D_PCM_TX_HIZ_CTRL_B, 0xFF); + regmap_write(max98927->regmap, MAX98927_R0025_PCM_TO_SPK_MONOMIX_A, + 0x80); + regmap_write(max98927->regmap, MAX98927_R0026_PCM_TO_SPK_MONOMIX_B, + 0x1); /* Set inital volume (+13dB) */ - regmap_write(max98927->regmap, - MAX98927_R0036_AMP_VOL_CTRL, - 0x38); - regmap_write(max98927->regmap, - MAX98927_R003C_SPK_GAIN, - 0x05); + regmap_write(max98927->regmap, MAX98927_R0036_AMP_VOL_CTRL, 0x38); + regmap_write(max98927->regmap, MAX98927_R003C_SPK_GAIN, 0x05); /* Enable DC blocker */ - regmap_write(max98927->regmap, - MAX98927_R0037_AMP_DSP_CFG, - 0x03); + regmap_write(max98927->regmap, MAX98927_R0037_AMP_DSP_CFG, 0x03); /* Enable IMON VMON DC blocker */ - regmap_write(max98927->regmap, - MAX98927_R003F_MEAS_DSP_CFG, - 0xF7); + regmap_write(max98927->regmap, MAX98927_R003F_MEAS_DSP_CFG, 0xF7); /* Boost Output Voltage & Current limit */ - regmap_write(max98927->regmap, - MAX98927_R0040_BOOST_CTRL0, - 0x1C); - regmap_write(max98927->regmap, - MAX98927_R0042_BOOST_CTRL1, - 0x3E); + regmap_write(max98927->regmap, MAX98927_R0040_BOOST_CTRL0, 0x1C); + regmap_write(max98927->regmap, MAX98927_R0042_BOOST_CTRL1, 0x3E); /* Measurement ADC config */ - regmap_write(max98927->regmap, - MAX98927_R0043_MEAS_ADC_CFG, - 0x04); - regmap_write(max98927->regmap, - MAX98927_R0044_MEAS_ADC_BASE_MSB, - 0x00); - regmap_write(max98927->regmap, - MAX98927_R0045_MEAS_ADC_BASE_LSB, - 0x24); + regmap_write(max98927->regmap, MAX98927_R0043_MEAS_ADC_CFG, 0x04); + regmap_write(max98927->regmap, MAX98927_R0044_MEAS_ADC_BASE_MSB, 0x00); + regmap_write(max98927->regmap, MAX98927_R0045_MEAS_ADC_BASE_LSB, 0x24); /* Brownout Level */ - regmap_write(max98927->regmap, - MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1, - 0x06); + regmap_write(max98927->regmap, MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1, + 0x06); /* Envelope Tracking configuration */ - regmap_write(max98927->regmap, - MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM, - 0x08); - regmap_write(max98927->regmap, - MAX98927_R0086_ENV_TRACK_CTRL, - 0x01); - regmap_write(max98927->regmap, - MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ, - 0x10); + regmap_write(max98927->regmap, MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM, + 0x08); + regmap_write(max98927->regmap, MAX98927_R0086_ENV_TRACK_CTRL, 0x01); + regmap_write(max98927->regmap, MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ, + 0x10); /* voltage, current slot configuration */ - regmap_write(max98927->regmap, - MAX98927_R001E_PCM_TX_CH_SRC_A, - (max98927->i_l_slot<v_l_slot)&0xFF); + regmap_write(max98927->regmap, MAX98927_R001E_PCM_TX_CH_SRC_A, + (max98927->i_l_slot << MAX98927_PCM_TX_CH_SRC_A_I_SHIFT | max98927->v_l_slot) & 0xFF); if (max98927->v_l_slot < 8) { regmap_update_bits(max98927->regmap, - MAX98927_R001C_PCM_TX_HIZ_CTRL_A, - 1 << max98927->v_l_slot, 0); - regmap_update_bits(max98927->regmap, - MAX98927_R001A_PCM_TX_EN_A, - 1 << max98927->v_l_slot, - 1 << max98927->v_l_slot); + MAX98927_R001C_PCM_TX_HIZ_CTRL_A, + 1 << max98927->v_l_slot, 0); + regmap_update_bits(max98927->regmap, MAX98927_R001A_PCM_TX_EN_A, + 1 << max98927->v_l_slot, + 1 << max98927->v_l_slot); } else { regmap_update_bits(max98927->regmap, - MAX98927_R001D_PCM_TX_HIZ_CTRL_B, - 1 << (max98927->v_l_slot - 8), 0); - regmap_update_bits(max98927->regmap, - MAX98927_R001B_PCM_TX_EN_B, - 1 << (max98927->v_l_slot - 8), - 1 << (max98927->v_l_slot - 8)); + MAX98927_R001D_PCM_TX_HIZ_CTRL_B, + 1 << (max98927->v_l_slot - 8), 0); + regmap_update_bits(max98927->regmap, MAX98927_R001B_PCM_TX_EN_B, + 1 << (max98927->v_l_slot - 8), + 1 << (max98927->v_l_slot - 8)); } if (max98927->i_l_slot < 8) { regmap_update_bits(max98927->regmap, - MAX98927_R001C_PCM_TX_HIZ_CTRL_A, - 1 << max98927->i_l_slot, 0); - regmap_update_bits(max98927->regmap, - MAX98927_R001A_PCM_TX_EN_A, - 1 << max98927->i_l_slot, - 1 << max98927->i_l_slot); + MAX98927_R001C_PCM_TX_HIZ_CTRL_A, + 1 << max98927->i_l_slot, 0); + regmap_update_bits(max98927->regmap, MAX98927_R001A_PCM_TX_EN_A, + 1 << max98927->i_l_slot, + 1 << max98927->i_l_slot); } else { regmap_update_bits(max98927->regmap, - MAX98927_R001D_PCM_TX_HIZ_CTRL_B, - 1 << (max98927->i_l_slot - 8), 0); - regmap_update_bits(max98927->regmap, - MAX98927_R001B_PCM_TX_EN_B, - 1 << (max98927->i_l_slot - 8), - 1 << (max98927->i_l_slot - 8)); + MAX98927_R001D_PCM_TX_HIZ_CTRL_B, + 1 << (max98927->i_l_slot - 8), 0); + regmap_update_bits(max98927->regmap, MAX98927_R001B_PCM_TX_EN_B, + 1 << (max98927->i_l_slot - 8), + 1 << (max98927->i_l_slot - 8)); } /* Set interleave mode */ if (max98927->interleave_mode) regmap_update_bits(max98927->regmap, - MAX98927_R001F_PCM_TX_CH_SRC_B, - MAX98927_PCM_TX_CH_INTERLEAVE_MASK, - MAX98927_PCM_TX_CH_INTERLEAVE_MASK); + MAX98927_R001F_PCM_TX_CH_SRC_B, + MAX98927_PCM_TX_CH_INTERLEAVE_MASK, + MAX98927_PCM_TX_CH_INTERLEAVE_MASK); return 0; } @@ -809,8 +746,8 @@ static int max98927_resume(struct device *dev) { struct max98927_priv *max98927 = dev_get_drvdata(dev); - regmap_write(max98927->regmap, - MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET); + regmap_write(max98927->regmap, MAX98927_R0100_SOFT_RESET, + MAX98927_SOFT_RESET); regcache_cache_only(max98927->regmap, false); regcache_sync(max98927->regmap); return 0; @@ -869,9 +806,7 @@ static int max98927_i2c_probe(struct i2c_client *i2c) int reg = 0; struct max98927_priv *max98927 = NULL; - max98927 = devm_kzalloc(&i2c->dev, - sizeof(*max98927), GFP_KERNEL); - + max98927 = devm_kzalloc(&i2c->dev, sizeof(*max98927), GFP_KERNEL); if (!max98927) { ret = -ENOMEM; return ret; @@ -897,9 +832,9 @@ static int max98927_i2c_probe(struct i2c_client *i2c) "Failed to allocate regmap: %d\n", ret); return ret; } - - max98927->reset_gpio - = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_HIGH); + + max98927->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", + GPIOD_OUT_HIGH); if (IS_ERR(max98927->reset_gpio)) { ret = PTR_ERR(max98927->reset_gpio); return dev_err_probe(&i2c->dev, ret, "failed to request GPIO reset pin"); @@ -912,8 +847,7 @@ static int max98927_i2c_probe(struct i2c_client *i2c) } /* Check Revision ID */ - ret = regmap_read(max98927->regmap, - MAX98927_R01FF_REV_ID, ®); + ret = regmap_read(max98927->regmap, MAX98927_R01FF_REV_ID, ®); if (ret < 0) { dev_err(&i2c->dev, "Failed to read: 0x%02X\n", MAX98927_R01FF_REV_ID); @@ -938,9 +872,8 @@ static void max98927_i2c_remove(struct i2c_client *i2c) { struct max98927_priv *max98927 = i2c_get_clientdata(i2c); - if (max98927->reset_gpio) { + if (max98927->reset_gpio) gpiod_set_value_cansleep(max98927->reset_gpio, 1); - } } static const struct i2c_device_id max98927_i2c_id[] = { -- cgit v1.2.3 From 1ec6dffdedae4cbbd6e33b1d9be0e5a3dbb31804 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Jul 2023 12:14:21 +0100 Subject: ASoC: jz4740: 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 jz4740 driver to use the more modern data structure. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230712-asoc-jz-maple-v1-1-3f745adf96e5@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/jz4740.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index 7c25acf6ff0d..d1cea93bdb59 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -301,7 +301,7 @@ static const struct regmap_config jz4740_codec_regmap_config = { .reg_defaults = jz4740_codec_reg_defaults, .num_reg_defaults = ARRAY_SIZE(jz4740_codec_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int jz4740_codec_probe(struct platform_device *pdev) -- cgit v1.2.3 From 7f4ec77802aa17518990ed954bf536fd3bcf25cb Mon Sep 17 00:00:00 2001 From: Weidong Wang Date: Fri, 4 Aug 2023 19:47:48 +0800 Subject: ASoC: codecs: Add code for bin parsing compatible with aw88261 Add aw88261 compatible code to the aw88395_lib.c file so that it can parse aw88261's bin file. Signed-off-by: Weidong Wang Link: https://lore.kernel.org/r/20230804114749.215460-3-wangweidong.a@awinic.com Signed-off-by: Mark Brown --- sound/soc/codecs/aw88395/aw88395_lib.c | 193 ++++++++++++++++++++++++++++++--- sound/soc/codecs/aw88395/aw88395_reg.h | 1 + 2 files changed, 177 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/aw88395/aw88395_lib.c b/sound/soc/codecs/aw88395/aw88395_lib.c index 05bcf49da857..8ee1baa03269 100644 --- a/sound/soc/codecs/aw88395/aw88395_lib.c +++ b/sound/soc/codecs/aw88395/aw88395_lib.c @@ -11,6 +11,7 @@ #include #include "aw88395_lib.h" #include "aw88395_device.h" +#include "aw88395_reg.h" #define AW88395_CRC8_POLYNOMIAL 0x8C DECLARE_CRC8_TABLE(aw_crc8_table); @@ -429,6 +430,53 @@ parse_bin_failed: return ret; } +static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len, struct aw_prof_desc *prof_desc) +{ + struct aw_bin *aw_bin; + int ret; + + aw_bin = devm_kzalloc(aw_dev->dev, data_len + sizeof(*aw_bin), GFP_KERNEL); + if (!aw_bin) + return -ENOMEM; + + aw_bin->info.len = data_len; + memcpy(aw_bin->info.data, data, data_len); + + ret = aw_parsing_bin_file(aw_dev, aw_bin); + if (ret < 0) { + dev_err(aw_dev->dev, "parse bin failed"); + goto parse_bin_failed; + } + + if ((aw_bin->all_bin_parse_num != 1) || + (aw_bin->header_info[0].bin_data_type != DATA_TYPE_REGISTER)) { + dev_err(aw_dev->dev, "bin num or type error"); + goto parse_bin_failed; + } + + if (aw_bin->header_info[0].valid_data_len % 4) { + dev_err(aw_dev->dev, "bin data len get error!"); + goto parse_bin_failed; + } + + prof_desc->sec_desc[AW88395_DATA_TYPE_REG].data = + data + aw_bin->header_info[0].valid_data_addr; + prof_desc->sec_desc[AW88395_DATA_TYPE_REG].len = + aw_bin->header_info[0].valid_data_len; + prof_desc->prof_st = AW88395_PROFILE_OK; + + devm_kfree(aw_dev->dev, aw_bin); + aw_bin = NULL; + + return 0; + +parse_bin_failed: + devm_kfree(aw_dev->dev, aw_bin); + aw_bin = NULL; + return ret; +} + static int aw_dev_parse_data_by_sec_type(struct aw_device *aw_dev, struct aw_cfg_hdr *cfg_hdr, struct aw_cfg_dde *cfg_dde, struct aw_prof_desc *scene_prof_desc) { @@ -447,6 +495,9 @@ static int aw_dev_parse_data_by_sec_type(struct aw_device *aw_dev, struct aw_cfg return aw_dev_prof_parse_multi_bin( aw_dev, (u8 *)cfg_hdr + cfg_dde->data_offset, cfg_dde->data_size, scene_prof_desc); + case ACF_SEC_TYPE_HDR_REG: + return aw_dev_parse_reg_bin_with_hdr(aw_dev, (u8 *)cfg_hdr + cfg_dde->data_offset, + cfg_dde->data_size, scene_prof_desc); default: dev_err(aw_dev->dev, "%s cfg_dde->data_type = %d\n", __func__, cfg_dde->data_type); break; @@ -527,7 +578,49 @@ static int aw_dev_parse_dev_default_type(struct aw_device *aw_dev, return 0; } -static int aw_dev_cfg_get_valid_prof(struct aw_device *aw_dev, +static int aw88261_dev_cfg_get_valid_prof(struct aw_device *aw_dev, + struct aw_all_prof_info all_prof_info) +{ + struct aw_prof_desc *prof_desc = all_prof_info.prof_desc; + struct aw_prof_info *prof_info = &aw_dev->prof_info; + int num = 0; + int i; + + for (i = 0; i < AW88395_PROFILE_MAX; i++) { + if (prof_desc[i].prof_st == AW88395_PROFILE_OK) + prof_info->count++; + } + + dev_dbg(aw_dev->dev, "get valid profile:%d", aw_dev->prof_info.count); + + if (!prof_info->count) { + dev_err(aw_dev->dev, "no profile data"); + return -EPERM; + } + + prof_info->prof_desc = devm_kcalloc(aw_dev->dev, + prof_info->count, sizeof(struct aw_prof_desc), + GFP_KERNEL); + if (!prof_info->prof_desc) + return -ENOMEM; + + for (i = 0; i < AW88395_PROFILE_MAX; i++) { + if (prof_desc[i].prof_st == AW88395_PROFILE_OK) { + if (num >= prof_info->count) { + dev_err(aw_dev->dev, "overflow count[%d]", + prof_info->count); + return -EINVAL; + } + prof_info->prof_desc[num] = prof_desc[i]; + prof_info->prof_desc[num].id = i; + num++; + } + } + + return 0; +} + +static int aw88395_dev_cfg_get_valid_prof(struct aw_device *aw_dev, struct aw_all_prof_info all_prof_info) { struct aw_prof_desc *prof_desc = all_prof_info.prof_desc; @@ -606,9 +699,22 @@ static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev, goto exit; } - ret = aw_dev_cfg_get_valid_prof(aw_dev, *all_prof_info); - if (ret < 0) - goto exit; + switch (aw_dev->chip_id) { + case AW88395_CHIP_ID: + ret = aw88395_dev_cfg_get_valid_prof(aw_dev, *all_prof_info); + if (ret < 0) + goto exit; + break; + case AW88261_CHIP_ID: + ret = aw88261_dev_cfg_get_valid_prof(aw_dev, *all_prof_info); + if (ret < 0) + goto exit; + break; + default: + dev_err(aw_dev->dev, "valid prof unsupported"); + ret = -EINVAL; + break; + } aw_dev->prof_info.prof_name_list = profile_name; @@ -679,16 +785,37 @@ static int aw_get_dev_scene_count_v1(struct aw_device *aw_dev, struct aw_contain struct aw_cfg_dde_v1 *cfg_dde = (struct aw_cfg_dde_v1 *)(aw_cfg->data + cfg_hdr->hdr_offset); unsigned int i; + int ret; - for (i = 0; i < cfg_hdr->ddt_num; ++i) { - if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) && - (aw_dev->chip_id == cfg_dde[i].chip_id) && - (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && - (aw_dev->i2c->addr == cfg_dde[i].dev_addr)) - (*scene_num)++; + switch (aw_dev->chip_id) { + case AW88395_CHIP_ID: + for (i = 0; i < cfg_hdr->ddt_num; ++i) { + if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) && + (aw_dev->chip_id == cfg_dde[i].chip_id) && + (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && + (aw_dev->i2c->addr == cfg_dde[i].dev_addr)) + (*scene_num)++; + } + ret = 0; + break; + case AW88261_CHIP_ID: + for (i = 0; i < cfg_hdr->ddt_num; ++i) { + if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || + (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && + (aw_dev->chip_id == cfg_dde[i].chip_id) && + (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && + (aw_dev->i2c->addr == cfg_dde[i].dev_addr)) + (*scene_num)++; + } + ret = 0; + break; + default: + dev_err(aw_dev->dev, "unsupported device"); + ret = -EINVAL; + break; } - return 0; + return ret; } static int aw_get_default_scene_count_v1(struct aw_device *aw_dev, @@ -699,15 +826,35 @@ static int aw_get_default_scene_count_v1(struct aw_device *aw_dev, struct aw_cfg_dde_v1 *cfg_dde = (struct aw_cfg_dde_v1 *)(aw_cfg->data + cfg_hdr->hdr_offset); unsigned int i; + int ret; - for (i = 0; i < cfg_hdr->ddt_num; ++i) { - if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) && - (aw_dev->chip_id == cfg_dde[i].chip_id) && - (aw_dev->channel == cfg_dde[i].dev_index)) - (*scene_num)++; + switch (aw_dev->chip_id) { + case AW88395_CHIP_ID: + for (i = 0; i < cfg_hdr->ddt_num; ++i) { + if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) && + (aw_dev->chip_id == cfg_dde[i].chip_id) && + (aw_dev->channel == cfg_dde[i].dev_index)) + (*scene_num)++; + } + ret = 0; + break; + case AW88261_CHIP_ID: + for (i = 0; i < cfg_hdr->ddt_num; ++i) { + if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || + (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && + (aw_dev->chip_id == cfg_dde[i].chip_id) && + (aw_dev->channel == cfg_dde[i].dev_index)) + (*scene_num)++; + } + ret = 0; + break; + default: + dev_err(aw_dev->dev, "unsupported device"); + ret = -EINVAL; + break; } - return 0; + return ret; } static int aw_dev_parse_scene_count_v1(struct aw_device *aw_dev, @@ -756,6 +903,18 @@ static int aw_dev_parse_data_by_sec_type_v1(struct aw_device *aw_dev, prof_info->prof_desc[*cur_scene_id].id = cfg_dde->dev_profile; (*cur_scene_id)++; break; + case ACF_SEC_TYPE_HDR_REG: + ret = aw_dev_parse_reg_bin_with_hdr(aw_dev, + (uint8_t *)prof_hdr + cfg_dde->data_offset, + cfg_dde->data_size, &prof_info->prof_desc[*cur_scene_id]); + if (ret < 0) { + dev_err(aw_dev->dev, "parse reg bin with hdr failed"); + return ret; + } + prof_info->prof_desc[*cur_scene_id].prf_str = cfg_dde->dev_profile_str; + prof_info->prof_desc[*cur_scene_id].id = cfg_dde->dev_profile; + (*cur_scene_id)++; + break; default: dev_err(aw_dev->dev, "unsupported SEC_TYPE [%d]", cfg_dde->data_type); return -EINVAL; diff --git a/sound/soc/codecs/aw88395/aw88395_reg.h b/sound/soc/codecs/aw88395/aw88395_reg.h index e64f24e97150..e7a7c02efaf3 100644 --- a/sound/soc/codecs/aw88395/aw88395_reg.h +++ b/sound/soc/codecs/aw88395/aw88395_reg.h @@ -96,6 +96,7 @@ enum aw88395_id { AW88395_CHIP_ID = 0x2049, + AW88261_CHIP_ID = 0x2113, }; #define AW88395_REG_MAX (0x7D) -- cgit v1.2.3 From 028a2ae256916eeae1040049d2d0129535ace60e Mon Sep 17 00:00:00 2001 From: Weidong Wang Date: Fri, 4 Aug 2023 19:47:49 +0800 Subject: ASoC: codecs: Add aw88261 amplifier driver Add i2c and amplifier registration for aw88261 and their associated operation functions. Signed-off-by: Weidong Wang Link: https://lore.kernel.org/r/20230804114749.215460-4-wangweidong.a@awinic.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 15 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/aw88261.c | 1298 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/aw88261.h | 459 ++++++++++++++++ 4 files changed, 1774 insertions(+) create mode 100644 sound/soc/codecs/aw88261.c create mode 100644 sound/soc/codecs/aw88261.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8aba442d1978..ef279a27eb51 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -56,6 +56,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_AUDIO_IIO_AUX imply SND_SOC_AW8738 imply SND_SOC_AW88395 + imply SND_SOC_AW88261 imply SND_SOC_BT_SCO imply SND_SOC_BD28623 imply SND_SOC_CHV3_CODEC @@ -653,6 +654,20 @@ config SND_SOC_AW88395 digital Smart K audio amplifier with an integrated 10V smart boost convert. +config SND_SOC_AW88261 + tristate "Soc Audio for awinic aw88261" + depends on I2C + select CRC8 + select REGMAP_I2C + select GPIOLIB + select SND_SOC_AW88395_LIB + help + This option enables support for aw88261 Smart PA. + The awinic AW88261 is an I2S/TDM input, high efficiency + digital Smart K audio amplifier. The output voltage of + boost converter can be adjusted smartly according to + the input amplitude. + config SND_SOC_BD28623 tristate "ROHM BD28623 CODEC" help diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index be367839cfa4..2bdc0ef29a9e 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -50,6 +50,7 @@ snd-soc-aw8738-objs := aw8738.o snd-soc-aw88395-lib-objs := aw88395/aw88395_lib.o snd-soc-aw88395-objs := aw88395/aw88395.o \ aw88395/aw88395_device.o +snd-soc-aw88261-objs := aw88261.o snd-soc-bd28623-objs := bd28623.o snd-soc-bt-sco-objs := bt-sco.o snd-soc-chv3-codec-objs := chv3-codec.o @@ -434,6 +435,7 @@ 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 +obj-$(CONFIG_SND_SOC_AW88261) +=snd-soc-aw88261.o obj-$(CONFIG_SND_SOC_BD28623) += snd-soc-bd28623.o obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o obj-$(CONFIG_SND_SOC_CHV3_CODEC) += snd-soc-chv3-codec.o diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c new file mode 100644 index 000000000000..82923b454dd4 --- /dev/null +++ b/sound/soc/codecs/aw88261.c @@ -0,0 +1,1298 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// aw88261.c -- AW88261 ALSA SoC Audio driver +// +// Copyright (c) 2023 awinic Technology CO., LTD +// +// Author: Jimmy Zhang +// Author: Weidong Wang +// + +#include +#include +#include +#include +#include +#include "aw88261.h" +#include "aw88395/aw88395_data_type.h" +#include "aw88395/aw88395_device.h" + +static const struct regmap_config aw88261_remap_config = { + .val_bits = 16, + .reg_bits = 8, + .max_register = AW88261_REG_MAX - 1, + .reg_format_endian = REGMAP_ENDIAN_LITTLE, + .val_format_endian = REGMAP_ENDIAN_BIG, +}; + +static void aw88261_dev_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + unsigned int real_value, volume; + unsigned int reg_value; + + volume = min((value + vol_desc->init_volume), (unsigned int)AW88261_MUTE_VOL); + real_value = DB_TO_REG_VAL(volume); + + regmap_read(aw_dev->regmap, AW88261_SYSCTRL2_REG, ®_value); + + real_value = (real_value | (reg_value & AW88261_VOL_START_MASK)); + + dev_dbg(aw_dev->dev, "value 0x%x , real_value:0x%x", value, real_value); + + regmap_write(aw_dev->regmap, AW88261_SYSCTRL2_REG, real_value); +} + +static void aw88261_dev_fade_in(struct aw_device *aw_dev) +{ + struct aw_volume_desc *desc = &aw_dev->volume_desc; + int fade_in_vol = desc->ctl_volume; + int fade_step = aw_dev->fade_step; + int i; + + if (fade_step == 0 || aw_dev->fade_in_time == 0) { + aw88261_dev_set_volume(aw_dev, fade_in_vol); + return; + } + + for (i = AW88261_MUTE_VOL; i >= fade_in_vol; i -= fade_step) { + aw88261_dev_set_volume(aw_dev, i); + usleep_range(aw_dev->fade_in_time, + aw_dev->fade_in_time + 10); + } + + if (i != fade_in_vol) + aw88261_dev_set_volume(aw_dev, fade_in_vol); +} + +static void aw88261_dev_fade_out(struct aw_device *aw_dev) +{ + struct aw_volume_desc *desc = &aw_dev->volume_desc; + int fade_step = aw_dev->fade_step; + int i; + + if (fade_step == 0 || aw_dev->fade_out_time == 0) { + aw88261_dev_set_volume(aw_dev, AW88261_MUTE_VOL); + return; + } + + for (i = desc->ctl_volume; i <= AW88261_MUTE_VOL; i += fade_step) { + aw88261_dev_set_volume(aw_dev, i); + usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); + } + + if (i != AW88261_MUTE_VOL) { + aw88261_dev_set_volume(aw_dev, AW88261_MUTE_VOL); + usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); + } +} + +static void aw88261_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag) +{ + if (flag) + regmap_update_bits(aw_dev->regmap, AW88261_I2SCFG1_REG, + ~AW88261_I2STXEN_MASK, AW88261_I2STXEN_ENABLE_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88261_I2SCFG1_REG, + ~AW88261_I2STXEN_MASK, AW88261_I2STXEN_DISABLE_VALUE); +} + +static void aw88261_dev_pwd(struct aw_device *aw_dev, bool pwd) +{ + if (pwd) + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_PWDN_MASK, AW88261_PWDN_POWER_DOWN_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_PWDN_MASK, AW88261_PWDN_WORKING_VALUE); +} + +static void aw88261_dev_amppd(struct aw_device *aw_dev, bool amppd) +{ + if (amppd) + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_AMPPD_MASK, AW88261_AMPPD_POWER_DOWN_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_AMPPD_MASK, AW88261_AMPPD_WORKING_VALUE); +} + +static void aw88261_dev_mute(struct aw_device *aw_dev, bool is_mute) +{ + if (is_mute) { + aw88261_dev_fade_out(aw_dev); + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_HMUTE_MASK, AW88261_HMUTE_ENABLE_VALUE); + } else { + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_HMUTE_MASK, AW88261_HMUTE_DISABLE_VALUE); + aw88261_dev_fade_in(aw_dev); + } +} + +static void aw88261_dev_clear_int_status(struct aw_device *aw_dev) +{ + unsigned int int_status; + + /* read int status and clear */ + regmap_read(aw_dev->regmap, AW88261_SYSINT_REG, &int_status); + /* make sure int status is clear */ + regmap_read(aw_dev->regmap, AW88261_SYSINT_REG, &int_status); + + dev_dbg(aw_dev->dev, "read interrupt reg = 0x%04x", int_status); +} + +static int aw88261_dev_get_iis_status(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88261_SYSST_REG, ®_val); + if (ret) + return ret; + if ((reg_val & AW88261_BIT_PLL_CHECK) != AW88261_BIT_PLL_CHECK) { + dev_err(aw_dev->dev, "check pll lock fail,reg_val:0x%04x", reg_val); + return -EINVAL; + } + + return ret; +} + +static int aw88261_dev_check_mode1_pll(struct aw_device *aw_dev) +{ + int ret, i; + + for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) { + ret = aw88261_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode1 iis signal check error"); + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + } else { + return ret; + } + } + + return -EPERM; +} + +static int aw88261_dev_check_mode2_pll(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret, i; + + ret = regmap_read(aw_dev->regmap, AW88261_PLLCTRL1_REG, ®_val); + if (ret) + return ret; + + reg_val &= (~AW88261_CCO_MUX_MASK); + if (reg_val == AW88261_CCO_MUX_DIVIDED_VALUE) { + dev_dbg(aw_dev->dev, "CCO_MUX is already divider"); + return -EPERM; + } + + /* change mode2 */ + ret = regmap_update_bits(aw_dev->regmap, AW88261_PLLCTRL1_REG, + ~AW88261_CCO_MUX_MASK, AW88261_CCO_MUX_DIVIDED_VALUE); + if (ret) + return ret; + + for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) { + ret = aw88261_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 iis signal check error"); + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + } else { + break; + } + } + + /* change mode1 */ + ret = regmap_update_bits(aw_dev->regmap, AW88261_PLLCTRL1_REG, + ~AW88261_CCO_MUX_MASK, AW88261_CCO_MUX_BYPASS_VALUE); + if (ret == 0) { + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) { + ret = aw88261_dev_check_mode1_pll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error"); + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + } else { + break; + } + } + } + + return ret; +} + +static int aw88261_dev_check_syspll(struct aw_device *aw_dev) +{ + int ret; + + ret = aw88261_dev_check_mode1_pll(aw_dev); + if (ret) { + dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check"); + ret = aw88261_dev_check_mode2_pll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 check iis failed"); + return ret; + } + } + + return ret; +} + +static int aw88261_dev_check_sysst(struct aw_device *aw_dev) +{ + unsigned int check_val; + unsigned int reg_val; + int ret, i; + + for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) { + ret = regmap_read(aw_dev->regmap, AW88261_SYSST_REG, ®_val); + if (ret) + return ret; + + check_val = reg_val & (~AW88261_BIT_SYSST_CHECK_MASK) + & AW88261_BIT_SYSST_CHECK; + if (check_val != AW88261_BIT_SYSST_CHECK) { + dev_err(aw_dev->dev, "check sysst fail, reg_val=0x%04x, check:0x%x", + reg_val, AW88261_BIT_SYSST_CHECK); + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + } else { + return 0; + } + } + + return -EPERM; +} + +static void aw88261_dev_uls_hmute(struct aw_device *aw_dev, bool uls_hmute) +{ + if (uls_hmute) + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_ULS_HMUTE_MASK, + AW88261_ULS_HMUTE_ENABLE_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_ULS_HMUTE_MASK, + AW88261_ULS_HMUTE_DISABLE_VALUE); +} + +static void aw88261_reg_force_set(struct aw88261 *aw88261) +{ + if (aw88261->frcset_en == AW88261_FRCSET_ENABLE) { + /* set FORCE_PWM */ + regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL3_REG, + AW88261_FORCE_PWM_MASK, AW88261_FORCE_PWM_FORCEMINUS_PWM_VALUE); + /* set BOOST_OS_WIDTH */ + regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL5_REG, + AW88261_BST_OS_WIDTH_MASK, AW88261_BST_OS_WIDTH_50NS_VALUE); + /* set BURST_LOOPR */ + regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL6_REG, + AW88261_BST_LOOPR_MASK, AW88261_BST_LOOPR_340K_VALUE); + /* set RSQN_DLY */ + regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL7_REG, + AW88261_RSQN_DLY_MASK, AW88261_RSQN_DLY_35NS_VALUE); + /* set BURST_SSMODE */ + regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL8_REG, + AW88261_BURST_SSMODE_MASK, AW88261_BURST_SSMODE_FAST_VALUE); + /* set BST_BURST */ + regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL9_REG, + AW88261_BST_BURST_MASK, AW88261_BST_BURST_30MA_VALUE); + } else { + dev_dbg(aw88261->aw_pa->dev, "needn't set reg value"); + } +} + +static int aw88261_dev_get_icalk(struct aw_device *aw_dev, int16_t *icalk) +{ + u16 reg_icalk, reg_icalkl; + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88261_EFRH4_REG, ®_val); + if (ret) + return ret; + + reg_icalk = reg_val & (~AW88261_EF_ISN_GESLP_H_MASK); + + ret = regmap_read(aw_dev->regmap, AW88261_EFRL4_REG, ®_val); + if (ret) + return ret; + + reg_icalkl = reg_val & (~AW88261_EF_ISN_GESLP_L_MASK); + + reg_icalk = (reg_icalk >> AW88261_ICALK_SHIFT) & (reg_icalkl >> AW88261_ICALKL_SHIFT); + + if (reg_icalk & (~AW88261_EF_ISN_GESLP_SIGN_MASK)) + reg_icalk = reg_icalk | ~AW88261_EF_ISN_GESLP_NEG; + + *icalk = (int16_t)reg_icalk; + + return ret; +} + +static int aw88261_dev_get_vcalk(struct aw_device *aw_dev, int16_t *vcalk) +{ + u16 reg_vcalk, reg_vcalkl; + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88261_EFRH3_REG, ®_val); + if (ret) + return ret; + + reg_vcalk = (u16)reg_val & (~AW88261_EF_VSN_GESLP_H_MASK); + + ret = regmap_read(aw_dev->regmap, AW88261_EFRL3_REG, ®_val); + if (ret) + return ret; + + reg_vcalkl = (u16)reg_val & (~AW88261_EF_VSN_GESLP_L_MASK); + + reg_vcalk = (reg_vcalk >> AW88261_VCALK_SHIFT) & (reg_vcalkl >> AW88261_VCALKL_SHIFT); + + if (reg_vcalk & AW88261_EF_VSN_GESLP_SIGN_MASK) + reg_vcalk = reg_vcalk | (~AW88261_EF_VSN_GESLP_NEG); + *vcalk = (int16_t)reg_vcalk; + + return ret; +} + +static int aw88261_dev_set_vcalb(struct aw_device *aw_dev) +{ + int16_t icalk_val, vcalk_val; + int icalk, vcalk, vcalb; + u32 reg_val; + int ret; + + ret = aw88261_dev_get_icalk(aw_dev, &icalk_val); + if (ret) + return ret; + + ret = aw88261_dev_get_vcalk(aw_dev, &vcalk_val); + if (ret) + return ret; + + icalk = AW88261_CABL_BASE_VALUE + AW88261_ICABLK_FACTOR * icalk_val; + vcalk = AW88261_CABL_BASE_VALUE + AW88261_VCABLK_FACTOR * vcalk_val; + if (!vcalk) + return -EINVAL; + + vcalb = AW88261_VCAL_FACTOR * icalk / vcalk; + reg_val = (unsigned int)vcalb; + + dev_dbg(aw_dev->dev, "icalk=%d, vcalk=%d, vcalb=%d, reg_val=0x%04x", + icalk, vcalk, vcalb, reg_val); + ret = regmap_write(aw_dev->regmap, AW88261_VSNTM1_REG, reg_val); + + return ret; +} + +static int aw88261_dev_reg_update(struct aw88261 *aw88261, + unsigned char *data, unsigned int len) +{ + struct aw_device *aw_dev = aw88261->aw_pa; + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + unsigned int read_val, efcheck_val, read_vol; + int data_len, i, ret; + int16_t *reg_data; + u16 reg_val; + u8 reg_addr; + + if (!len || !data) { + dev_err(aw_dev->dev, "reg data is null or len is 0"); + return -EINVAL; + } + + reg_data = (int16_t *)data; + data_len = len >> 1; + + if (data_len & 0x1) { + dev_err(aw_dev->dev, "data len:%d unsupported", data_len); + return -EINVAL; + } + + for (i = 0; i < data_len; i += 2) { + reg_addr = reg_data[i]; + reg_val = reg_data[i + 1]; + + if (reg_addr == AW88261_SYSCTRL_REG) { + aw88261->amppd_st = reg_val & (~AW88261_AMPPD_MASK); + ret = regmap_read(aw_dev->regmap, reg_addr, &read_val); + if (ret) + break; + + read_val &= (~AW88261_AMPPD_MASK) | (~AW88261_PWDN_MASK) | + (~AW88261_HMUTE_MASK); + reg_val &= (AW88261_AMPPD_MASK | AW88261_PWDN_MASK | AW88261_HMUTE_MASK); + reg_val |= read_val; + + /* enable uls hmute */ + reg_val &= AW88261_ULS_HMUTE_MASK; + reg_val |= AW88261_ULS_HMUTE_ENABLE_VALUE; + } + + if (reg_addr == AW88261_DBGCTRL_REG) { + efcheck_val = reg_val & (~AW88261_EF_DBMD_MASK); + if (efcheck_val == AW88261_OR_VALUE) + aw88261->efuse_check = AW88261_EF_OR_CHECK; + else + aw88261->efuse_check = AW88261_EF_AND_CHECK; + } + + /* i2stxen */ + if (reg_addr == AW88261_I2SCTRL3_REG) { + /* close tx */ + reg_val &= AW88261_I2STXEN_MASK; + reg_val |= AW88261_I2STXEN_DISABLE_VALUE; + } + + if (reg_addr == AW88261_SYSCTRL2_REG) { + read_vol = (reg_val & (~AW88261_VOL_MASK)) >> + AW88261_VOL_START_BIT; + aw_dev->volume_desc.init_volume = + REG_VAL_TO_DB(read_vol); + } + + if (reg_addr == AW88261_VSNTM1_REG) + continue; + + ret = regmap_write(aw_dev->regmap, reg_addr, reg_val); + if (ret) + break; + } + + ret = aw88261_dev_set_vcalb(aw_dev); + if (ret) + return ret; + + if (aw_dev->prof_cur != aw_dev->prof_index) + vol_desc->ctl_volume = 0; + + /* keep min volume */ + aw88261_dev_set_volume(aw_dev, vol_desc->mute_volume); + + return ret; +} + +static char *aw88261_dev_get_prof_name(struct aw_device *aw_dev, int index) +{ + struct aw_prof_info *prof_info = &aw_dev->prof_info; + struct aw_prof_desc *prof_desc; + + if ((index >= aw_dev->prof_info.count) || (index < 0)) { + dev_err(aw_dev->dev, "index[%d] overflow count[%d]", + index, aw_dev->prof_info.count); + return NULL; + } + + prof_desc = &aw_dev->prof_info.prof_desc[index]; + + return prof_info->prof_name_list[prof_desc->id]; +} + +static int aw88261_dev_get_prof_data(struct aw_device *aw_dev, int index, + struct aw_prof_desc **prof_desc) +{ + if ((index >= aw_dev->prof_info.count) || (index < 0)) { + dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n", + __func__, index, aw_dev->prof_info.count); + return -EINVAL; + } + + *prof_desc = &aw_dev->prof_info.prof_desc[index]; + + return 0; +} + +static int aw88261_dev_fw_update(struct aw88261 *aw88261) +{ + struct aw_device *aw_dev = aw88261->aw_pa; + struct aw_prof_desc *prof_index_desc; + struct aw_sec_data_desc *sec_desc; + char *prof_name; + int ret; + + prof_name = aw88261_dev_get_prof_name(aw_dev, aw_dev->prof_index); + if (!prof_name) { + dev_err(aw_dev->dev, "get prof name failed"); + return -EINVAL; + } + + dev_dbg(aw_dev->dev, "start update %s", prof_name); + + ret = aw88261_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc); + if (ret) + return ret; + + /* update reg */ + sec_desc = prof_index_desc->sec_desc; + ret = aw88261_dev_reg_update(aw88261, sec_desc[AW88395_DATA_TYPE_REG].data, + sec_desc[AW88395_DATA_TYPE_REG].len); + if (ret) { + dev_err(aw_dev->dev, "update reg failed"); + return ret; + } + + aw_dev->prof_cur = aw_dev->prof_index; + + return ret; +} + +static int aw88261_dev_start(struct aw88261 *aw88261) +{ + struct aw_device *aw_dev = aw88261->aw_pa; + int ret; + + if (aw_dev->status == AW88261_DEV_PW_ON) { + dev_info(aw_dev->dev, "already power on"); + return 0; + } + + /* power on */ + aw88261_dev_pwd(aw_dev, false); + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + + ret = aw88261_dev_check_syspll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "pll check failed cannot start"); + goto pll_check_fail; + } + + /* amppd on */ + aw88261_dev_amppd(aw_dev, false); + usleep_range(AW88261_1000_US, AW88261_1000_US + 50); + + /* check i2s status */ + ret = aw88261_dev_check_sysst(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "sysst check failed"); + goto sysst_check_fail; + } + + /* enable tx feedback */ + aw88261_dev_i2s_tx_enable(aw_dev, true); + + if (aw88261->amppd_st) + aw88261_dev_amppd(aw_dev, true); + + aw88261_reg_force_set(aw88261); + + /* close uls mute */ + aw88261_dev_uls_hmute(aw_dev, false); + + /* close mute */ + if (!aw88261->mute_st) + aw88261_dev_mute(aw_dev, false); + + /* clear inturrupt */ + aw88261_dev_clear_int_status(aw_dev); + aw_dev->status = AW88261_DEV_PW_ON; + + return 0; + +sysst_check_fail: + aw88261_dev_i2s_tx_enable(aw_dev, false); + aw88261_dev_clear_int_status(aw_dev); + aw88261_dev_amppd(aw_dev, true); +pll_check_fail: + aw88261_dev_pwd(aw_dev, true); + aw_dev->status = AW88261_DEV_PW_OFF; + + return ret; +} + +static int aw88261_dev_stop(struct aw_device *aw_dev) +{ + if (aw_dev->status == AW88261_DEV_PW_OFF) { + dev_info(aw_dev->dev, "already power off"); + return 0; + } + + aw_dev->status = AW88261_DEV_PW_OFF; + + /* clear inturrupt */ + aw88261_dev_clear_int_status(aw_dev); + + aw88261_dev_uls_hmute(aw_dev, true); + /* set mute */ + aw88261_dev_mute(aw_dev, true); + + /* close tx feedback */ + aw88261_dev_i2s_tx_enable(aw_dev, false); + usleep_range(AW88261_1000_US, AW88261_1000_US + 100); + + /* enable amppd */ + aw88261_dev_amppd(aw_dev, true); + + /* set power down */ + aw88261_dev_pwd(aw_dev, true); + + return 0; +} + +static int aw88261_reg_update(struct aw88261 *aw88261, bool force) +{ + struct aw_device *aw_dev = aw88261->aw_pa; + int ret; + + if (force) { + ret = regmap_write(aw_dev->regmap, + AW88261_ID_REG, AW88261_SOFT_RESET_VALUE); + if (ret) + return ret; + + ret = aw88261_dev_fw_update(aw88261); + if (ret) + return ret; + } else { + if (aw_dev->prof_cur != aw_dev->prof_index) { + ret = aw88261_dev_fw_update(aw88261); + if (ret) + return ret; + } + } + + aw_dev->prof_cur = aw_dev->prof_index; + + return ret; +} + +static void aw88261_start_pa(struct aw88261 *aw88261) +{ + int ret, i; + + for (i = 0; i < AW88261_START_RETRIES; i++) { + ret = aw88261_reg_update(aw88261, aw88261->phase_sync); + if (ret) { + dev_err(aw88261->aw_pa->dev, "fw update failed, cnt:%d\n", i); + continue; + } + ret = aw88261_dev_start(aw88261); + if (ret) { + dev_err(aw88261->aw_pa->dev, "aw88261 device start failed. retry = %d", i); + continue; + } else { + dev_info(aw88261->aw_pa->dev, "start success\n"); + break; + } + } +} + +static void aw88261_startup_work(struct work_struct *work) +{ + struct aw88261 *aw88261 = + container_of(work, struct aw88261, start_work.work); + + mutex_lock(&aw88261->lock); + aw88261_start_pa(aw88261); + mutex_unlock(&aw88261->lock); +} + +static void aw88261_start(struct aw88261 *aw88261, bool sync_start) +{ + if (aw88261->aw_pa->fw_status != AW88261_DEV_FW_OK) + return; + + if (aw88261->aw_pa->status == AW88261_DEV_PW_ON) + return; + + if (sync_start == AW88261_SYNC_START) + aw88261_start_pa(aw88261); + else + queue_delayed_work(system_wq, + &aw88261->start_work, + AW88261_START_WORK_DELAY_MS); +} + +static struct snd_soc_dai_driver aw88261_dai[] = { + { + .name = "aw88261-aif", + .id = 1, + .playback = { + .stream_name = "Speaker_Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AW88261_RATES, + .formats = AW88261_FORMATS, + }, + .capture = { + .stream_name = "Speaker_Capture", + .channels_min = 1, + .channels_max = 2, + .rates = AW88261_RATES, + .formats = AW88261_FORMATS, + }, + }, +}; + +static int aw88261_get_fade_in_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + struct aw_device *aw_dev = aw88261->aw_pa; + + ucontrol->value.integer.value[0] = aw_dev->fade_in_time; + + return 0; +} + +static int aw88261_set_fade_in_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct aw_device *aw_dev = aw88261->aw_pa; + int time; + + time = ucontrol->value.integer.value[0]; + + if (time < mc->min || time > mc->max) + return -EINVAL; + + if (time != aw_dev->fade_in_time) { + aw_dev->fade_in_time = time; + return 1; + } + + return 0; +} + +static int aw88261_get_fade_out_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + struct aw_device *aw_dev = aw88261->aw_pa; + + ucontrol->value.integer.value[0] = aw_dev->fade_out_time; + + return 0; +} + +static int aw88261_set_fade_out_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct aw_device *aw_dev = aw88261->aw_pa; + int time; + + time = ucontrol->value.integer.value[0]; + if (time < mc->min || time > mc->max) + return -EINVAL; + + if (time != aw_dev->fade_out_time) { + aw_dev->fade_out_time = time; + return 1; + } + + return 0; +} + +static int aw88261_dev_set_profile_index(struct aw_device *aw_dev, int index) +{ + /* check the index whether is valid */ + if ((index >= aw_dev->prof_info.count) || (index < 0)) + return -EINVAL; + /* check the index whether change */ + if (aw_dev->prof_index == index) + return -EPERM; + + aw_dev->prof_index = index; + + return 0; +} + +static int aw88261_profile_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + const char *prof_name; + char *name; + int count; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + + count = aw88261->aw_pa->prof_info.count; + if (count <= 0) { + uinfo->value.enumerated.items = 0; + return 0; + } + + uinfo->value.enumerated.items = count; + + if (uinfo->value.enumerated.item >= count) + uinfo->value.enumerated.item = count - 1; + + name = uinfo->value.enumerated.name; + count = uinfo->value.enumerated.item; + + prof_name = aw88261_dev_get_prof_name(aw88261->aw_pa, count); + if (!prof_name) { + strscpy(uinfo->value.enumerated.name, "null", + strlen("null") + 1); + return 0; + } + + strscpy(name, prof_name, sizeof(uinfo->value.enumerated.name)); + + return 0; +} + +static int aw88261_profile_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw88261->aw_pa->prof_index; + + return 0; +} + +static int aw88261_profile_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + int ret; + + /* pa stop or stopping just set profile */ + mutex_lock(&aw88261->lock); + ret = aw88261_dev_set_profile_index(aw88261->aw_pa, ucontrol->value.integer.value[0]); + if (ret) { + dev_dbg(codec->dev, "profile index does not change"); + mutex_unlock(&aw88261->lock); + return 0; + } + + if (aw88261->aw_pa->status) { + aw88261_dev_stop(aw88261->aw_pa); + aw88261_start(aw88261, AW88261_SYNC_START); + } + + mutex_unlock(&aw88261->lock); + + return 1; +} + +static int aw88261_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + struct aw_volume_desc *vol_desc = &aw88261->aw_pa->volume_desc; + + ucontrol->value.integer.value[0] = vol_desc->ctl_volume; + + return 0; +} + +static int aw88261_volume_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + struct aw_volume_desc *vol_desc = &aw88261->aw_pa->volume_desc; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int value; + + value = ucontrol->value.integer.value[0]; + + if (value < mc->min || value > mc->max) + return -EINVAL; + + if (vol_desc->ctl_volume != value) { + vol_desc->ctl_volume = value; + aw88261_dev_set_volume(aw88261->aw_pa, vol_desc->ctl_volume); + + return 1; + } + + return 0; +} + +static int aw88261_get_fade_step(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw88261->aw_pa->fade_step; + + return 0; +} + +static int aw88261_set_fade_step(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int value; + + value = ucontrol->value.integer.value[0]; + if (value < mc->min || value > mc->max) + return -EINVAL; + + if (aw88261->aw_pa->fade_step != value) { + aw88261->aw_pa->fade_step = value; + return 1; + } + + return 0; +} + +static const struct snd_kcontrol_new aw88261_controls[] = { + SOC_SINGLE_EXT("PCM Playback Volume", AW88261_SYSCTRL2_REG, + 6, AW88261_MUTE_VOL, 0, aw88261_volume_get, + aw88261_volume_set), + SOC_SINGLE_EXT("Fade Step", 0, 0, AW88261_MUTE_VOL, 0, + aw88261_get_fade_step, aw88261_set_fade_step), + SOC_SINGLE_EXT("Volume Ramp Up Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN, + aw88261_get_fade_in_time, aw88261_set_fade_in_time), + SOC_SINGLE_EXT("Volume Ramp Down Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN, + aw88261_get_fade_out_time, aw88261_set_fade_out_time), + AW88261_PROFILE_EXT("Profile Set", aw88261_profile_info, + aw88261_profile_get, aw88261_profile_set), +}; + +static int aw88261_playback_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + + mutex_lock(&aw88261->lock); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + aw88261_start(aw88261, AW88261_ASYNC_START); + break; + case SND_SOC_DAPM_POST_PMD: + aw88261_dev_stop(aw88261->aw_pa); + break; + default: + break; + } + mutex_unlock(&aw88261->lock); + + return 0; +} + +static const struct snd_soc_dapm_widget aw88261_dapm_widgets[] = { + /* playback */ + SND_SOC_DAPM_AIF_IN_E("AIF_RX", "Speaker_Playback", 0, 0, 0, 0, + aw88261_playback_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_OUTPUT("DAC Output"), + + /* capture */ + SND_SOC_DAPM_AIF_OUT("AIF_TX", "Speaker_Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_INPUT("ADC Input"), +}; + +static const struct snd_soc_dapm_route aw88261_audio_map[] = { + {"DAC Output", NULL, "AIF_RX"}, + {"AIF_TX", NULL, "ADC Input"}, +}; + +static int aw88261_frcset_check(struct aw88261 *aw88261) +{ + unsigned int reg_val; + u16 temh, teml, tem; + int ret; + + ret = regmap_read(aw88261->regmap, AW88261_EFRH3_REG, ®_val); + if (ret) + return ret; + temh = ((u16)reg_val & (~AW88261_TEMH_MASK)); + + ret = regmap_read(aw88261->regmap, AW88261_EFRL3_REG, ®_val); + if (ret) + return ret; + teml = ((u16)reg_val & (~AW88261_TEML_MASK)); + + if (aw88261->efuse_check == AW88261_EF_OR_CHECK) + tem = (temh | teml); + else + tem = (temh & teml); + + if (tem == AW88261_DEFAULT_CFG) + aw88261->frcset_en = AW88261_FRCSET_ENABLE; + else + aw88261->frcset_en = AW88261_FRCSET_DISABLE; + + dev_dbg(aw88261->aw_pa->dev, "tem is 0x%04x, frcset_en is %d", + tem, aw88261->frcset_en); + + return ret; +} + +static int aw88261_dev_init(struct aw88261 *aw88261, struct aw_container *aw_cfg) +{ + struct aw_device *aw_dev = aw88261->aw_pa; + int ret; + + ret = aw88395_dev_cfg_load(aw_dev, aw_cfg); + if (ret) { + dev_err(aw_dev->dev, "aw_dev acf parse failed"); + return -EINVAL; + } + + ret = regmap_write(aw_dev->regmap, AW88261_ID_REG, AW88261_SOFT_RESET_VALUE); + if (ret) + return ret; + + aw_dev->fade_in_time = AW88261_500_US; + aw_dev->fade_out_time = AW88261_500_US; + aw_dev->prof_cur = AW88261_INIT_PROFILE; + aw_dev->prof_index = AW88261_INIT_PROFILE; + + ret = aw88261_dev_fw_update(aw88261); + if (ret) { + dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret); + return ret; + } + + ret = aw88261_frcset_check(aw88261); + if (ret) { + dev_err(aw_dev->dev, "aw88261_frcset_check ret = %d\n", ret); + return ret; + } + + aw88261_dev_clear_int_status(aw_dev); + + aw88261_dev_uls_hmute(aw_dev, true); + + aw88261_dev_mute(aw_dev, true); + + aw88261_dev_i2s_tx_enable(aw_dev, false); + + usleep_range(AW88261_1000_US, AW88261_1000_US + 100); + + aw88261_dev_amppd(aw_dev, true); + + aw88261_dev_pwd(aw_dev, true); + + return 0; +} + +static int aw88261_request_firmware_file(struct aw88261 *aw88261) +{ + const struct firmware *cont = NULL; + int ret; + + aw88261->aw_pa->fw_status = AW88261_DEV_FW_FAILED; + + ret = request_firmware(&cont, AW88261_ACF_FILE, aw88261->aw_pa->dev); + if (ret) + return dev_err_probe(aw88261->aw_pa->dev, ret, + "load [%s] failed!", AW88261_ACF_FILE); + + dev_info(aw88261->aw_pa->dev, "loaded %s - size: %zu\n", + AW88261_ACF_FILE, cont ? cont->size : 0); + + aw88261->aw_cfg = devm_kzalloc(aw88261->aw_pa->dev, cont->size + sizeof(int), GFP_KERNEL); + if (!aw88261->aw_cfg) { + release_firmware(cont); + return -ENOMEM; + } + aw88261->aw_cfg->len = (int)cont->size; + memcpy(aw88261->aw_cfg->data, cont->data, cont->size); + release_firmware(cont); + + ret = aw88395_dev_load_acf_check(aw88261->aw_pa, aw88261->aw_cfg); + if (ret) { + dev_err(aw88261->aw_pa->dev, "load [%s] failed !", AW88261_ACF_FILE); + return ret; + } + + mutex_lock(&aw88261->lock); + /* aw device init */ + ret = aw88261_dev_init(aw88261, aw88261->aw_cfg); + if (ret) + dev_err(aw88261->aw_pa->dev, "dev init failed"); + mutex_unlock(&aw88261->lock); + + return ret; +} + +static int aw88261_codec_probe(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + int ret; + + INIT_DELAYED_WORK(&aw88261->start_work, aw88261_startup_work); + + ret = aw88261_request_firmware_file(aw88261); + if (ret) + return dev_err_probe(aw88261->aw_pa->dev, ret, + "aw88261_request_firmware_file failed\n"); + + /* add widgets */ + ret = snd_soc_dapm_new_controls(dapm, aw88261_dapm_widgets, + ARRAY_SIZE(aw88261_dapm_widgets)); + if (ret) + return ret; + + /* add route */ + ret = snd_soc_dapm_add_routes(dapm, aw88261_audio_map, + ARRAY_SIZE(aw88261_audio_map)); + if (ret) + return ret; + + ret = snd_soc_add_component_controls(component, aw88261_controls, + ARRAY_SIZE(aw88261_controls)); + + return ret; +} + +static void aw88261_codec_remove(struct snd_soc_component *aw_codec) +{ + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(aw_codec); + + cancel_delayed_work_sync(&aw88261->start_work); +} + +static const struct snd_soc_component_driver soc_codec_dev_aw88261 = { + .probe = aw88261_codec_probe, + .remove = aw88261_codec_remove, +}; + +static void aw88261_hw_reset(struct aw88261 *aw88261) +{ + gpiod_set_value_cansleep(aw88261->reset_gpio, 0); + usleep_range(AW88261_1000_US, AW88261_1000_US + 10); + gpiod_set_value_cansleep(aw88261->reset_gpio, 1); + usleep_range(AW88261_1000_US, AW88261_1000_US + 10); +} + +static void aw88261_parse_channel_dt(struct aw88261 *aw88261) +{ + struct aw_device *aw_dev = aw88261->aw_pa; + struct device_node *np = aw_dev->dev->of_node; + u32 channel_value = AW88261_DEV_DEFAULT_CH; + u32 sync_enable = false; + + of_property_read_u32(np, "sound-channel", &channel_value); + of_property_read_u32(np, "sync-flag", &sync_enable); + + aw_dev->channel = channel_value; + aw88261->phase_sync = sync_enable; +} + +static int aw88261_init(struct aw88261 **aw88261, struct i2c_client *i2c, struct regmap *regmap) +{ + struct aw_device *aw_dev; + unsigned int chip_id; + int ret; + + /* read chip id */ + ret = regmap_read(regmap, AW88261_ID_REG, &chip_id); + if (ret) { + dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret); + return ret; + } + if (chip_id != AW88261_CHIP_ID) { + dev_err(&i2c->dev, "unsupported device"); + return -ENXIO; + } + + dev_info(&i2c->dev, "chip id = %x\n", chip_id); + + aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL); + if (!aw_dev) + return -ENOMEM; + + (*aw88261)->aw_pa = aw_dev; + aw_dev->i2c = i2c; + aw_dev->regmap = regmap; + aw_dev->dev = &i2c->dev; + aw_dev->chip_id = AW88261_CHIP_ID; + aw_dev->acf = NULL; + aw_dev->prof_info.prof_desc = NULL; + aw_dev->prof_info.count = 0; + aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID; + aw_dev->channel = 0; + aw_dev->fw_status = AW88261_DEV_FW_FAILED; + aw_dev->fade_step = AW88261_VOLUME_STEP_DB; + aw_dev->volume_desc.ctl_volume = AW88261_VOL_DEFAULT_VALUE; + aw_dev->volume_desc.mute_volume = AW88261_MUTE_VOL; + aw88261_parse_channel_dt(*aw88261); + + return ret; +} + +static int aw88261_i2c_probe(struct i2c_client *i2c) +{ + struct aw88261 *aw88261; + int ret; + + ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C); + if (!ret) + return dev_err_probe(&i2c->dev, ret, "check_functionality failed"); + + aw88261 = devm_kzalloc(&i2c->dev, sizeof(*aw88261), GFP_KERNEL); + if (!aw88261) + return -ENOMEM; + + mutex_init(&aw88261->lock); + + i2c_set_clientdata(i2c, aw88261); + + aw88261->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(aw88261->reset_gpio)) + dev_info(&i2c->dev, "reset gpio not defined\n"); + else + aw88261_hw_reset(aw88261); + + aw88261->regmap = devm_regmap_init_i2c(i2c, &aw88261_remap_config); + if (IS_ERR(aw88261->regmap)) { + ret = PTR_ERR(aw88261->regmap); + return dev_err_probe(&i2c->dev, ret, "failed to init regmap: %d\n", ret); + } + + /* aw pa init */ + ret = aw88261_init(&aw88261, i2c, aw88261->regmap); + if (ret) + return ret; + + ret = devm_snd_soc_register_component(&i2c->dev, + &soc_codec_dev_aw88261, + aw88261_dai, ARRAY_SIZE(aw88261_dai)); + if (ret) + dev_err(&i2c->dev, "failed to register aw88261: %d", ret); + + return ret; +} + +static const struct i2c_device_id aw88261_i2c_id[] = { + { AW88261_I2C_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aw88261_i2c_id); + +static struct i2c_driver aw88261_i2c_driver = { + .driver = { + .name = AW88261_I2C_NAME, + }, + .probe = aw88261_i2c_probe, + .id_table = aw88261_i2c_id, +}; +module_i2c_driver(aw88261_i2c_driver); + +MODULE_DESCRIPTION("ASoC AW88261 Smart PA Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/aw88261.h b/sound/soc/codecs/aw88261.h new file mode 100644 index 000000000000..4f3dbf438510 --- /dev/null +++ b/sound/soc/codecs/aw88261.h @@ -0,0 +1,459 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// aw88261.h -- AW88261 ALSA SoC Audio driver +// +// Copyright (c) 2023 awinic Technology CO., LTD +// +// Author: Jimmy Zhang +// Author: Weidong Wang +// + +#ifndef __AW88261_H__ +#define __AW88261_H__ + +#define AW88261_ID_REG (0x00) +#define AW88261_SYSST_REG (0x01) +#define AW88261_SYSINT_REG (0x02) +#define AW88261_SYSINTM_REG (0x03) +#define AW88261_SYSCTRL_REG (0x04) +#define AW88261_SYSCTRL2_REG (0x05) +#define AW88261_I2SCTRL1_REG (0x06) +#define AW88261_I2SCTRL2_REG (0x07) +#define AW88261_I2SCTRL3_REG (0x08) +#define AW88261_DACCFG1_REG (0x09) +#define AW88261_DACCFG2_REG (0x0A) +#define AW88261_DACCFG3_REG (0x0B) +#define AW88261_DACCFG4_REG (0x0C) +#define AW88261_DACCFG5_REG (0x0D) +#define AW88261_DACCFG6_REG (0x0E) +#define AW88261_DACCFG7_REG (0x0F) +#define AW88261_DACCFG8_REG (0x10) +#define AW88261_PWMCTRL1_REG (0x11) +#define AW88261_PWMCTRL2_REG (0x12) +#define AW88261_I2SCFG1_REG (0x13) +#define AW88261_DBGCTRL_REG (0x14) +#define AW88261_DACCFG9_REG (0x15) +#define AW88261_DACCFG10_REG (0x16) +#define AW88261_DACST_REG (0x20) +#define AW88261_VBAT_REG (0x21) +#define AW88261_TEMP_REG (0x22) +#define AW88261_PVDD_REG (0x23) +#define AW88261_ISNDAT_REG (0x24) +#define AW88261_VSNDAT_REG (0x25) +#define AW88261_I2SINT_REG (0x26) +#define AW88261_I2SCAPCNT_REG (0x27) +#define AW88261_ANASTA1_REG (0x28) +#define AW88261_ANASTA2_REG (0x29) +#define AW88261_ANASTA3_REG (0x2A) +#define AW88261_TESTDET_REG (0x2B) +#define AW88261_DSMCFG1_REG (0x30) +#define AW88261_DSMCFG2_REG (0x31) +#define AW88261_DSMCFG3_REG (0x32) +#define AW88261_DSMCFG4_REG (0x33) +#define AW88261_DSMCFG5_REG (0x34) +#define AW88261_DSMCFG6_REG (0x35) +#define AW88261_DSMCFG7_REG (0x36) +#define AW88261_DSMCFG8_REG (0x37) +#define AW88261_TESTIN_REG (0x38) +#define AW88261_TESTOUT_REG (0x39) +#define AW88261_SADCCTRL1_REG (0x3A) +#define AW88261_SADCCTRL2_REG (0x3B) +#define AW88261_SADCCTRL3_REG (0x3C) +#define AW88261_SADCCTRL4_REG (0x3D) +#define AW88261_SADCCTRL5_REG (0x3E) +#define AW88261_SADCCTRL6_REG (0x3F) +#define AW88261_SADCCTRL7_REG (0x40) +#define AW88261_VSNTM1_REG (0x50) +#define AW88261_VSNTM2_REG (0x51) +#define AW88261_ISNCTRL1_REG (0x52) +#define AW88261_ISNCTRL2_REG (0x53) +#define AW88261_PLLCTRL1_REG (0x54) +#define AW88261_PLLCTRL2_REG (0x55) +#define AW88261_PLLCTRL3_REG (0x56) +#define AW88261_CDACTRL1_REG (0x57) +#define AW88261_CDACTRL2_REG (0x58) +#define AW88261_DITHERCFG1_REG (0x59) +#define AW88261_DITHERCFG2_REG (0x5A) +#define AW88261_DITHERCFG3_REG (0x5B) +#define AW88261_CPCTRL_REG (0x5C) +#define AW88261_BSTCTRL1_REG (0x60) +#define AW88261_BSTCTRL2_REG (0x61) +#define AW88261_BSTCTRL3_REG (0x62) +#define AW88261_BSTCTRL4_REG (0x63) +#define AW88261_BSTCTRL5_REG (0x64) +#define AW88261_BSTCTRL6_REG (0x65) +#define AW88261_BSTCTRL7_REG (0x66) +#define AW88261_BSTCTRL8_REG (0x67) +#define AW88261_BSTCTRL9_REG (0x68) +#define AW88261_TM_REG (0x6F) +#define AW88261_TESTCTRL1_REG (0x70) +#define AW88261_TESTCTRL2_REG (0x71) +#define AW88261_EFCTRL1_REG (0x72) +#define AW88261_EFCTRL2_REG (0x73) +#define AW88261_EFWH_REG (0x74) +#define AW88261_EFWM2_REG (0x75) +#define AW88261_EFWM1_REG (0x76) +#define AW88261_EFWL_REG (0x77) +#define AW88261_EFRH4_REG (0x78) +#define AW88261_EFRH3_REG (0x79) +#define AW88261_EFRH2_REG (0x7A) +#define AW88261_EFRH1_REG (0x7B) +#define AW88261_EFRL4_REG (0x7C) +#define AW88261_EFRL3_REG (0x7D) +#define AW88261_EFRL2_REG (0x7E) +#define AW88261_EFRL1_REG (0x7F) + +#define AW88261_REG_MAX (0x80) +#define AW88261_EF_DBMD_MASK (0xfff7) +#define AW88261_OR_VALUE (0x0008) + +#define AW88261_TEMH_MASK (0x83ff) +#define AW88261_TEML_MASK (0x83ff) +#define AW88261_DEFAULT_CFG (0x0000) + +#define AW88261_ICALK_SHIFT (0) +#define AW88261_ICALKL_SHIFT (0) +#define AW88261_VCALK_SHIFT (0) +#define AW88261_VCALKL_SHIFT (0) + +#define AW88261_AMPPD_START_BIT (1) +#define AW88261_AMPPD_BITS_LEN (1) +#define AW88261_AMPPD_MASK \ + (~(((1<> AW88261_VOL_6DB_START) * \ + AW88261_VOLUME_STEP_DB) + \ + ((value) & AW88261_REG_TO_DB)) +#define DB_TO_REG_VAL(value) ((((value) / AW88261_VOLUME_STEP_DB) << \ + AW88261_VOL_6DB_START) + \ + ((value) % AW88261_VOLUME_STEP_DB)) + +#define AW88261_PROFILE_EXT(xname, profile_info, profile_get, profile_set) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = profile_info, \ + .get = profile_get, \ + .put = profile_set, \ +} + +enum { + AW88261_SYNC_START = 0, + AW88261_ASYNC_START, +}; + +enum aw88261_id { + AW88261_CHIP_ID = 0x2113, +}; + +enum { + AW88261_500_US = 500, + AW88261_1000_US = 1000, + AW88261_2000_US = 2000, +}; + +enum { + AW88261_DEV_PW_OFF = 0, + AW88261_DEV_PW_ON, +}; + +enum { + AW88261_DEV_FW_FAILED = 0, + AW88261_DEV_FW_OK, +}; + +enum { + AW88261_EF_AND_CHECK = 0, + AW88261_EF_OR_CHECK, +}; + +enum { + AW88261_FRCSET_DISABLE = 0, + AW88261_FRCSET_ENABLE, +}; + +struct aw88261 { + struct aw_device *aw_pa; + struct mutex lock; + struct gpio_desc *reset_gpio; + struct delayed_work start_work; + struct regmap *regmap; + struct aw_container *aw_cfg; + + int efuse_check; + int frcset_en; + unsigned int mute_st; + unsigned int amppd_st; + + unsigned char phase_sync; +}; + +#endif -- cgit v1.2.3 From f957172bf7c562df10dc57586118b1cbe15e6b00 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 5 Aug 2023 19:14:35 +0200 Subject: ASoC: lower "no backend DAIs enabled for ... Port" log severity If SNDRV_PCM_IOCTL_PREPARE is called when the mixer settings linking frontend and backend have not been setup yet this results in e.g. the following errors getting logged: [ 43.244549] Baytrail Audio Port: ASoC: no backend DAIs enabled for Baytrail Audio Port [ 43.244744] Baytrail Audio Port: ASoC: error at dpcm_fe_dai_prepare on Baytrail Audio Port: -22 pipewire triggers this leading to 96 lines getting logged after the user has logged into a GNOME session. Change the actual "no backend DAIs enabled for ... Port" error to dev_err_once() to avoid it getting repeated 48 times. While at it also improve the error by hinting the user how to fix this. To not make developing new UCM profiles harder, also log the error at dev_dbg() level all the time (vs once). So that e.g. dyndbg can be used to (re)enable the messages. Also changes _soc_pcm_ret() to not log for -EINVAL errors, to fix the other error getting logged 48 times. Userspace passing wrong parameters should not lead to dmesg messages. Link: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/3407 Signed-off-by: Hans de Goede Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230805171435.31696-1-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 8896227e4fb7..3aa6b988cb4b 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -38,6 +38,7 @@ static inline int _soc_pcm_ret(struct snd_soc_pcm_runtime *rtd, switch (ret) { case -EPROBE_DEFER: case -ENOTSUPP: + case -EINVAL: break; default: dev_err(rtd->dev, @@ -2466,8 +2467,11 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) /* there is no point preparing this FE if there are no BEs */ if (list_empty(&fe->dpcm[stream].be_clients)) { - dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n", - fe->dai_link->name); + /* dev_err_once() for visibility, dev_dbg() for debugging UCM profiles */ + dev_err_once(fe->dev, "ASoC: no backend DAIs enabled for %s, possibly missing ALSA mixer-based routing or UCM profile\n", + fe->dai_link->name); + dev_dbg(fe->dev, "ASoC: no backend DAIs enabled for %s\n", + fe->dai_link->name); ret = -EINVAL; goto out; } -- cgit v1.2.3 From 93fd2be6eb80fe37570fbd87652ec07a4f7c5b5a Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 25 Jul 2023 20:02:47 +0800 Subject: ASoC: SOF: ipc3-dtrace: Switch to memdup_user_nul() helper Use memdup_user_nul() helper instead of open-coding to simplify the code. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20230725120247.509422-1-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc3-dtrace.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/ipc3-dtrace.c b/sound/soc/sof/ipc3-dtrace.c index 35da85a45a9a..bd07f0472efd 100644 --- a/sound/soc/sof/ipc3-dtrace.c +++ b/sound/soc/sof/ipc3-dtrace.c @@ -196,15 +196,9 @@ static ssize_t dfsentry_trace_filter_write(struct file *file, const char __user return -EINVAL; } - string = kmalloc(count + 1, GFP_KERNEL); - if (!string) - return -ENOMEM; - - if (copy_from_user(string, from, count)) { - ret = -EFAULT; - goto error; - } - string[count] = '\0'; + string = memdup_user_nul(from, count); + if (IS_ERR(string)) + return PTR_ERR(string); ret = trace_filter_parse(sdev, string, &num_elems, &elems); if (ret < 0) -- cgit v1.2.3 From 7075b0c91b3cd5d32b4ac7403f771a3253d3fbf6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:40 -0500 Subject: ASoC: SOF: Intel: hda-mlink: fix off-by-one error The HCHAN parameter should be the highest channel number, not the channel count. While we're at it, handle LCHAN with the dual __ffs helper. Fixes: ccc2f0c1b6b6 ("ASoC: SOF: Intel: hda-mlink: add helper to program SoundWire PCMSyCM registers") Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20230807210959.506849-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-mlink.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c index b7cbf66badf5..acad3ea2f471 100644 --- a/sound/soc/sof/intel/hda-mlink.c +++ b/sound/soc/sof/intel/hda-mlink.c @@ -781,6 +781,8 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, { struct hdac_ext2_link *h2link; u16 __iomem *pcmsycm; + int hchan; + int lchan; u16 val; h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW); @@ -791,9 +793,17 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, h2link->instance_offset * sublink + AZX_REG_SDW_SHIM_PCMSyCM(y); + if (channel_mask) { + hchan = __fls(channel_mask); + lchan = __ffs(channel_mask); + } else { + hchan = 0; + lchan = 0; + } + mutex_lock(&h2link->eml_lock); - hdaml_shim_map_stream_ch(pcmsycm, 0, hweight32(channel_mask), + hdaml_shim_map_stream_ch(pcmsycm, lchan, hchan, stream_id, dir); mutex_unlock(&h2link->eml_lock); -- cgit v1.2.3 From 7a52d7062e02af4a479da24b40cfd76b54c0cd6c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:41 -0500 Subject: ASoC: SOF: Intel: fix u16/32 confusion in LSDIID Likely a combination of copy-paste and test coverage problem. Oops. Fixes: 87a6ddc0cf1c ("ASoC: SOF: Intel: hda-mlink: program SoundWire LSDIID registers") Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20230807210959.506849-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-mlink.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c index acad3ea2f471..df87b3791c23 100644 --- a/sound/soc/sof/intel/hda-mlink.c +++ b/sound/soc/sof/intel/hda-mlink.c @@ -331,14 +331,14 @@ static bool hdaml_link_check_cmdsync(u32 __iomem *lsync, u32 cmdsync_mask) return !!(val & cmdsync_mask); } -static void hdaml_link_set_lsdiid(u32 __iomem *lsdiid, int dev_num) +static void hdaml_link_set_lsdiid(u16 __iomem *lsdiid, int dev_num) { - u32 val; + u16 val; - val = readl(lsdiid); + val = readw(lsdiid); val |= BIT(dev_num); - writel(val, lsdiid); + writew(val, lsdiid); } static void hdaml_shim_map_stream_ch(u16 __iomem *pcmsycm, int lchan, int hchan, -- cgit v1.2.3 From defc0c638d20eec17ebb3dbf82709aba1ac2f0d4 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 7 Aug 2023 16:09:42 -0500 Subject: ASoC: SOF: ipc4: avoid uninitialized default instance 0 When a pipeline contains multiple DAI widgets, the pipe_widget is not set up except for the first DAI. This result in the pipe_widget having a default instance 0, which can conflict with another real the pipeline instance 0 and leads to spurious transitions. This patch makes sure the instance_id is properly initialized to a -EINVAL value. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230807210959.506849-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai-ops.c | 6 ++++++ sound/soc/sof/ipc4-topology.c | 1 + sound/soc/sof/topology.c | 2 ++ 3 files changed, 9 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index f3513796c189..e9ae38916434 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -234,6 +234,9 @@ static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cp pipe_widget = swidget->spipe->pipe_widget; pipeline = pipe_widget->private; + if (pipe_widget->instance_id < 0) + return 0; + mutex_lock(&ipc4_data->pipeline_state_mutex); switch (cmd) { @@ -297,6 +300,9 @@ static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c pipe_widget = swidget->spipe->pipe_widget; pipeline = pipe_widget->private; + if (pipe_widget->instance_id < 0) + return 0; + mutex_lock(&ipc4_data->pipeline_state_mutex); switch (cmd) { diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index a4e1a70b607d..9bc94be072aa 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -2319,6 +2319,7 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget pipeline->mem_usage = 0; pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; ida_free(&pipeline_ida, swidget->instance_id); + swidget->instance_id = -EINVAL; } else { struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; struct sof_ipc4_pipeline *pipeline = pipe_widget->private; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 698129dccc7d..1afcbb134d2c 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2157,6 +2157,8 @@ static int sof_complete(struct snd_soc_component *scomp) struct snd_sof_widget *pipe_widget = spipe->pipe_widget; struct snd_sof_widget *swidget; + pipe_widget->instance_id = -EINVAL; + /* Update the scheduler widget's IPC structure */ if (widget_ops && widget_ops[pipe_widget->id].ipc_setup) { ret = widget_ops[pipe_widget->id].ipc_setup(pipe_widget); -- cgit v1.2.3 From ef8a29bae82fc635952de97fdd3bcf8e29d8c6be Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:43 -0500 Subject: ASoC: SOF: ipc4-topology: restore gateway config length The initial code had a logic flaw where the gateway config length kept increasing after each playback/capture trigger, with the DMA config TLV being added at every call of sof_ipc4_prepare_copier_module() This didn't cause any issues with regular playback/capture, but this was flagged as an error by firmware in the case of multiple amplifiers on different links. Fixes: a0659f81c348 ("ASoC: SOF: ipc4-topology: add DMA config TLV to IPC data") Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20230807210959.506849-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 9bc94be072aa..0196cbfc0998 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1746,6 +1746,12 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, /* update pipeline memory usage */ sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config); + /* + * Restore gateway config length now that IPC payload is prepared. This avoids + * counting the DMA CONFIG TLV multiple times + */ + copier_data->gtw_cfg.config_length = gtw_cfg_config_length / 4; + return 0; } -- cgit v1.2.3 From 701c0ba46fabc4715606f840119271a818209357 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:44 -0500 Subject: ASoC: SOF: Intel: hda: add interface definitions for ACE2.x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All interfaces are accessible without the DSP and rely on the HDaudio DMA only. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230807210959.506849-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 64bebe1a72bb..6074b0ca13aa 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -71,6 +71,11 @@ static u32 hda_get_interface_mask(struct snd_sof_dev *sdev) BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH); interface_mask[1] = BIT(SOF_DAI_INTEL_HDA); break; + case SOF_INTEL_ACE_2_0: + interface_mask[0] = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) | + BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH); + interface_mask[1] = interface_mask[0]; /* all interfaces accessible without DSP */ + break; default: break; } -- cgit v1.2.3 From 64a63d9914a5e9278fcd81c6dbc095fc84b772d2 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 7 Aug 2023 16:09:45 -0500 Subject: ASoC: SOF: Intel: LNL: Add support for Lunarlake platform MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add initial support for Lunarlake. For now only HDAudio interfaces are supported, DMIC/SSP/SoundWire require additional work so that the DAIs reuse the HDaudio DMA stream allocation. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230807210959.506849-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/Kconfig | 16 ++++++++++ sound/soc/sof/intel/Makefile | 4 ++- sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/intel/lnl.c | 66 +++++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/pci-lnl.c | 72 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 sound/soc/sof/intel/lnl.c create mode 100644 sound/soc/sof/intel/pci-lnl.c (limited to 'sound') diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 69c1a370d3b6..9d0107932117 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -262,6 +262,22 @@ config SND_SOC_SOF_METEORLAKE Say Y if you have such a device. If unsure select "N". +config SND_SOC_SOF_INTEL_LNL + tristate + select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE + select SND_SOC_SOF_INTEL_IPC4 + +config SND_SOC_SOF_LUNARLAKE + tristate "SOF support for Lunarlake" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_LNL + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Lunarlake processors. + Say Y if you have such a device. + If unsure select "N". + config SND_SOC_SOF_HDA_COMMON tristate select SND_SOC_SOF_INTEL_COMMON diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index fdb463c12e91..030574dbc998 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -7,7 +7,7 @@ snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \ hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \ hda-dai.o hda-dai-ops.o hda-bus.o \ skl.o hda-loader-skl.o \ - apl.o cnl.o tgl.o icl.o mtl.o hda-common-ops.o + apl.o cnl.o tgl.o icl.o mtl.o lnl.o hda-common-ops.o snd-sof-intel-hda-mlink-objs := hda-mlink.o @@ -31,6 +31,7 @@ snd-sof-pci-intel-cnl-objs := pci-cnl.o snd-sof-pci-intel-icl-objs := pci-icl.o snd-sof-pci-intel-tgl-objs := pci-tgl.o snd-sof-pci-intel-mtl-objs := pci-mtl.o +snd-sof-pci-intel-lnl-objs := pci-lnl.o obj-$(CONFIG_SND_SOC_SOF_MERRIFIELD) += snd-sof-pci-intel-tng.o obj-$(CONFIG_SND_SOC_SOF_INTEL_SKL) += snd-sof-pci-intel-skl.o @@ -39,3 +40,4 @@ obj-$(CONFIG_SND_SOC_SOF_INTEL_CNL) += snd-sof-pci-intel-cnl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_ICL) += snd-sof-pci-intel-icl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_TGL) += snd-sof-pci-intel-tgl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_MTL) += snd-sof-pci-intel-mtl.o +obj-$(CONFIG_SND_SOC_SOF_INTEL_LNL) += snd-sof-pci-intel-lnl.o diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 3f7c6fb05e5d..fae3be291861 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -856,6 +856,7 @@ extern const struct sof_intel_dsp_desc ehl_chip_info; extern const struct sof_intel_dsp_desc jsl_chip_info; extern const struct sof_intel_dsp_desc adls_chip_info; extern const struct sof_intel_dsp_desc mtl_chip_info; +extern const struct sof_intel_dsp_desc lnl_chip_info; /* Probes support */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c new file mode 100644 index 000000000000..535a0fd36f38 --- /dev/null +++ b/sound/soc/sof/intel/lnl.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright(c) 2023 Intel Corporation. All rights reserved. + +/* + * Hardware interface for audio DSP on LunarLake. + */ + +#include +#include +#include +#include +#include "../ipc4-priv.h" +#include "../ops.h" +#include "hda.h" +#include "hda-ipc.h" +#include "../sof-audio.h" +#include "mtl.h" +#include "hda.h" +#include + +/* Check if an SDW IRQ occurred */ +static bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + return hdac_bus_eml_check_interrupt(bus, true, AZX_REG_ML_LEPTR_ID_SDW); +} + +static void lnl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + hdac_bus_eml_enable_interrupt(bus, true, AZX_REG_ML_LEPTR_ID_SDW, enable); +} + +static int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev) +{ + lnl_enable_sdw_irq(sdev, false); + mtl_disable_ipc_interrupts(sdev); + return mtl_enable_interrupts(sdev, false); +} + +const struct sof_intel_dsp_desc lnl_chip_info = { + .cores_num = 5, + .init_core_mask = BIT(0), + .host_managed_cores_mask = BIT(0), + .ipc_req = MTL_DSP_REG_HFIPCXIDR, + .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY, + .ipc_ack = MTL_DSP_REG_HFIPCXIDA, + .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE, + .ipc_ctl = MTL_DSP_REG_HFIPCXCTL, + .rom_status_reg = MTL_DSP_ROM_STS, + .rom_init_timeout = 300, + .ssp_count = MTL_SSP_COUNT, + .d0i3_offset = MTL_HDA_VS_D0I3C, + .read_sdw_lcount = hda_sdw_check_lcount_ext, + .enable_sdw_irq = lnl_enable_sdw_irq, + .check_sdw_irq = lnl_dsp_check_sdw_irq, + .check_ipc_irq = mtl_dsp_check_ipc_irq, + .cl_init = mtl_dsp_cl_init, + .power_down_dsp = mtl_power_down_dsp, + .disable_interrupts = lnl_dsp_disable_interrupts, + .hw_ip_version = SOF_INTEL_ACE_2_0, +}; +EXPORT_SYMBOL_NS(lnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/pci-lnl.c b/sound/soc/sof/intel/pci-lnl.c new file mode 100644 index 000000000000..55c757737a95 --- /dev/null +++ b/sound/soc/sof/intel/pci-lnl.c @@ -0,0 +1,72 @@ +// 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 Intel Corporation. All rights reserved. +// +// Author: Ranjani Sridharan +// + +#include +#include +#include +#include +#include +#include "../ops.h" +#include "../sof-pci-dev.h" + +/* platform specific devices */ +#include "hda.h" +#include "mtl.h" + +static const struct sof_dev_desc lnl_desc = { + .use_acpi_target_states = true, + .machines = snd_soc_acpi_intel_lnl_machines, + .alt_machines = snd_soc_acpi_intel_lnl_sdw_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .chip_info = &lnl_chip_info, + .ipc_supported_mask = BIT(SOF_INTEL_IPC4), + .ipc_default = SOF_INTEL_IPC4, + .dspless_mode_supported = true, + .default_fw_path = { + [SOF_INTEL_IPC4] = "intel/sof-ipc4/lnl", + }, + .default_tplg_path = { + [SOF_INTEL_IPC4] = "intel/sof-ace-tplg", + }, + .default_fw_filename = { + [SOF_INTEL_IPC4] = "sof-lnl.ri", + }, + .nocodec_tplg_filename = "sof-lnl-nocodec.tplg", + /* the MTL ops are still used for now */ + .ops = &sof_mtl_ops, + .ops_init = sof_mtl_ops_init, +}; + +/* PCI IDs */ +static const struct pci_device_id sof_pci_ids[] = { + { PCI_DEVICE_DATA(INTEL, HDA_LNL_P, &lnl_desc) }, /* LNL-P */ + { 0, } +}; +MODULE_DEVICE_TABLE(pci, sof_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_intel_lnl_driver = { + .name = "sof-audio-pci-intel-lnl", + .id_table = sof_pci_ids, + .probe = hda_pci_intel_probe, + .remove = sof_pci_remove, + .shutdown = sof_pci_shutdown, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_intel_lnl_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); -- cgit v1.2.3 From c22d53279709c46f2e19caf2886e38cee93d07ea Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:46 -0500 Subject: ASoC: SOF: Intel: split MTL and LNL operations It was just a matter of time before we found a case where we needed separate ops for MTL and LNL. For LNL we need to set the DMIC/SSP OFLEN bit in the probe and resume steps, and this can only be done cleanly with separate ops. The function prototypes in mtl.h were added in the same order as their implementation in mtl.c. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230807210959.506849-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.h | 2 ++ sound/soc/sof/intel/lnl.c | 67 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/mtl.c | 22 +++++++------- sound/soc/sof/intel/mtl.h | 22 ++++++++++++-- sound/soc/sof/intel/pci-lnl.c | 5 ++-- 5 files changed, 102 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index fae3be291861..17164fc42501 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -845,6 +845,8 @@ extern struct snd_sof_dsp_ops sof_icl_ops; int sof_icl_ops_init(struct snd_sof_dev *sdev); extern struct snd_sof_dsp_ops sof_mtl_ops; int sof_mtl_ops_init(struct snd_sof_dev *sdev); +extern struct snd_sof_dsp_ops sof_lnl_ops; +int sof_lnl_ops_init(struct snd_sof_dev *sdev); extern const struct sof_intel_dsp_desc skl_chip_info; extern const struct sof_intel_dsp_desc apl_chip_info; diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c index 535a0fd36f38..65a78d9511e9 100644 --- a/sound/soc/sof/intel/lnl.c +++ b/sound/soc/sof/intel/lnl.c @@ -19,6 +19,73 @@ #include "hda.h" #include +/* LunarLake ops */ +struct snd_sof_dsp_ops sof_lnl_ops; +EXPORT_SYMBOL_NS(sof_lnl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); + +static const struct snd_sof_debugfs_map lnl_dsp_debugfs[] = { + {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, +}; + +int sof_lnl_ops_init(struct snd_sof_dev *sdev) +{ + struct sof_ipc4_fw_data *ipc4_data; + + /* common defaults */ + memcpy(&sof_lnl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops)); + + /* shutdown */ + sof_lnl_ops.shutdown = hda_dsp_shutdown; + + /* doorbell */ + sof_lnl_ops.irq_thread = mtl_ipc_irq_thread; + + /* ipc */ + sof_lnl_ops.send_msg = mtl_ipc_send_msg; + sof_lnl_ops.get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset; + sof_lnl_ops.get_window_offset = mtl_dsp_ipc_get_window_offset; + + /* debug */ + sof_lnl_ops.debug_map = lnl_dsp_debugfs; + sof_lnl_ops.debug_map_count = ARRAY_SIZE(lnl_dsp_debugfs); + sof_lnl_ops.dbg_dump = mtl_dsp_dump; + sof_lnl_ops.ipc_dump = mtl_ipc_dump; + + /* pre/post fw run */ + sof_lnl_ops.pre_fw_run = mtl_dsp_pre_fw_run; + sof_lnl_ops.post_fw_run = mtl_dsp_post_fw_run; + + /* parse platform specific extended manifest */ + sof_lnl_ops.parse_platform_ext_manifest = NULL; + + /* dsp core get/put */ + /* TODO: add core_get and core_put */ + + sof_lnl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position; + + sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL); + if (!sdev->private) + return -ENOMEM; + + ipc4_data = sdev->private; + ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET; + + ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2; + + /* External library loading support */ + ipc4_data->load_library = hda_dsp_ipc4_load_library; + + /* set DAI ops */ + hda_set_dai_drv_ops(sdev, &sof_lnl_ops); + + sof_lnl_ops.set_power_state = hda_dsp_set_power_state_ipc4; + + return 0; +}; +EXPORT_SYMBOL_NS(sof_lnl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON); + /* Check if an SDW IRQ occurred */ static bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 30fe77fd87bf..be3155f98944 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -91,7 +91,7 @@ static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) return false; } -static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; struct sof_ipc4_msg *msg_data = msg->msg_data; @@ -230,7 +230,7 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable) } /* pre fw run operations */ -static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) +int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) { struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; u32 dsphfpwrsts; @@ -279,7 +279,7 @@ static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) return ret; } -static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev) +int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev) { int ret; @@ -301,7 +301,7 @@ static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev) return 0; } -static void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags) +void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags) { char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR; u32 romdbgsts; @@ -495,7 +495,7 @@ err: return ret; } -static irqreturn_t mtl_ipc_irq_thread(int irq, void *context) +irqreturn_t mtl_ipc_irq_thread(int irq, void *context) { struct sof_ipc4_msg notification_data = {{ 0 }}; struct snd_sof_dev *sdev = context; @@ -578,17 +578,17 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context) return IRQ_HANDLED; } -static int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) +int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) { return MTL_DSP_MBOX_UPLINK_OFFSET; } -static int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) +int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) { return MTL_SRAM_WINDOW_OFFSET(id); } -static void mtl_ipc_dump(struct snd_sof_dev *sdev) +void mtl_ipc_dump(struct snd_sof_dev *sdev) { u32 hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl; @@ -612,9 +612,9 @@ static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev) return mtl_enable_interrupts(sdev, false); } -static u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev, - struct snd_soc_component *component, - struct snd_pcm_substream *substream) +u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev, + struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct hdac_stream *hstream = substream->runtime->private_data; u32 llp_l, llp_u; diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h index 2794fe6e8139..02181490f12a 100644 --- a/sound/soc/sof/intel/mtl.h +++ b/sound/soc/sof/intel/mtl.h @@ -82,10 +82,28 @@ #define MTL_DSP_REG_HfIMRIS1 0x162088 #define MTL_DSP_REG_HfIMRIS1_IU_MASK BIT(0) +bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev); +int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); + void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev); void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev); -bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev); int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable); -int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot); + +int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev); +int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev); +void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags); + int mtl_power_down_dsp(struct snd_sof_dev *sdev); +int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot); + +irqreturn_t mtl_ipc_irq_thread(int irq, void *context); + +int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev); +int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id); + +void mtl_ipc_dump(struct snd_sof_dev *sdev); + +u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev, + struct snd_soc_component *component, + struct snd_pcm_substream *substream); diff --git a/sound/soc/sof/intel/pci-lnl.c b/sound/soc/sof/intel/pci-lnl.c index 55c757737a95..1b12c280edb4 100644 --- a/sound/soc/sof/intel/pci-lnl.c +++ b/sound/soc/sof/intel/pci-lnl.c @@ -42,9 +42,8 @@ static const struct sof_dev_desc lnl_desc = { [SOF_INTEL_IPC4] = "sof-lnl.ri", }, .nocodec_tplg_filename = "sof-lnl-nocodec.tplg", - /* the MTL ops are still used for now */ - .ops = &sof_mtl_ops, - .ops_init = sof_mtl_ops_init, + .ops = &sof_lnl_ops, + .ops_init = sof_lnl_ops_init, }; /* PCI IDs */ -- cgit v1.2.3 From e78576c4aa0d5b7185e1f5188578d9bfb2d43d4b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:47 -0500 Subject: ASoC: SOF: Intel: LNL: enable DMIC/SSP offload in probe/resume In the LunarLake hardware, the default IP ownership changed to the host driver, instead of the firmware in previous generation. In the absence of any capability negotiation, we need to assume a fixed partitioning between host driver and firmware. The OFLEN bit needs to be set as early as possible for resources handled by the firmware, since we can't control when the firmware might try to access the resources. For now DMIC and SSP are handled by the DSP firmware. SoundWire is a separate case, the OFLEN bit can be set when starting-up and resuming the aux device for each link. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20230807210959.506849-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/lnl.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c index 65a78d9511e9..3d919b0b6891 100644 --- a/sound/soc/sof/intel/lnl.c +++ b/sound/soc/sof/intel/lnl.c @@ -29,6 +29,55 @@ static const struct snd_sof_debugfs_map lnl_dsp_debugfs[] = { {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, }; +/* this helps allows the DSP to setup DMIC/SSP */ +static int hdac_bus_offload_dmic_ssp(struct hdac_bus *bus) +{ + int ret; + + ret = hdac_bus_eml_enable_offload(bus, true, AZX_REG_ML_LEPTR_ID_INTEL_SSP, true); + if (ret < 0) + return ret; + + ret = hdac_bus_eml_enable_offload(bus, true, AZX_REG_ML_LEPTR_ID_INTEL_DMIC, true); + if (ret < 0) + return ret; + + return 0; +} + +static int lnl_hda_dsp_probe(struct snd_sof_dev *sdev) +{ + int ret; + + ret = hda_dsp_probe(sdev); + if (ret < 0) + return ret; + + return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev)); +} + +static int lnl_hda_dsp_resume(struct snd_sof_dev *sdev) +{ + int ret; + + ret = hda_dsp_resume(sdev); + if (ret < 0) + return ret; + + return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev)); +} + +static int lnl_hda_dsp_runtime_resume(struct snd_sof_dev *sdev) +{ + int ret; + + ret = hda_dsp_runtime_resume(sdev); + if (ret < 0) + return ret; + + return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev)); +} + int sof_lnl_ops_init(struct snd_sof_dev *sdev) { struct sof_ipc4_fw_data *ipc4_data; @@ -36,6 +85,9 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev) /* common defaults */ memcpy(&sof_lnl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops)); + /* probe */ + sof_lnl_ops.probe = lnl_hda_dsp_probe; + /* shutdown */ sof_lnl_ops.shutdown = hda_dsp_shutdown; @@ -63,6 +115,10 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev) /* dsp core get/put */ /* TODO: add core_get and core_put */ + /* PM */ + sof_lnl_ops.resume = lnl_hda_dsp_resume; + sof_lnl_ops.runtime_resume = lnl_hda_dsp_runtime_resume; + sof_lnl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position; sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL); -- cgit v1.2.3 From 12547730e5b7c41e2203003cda74f39f43739c53 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:48 -0500 Subject: ASoC: SOF: Intel: hda-dai-ops: add/select DMA ops for SSP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DMA widget ops are almost similar to the HDaudio ones, with the exception of codec_dai_set_hext_stream() which is not relevant and the format calculation which isn't dependent on the codec dai. The DMA ops can be selected only starting with ACE_2_0. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Reviewed-by: Péter Ujfalusi Link: https://lore.kernel.org/r/20230807210959.506849-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai-ops.c | 53 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index e9ae38916434..05ef77be6435 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include "../ipc4-priv.h" @@ -219,6 +220,31 @@ static struct hdac_ext_link *hda_get_hlink(struct snd_sof_dev *sdev, return snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name); } +static unsigned int generic_calc_stream_format(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + unsigned int format_val; + + format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params), + params_format(params), + params_physical_width(params), + 0); + + dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val, + params_rate(params), params_channels(params), params_format(params)); + + return format_val; +} + +static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + return hdac_bus_eml_ssp_get_hlink(bus); +} + static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream, int cmd) { @@ -363,6 +389,19 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = { .get_hlink = hda_get_hlink, }; +static const struct hda_dai_widget_dma_ops ssp_ipc4_dma_ops = { + .get_hext_stream = hda_ipc4_get_hext_stream, + .assign_hext_stream = hda_assign_hext_stream, + .release_hext_stream = hda_release_hext_stream, + .setup_hext_stream = hda_setup_hext_stream, + .reset_hext_stream = hda_reset_hext_stream, + .pre_trigger = hda_ipc4_pre_trigger, + .trigger = hda_trigger, + .post_trigger = hda_ipc4_post_trigger, + .calc_stream_format = generic_calc_stream_format, + .get_hlink = ssp_get_hlink, +}; + static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = { .get_hext_stream = hda_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, @@ -465,8 +504,13 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg case SOF_INTEL_IPC4: { struct sof_ipc4_copier *ipc4_copier = sdai->private; + const struct sof_intel_dsp_desc *chip; - if (ipc4_copier->dai_type == SOF_DAI_INTEL_HDA) { + chip = get_chip_info(sdev->pdata); + + switch (ipc4_copier->dai_type) { + case SOF_DAI_INTEL_HDA: + { struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; struct sof_ipc4_pipeline *pipeline = pipe_widget->private; @@ -475,6 +519,13 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg return &hda_ipc4_dma_ops; } + case SOF_DAI_INTEL_SSP: + if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) + return NULL; + return &ssp_ipc4_dma_ops; + default: + break; + } break; } default: -- cgit v1.2.3 From a8338e76457c14c56bb13fbb16c8607e80498499 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:49 -0500 Subject: ASoC: SOF: Intel: hda-dai: add ops for SSP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add new ops for SSP. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Reviewed-by: Péter Ujfalusi Link: https://lore.kernel.org/r/20230807210959.506849-11-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai.c | 115 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 3297dea493aa..711854f59cf5 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -10,6 +10,8 @@ #include #include +#include +#include #include #include #include @@ -330,6 +332,96 @@ static const struct snd_soc_dai_ops hda_dai_ops = { #endif +static struct sof_ipc4_copier *widget_to_copier(struct snd_soc_dapm_widget *w) +{ + struct snd_sof_widget *swidget = w->dobj.private; + struct snd_sof_dai *sdai = swidget->private; + struct sof_ipc4_copier *ipc4_copier = (struct sof_ipc4_copier *)sdai->private; + + return ipc4_copier; +} + +static int non_hda_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai) +{ + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); + struct sof_ipc4_dma_config_tlv *dma_config_tlv; + const struct hda_dai_widget_dma_ops *ops; + struct sof_ipc4_dma_config *dma_config; + struct sof_ipc4_copier *ipc4_copier; + struct hdac_ext_stream *hext_stream; + struct hdac_stream *hstream; + struct snd_sof_dev *sdev; + int stream_id; + int ret; + + ops = hda_dai_get_ops(substream, cpu_dai); + if (!ops) { + dev_err(cpu_dai->dev, "DAI widget ops not set\n"); + return -EINVAL; + } + + /* use HDaudio stream handling */ + ret = hda_dai_hw_params(substream, params, cpu_dai); + if (ret < 0) { + dev_err(cpu_dai->dev, "%s: hda_dai_hw_params failed: %d\n", __func__, ret); + return ret; + } + + /* get stream_id */ + sdev = widget_to_sdev(w); + hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); + + if (!hext_stream) { + dev_err(cpu_dai->dev, "%s: no hext_stream found\n", __func__); + return -ENODEV; + } + + hstream = &hext_stream->hstream; + stream_id = hstream->stream_tag; + + if (!stream_id) { + dev_err(cpu_dai->dev, "%s: no stream_id allocated\n", __func__); + return -ENODEV; + } + + /* configure TLV */ + ipc4_copier = widget_to_copier(w); + + dma_config_tlv = &ipc4_copier->dma_config_tlv; + dma_config_tlv->type = SOF_IPC4_GTW_DMA_CONFIG_ID; + /* dma_config_priv_size is zero */ + dma_config_tlv->length = sizeof(dma_config_tlv->dma_config); + + dma_config = &dma_config_tlv->dma_config; + + dma_config->dma_method = SOF_IPC4_DMA_METHOD_HDA; + dma_config->pre_allocated_by_host = 1; + dma_config->dma_channel_id = stream_id - 1; + dma_config->stream_id = stream_id; + dma_config->dma_stream_channel_map.device_count = 0; /* mapping not used */ + dma_config->dma_priv_config_size = 0; + + return 0; +} + +static int non_hda_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + int stream = substream->stream; + + return non_hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai); +} + +static const struct snd_soc_dai_ops ssp_dai_ops = { + .hw_params = non_hda_dai_hw_params, + .hw_free = hda_dai_hw_free, + .trigger = hda_dai_trigger, + .prepare = non_hda_dai_prepare, +}; + static int hda_dai_suspend(struct hdac_bus *bus) { struct snd_soc_pcm_runtime *rtd; @@ -384,7 +476,26 @@ static int hda_dai_suspend(struct hdac_bus *bus) return 0; } -#endif +static void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) +{ + const struct sof_intel_dsp_desc *chip; + int i; + + chip = get_chip_info(sdev->pdata); + + if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) { + for (i = 0; i < ops->num_drv; i++) { + if (strstr(ops->drv[i].name, "SSP")) + ops->drv[i].ops = &ssp_dai_ops; + } + } +} + +#else + +static inline void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {} + +#endif /* CONFIG_SND_SOC_SOF_HDA_LINK */ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) { @@ -399,6 +510,8 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) #endif } + ssp_set_dai_drv_ops(sdev, ops); + if (sdev->pdata->ipc_type == SOF_INTEL_IPC4 && !hda_use_tplg_nhlt) { struct sof_ipc4_fw_data *ipc4_data = sdev->private; -- cgit v1.2.3 From b6c508b46d84d88e617d8b9f38ffbe60470589d0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:50 -0500 Subject: ASoC: SOF: Intel: hda-dai: add DMIC support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can reuse the same helpers as for SSP, with just the link type being different. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Péter Ujfalusi Reviewed-by: Jaska Uimonen Link: https://lore.kernel.org/r/20230807210959.506849-12-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai-ops.c | 55 +++++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda-dai.c | 24 +++++++++++++++++ 2 files changed, 79 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index 05ef77be6435..b66886244f24 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -237,6 +237,36 @@ static unsigned int generic_calc_stream_format(struct snd_sof_dev *sdev, return format_val; } +static unsigned int dmic_calc_stream_format(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + unsigned int format_val; + snd_pcm_format_t format; + unsigned int channels; + unsigned int width; + + channels = params_channels(params); + format = params_format(params); + width = params_physical_width(params); + + if (format == SNDRV_PCM_FORMAT_S16_LE) { + format = SNDRV_PCM_FORMAT_S32_LE; + channels /= 2; + width = 32; + } + + format_val = snd_hdac_calc_stream_format(params_rate(params), channels, + format, + width, + 0); + + dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val, + params_rate(params), channels, format); + + return format_val; +} + static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { @@ -245,6 +275,14 @@ static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev, return hdac_bus_eml_ssp_get_hlink(bus); } +static struct hdac_ext_link *dmic_get_hlink(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + return hdac_bus_eml_dmic_get_hlink(bus); +} + static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream, int cmd) { @@ -402,6 +440,19 @@ static const struct hda_dai_widget_dma_ops ssp_ipc4_dma_ops = { .get_hlink = ssp_get_hlink, }; +static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = { + .get_hext_stream = hda_ipc4_get_hext_stream, + .assign_hext_stream = hda_assign_hext_stream, + .release_hext_stream = hda_release_hext_stream, + .setup_hext_stream = hda_setup_hext_stream, + .reset_hext_stream = hda_reset_hext_stream, + .pre_trigger = hda_ipc4_pre_trigger, + .trigger = hda_trigger, + .post_trigger = hda_ipc4_post_trigger, + .calc_stream_format = dmic_calc_stream_format, + .get_hlink = dmic_get_hlink, +}; + static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = { .get_hext_stream = hda_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, @@ -523,6 +574,10 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) return NULL; return &ssp_ipc4_dma_ops; + case SOF_DAI_INTEL_DMIC: + if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) + return NULL; + return &dmic_ipc4_dma_ops; default: break; } diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 711854f59cf5..08de9b614a83 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -422,6 +422,13 @@ static const struct snd_soc_dai_ops ssp_dai_ops = { .prepare = non_hda_dai_prepare, }; +static const struct snd_soc_dai_ops dmic_dai_ops = { + .hw_params = non_hda_dai_hw_params, + .hw_free = hda_dai_hw_free, + .trigger = hda_dai_trigger, + .prepare = non_hda_dai_prepare, +}; + static int hda_dai_suspend(struct hdac_bus *bus) { struct snd_soc_pcm_runtime *rtd; @@ -491,9 +498,25 @@ static void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops } } +static void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) +{ + const struct sof_intel_dsp_desc *chip; + int i; + + chip = get_chip_info(sdev->pdata); + + if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) { + for (i = 0; i < ops->num_drv; i++) { + if (strstr(ops->drv[i].name, "DMIC")) + ops->drv[i].ops = &dmic_dai_ops; + } + } +} + #else static inline void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {} +static inline void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {} #endif /* CONFIG_SND_SOC_SOF_HDA_LINK */ @@ -511,6 +534,7 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) } ssp_set_dai_drv_ops(sdev, ops); + dmic_set_dai_drv_ops(sdev, ops); if (sdev->pdata->ipc_type == SOF_INTEL_IPC4 && !hda_use_tplg_nhlt) { struct sof_ipc4_fw_data *ipc4_data = sdev->private; -- cgit v1.2.3 From f8ba62ac863c33fc0d8ac3f1270985c2b77f4377 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:51 -0500 Subject: ASoC: SOF: Intel: hda-dai-ops: only allocate/release streams for first CPU DAI When we have multiple CPU DAIs in a dailink, typically for SoundWire aggregated solutions with amplifiers on multiple links, we only want to allocate one HDaudio stream_tag. The simplest solution is to allocate the hext_stream/stream_tag for the DAI with index 0 in the dailink, and reuse the same stream for all other CPU DAIs. This assumption relies on serialization of DAIs by the ASoC core, where all CPU DAIs are handled in a loop. The stream release follows the same idea of releasing the tag for the first DAI only. Ideally we would want the loop to be handled in reverse-order to summetry, but there is no risk of reusing a stream_tag which is no longer valid. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20230807210959.506849-13-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai-ops.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index b66886244f24..9a6d995a8453 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -145,9 +145,17 @@ static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *dai; struct hdac_ext_stream *hext_stream; - hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream); + /* only allocate a stream_tag for the first DAI in the dailink */ + dai = asoc_rtd_to_cpu(rtd, 0); + if (dai == cpu_dai) + hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream); + else + hext_stream = snd_soc_dai_get_dma_data(dai, substream); + if (!hext_stream) return NULL; @@ -160,9 +168,14 @@ static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai struct snd_pcm_substream *substream) { struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *dai; + /* only release a stream_tag for the first DAI in the dailink */ + dai = asoc_rtd_to_cpu(rtd, 0); + if (dai == cpu_dai) + snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); - snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); } static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream, -- cgit v1.2.3 From bb0b992c1bb94e44ba40f82ddb2c4e6d5c9fcc9e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:52 -0500 Subject: ASoC: SOF: Intel: hda-dai-ops: add ops for SoundWire Same abstraction as SSP/DMIC, with only the get_hlink helper changing. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20230807210959.506849-14-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai-ops.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index 9a6d995a8453..4ae211141c40 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -296,6 +296,14 @@ static struct hdac_ext_link *dmic_get_hlink(struct snd_sof_dev *sdev, return hdac_bus_eml_dmic_get_hlink(bus); } +static struct hdac_ext_link *sdw_get_hlink(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + return hdac_bus_eml_sdw_get_hlink(bus); +} + static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream, int cmd) { @@ -466,6 +474,19 @@ static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = { .get_hlink = dmic_get_hlink, }; +static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = { + .get_hext_stream = hda_ipc4_get_hext_stream, + .assign_hext_stream = hda_assign_hext_stream, + .release_hext_stream = hda_release_hext_stream, + .setup_hext_stream = hda_setup_hext_stream, + .reset_hext_stream = hda_reset_hext_stream, + .pre_trigger = hda_ipc4_pre_trigger, + .trigger = hda_trigger, + .post_trigger = hda_ipc4_post_trigger, + .calc_stream_format = generic_calc_stream_format, + .get_hlink = sdw_get_hlink, +}; + static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = { .get_hext_stream = hda_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, @@ -591,6 +612,11 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) return NULL; return &dmic_ipc4_dma_ops; + case SOF_DAI_INTEL_ALH: + if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) + return NULL; + return &sdw_ipc4_dma_ops; + default: break; } -- cgit v1.2.3 From 2960ee5c4814ee50b7b9f030dd99382623a4d7f0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:53 -0500 Subject: ASoC: SOF: Intel: hda-dai: add helpers for SoundWire callbacks During the hw_params and hw_free stages, we need to map the stream tag and channels in the PCMSyCM registers. The trigger callback is just a wrapper. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20230807210959.506849-15-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai.c | 72 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 12 ++++++++ 2 files changed, 84 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 08de9b614a83..c984fa79b1ef 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -429,6 +429,78 @@ static const struct snd_soc_dai_ops dmic_dai_ops = { .prepare = non_hda_dai_prepare, }; +int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai, + int link_id) +{ + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); + const struct hda_dai_widget_dma_ops *ops; + struct hdac_ext_stream *hext_stream; + struct snd_sof_dev *sdev; + int ret; + + ret = non_hda_dai_hw_params(substream, params, cpu_dai); + if (ret < 0) { + dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_params failed %d\n", __func__, ret); + return ret; + } + + ops = hda_dai_get_ops(substream, cpu_dai); + sdev = widget_to_sdev(w); + hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); + + if (!hext_stream) + return -ENODEV; + + /* in the case of SoundWire we need to program the PCMSyCM registers */ + ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id, + GENMASK(params_channels(params) - 1, 0), + hdac_stream(hext_stream)->stream_tag, + substream->stream); + if (ret < 0) { + dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n", + __func__, ret); + return ret; + } + + return 0; +} + +int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai, + int link_id) +{ + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); + struct snd_sof_dev *sdev; + int ret; + + ret = hda_dai_hw_free(substream, cpu_dai); + if (ret < 0) { + dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_free failed %d\n", __func__, ret); + return ret; + } + + sdev = widget_to_sdev(w); + + /* in the case of SoundWire we need to reset the PCMSyCM registers */ + ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id, + 0, 0, substream->stream); + if (ret < 0) { + dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n", + __func__, ret); + return ret; + } + + return 0; +} + +int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *cpu_dai) +{ + return hda_dai_trigger(substream, cmd, cpu_dai); +} + static int hda_dai_suspend(struct hdac_bus *bus) { struct snd_soc_pcm_runtime *rtd; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 17164fc42501..4f60b722e5d5 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -824,6 +824,18 @@ static inline bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev) #endif +int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai, + int link_id); + +int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai, + int link_id); + +int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *cpu_dai); + /* common dai driver */ extern struct snd_soc_dai_driver skl_dai[]; int hda_dsp_dais_suspend(struct snd_sof_dev *sdev); -- cgit v1.2.3 From 186ca4b522fec020f0201d4fcef09ea58b4d5701 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:54 -0500 Subject: ASoC: SOF: Intel: hda: add hw_params/free/trigger callbacks These callbacks are just wrappers to keep the code relatively clean. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20230807210959.506849-16-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 6074b0ca13aa..67b2e00baf4e 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -112,6 +112,34 @@ struct sdw_intel_ops sdw_callback = { .params_stream = sdw_params_stream, }; +static int sdw_ace2x_params_stream(struct device *dev, + struct sdw_intel_stream_params_data *params_data) +{ + return sdw_hda_dai_hw_params(params_data->substream, + params_data->hw_params, + params_data->dai, + params_data->link_id); +} + +static int sdw_ace2x_free_stream(struct device *dev, + struct sdw_intel_stream_free_data *free_data) +{ + return sdw_hda_dai_hw_free(free_data->substream, + free_data->dai, + free_data->link_id); +} + +static int sdw_ace2x_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) +{ + return sdw_hda_dai_trigger(substream, cmd, dai); +} + +static struct sdw_intel_ops sdw_ace2x_callback = { + .params_stream = sdw_ace2x_params_stream, + .free_stream = sdw_ace2x_free_stream, + .trigger = sdw_ace2x_trigger, +}; + void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable) { struct sof_intel_hda_dev *hdev; @@ -179,6 +207,7 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev) res.shim_base = hdev->desc->sdw_shim_base; res.alh_base = hdev->desc->sdw_alh_base; res.ext = false; + res.ops = &sdw_callback; } else { /* * retrieve eml_lock needed to protect shared registers @@ -196,11 +225,13 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev) */ res.hw_ops = &sdw_intel_lnl_hw_ops; res.ext = true; + res.ops = &sdw_ace2x_callback; + } res.irq = sdev->ipc_irq; res.handle = hdev->info.handle; res.parent = sdev->dev; - res.ops = &sdw_callback; + res.dev = sdev->dev; res.clock_stop_quirks = sdw_clock_stop_quirks; res.hbus = sof_to_bus(sdev); -- cgit v1.2.3 From 9362ab78f175db2003674e008ef1b8917725d502 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:55 -0500 Subject: ASoC: SOF: Intel: add abstraction for SoundWire wake-ups The existing code cannot work for LunarLake, let's add a layer of abstraction. No functional change in this patch. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20230807210959.506849-17-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/cnl.c | 2 ++ sound/soc/sof/intel/hda.c | 20 +++++++++++++++----- sound/soc/sof/intel/hda.h | 6 ++++++ sound/soc/sof/intel/icl.c | 1 + sound/soc/sof/intel/mtl.c | 1 + sound/soc/sof/intel/shim.h | 1 + sound/soc/sof/intel/tgl.c | 4 ++++ 7 files changed, 30 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index a95222e53ecf..c6fbf4285262 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -466,6 +466,7 @@ const struct sof_intel_dsp_desc cnl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, @@ -501,6 +502,7 @@ const struct sof_intel_dsp_desc jsl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 67b2e00baf4e..5c1e6ad2b7f2 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -399,14 +399,10 @@ static irqreturn_t hda_dsp_sdw_thread(int irq, void *context) return sdw_intel_thread(irq, context); } -static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) +bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev) { - u32 interface_mask = hda_get_interface_mask(sdev); struct sof_intel_hda_dev *hdev; - if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH))) - return false; - hdev = sdev->pdata->hw_pdata; if (hdev->sdw && snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -416,6 +412,20 @@ static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) return false; } +static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) +{ + u32 interface_mask = hda_get_interface_mask(sdev); + const struct sof_intel_dsp_desc *chip; + + if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH))) + return false; + + if (chip && chip->check_sdw_wakeen_irq) + return chip->check_sdw_wakeen_irq(sdev); + + return false; +} + void hda_sdw_process_wakeen(struct snd_sof_dev *sdev) { u32 interface_mask = hda_get_interface_mask(sdev); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 4f60b722e5d5..f19510e8ce87 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -785,6 +785,7 @@ int hda_sdw_check_lcount_ext(struct snd_sof_dev *sdev); int hda_sdw_startup(struct snd_sof_dev *sdev); void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable); void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable); +bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev); void hda_sdw_process_wakeen(struct snd_sof_dev *sdev); bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev); @@ -813,6 +814,11 @@ static inline void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable) { } +static inline bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev) +{ + return false; +} + static inline void hda_sdw_process_wakeen(struct snd_sof_dev *sdev) { } diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index 0f249efc6a5a..7ac10167a90d 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -188,6 +188,7 @@ const struct sof_intel_dsp_desc icl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index be3155f98944..b84ca58da9d5 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -735,6 +735,7 @@ const struct sof_intel_dsp_desc mtl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = mtl_enable_sdw_irq, .check_sdw_irq = mtl_dsp_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = mtl_dsp_check_ipc_irq, .cl_init = mtl_dsp_cl_init, .power_down_dsp = mtl_power_down_dsp, diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 207df48e27cf..9515d753c816 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -189,6 +189,7 @@ struct sof_intel_dsp_desc { int (*read_sdw_lcount)(struct snd_sof_dev *sdev); void (*enable_sdw_irq)(struct snd_sof_dev *sdev, bool enable); bool (*check_sdw_irq)(struct snd_sof_dev *sdev); + bool (*check_sdw_wakeen_irq)(struct snd_sof_dev *sdev); bool (*check_ipc_irq)(struct snd_sof_dev *sdev); int (*power_down_dsp)(struct snd_sof_dev *sdev); int (*disable_interrupts)(struct snd_sof_dev *sdev); diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 8e2b07e1612b..bb9f20253c99 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -147,6 +147,7 @@ const struct sof_intel_dsp_desc tgl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, @@ -175,6 +176,7 @@ const struct sof_intel_dsp_desc tglh_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, @@ -203,6 +205,7 @@ const struct sof_intel_dsp_desc ehl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, @@ -231,6 +234,7 @@ const struct sof_intel_dsp_desc adls_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, -- cgit v1.2.3 From 34e38f03d7e77141ef6879c69ca55fc2a44b9f2e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:56 -0500 Subject: ASoC: SOF: Intel: hda-mlink: add helper to get sublink LSDIID register We need to retrieve the current value to deal with the HDAudio WAKEEN/WAKESTS setup. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20230807210959.506849-18-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-mlink.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c index df87b3791c23..9fbbcc1744db 100644 --- a/sound/soc/sof/intel/hda-mlink.c +++ b/sound/soc/sof/intel/hda-mlink.c @@ -331,6 +331,11 @@ static bool hdaml_link_check_cmdsync(u32 __iomem *lsync, u32 cmdsync_mask) return !!(val & cmdsync_mask); } +static u16 hdaml_link_get_lsdiid(u16 __iomem *lsdiid) +{ + return readw(lsdiid); +} + static void hdaml_link_set_lsdiid(u16 __iomem *lsdiid, int dev_num) { u16 val; @@ -752,6 +757,22 @@ int hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink) } EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_down_unlocked, SND_SOC_SOF_HDA_MLINK); +int hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid) +{ + struct hdac_ext2_link *h2link; + struct hdac_ext_link *hlink; + + h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW); + if (!h2link) + return -ENODEV; + + hlink = &h2link->hext_link; + + *lsdiid = hdaml_link_get_lsdiid(hlink->ml_addr + AZX_REG_ML_LSDIID_OFFSET(sublink)); + + return 0; +} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_lsdiid_unlocked, SND_SOC_SOF_HDA_MLINK); + int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num) { struct hdac_ext2_link *h2link; -- cgit v1.2.3 From 699e146d9ebf42ee2a5d4e4e28f7a49c4aef0105 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:57 -0500 Subject: ASoC: SOF: Intel: hda-dai-ops: reset device count for SoundWire DAIs The solution used before LunarLake relies on a 'Multi-gateway' firmware configuration. This is no longer needed with the DMA hardware handling multiple links directly. To avoid adding a platform-specific quirk in the generic IPC4 code, this patch resets the device count when fetching the stream context. Suggested-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20230807210959.506849-19-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai-ops.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index 4ae211141c40..ae4a5aa73bfc 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -434,6 +434,28 @@ out: return ret; } +static struct hdac_ext_stream *sdw_hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev, + struct snd_soc_dai *cpu_dai, + struct snd_pcm_substream *substream) +{ + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); + struct snd_sof_widget *swidget = w->dobj.private; + struct snd_sof_dai *dai = swidget->private; + struct sof_ipc4_copier *ipc4_copier = dai->private; + struct sof_ipc4_alh_configuration_blob *blob; + + blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; + + /* + * Starting with ACE_2_0, re-setting the device_count is mandatory to avoid using + * the multi-gateway firmware configuration. The DMA hardware can take care of + * multiple links without needing any firmware assistance + */ + blob->alh_cfg.device_count = 1; + + return hda_ipc4_get_hext_stream(sdev, cpu_dai, substream); +} + static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = { .get_hext_stream = hda_ipc4_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, @@ -475,7 +497,7 @@ static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = { }; static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = { - .get_hext_stream = hda_ipc4_get_hext_stream, + .get_hext_stream = sdw_hda_ipc4_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, .release_hext_stream = hda_release_hext_stream, .setup_hext_stream = hda_setup_hext_stream, -- cgit v1.2.3 From 1eaff2647eb1dfbaa500fb5f28e032db5ad35b70 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:58 -0500 Subject: ASoC: SOF: IPC4: clarify 'pipeline_ids' usage and logs A pipeline is identified by two indices: 'instance_id' and 'pipeline_id' This is clearly seen in kernel logs when creating a pipeline "Create widget pipeline.20 instance 0 - pipe 20 - core 0" but other logs are less clear "ipc4 set pipeline 1 state 4" Change definitions and logs to make sure the logs clearly identify which of the two indices are used in state transitions. No functional change. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20230807210959.506849-20-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-pcm.c | 21 +++++++++++---------- sound/soc/sof/ipc4-topology.h | 4 ++-- 2 files changed, 13 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 0c905bd0fab4..802cbf73594e 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -23,7 +23,8 @@ static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state /* trigger a single pipeline */ if (trigger_list->count == 1) - return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_ids[0], state); + return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_instance_ids[0], + state); primary = state; primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE); @@ -42,15 +43,15 @@ static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, ipc_size); } -int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state) +int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 state) { struct sof_ipc4_msg msg = {{ 0 }}; u32 primary; - dev_dbg(sdev->dev, "ipc4 set pipeline %d state %d", id, state); + dev_dbg(sdev->dev, "ipc4 set pipeline instance %d state %d", instance_id, state); primary = state; - primary |= SOF_IPC4_GLB_PIPE_STATE_ID(id); + primary |= SOF_IPC4_GLB_PIPE_STATE_ID(instance_id); primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE); primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); @@ -79,19 +80,19 @@ sof_ipc4_add_pipeline_to_trigger_list(struct snd_sof_dev *sdev, int state, * for the first time */ if (spipe->started_count == spipe->paused_count) - trigger_list->pipeline_ids[trigger_list->count++] = + trigger_list->pipeline_instance_ids[trigger_list->count++] = pipe_widget->instance_id; break; case SOF_IPC4_PIPE_RESET: /* RESET if the pipeline is neither running nor paused */ if (!spipe->started_count && !spipe->paused_count) - trigger_list->pipeline_ids[trigger_list->count++] = + trigger_list->pipeline_instance_ids[trigger_list->count++] = pipe_widget->instance_id; break; case SOF_IPC4_PIPE_PAUSED: /* Pause the pipeline only when its started_count is 1 more than paused_count */ if (spipe->paused_count == (spipe->started_count - 1)) - trigger_list->pipeline_ids[trigger_list->count++] = + trigger_list->pipeline_instance_ids[trigger_list->count++] = pipe_widget->instance_id; break; default: @@ -113,7 +114,7 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd, /* set state for pipeline if it was just triggered */ for (i = 0; i < trigger_list->count; i++) { - if (trigger_list->pipeline_ids[i] == pipe_widget->instance_id) { + if (trigger_list->pipeline_instance_ids[i] == pipe_widget->instance_id) { pipeline->state = state; break; } @@ -314,8 +315,8 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, return sof_ipc4_chain_dma_trigger(sdev, pipeline_list, state, cmd); /* allocate memory for the pipeline data */ - trigger_list = kzalloc(struct_size(trigger_list, pipeline_ids, pipeline_list->count), - GFP_KERNEL); + trigger_list = kzalloc(struct_size(trigger_list, pipeline_instance_ids, + pipeline_list->count), GFP_KERNEL); if (!trigger_list) return -ENOMEM; diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index 6dcf14886e85..d75f17f4749c 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -144,11 +144,11 @@ struct sof_ipc4_pipeline { /** * struct sof_ipc4_multi_pipeline_data - multi pipeline trigger IPC data * @count: Number of pipelines to be triggered - * @pipeline_ids: Flexible array of IDs of the pipelines to be triggered + * @pipeline_instance_ids: Flexible array of IDs of the pipelines to be triggered */ struct ipc4_pipeline_set_state_data { u32 count; - DECLARE_FLEX_ARRAY(u32, pipeline_ids); + DECLARE_FLEX_ARRAY(u32, pipeline_instance_ids); } __packed; /** -- cgit v1.2.3 From 02c7f8729a5a1e78412177482372c3124edd4d62 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 7 Aug 2023 16:09:59 -0500 Subject: ASoC: SOF: Intel: hda-mlink: add sublink to dev_dbg() log When using more than one sublink for amplifier aggregation, we need to add the sublink info to debug the programming sequences. No functional change, only additional precisions in the log. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20230807210959.506849-21-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-mlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c index 9fbbcc1744db..b592e687a87a 100644 --- a/sound/soc/sof/intel/hda-mlink.c +++ b/sound/soc/sof/intel/hda-mlink.c @@ -831,8 +831,8 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, val = readw(pcmsycm); - dev_dbg(bus->dev, "channel_mask %#x stream_id %d dir %d pcmscm %#x\n", - channel_mask, stream_id, dir, val); + dev_dbg(bus->dev, "sublink %d channel_mask %#x stream_id %d dir %d pcmscm %#x\n", + sublink, channel_mask, stream_id, dir, val); return 0; } EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, SND_SOC_SOF_HDA_MLINK); -- cgit v1.2.3 From 205b96e307480e0484894b619c481fac5b6653e6 Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Fri, 4 Aug 2023 15:07:39 +0400 Subject: 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(-) (limited to 'sound') 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; } -- cgit v1.2.3 From bba0498bd2d31f958b697d9d8a6b1c106de02e43 Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Fri, 4 Aug 2023 15:07:40 +0400 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From 3d28c466317b9515810a1f5ec29be394269bcb73 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Mon, 7 Aug 2023 17:49:28 +0000 Subject: 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(-) (limited to 'sound') 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), -- cgit v1.2.3 From 94c40dbbffa11bec54b5ca74df1c5bb0f52995b9 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Sat, 5 Aug 2023 19:22:16 +0300 Subject: ASoC: amd: acp3x-rt5682-max9836: Configure jack as not detecting Line Out The RT5682, RT1015 and RT1015p codecs used in this driver do not seem capable of distinguishing Line Out connections from Headphone, but the driver configures its jack object as if it can. Remove the wrong value from the jack creation call to avoid any confusion. Signed-off-by: Alper Nebi Yasak Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki Link: https://lore.kernel.org/r/20230805162216.441410-1-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/acp3x-rt5682-max9836.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/amd/acp3x-rt5682-max9836.c b/sound/soc/amd/acp3x-rt5682-max9836.c index 3bf7e1e83c36..28ad5f5b9a76 100644 --- a/sound/soc/amd/acp3x-rt5682-max9836.c +++ b/sound/soc/amd/acp3x-rt5682-max9836.c @@ -98,7 +98,7 @@ static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd) rt5682_dai_bclk = clk_get(component->dev, "rt5682-dai-bclk"); ret = snd_soc_card_jack_new_pins(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, &pco_jack, -- cgit v1.2.3 From 8e5c4a9fc47ab6d8e1d9cf6c1f11c90675c1d968 Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Tue, 8 Aug 2023 10:17:28 +0800 Subject: ASoC: imx-audio-rpmsg: Remove redundant initialization owner in imx_audio_rpmsg_driver The module_rpmsg_driver() will set "THIS_MODULE" to driver.owner when register a rpmsg_driver driver, so it is redundant initialization to set driver.owner in the statement. Remove it for clean code. Signed-off-by: Li Zetao Link: https://lore.kernel.org/r/20230808021728.2978035-1-lizetao1@huawei.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-audio-rpmsg.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/fsl/imx-audio-rpmsg.c b/sound/soc/fsl/imx-audio-rpmsg.c index d5234ac4b09b..289e47c03d40 100644 --- a/sound/soc/fsl/imx-audio-rpmsg.c +++ b/sound/soc/fsl/imx-audio-rpmsg.c @@ -116,7 +116,6 @@ static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = { static struct rpmsg_driver imx_audio_rpmsg_driver = { .drv.name = "imx_audio_rpmsg", - .drv.owner = THIS_MODULE, .id_table = imx_audio_rpmsg_id_table, .probe = imx_audio_rpmsg_probe, .callback = imx_audio_rpmsg_cb, -- cgit v1.2.3 From c307ca16c9bffc18dbf37ae64c71d935a2923c3a Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:02 +0100 Subject: ASoC: intel: sof_sdw: Printk's should end with a newline Add the missing new lines. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index fd27e211211b..8f3329dcf706 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -524,7 +524,7 @@ int sdw_prepare(struct snd_pcm_substream *substream) sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s", dai->name); + dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); return PTR_ERR(sdw_stream); } @@ -543,7 +543,7 @@ int sdw_trigger(struct snd_pcm_substream *substream, int cmd) sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s", dai->name); + dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); return PTR_ERR(sdw_stream); } @@ -565,7 +565,7 @@ int sdw_trigger(struct snd_pcm_substream *substream, int cmd) } if (ret) - dev_err(rtd->dev, "%s trigger %d failed: %d", __func__, cmd, ret); + dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret); return ret; } @@ -630,7 +630,7 @@ int sdw_hw_free(struct snd_pcm_substream *substream) sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s", dai->name); + dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); return PTR_ERR(sdw_stream); } @@ -1339,7 +1339,7 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, return -EINVAL; if (index >= SDW_MAX_CPU_DAIS) { - dev_err(dev, " cpu_dai_id array overflows"); + dev_err(dev, "cpu_dai_id array overflows\n"); return -EINVAL; } @@ -1490,7 +1490,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, return -ENOMEM; if (cpu_dai_index >= sdw_cpu_dai_num) { - dev_err(dev, "invalid cpu dai index %d", + dev_err(dev, "invalid cpu dai index %d\n", cpu_dai_index); return -EINVAL; } @@ -1503,12 +1503,12 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, * not be larger than sdw_be_num */ if (*link_index >= sdw_be_num) { - dev_err(dev, "invalid dai link index %d", *link_index); + dev_err(dev, "invalid dai link index %d\n", *link_index); return -EINVAL; } if (*cpu_id >= sdw_cpu_dai_num) { - dev_err(dev, " invalid cpu dai index %d", *cpu_id); + dev_err(dev, "invalid cpu dai index %d\n", *cpu_id); return -EINVAL; } @@ -1531,7 +1531,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, ret = set_codec_init_func(card, adr_link, dai_links + (*link_index)++, playback, group_id, adr_index, dai_index); if (ret < 0) { - dev_err(dev, "failed to init codec %d", codec_index); + dev_err(dev, "failed to init codec %d\n", codec_index); return ret; } @@ -1675,7 +1675,7 @@ out: endpoint = adr_link->adr_d[i].endpoints; if (endpoint->aggregated && !endpoint->group_id) { - dev_err(dev, "invalid group id on link %x", + dev_err(dev, "invalid group id on link %x\n", adr_link->mask); continue; } @@ -1698,7 +1698,7 @@ out: &be_id, &codec_conf_index, &ignore_pch_dmic, append_dai_type, i, j); if (ret < 0) { - dev_err(dev, "failed to create dai link %d", link_index); + dev_err(dev, "failed to create dai link %d\n", link_index); return ret; } } -- cgit v1.2.3 From 3003ea9cb7bd6399ca9962e0b3dd0ac58b151c2e Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:03 +0100 Subject: ASoC: intel: sof_sdw: Remove duplicate NULL check on adr_link get_dailink_info already checked if the adr_link pointer was NULL so there is no need to recheck later in sof_card_dai_links_create. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-2-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 8f3329dcf706..89614d08d091 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1632,10 +1632,6 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) if (!sdw_be_num) goto SSP; - adr_link = mach_params->links; - if (!adr_link) - return -EINVAL; - for (i = 0; i < SDW_MAX_LINKS; i++) sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE; -- cgit v1.2.3 From e1cfd5fef3d6eaf0ddbc54da70ddf54462b23592 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:04 +0100 Subject: ASoC: intel: sof_sdw: Check link mask validity in get_dailink_info As get_dailink_info spins through all the links anyway simply check the link masks there. This saves an extra check and means the code will fail earlier if the mask is invalid. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-3-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 89614d08d091..268629d5505c 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1053,6 +1053,10 @@ static int get_dailink_info(struct device *dev, int stream; u64 adr; + /* make sure the link mask has a single bit set */ + if (!is_power_of_2(adr_link->mask)) + return -EINVAL; + for (i = 0; i < adr_link->num_adr; i++) { adr = adr_link->adr_d[i].adr; codec_index = find_codec_info_part(adr); @@ -1302,10 +1306,6 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; adr_d = &adr_link->adr_d[adr_index]; - /* make sure the link mask has a single bit set */ - if (!is_power_of_2(adr_link->mask)) - return -EINVAL; - cpu_dai_id[index++] = ffs(adr_link->mask) - 1; if (!adr_d->endpoints->aggregated || no_aggregation) { *cpu_dai_num = 1; @@ -1334,10 +1334,6 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, endpoint->group_id != *group_id) continue; - /* make sure the link mask has a single bit set */ - if (!is_power_of_2(adr_next->mask)) - return -EINVAL; - if (index >= SDW_MAX_CPU_DAIS) { dev_err(dev, "cpu_dai_id array overflows\n"); return -EINVAL; -- cgit v1.2.3 From 87608d3e9de18331c5d3c9ecb915b0ff3d03c089 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:05 +0100 Subject: ASoC: intel: sof-sdw: Move check for valid group id to get_dailink_info Move the check for a valid group id into get_dailink_info as well. This does cause a slight change in behaviour in that the system will return an error rather than just ignoring the link with an invalid group id. There are presently no systems with invalid group ids in mainline and failing seems more appropriate since it will better highlight the code needs fixing. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-4-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 268629d5505c..b250fb7be4bf 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1074,6 +1074,11 @@ static int get_dailink_info(struct device *dev, } endpoint = adr_link->adr_d[i].endpoints; + if (endpoint->aggregated && !endpoint->group_id) { + dev_err(dev, "invalid group id on link %x\n", + adr_link->mask); + return -EINVAL; + } for (j = 0; j < codec_info->dai_num; j++) { /* count DAI number for playback and capture */ @@ -1666,11 +1671,6 @@ out: const struct snd_soc_acpi_endpoint *endpoint; endpoint = adr_link->adr_d[i].endpoints; - if (endpoint->aggregated && !endpoint->group_id) { - dev_err(dev, "invalid group id on link %x\n", - adr_link->mask); - continue; - } /* this group has been generated */ if (endpoint->aggregated && -- cgit v1.2.3 From 92e9f10a093529f85b7557b0627531728d89afa2 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:06 +0100 Subject: ASoC: intel: sof_sdw: Add helper to create a single codec DLC Add a helper function to create a single codec DAI link component structure. This sets things up for more refactoring of the creating of the DAI links. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-5-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 80 +++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 37 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index b250fb7be4bf..ba4775e77807 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1160,6 +1160,43 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, return true; } +static int fill_sdw_codec_dlc(struct device *dev, + const struct snd_soc_acpi_link_adr *adr_link, + struct snd_soc_dai_link_component *codec, + int codec_index, int adr_index, int dai_index) +{ + unsigned int sdw_version, unique_id, mfg_id, link_id, part_id, class_id; + u64 adr = adr_link->adr_d[adr_index].adr; + + sdw_version = SDW_VERSION(adr); + link_id = SDW_DISCO_LINK_ID(adr); + unique_id = SDW_UNIQUE_ID(adr); + mfg_id = SDW_MFG_ID(adr); + part_id = SDW_PART_ID(adr); + class_id = SDW_CLASS_ID(adr); + + if (codec_info_list[codec_index].codec_name) + codec->name = devm_kstrdup(dev, + codec_info_list[codec_index].codec_name, + GFP_KERNEL); + else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id, + class_id, adr_index)) + codec->name = devm_kasprintf(dev, GFP_KERNEL, + "sdw:%01x:%04x:%04x:%02x", link_id, + mfg_id, part_id, class_id); + else + codec->name = devm_kasprintf(dev, GFP_KERNEL, + "sdw:%01x:%04x:%04x:%02x:%01x", link_id, + mfg_id, part_id, class_id, unique_id); + + if (!codec->name) + return -ENOMEM; + + codec->dai_name = codec_info_list[codec_index].dais[dai_index].dai_name; + + return 0; +} + static int create_codec_dai_name(struct device *dev, const struct snd_soc_acpi_link_adr *adr_link, struct snd_soc_dai_link_component *codec, @@ -1171,7 +1208,7 @@ static int create_codec_dai_name(struct device *dev, int dai_index) { int _codec_index = -1; - int i; + int i, ret; /* sanity check */ if (*codec_conf_index + adr_link->num_adr - adr_index > codec_count) { @@ -1180,13 +1217,8 @@ static int create_codec_dai_name(struct device *dev, } for (i = adr_index; i < adr_link->num_adr; i++) { - unsigned int sdw_version, unique_id, mfg_id; - unsigned int link_id, part_id, class_id; int codec_index, comp_index; - char *codec_str; - u64 adr; - - adr = adr_link->adr_d[i].adr; + u64 adr = adr_link->adr_d[i].adr; codec_index = find_codec_info_part(adr); if (codec_index < 0) @@ -1197,38 +1229,12 @@ static int create_codec_dai_name(struct device *dev, } _codec_index = codec_index; - sdw_version = SDW_VERSION(adr); - link_id = SDW_DISCO_LINK_ID(adr); - unique_id = SDW_UNIQUE_ID(adr); - mfg_id = SDW_MFG_ID(adr); - part_id = SDW_PART_ID(adr); - class_id = SDW_CLASS_ID(adr); - comp_index = i - adr_index + offset; - if (codec_info_list[codec_index].codec_name) { - codec[comp_index].name = - devm_kstrdup(dev, codec_info_list[codec_index].codec_name, - GFP_KERNEL); - } else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id, - class_id, i)) { - codec_str = "sdw:%01x:%04x:%04x:%02x"; - codec[comp_index].name = - devm_kasprintf(dev, GFP_KERNEL, codec_str, - link_id, mfg_id, part_id, - class_id); - } else { - codec_str = "sdw:%01x:%04x:%04x:%02x:%01x"; - codec[comp_index].name = - devm_kasprintf(dev, GFP_KERNEL, codec_str, - link_id, mfg_id, part_id, - class_id, unique_id); - } - if (!codec[comp_index].name) - return -ENOMEM; - - codec[comp_index].dai_name = - codec_info_list[codec_index].dais[dai_index].dai_name; + ret = fill_sdw_codec_dlc(dev, adr_link, &codec[comp_index], + codec_index, i, dai_index); + if (ret) + return ret; codec_conf[*codec_conf_index].dlc = codec[comp_index]; codec_conf[*codec_conf_index].name_prefix = adr_link->adr_d[i].name_prefix; -- cgit v1.2.3 From c3d7e29ad82ee689b1adf5ea7806b9d06eb098c0 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:07 +0100 Subject: ASoC: intel: sof_sdw: Pull device loop up into create_sdw_dailink The loops which fill the codec DAI link component structures are split across create_sdw_dailink and create_codec_dai_name. This causes the code to be rather confusing, needing to return out the function to allow the upper loop to iterate. Remove the create_codec_dai_name helper and pull its code up into create_sdw_dailink, this makes it more obvious what is happening in the code. This patch makes no functional change just hoists the code up a level. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-6-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 89 ++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 54 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index ba4775e77807..5c154628236c 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1197,54 +1197,6 @@ static int fill_sdw_codec_dlc(struct device *dev, return 0; } -static int create_codec_dai_name(struct device *dev, - const struct snd_soc_acpi_link_adr *adr_link, - struct snd_soc_dai_link_component *codec, - int offset, - struct snd_soc_codec_conf *codec_conf, - int codec_count, - int *codec_conf_index, - int adr_index, - int dai_index) -{ - int _codec_index = -1; - int i, ret; - - /* sanity check */ - if (*codec_conf_index + adr_link->num_adr - adr_index > codec_count) { - dev_err(dev, "codec_conf: out-of-bounds access requested\n"); - return -EINVAL; - } - - for (i = adr_index; i < adr_link->num_adr; i++) { - int codec_index, comp_index; - u64 adr = adr_link->adr_d[i].adr; - - codec_index = find_codec_info_part(adr); - if (codec_index < 0) - return codec_index; - if (_codec_index != -1 && codec_index != _codec_index) { - dev_dbg(dev, "Different devices on the same sdw link\n"); - break; - } - _codec_index = codec_index; - - comp_index = i - adr_index + offset; - - ret = fill_sdw_codec_dlc(dev, adr_link, &codec[comp_index], - codec_index, i, dai_index); - if (ret) - return ret; - - codec_conf[*codec_conf_index].dlc = codec[comp_index]; - codec_conf[*codec_conf_index].name_prefix = adr_link->adr_d[i].name_prefix; - - ++*codec_conf_index; - } - - return 0; -} - static int set_codec_init_func(struct snd_soc_card *card, const struct snd_soc_acpi_link_adr *adr_link, struct snd_soc_dai_link *dai_links, @@ -1401,8 +1353,8 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, int codec_num; int stream; int i = 0; + int j, k; int ret; - int k; ret = get_slave_info(adr_link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, &group_id, adr_index); @@ -1417,6 +1369,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr && i < cpu_dai_num; adr_link_next++) { const struct snd_soc_acpi_endpoint *endpoints; + int _codec_index = -1; endpoints = adr_link_next->adr_d->endpoints; if (group_id && (!endpoints->aggregated || @@ -1427,11 +1380,39 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) continue; - ret = create_codec_dai_name(dev, adr_link_next, codecs, codec_dlc_index, - codec_conf, codec_count, codec_conf_index, - adr_index, dai_index); - if (ret < 0) - return ret; + /* sanity check */ + if (*codec_conf_index + adr_link_next->num_adr - adr_index > codec_count) { + dev_err(dev, "codec_conf: out-of-bounds access requested\n"); + return -EINVAL; + } + + for (j = adr_index; j < adr_link_next->num_adr; j++) { + int codec_index, comp_index; + u64 adr = adr_link_next->adr_d[j].adr; + + codec_index = find_codec_info_part(adr); + if (codec_index < 0) + return codec_index; + if (_codec_index != -1 && codec_index != _codec_index) { + dev_dbg(dev, "Different devices on the same sdw link\n"); + break; + } + _codec_index = codec_index; + + comp_index = j - adr_index + codec_dlc_index; + + ret = fill_sdw_codec_dlc(dev, adr_link_next, + &codecs[comp_index], + codec_index, j, dai_index); + if (ret) + return ret; + + codec_conf[*codec_conf_index].dlc = codecs[comp_index]; + codec_conf[*codec_conf_index].name_prefix = + adr_link_next->adr_d[j].name_prefix; + + (*codec_conf_index)++; + } /* check next link to create codec dai in the processed group */ i++; -- cgit v1.2.3 From 0e82229fb74a26cfaf6ae3772cbdefdb643f98a5 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:08 +0100 Subject: ASoC: intel: sof_sdw: Update DLC index each time one is added In create_sdw_dailink, rather than bulk updating the index into the DAI link components array, at the end of processing a link, do so each time the code adds a new component. This simplifies things slightly, as an intermediate variable is no longer needed to track the current place in the DAI link components array. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-7-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 5c154628236c..b381fb261994 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1387,7 +1387,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, } for (j = adr_index; j < adr_link_next->num_adr; j++) { - int codec_index, comp_index; + int codec_index; u64 adr = adr_link_next->adr_d[j].adr; codec_index = find_codec_info_part(adr); @@ -1399,24 +1399,22 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, } _codec_index = codec_index; - comp_index = j - adr_index + codec_dlc_index; - ret = fill_sdw_codec_dlc(dev, adr_link_next, - &codecs[comp_index], + &codecs[codec_dlc_index], codec_index, j, dai_index); if (ret) return ret; - codec_conf[*codec_conf_index].dlc = codecs[comp_index]; + codec_conf[*codec_conf_index].dlc = codecs[codec_dlc_index]; codec_conf[*codec_conf_index].name_prefix = adr_link_next->adr_d[j].name_prefix; + codec_dlc_index++; (*codec_conf_index)++; } /* check next link to create codec dai in the processed group */ i++; - codec_dlc_index += adr_link_next->num_adr; } /* find codec info to create BE DAI */ -- cgit v1.2.3 From 59736ca62e1eeb4466ace99e167cbe7a0f9bc0fa Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:09 +0100 Subject: ASoC: intel: sof_sdw: Move range check of codec_conf into inner loop There are two problems with the current range check on the codec_conf array. Firstly, adr_link_next->num_adr refers to the number of devices on the current SoundWire link, but adr_index refers to the first SoundWire link involved in the DAI link. This means that subtracting these two numbers is only meaningful on the first SoundWire link in the DAI and broken on later links. Secondly, the intention of the range check is to add the number of remaining devices on the currently link to the current index and ensure enough space remains. However, this assumes that all remaining devices on the SoundWire link will be added to the current DAI link. Ideally this would not be the case, and devices could be grouped as the user desired. Moving the range check into the inner loop both simplifies the code (no need to add and subtract offsets) and allows future refactoring such that devices on a single SoundWire link don't have to all be grouped onto a single DAI link. The check will be processed slightly more often since it is processed for each device rather each link but this is probe time and the numbers involved are very small here (4 links, likely no more than 2-4 devices per link). Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-8-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index b381fb261994..0401516f35de 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1380,12 +1380,6 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) continue; - /* sanity check */ - if (*codec_conf_index + adr_link_next->num_adr - adr_index > codec_count) { - dev_err(dev, "codec_conf: out-of-bounds access requested\n"); - return -EINVAL; - } - for (j = adr_index; j < adr_link_next->num_adr; j++) { int codec_index; u64 adr = adr_link_next->adr_d[j].adr; @@ -1399,6 +1393,12 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, } _codec_index = codec_index; + /* sanity check */ + if (*codec_conf_index >= codec_count) { + dev_err(dev, "codec_conf array overflowed\n"); + return -EINVAL; + } + ret = fill_sdw_codec_dlc(dev, adr_link_next, &codecs[codec_dlc_index], codec_index, j, dai_index); -- cgit v1.2.3 From f3eb3d45fdfd693dc004e664544f978ae8d38f48 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:10 +0100 Subject: ASoC: intel: sof_sdw: Device loop should not always start at adr_index The current loops at the top of create_sdw_dailink process the devices on each link starting from device index adr_index. But adr_index is only meaningful on the first on these SoundWire links, as it is the index of the current device on that link. This means devices will be skipped on later links. Say for example the system looks like this: SDW0 - Codec (Not Aggregated), Amp 1 (Aggregated, Group 1) SDW1 - Amp 2 (Aggregated, Group 1), Amp 3 (Aggregated, Group 1) The code should create 2 DAI links, one for the CODEC and one for the aggregated amps. It will create the DAI link for the codec no problem. When it creates the DAI link for Group 1 however, create_sdw_dailink will be called with an adr_index of 1, since that is the index of Amp 1 on SDW0. However, as the loop in create_sdw_dailink moves onto SDW1 it will again start from adr_index, skipping Amp 2. Resulting in the amp DAI link only have amps 1 and 3 in it. It is reasonable to start at adr_index on the first link, since earlier devices have by definition already been processed. However, update the code when processing later links to handle all devices. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-9-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 0401516f35de..767c49022eae 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1366,6 +1366,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, return -ENOMEM; /* generate codec name on different links in the same group */ + j = adr_index; for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr && i < cpu_dai_num; adr_link_next++) { const struct snd_soc_acpi_endpoint *endpoints; @@ -1380,7 +1381,8 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) continue; - for (j = adr_index; j < adr_link_next->num_adr; j++) { + /* j reset after loop, adr_index only applies to first link */ + for (; j < adr_link_next->num_adr; j++) { int codec_index; u64 adr = adr_link_next->adr_d[j].adr; @@ -1412,6 +1414,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, codec_dlc_index++; (*codec_conf_index)++; } + j = 0; /* check next link to create codec dai in the processed group */ i++; -- cgit v1.2.3 From f82742dd479dfec7dc6a30a84f165a258c51ce09 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:11 +0100 Subject: ASoC: intel: sof_sdw: Support multiple groups on the same link The current code checks the first device on a link and assumes that all the other devices on the link will have the same endpoint aggregation status and endpoint group ID. Say for example a system looked like: SDW0 - Amp 1 (Aggregated, Group 1), Mic 1 (Aggregated, Group 2) SDW1 - Amp 2 (Aggregated, Group 1), Mic 2 (Aggregated, Group 2) The current code would create the DAI link for the aggregated amps, although it is worth noting that the only reason Mic 2 is not added is the additional check that aborts processing the link when the device changes. Then when processing the DAI link for the microphones, Mic 2 would not be added, as the check will only be done on the first device, which would be Amp 2 and thus the wrong group, causing the whole link to be skipped. Move the endpoint check to be for each device rather than the first device on each link. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-10-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 42 ++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 767c49022eae..357946365e76 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1288,25 +1288,24 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, } /* gather other link ID of slaves in the same group */ - for (adr_next = adr_link + 1; adr_next && adr_next->num_adr; - adr_next++) { - const struct snd_soc_acpi_endpoint *endpoint; - - endpoint = adr_next->adr_d->endpoints; - if (!endpoint->aggregated || - endpoint->group_id != *group_id) - continue; + for (adr_next = adr_link + 1; adr_next && adr_next->num_adr; adr_next++) { + unsigned int link_codecs = 0; - if (index >= SDW_MAX_CPU_DAIS) { - dev_err(dev, "cpu_dai_id array overflows\n"); - return -EINVAL; - } - - cpu_dai_id[index++] = ffs(adr_next->mask) - 1; for (i = 0; i < adr_next->num_adr; i++) { if (adr_next->adr_d[i].endpoints->aggregated && adr_next->adr_d[i].endpoints->group_id == *group_id) - (*codec_num)++; + link_codecs++; + } + + if (link_codecs) { + *codec_num += link_codecs; + + if (index >= SDW_MAX_CPU_DAIS) { + dev_err(dev, "cpu_dai_id array overflowed\n"); + return -EINVAL; + } + + cpu_dai_id[index++] = ffs(adr_next->mask) - 1; } } @@ -1369,20 +1368,15 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, j = adr_index; for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr && i < cpu_dai_num; adr_link_next++) { - const struct snd_soc_acpi_endpoint *endpoints; int _codec_index = -1; - endpoints = adr_link_next->adr_d->endpoints; - if (group_id && (!endpoints->aggregated || - endpoints->group_id != group_id)) - continue; - /* skip the link excluded by this processed group */ if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) continue; /* j reset after loop, adr_index only applies to first link */ for (; j < adr_link_next->num_adr; j++) { + const struct snd_soc_acpi_endpoint *endpoints; int codec_index; u64 adr = adr_link_next->adr_d[j].adr; @@ -1395,6 +1389,12 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, } _codec_index = codec_index; + endpoints = adr_link_next->adr_d[j].endpoints; + + if (group_id && (!endpoints->aggregated || + endpoints->group_id != group_id)) + continue; + /* sanity check */ if (*codec_conf_index >= codec_count) { dev_err(dev, "codec_conf array overflowed\n"); -- cgit v1.2.3 From 317dcdecaf7a42febb78c564df15fd817bf720b2 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:12 +0100 Subject: ASoC: intel: sof_sdw: Allow different devices on the same link If the current code encounters a new type of device on a SoundWire link, it will abort processing that link and move onto the next link. However, there is no reason to disallow this setup, it would appear this was being disallowed to work around issues introduced by only the first endpoint on each link being checked, which is now fixed. The device type shouldn't determine which DAI link it is connected to, the group ID and aggregation status should. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-11-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 357946365e76..296de5baee3d 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1163,10 +1163,15 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, static int fill_sdw_codec_dlc(struct device *dev, const struct snd_soc_acpi_link_adr *adr_link, struct snd_soc_dai_link_component *codec, - int codec_index, int adr_index, int dai_index) + int adr_index, int dai_index) { unsigned int sdw_version, unique_id, mfg_id, link_id, part_id, class_id; u64 adr = adr_link->adr_d[adr_index].adr; + int codec_index; + + codec_index = find_codec_info_part(adr); + if (codec_index < 0) + return codec_index; sdw_version = SDW_VERSION(adr); link_id = SDW_DISCO_LINK_ID(adr); @@ -1368,8 +1373,6 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, j = adr_index; for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr && i < cpu_dai_num; adr_link_next++) { - int _codec_index = -1; - /* skip the link excluded by this processed group */ if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) continue; @@ -1377,17 +1380,6 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, /* j reset after loop, adr_index only applies to first link */ for (; j < adr_link_next->num_adr; j++) { const struct snd_soc_acpi_endpoint *endpoints; - int codec_index; - u64 adr = adr_link_next->adr_d[j].adr; - - codec_index = find_codec_info_part(adr); - if (codec_index < 0) - return codec_index; - if (_codec_index != -1 && codec_index != _codec_index) { - dev_dbg(dev, "Different devices on the same sdw link\n"); - break; - } - _codec_index = codec_index; endpoints = adr_link_next->adr_d[j].endpoints; @@ -1403,7 +1395,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, ret = fill_sdw_codec_dlc(dev, adr_link_next, &codecs[codec_dlc_index], - codec_index, j, dai_index); + j, dai_index); if (ret) return ret; -- cgit v1.2.3 From 7f5cf19703ccb05ac4965d1cfc1422e38bec93aa Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Aug 2023 14:20:13 +0100 Subject: ASoC: intel: sof_sdw: Simplify get_slave_info Now the first device on a link is not treated specially there is no need to have a separate loop to handle the current link over the future links, as the logic is identical. Combine this all into a single processing loop. Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230808132013.889419-12-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 296de5baee3d..f283c0d528df 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1265,57 +1265,43 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, int *codec_num, unsigned int *group_id, int adr_index) { - const struct snd_soc_acpi_adr_device *adr_d; - const struct snd_soc_acpi_link_adr *adr_next; - bool no_aggregation; - int index = 0; + bool no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; int i; - no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; - adr_d = &adr_link->adr_d[adr_index]; - - cpu_dai_id[index++] = ffs(adr_link->mask) - 1; - if (!adr_d->endpoints->aggregated || no_aggregation) { + if (!adr_link->adr_d[adr_index].endpoints->aggregated || no_aggregation) { + cpu_dai_id[0] = ffs(adr_link->mask) - 1; *cpu_dai_num = 1; *codec_num = 1; *group_id = 0; return 0; } - *group_id = adr_d->endpoints->group_id; - - /* Count endpoints with the same group_id in the adr_link */ *codec_num = 0; - for (i = 0; i < adr_link->num_adr; i++) { - if (adr_link->adr_d[i].endpoints->aggregated && - adr_link->adr_d[i].endpoints->group_id == *group_id) - (*codec_num)++; - } + *cpu_dai_num = 0; + *group_id = adr_link->adr_d[adr_index].endpoints->group_id; - /* gather other link ID of slaves in the same group */ - for (adr_next = adr_link + 1; adr_next && adr_next->num_adr; adr_next++) { + /* Count endpoints with the same group_id in the adr_link */ + for (; adr_link && adr_link->num_adr; adr_link++) { unsigned int link_codecs = 0; - for (i = 0; i < adr_next->num_adr; i++) { - if (adr_next->adr_d[i].endpoints->aggregated && - adr_next->adr_d[i].endpoints->group_id == *group_id) + for (i = 0; i < adr_link->num_adr; i++) { + if (adr_link->adr_d[i].endpoints->aggregated && + adr_link->adr_d[i].endpoints->group_id == *group_id) link_codecs++; } if (link_codecs) { *codec_num += link_codecs; - if (index >= SDW_MAX_CPU_DAIS) { + if (*cpu_dai_num >= SDW_MAX_CPU_DAIS) { dev_err(dev, "cpu_dai_id array overflowed\n"); return -EINVAL; } - cpu_dai_id[index++] = ffs(adr_next->mask) - 1; + cpu_dai_id[(*cpu_dai_num)++] = ffs(adr_link->mask) - 1; } } - *cpu_dai_num = index; - return 0; } -- cgit v1.2.3 From 87b56172431bc2e8c497d2f10ee8245313167bd9 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 8 Aug 2023 14:56:54 +0200 Subject: ASoC: codecs: aw88261: avoid uninitialized variable warning aw88261_reg_update() returns an unintialized error code in the success path: sound/soc/codecs/aw88261.c:651:7: error: variable 'ret' is used uninitialized whenever 'if' condition is false [-Werror,-Wsometimes-uninitialized] if (aw_dev->prof_cur != aw_dev->prof_index) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sound/soc/codecs/aw88261.c:660:9: note: uninitialized use occurs here return ret; ^~~ sound/soc/codecs/aw88261.c:651:3: note: remove the 'if' if its condition is always true if (aw_dev->prof_cur != aw_dev->prof_index) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Return zero instead here. Fixes: 028a2ae256916 ("ASoC: codecs: Add aw88261 amplifier driver") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20230808125703.1611325-1-arnd@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/aw88261.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c index 82923b454dd4..6e2266b71386 100644 --- a/sound/soc/codecs/aw88261.c +++ b/sound/soc/codecs/aw88261.c @@ -652,6 +652,8 @@ static int aw88261_reg_update(struct aw88261 *aw88261, bool force) ret = aw88261_dev_fw_update(aw88261); if (ret) return ret; + } else { + ret = 0; } } -- cgit v1.2.3 From a932f45a1832d18fb64704636a958ef993a1d1da Mon Sep 17 00:00:00 2001 From: Yu Liao Date: Tue, 8 Aug 2023 21:25:19 +0800 Subject: ASoC: pxa: address unused variable warning gcc with W=1 reports sound/soc/pxa/pxa-ssp.c:594:15: warning: variable 'acds' set but not used [-Wunused-but-set-variable] ^ This variable is not used so remove it. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202308040619.BEismjFv-lkp@intel.com/ Signed-off-by: Yu Liao Link: https://lore.kernel.org/r/20230808132519.637452-1-liaoyu15@huawei.com Signed-off-by: Mark Brown --- sound/soc/pxa/pxa-ssp.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 430dd446321e..d19769dde139 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -591,7 +591,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, if (ret < 0) { const struct pxa_ssp_clock_mode *m; - int ssacd, acds; + int ssacd; for (m = pxa_ssp_clock_modes; m->rate; m++) { if (m->rate == rate) @@ -601,12 +601,6 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, if (!m->rate) return -EINVAL; - acds = m->acds; - - /* The values in the table are for 16 bits */ - if (width == 32) - acds--; - ret = pxa_ssp_set_pll(priv, bclk); if (ret < 0) return ret; -- cgit v1.2.3 From ebd0f7b08e032900e5327962f7da6bed6f37feb6 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 8 Aug 2023 17:46:58 +0100 Subject: ASoC: cs35l56: Avoid uninitialized variable in cs35l56_set_asp_slot_positions() Re-implement setting of ASP TDM slots so that only the common loop to build the register word is factored out. The original cs35l56_set_asp_slot_positions() had an apparent uninitialized variable if the passed register address was neither of the ASP slot registers. In fact this would never happen because the calling code passed valid registers. While it's trivial to initialize the variable or add a default case, actually the only common code was the loop at the end of the function, which simply manipulates some mask values and is identical for either register. Factoring out the regmap_write() didn't really gain anything. So instead re-implement the code to replace the original function with cs35l56_make_tdm_config_word() that only does the loop, and change the calling code to call regmap_write() directly. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230808164702.21272-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 19b6b4fbe5de..be400208205a 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -358,22 +358,11 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f return 0; } -static void cs35l56_set_asp_slot_positions(struct cs35l56_private *cs35l56, - unsigned int reg, unsigned long mask) +static unsigned int cs35l56_make_tdm_config_word(unsigned int reg_val, unsigned long mask) { - unsigned int reg_val, channel_shift; + unsigned int channel_shift; int bit_num; - /* Init all slots to 63 */ - switch (reg) { - case CS35L56_ASP1_FRAME_CONTROL1: - reg_val = 0x3f3f3f3f; - break; - case CS35L56_ASP1_FRAME_CONTROL5: - reg_val = 0x3f3f3f; - break; - } - /* Enable consecutive TX1..TXn for each of the slots set in mask */ channel_shift = 0; for_each_set_bit(bit_num, &mask, 32) { @@ -382,7 +371,7 @@ static void cs35l56_set_asp_slot_positions(struct cs35l56_private *cs35l56, channel_shift += 8; } - regmap_write(cs35l56->base.regmap, reg, reg_val); + return reg_val; } static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, @@ -418,8 +407,11 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx if (rx_mask == 0) rx_mask = 0xf; // ASPTX1..TX4 in slots 0..3 - cs35l56_set_asp_slot_positions(cs35l56, CS35L56_ASP1_FRAME_CONTROL1, rx_mask); - cs35l56_set_asp_slot_positions(cs35l56, CS35L56_ASP1_FRAME_CONTROL5, tx_mask); + /* Default unused slots to 63 */ + regmap_write(cs35l56->base.regmap, CS35L56_ASP1_FRAME_CONTROL1, + cs35l56_make_tdm_config_word(0x3f3f3f3f, rx_mask)); + regmap_write(cs35l56->base.regmap, CS35L56_ASP1_FRAME_CONTROL5, + cs35l56_make_tdm_config_word(0x3f3f3f, tx_mask)); 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); -- cgit v1.2.3 From 853734588dcb1bf4c41a17e4d9df231965e559db Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 8 Aug 2023 17:46:59 +0100 Subject: ASoC: cs35l56: Don't rely on GPIOD_OUT_LOW to set RESET initially low The ACPI setting for a GPIO default state has higher priority than the flag passed to devm_gpiod_get_optional() so ACPI can override the GPIOD_OUT_LOW. Explicitly set the GPIO low when hard resetting. Although GPIOD_OUT_LOW can't be relied on this doesn't seem like a reason to stop passing it to devm_gpiod_get_optional(). So we still pass it to state our intent, but can deal with it having no effect. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230808164702.21272-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index be400208205a..9560059c867b 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -1069,6 +1069,8 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56) return dev_err_probe(cs35l56->base.dev, ret, "Failed to enable supplies\n"); if (cs35l56->base.reset_gpio) { + /* ACPI can override GPIOD_OUT_LOW flag so force it to start low */ + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); cs35l56_wait_min_reset_pulse(); gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1); } -- cgit v1.2.3 From f5eb9503e80e70c22e3d3f73a5d3c149c132407f Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 8 Aug 2023 17:47:00 +0100 Subject: ASoC: cs35l56: Wait for control port ready during system-resume The CS35L56 could be hard-reset during a system suspend-resume cycle, either by the codec driver, in cs35l56_system_resume_early(), or by ACPI. After a hard reset the driver must wait for the control port to be ready (datasheet tIRS time) before attempting to access the CS35L56. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230808164702.21272-4-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 9560059c867b..094bcbd0a174 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -952,6 +952,12 @@ int cs35l56_system_resume(struct device *dev) dev_dbg(dev, "system_resume\n"); + /* + * We might have done a hard reset or the CS35L56 was power-cycled + * so wait for control port to be ready. + */ + cs35l56_wait_control_port_ready(); + /* Undo pm_runtime_force_suspend() before re-enabling the irq */ ret = pm_runtime_force_resume(dev); if (cs35l56->base.irq) -- cgit v1.2.3 From d0a3a6ad0d3b24578f1b3832ad1d7fbdb20f7a20 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Tue, 8 Aug 2023 17:47:01 +0100 Subject: ASoC: wm_adsp: Expose the DSP power down actions as wm_adsp_power_down() To support self-booting DSPs that operate outside of a conventional DAPM event life cycle expose a companion function to wm_adsp_power_up() so that the correct state of the DSP firmware and controls can be recorded. Signed-off-by: Simon Trimmer Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230808164702.21272-5-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 8 +++++++- sound/soc/codecs/wm_adsp.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 5a89abfe8784..13f500fa9a5f 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -1025,6 +1025,12 @@ int wm_adsp_power_up(struct wm_adsp *dsp) } EXPORT_SYMBOL_GPL(wm_adsp_power_up); +void wm_adsp_power_down(struct wm_adsp *dsp) +{ + cs_dsp_power_down(&dsp->cs_dsp); +} +EXPORT_SYMBOL_GPL(wm_adsp_power_down); + static void wm_adsp_boot_work(struct work_struct *work) { struct wm_adsp *dsp = container_of(work, @@ -1046,7 +1052,7 @@ int wm_adsp_early_event(struct snd_soc_dapm_widget *w, queue_work(system_unbound_wq, &dsp->boot_work); break; case SND_SOC_DAPM_PRE_PMD: - cs_dsp_power_down(&dsp->cs_dsp); + wm_adsp_power_down(dsp); break; default: break; diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 769904d34a87..3044f964ac14 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -92,6 +92,7 @@ int wm_adsp_early_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); int wm_adsp_power_up(struct wm_adsp *dsp); +void wm_adsp_power_down(struct wm_adsp *dsp); irqreturn_t wm_adsp2_bus_error(int irq, void *data); irqreturn_t wm_halo_bus_error(int irq, void *data); -- cgit v1.2.3 From e24ef967c735bf7272099610e422f964c0a4258b Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Tue, 8 Aug 2023 17:47:02 +0100 Subject: ASoC: cs35l56: Call wm_adsp_power_down() before reloading firmware When cs35l56_system_resume() needs to reload firmware it should call wm_adsp_power_down() to put cs_dsp into a powered-down state before cs35l56_secure_patch() or cs35l56_patch() calls wm_adsp_power_up(). Signed-off-by: Simon Trimmer Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230808164702.21272-6-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 094bcbd0a174..80e7fddae926 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -976,6 +976,7 @@ int cs35l56_system_resume(struct device *dev) return ret; cs35l56->base.fw_patched = false; + wm_adsp_power_down(&cs35l56->dsp); queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work); /* -- cgit v1.2.3 From 1a5ca2aad7b907f9d7101eaba7dfa068b2da3bdd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 9 Aug 2023 01:07:45 +0000 Subject: ASoC: rsnd: call of_node_put() when break We need to call of_node_put() when break from for_each_child_of_node(). This patch add missing of_node_put(). Reported-by: kernel test robot Reported-by: Julia Lawall Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87bkfh9g68.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 9f3d97bc177a..cf2031b7e209 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1293,6 +1293,7 @@ static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph) i++; if (i >= RSND_MAX_COMPONENT) { dev_info(dev, "reach to max component\n"); + of_node_put(node); break; } } @@ -1312,6 +1313,7 @@ audio_graph: i++; if (i >= RSND_MAX_COMPONENT) { dev_info(dev, "reach to max component\n"); + of_node_put(node); break; } } -- cgit v1.2.3 From 48c6253fefa38556e0c5c2942edd9181529407e4 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 9 Aug 2023 12:04:46 +0200 Subject: ASoC: samsung: midas_wm1811: Fix 'Headphone Switch' control creation 'Headphone Switch' control is already registered from sound/soc/codecs/wm_hubs.c:479, so duplicating it in midas_wm1811 causes following probe failure: midas-audio sound: control 2:0:0:Headphone Switch:0 is already present midas-audio sound: ASoC: Failed to add Headphone Switch: -16 midas-audio sound: Failed to register card: -16 midas-audio: probe of sound failed with error -16 Fix this by dropping duplicated control. Fixes: d27224a45e54 ("ASoC: samsung: midas_wm1811: Map missing jack kcontrols") Signed-off-by: Marek Szyprowski Link: https://lore.kernel.org/r/20230809100446.2105825-1-m.szyprowski@samsung.com Signed-off-by: Mark Brown --- sound/soc/samsung/midas_wm1811.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c index 44b32f5cddca..126098fdcf1b 100644 --- a/sound/soc/samsung/midas_wm1811.c +++ b/sound/soc/samsung/midas_wm1811.c @@ -257,7 +257,6 @@ static const struct snd_kcontrol_new midas_controls[] = { SOC_DAPM_PIN_SWITCH("Main Mic"), SOC_DAPM_PIN_SWITCH("Sub Mic"), SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("FM In"), }; -- cgit v1.2.3 From 9c28423d3caae63e665e2b8d704fa41ac823b2a6 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 9 Aug 2023 11:12:07 -0700 Subject: ASoC: SOF: Intel: Initialize chip in hda_sdw_check_wakeen_irq() Clang warns (or errors with CONFIG_WERROR): sound/soc/sof/intel/hda.c:423:6: error: variable 'chip' is uninitialized when used here [-Werror,-Wuninitialized] 423 | if (chip && chip->check_sdw_wakeen_irq) | ^~~~ sound/soc/sof/intel/hda.c:418:39: note: initialize the variable 'chip' to silence this warning 418 | const struct sof_intel_dsp_desc *chip; | ^ | = NULL 1 error generated. Add the missing initialization, following the pattern of the other irq functions. Fixes: 9362ab78f175 ("ASoC: SOF: Intel: add abstraction for SoundWire wake-ups") Signed-off-by: Nathan Chancellor Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230809-intel-hda-missing-chip-init-v1-1-61557ca6fa8a@kernel.org Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 04c748a72b13..15e6779efaa3 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -420,6 +420,7 @@ static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH))) return false; + chip = get_chip_info(sdev->pdata); if (chip && chip->check_sdw_wakeen_irq) return chip->check_sdw_wakeen_irq(sdev); -- cgit v1.2.3 From ff7a0b4016cb349f9148d0bf9c664e604167128c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 9 Aug 2023 09:26:31 +0900 Subject: 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 (limited to 'sound') 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 -- cgit v1.2.3 From 927073ee468d9d9f7ef0fe1eb777a673120e7caa Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 10 Aug 2023 09:27:45 +0000 Subject: ASoC: rt715: Add software reset in io init Add software reset before setting preset registers to make sure all the registers are the default value before preset. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/4f405c7deb9642e1a8599c5f103b5759@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt715.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt715.h | 7 ++++++ 2 files changed, 63 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 79416bb48814..c95f481cd235 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -52,6 +52,60 @@ static int rt715_index_write(struct regmap *regmap, unsigned int reg, return ret; } +static int rt715_index_write_nid(struct regmap *regmap, + unsigned int nid, unsigned int reg, unsigned int value) +{ + int ret; + unsigned int addr = ((RT715_PRIV_INDEX_W_H_2 | nid) << 8) | reg; + + ret = regmap_write(regmap, addr, value); + if (ret < 0) + pr_err("Failed to set private value: %06x <= %04x ret=%d\n", + addr, value, ret); + + return ret; +} + +static int rt715_index_read_nid(struct regmap *regmap, + unsigned int nid, unsigned int reg, unsigned int *value) +{ + int ret; + unsigned int addr = ((RT715_PRIV_INDEX_W_H_2 | nid) << 8) | reg; + + *value = 0; + ret = regmap_read(regmap, addr, value); + if (ret < 0) + pr_err("Failed to get private value: %06x => %04x ret=%d\n", + addr, *value, ret); + + return ret; +} + +static int rt715_index_update_bits(struct regmap *regmap, unsigned int nid, + unsigned int reg, unsigned int mask, unsigned int val) +{ + unsigned int tmp, orig; + int ret; + + ret = rt715_index_read_nid(regmap, nid, reg, &orig); + if (ret < 0) + return ret; + + tmp = orig & ~mask; + tmp |= val & mask; + + return rt715_index_write_nid(regmap, nid, reg, tmp); +} + +static void rt715_reset(struct regmap *regmap) +{ + regmap_write(regmap, RT715_FUNC_RESET, 0); + rt715_index_update_bits(regmap, RT715_VENDOR_REGISTERS, + RT715_VD_CLEAR_CTRL, RT715_CLEAR_HIDDEN_REG, + RT715_CLEAR_HIDDEN_REG); +} + + static void rt715_get_gain(struct rt715_priv *rt715, unsigned int addr_h, unsigned int addr_l, unsigned int val_h, unsigned int *r_val, unsigned int *l_val) @@ -1040,6 +1094,8 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave) pm_runtime_get_noresume(&slave->dev); + rt715_reset(rt715->regmap); + /* Mute nid=08h/09h */ regmap_write(rt715->regmap, RT715_SET_GAIN_LINE_ADC_H, 0xb080); regmap_write(rt715->regmap, RT715_SET_GAIN_MIX_ADC_H, 0xb080); diff --git a/sound/soc/codecs/rt715.h b/sound/soc/codecs/rt715.h index 12a0ae656d09..6e37bf64e12f 100644 --- a/sound/soc/codecs/rt715.h +++ b/sound/soc/codecs/rt715.h @@ -48,6 +48,7 @@ struct rt715_priv { #define RT715_INLINE_CMD 0x55 /* Index (NID:20h) */ +#define RT715_VD_CLEAR_CTRL 0x01 #define RT715_SDW_INPUT_SEL 0x39 #define RT715_EXT_DMIC_CLK_CTRL2 0x54 @@ -71,6 +72,8 @@ struct rt715_priv { #define RT715_READ_HDA_0 0x2015 #define RT715_PRIV_INDEX_W_H 0x7520 #define RT715_PRIV_INDEX_W_L 0x85a0 +#define RT715_PRIV_INDEX_W_H_2 0x7500 +#define RT715_PRIV_INDEX_W_L_2 0x8580 #define RT715_PRIV_DATA_W_H 0x7420 #define RT715_PRIV_DATA_W_L 0x84a0 #define RT715_PRIV_INDEX_R_H 0x9d20 @@ -198,6 +201,10 @@ struct rt715_priv { #define RT715_SET_DMIC4_CONFIG_DEFAULT4\ (RT715_VERB_SET_CONFIG_DEFAULT4 | RT715_DMIC4) +/* vendor register clear ctrl-1 (0x01)(NID:20h) */ +#define RT715_CLEAR_HIDDEN_REG (0x1 << 15) + + #define RT715_MUTE_SFT 7 #define RT715_DIR_IN_SFT 6 #define RT715_DIR_OUT_SFT 7 -- cgit v1.2.3 From 061599c8285848fe4ec64becb278dcdd60dd3369 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 10 Aug 2023 08:55:55 +0800 Subject: ASoC: SOF: Intel: Remove duplicated include in lnl.c ./sound/soc/sof/intel/lnl.c: hda.h is included more than once. Signed-off-by: Yang Li Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230810005555.4610-1-yang.lee@linux.alibaba.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/lnl.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c index 3d919b0b6891..db94b45e53af 100644 --- a/sound/soc/sof/intel/lnl.c +++ b/sound/soc/sof/intel/lnl.c @@ -16,7 +16,6 @@ #include "hda-ipc.h" #include "../sof-audio.h" #include "mtl.h" -#include "hda.h" #include /* LunarLake ops */ -- cgit v1.2.3 From bb6979c5ac592e11b456da728f645c9bea965489 Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Fri, 11 Aug 2023 18:01:30 +0800 Subject: ASoC: q6dsp: Remove unused declaration Commit 5477518b8a0e ("ASoC: qdsp6: audioreach: add q6apm support") declared but never implemented these. Signed-off-by: Yue Haibing Date: Fri, 11 Aug 2023 19:00:21 +0800 Subject: ASoC: cygnus: Remove unused declarations Commit a6ee05d94e8f ("ASoC: cygnus: Add Cygnus audio DAI driver") declared but never implemented these. Signed-off-by: Yue Haibing Date: Fri, 11 Aug 2023 15:14:22 +0800 Subject: ASoC: atmel: Remove redundant of_match_ptr() The driver depends on CONFIG_OF, it is not necessary to use of_match_ptr() here. Signed-off-by: Ruan Jinjie Date: Fri, 11 Aug 2023 15:14:23 +0800 Subject: ASoC: atmel: tse850-pcm5142: Remove redundant of_match_ptr() The driver depends on CONFIG_OF, it is not necessary to use of_match_ptr() here. Signed-off-by: Ruan Jinjie Date: Fri, 11 Aug 2023 15:14:24 +0800 Subject: ASoC: sunxi: sun4i-spdif: Remove redundant of_match_ptr() The driver depends on CONFIG_OF, it is not necessary to use of_match_ptr() here. Signed-off-by: Ruan Jinjie Date: Fri, 11 Aug 2023 15:14:25 +0800 Subject: ASoC: ssm3515: Remove redundant of_match_ptr() The driver depends on CONFIG_OF, it is not necessary to use of_match_ptr() here. Signed-off-by: Ruan Jinjie Date: Fri, 11 Aug 2023 15:14:26 +0800 Subject: ALSA: Remove redundant of_match_ptr() The driver depends on CONFIG_OF, it is not necessary to use of_match_ptr() here. Signed-off-by: Ruan Jinjie Date: Sat, 12 Aug 2023 21:56:39 +0200 Subject: ASoC: rt1011: Drop GPIO includes This driver include two GPIO legacy headers yet doesn't use symbols from any of them. Drop the includes. Signed-off-by: Linus Walleij #include #include -#include #include #include #include -#include #include #include #include -- cgit v1.2.3 From c7a7f4444b1fd648edc3fb54f2d3822215b46c56 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:40 +0200 Subject: ASoC: rt1015: Drop GPIO include This driver include the GPIO legacy header #include #include -#include #include #include #include -- cgit v1.2.3 From 3abc7076851f63c5d193ee9d942554f182527d18 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:41 +0200 Subject: ASoC: rt1015p: Drop legacy GPIO include This driver include the GPIO legacy header #include #include -#include #include #include #include -- cgit v1.2.3 From 8a5a8015b1e23e41204738f2147c01bf18039965 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:42 +0200 Subject: ASoC: rt1016: Drop GPIO include This driver include the GPIO legacy header #include #include -#include #include #include #include -- cgit v1.2.3 From e04cbe53205ecfcb1f2a8314dfc829ebbcb542f1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:43 +0200 Subject: ASoC: rt1019: Drop GPIO include This driver include the GPIO legacy header #include #include -#include #include #include #include -- cgit v1.2.3 From ba55dde45b5a5595763af6d06066ab789792e9d3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:44 +0200 Subject: ASoC: rt1305: Drop GPIO includes This driver include two GPIO legacy headers yet doesn't use symbols from any of them. Drop the includes. Signed-off-by: Linus Walleij #include #include -#include #include #include -#include #include #include #include -- cgit v1.2.3 From f36c684e9941b3af6769b984239f62dc9fe99698 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:45 +0200 Subject: ASoC: rt1308: Drop GPIO includes This driver include two GPIO legacy headers yet doesn't use symbols from any of them. Drop the includes. Signed-off-by: Linus Walleij #include #include -#include #include #include -#include #include #include #include -- cgit v1.2.3 From 12ffd88e398cb82f960da25ab990a6864641fee1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:46 +0200 Subject: ASoC: rt5514-spi: Drop GPIO include This driver include the GPIO legacy header #include #include -#include #include #include #include -- cgit v1.2.3 From 9fdc4feacdb0a5b3a49d611aff88371f8f8d4971 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:47 +0200 Subject: ASoC: rt5514: Drop GPIO include This driver include the GPIO legacy header #include #include -#include #include #include #include -- cgit v1.2.3 From 92f1b48277f2fdaa9649630dc9a8ec298bfd6def Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:48 +0200 Subject: ASoC: rt5645: Drop legacy GPIO include This driver include the GPIO legacy header #include #include -#include #include #include #include -- cgit v1.2.3 From 0b759f3b3faa51022752bc4a99ae1af57baf344f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:49 +0200 Subject: ASoC: rt5659: Drop legacy GPIO include This driver include the GPIO legacy header #include #include -#include #include #include #include -- cgit v1.2.3 From b72a4dc2bede787221a4b1b2e3860f6725f109b5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:50 +0200 Subject: ASoC: rt5660: Drop GPIO includes This driver include two GPIO legacy headers yet doesn't use symbols from any of them. Drop the includes. Signed-off-by: Linus Walleij #include #include -#include #include #include #include -#include #include #include #include -- cgit v1.2.3 From 1a625a7a5d74be6b367301e6eb9e38d35797313a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:51 +0200 Subject: ASoC: rt5682-sdw: Drop GPIO includes This driver include two GPIO legacy headers yet doesn't use symbols from any of them. Drop the includes. Signed-off-by: Linus Walleij #include #include -#include -#include #include #include #include -- cgit v1.2.3 From 797df2a670c336500cdea482f404a24b45b28f45 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Aug 2023 21:56:52 +0200 Subject: ASoC: rt715: Drop GPIO includes This driver include two GPIO legacy headers and one contemporary, yet doesn't use symbols from any of them. Drop the includes. Signed-off-by: Linus Walleij #include #include -#include #include #include #include #include -#include #include -#include #include #include #include -- cgit v1.2.3 From 624fee45111d587ab346b2fc3bcc316615fd97e8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:54:50 +0000 Subject: ASoC: soc-dai.h: merge DAI call back functions into ops snd_soc_dai_driver has .ops for call back functions (A), but it also has other call back functions (B). It is duplicated and confusable. struct snd_soc_dai_driver { ... ^ int (*probe)(...); | int (*remove)(...); (B) int (*compress_new)(...); | int (*pcm_new)(...); v ... (A) const struct snd_soc_dai_ops *ops; ... } This patch merges (B) into (A). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87v8dpb0w6.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 2 +- sound/soc/soc-core.c | 25 ++++++++++++++++++++ sound/soc/soc-dai.c | 44 ++++++++++++++++++++---------------- 3 files changed, 51 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 0b8258b6bd8e..13693ef9c242 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -60,7 +60,7 @@ static bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc) struct snd_soc_dai *dai = snd_soc_find_dai_with_mutex(dlc); if (dai && (dai->component->driver->pcm_construct || - dai->driver->pcm_new)) + (dai->driver->ops && dai->driver->ops->pcm_new))) return true; return false; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a5b96c17633a..7dbf37e0ba2f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2510,6 +2510,7 @@ struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, { struct device *dev = component->dev; struct snd_soc_dai *dai; + struct snd_soc_dai_ops *ops; /* REMOVE ME */ lockdep_assert_held(&client_mutex); @@ -2538,6 +2539,30 @@ struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, if (!dai->name) return NULL; + /* REMOVE ME */ + if (dai_drv->probe || + dai_drv->remove || + dai_drv->compress_new || + dai_drv->pcm_new || + dai_drv->probe_order || + dai_drv->remove_order) { + + ops = devm_kzalloc(dev, sizeof(struct snd_soc_dai_ops), GFP_KERNEL); + if (!ops) + return NULL; + if (dai_drv->ops) + memcpy(ops, dai_drv->ops, sizeof(struct snd_soc_dai_ops)); + + ops->probe = dai_drv->probe; + ops->remove = dai_drv->remove; + ops->compress_new = dai_drv->compress_new; + ops->pcm_new = dai_drv->pcm_new; + ops->probe_order = dai_drv->probe_order; + ops->remove_order = dai_drv->remove_order; + + dai_drv->ops = ops; + } + dai->component = component; dai->dev = dev; dai->driver = dai_drv; diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 73a97ac6ccb8..3f33f0630ad8 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -460,8 +460,9 @@ int snd_soc_dai_compress_new(struct snd_soc_dai *dai, struct snd_soc_pcm_runtime *rtd, int num) { int ret = -ENOTSUPP; - if (dai->driver->compress_new) - ret = dai->driver->compress_new(rtd, num); + if (dai->driver->ops && + dai->driver->ops->compress_new) + ret = dai->driver->ops->compress_new(rtd, num); return soc_dai_ret(dai, ret); } @@ -545,19 +546,20 @@ int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order) int i; for_each_rtd_dais(rtd, i, dai) { - if (dai->driver->probe_order != order) - continue; - if (dai->probed) continue; - if (dai->driver->probe) { - int ret = dai->driver->probe(dai); + if (dai->driver->ops) { + if (dai->driver->ops->probe_order != order) + continue; - if (ret < 0) - return soc_dai_ret(dai, ret); - } + if (dai->driver->ops->probe) { + int ret = dai->driver->ops->probe(dai); + if (ret < 0) + return soc_dai_ret(dai, ret); + } + } dai->probed = 1; } @@ -570,16 +572,19 @@ int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order) int i, r, ret = 0; for_each_rtd_dais(rtd, i, dai) { - if (dai->driver->remove_order != order) + if (!dai->probed) continue; - if (dai->probed && - dai->driver->remove) { - r = dai->driver->remove(dai); - if (r < 0) - ret = r; /* use last error */ - } + if (dai->driver->ops) { + if (dai->driver->ops->remove_order != order) + continue; + if (dai->driver->ops->remove) { + r = dai->driver->ops->remove(dai); + if (r < 0) + ret = r; /* use last error */ + } + } dai->probed = 0; } @@ -592,8 +597,9 @@ int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd) int i; for_each_rtd_dais(rtd, i, dai) { - if (dai->driver->pcm_new) { - int ret = dai->driver->pcm_new(rtd, dai); + if (dai->driver->ops && + dai->driver->ops->pcm_new) { + int ret = dai->driver->ops->pcm_new(rtd, dai); if (ret < 0) return soc_dai_ret(dai, ret); } -- cgit v1.2.3 From dd9d64de8ea66def69ff684a755652d6ef15d7ee Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:54:59 +0000 Subject: ASoC: ti: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ttt9b0vw.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-i2s.c | 22 +++++++++++----------- sound/soc/ti/davinci-mcasp.c | 27 +++++++++++++-------------- sound/soc/ti/omap-dmic.c | 22 +++++++++++----------- sound/soc/ti/omap-mcbsp.c | 28 ++++++++++++++-------------- sound/soc/ti/omap-mcpdm.c | 22 +++++++++++----------- 5 files changed, 60 insertions(+), 61 deletions(-) (limited to 'sound') diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c index 97dd1634b6be..07c8b2259208 100644 --- a/sound/soc/ti/davinci-i2s.c +++ b/sound/soc/ti/davinci-i2s.c @@ -601,16 +601,6 @@ static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, #define DAVINCI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S32_LE) -static const struct snd_soc_dai_ops davinci_i2s_dai_ops = { - .shutdown = davinci_i2s_shutdown, - .prepare = davinci_i2s_prepare, - .trigger = davinci_i2s_trigger, - .hw_params = davinci_i2s_hw_params, - .set_fmt = davinci_i2s_set_dai_fmt, - .set_clkdiv = davinci_i2s_dai_set_clkdiv, - -}; - static int davinci_i2s_dai_probe(struct snd_soc_dai *dai) { struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); @@ -622,8 +612,18 @@ static int davinci_i2s_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops davinci_i2s_dai_ops = { + .probe = davinci_i2s_dai_probe, + .shutdown = davinci_i2s_shutdown, + .prepare = davinci_i2s_prepare, + .trigger = davinci_i2s_trigger, + .hw_params = davinci_i2s_hw_params, + .set_fmt = davinci_i2s_set_dai_fmt, + .set_clkdiv = davinci_i2s_dai_set_clkdiv, + +}; + static struct snd_soc_dai_driver davinci_i2s_dai = { - .probe = davinci_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 172fea764a31..7e7d665a5504 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -1616,18 +1616,6 @@ static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream, } } -static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { - .startup = davinci_mcasp_startup, - .shutdown = davinci_mcasp_shutdown, - .trigger = davinci_mcasp_trigger, - .delay = davinci_mcasp_delay, - .hw_params = davinci_mcasp_hw_params, - .set_fmt = davinci_mcasp_set_dai_fmt, - .set_clkdiv = davinci_mcasp_set_clkdiv, - .set_sysclk = davinci_mcasp_set_sysclk, - .set_tdm_slot = davinci_mcasp_set_tdm_slot, -}; - static int davinci_mcasp_iec958_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1716,6 +1704,19 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { + .probe = davinci_mcasp_dai_probe, + .startup = davinci_mcasp_startup, + .shutdown = davinci_mcasp_shutdown, + .trigger = davinci_mcasp_trigger, + .delay = davinci_mcasp_delay, + .hw_params = davinci_mcasp_hw_params, + .set_fmt = davinci_mcasp_set_dai_fmt, + .set_clkdiv = davinci_mcasp_set_clkdiv, + .set_sysclk = davinci_mcasp_set_sysclk, + .set_tdm_slot = davinci_mcasp_set_tdm_slot, +}; + #define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000 #define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \ @@ -1732,7 +1733,6 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) static struct snd_soc_dai_driver davinci_mcasp_dai[] = { { .name = "davinci-mcasp.0", - .probe = davinci_mcasp_dai_probe, .playback = { .stream_name = "IIS Playback", .channels_min = 1, @@ -1753,7 +1753,6 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { }, { .name = "davinci-mcasp.1", - .probe = davinci_mcasp_dai_probe, .playback = { .stream_name = "DIT Playback", .channels_min = 1, diff --git a/sound/soc/ti/omap-dmic.c b/sound/soc/ti/omap-dmic.c index cb60af36dbc3..5b5eccf303ab 100644 --- a/sound/soc/ti/omap-dmic.c +++ b/sound/soc/ti/omap-dmic.c @@ -401,15 +401,6 @@ static int omap_dmic_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, return -EINVAL; } -static const struct snd_soc_dai_ops omap_dmic_dai_ops = { - .startup = omap_dmic_dai_startup, - .shutdown = omap_dmic_dai_shutdown, - .hw_params = omap_dmic_dai_hw_params, - .prepare = omap_dmic_dai_prepare, - .trigger = omap_dmic_dai_trigger, - .set_sysclk = omap_dmic_set_dai_sysclk, -}; - static int omap_dmic_probe(struct snd_soc_dai *dai) { struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); @@ -438,10 +429,19 @@ static int omap_dmic_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops omap_dmic_dai_ops = { + .probe = omap_dmic_probe, + .remove = omap_dmic_remove, + .startup = omap_dmic_dai_startup, + .shutdown = omap_dmic_dai_shutdown, + .hw_params = omap_dmic_dai_hw_params, + .prepare = omap_dmic_dai_prepare, + .trigger = omap_dmic_dai_trigger, + .set_sysclk = omap_dmic_set_dai_sysclk, +}; + static struct snd_soc_dai_driver omap_dmic_dai = { .name = "omap-dmic", - .probe = omap_dmic_probe, - .remove = omap_dmic_remove, .capture = { .channels_min = 2, .channels_max = 6, diff --git a/sound/soc/ti/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c index f9fe96b61852..fdabed5133e8 100644 --- a/sound/soc/ti/omap-mcbsp.c +++ b/sound/soc/ti/omap-mcbsp.c @@ -1254,18 +1254,6 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, return err; } -static const struct snd_soc_dai_ops mcbsp_dai_ops = { - .startup = omap_mcbsp_dai_startup, - .shutdown = omap_mcbsp_dai_shutdown, - .prepare = omap_mcbsp_dai_prepare, - .trigger = omap_mcbsp_dai_trigger, - .delay = omap_mcbsp_dai_delay, - .hw_params = omap_mcbsp_dai_hw_params, - .set_fmt = omap_mcbsp_dai_set_dai_fmt, - .set_clkdiv = omap_mcbsp_dai_set_clkdiv, - .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, -}; - static int omap_mcbsp_probe(struct snd_soc_dai *dai) { struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai); @@ -1288,9 +1276,21 @@ static int omap_mcbsp_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mcbsp_dai_ops = { + .probe = omap_mcbsp_probe, + .remove = omap_mcbsp_remove, + .startup = omap_mcbsp_dai_startup, + .shutdown = omap_mcbsp_dai_shutdown, + .prepare = omap_mcbsp_dai_prepare, + .trigger = omap_mcbsp_dai_trigger, + .delay = omap_mcbsp_dai_delay, + .hw_params = omap_mcbsp_dai_hw_params, + .set_fmt = omap_mcbsp_dai_set_dai_fmt, + .set_clkdiv = omap_mcbsp_dai_set_clkdiv, + .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, +}; + static struct snd_soc_dai_driver omap_mcbsp_dai = { - .probe = omap_mcbsp_probe, - .remove = omap_mcbsp_remove, .playback = { .channels_min = 1, .channels_max = 16, diff --git a/sound/soc/ti/omap-mcpdm.c b/sound/soc/ti/omap-mcpdm.c index 35deceb73427..d7d9f708f1fd 100644 --- a/sound/soc/ti/omap-mcpdm.c +++ b/sound/soc/ti/omap-mcpdm.c @@ -404,13 +404,6 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = { - .startup = omap_mcpdm_dai_startup, - .shutdown = omap_mcpdm_dai_shutdown, - .hw_params = omap_mcpdm_dai_hw_params, - .prepare = omap_mcpdm_prepare, -}; - static int omap_mcpdm_probe(struct snd_soc_dai *dai) { struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); @@ -457,6 +450,17 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = { + .probe = omap_mcpdm_probe, + .remove = omap_mcpdm_remove, + .startup = omap_mcpdm_dai_startup, + .shutdown = omap_mcpdm_dai_shutdown, + .hw_params = omap_mcpdm_dai_hw_params, + .prepare = omap_mcpdm_prepare, + .probe_order = SND_SOC_COMP_ORDER_LATE, + .remove_order = SND_SOC_COMP_ORDER_EARLY, +}; + #ifdef CONFIG_PM_SLEEP static int omap_mcpdm_suspend(struct snd_soc_component *component) { @@ -502,10 +506,6 @@ static int omap_mcpdm_resume(struct snd_soc_component *component) #define OMAP_MCPDM_FORMATS SNDRV_PCM_FMTBIT_S32_LE static struct snd_soc_dai_driver omap_mcpdm_dai = { - .probe = omap_mcpdm_probe, - .remove = omap_mcpdm_remove, - .probe_order = SND_SOC_COMP_ORDER_LATE, - .remove_order = SND_SOC_COMP_ORDER_EARLY, .playback = { .channels_min = 1, .channels_max = 5, -- cgit v1.2.3 From b4a752b505d0819be95262cc6b2d7b3737617b82 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:06 +0000 Subject: ASoC: adi: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sf8tb0vp.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/adi/axi-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/adi/axi-i2s.c b/sound/soc/adi/axi-i2s.c index d5b6f5187f8e..7b2563075743 100644 --- a/sound/soc/adi/axi-i2s.c +++ b/sound/soc/adi/axi-i2s.c @@ -147,6 +147,7 @@ static int axi_i2s_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops axi_i2s_dai_ops = { + .probe = axi_i2s_dai_probe, .startup = axi_i2s_startup, .shutdown = axi_i2s_shutdown, .trigger = axi_i2s_trigger, @@ -154,7 +155,6 @@ static const struct snd_soc_dai_ops axi_i2s_dai_ops = { }; static struct snd_soc_dai_driver axi_i2s_dai = { - .probe = axi_i2s_dai_probe, .ops = &axi_i2s_dai_ops, .symmetric_rate = 1, }; -- cgit v1.2.3 From 7baf6b1e4f430162622838c6a13c3a2f84d5678b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:15 +0000 Subject: ASoC: adi: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r0odb0vg.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/adi/axi-spdif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/adi/axi-spdif.c b/sound/soc/adi/axi-spdif.c index e4c99bbc9cdd..10545bd99704 100644 --- a/sound/soc/adi/axi-spdif.c +++ b/sound/soc/adi/axi-spdif.c @@ -148,6 +148,7 @@ static void axi_spdif_shutdown(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops axi_spdif_dai_ops = { + .probe = axi_spdif_dai_probe, .startup = axi_spdif_startup, .shutdown = axi_spdif_shutdown, .trigger = axi_spdif_trigger, @@ -155,7 +156,6 @@ static const struct snd_soc_dai_ops axi_spdif_dai_ops = { }; static struct snd_soc_dai_driver axi_spdif_dai = { - .probe = axi_spdif_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, -- cgit v1.2.3 From 4062afe9861e4f45151af6a19c2f39d1894268ef Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:21 +0000 Subject: ASoC: amd: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pm3xb0va.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-i2s.c | 24 ++++++++++++------------ sound/soc/amd/acp/acp-rembrandt.c | 3 --- sound/soc/amd/acp/acp-renoir.c | 2 -- sound/soc/amd/acp/amd.h | 1 - 4 files changed, 12 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 09dc5f2c0bfc..df350014966a 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -539,17 +539,7 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d return 0; } -const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = { - .startup = acp_i2s_startup, - .hw_params = acp_i2s_hwparams, - .prepare = acp_i2s_prepare, - .trigger = acp_i2s_trigger, - .set_fmt = acp_i2s_set_fmt, - .set_tdm_slot = acp_i2s_set_tdm_slot, -}; -EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON); - -int asoc_acp_i2s_probe(struct snd_soc_dai *dai) +static int acp_i2s_probe(struct snd_soc_dai *dai) { struct device *dev = dai->component->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); @@ -569,7 +559,17 @@ int asoc_acp_i2s_probe(struct snd_soc_dai *dai) return 0; } -EXPORT_SYMBOL_NS_GPL(asoc_acp_i2s_probe, SND_SOC_ACP_COMMON); + +const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = { + .probe = acp_i2s_probe, + .startup = acp_i2s_startup, + .hw_params = acp_i2s_hwparams, + .prepare = acp_i2s_prepare, + .trigger = acp_i2s_trigger, + .set_fmt = acp_i2s_set_fmt, + .set_tdm_slot = acp_i2s_set_tdm_slot, +}; +EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS(DRV_NAME); diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c index cc8284f417c0..1bf7b2e68a11 100644 --- a/sound/soc/amd/acp/acp-rembrandt.c +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -98,7 +98,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-i2s-bt", @@ -124,7 +123,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-i2s-hs", @@ -150,7 +148,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-pdm-dmic", diff --git a/sound/soc/amd/acp/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c index 1899658ab25d..54235cad9cc9 100644 --- a/sound/soc/amd/acp/acp-renoir.c +++ b/sound/soc/amd/acp/acp-renoir.c @@ -97,7 +97,6 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-i2s-bt", @@ -123,7 +122,6 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-pdm-dmic", diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index 2ebe2099cbb5..d6cfae6ec5f7 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -198,7 +198,6 @@ union acp_i2stdm_mstrclkgen { extern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops; extern const struct snd_soc_dai_ops acp_dmic_dai_ops; -int asoc_acp_i2s_probe(struct snd_soc_dai *dai); int acp_platform_register(struct device *dev); int acp_platform_unregister(struct device *dev); -- cgit v1.2.3 From ddef7aff709e5b04c9c77851c6a87b0765ca363f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:27 +0000 Subject: ASoC: dwc: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Reviewed-by: Maxim Kochetkov Link: https://lore.kernel.org/r/87o7jhb0v4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/dwc/dwc-i2s.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index 1f1ee14b04e6..0a4698008d64 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -443,7 +443,16 @@ static int dw_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, unsigned int tx_mask return 0; } +static int dw_i2s_dai_probe(struct snd_soc_dai *dai) +{ + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data); + return 0; +} + static const struct snd_soc_dai_ops dw_i2s_dai_ops = { + .probe = dw_i2s_dai_probe, .hw_params = dw_i2s_hw_params, .prepare = dw_i2s_prepare, .trigger = dw_i2s_trigger, @@ -680,14 +689,6 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, } -static int dw_i2s_dai_probe(struct snd_soc_dai *dai) -{ - struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); - - snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data); - return 0; -} - static int dw_i2s_probe(struct platform_device *pdev) { const struct i2s_platform_data *pdata = pdev->dev.platform_data; @@ -706,7 +707,6 @@ static int dw_i2s_probe(struct platform_device *pdev) return -ENOMEM; dw_i2s_dai->ops = &dw_i2s_dai_ops; - dw_i2s_dai->probe = dw_i2s_dai_probe; dev->i2s_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(dev->i2s_base)) -- cgit v1.2.3 From 598d2dce58ffae5ca090a4cf36b7543e7069a16a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:41 +0000 Subject: ASoC: pxa: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87msz1b0uq.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/pxa/mmp-sspa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index a1ed141b8795..abfaf3cdf5bb 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c @@ -340,6 +340,7 @@ static int mmp_sspa_probe(struct snd_soc_dai *dai) SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops mmp_sspa_dai_ops = { + .probe = mmp_sspa_probe, .startup = mmp_sspa_startup, .shutdown = mmp_sspa_shutdown, .trigger = mmp_sspa_trigger, @@ -350,7 +351,6 @@ static const struct snd_soc_dai_ops mmp_sspa_dai_ops = { }; static struct snd_soc_dai_driver mmp_sspa_dai = { - .probe = mmp_sspa_probe, .playback = { .channels_min = 1, .channels_max = 128, -- cgit v1.2.3 From 755ecb00620b1dda0b3dade626ea711aad16bfa7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:47 +0000 Subject: ASoC: bcm: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87leelb0uk.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/bcm/bcm2835-i2s.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index 85f705afcdbb..9bda6499e66e 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -737,7 +737,19 @@ static void bcm2835_i2s_shutdown(struct snd_pcm_substream *substream, bcm2835_i2s_stop_clock(dev); } +static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai) +{ + struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, + &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK], + &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]); + + return 0; +} + static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = { + .probe = bcm2835_i2s_dai_probe, .startup = bcm2835_i2s_startup, .shutdown = bcm2835_i2s_shutdown, .prepare = bcm2835_i2s_prepare, @@ -748,20 +760,8 @@ static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = { .set_tdm_slot = bcm2835_i2s_set_dai_tdm_slot, }; -static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai) -{ - struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); - - snd_soc_dai_init_dma_data(dai, - &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK], - &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]); - - return 0; -} - static struct snd_soc_dai_driver bcm2835_i2s_dai = { .name = "bcm2835-i2s", - .probe = bcm2835_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, -- cgit v1.2.3 From ac27ca16a0bbbac2d38211634c15827d37a5150e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:53 +0000 Subject: ASoC: fsl: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87jzu5b0ue.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 16 ++++++++-------- sound/soc/fsl/fsl_aud2htx.c | 10 +++++----- sound/soc/fsl/fsl_easrc.c | 16 ++++++++-------- sound/soc/fsl/fsl_esai.c | 20 ++++++++++---------- sound/soc/fsl/fsl_micfil.c | 14 +++++++------- sound/soc/fsl/fsl_sai.c | 24 ++++++++++++------------ sound/soc/fsl/fsl_spdif.c | 17 ++++++++--------- sound/soc/fsl/fsl_ssi.c | 3 +-- sound/soc/fsl/fsl_xcvr.c | 16 ++++++++-------- 9 files changed, 67 insertions(+), 69 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index adb8a59de2bd..b793263291dc 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -780,13 +780,6 @@ static int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static const struct snd_soc_dai_ops fsl_asrc_dai_ops = { - .startup = fsl_asrc_dai_startup, - .hw_params = fsl_asrc_dai_hw_params, - .hw_free = fsl_asrc_dai_hw_free, - .trigger = fsl_asrc_dai_trigger, -}; - static int fsl_asrc_dai_probe(struct snd_soc_dai *dai) { struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); @@ -797,12 +790,19 @@ static int fsl_asrc_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops fsl_asrc_dai_ops = { + .probe = fsl_asrc_dai_probe, + .startup = fsl_asrc_dai_startup, + .hw_params = fsl_asrc_dai_hw_params, + .hw_free = fsl_asrc_dai_hw_free, + .trigger = fsl_asrc_dai_trigger, +}; + #define FSL_ASRC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_3LE) static struct snd_soc_dai_driver fsl_asrc_dai = { - .probe = fsl_asrc_dai_probe, .playback = { .stream_name = "ASRC-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c index 46b0c5dcc4a5..fc56f6ade368 100644 --- a/sound/soc/fsl/fsl_aud2htx.c +++ b/sound/soc/fsl/fsl_aud2htx.c @@ -49,10 +49,6 @@ static int fsl_aud2htx_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = { - .trigger = fsl_aud2htx_trigger, -}; - static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_aud2htx *aud2htx = dev_get_drvdata(cpu_dai->dev); @@ -84,8 +80,12 @@ static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = { + .probe = fsl_aud2htx_dai_probe, + .trigger = fsl_aud2htx_trigger, +}; + static struct snd_soc_dai_driver fsl_aud2htx_dai = { - .probe = fsl_aud2htx_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 670cbdb361b6..ba62995c909a 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -1531,13 +1531,6 @@ static int fsl_easrc_hw_free(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops fsl_easrc_dai_ops = { - .startup = fsl_easrc_startup, - .trigger = fsl_easrc_trigger, - .hw_params = fsl_easrc_hw_params, - .hw_free = fsl_easrc_hw_free, -}; - static int fsl_easrc_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_asrc *easrc = dev_get_drvdata(cpu_dai->dev); @@ -1548,8 +1541,15 @@ static int fsl_easrc_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops fsl_easrc_dai_ops = { + .probe = fsl_easrc_dai_probe, + .startup = fsl_easrc_startup, + .trigger = fsl_easrc_trigger, + .hw_params = fsl_easrc_hw_params, + .hw_free = fsl_easrc_hw_free, +}; + static struct snd_soc_dai_driver fsl_easrc_dai = { - .probe = fsl_easrc_dai_probe, .playback = { .stream_name = "ASRC-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 936f0cd4b06d..d0d8a01da9bd 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -785,15 +785,6 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static const struct snd_soc_dai_ops fsl_esai_dai_ops = { - .startup = fsl_esai_startup, - .trigger = fsl_esai_trigger, - .hw_params = fsl_esai_hw_params, - .set_sysclk = fsl_esai_set_dai_sysclk, - .set_fmt = fsl_esai_set_dai_fmt, - .set_tdm_slot = fsl_esai_set_dai_tdm_slot, -}; - static int fsl_esai_dai_probe(struct snd_soc_dai *dai) { struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); @@ -804,8 +795,17 @@ static int fsl_esai_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops fsl_esai_dai_ops = { + .probe = fsl_esai_dai_probe, + .startup = fsl_esai_startup, + .trigger = fsl_esai_trigger, + .hw_params = fsl_esai_hw_params, + .set_sysclk = fsl_esai_set_dai_sysclk, + .set_fmt = fsl_esai_set_dai_fmt, + .set_tdm_slot = fsl_esai_set_dai_tdm_slot, +}; + static struct snd_soc_dai_driver fsl_esai_dai = { - .probe = fsl_esai_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index bbaad6ec2e72..0d37edb70261 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -764,12 +764,6 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops fsl_micfil_dai_ops = { - .startup = fsl_micfil_startup, - .trigger = fsl_micfil_trigger, - .hw_params = fsl_micfil_hw_params, -}; - static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev); @@ -807,8 +801,14 @@ static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops fsl_micfil_dai_ops = { + .probe = fsl_micfil_dai_probe, + .startup = fsl_micfil_startup, + .trigger = fsl_micfil_trigger, + .hw_params = fsl_micfil_hw_params, +}; + static struct snd_soc_dai_driver fsl_micfil_dai = { - .probe = fsl_micfil_dai_probe, .capture = { .stream_name = "CPU-Capture", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index f7676d30c82f..1e4020fae05a 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -849,17 +849,6 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, return ret; } -static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { - .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio, - .set_sysclk = fsl_sai_set_dai_sysclk, - .set_fmt = fsl_sai_set_dai_fmt, - .set_tdm_slot = fsl_sai_set_dai_tdm_slot, - .hw_params = fsl_sai_hw_params, - .hw_free = fsl_sai_hw_free, - .trigger = fsl_sai_trigger, - .startup = fsl_sai_startup, -}; - static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); @@ -885,6 +874,18 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { + .probe = fsl_sai_dai_probe, + .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio, + .set_sysclk = fsl_sai_set_dai_sysclk, + .set_fmt = fsl_sai_set_dai_fmt, + .set_tdm_slot = fsl_sai_set_dai_tdm_slot, + .hw_params = fsl_sai_hw_params, + .hw_free = fsl_sai_hw_free, + .trigger = fsl_sai_trigger, + .startup = fsl_sai_startup, +}; + static int fsl_sai_dai_resume(struct snd_soc_component *component) { struct fsl_sai *sai = snd_soc_component_get_drvdata(component); @@ -903,7 +904,6 @@ static int fsl_sai_dai_resume(struct snd_soc_component *component) } static struct snd_soc_dai_driver fsl_sai_dai_template = { - .probe = fsl_sai_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 95bb8b10494a..78d9dfbe6548 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -765,14 +765,6 @@ static int fsl_spdif_trigger(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops fsl_spdif_dai_ops = { - .startup = fsl_spdif_startup, - .hw_params = fsl_spdif_hw_params, - .trigger = fsl_spdif_trigger, - .shutdown = fsl_spdif_shutdown, -}; - - /* * FSL SPDIF IEC958 controller(mixer) functions * @@ -1283,8 +1275,15 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops fsl_spdif_dai_ops = { + .probe = fsl_spdif_dai_probe, + .startup = fsl_spdif_startup, + .hw_params = fsl_spdif_hw_params, + .trigger = fsl_spdif_trigger, + .shutdown = fsl_spdif_shutdown, +}; + static struct snd_soc_dai_driver fsl_spdif_dai = { - .probe = &fsl_spdif_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 2, diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 53ed3701b0b0..079ac04272b8 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1152,6 +1152,7 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { + .probe = fsl_ssi_dai_probe, .startup = fsl_ssi_startup, .shutdown = fsl_ssi_shutdown, .hw_params = fsl_ssi_hw_params, @@ -1162,7 +1163,6 @@ static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { }; static struct snd_soc_dai_driver fsl_ssi_dai_template = { - .probe = fsl_ssi_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, @@ -1187,7 +1187,6 @@ static const struct snd_soc_component_driver fsl_ssi_component = { static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { .symmetric_channels = 1, - .probe = fsl_ssi_dai_probe, .playback = { .stream_name = "CPU AC97 Playback", .channels_min = 2, diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 318fe77683f5..fa0a15263c66 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -888,13 +888,6 @@ static struct snd_kcontrol_new fsl_xcvr_tx_ctls[] = { }, }; -static const struct snd_soc_dai_ops fsl_xcvr_dai_ops = { - .prepare = fsl_xcvr_prepare, - .startup = fsl_xcvr_startup, - .shutdown = fsl_xcvr_shutdown, - .trigger = fsl_xcvr_trigger, -}; - static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai) { struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); @@ -915,8 +908,15 @@ static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops fsl_xcvr_dai_ops = { + .probe = fsl_xcvr_dai_probe, + .prepare = fsl_xcvr_prepare, + .startup = fsl_xcvr_startup, + .shutdown = fsl_xcvr_shutdown, + .trigger = fsl_xcvr_trigger, +}; + static struct snd_soc_dai_driver fsl_xcvr_dai = { - .probe = fsl_xcvr_dai_probe, .ops = &fsl_xcvr_dai_ops, .playback = { .stream_name = "CPU-Playback", -- cgit v1.2.3 From ca6b2aac2ad49101d058f8f1d5099d36fd7b5360 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:55:59 +0000 Subject: ASoC: img: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87il9pb0u8.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/img/img-i2s-in.c | 14 +++++++------- sound/soc/img/img-i2s-out.c | 14 +++++++------- sound/soc/img/img-parallel-out.c | 14 +++++++------- sound/soc/img/img-spdif-in.c | 12 ++++++------ sound/soc/img/img-spdif-out.c | 12 ++++++------ 5 files changed, 33 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c index b7ab8467b5cf..b6b6339c164b 100644 --- a/sound/soc/img/img-i2s-in.c +++ b/sound/soc/img/img-i2s-in.c @@ -370,12 +370,6 @@ static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static const struct snd_soc_dai_ops img_i2s_in_dai_ops = { - .trigger = img_i2s_in_trigger, - .hw_params = img_i2s_in_hw_params, - .set_fmt = img_i2s_in_set_fmt -}; - static int img_i2s_in_dai_probe(struct snd_soc_dai *dai) { struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai); @@ -385,6 +379,13 @@ static int img_i2s_in_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_i2s_in_dai_ops = { + .probe = img_i2s_in_dai_probe, + .trigger = img_i2s_in_trigger, + .hw_params = img_i2s_in_hw_params, + .set_fmt = img_i2s_in_set_fmt +}; + static const struct snd_soc_component_driver img_i2s_in_component = { .name = "img-i2s-in", .legacy_dai_naming = 1, @@ -468,7 +469,6 @@ static int img_i2s_in_probe(struct platform_device *pdev) i2s->dma_data.addr = res->start + IMG_I2S_IN_RX_FIFO; i2s->dma_data.addr_width = 4; - i2s->dai_driver.probe = img_i2s_in_dai_probe; i2s->dai_driver.capture.channels_min = 2; i2s->dai_driver.capture.channels_max = i2s->max_i2s_chan * 2; i2s->dai_driver.capture.rates = SNDRV_PCM_RATE_8000_192000; diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c index fe95ddfb8407..41ea5ba52181 100644 --- a/sound/soc/img/img-i2s-out.c +++ b/sound/soc/img/img-i2s-out.c @@ -376,12 +376,6 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static const struct snd_soc_dai_ops img_i2s_out_dai_ops = { - .trigger = img_i2s_out_trigger, - .hw_params = img_i2s_out_hw_params, - .set_fmt = img_i2s_out_set_fmt -}; - static int img_i2s_out_dai_probe(struct snd_soc_dai *dai) { struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); @@ -391,6 +385,13 @@ static int img_i2s_out_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_i2s_out_dai_ops = { + .probe = img_i2s_out_dai_probe, + .trigger = img_i2s_out_trigger, + .hw_params = img_i2s_out_hw_params, + .set_fmt = img_i2s_out_set_fmt +}; + static const struct snd_soc_component_driver img_i2s_out_component = { .name = "img-i2s-out", .legacy_dai_naming = 1, @@ -504,7 +505,6 @@ static int img_i2s_out_probe(struct platform_device *pdev) i2s->dma_data.addr_width = 4; i2s->dma_data.maxburst = 4; - i2s->dai_driver.probe = img_i2s_out_dai_probe; i2s->dai_driver.playback.channels_min = 2; i2s->dai_driver.playback.channels_max = i2s->max_i2s_chan * 2; i2s->dai_driver.playback.rates = SNDRV_PCM_RATE_8000_192000; diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c index df1291ee2b3b..815e68a7048c 100644 --- a/sound/soc/img/img-parallel-out.c +++ b/sound/soc/img/img-parallel-out.c @@ -174,12 +174,6 @@ static int img_prl_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static const struct snd_soc_dai_ops img_prl_out_dai_ops = { - .trigger = img_prl_out_trigger, - .hw_params = img_prl_out_hw_params, - .set_fmt = img_prl_out_set_fmt -}; - static int img_prl_out_dai_probe(struct snd_soc_dai *dai) { struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai); @@ -189,8 +183,14 @@ static int img_prl_out_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_prl_out_dai_ops = { + .probe = img_prl_out_dai_probe, + .trigger = img_prl_out_trigger, + .hw_params = img_prl_out_hw_params, + .set_fmt = img_prl_out_set_fmt +}; + static struct snd_soc_dai_driver img_prl_out_dai = { - .probe = img_prl_out_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c index 558062a1804a..9646e9d3f0bc 100644 --- a/sound/soc/img/img-spdif-in.c +++ b/sound/soc/img/img-spdif-in.c @@ -682,11 +682,6 @@ static int img_spdif_in_hw_params(struct snd_pcm_substream *substream, return img_spdif_in_do_clkgen_single(spdif, rate); } -static const struct snd_soc_dai_ops img_spdif_in_dai_ops = { - .trigger = img_spdif_in_trigger, - .hw_params = img_spdif_in_hw_params -}; - static int img_spdif_in_dai_probe(struct snd_soc_dai *dai) { struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai); @@ -699,8 +694,13 @@ static int img_spdif_in_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_spdif_in_dai_ops = { + .probe = img_spdif_in_dai_probe, + .trigger = img_spdif_in_trigger, + .hw_params = img_spdif_in_hw_params +}; + static struct snd_soc_dai_driver img_spdif_in_dai = { - .probe = img_spdif_in_dai_probe, .capture = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c index b13e128e50d6..dfa72afa946e 100644 --- a/sound/soc/img/img-spdif-out.c +++ b/sound/soc/img/img-spdif-out.c @@ -287,11 +287,6 @@ static int img_spdif_out_hw_params(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops img_spdif_out_dai_ops = { - .trigger = img_spdif_out_trigger, - .hw_params = img_spdif_out_hw_params -}; - static int img_spdif_out_dai_probe(struct snd_soc_dai *dai) { struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai); @@ -304,8 +299,13 @@ static int img_spdif_out_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_spdif_out_dai_ops = { + .probe = img_spdif_out_dai_probe, + .trigger = img_spdif_out_trigger, + .hw_params = img_spdif_out_hw_params +}; + static struct snd_soc_dai_driver img_spdif_out_dai = { - .probe = img_spdif_out_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, -- cgit v1.2.3 From 450e7222236370e79fd3b75105967dc1e5cc0919 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:05 +0000 Subject: ASoC: sof: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87h6p9b0u2.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-client-probes.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c index 5530b5d793d0..740b637822db 100644 --- a/sound/soc/sof/sof-client-probes.c +++ b/sound/soc/sof/sof-client-probes.c @@ -354,10 +354,14 @@ static const struct file_operations sof_probes_points_remove_fops = { .owner = THIS_MODULE, }; +static const struct snd_soc_dai_ops sof_probes_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver sof_probes_dai_drv[] = { { .name = "Probe Extraction CPU DAI", - .compress_new = snd_soc_new_compress, + .ops = &sof_probes_dai_ops, .cops = &sof_probes_compr_ops, .capture = { .stream_name = "Probe Extraction", -- cgit v1.2.3 From 9f625f5e6cf9248796faaf1fb9368147dce82ca9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:11 +0000 Subject: ASoC: sti: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87fs4tb0tw.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sti/sti_uniperif.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index a4d74d1e3c24..2c21a86421e6 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -369,10 +369,14 @@ static int sti_uniperiph_dai_probe(struct snd_soc_dai *dai) return sti_uniperiph_dai_create_ctrl(dai); } -static const struct snd_soc_dai_driver sti_uniperiph_dai_template = { +static const struct snd_soc_dai_ops sti_uniperiph_dai_ops = { .probe = sti_uniperiph_dai_probe, }; +static const struct snd_soc_dai_driver sti_uniperiph_dai_template = { + .ops = &sti_uniperiph_dai_ops, +}; + static const struct snd_soc_component_driver sti_uniperiph_dai_component = { .name = "sti_cpu_dai", .suspend = sti_uniperiph_suspend, -- cgit v1.2.3 From 53c577ba4f506afe450733d583c529cd7214563b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:17 +0000 Subject: ASoC: stm: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87edkdb0tq.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 2 +- sound/soc/stm/stm32_sai_sub.c | 18 ++++++++++++++---- sound/soc/stm/stm32_spdifrx.c | 2 +- 3 files changed, 16 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 387130701960..06a42130f5e4 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -953,6 +953,7 @@ static const struct regmap_config stm32_h7_i2s_regmap_conf = { }; static const struct snd_soc_dai_ops stm32_i2s_pcm_dai_ops = { + .probe = stm32_i2s_dai_probe, .set_sysclk = stm32_i2s_set_sysclk, .set_fmt = stm32_i2s_set_dai_fmt, .startup = stm32_i2s_startup, @@ -1002,7 +1003,6 @@ static int stm32_i2s_dais_init(struct platform_device *pdev, if (!dai_ptr) return -ENOMEM; - dai_ptr->probe = stm32_i2s_dai_probe; dai_ptr->ops = &stm32_i2s_pcm_dai_ops; dai_ptr->id = 1; stm32_i2s_dai_init(&dai_ptr->playback, "playback"); diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 271ec5b3378d..42d67b7a68e8 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1222,6 +1222,19 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) } static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = { + .probe = stm32_sai_dai_probe, + .set_sysclk = stm32_sai_set_sysclk, + .set_fmt = stm32_sai_set_dai_fmt, + .set_tdm_slot = stm32_sai_set_dai_tdm_slot, + .startup = stm32_sai_startup, + .hw_params = stm32_sai_hw_params, + .trigger = stm32_sai_trigger, + .shutdown = stm32_sai_shutdown, + .pcm_new = stm32_sai_pcm_new, +}; + +static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops2 = { + .probe = stm32_sai_dai_probe, .set_sysclk = stm32_sai_set_sysclk, .set_fmt = stm32_sai_set_dai_fmt, .set_tdm_slot = stm32_sai_set_dai_tdm_slot, @@ -1287,8 +1300,6 @@ static const struct snd_pcm_hardware stm32_sai_pcm_hw = { }; static struct snd_soc_dai_driver stm32_sai_playback_dai = { - .probe = stm32_sai_dai_probe, - .pcm_new = stm32_sai_pcm_new, .id = 1, /* avoid call to fmt_single_name() */ .playback = { .channels_min = 1, @@ -1306,7 +1317,6 @@ static struct snd_soc_dai_driver stm32_sai_playback_dai = { }; static struct snd_soc_dai_driver stm32_sai_capture_dai = { - .probe = stm32_sai_dai_probe, .id = 1, /* avoid call to fmt_single_name() */ .capture = { .channels_min = 1, @@ -1320,7 +1330,7 @@ static struct snd_soc_dai_driver stm32_sai_capture_dai = { SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, }, - .ops = &stm32_sai_pcm_dai_ops, + .ops = &stm32_sai_pcm_dai_ops2, }; static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config = { diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index a4066f271f2d..a359b528b26b 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -856,6 +856,7 @@ static void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = { + .probe = stm32_spdifrx_dai_probe, .startup = stm32_spdifrx_startup, .hw_params = stm32_spdifrx_hw_params, .trigger = stm32_spdifrx_trigger, @@ -864,7 +865,6 @@ static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = { static struct snd_soc_dai_driver stm32_spdifrx_dai[] = { { - .probe = stm32_spdifrx_dai_probe, .capture = { .stream_name = "CPU-Capture", .channels_min = 1, -- cgit v1.2.3 From e41906778603cd4534fded6d9fa5302918c1c169 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:22 +0000 Subject: ASoC: pxa: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87cyzxb0tl.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/pxa/pxa-ssp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index d19769dde139..b70034c07eee 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -813,6 +813,8 @@ static int pxa_ssp_remove(struct snd_soc_dai *dai) #define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops pxa_ssp_dai_ops = { + .probe = pxa_ssp_probe, + .remove = pxa_ssp_remove, .startup = pxa_ssp_startup, .shutdown = pxa_ssp_shutdown, .trigger = pxa_ssp_trigger, @@ -824,8 +826,6 @@ static const struct snd_soc_dai_ops pxa_ssp_dai_ops = { }; static struct snd_soc_dai_driver pxa_ssp_dai = { - .probe = pxa_ssp_probe, - .remove = pxa_ssp_remove, .playback = { .channels_min = 1, .channels_max = 8, -- cgit v1.2.3 From 4b0891a7b60a6fd8a047a0e74a4c37d62d43402a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:28 +0000 Subject: ASoC: rsnd: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87bkfhb0tg.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index cf2031b7e209..e29c2fee9521 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1085,17 +1085,6 @@ static u64 rsnd_soc_dai_formats[] = { SND_SOC_POSSIBLE_DAIFMT_DSP_B, }; -static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { - .startup = rsnd_soc_dai_startup, - .shutdown = rsnd_soc_dai_shutdown, - .trigger = rsnd_soc_dai_trigger, - .set_fmt = rsnd_soc_dai_set_fmt, - .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, - .prepare = rsnd_soc_dai_prepare, - .auto_selectable_formats = rsnd_soc_dai_formats, - .num_auto_selectable_formats = ARRAY_SIZE(rsnd_soc_dai_formats), -}; - static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, struct rsnd_dai_stream *io, struct device_node *dai_np) @@ -1355,8 +1344,7 @@ static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd, return 0; } -static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dai *dai) +static int rsnd_soc_dai_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); int ret; @@ -1382,6 +1370,18 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd, return 0; } +static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { + .pcm_new = rsnd_soc_dai_pcm_new, + .startup = rsnd_soc_dai_startup, + .shutdown = rsnd_soc_dai_shutdown, + .trigger = rsnd_soc_dai_trigger, + .set_fmt = rsnd_soc_dai_set_fmt, + .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, + .prepare = rsnd_soc_dai_prepare, + .auto_selectable_formats = rsnd_soc_dai_formats, + .num_auto_selectable_formats = ARRAY_SIZE(rsnd_soc_dai_formats), +}; + static void __rsnd_dai_probe(struct rsnd_priv *priv, struct device_node *dai_np, struct device_node *node_np, @@ -1411,7 +1411,6 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, rdai->priv = priv; drv->name = rdai->name; drv->ops = &rsnd_soc_dai_ops; - drv->pcm_new = rsnd_pcm_new; drv->id = dai_i; drv->dai_args = &rdai->dai_args; -- cgit v1.2.3 From e4222bbdecf4a5d5c25df753e9f5aefd96368ae3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:34 +0000 Subject: ASoC: qcom: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87a5v1b0ta.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-apq8016.c | 4 -- sound/soc/qcom/lpass-cpu.c | 40 +++++++++------ sound/soc/qcom/lpass-ipq806x.c | 1 - sound/soc/qcom/lpass-sc7180.c | 5 +- sound/soc/qcom/lpass-sc7280.c | 2 - sound/soc/qcom/lpass.h | 4 +- sound/soc/qcom/qdsp6/q6afe-dai.c | 88 +++++++++++++++++--------------- sound/soc/qcom/qdsp6/q6asm-dai.c | 6 ++- sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c | 3 -- 9 files changed, 80 insertions(+), 73 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c index abaf694ee9a3..f919d46e18ca 100644 --- a/sound/soc/qcom/lpass-apq8016.c +++ b/sound/soc/qcom/lpass-apq8016.c @@ -41,7 +41,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, [MI2S_SECONDARY] = { @@ -62,7 +61,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, [MI2S_TERTIARY] = { @@ -83,7 +81,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, [MI2S_QUATERNARY] = { @@ -119,7 +116,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, }; diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index dbdaaa85ce48..39571fed4001 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -404,18 +404,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream, return 0; } -const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = { - .set_sysclk = lpass_cpu_daiops_set_sysclk, - .startup = lpass_cpu_daiops_startup, - .shutdown = lpass_cpu_daiops_shutdown, - .hw_params = lpass_cpu_daiops_hw_params, - .trigger = lpass_cpu_daiops_trigger, - .prepare = lpass_cpu_daiops_prepare, -}; -EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops); - -int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dai *dai) +static int lpass_cpu_daiops_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { int ret; struct snd_soc_dai_driver *drv = dai->driver; @@ -431,9 +420,8 @@ int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd, return 0; } -EXPORT_SYMBOL_GPL(lpass_cpu_pcm_new); -int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai) +static int lpass_cpu_daiops_probe(struct snd_soc_dai *dai) { struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); int ret; @@ -446,7 +434,29 @@ int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai) return ret; } -EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe); + +const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = { + .probe = lpass_cpu_daiops_probe, + .set_sysclk = lpass_cpu_daiops_set_sysclk, + .startup = lpass_cpu_daiops_startup, + .shutdown = lpass_cpu_daiops_shutdown, + .hw_params = lpass_cpu_daiops_hw_params, + .trigger = lpass_cpu_daiops_trigger, + .prepare = lpass_cpu_daiops_prepare, +}; +EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops); + +const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops2 = { + .pcm_new = lpass_cpu_daiops_pcm_new, + .probe = lpass_cpu_daiops_probe, + .set_sysclk = lpass_cpu_daiops_set_sysclk, + .startup = lpass_cpu_daiops_startup, + .shutdown = lpass_cpu_daiops_shutdown, + .hw_params = lpass_cpu_daiops_hw_params, + .trigger = lpass_cpu_daiops_trigger, + .prepare = lpass_cpu_daiops_prepare, +}; +EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops2); static int asoc_qcom_of_xlate_dai_name(struct snd_soc_component *component, const struct of_phandle_args *args, diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c index ef8a7984f232..2c97f295e394 100644 --- a/sound/soc/qcom/lpass-ipq806x.c +++ b/sound/soc/qcom/lpass-ipq806x.c @@ -51,7 +51,6 @@ static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }; diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c index 56db852f4eab..d16c0d83aaad 100644 --- a/sound/soc/qcom/lpass-sc7180.c +++ b/sound/soc/qcom/lpass-sc7180.c @@ -43,7 +43,6 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = { .channels_min = 2, .channels_max = 2, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, { .id = MI2S_SECONDARY, @@ -57,9 +56,7 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = { .channels_min = 2, .channels_max = 2, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, - .ops = &asoc_qcom_lpass_cpu_dai_ops, - .pcm_new = lpass_cpu_pcm_new, + .ops = &asoc_qcom_lpass_cpu_dai_ops2, }, { .id = LPASS_DP_RX, .name = "Hdmi", diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c index bcf18fe8e14d..6b2eb25ed939 100644 --- a/sound/soc/qcom/lpass-sc7280.c +++ b/sound/soc/qcom/lpass-sc7280.c @@ -38,7 +38,6 @@ static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = { .channels_min = 2, .channels_max = 2, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, { .id = MI2S_SECONDARY, @@ -52,7 +51,6 @@ static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = { .channels_min = 2, .channels_max = 2, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, { .id = LPASS_DP_RX, diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index dd78600fc7b0..bdfe66ec3314 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -402,10 +402,8 @@ int asoc_qcom_lpass_platform_register(struct platform_device *); int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev); void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev); int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev); -int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai); extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops; -int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dai *dai); +extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops2; extern const struct snd_soc_dai_ops asoc_qcom_lpass_cdc_dma_dai_ops; #endif /* __LPASS_H__ */ diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c index dbff55a97162..3faa7e0eb0dd 100644 --- a/sound/soc/qcom/qdsp6/q6afe-dai.c +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -619,44 +619,6 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = { {"RX_CODEC_DMA_RX_7 Playback", NULL, "RX_CODEC_DMA_RX_7"}, }; -static const struct snd_soc_dai_ops q6hdmi_ops = { - .prepare = q6afe_dai_prepare, - .hw_params = q6hdmi_hw_params, - .shutdown = q6afe_dai_shutdown, -}; - -static const struct snd_soc_dai_ops q6i2s_ops = { - .prepare = q6afe_dai_prepare, - .hw_params = q6i2s_hw_params, - .set_fmt = q6i2s_set_fmt, - .shutdown = q6afe_dai_shutdown, - .set_sysclk = q6afe_mi2s_set_sysclk, -}; - -static const struct snd_soc_dai_ops q6slim_ops = { - .prepare = q6afe_dai_prepare, - .hw_params = q6slim_hw_params, - .shutdown = q6afe_dai_shutdown, - .set_channel_map = q6slim_set_channel_map, -}; - -static const struct snd_soc_dai_ops q6tdm_ops = { - .prepare = q6afe_dai_prepare, - .shutdown = q6afe_dai_shutdown, - .set_sysclk = q6afe_mi2s_set_sysclk, - .set_tdm_slot = q6tdm_set_tdm_slot, - .set_channel_map = q6tdm_set_channel_map, - .hw_params = q6tdm_hw_params, -}; - -static const struct snd_soc_dai_ops q6dma_ops = { - .prepare = q6afe_dai_prepare, - .shutdown = q6afe_dai_shutdown, - .set_sysclk = q6afe_mi2s_set_sysclk, - .set_channel_map = q6dma_set_channel_map, - .hw_params = q6dma_hw_params, -}; - static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) { struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); @@ -682,6 +644,54 @@ static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops q6hdmi_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .hw_params = q6hdmi_hw_params, + .shutdown = q6afe_dai_shutdown, +}; + +static const struct snd_soc_dai_ops q6i2s_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .hw_params = q6i2s_hw_params, + .set_fmt = q6i2s_set_fmt, + .shutdown = q6afe_dai_shutdown, + .set_sysclk = q6afe_mi2s_set_sysclk, +}; + +static const struct snd_soc_dai_ops q6slim_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .hw_params = q6slim_hw_params, + .shutdown = q6afe_dai_shutdown, + .set_channel_map = q6slim_set_channel_map, +}; + +static const struct snd_soc_dai_ops q6tdm_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .shutdown = q6afe_dai_shutdown, + .set_sysclk = q6afe_mi2s_set_sysclk, + .set_tdm_slot = q6tdm_set_tdm_slot, + .set_channel_map = q6tdm_set_channel_map, + .hw_params = q6tdm_hw_params, +}; + +static const struct snd_soc_dai_ops q6dma_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .shutdown = q6afe_dai_shutdown, + .set_sysclk = q6afe_mi2s_set_sysclk, + .set_channel_map = q6dma_set_channel_map, + .hw_params = q6dma_hw_params, +}; + static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = { SND_SOC_DAPM_AIF_IN("HDMI_RX", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("SLIMBUS_0_RX", NULL, 0, SND_SOC_NOPM, 0, 0), @@ -1041,8 +1051,6 @@ static int q6afe_dai_dev_probe(struct platform_device *pdev) dev_set_drvdata(dev, dai_data); of_q6afe_parse_dai_data(dev, dai_data); - cfg.probe = msm_dai_q6_dai_probe; - cfg.remove = msm_dai_q6_dai_remove; cfg.q6hdmi_ops = &q6hdmi_ops; cfg.q6slim_ops = &q6slim_ops; cfg.q6i2s_ops = &q6i2s_ops; diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index 5fc8088e63c8..fe0666e9fd23 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -1230,6 +1230,10 @@ static struct snd_soc_dai_driver q6asm_fe_dais_template[] = { Q6ASM_FEDAI_DRIVER(8), }; +static const struct snd_soc_dai_ops q6asm_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static int of_q6asm_parse_dai_data(struct device *dev, struct q6asm_dai_data *pdata) { @@ -1272,7 +1276,7 @@ static int of_q6asm_parse_dai_data(struct device *dev, dai_drv->playback = empty_stream; if (of_property_read_bool(node, "is-compress-dai")) - dai_drv->compress_new = snd_soc_new_compress; + dai_drv->ops = &q6asm_dai_ops; } return 0; diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c index ac937a6bf909..4919001de08b 100644 --- a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c +++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c @@ -603,9 +603,6 @@ struct snd_soc_dai_driver *q6dsp_audio_ports_set_config(struct device *dev, int i; for (i = 0; i < ARRAY_SIZE(q6dsp_audio_fe_dais); i++) { - q6dsp_audio_fe_dais[i].probe = cfg->probe; - q6dsp_audio_fe_dais[i].remove = cfg->remove; - switch (q6dsp_audio_fe_dais[i].id) { case HDMI_RX: case DISPLAY_PORT_RX: -- cgit v1.2.3 From 2d2f3044440eee6a90d1dc4e05388e03be6f4b0d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:41 +0000 Subject: ASoC: au1x: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/878ralb0t3.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/au1x/ac97c.c | 10 +++++----- sound/soc/au1x/psc-ac97.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c index a11d6841afc2..b0e1a1253e10 100644 --- a/sound/soc/au1x/ac97c.c +++ b/sound/soc/au1x/ac97c.c @@ -195,18 +195,18 @@ static int alchemy_ac97c_startup(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops alchemy_ac97c_ops = { - .startup = alchemy_ac97c_startup, -}; - static int au1xac97c_dai_probe(struct snd_soc_dai *dai) { return ac97c_workdata ? 0 : -ENODEV; } +static const struct snd_soc_dai_ops alchemy_ac97c_ops = { + .probe = au1xac97c_dai_probe, + .startup = alchemy_ac97c_startup, +}; + static struct snd_soc_dai_driver au1xac97c_dai_driver = { .name = "alchemy-ac97c", - .probe = au1xac97c_dai_probe, .playback = { .rates = AC97_RATES, .formats = AC97_FMTS, diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 9fd91aea7d1a..5d50ebc2bdd5 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -333,13 +333,13 @@ static int au1xpsc_ac97_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = { + .probe = au1xpsc_ac97_probe, .startup = au1xpsc_ac97_startup, .trigger = au1xpsc_ac97_trigger, .hw_params = au1xpsc_ac97_hw_params, }; static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = { - .probe = au1xpsc_ac97_probe, .playback = { .rates = AC97_RATES, .formats = AC97_FMTS, -- cgit v1.2.3 From ce11656ccdc9cb520d8beb07854dec1875017282 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:46 +0000 Subject: ASoC: ux500: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Acked-by: Linus Walleij Link: https://lore.kernel.org/r/877cq5b0sx.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/ux500/ux500_msp_dai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 44e88dad8584..cde0dd8e2569 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -683,6 +683,7 @@ static int ux500_msp_dai_of_probe(struct snd_soc_dai *dai) static const struct snd_soc_dai_ops ux500_msp_dai_ops[] = { { + .probe = ux500_msp_dai_of_probe, .set_sysclk = ux500_msp_dai_set_dai_sysclk, .set_fmt = ux500_msp_dai_set_dai_fmt, .set_tdm_slot = ux500_msp_dai_set_tdm_slot, @@ -695,7 +696,6 @@ static const struct snd_soc_dai_ops ux500_msp_dai_ops[] = { }; static struct snd_soc_dai_driver ux500_msp_dai_drv = { - .probe = ux500_msp_dai_of_probe, .playback.channels_min = UX500_MSP_MIN_CHANNELS, .playback.channels_max = UX500_MSP_MAX_CHANNELS, .playback.rates = UX500_I2S_RATES, -- cgit v1.2.3 From fc95a8a3eaebff8130bd34a43e6a0fc14aa766d9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:52 +0000 Subject: ASoC: sunxi: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Reviewed-by: Jernej Skrabec Link: https://lore.kernel.org/r/875y5pb0sr.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 6 +++++- sound/soc/sunxi/sun4i-i2s.c | 18 +++++++++--------- sound/soc/sunxi/sun4i-spdif.c | 2 +- sound/soc/sunxi/sun50i-dmic.c | 2 +- 4 files changed, 16 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 55328850aef5..f0a5fd901101 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -1252,9 +1252,12 @@ static int sun4i_codec_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops dummy_dai_ops = { + .probe = sun4i_codec_dai_probe, +}; + static struct snd_soc_dai_driver dummy_cpu_dai = { .name = "sun4i-codec-cpu-dai", - .probe = sun4i_codec_dai_probe, .playback = { .stream_name = "Playback", .channels_min = 1, @@ -1271,6 +1274,7 @@ static struct snd_soc_dai_driver dummy_cpu_dai = { .formats = SUN4I_CODEC_FORMATS, .sig_bits = 24, }, + .ops = &dummy_dai_ops, }; static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev, diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 669d712bbe9f..5124b6c9ceb4 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1081,14 +1081,6 @@ static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai, return 0; } -static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { - .hw_params = sun4i_i2s_hw_params, - .set_fmt = sun4i_i2s_set_fmt, - .set_sysclk = sun4i_i2s_set_sysclk, - .set_tdm_slot = sun4i_i2s_set_tdm_slot, - .trigger = sun4i_i2s_trigger, -}; - static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); @@ -1100,12 +1092,20 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { + .probe = sun4i_i2s_dai_probe, + .hw_params = sun4i_i2s_hw_params, + .set_fmt = sun4i_i2s_set_fmt, + .set_sysclk = sun4i_i2s_set_sysclk, + .set_tdm_slot = sun4i_i2s_set_tdm_slot, + .trigger = sun4i_i2s_trigger, +}; + #define SUN4I_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S20_LE | \ SNDRV_PCM_FMTBIT_S24_LE) static struct snd_soc_dai_driver sun4i_i2s_dai = { - .probe = sun4i_i2s_dai_probe, .capture = { .stream_name = "Capture", .channels_min = 1, diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c index c2b55d2e5fe1..b849bb7cf58e 100644 --- a/sound/soc/sunxi/sun4i-spdif.c +++ b/sound/soc/sunxi/sun4i-spdif.c @@ -508,6 +508,7 @@ static int sun4i_spdif_soc_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops sun4i_spdif_dai_ops = { + .probe = sun4i_spdif_soc_dai_probe, .startup = sun4i_spdif_startup, .trigger = sun4i_spdif_trigger, .hw_params = sun4i_spdif_hw_params, @@ -533,7 +534,6 @@ static struct snd_soc_dai_driver sun4i_spdif_dai = { .rates = SUN4I_RATES, .formats = SUN4I_FORMATS, }, - .probe = sun4i_spdif_soc_dai_probe, .ops = &sun4i_spdif_dai_ops, .name = "spdif", }; diff --git a/sound/soc/sunxi/sun50i-dmic.c b/sound/soc/sunxi/sun50i-dmic.c index c10439b9e0a2..2599683a582d 100644 --- a/sound/soc/sunxi/sun50i-dmic.c +++ b/sound/soc/sunxi/sun50i-dmic.c @@ -236,6 +236,7 @@ static int sun50i_dmic_soc_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops sun50i_dmic_dai_ops = { + .probe = sun50i_dmic_soc_dai_probe, .startup = sun50i_dmic_startup, .trigger = sun50i_dmic_trigger, .hw_params = sun50i_dmic_hw_params, @@ -260,7 +261,6 @@ static struct snd_soc_dai_driver sun50i_dmic_dai = { .formats = SUN50I_DMIC_FORMATS, .sig_bits = 21, }, - .probe = sun50i_dmic_soc_dai_probe, .ops = &sun50i_dmic_dai_ops, .name = "dmic", }; -- cgit v1.2.3 From 516ee7009ff20eb3f73a64a1fe2ffe10997696e6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:56:58 +0000 Subject: ASoC: tegra: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/874jl9b0sl.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_ac97.c | 10 +++++----- sound/soc/tegra/tegra20_i2s.c | 2 +- sound/soc/tegra/tegra20_spdif.c | 2 +- sound/soc/tegra/tegra210_admaif.c | 12 ++++++------ sound/soc/tegra/tegra30_i2s.c | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c index 60e7df41c64c..e713feca25fa 100644 --- a/sound/soc/tegra/tegra20_ac97.c +++ b/sound/soc/tegra/tegra20_ac97.c @@ -203,10 +203,6 @@ static int tegra20_ac97_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static const struct snd_soc_dai_ops tegra20_ac97_dai_ops = { - .trigger = tegra20_ac97_trigger, -}; - static int tegra20_ac97_probe(struct snd_soc_dai *dai) { struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(dai); @@ -217,9 +213,13 @@ static int tegra20_ac97_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops tegra20_ac97_dai_ops = { + .probe = tegra20_ac97_probe, + .trigger = tegra20_ac97_trigger, +}; + static struct snd_soc_dai_driver tegra20_ac97_dai = { .name = "tegra-ac97-pcm", - .probe = tegra20_ac97_probe, .playback = { .stream_name = "PCM Playback", .channels_min = 2, diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index d38b58305c6b..f11618e8f13e 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -310,6 +310,7 @@ static int tegra20_i2s_startup(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = { + .probe = tegra20_i2s_probe, .set_fmt = tegra20_i2s_set_fmt, .hw_params = tegra20_i2s_hw_params, .trigger = tegra20_i2s_trigger, @@ -317,7 +318,6 @@ static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = { }; static const struct snd_soc_dai_driver tegra20_i2s_dai_template = { - .probe = tegra20_i2s_probe, .playback = { .stream_name = "Playback", .channels_min = 2, diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index d034803695a0..b0670aa4d967 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -241,6 +241,7 @@ static int tegra20_spdif_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = { + .probe = tegra20_spdif_probe, .hw_params = tegra20_spdif_hw_params, .trigger = tegra20_spdif_trigger, .startup = tegra20_spdif_startup, @@ -248,7 +249,6 @@ static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = { static struct snd_soc_dai_driver tegra20_spdif_dai = { .name = "tegra20-spdif", - .probe = tegra20_spdif_probe, .playback = { .stream_name = "Playback", .channels_min = 2, diff --git a/sound/soc/tegra/tegra210_admaif.c b/sound/soc/tegra/tegra210_admaif.c index 6868508585a0..9f9334e48049 100644 --- a/sound/soc/tegra/tegra210_admaif.c +++ b/sound/soc/tegra/tegra210_admaif.c @@ -419,11 +419,6 @@ static int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd, } } -static const struct snd_soc_dai_ops tegra_admaif_dai_ops = { - .hw_params = tegra_admaif_hw_params, - .trigger = tegra_admaif_trigger, -}; - static int tegra210_admaif_pget_mono_to_stereo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -550,10 +545,15 @@ static int tegra_admaif_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops tegra_admaif_dai_ops = { + .probe = tegra_admaif_dai_probe, + .hw_params = tegra_admaif_hw_params, + .trigger = tegra_admaif_trigger, +}; + #define DAI(dai_name) \ { \ .name = dai_name, \ - .probe = tegra_admaif_dai_probe, \ .playback = { \ .stream_name = dai_name " Playback", \ .channels_min = 1, \ diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 644280603095..81eaece51130 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -304,6 +304,7 @@ static int tegra30_i2s_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops tegra30_i2s_dai_ops = { + .probe = tegra30_i2s_probe, .set_fmt = tegra30_i2s_set_fmt, .hw_params = tegra30_i2s_hw_params, .trigger = tegra30_i2s_trigger, @@ -311,7 +312,6 @@ static const struct snd_soc_dai_ops tegra30_i2s_dai_ops = { }; static const struct snd_soc_dai_driver tegra30_i2s_dai_template = { - .probe = tegra30_i2s_probe, .playback = { .stream_name = "Playback", .channels_min = 2, -- cgit v1.2.3 From 2ff8a43d4d4eec1f74cc024b21fe6737faaa69f9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:04 +0000 Subject: ASoC: atmel: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87350tb0sg.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-i2s.c | 16 ++++++++-------- sound/soc/atmel/mchp-i2s-mcc.c | 24 ++++++++++++------------ sound/soc/atmel/mchp-pdmc.c | 18 +++++++++--------- sound/soc/atmel/mchp-spdifrx.c | 14 +++++++------- sound/soc/atmel/mchp-spdiftx.c | 18 +++++++++--------- 5 files changed, 45 insertions(+), 45 deletions(-) (limited to 'sound') diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c index 4febd4d3d0fa..6c20c643f321 100644 --- a/sound/soc/atmel/atmel-i2s.c +++ b/sound/soc/atmel/atmel-i2s.c @@ -532,13 +532,6 @@ static int atmel_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return err; } -static const struct snd_soc_dai_ops atmel_i2s_dai_ops = { - .prepare = atmel_i2s_prepare, - .trigger = atmel_i2s_trigger, - .hw_params = atmel_i2s_hw_params, - .set_fmt = atmel_i2s_set_dai_fmt, -}; - static int atmel_i2s_dai_probe(struct snd_soc_dai *dai) { struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); @@ -547,8 +540,15 @@ static int atmel_i2s_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops atmel_i2s_dai_ops = { + .probe = atmel_i2s_dai_probe, + .prepare = atmel_i2s_prepare, + .trigger = atmel_i2s_trigger, + .hw_params = atmel_i2s_hw_params, + .set_fmt = atmel_i2s_set_dai_fmt, +}; + static struct snd_soc_dai_driver atmel_i2s_dai = { - .probe = atmel_i2s_dai_probe, .playback = { .channels_min = 1, .channels_max = 2, diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index 4b8a63295f89..25ed0b953bfd 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -870,17 +870,6 @@ static int mchp_i2s_mcc_startup(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = { - .set_sysclk = mchp_i2s_mcc_set_sysclk, - .set_bclk_ratio = mchp_i2s_mcc_set_bclk_ratio, - .startup = mchp_i2s_mcc_startup, - .trigger = mchp_i2s_mcc_trigger, - .hw_params = mchp_i2s_mcc_hw_params, - .hw_free = mchp_i2s_mcc_hw_free, - .set_fmt = mchp_i2s_mcc_set_dai_fmt, - .set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot, -}; - static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai) { struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai); @@ -895,6 +884,18 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = { + .probe = mchp_i2s_mcc_dai_probe, + .set_sysclk = mchp_i2s_mcc_set_sysclk, + .set_bclk_ratio = mchp_i2s_mcc_set_bclk_ratio, + .startup = mchp_i2s_mcc_startup, + .trigger = mchp_i2s_mcc_trigger, + .hw_params = mchp_i2s_mcc_hw_params, + .hw_free = mchp_i2s_mcc_hw_free, + .set_fmt = mchp_i2s_mcc_set_dai_fmt, + .set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot, +}; + #define MCHP_I2SMCC_RATES SNDRV_PCM_RATE_8000_192000 #define MCHP_I2SMCC_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ @@ -906,7 +907,6 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai) SNDRV_PCM_FMTBIT_S32_LE) static struct snd_soc_dai_driver mchp_i2s_mcc_dai = { - .probe = mchp_i2s_mcc_dai_probe, .playback = { .stream_name = "I2SMCC-Playback", .channels_min = 1, diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c index c79c73e6791e..944d78ef2f36 100644 --- a/sound/soc/atmel/mchp-pdmc.c +++ b/sound/soc/atmel/mchp-pdmc.c @@ -706,13 +706,6 @@ static int mchp_pdmc_trigger(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = { - .set_fmt = mchp_pdmc_set_fmt, - .startup = mchp_pdmc_startup, - .hw_params = mchp_pdmc_hw_params, - .trigger = mchp_pdmc_trigger, -}; - static int mchp_pdmc_add_chmap_ctls(struct snd_pcm *pcm, struct mchp_pdmc *dd) { struct mchp_pdmc_chmap *info; @@ -765,8 +758,16 @@ static int mchp_pdmc_pcm_new(struct snd_soc_pcm_runtime *rtd, return ret; } +static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = { + .probe = mchp_pdmc_dai_probe, + .set_fmt = mchp_pdmc_set_fmt, + .startup = mchp_pdmc_startup, + .hw_params = mchp_pdmc_hw_params, + .trigger = mchp_pdmc_trigger, + .pcm_new = &mchp_pdmc_pcm_new, +}; + static struct snd_soc_dai_driver mchp_pdmc_dai = { - .probe = mchp_pdmc_dai_probe, .capture = { .stream_name = "Capture", .channels_min = 1, @@ -777,7 +778,6 @@ static struct snd_soc_dai_driver mchp_pdmc_dai = { .formats = SNDRV_PCM_FMTBIT_S24_LE, }, .ops = &mchp_pdmc_dai_ops, - .pcm_new = &mchp_pdmc_pcm_new, }; /* PDMC interrupt handler */ diff --git a/sound/soc/atmel/mchp-spdifrx.c b/sound/soc/atmel/mchp-spdifrx.c index e97cd8f4a728..33ce5e54482b 100644 --- a/sound/soc/atmel/mchp-spdifrx.c +++ b/sound/soc/atmel/mchp-spdifrx.c @@ -503,11 +503,6 @@ unlock: return ret; } -static const struct snd_soc_dai_ops mchp_spdifrx_dai_ops = { - .trigger = mchp_spdifrx_trigger, - .hw_params = mchp_spdifrx_hw_params, -}; - #define MCHP_SPDIF_RATES SNDRV_PCM_RATE_8000_192000 #define MCHP_SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ @@ -1009,10 +1004,15 @@ static int mchp_spdifrx_dai_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mchp_spdifrx_dai_ops = { + .probe = mchp_spdifrx_dai_probe, + .remove = mchp_spdifrx_dai_remove, + .trigger = mchp_spdifrx_trigger, + .hw_params = mchp_spdifrx_hw_params, +}; + static struct snd_soc_dai_driver mchp_spdifrx_dai = { .name = "mchp-spdifrx", - .probe = mchp_spdifrx_dai_probe, - .remove = mchp_spdifrx_dai_remove, .capture = { .stream_name = "S/PDIF Capture", .channels_min = SPDIFRX_CHANNELS, diff --git a/sound/soc/atmel/mchp-spdiftx.c b/sound/soc/atmel/mchp-spdiftx.c index b1040576f71f..a201a96fa690 100644 --- a/sound/soc/atmel/mchp-spdiftx.c +++ b/sound/soc/atmel/mchp-spdiftx.c @@ -516,14 +516,6 @@ static int mchp_spdiftx_hw_free(struct snd_pcm_substream *substream, SPDIFTX_CR_SWRST | SPDIFTX_CR_FCLR); } -static const struct snd_soc_dai_ops mchp_spdiftx_dai_ops = { - .startup = mchp_spdiftx_dai_startup, - .shutdown = mchp_spdiftx_dai_shutdown, - .trigger = mchp_spdiftx_trigger, - .hw_params = mchp_spdiftx_hw_params, - .hw_free = mchp_spdiftx_hw_free, -}; - #define MCHP_SPDIFTX_RATES SNDRV_PCM_RATE_8000_192000 #define MCHP_SPDIFTX_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ @@ -703,9 +695,17 @@ static int mchp_spdiftx_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mchp_spdiftx_dai_ops = { + .probe = mchp_spdiftx_dai_probe, + .startup = mchp_spdiftx_dai_startup, + .shutdown = mchp_spdiftx_dai_shutdown, + .trigger = mchp_spdiftx_trigger, + .hw_params = mchp_spdiftx_hw_params, + .hw_free = mchp_spdiftx_hw_free, +}; + static struct snd_soc_dai_driver mchp_spdiftx_dai = { .name = "mchp-spdiftx", - .probe = mchp_spdiftx_dai_probe, .playback = { .stream_name = "S/PDIF Playback", .channels_min = 1, -- cgit v1.2.3 From e9f512121e6ae491aac255849eabeb3d2b1e4199 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:09 +0000 Subject: ASoC: intel: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/871qgdb0sa.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 2 +- sound/soc/intel/avs/probes.c | 10 +++++++--- sound/soc/intel/catpt/pcm.c | 8 ++++++-- sound/soc/intel/keembay/kmb_platform.c | 4 +--- 4 files changed, 15 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index ba4597bdf32e..6f986c7bbc8b 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -467,6 +467,7 @@ static const struct snd_soc_dai_ops sst_media_dai_ops = { }; static const struct snd_soc_dai_ops sst_compr_dai_ops = { + .compress_new = snd_soc_new_compress, .mute_stream = sst_media_digital_mute, }; @@ -510,7 +511,6 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { }, { .name = "compress-cpu-dai", - .compress_new = snd_soc_new_compress, .ops = &sst_compr_dai_ops, .playback = { .stream_name = "Compress Playback", diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c index 275928281c6c..4cab8c6c4576 100644 --- a/sound/soc/intel/avs/probes.c +++ b/sound/soc/intel/avs/probes.c @@ -249,7 +249,7 @@ static int avs_probe_compr_copy(struct snd_soc_component *comp, struct snd_compr return count; } -static const struct snd_soc_cdai_ops avs_probe_dai_ops = { +static const struct snd_soc_cdai_ops avs_probe_cdai_ops = { .startup = avs_probe_compr_open, .shutdown = avs_probe_compr_free, .set_params = avs_probe_compr_set_params, @@ -257,6 +257,10 @@ static const struct snd_soc_cdai_ops avs_probe_dai_ops = { .pointer = avs_probe_compr_pointer, }; +static const struct snd_soc_dai_ops avs_probe_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static const struct snd_compress_ops avs_probe_compress_ops = { .copy = avs_probe_compr_copy, }; @@ -264,8 +268,8 @@ static const struct snd_compress_ops avs_probe_compress_ops = { static struct snd_soc_dai_driver probe_cpu_dais[] = { { .name = "Probe Extraction CPU DAI", - .compress_new = snd_soc_new_compress, - .cops = &avs_probe_dai_ops, + .cops = &avs_probe_cdai_ops, + .ops = &avs_probe_dai_ops, .capture = { .stream_name = "Probe Extraction", .channels_min = 1, diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c index 30ca5416c9a3..f1a5cb825ff1 100644 --- a/sound/soc/intel/catpt/pcm.c +++ b/sound/soc/intel/catpt/pcm.c @@ -684,6 +684,10 @@ static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm, return 0; } +static const struct snd_soc_dai_ops catpt_dai_ops = { + .pcm_new = catpt_dai_pcm_new, +}; + static struct snd_soc_dai_driver dai_drivers[] = { /* FE DAIs */ { @@ -764,7 +768,6 @@ static struct snd_soc_dai_driver dai_drivers[] = { { .name = "ssp0-port", .id = CATPT_SSP_IFACE_0, - .pcm_new = catpt_dai_pcm_new, .playback = { .channels_min = 1, .channels_max = 8, @@ -773,11 +776,11 @@ static struct snd_soc_dai_driver dai_drivers[] = { .channels_min = 1, .channels_max = 8, }, + .ops = &catpt_dai_ops, }, { .name = "ssp1-port", .id = CATPT_SSP_IFACE_1, - .pcm_new = catpt_dai_pcm_new, .playback = { .channels_min = 1, .channels_max = 8, @@ -786,6 +789,7 @@ static struct snd_soc_dai_driver dai_drivers[] = { .channels_min = 1, .channels_max = 8, }, + .ops = &catpt_dai_ops, }, }; diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c index b4893365d01d..6b06b7b5ede8 100644 --- a/sound/soc/intel/keembay/kmb_platform.c +++ b/sound/soc/intel/keembay/kmb_platform.c @@ -733,6 +733,7 @@ static int kmb_dai_hw_free(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops kmb_dai_ops = { + .probe = kmb_probe, .startup = kmb_dai_startup, .trigger = kmb_dai_trigger, .hw_params = kmb_dai_hw_params, @@ -755,7 +756,6 @@ static struct snd_soc_dai_driver intel_kmb_hdmi_dai[] = { SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE), }, .ops = &kmb_dai_ops, - .probe = kmb_probe, }, }; @@ -787,7 +787,6 @@ static struct snd_soc_dai_driver intel_kmb_i2s_dai[] = { SNDRV_PCM_FMTBIT_S16_LE), }, .ops = &kmb_dai_ops, - .probe = kmb_probe, }, }; @@ -807,7 +806,6 @@ static struct snd_soc_dai_driver intel_kmb_tdm_dai[] = { SNDRV_PCM_FMTBIT_S16_LE), }, .ops = &kmb_dai_ops, - .probe = kmb_probe, }, }; -- cgit v1.2.3 From 2d3155a90757ec37f50c0aa98a532e5d0a61b953 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:18 +0000 Subject: ASoC: meson: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87zg319m7m.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/meson/aiu-acodec-ctrl.c | 4 ++-- sound/soc/meson/aiu-codec-ctrl.c | 4 ++-- sound/soc/meson/aiu-fifo-i2s.c | 3 +++ sound/soc/meson/aiu-fifo-spdif.c | 3 +++ sound/soc/meson/aiu.c | 6 ------ sound/soc/meson/axg-frddr.c | 4 ++-- sound/soc/meson/axg-pdm.c | 18 +++++++++--------- sound/soc/meson/axg-spdifin.c | 4 ++-- sound/soc/meson/axg-tdm-interface.c | 6 ++---- sound/soc/meson/axg-toddr.c | 4 ++-- sound/soc/meson/g12a-toacodec.c | 4 ++-- sound/soc/meson/g12a-tohdmitx.c | 4 ++-- 12 files changed, 31 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/soc/meson/aiu-acodec-ctrl.c b/sound/soc/meson/aiu-acodec-ctrl.c index d0f0ada5f4bc..7b04b97f7b41 100644 --- a/sound/soc/meson/aiu-acodec-ctrl.c +++ b/sound/soc/meson/aiu-acodec-ctrl.c @@ -103,6 +103,8 @@ static int aiu_acodec_ctrl_input_hw_params(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops aiu_acodec_ctrl_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = aiu_acodec_ctrl_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -130,8 +132,6 @@ static const struct snd_soc_dai_ops aiu_acodec_ctrl_output_ops = { .name = "ACODEC CTRL " xname, \ .playback = AIU_ACODEC_STREAM(xname, "Playback", 8), \ .ops = &aiu_acodec_ctrl_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define AIU_ACODEC_OUTPUT(xname) { \ diff --git a/sound/soc/meson/aiu-codec-ctrl.c b/sound/soc/meson/aiu-codec-ctrl.c index 84c10956c241..ee0ef6301010 100644 --- a/sound/soc/meson/aiu-codec-ctrl.c +++ b/sound/soc/meson/aiu-codec-ctrl.c @@ -75,6 +75,8 @@ static const struct snd_soc_dapm_widget aiu_hdmi_ctrl_widgets[] = { }; static const struct snd_soc_dai_ops aiu_codec_ctrl_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = meson_codec_glue_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -102,8 +104,6 @@ static const struct snd_soc_dai_ops aiu_codec_ctrl_output_ops = { .name = "CODEC CTRL " xname, \ .playback = AIU_CODEC_CTRL_STREAM(xname, "Playback"), \ .ops = &aiu_codec_ctrl_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define AIU_CODEC_CTRL_OUTPUT(xname) { \ diff --git a/sound/soc/meson/aiu-fifo-i2s.c b/sound/soc/meson/aiu-fifo-i2s.c index 59e00a74b5f8..7d833500c799 100644 --- a/sound/soc/meson/aiu-fifo-i2s.c +++ b/sound/soc/meson/aiu-fifo-i2s.c @@ -140,6 +140,9 @@ static int aiu_fifo_i2s_hw_params(struct snd_pcm_substream *substream, } const struct snd_soc_dai_ops aiu_fifo_i2s_dai_ops = { + .pcm_new = aiu_fifo_pcm_new, + .probe = aiu_fifo_i2s_dai_probe, + .remove = aiu_fifo_dai_remove, .trigger = aiu_fifo_i2s_trigger, .prepare = aiu_fifo_i2s_prepare, .hw_params = aiu_fifo_i2s_hw_params, diff --git a/sound/soc/meson/aiu-fifo-spdif.c b/sound/soc/meson/aiu-fifo-spdif.c index ddbd2fc40185..fa91f3c53fa4 100644 --- a/sound/soc/meson/aiu-fifo-spdif.c +++ b/sound/soc/meson/aiu-fifo-spdif.c @@ -155,6 +155,9 @@ static int fifo_spdif_hw_params(struct snd_pcm_substream *substream, } const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops = { + .pcm_new = aiu_fifo_pcm_new, + .probe = aiu_fifo_spdif_dai_probe, + .remove = aiu_fifo_dai_remove, .trigger = fifo_spdif_trigger, .prepare = fifo_spdif_prepare, .hw_params = fifo_spdif_hw_params, diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c index da351a60df0c..7109b81cc3d0 100644 --- a/sound/soc/meson/aiu.c +++ b/sound/soc/meson/aiu.c @@ -121,9 +121,6 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = { .formats = AIU_FORMATS, }, .ops = &aiu_fifo_i2s_dai_ops, - .pcm_new = aiu_fifo_pcm_new, - .probe = aiu_fifo_i2s_dai_probe, - .remove = aiu_fifo_dai_remove, }, [CPU_SPDIF_FIFO] = { .name = "SPDIF FIFO", @@ -137,9 +134,6 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = { .formats = AIU_FORMATS, }, .ops = &aiu_fifo_spdif_dai_ops, - .pcm_new = aiu_fifo_pcm_new, - .probe = aiu_fifo_spdif_dai_probe, - .remove = aiu_fifo_dai_remove, }, [CPU_I2S_ENCODER] = { .name = "I2S Encoder", diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c index 61f9d417fd60..8c166a5f338c 100644 --- a/sound/soc/meson/axg-frddr.c +++ b/sound/soc/meson/axg-frddr.c @@ -100,6 +100,7 @@ static const struct snd_soc_dai_ops axg_frddr_ops = { .hw_params = axg_frddr_dai_hw_params, .startup = axg_frddr_dai_startup, .shutdown = axg_frddr_dai_shutdown, + .pcm_new = axg_frddr_pcm_new, }; static struct snd_soc_dai_driver axg_frddr_dai_drv = { @@ -112,7 +113,6 @@ static struct snd_soc_dai_driver axg_frddr_dai_drv = { .formats = AXG_FIFO_FORMATS, }, .ops = &axg_frddr_ops, - .pcm_new = axg_frddr_pcm_new, }; static const char * const axg_frddr_sel_texts[] = { @@ -175,6 +175,7 @@ static const struct snd_soc_dai_ops g12a_frddr_ops = { .hw_params = axg_frddr_dai_hw_params, .startup = axg_frddr_dai_startup, .shutdown = axg_frddr_dai_shutdown, + .pcm_new = axg_frddr_pcm_new, }; static struct snd_soc_dai_driver g12a_frddr_dai_drv = { @@ -187,7 +188,6 @@ static struct snd_soc_dai_driver g12a_frddr_dai_drv = { .formats = AXG_FIFO_FORMATS, }, .ops = &g12a_frddr_ops, - .pcm_new = axg_frddr_pcm_new, }; static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel1_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT, diff --git a/sound/soc/meson/axg-pdm.c b/sound/soc/meson/axg-pdm.c index ad43cb2a1e3f..d59050914d3c 100644 --- a/sound/soc/meson/axg-pdm.c +++ b/sound/soc/meson/axg-pdm.c @@ -294,13 +294,6 @@ static void axg_pdm_shutdown(struct snd_pcm_substream *substream, clk_disable_unprepare(priv->dclk); } -static const struct snd_soc_dai_ops axg_pdm_dai_ops = { - .trigger = axg_pdm_trigger, - .hw_params = axg_pdm_hw_params, - .startup = axg_pdm_startup, - .shutdown = axg_pdm_shutdown, -}; - static void axg_pdm_set_hcic_ctrl(struct axg_pdm *priv) { const struct axg_pdm_hcic *hcic = &priv->cfg->filters->hcic; @@ -440,6 +433,15 @@ static int axg_pdm_dai_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops axg_pdm_dai_ops = { + .probe = axg_pdm_dai_probe, + .remove = axg_pdm_dai_remove, + .trigger = axg_pdm_trigger, + .hw_params = axg_pdm_hw_params, + .startup = axg_pdm_startup, + .shutdown = axg_pdm_shutdown, +}; + static struct snd_soc_dai_driver axg_pdm_dai_drv = { .name = "PDM", .capture = { @@ -453,8 +455,6 @@ static struct snd_soc_dai_driver axg_pdm_dai_drv = { SNDRV_PCM_FMTBIT_S32_LE), }, .ops = &axg_pdm_dai_ops, - .probe = axg_pdm_dai_probe, - .remove = axg_pdm_dai_remove, }; static const struct snd_soc_component_driver axg_pdm_component_drv = { diff --git a/sound/soc/meson/axg-spdifin.c b/sound/soc/meson/axg-spdifin.c index e2cc4c4be758..d86880169075 100644 --- a/sound/soc/meson/axg-spdifin.c +++ b/sound/soc/meson/axg-spdifin.c @@ -267,6 +267,8 @@ static int axg_spdifin_dai_remove(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops axg_spdifin_ops = { + .probe = axg_spdifin_dai_probe, + .remove = axg_spdifin_dai_remove, .prepare = axg_spdifin_prepare, .startup = axg_spdifin_startup, .shutdown = axg_spdifin_shutdown, @@ -429,8 +431,6 @@ axg_spdifin_get_dai_drv(struct device *dev, struct axg_spdifin *priv) drv->name = "SPDIF Input"; drv->ops = &axg_spdifin_ops; - drv->probe = axg_spdifin_dai_probe; - drv->remove = axg_spdifin_dai_remove; drv->capture.stream_name = "Capture"; drv->capture.channels_min = 1; drv->capture.channels_max = 2; diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c index 5e5e4c56d505..1c3d433cefd2 100644 --- a/sound/soc/meson/axg-tdm-interface.c +++ b/sound/soc/meson/axg-tdm-interface.c @@ -395,6 +395,8 @@ static int axg_tdm_iface_probe_dai(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops axg_tdm_iface_ops = { + .probe = axg_tdm_iface_probe_dai, + .remove = axg_tdm_iface_remove_dai, .set_sysclk = axg_tdm_iface_set_sysclk, .set_fmt = axg_tdm_iface_set_fmt, .startup = axg_tdm_iface_startup, @@ -423,8 +425,6 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = { }, .id = TDM_IFACE_PAD, .ops = &axg_tdm_iface_ops, - .probe = axg_tdm_iface_probe_dai, - .remove = axg_tdm_iface_remove_dai, }, [TDM_IFACE_LOOPBACK] = { .name = "TDM Loopback", @@ -437,8 +437,6 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = { }, .id = TDM_IFACE_LOOPBACK, .ops = &axg_tdm_iface_ops, - .probe = axg_tdm_iface_probe_dai, - .remove = axg_tdm_iface_remove_dai, }, }; diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c index e9208e74e965..1a0be177b8fe 100644 --- a/sound/soc/meson/axg-toddr.c +++ b/sound/soc/meson/axg-toddr.c @@ -122,6 +122,7 @@ static const struct snd_soc_dai_ops axg_toddr_ops = { .hw_params = axg_toddr_dai_hw_params, .startup = axg_toddr_dai_startup, .shutdown = axg_toddr_dai_shutdown, + .pcm_new = axg_toddr_pcm_new, }; static struct snd_soc_dai_driver axg_toddr_dai_drv = { @@ -134,7 +135,6 @@ static struct snd_soc_dai_driver axg_toddr_dai_drv = { .formats = AXG_FIFO_FORMATS, }, .ops = &axg_toddr_ops, - .pcm_new = axg_toddr_pcm_new, }; static const char * const axg_toddr_sel_texts[] = { @@ -217,6 +217,7 @@ static const struct snd_soc_dai_ops g12a_toddr_ops = { .hw_params = axg_toddr_dai_hw_params, .startup = g12a_toddr_dai_startup, .shutdown = axg_toddr_dai_shutdown, + .pcm_new = axg_toddr_pcm_new, }; static struct snd_soc_dai_driver g12a_toddr_dai_drv = { @@ -229,7 +230,6 @@ static struct snd_soc_dai_driver g12a_toddr_dai_drv = { .formats = AXG_FIFO_FORMATS, }, .ops = &g12a_toddr_ops, - .pcm_new = axg_toddr_pcm_new, }; static const struct snd_soc_component_driver g12a_toddr_component_drv = { diff --git a/sound/soc/meson/g12a-toacodec.c b/sound/soc/meson/g12a-toacodec.c index ddc667956cf5..6c4503766fdc 100644 --- a/sound/soc/meson/g12a-toacodec.c +++ b/sound/soc/meson/g12a-toacodec.c @@ -162,6 +162,8 @@ static int g12a_toacodec_input_hw_params(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops g12a_toacodec_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = g12a_toacodec_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -185,8 +187,6 @@ static const struct snd_soc_dai_ops g12a_toacodec_output_ops = { .id = (xid), \ .playback = TOACODEC_STREAM(xname, "Playback", 8), \ .ops = &g12a_toacodec_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define TOACODEC_OUTPUT(xname, xid) { \ diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c index 579a04ad4d19..f7ef9aa1eed8 100644 --- a/sound/soc/meson/g12a-tohdmitx.c +++ b/sound/soc/meson/g12a-tohdmitx.c @@ -140,6 +140,8 @@ static const struct snd_soc_dapm_widget g12a_tohdmitx_widgets[] = { }; static const struct snd_soc_dai_ops g12a_tohdmitx_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = meson_codec_glue_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -172,8 +174,6 @@ static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = { .id = (xid), \ .playback = TOHDMITX_STREAM(xname, "Playback", xfmt, xchmax), \ .ops = &g12a_tohdmitx_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define TOHDMITX_OUT(xname, xid, xfmt, xchmax) { \ -- cgit v1.2.3 From cfacc4d8c04d177911ae2c6601d9c320c5c5c29e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:24 +0000 Subject: ASoC: jz4740: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87y1il9m7f.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/jz4740/jz4740-i2s.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 578af21769c9..517619531615 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -328,6 +328,7 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = { + .probe = jz4740_i2s_dai_probe, .startup = jz4740_i2s_startup, .shutdown = jz4740_i2s_shutdown, .trigger = jz4740_i2s_trigger, @@ -341,7 +342,6 @@ static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = { SNDRV_PCM_FMTBIT_S24_LE) static struct snd_soc_dai_driver jz4740_i2s_dai = { - .probe = jz4740_i2s_dai_probe, .playback = { .channels_min = 1, .channels_max = 2, @@ -384,7 +384,6 @@ static const struct i2s_soc_info x1000_i2s_soc_info = { }; static struct snd_soc_dai_driver jz4770_i2s_dai = { - .probe = jz4740_i2s_dai_probe, .playback = { .channels_min = 1, .channels_max = 2, -- cgit v1.2.3 From dd64a7546dcba40aef17fea52c66fac766902d32 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:29 +0000 Subject: ASoC: cirrus: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Reviewed-by: Alexander Sverdlin Link: https://lore.kernel.org/r/87wmy59m7a.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/cirrus/ep93xx-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index afc6b5b570ea..522de4b80293 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@ -407,6 +407,7 @@ static int ep93xx_i2s_resume(struct snd_soc_component *component) #endif static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = { + .probe = ep93xx_i2s_dai_probe, .startup = ep93xx_i2s_startup, .shutdown = ep93xx_i2s_shutdown, .hw_params = ep93xx_i2s_hw_params, @@ -418,7 +419,6 @@ static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = { static struct snd_soc_dai_driver ep93xx_i2s_dai = { .symmetric_rate = 1, - .probe = ep93xx_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, -- cgit v1.2.3 From fda5c5e752aae1b1b8809055b09ba5184507ce5a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:41 +0000 Subject: ASoC: samsung: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ttt99m6y.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 5 ++--- sound/soc/samsung/pcm.c | 18 +++++++++--------- 2 files changed, 11 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index f3d98abd5f0d..3af48c9b5ab7 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1120,6 +1120,8 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops samsung_i2s_dai_ops = { + .probe = samsung_i2s_dai_probe, + .remove = samsung_i2s_dai_remove, .trigger = i2s_trigger, .hw_params = i2s_hw_params, .set_fmt = i2s_set_fmt, @@ -1188,9 +1190,6 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv, for (i = 0; i < num_dais; i++) { dai_drv = &priv->dai_drv[i]; - dai_drv->probe = samsung_i2s_dai_probe; - dai_drv->remove = samsung_i2s_dai_remove; - dai_drv->symmetric_rate = 1; dai_drv->ops = &samsung_i2s_dai_ops; diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 335fe5cb9cfc..d2cdc5c8e05b 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -432,14 +432,6 @@ static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai, return 0; } -static const struct snd_soc_dai_ops s3c_pcm_dai_ops = { - .set_sysclk = s3c_pcm_set_sysclk, - .set_clkdiv = s3c_pcm_set_clkdiv, - .trigger = s3c_pcm_trigger, - .hw_params = s3c_pcm_hw_params, - .set_fmt = s3c_pcm_set_fmt, -}; - static int s3c_pcm_dai_probe(struct snd_soc_dai *dai) { struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(dai); @@ -449,11 +441,19 @@ static int s3c_pcm_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops s3c_pcm_dai_ops = { + .probe = s3c_pcm_dai_probe, + .set_sysclk = s3c_pcm_set_sysclk, + .set_clkdiv = s3c_pcm_set_clkdiv, + .trigger = s3c_pcm_trigger, + .hw_params = s3c_pcm_hw_params, + .set_fmt = s3c_pcm_set_fmt, +}; + #define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000 #define S3C_PCM_DAI_DECLARE \ .symmetric_rate = 1, \ - .probe = s3c_pcm_dai_probe, \ .ops = &s3c_pcm_dai_ops, \ .playback = { \ .channels_min = 2, \ -- cgit v1.2.3 From d656593b3d5218e0ce623cd725e806879e9ce2df Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:52 +0000 Subject: ASoC: mediatek: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Acked-by: Trevor Wu Link: https://lore.kernel.org/r/87sf8t9m6n.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8195/mt8195-dai-etdm.c | 56 ++++++++++++++++------------- 1 file changed, 31 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c index eedb9165f911..fd4f9f8f032d 100644 --- a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c +++ b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c @@ -2456,25 +2456,6 @@ static int mtk_dai_hdmitx_dptx_set_sysclk(struct snd_soc_dai *dai, return mtk_dai_etdm_cal_mclk(afe, freq, dai->id); } -static const struct snd_soc_dai_ops mtk_dai_etdm_ops = { - .startup = mtk_dai_etdm_startup, - .shutdown = mtk_dai_etdm_shutdown, - .hw_params = mtk_dai_etdm_hw_params, - .trigger = mtk_dai_etdm_trigger, - .set_sysclk = mtk_dai_etdm_set_sysclk, - .set_fmt = mtk_dai_etdm_set_fmt, - .set_tdm_slot = mtk_dai_etdm_set_tdm_slot, -}; - -static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = { - .startup = mtk_dai_hdmitx_dptx_startup, - .shutdown = mtk_dai_hdmitx_dptx_shutdown, - .hw_params = mtk_dai_hdmitx_dptx_hw_params, - .trigger = mtk_dai_hdmitx_dptx_trigger, - .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk, - .set_fmt = mtk_dai_etdm_set_fmt, -}; - /* dai driver */ #define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_384000) @@ -2505,6 +2486,36 @@ static int mtk_dai_etdm_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = { + .startup = mtk_dai_hdmitx_dptx_startup, + .shutdown = mtk_dai_hdmitx_dptx_shutdown, + .hw_params = mtk_dai_hdmitx_dptx_hw_params, + .trigger = mtk_dai_hdmitx_dptx_trigger, + .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk, + .set_fmt = mtk_dai_etdm_set_fmt, +}; + +static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops2 = { + .probe = mtk_dai_etdm_probe, + .startup = mtk_dai_hdmitx_dptx_startup, + .shutdown = mtk_dai_hdmitx_dptx_shutdown, + .hw_params = mtk_dai_hdmitx_dptx_hw_params, + .trigger = mtk_dai_hdmitx_dptx_trigger, + .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk, + .set_fmt = mtk_dai_etdm_set_fmt, +}; + +static const struct snd_soc_dai_ops mtk_dai_etdm_ops = { + .probe = mtk_dai_etdm_probe, + .startup = mtk_dai_etdm_startup, + .shutdown = mtk_dai_etdm_shutdown, + .hw_params = mtk_dai_etdm_hw_params, + .trigger = mtk_dai_etdm_trigger, + .set_sysclk = mtk_dai_etdm_set_sysclk, + .set_fmt = mtk_dai_etdm_set_fmt, + .set_tdm_slot = mtk_dai_etdm_set_tdm_slot, +}; + static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { { .name = "DPTX", @@ -2529,7 +2540,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .formats = MTK_ETDM_FORMATS, }, .ops = &mtk_dai_etdm_ops, - .probe = mtk_dai_etdm_probe, }, { .name = "ETDM2_IN", @@ -2542,7 +2552,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .formats = MTK_ETDM_FORMATS, }, .ops = &mtk_dai_etdm_ops, - .probe = mtk_dai_etdm_probe, }, { .name = "ETDM1_OUT", @@ -2555,7 +2564,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .formats = MTK_ETDM_FORMATS, }, .ops = &mtk_dai_etdm_ops, - .probe = mtk_dai_etdm_probe, }, { .name = "ETDM2_OUT", @@ -2568,7 +2576,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .formats = MTK_ETDM_FORMATS, }, .ops = &mtk_dai_etdm_ops, - .probe = mtk_dai_etdm_probe, }, { .name = "ETDM3_OUT", @@ -2580,8 +2587,7 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .rates = MTK_ETDM_RATES, .formats = MTK_ETDM_FORMATS, }, - .ops = &mtk_dai_hdmitx_dptx_ops, - .probe = mtk_dai_etdm_probe, + .ops = &mtk_dai_hdmitx_dptx_ops2, }, }; -- cgit v1.2.3 From bd6af1bc86014f67cbed3804eb6c9bdbfed1b3c0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:57:58 +0000 Subject: ASoC: rockchip: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r0od9m6i.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 2 +- sound/soc/rockchip/rockchip_i2s_tdm.c | 2 +- sound/soc/rockchip/rockchip_pdm.c | 2 +- sound/soc/rockchip/rockchip_spdif.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 575a0b9b01e9..834fbb5cf810 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -539,6 +539,7 @@ static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = { + .probe = rockchip_i2s_dai_probe, .hw_params = rockchip_i2s_hw_params, .set_bclk_ratio = rockchip_i2s_set_bclk_ratio, .set_sysclk = rockchip_i2s_set_sysclk, @@ -547,7 +548,6 @@ static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = { }; static struct snd_soc_dai_driver rockchip_i2s_dai = { - .probe = rockchip_i2s_dai_probe, .ops = &rockchip_i2s_dai_ops, .symmetric_rate = 1, }; diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index 166257c6ae14..d3700f3c98e6 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -1114,6 +1114,7 @@ static int rockchip_i2s_tdm_set_bclk_ratio(struct snd_soc_dai *dai, } static const struct snd_soc_dai_ops rockchip_i2s_tdm_dai_ops = { + .probe = rockchip_i2s_tdm_dai_probe, .hw_params = rockchip_i2s_tdm_hw_params, .set_bclk_ratio = rockchip_i2s_tdm_set_bclk_ratio, .set_sysclk = rockchip_i2s_tdm_set_sysclk, @@ -1324,7 +1325,6 @@ static const struct of_device_id rockchip_i2s_tdm_match[] = { }; static const struct snd_soc_dai_driver i2s_tdm_dai = { - .probe = rockchip_i2s_tdm_dai_probe, .ops = &rockchip_i2s_tdm_dai_ops, }; diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c index 52f9aae60be8..667f2fa65c3e 100644 --- a/sound/soc/rockchip/rockchip_pdm.c +++ b/sound/soc/rockchip/rockchip_pdm.c @@ -379,6 +379,7 @@ static int rockchip_pdm_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = { + .probe = rockchip_pdm_dai_probe, .set_fmt = rockchip_pdm_set_fmt, .trigger = rockchip_pdm_trigger, .hw_params = rockchip_pdm_hw_params, @@ -391,7 +392,6 @@ static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = { SNDRV_PCM_FMTBIT_S32_LE) static struct snd_soc_dai_driver rockchip_pdm_dai = { - .probe = rockchip_pdm_dai_probe, .capture = { .stream_name = "Capture", .channels_min = 2, diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c index 0b73fe94e4bb..1a24b78e9e02 100644 --- a/sound/soc/rockchip/rockchip_spdif.c +++ b/sound/soc/rockchip/rockchip_spdif.c @@ -202,12 +202,12 @@ static int rk_spdif_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops rk_spdif_dai_ops = { + .probe = rk_spdif_dai_probe, .hw_params = rk_spdif_hw_params, .trigger = rk_spdif_trigger, }; static struct snd_soc_dai_driver rk_spdif_dai = { - .probe = rk_spdif_dai_probe, .playback = { .stream_name = "Playback", .channels_min = 2, -- cgit v1.2.3 From 89621b57eef451592553227a781d12aa1a6a2556 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:13 +0000 Subject: ASoC: uniphier: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pm3x9m62.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/uniphier/aio-cpu.c | 161 +++++++++++++++++++++++++++++++++++------- sound/soc/uniphier/aio-ld11.c | 62 +++------------- sound/soc/uniphier/aio-pxs2.c | 55 ++------------- sound/soc/uniphier/aio.h | 10 +-- 4 files changed, 156 insertions(+), 132 deletions(-) (limited to 'sound') diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c index 4e8d5f7532ba..7c5188477b7c 100644 --- a/sound/soc/uniphier/aio-cpu.c +++ b/sound/soc/uniphier/aio-cpu.c @@ -355,30 +355,7 @@ static int uniphier_aio_prepare(struct snd_pcm_substream *substream, return 0; } -const struct snd_soc_dai_ops uniphier_aio_i2s_ops = { - .set_sysclk = uniphier_aio_set_sysclk, - .set_pll = uniphier_aio_set_pll, - .set_fmt = uniphier_aio_set_fmt, - .startup = uniphier_aio_startup, - .shutdown = uniphier_aio_shutdown, - .hw_params = uniphier_aio_hw_params, - .hw_free = uniphier_aio_hw_free, - .prepare = uniphier_aio_prepare, -}; -EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ops); - -const struct snd_soc_dai_ops uniphier_aio_spdif_ops = { - .set_sysclk = uniphier_aio_set_sysclk, - .set_pll = uniphier_aio_set_pll, - .startup = uniphier_aio_startup, - .shutdown = uniphier_aio_shutdown, - .hw_params = uniphier_aio_hw_params, - .hw_free = uniphier_aio_hw_free, - .prepare = uniphier_aio_prepare, -}; -EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ops); - -int uniphier_aio_dai_probe(struct snd_soc_dai *dai) +static int uniphier_aio_dai_probe(struct snd_soc_dai *dai) { struct uniphier_aio *aio = uniphier_priv(dai); int i; @@ -403,9 +380,8 @@ int uniphier_aio_dai_probe(struct snd_soc_dai *dai) return 0; } -EXPORT_SYMBOL_GPL(uniphier_aio_dai_probe); -int uniphier_aio_dai_remove(struct snd_soc_dai *dai) +static int uniphier_aio_dai_remove(struct snd_soc_dai *dai) { struct uniphier_aio *aio = uniphier_priv(dai); @@ -413,7 +389,138 @@ int uniphier_aio_dai_remove(struct snd_soc_dai *dai) return 0; } -EXPORT_SYMBOL_GPL(uniphier_aio_dai_remove); + +static int uniphier_aio_ld11_probe(struct snd_soc_dai *dai) +{ + int ret; + + ret = uniphier_aio_dai_probe(dai); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000); + if (ret < 0) + return ret; + ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800); + if (ret < 0) + return ret; + ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800); + if (ret < 0) + return ret; + + return 0; +} + +static int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai) +{ + int ret; + + ret = uniphier_aio_dai_probe(dai); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000); + if (ret < 0) + return ret; + ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800); + if (ret < 0) + return ret; + ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800); + if (ret < 0) + return ret; + + return 0; +} + +const struct snd_soc_dai_ops uniphier_aio_i2s_ld11_ops = { + .probe = uniphier_aio_ld11_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .set_fmt = uniphier_aio_set_fmt, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ld11_ops); + +const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops = { + .probe = uniphier_aio_ld11_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops); + +const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops2 = { + .probe = uniphier_aio_ld11_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, + .compress_new = snd_soc_new_compress, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops2); + +const struct snd_soc_dai_ops uniphier_aio_i2s_pxs2_ops = { + .probe = uniphier_aio_pxs2_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .set_fmt = uniphier_aio_set_fmt, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_i2s_pxs2_ops); + +const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops = { + .probe = uniphier_aio_pxs2_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops); + +const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops2 = { + .probe = uniphier_aio_pxs2_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, + .compress_new = snd_soc_new_compress, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops2); static void uniphier_aio_dai_suspend(struct snd_soc_dai *dai) { diff --git a/sound/soc/uniphier/aio-ld11.c b/sound/soc/uniphier/aio-ld11.c index 7b3cf5d751f6..15dbded63804 100644 --- a/sound/soc/uniphier/aio-ld11.c +++ b/sound/soc/uniphier/aio-ld11.c @@ -188,36 +188,9 @@ static const struct uniphier_aio_pll uniphier_aio_pll_ld11[] = { [AUD_PLL_HSC0] = { .enable = true, }, }; -static int uniphier_aio_ld11_probe(struct snd_soc_dai *dai) -{ - int ret; - - ret = uniphier_aio_dai_probe(dai); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800); - if (ret < 0) - return ret; - - return 0; -} - static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { { .name = AUD_GNAME_HDMI, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -234,12 +207,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_PCMIN2, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .capture = { .stream_name = AUD_NAME_PCMIN2, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -247,12 +218,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_GNAME_LINE, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT2, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -267,12 +236,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_HPCMOUT1, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_HPCMOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -280,12 +247,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 8, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_PCMOUT3, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT3, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -293,12 +258,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_HIECOUT1, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_HIECOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -306,12 +269,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_ld11_ops, }, { .name = AUD_NAME_EPCMOUT2, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_EPCMOUT2, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -321,12 +282,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_EPCMOUT3, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_EPCMOUT3, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -336,19 +295,16 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_HIECCOMPOUT1, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, - .compress_new = snd_soc_new_compress, .playback = { .stream_name = AUD_NAME_HIECCOMPOUT1, .channels_min = 1, .channels_max = 1, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_ld11_ops2, }, }; diff --git a/sound/soc/uniphier/aio-pxs2.c b/sound/soc/uniphier/aio-pxs2.c index 899904f7ffd6..305cb2a1253d 100644 --- a/sound/soc/uniphier/aio-pxs2.c +++ b/sound/soc/uniphier/aio-pxs2.c @@ -141,36 +141,9 @@ static const struct uniphier_aio_pll uniphier_aio_pll_pxs2[] = { [AUD_PLL_HSC0] = { .enable = true, }, }; -static int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai) -{ - int ret; - - ret = uniphier_aio_dai_probe(dai); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800); - if (ret < 0) - return ret; - - return 0; -} - static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { { .name = AUD_GNAME_HDMI, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_HPCMOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -178,12 +151,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_pxs2_ops, }, { .name = AUD_GNAME_LINE, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -198,12 +169,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_pxs2_ops, }, { .name = AUD_GNAME_AUX, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT2, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -218,12 +187,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_pxs2_ops, }, { .name = AUD_NAME_HIECOUT1, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_HIECOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -231,12 +198,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_pxs2_ops, }, { .name = AUD_NAME_IECOUT1, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_IECOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -244,31 +209,25 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_pxs2_ops, }, { .name = AUD_NAME_HIECCOMPOUT1, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, - .compress_new = snd_soc_new_compress, .playback = { .stream_name = AUD_NAME_HIECCOMPOUT1, .channels_min = 1, .channels_max = 1, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_pxs2_ops2, }, { .name = AUD_NAME_IECCOMPOUT1, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, - .compress_new = snd_soc_new_compress, .playback = { .stream_name = AUD_NAME_IECCOMPOUT1, .channels_min = 1, .channels_max = 1, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_pxs2_ops2, }, }; diff --git a/sound/soc/uniphier/aio.h b/sound/soc/uniphier/aio.h index 0b03571aa9f0..09ccb47337fd 100644 --- a/sound/soc/uniphier/aio.h +++ b/sound/soc/uniphier/aio.h @@ -306,12 +306,14 @@ static inline struct uniphier_aio *uniphier_priv(struct snd_soc_dai *dai) int uniphier_aiodma_soc_register_platform(struct platform_device *pdev); extern const struct snd_compress_ops uniphier_aio_compress_ops; -int uniphier_aio_dai_probe(struct snd_soc_dai *dai); -int uniphier_aio_dai_remove(struct snd_soc_dai *dai); int uniphier_aio_probe(struct platform_device *pdev); int uniphier_aio_remove(struct platform_device *pdev); -extern const struct snd_soc_dai_ops uniphier_aio_i2s_ops; -extern const struct snd_soc_dai_ops uniphier_aio_spdif_ops; +extern const struct snd_soc_dai_ops uniphier_aio_i2s_ld11_ops; +extern const struct snd_soc_dai_ops uniphier_aio_i2s_pxs2_ops; +extern const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops; +extern const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops2; +extern const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops; +extern const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops2; u64 aio_rb_cnt(struct uniphier_aio_sub *sub); u64 aio_rbt_cnt_to_end(struct uniphier_aio_sub *sub); -- cgit v1.2.3 From b396843799ae92bbac30874f18e6a79d5fa736d1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:19 +0000 Subject: ASoC: loongson: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87o7jh9m5w.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/loongson/loongson_i2s.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/loongson/loongson_i2s.c b/sound/soc/loongson/loongson_i2s.c index b919f0fe8361..d45228a3a558 100644 --- a/sound/soc/loongson/loongson_i2s.c +++ b/sound/soc/loongson/loongson_i2s.c @@ -204,13 +204,6 @@ static int loongson_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static const struct snd_soc_dai_ops loongson_i2s_dai_ops = { - .trigger = loongson_i2s_trigger, - .hw_params = loongson_i2s_hw_params, - .set_sysclk = loongson_i2s_set_dai_sysclk, - .set_fmt = loongson_i2s_set_fmt, -}; - static int loongson_i2s_dai_probe(struct snd_soc_dai *cpu_dai) { struct loongson_i2s *i2s = dev_get_drvdata(cpu_dai->dev); @@ -222,9 +215,16 @@ static int loongson_i2s_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops loongson_i2s_dai_ops = { + .probe = loongson_i2s_dai_probe, + .trigger = loongson_i2s_trigger, + .hw_params = loongson_i2s_hw_params, + .set_sysclk = loongson_i2s_set_dai_sysclk, + .set_fmt = loongson_i2s_set_fmt, +}; + struct snd_soc_dai_driver loongson_i2s_dai = { .name = "loongson-i2s", - .probe = loongson_i2s_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, -- cgit v1.2.3 From e86cc958cf2d7d8813fd865603d83a2963e87954 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:25 +0000 Subject: ASoC: starfive: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Acked-by: Walker Chen Link: https://lore.kernel.org/r/87msz19m5r.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/starfive/jh7110_tdm.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/starfive/jh7110_tdm.c b/sound/soc/starfive/jh7110_tdm.c index 705f1420097b..8c117794b028 100644 --- a/sound/soc/starfive/jh7110_tdm.c +++ b/sound/soc/starfive/jh7110_tdm.c @@ -463,13 +463,6 @@ static int jh7110_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai, return 0; } -static const struct snd_soc_dai_ops jh7110_tdm_dai_ops = { - .startup = jh7110_tdm_startup, - .hw_params = jh7110_tdm_hw_params, - .trigger = jh7110_tdm_trigger, - .set_fmt = jh7110_tdm_set_dai_fmt, -}; - static int jh7110_tdm_dai_probe(struct snd_soc_dai *dai) { struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(dai); @@ -479,6 +472,14 @@ static int jh7110_tdm_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops jh7110_tdm_dai_ops = { + .probe = jh7110_tdm_dai_probe, + .startup = jh7110_tdm_startup, + .hw_params = jh7110_tdm_hw_params, + .trigger = jh7110_tdm_trigger, + .set_fmt = jh7110_tdm_set_dai_fmt, +}; + #define JH7110_TDM_RATES SNDRV_PCM_RATE_8000_48000 #define JH7110_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ @@ -502,7 +503,6 @@ static struct snd_soc_dai_driver jh7110_tdm_dai = { .formats = JH7110_TDM_FORMATS, }, .ops = &jh7110_tdm_dai_ops, - .probe = jh7110_tdm_dai_probe, .symmetric_rate = 1, }; -- cgit v1.2.3 From 4f1ec3da4e1377b548e2af55586d0f7a92847a96 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:30 +0000 Subject: ASoC: hisilicon: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87leel9m5l.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/hisilicon/hi6210-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c index 27219a9e7d0d..dd7d2a077248 100644 --- a/sound/soc/hisilicon/hi6210-i2s.c +++ b/sound/soc/hisilicon/hi6210-i2s.c @@ -511,6 +511,7 @@ static int hi6210_i2s_dai_probe(struct snd_soc_dai *dai) static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = { + .probe = hi6210_i2s_dai_probe, .trigger = hi6210_i2s_trigger, .hw_params = hi6210_i2s_hw_params, .set_fmt = hi6210_i2s_set_fmt, @@ -519,7 +520,6 @@ static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = { }; static const struct snd_soc_dai_driver hi6210_i2s_dai_init = { - .probe = hi6210_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, -- cgit v1.2.3 From 586685f14d9dd16556449ceaa07c2bdc94cbed1b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:36 +0000 Subject: ASoC: codecs/wm*: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87jzu59m5f.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm2200.c | 12 ++++++------ sound/soc/codecs/wm5102.c | 6 +++++- sound/soc/codecs/wm5110.c | 8 ++++++-- sound/soc/codecs/wm8994.c | 2 +- 4 files changed, 18 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 36cdf97993a5..9679906c6bd5 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1770,11 +1770,6 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops wm2200_dai_ops = { - .set_fmt = wm2200_set_fmt, - .hw_params = wm2200_hw_params, -}; - static int wm2200_set_sysclk(struct snd_soc_component *component, int clk_id, int source, unsigned int freq, int dir) { @@ -2068,6 +2063,12 @@ static int wm2200_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops wm2200_dai_ops = { + .probe = wm2200_dai_probe, + .set_fmt = wm2200_set_fmt, + .hw_params = wm2200_hw_params, +}; + #define WM2200_RATES SNDRV_PCM_RATE_8000_48000 #define WM2200_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ @@ -2075,7 +2076,6 @@ static int wm2200_dai_probe(struct snd_soc_dai *dai) static struct snd_soc_dai_driver wm2200_dai = { .name = "wm2200", - .probe = wm2200_dai_probe, .playback = { .stream_name = "Playback", .channels_min = 2, diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 3bdbdf3770b5..4ecf07c7448c 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1773,6 +1773,10 @@ static int wm5102_set_fll(struct snd_soc_component *component, int fll_id, #define WM5102_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) +static const struct snd_soc_dai_ops wm5102_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver wm5102_dai[] = { { .name = "wm5102-aif1", @@ -1906,7 +1910,7 @@ static struct snd_soc_dai_driver wm5102_dai[] = { .rates = WM5102_RATES, .formats = WM5102_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &wm5102_dai_ops, }, { .name = "wm5102-dsp-trace", diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index ad670300de8d..ac1f2c850346 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2073,6 +2073,10 @@ static int wm5110_set_fll(struct snd_soc_component *component, int fll_id, #define WM5110_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) +static const struct snd_soc_dai_ops wm5110_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver wm5110_dai[] = { { .name = "wm5110-aif1", @@ -2206,7 +2210,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = { .rates = WM5110_RATES, .formats = WM5110_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &wm5110_dai_ops, }, { .name = "wm5110-dsp-voicectrl", @@ -2227,7 +2231,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = { .rates = WM5110_RATES, .formats = WM5110_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &wm5110_dai_ops, }, { .name = "wm5110-dsp-trace", diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index bca3ebe0dac4..a48e904a9740 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3215,6 +3215,7 @@ static const struct snd_soc_dai_ops wm8994_aif1_dai_ops = { }; static const struct snd_soc_dai_ops wm8994_aif2_dai_ops = { + .probe = wm8994_aif2_probe, .set_sysclk = wm8994_set_dai_sysclk, .set_fmt = wm8994_set_dai_fmt, .hw_params = wm8994_hw_params, @@ -3269,7 +3270,6 @@ static struct snd_soc_dai_driver wm8994_dai[] = { .formats = WM8994_FORMATS, .sig_bits = 24, }, - .probe = wm8994_aif2_probe, .ops = &wm8994_aif2_dai_ops, }, { -- cgit v1.2.3 From 80585b0c6aaabc5a4a8273c2e8e084a4f4d7f62f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:42 +0000 Subject: ASoC: soc-topology: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87il9p9m5a.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index ad08d4f75a7b..e783055b6c3a 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1560,6 +1560,10 @@ static void set_dai_flags(struct snd_soc_dai_driver *dai_drv, 1 : 0; } +static const struct snd_soc_dai_ops tplg_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static int soc_tplg_dai_create(struct soc_tplg *tplg, struct snd_soc_tplg_pcm *pcm) { @@ -1601,7 +1605,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, } if (pcm->compress) - dai_drv->compress_new = snd_soc_new_compress; + dai_drv->ops = &tplg_dai_ops; /* pass control to component driver for optional further init */ ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL); -- cgit v1.2.3 From e22a907d66b679d2ce86fe73fbd47760981b30cb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:47 +0000 Subject: ASoC: codecs/cs47lxx: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Acked-by: Charles Keepax Link: https://lore.kernel.org/r/87h6p99m55.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l15.c | 6 +++++- sound/soc/codecs/cs47l24.c | 8 ++++++-- sound/soc/codecs/cs47l35.c | 8 ++++++-- sound/soc/codecs/cs47l85.c | 8 ++++++-- sound/soc/codecs/cs47l90.c | 8 ++++++-- sound/soc/codecs/cs47l92.c | 6 +++++- 6 files changed, 34 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c index a6538dab6639..1245e1a4f2a5 100644 --- a/sound/soc/codecs/cs47l15.c +++ b/sound/soc/codecs/cs47l15.c @@ -1143,6 +1143,10 @@ static int cs47l15_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l15_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l15_dai[] = { { .name = "cs47l15-aif1", @@ -1219,7 +1223,7 @@ static struct snd_soc_dai_driver cs47l15_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &cs47l15_dai_ops, }, { .name = "cs47l15-dsp-trace", diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index a07b621d463e..cfa1d34f6ebd 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -957,6 +957,10 @@ static int cs47l24_set_fll(struct snd_soc_component *component, int fll_id, #define CS47L24_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) +static const struct snd_soc_dai_ops cs47l24_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l24_dai[] = { { .name = "cs47l24-aif1", @@ -1033,7 +1037,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = { .rates = CS47L24_RATES, .formats = CS47L24_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &cs47l24_dai_ops, }, { .name = "cs47l24-dsp-voicectrl", @@ -1054,7 +1058,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = { .rates = CS47L24_RATES, .formats = CS47L24_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &cs47l24_dai_ops, }, { .name = "cs47l24-dsp-trace", diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c index c05c80c16c84..a953f2ede1ee 100644 --- a/sound/soc/codecs/cs47l35.c +++ b/sound/soc/codecs/cs47l35.c @@ -1348,6 +1348,10 @@ static int cs47l35_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l35_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l35_dai[] = { { .name = "cs47l35-aif1", @@ -1462,7 +1466,7 @@ static struct snd_soc_dai_driver cs47l35_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l35_dai_ops, }, { .name = "cs47l35-dsp-voicectrl", @@ -1483,7 +1487,7 @@ static struct snd_soc_dai_driver cs47l35_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l35_dai_ops, }, { .name = "cs47l35-dsp-trace", diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c index dd7997a53e70..827685481859 100644 --- a/sound/soc/codecs/cs47l85.c +++ b/sound/soc/codecs/cs47l85.c @@ -2249,6 +2249,10 @@ static int cs47l85_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l85_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l85_dai[] = { { .name = "cs47l85-aif1", @@ -2404,7 +2408,7 @@ static struct snd_soc_dai_driver cs47l85_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l85_dai_ops, }, { .name = "cs47l85-dsp-voicectrl", @@ -2425,7 +2429,7 @@ static struct snd_soc_dai_driver cs47l85_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l85_dai_ops, }, { .name = "cs47l85-dsp-trace", diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c index cdd5e7e20b5d..2c9a5372cf51 100644 --- a/sound/soc/codecs/cs47l90.c +++ b/sound/soc/codecs/cs47l90.c @@ -2168,6 +2168,10 @@ static int cs47l90_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l90_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l90_dai[] = { { .name = "cs47l90-aif1", @@ -2323,7 +2327,7 @@ static struct snd_soc_dai_driver cs47l90_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l90_dai_ops, }, { .name = "cs47l90-dsp-voicectrl", @@ -2344,7 +2348,7 @@ static struct snd_soc_dai_driver cs47l90_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l90_dai_ops, }, { .name = "cs47l90-dsp-trace", diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c index bc4d311d4778..352deeaff1ca 100644 --- a/sound/soc/codecs/cs47l92.c +++ b/sound/soc/codecs/cs47l92.c @@ -1690,6 +1690,10 @@ static int cs47l92_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l92_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l92_dai[] = { { .name = "cs47l92-aif1", @@ -1823,7 +1827,7 @@ static struct snd_soc_dai_driver cs47l92_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &cs47l92_dai_ops, }, { .name = "cs47l92-dsp-trace", -- cgit v1.2.3 From 878b5fee6e2296685f459148ab82c6a3f300bfe1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:53 +0000 Subject: ASoC: codecs/cx2072x: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87fs4t9m4y.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/cx2072x.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index 082231088a26..f8b128084015 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -1546,6 +1546,14 @@ static int cx2072x_dsp_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops cx2072x_dai_ops2 = { + .probe = cx2072x_dsp_dai_probe, + .set_sysclk = cx2072x_set_dai_sysclk, + .set_fmt = cx2072x_set_dai_fmt, + .hw_params = cx2072x_hw_params, + .set_bclk_ratio = cx2072x_set_dai_bclk_ratio, +}; + #define CX2072X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = { @@ -1572,7 +1580,6 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = { { /* plabayck only, return echo reference to Conexant DSP chip */ .name = "cx2072x-dsp", .id = CX2072X_DAI_DSP, - .probe = cx2072x_dsp_dai_probe, .playback = { .stream_name = "DSP Playback", .channels_min = 2, @@ -1580,7 +1587,7 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = { .rates = CX2072X_RATES_DSP, .formats = CX2072X_FORMATS, }, - .ops = &cx2072x_dai_ops, + .ops = &cx2072x_dai_ops2, }, { /* plabayck only, return echo reference through I2S TX */ .name = "cx2072x-aec", -- cgit v1.2.3 From 2edc4a2cc11160f4729d28094952fc906b74ca64 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:58:58 +0000 Subject: ASoC: codecs/hdmi-codec: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87edkd9m4t.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 44 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index d21f69f05342..13689e718d36 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -723,24 +723,6 @@ static u64 hdmi_codec_formats = SND_SOC_POSSIBLE_DAIFMT_LEFT_J | SND_SOC_POSSIBLE_DAIFMT_AC97; -static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { - .startup = hdmi_codec_startup, - .shutdown = hdmi_codec_shutdown, - .hw_params = hdmi_codec_hw_params, - .prepare = hdmi_codec_prepare, - .set_fmt = hdmi_codec_i2s_set_fmt, - .mute_stream = hdmi_codec_mute, - .auto_selectable_formats = &hdmi_codec_formats, - .num_auto_selectable_formats = 1, -}; - -static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { - .startup = hdmi_codec_startup, - .shutdown = hdmi_codec_shutdown, - .hw_params = hdmi_codec_hw_params, - .mute_stream = hdmi_codec_mute, -}; - #define HDMI_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\ @@ -921,10 +903,31 @@ static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { + .probe = hdmi_dai_probe, + .startup = hdmi_codec_startup, + .shutdown = hdmi_codec_shutdown, + .hw_params = hdmi_codec_hw_params, + .prepare = hdmi_codec_prepare, + .set_fmt = hdmi_codec_i2s_set_fmt, + .mute_stream = hdmi_codec_mute, + .pcm_new = hdmi_codec_pcm_new, + .auto_selectable_formats = &hdmi_codec_formats, + .num_auto_selectable_formats = 1, +}; + +static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { + .probe = hdmi_dai_spdif_probe, + .startup = hdmi_codec_startup, + .shutdown = hdmi_codec_shutdown, + .hw_params = hdmi_codec_hw_params, + .mute_stream = hdmi_codec_mute, + .pcm_new = hdmi_codec_pcm_new, +}; + static const struct snd_soc_dai_driver hdmi_i2s_dai = { .name = "i2s-hifi", .id = DAI_ID_I2S, - .probe = hdmi_dai_probe, .playback = { .stream_name = "I2S Playback", .channels_min = 2, @@ -942,13 +945,11 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = { .sig_bits = 24, }, .ops = &hdmi_codec_i2s_dai_ops, - .pcm_new = hdmi_codec_pcm_new, }; static const struct snd_soc_dai_driver hdmi_spdif_dai = { .name = "spdif-hifi", .id = DAI_ID_SPDIF, - .probe = hdmi_dai_spdif_probe, .playback = { .stream_name = "SPDIF Playback", .channels_min = 2, @@ -964,7 +965,6 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { .formats = SPDIF_FORMATS, }, .ops = &hdmi_codec_spdif_dai_ops, - .pcm_new = hdmi_codec_pcm_new, }; static int hdmi_of_xlate_dai_id(struct snd_soc_component *component, -- cgit v1.2.3 From 446b31e894935ebbcf84302061a4e0e2efb2368f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Aug 2023 22:59:03 +0000 Subject: ASoC: soc-dai.h: remove unused call back functions Now, all drivers are using ops call backs. Let's remove unused other call back functions. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87cyzx9m4o.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 25 ------------------------- 1 file changed, 25 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7dbf37e0ba2f..a5b96c17633a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2510,7 +2510,6 @@ struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, { struct device *dev = component->dev; struct snd_soc_dai *dai; - struct snd_soc_dai_ops *ops; /* REMOVE ME */ lockdep_assert_held(&client_mutex); @@ -2539,30 +2538,6 @@ struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, if (!dai->name) return NULL; - /* REMOVE ME */ - if (dai_drv->probe || - dai_drv->remove || - dai_drv->compress_new || - dai_drv->pcm_new || - dai_drv->probe_order || - dai_drv->remove_order) { - - ops = devm_kzalloc(dev, sizeof(struct snd_soc_dai_ops), GFP_KERNEL); - if (!ops) - return NULL; - if (dai_drv->ops) - memcpy(ops, dai_drv->ops, sizeof(struct snd_soc_dai_ops)); - - ops->probe = dai_drv->probe; - ops->remove = dai_drv->remove; - ops->compress_new = dai_drv->compress_new; - ops->pcm_new = dai_drv->pcm_new; - ops->probe_order = dai_drv->probe_order; - ops->remove_order = dai_drv->remove_order; - - dai_drv->ops = ops; - } - dai->component = component; dai->dev = dev; dai->driver = dai_drv; -- cgit v1.2.3 From b39eee2754e9fbcbbdd866c1aad59575d8c4342e Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sun, 13 Aug 2023 08:34:58 +0100 Subject: ASoC: ak4613: Simplify probe() Simpilfy probe() by replacing of_device_get_match_data() and id lookup for retrieving match data by i2c_get_match_data(). While at it, drop unused local variable np from probe(). Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230813073458.59606-1-biju.das.jz@bp.renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/ak4613.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index ad56caec9dac..619a817ee91c 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -880,20 +880,11 @@ static void ak4613_parse_of(struct ak4613_priv *priv, static int ak4613_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; - struct device_node *np = dev->of_node; const struct regmap_config *regmap_cfg; struct regmap *regmap; struct ak4613_priv *priv; - regmap_cfg = NULL; - if (np) - regmap_cfg = of_device_get_match_data(dev); - else { - const struct i2c_device_id *id = - i2c_match_id(ak4613_i2c_id, i2c); - regmap_cfg = (const struct regmap_config *)id->driver_data; - } - + regmap_cfg = i2c_get_match_data(i2c); if (!regmap_cfg) return -EINVAL; -- cgit v1.2.3 From 11e756cc85fac43e2025306ad6aea80114cc7e98 Mon Sep 17 00:00:00 2001 From: Guiting Shen Date: Sun, 13 Aug 2023 20:55:20 +0800 Subject: ASoC: tlv320aic32x4: Fix the divide by zero The value of register(NDAC,MDAC,NADC,MADC,BCLKN) maybe zero lead to divide by zero in clk_aic32x4_div_recalc_rate().And the rate should be divide by 128 if the value was zero in this function according to the datasheet. Add the macro AIC32X4_DIV_MAX to present the 128 and return 0 if failing to read the value of register. Signed-off-by: Guiting Shen Link: https://lore.kernel.org/r/20230813125520.11067-1-aarongt.shen@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4-clk.c | 16 +++++++++++----- sound/soc/codecs/tlv320aic32x4.h | 5 +++-- 2 files changed, 14 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c index c116e82f712d..5c0a76a4a106 100644 --- a/sound/soc/codecs/tlv320aic32x4-clk.c +++ b/sound/soc/codecs/tlv320aic32x4-clk.c @@ -321,7 +321,7 @@ static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate, u8 divisor; divisor = DIV_ROUND_UP(parent_rate, rate); - if (divisor > 128) + if (divisor > AIC32X4_DIV_MAX) return -EINVAL; return regmap_update_bits(div->regmap, div->reg, @@ -334,7 +334,7 @@ static int clk_aic32x4_div_determine_rate(struct clk_hw *hw, unsigned long divisor; divisor = DIV_ROUND_UP(req->best_parent_rate, req->rate); - if (divisor > 128) + if (divisor > AIC32X4_DIV_MAX) return -EINVAL; req->rate = DIV_ROUND_UP(req->best_parent_rate, divisor); @@ -345,12 +345,18 @@ static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_aic32x4 *div = to_clk_aic32x4(hw); - unsigned int val; + int err; + + err = regmap_read(div->regmap, div->reg, &val); + if (err) + return 0; - regmap_read(div->regmap, div->reg, &val); + val &= AIC32X4_DIV_MASK; + if (!val) + val = AIC32X4_DIV_MAX; - return DIV_ROUND_UP(parent_rate, val & AIC32X4_DIV_MASK); + return DIV_ROUND_UP(parent_rate, val); } static const struct clk_ops aic32x4_div_ops = { diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index 4de5bd9e8cc5..d6101ce73f80 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h @@ -223,8 +223,9 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name); #define AIC32X4_REFPOWERUP_120MS 0x07 /* Common mask and enable for all of the dividers */ -#define AIC32X4_DIVEN BIT(7) -#define AIC32X4_DIV_MASK GENMASK(6, 0) +#define AIC32X4_DIVEN BIT(7) +#define AIC32X4_DIV_MASK GENMASK(6, 0) +#define AIC32X4_DIV_MAX 128 /* Clock Limits */ #define AIC32X4_MAX_DOSR_FREQ 6200000 -- cgit v1.2.3 From b0a4c7f5921d9c2998bdd767a93d995786d72adc Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Thu, 10 Aug 2023 19:47:37 +0800 Subject: ASoC: tas5805m: Use devm_kmemdup to replace devm_kmalloc + memcpy Use the helper function devm_kmemdup() rather than duplicating its implementation, which helps to enhance code readability. Signed-off-by: Li Zetao Link: https://lore.kernel.org/r/20230810114738.2103792-2-lizetao1@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas5805m.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tas5805m.c b/sound/soc/codecs/tas5805m.c index aca3756ffab6..3b53eba38a0b 100644 --- a/sound/soc/codecs/tas5805m.c +++ b/sound/soc/codecs/tas5805m.c @@ -520,12 +520,11 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c) } tas5805m->dsp_cfg_len = fw->size; - tas5805m->dsp_cfg_data = devm_kmalloc(dev, fw->size, GFP_KERNEL); + tas5805m->dsp_cfg_data = devm_kmemdup(dev, fw->data, fw->size, GFP_KERNEL); if (!tas5805m->dsp_cfg_data) { release_firmware(fw); return -ENOMEM; } - memcpy(tas5805m->dsp_cfg_data, fw->data, fw->size); release_firmware(fw); -- cgit v1.2.3 From 29681184da28babc990a66e197d27ab98f2027af Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Thu, 10 Aug 2023 19:47:38 +0800 Subject: ASoC: SOF: ipc3: Use devm_kmemdup to replace devm_kmalloc + memcpy Use the helper function devm_kmemdup() rather than duplicating its implementation, which helps to enhance code readability. Signed-off-by: Li Zetao Reviewed-by: Luca Ceresoli Link: https://lore.kernel.org/r/20230810114738.2103792-3-lizetao1@huawei.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc3.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index 33df028d4854..fb40378ad084 100644 --- a/sound/soc/sof/ipc3.c +++ b/sound/soc/sof/ipc3.c @@ -567,13 +567,10 @@ int sof_ipc3_get_cc_info(struct snd_sof_dev *sdev, /* create read-only cc_version debugfs to store compiler version info */ /* use local copy of the cc_version to prevent data corruption */ if (sdev->first_boot) { - sdev->cc_version = devm_kmalloc(sdev->dev, cc->ext_hdr.hdr.size, - GFP_KERNEL); - + sdev->cc_version = devm_kmemdup(sdev->dev, cc, cc->ext_hdr.hdr.size, GFP_KERNEL); if (!sdev->cc_version) return -ENOMEM; - memcpy(sdev->cc_version, cc, cc->ext_hdr.hdr.size); ret = snd_sof_debugfs_buf_item(sdev, sdev->cc_version, cc->ext_hdr.hdr.size, "cc_version", 0444); -- cgit v1.2.3 From 273bc8bf2227108ed2851bea71786a026e34ecbb Mon Sep 17 00:00:00 2001 From: Ajye Huang Date: Fri, 4 Aug 2023 16:56:48 +0800 Subject: ASoC: Intel: Add rpl_nau8318_8825 driver Boards were using this in older kernels before adl and rpl ids were split. Add this back to maintain support. Signed-off-by: Ajye Huang Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230804085648.3721416-1-ajye_huang@compal.corp-partner.google.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_nau8825.c | 10 ++++++++++ sound/soc/intel/common/soc-acpi-intel-rpl-match.c | 12 ++++++++++++ 2 files changed, 22 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index 4fc6e1c6aef3..46b7ecf6f9f1 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -684,6 +684,16 @@ static const struct platform_device_id board_ids[] = { SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, + { + .name = "rpl_nau8318_8825", + .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_NAU8318_SPEAKER_AMP_PRESENT | + SOF_NAU8825_SSP_AMP(1) | + SOF_NAU8825_NUM_HDMIDEV(4) | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c index 4eefdb2dd45c..1dd699181765 100644 --- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -351,6 +351,11 @@ static const struct snd_soc_acpi_codecs rpl_rt1019p_amp = { .codecs = {"RTL1019"} }; +static const struct snd_soc_acpi_codecs rpl_nau8318_amp = { + .num_codecs = 1, + .codecs = {"NVTN2012"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { { .comp_ids = &rpl_rt5682_hp, @@ -373,6 +378,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { .quirk_data = &rpl_max98373_amp, .sof_tplg_filename = "sof-rpl-max98373-nau8825.tplg", }, + { + .id = "10508825", + .drv_name = "rpl_nau8318_8825", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &rpl_nau8318_amp, + .sof_tplg_filename = "sof-rpl-nau8318-nau8825.tplg", + }, { .comp_ids = &rpl_rt5682_hp, .drv_name = "rpl_rt1019_rt5682", -- cgit v1.2.3 From 62cc82e6486b9b66b340bbf5fb38b0171fb56a7f Mon Sep 17 00:00:00 2001 From: mnlife Date: Fri, 11 Aug 2023 22:25:11 +0800 Subject: ASoC: soc-jack: calling snd_soc_jack_report causes a null pointer access When snd_soc_card_jack_new is not called or the call fails, calling this function causes a null pointer access Signed-off-by: mnlife Link: https://lore.kernel.org/r/20230811142511.6570-1-mnlife@126.com Signed-off-by: Mark Brown --- sound/soc/soc-jack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index f951acb2ce36..b2cc13b9c77b 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -37,7 +37,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) struct snd_soc_jack_pin *pin; unsigned int sync = 0; - if (!jack) + if (!jack || !jack->jack) return; trace_snd_soc_jack_report(jack, mask, status); -- cgit v1.2.3 From f7f4a5ad8e11de4edb7b62d099f0501c8610c92b Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 14 Aug 2023 18:23:24 -0500 Subject: ASoC: dapm: Add a flag for not having widget name in kcontrol name The existing soc-dapm code may add a prefix to control names, which in some cases is useful but in others leads to long and confusing kcontrol names such as "gain 2.1 Main Playback Volume". This patch suggests an added flag to prevent the widget name prefix from being added. That flag will be set in the topology file on a per-widget basis. The flag no_wname_in_kcontrol_name is added to struct snd_soc_dapm_widget, and the logic in dapm_create_or_share_kcontrol() is changed to not to add widget name if the flag is set. Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Signed-off-by: Jyri Sarha Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230814232325.86397-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 3091e8160bad..f07e83678373 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -916,6 +916,8 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w, return -EINVAL; } } + if (w->no_wname_in_kcontrol_name) + wname_in_long_name = false; if (wname_in_long_name && kcname_in_long_name) { /* -- cgit v1.2.3 From 56ce7b791b787e0aee19601e422f13a18d4eafe7 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 14 Aug 2023 18:23:25 -0500 Subject: ASoC: SOF: topology: Add a token for dropping widget name in kcontrol name Adds SOF_TKN_COMP_NO_WNAME_IN_KCONTROL_NAME token, and copies the token's tuple value to the no_wname_in_kcontrol_name flag in struct snd_soc_dapm_widget. If the tuple value for the token in the topology is true, then the widget name is not added to the mixer name. In practice "gain.2.1 Post Mixer Analog Playback Volume" becomes just "Post Mixer Analog Playback Volume". Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Signed-off-by: Jyri Sarha Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230814232325.86397-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index be63ba06762f..a3a3af252259 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1367,6 +1367,20 @@ err: return ret; } +static int get_w_no_wname_in_long_name(void *elem, void *object, u32 offset) +{ + struct snd_soc_tplg_vendor_value_elem *velem = elem; + struct snd_soc_dapm_widget *w = object; + + w->no_wname_in_kcontrol_name = !!le32_to_cpu(velem->value); + return 0; +} + +static const struct sof_topology_token dapm_widget_tokens[] = { + {SOF_TKN_COMP_NO_WNAME_IN_KCONTROL_NAME, SND_SOC_TPLG_TUPLE_TYPE_BOOL, + get_w_no_wname_in_long_name, 0} +}; + /* external widget init - used for any driver specific init */ static int sof_widget_ready(struct snd_soc_component *scomp, int index, struct snd_soc_dapm_widget *w, @@ -1397,6 +1411,14 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, ida_init(&swidget->output_queue_ida); ida_init(&swidget->input_queue_ida); + ret = sof_parse_tokens(scomp, w, dapm_widget_tokens, ARRAY_SIZE(dapm_widget_tokens), + priv->array, le32_to_cpu(priv->size)); + if (ret < 0) { + dev_err(scomp->dev, "failed to parse dapm widget tokens for %s\n", + w->name); + goto widget_free; + } + ret = sof_parse_tokens(scomp, swidget, comp_pin_tokens, ARRAY_SIZE(comp_pin_tokens), priv->array, le32_to_cpu(priv->size)); -- cgit v1.2.3 From fc8b9d05a01f7cd98e0805aa773603b07515de06 Mon Sep 17 00:00:00 2001 From: Balamurugan C Date: Mon, 14 Aug 2023 18:13:55 -0500 Subject: ASoC: Intel: soc-acpi: Add entry for sof_es8336 in RPL match table. Adding support for ES83x6 codec in RPL match table. Reviewed-by: Bard Liao Signed-off-by: Balamurugan C Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230814231358.78971-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-rpl-match.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c index 4eefdb2dd45c..1f503c734ab5 100644 --- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -331,6 +331,11 @@ static const struct snd_soc_acpi_codecs rpl_rt5682_hp = { .codecs = {"10EC5682", "RTL5682"}, }; +static const struct snd_soc_acpi_codecs rpl_essx_83x6 = { + .num_codecs = 3, + .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, +}; + static const struct snd_soc_acpi_codecs rpl_max98357a_amp = { .num_codecs = 1, .codecs = {"MX98357A"} @@ -380,6 +385,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { .quirk_data = &rpl_rt1019p_amp, .sof_tplg_filename = "sof-rpl-rt1019-rt5682.tplg", }, + { + .comp_ids = &rpl_essx_83x6, + .drv_name = "sof-essx8336", + .sof_tplg_filename = "sof-rpl-es83x6", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER | + SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | + SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_rpl_machines); -- cgit v1.2.3 From fbc82c016d96aa4a2d99587cae2b78d5c5a59ea7 Mon Sep 17 00:00:00 2001 From: Balamurugan C Date: Mon, 14 Aug 2023 18:13:56 -0500 Subject: ASoC: Intel: soc-acpi: Add entry for HDMI_In capture support in RPL match table Adding HDMI-In capture via I2S feature support in RPL platfroms. Reviewed-by: Bard Liao Signed-off-by: Balamurugan C Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230814231358.78971-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_es8336.c | 10 ++++++++++ sound/soc/intel/common/soc-acpi-intel-rpl-match.c | 12 ++++++++++++ 2 files changed, 22 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index d6c38d8ea2ff..f8a3e8a91761 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -798,6 +798,16 @@ static const struct platform_device_id board_ids[] = { SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | SOF_ES8336_JD_INVERTED), }, + { + .name = "rpl_es83x6_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) | + SOF_NO_OF_HDMI_CAPTURE_SSP(2) | + SOF_HDMI_CAPTURE_1_SSP(0) | + SOF_HDMI_CAPTURE_2_SSP(2) | + SOF_SSP_HDMI_CAPTURE_PRESENT | + SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | + SOF_ES8336_JD_INVERTED), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c index 1f503c734ab5..3db0dc4ca66f 100644 --- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -356,6 +356,11 @@ static const struct snd_soc_acpi_codecs rpl_rt1019p_amp = { .codecs = {"RTL1019"} }; +static const struct snd_soc_acpi_codecs rpl_lt6911_hdmi = { + .num_codecs = 1, + .codecs = {"INTC10B0"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { { .comp_ids = &rpl_rt5682_hp, @@ -385,6 +390,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { .quirk_data = &rpl_rt1019p_amp, .sof_tplg_filename = "sof-rpl-rt1019-rt5682.tplg", }, + { + .comp_ids = &rpl_essx_83x6, + .drv_name = "rpl_es83x6_c1_h02", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &rpl_lt6911_hdmi, + .sof_tplg_filename = "sof-rpl-es83x6-ssp1-hdmi-ssp02.tplg", + }, { .comp_ids = &rpl_essx_83x6, .drv_name = "sof-essx8336", -- cgit v1.2.3 From fec75606f48f6c85eca8a9e868e41fb657abd1ca Mon Sep 17 00:00:00 2001 From: Chao Song Date: Mon, 14 Aug 2023 18:13:57 -0500 Subject: ASoC: Intel: soc-acpi: add support for Dell SKU0C87 devices This patch adds the acpi match table for Dell SKU0C87 devices, the codec layout is: SDW0: RT714 DMIC SDW1: RT1318 Speaker SDW2: RT1318 Speaker Note that there is no jack codec on SKU0C87 devices. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Signed-off-by: Chao Song Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230814231358.78971-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-mtl-match.c | 52 +++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c index ed9821adc1d9..0304246d2922 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -161,6 +161,33 @@ static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1318_1_group1_adr[] = { + { + .adr = 0x000130025D131801ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "rt1318-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt1318_2_group1_adr[] = { + { + .adr = 0x000232025D131801ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1318-2" + } +}; + +static const struct snd_soc_acpi_adr_device rt714_0_adr[] = { + { + .adr = 0x000030025D071401ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt714" + } +}; + static const struct snd_soc_acpi_adr_device rt714_1_adr[] = { { .adr = 0x000130025D071401ull, @@ -232,6 +259,25 @@ static const struct snd_soc_acpi_link_adr mtl_3_in_1_sdca[] = { {} }; +static const struct snd_soc_acpi_link_adr mtl_sdw_rt1318_l12_rt714_l0[] = { + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1318_1_group1_adr), + .adr_d = rt1318_1_group1_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1318_2_group1_adr), + .adr_d = rt1318_2_group1_adr, + }, + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt714_0_adr), + .adr_d = rt714_0_adr, + }, + {} +}; + static const struct snd_soc_acpi_adr_device mx8363_2_adr[] = { { .adr = 0x000230019F836300ull, @@ -298,6 +344,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-rt712-l0-rt1712-l3.tplg", }, + { + .link_mask = GENMASK(2, 0), + .links = mtl_sdw_rt1318_l12_rt714_l0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-rt1318-l12-rt714-l0.tplg" + }, { .link_mask = GENMASK(3, 0), .links = mtl_3_in_1_sdca, -- cgit v1.2.3 From f7555da71ef6eb9d289173d94ec2cc9d15061f33 Mon Sep 17 00:00:00 2001 From: Balamurugan C Date: Mon, 14 Aug 2023 18:13:58 -0500 Subject: ASoC: Intel: RPL: Add entry for HDMI-In capture support on non-I2S codec boards. Adding HDMI-In capture support for the RPL products doesn't have onboard I2S codec.but need to support HDMI-In capture via I2S and audio playback through HDMI/DP monitor. Reviewed-by: Bard Liao Signed-off-by: Balamurugan C Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230814231358.78971-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_ssp_amp.c | 9 +++++++++ sound/soc/intel/common/soc-acpi-intel-rpl-match.c | 5 +++++ 2 files changed, 14 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index 0aef718e82b2..5aa16fd3939b 100644 --- a/sound/soc/intel/boards/sof_ssp_amp.c +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -472,6 +472,15 @@ static const struct platform_device_id board_ids[] = { SOF_NO_OF_HDMI_PLAYBACK(3) | SOF_HDMI_PLAYBACK_PRESENT), }, + { + .name = "rpl_lt6911_hdmi_ssp", + .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) | + SOF_HDMI_CAPTURE_1_SSP(0) | + SOF_HDMI_CAPTURE_2_SSP(2) | + SOF_SSP_HDMI_CAPTURE_PRESENT | + SOF_NO_OF_HDMI_PLAYBACK(3) | + SOF_HDMI_PLAYBACK_PRESENT), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c index 3db0dc4ca66f..91b0648799b2 100644 --- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -405,6 +405,11 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, }, + { + .id = "INTC10B0", + .drv_name = "rpl_lt6911_hdmi_ssp", + .sof_tplg_filename = "sof-rpl-nocodec-hdmi-ssp02.tplg" + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_rpl_machines); -- cgit v1.2.3 From c5556d8651b4c58e0d9894be5a0188c9c90ce899 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 14 Aug 2023 18:42:35 -0500 Subject: ASoC: SOF: remove duplicate code due to merge Commit 81113108491e ("ASoC: Merge up fixes") added the same code twice, remove the extra call. Signed-off-by: Pierre-Louis Bossart Acked-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230814234235.87268-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index b43663822613..633f6040d712 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1734,9 +1734,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, /* update pipeline memory usage */ sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config); - /* update pipeline memory usage */ - sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config); - /* copy IPC data */ memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data)); if (gtw_cfg_config_length) -- cgit v1.2.3 From a942409c97ce12c2a4811b538568b1342d91e56c Mon Sep 17 00:00:00 2001 From: Chao Song Date: Mon, 14 Aug 2023 18:15:19 -0500 Subject: ASoC: SOF: Intel: Refactor code for HDA stream creation Existing HDA stream creation is split into two for loops for capture and playback, but most of the code in the two for loops are duplicated. This patch refactors HDA stream creation with a single for loop, thus remove code duplication. No functional change in this patch. Reviewed-by: Bard Liao Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Signed-off-by: Chao Song Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230814231519.79051-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-stream.c | 68 +++++----------------------------------- 1 file changed, 8 insertions(+), 60 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index b13acb959653..0b0087abcc50 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -869,8 +869,8 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) return -ENOMEM; } - /* create capture streams */ - for (i = 0; i < num_capture; i++) { + /* create capture and playback streams */ + for (i = 0; i < num_total; i++) { struct sof_intel_hda_stream *hda_stream; hda_stream = devm_kzalloc(sdev->dev, sizeof(*hda_stream), @@ -909,69 +909,17 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) hstream->index = i; sd_offset = SOF_STREAM_SD_OFFSET(hstream); hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset; - hstream->stream_tag = i + 1; hstream->opened = false; hstream->running = false; - hstream->direction = SNDRV_PCM_STREAM_CAPTURE; - /* memory alloc for stream BDL */ - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, - HDA_DSP_BDL_SIZE, &hstream->bdl); - if (ret < 0) { - dev_err(sdev->dev, "error: stream bdl dma alloc failed\n"); - return -ENOMEM; - } - hstream->posbuf = (__le32 *)(bus->posbuf.area + - (hstream->index) * 8); - - list_add_tail(&hstream->list, &bus->stream_list); - } - - /* create playback streams */ - for (i = num_capture; i < num_total; i++) { - struct sof_intel_hda_stream *hda_stream; - - hda_stream = devm_kzalloc(sdev->dev, sizeof(*hda_stream), - GFP_KERNEL); - if (!hda_stream) - return -ENOMEM; - - hda_stream->sdev = sdev; - - hext_stream = &hda_stream->hext_stream; - - if (sdev->bar[HDA_DSP_PP_BAR]) { - hext_stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] + - SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i; - - hext_stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] + - SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total + - SOF_HDA_PPLC_INTERVAL * i; - } - - hstream = &hext_stream->hstream; - - /* do we support SPIB */ - if (sdev->bar[HDA_DSP_SPIB_BAR]) { - hstream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] + - SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i + - SOF_HDA_SPIB_SPIB; - - hstream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] + - SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i + - SOF_HDA_SPIB_MAXFIFO; + if (i < num_capture) { + hstream->stream_tag = i + 1; + hstream->direction = SNDRV_PCM_STREAM_CAPTURE; + } else { + hstream->stream_tag = i - num_capture + 1; + hstream->direction = SNDRV_PCM_STREAM_PLAYBACK; } - hstream->bus = bus; - hstream->sd_int_sta_mask = 1 << i; - hstream->index = i; - sd_offset = SOF_STREAM_SD_OFFSET(hstream); - hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset; - hstream->stream_tag = i - num_capture + 1; - hstream->opened = false; - hstream->running = false; - hstream->direction = SNDRV_PCM_STREAM_PLAYBACK; - /* mem alloc for stream BDL */ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, HDA_DSP_BDL_SIZE, &hstream->bdl); -- cgit v1.2.3 From 62ddad4238a0250aa9cedade127c39aac9d26d45 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 15 Aug 2023 13:48:25 +0100 Subject: ASoC: wm_adsp: Support powering-up DSP without trying to load firmware Add a flag to wm_adsp_power_up() that indicates whether it should attempt to find and load firmware files. This is to support DSPs that have built-in firmware that may already have been patched (for example, by the BIOS). In that case the patch must not be overwritten because that could corrupt the running firmware. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230815124826.5447-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56.c | 4 ++-- sound/soc/codecs/wm_adsp.c | 16 +++++++++------- sound/soc/codecs/wm_adsp.h | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 80e7fddae926..98cfcae554af 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -656,7 +656,7 @@ static void cs35l56_secure_patch(struct cs35l56_private *cs35l56) int ret; /* Use wm_adsp to load and apply the firmware patch and coefficient files */ - ret = wm_adsp_power_up(&cs35l56->dsp); + ret = wm_adsp_power_up(&cs35l56->dsp, true); if (ret) dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret); else @@ -686,7 +686,7 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56) goto err; /* Use wm_adsp to load and apply the firmware patch and coefficient files */ - ret = wm_adsp_power_up(&cs35l56->dsp); + ret = wm_adsp_power_up(&cs35l56->dsp, true); if (ret) { dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret); goto err; diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 13f500fa9a5f..6fc34f41b175 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -998,7 +998,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put); -int wm_adsp_power_up(struct wm_adsp *dsp) +int wm_adsp_power_up(struct wm_adsp *dsp, bool load_firmware) { int ret = 0; char *wmfw_filename = NULL; @@ -1006,11 +1006,13 @@ int wm_adsp_power_up(struct wm_adsp *dsp) char *coeff_filename = NULL; const struct firmware *coeff_firmware = NULL; - ret = wm_adsp_request_firmware_files(dsp, - &wmfw_firmware, &wmfw_filename, - &coeff_firmware, &coeff_filename); - if (ret) - return ret; + if (load_firmware) { + ret = wm_adsp_request_firmware_files(dsp, + &wmfw_firmware, &wmfw_filename, + &coeff_firmware, &coeff_filename); + if (ret) + return ret; + } ret = cs_dsp_power_up(&dsp->cs_dsp, wmfw_firmware, wmfw_filename, @@ -1037,7 +1039,7 @@ static void wm_adsp_boot_work(struct work_struct *work) struct wm_adsp, boot_work); - wm_adsp_power_up(dsp); + wm_adsp_power_up(dsp, true); } int wm_adsp_early_event(struct snd_soc_dapm_widget *w, diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 3044f964ac14..067d807a7ca8 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -91,7 +91,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, int wm_adsp_early_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); -int wm_adsp_power_up(struct wm_adsp *dsp); +int wm_adsp_power_up(struct wm_adsp *dsp, bool load_firmware); void wm_adsp_power_down(struct wm_adsp *dsp); irqreturn_t wm_adsp2_bus_error(int irq, void *data); -- cgit v1.2.3 From 67bd793ba5e0984ecb7ee4407c2f79d159e305ff Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 15 Aug 2023 13:48:26 +0100 Subject: ASoC: cs35l56: Don't overwrite a patched firmware Only attempt to download wmfw/bin files to a non-secured part if it reports FIRMWARE_MISSING. If FIRMWARE_MISSING is false the firmware has already been patched and overwriting the patch could corrupt the running firmware. For a secured part the wmfw/bin can be downloaded even if FIRMWARE_MISSING is false, because they will only patch tunings. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20230815124826.5447-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 98cfcae554af..3a9ec8724cc1 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -665,8 +665,17 @@ static void cs35l56_secure_patch(struct cs35l56_private *cs35l56) static void cs35l56_patch(struct cs35l56_private *cs35l56) { + unsigned int firmware_missing; int ret; + 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); + return; + } + + firmware_missing &= CS35L56_FIRMWARE_MISSING; + /* * Disable SoundWire interrupts to prevent race with IRQ work. * Setting sdw_irq_no_unmask prevents the handler re-enabling @@ -685,8 +694,12 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56) if (ret) goto err; - /* Use wm_adsp to load and apply the firmware patch and coefficient files */ - ret = wm_adsp_power_up(&cs35l56->dsp, true); + /* + * Use wm_adsp to load and apply the firmware patch and coefficient files, + * but only if firmware is missing. If firmware is already patched just + * power-up wm_adsp without downloading firmware. + */ + ret = wm_adsp_power_up(&cs35l56->dsp, !!firmware_missing); if (ret) { dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret); goto err; -- cgit v1.2.3 From 66de320b0214a60095287ba1afa09e870d8cdbe5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 15 Aug 2023 16:32:02 +0200 Subject: ASoC: codecs: tlv320aic32x4: Fix Wvoid-pointer-to-enum-cast warning 'type' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: tlv320aic32x4.c:1352:18: error: cast to smaller integer type 'enum aic32x4_type' from 'void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230815143204.379708-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index ffe1828a4b7e..6829834a412f 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -1349,7 +1349,7 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap) return -ENOMEM; aic32x4->dev = dev; - aic32x4->type = (enum aic32x4_type)dev_get_drvdata(dev); + aic32x4->type = (uintptr_t)dev_get_drvdata(dev); dev_set_drvdata(dev, aic32x4); -- cgit v1.2.3 From 5a1803324949f4ebdf6e887b59e0e89afc3ee0bb Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 15 Aug 2023 16:32:03 +0200 Subject: ASoC: codecs: wm8904: Fix Wvoid-pointer-to-enum-cast warning 'devtype' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: wm8904.c:2205:21: error: cast to smaller integer type 'enum wm8904_type' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230815143204.379708-2-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wm8904.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 60319b468fb2..829bf055622a 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -2202,7 +2202,7 @@ static int wm8904_i2c_probe(struct i2c_client *i2c) match = of_match_node(wm8904_of_match, i2c->dev.of_node); if (match == NULL) return -EINVAL; - wm8904->devtype = (enum wm8904_type)match->data; + wm8904->devtype = (uintptr_t)match->data; } else { const struct i2c_device_id *id = i2c_match_id(wm8904_i2c_id, i2c); -- cgit v1.2.3 From 49a4a8d1261230378a8931d0859329057686b6eb Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 15 Aug 2023 16:32:04 +0200 Subject: ASoC: rockchip: Fix Wvoid-pointer-to-enum-cast warning 'version' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: rockchip_pdm.c:587:18: error: cast to smaller integer type 'enum rk_pdm_version' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230815143204.379708-3-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_pdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c index 667f2fa65c3e..4756cfc23218 100644 --- a/sound/soc/rockchip/rockchip_pdm.c +++ b/sound/soc/rockchip/rockchip_pdm.c @@ -584,7 +584,7 @@ static int rockchip_pdm_probe(struct platform_device *pdev) match = of_match_device(rockchip_pdm_match, &pdev->dev); if (match) - pdm->version = (enum rk_pdm_version)match->data; + pdm->version = (uintptr_t)match->data; if (pdm->version == RK_PDM_RK3308) { pdm->reset = devm_reset_control_get(&pdev->dev, "pdm-m"); -- cgit v1.2.3 From ef4ba63f12b03532378395a8611f2f6e22ece67b Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Tue, 15 Aug 2023 17:10:33 +0100 Subject: 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 (limited to 'sound') 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 */ -- cgit v1.2.3 From 409896794380c1dc0d596bbb9255e583a94d9a00 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 08:35:25 +0200 Subject: 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(-) (limited to 'sound') 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 && -- cgit v1.2.3 From 905240d169ebe4b879628b4a05316332803a3c3d Mon Sep 17 00:00:00 2001 From: Brady Norander Date: Tue, 15 Aug 2023 09:52:46 -0400 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From ebba2fd5adc2d79afa10c00255a60c79665c091a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 08:32:55 +0200 Subject: ASoC: samsung: odroid: use of_property_present to check for property "samsung,audio-widgets" and "samsung,audio-routing" are not boolean properties, thus more appropriate is to use of_property_present() to check if they are present. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810063300.20151-7-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/samsung/odroid.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index a5442592bde4..1743bd55ba1a 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -223,14 +223,14 @@ static int odroid_audio_probe(struct platform_device *pdev) if (ret < 0) return ret; - if (of_property_read_bool(dev->of_node, "samsung,audio-widgets")) { + if (of_property_present(dev->of_node, "samsung,audio-widgets")) { ret = snd_soc_of_parse_audio_simple_widgets(card, "samsung,audio-widgets"); if (ret < 0) return ret; } - if (of_property_read_bool(dev->of_node, "samsung,audio-routing")) { + if (of_property_present(dev->of_node, "samsung,audio-routing")) { ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); if (ret < 0) -- cgit v1.2.3 From 55ebfafbc32db54259d91383faf65a5bc6bef382 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 08:32:56 +0200 Subject: ASoC: samsung: aries_wm8994: parse audio-routing Parse generic sound card "audio-routing" property and fallback to "samsung,audio-routing" if it is missing. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810063300.20151-8-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/samsung/aries_wm8994.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c index 7492bb41456c..dd3cd2c9644a 100644 --- a/sound/soc/samsung/aries_wm8994.c +++ b/sound/soc/samsung/aries_wm8994.c @@ -620,10 +620,14 @@ static int aries_audio_probe(struct platform_device *pdev) /* Update card-name if provided through DT, else use default name */ snd_soc_of_parse_card_name(card, "model"); - ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); if (ret < 0) { - dev_err(dev, "Audio routing invalid/unspecified\n"); - return ret; + /* Backwards compatible way */ + ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + if (ret < 0) { + dev_err(dev, "Audio routing invalid/unspecified\n"); + return ret; + } } aries_dai[1].dai_fmt = priv->variant->modem_dai_fmt; -- cgit v1.2.3 From c91e67145bc6d03f94416f7fbe566c6f6751cd47 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 08:32:57 +0200 Subject: ASoC: samsung: midas_wm1811: parse audio-routing Parse generic sound card "audio-routing" property and fallback to "samsung,audio-routing" if it is missing. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810063300.20151-9-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/samsung/midas_wm1811.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c index 126098fdcf1b..2ec7e16ddfa2 100644 --- a/sound/soc/samsung/midas_wm1811.c +++ b/sound/soc/samsung/midas_wm1811.c @@ -476,10 +476,14 @@ static int midas_probe(struct platform_device *pdev) return ret; } - ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); if (ret < 0) { - dev_err(dev, "Audio routing invalid/unspecified\n"); - return ret; + /* Backwards compatible way */ + ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + if (ret < 0) { + dev_err(dev, "Audio routing invalid/unspecified\n"); + return ret; + } } cpu = of_get_child_by_name(dev->of_node, "cpu"); -- cgit v1.2.3 From 2dc8c0366599cb4dfd939e6eafd94010f3aff233 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 08:32:58 +0200 Subject: ASoC: samsung: odroid: parse audio-routing Parse generic sound card "audio-routing" property and fallback to "samsung,audio-routing" if it is missing. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810063300.20151-10-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/samsung/odroid.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index 1743bd55ba1a..c93cb5a86426 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -230,12 +230,13 @@ static int odroid_audio_probe(struct platform_device *pdev) return ret; } - if (of_property_present(dev->of_node, "samsung,audio-routing")) { - ret = snd_soc_of_parse_audio_routing(card, - "samsung,audio-routing"); - if (ret < 0) - return ret; - } + ret = 0; + if (of_property_present(dev->of_node, "audio-routing")) + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); + else if (of_property_present(dev->of_node, "samsung,audio-routing")) + ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + if (ret < 0) + return ret; card->dai_link = odroid_card_dais; card->num_links = ARRAY_SIZE(odroid_card_dais); -- cgit v1.2.3 From 17b9f4387ebabb19b871bbe2d06562e48e4e7130 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 08:32:59 +0200 Subject: ASoC: samsung: tm2_wm5110: parse audio-routing Parse generic sound card "audio-routing" property and fallback to "samsung,audio-routing" if it is missing. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810063300.20151-11-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/samsung/tm2_wm5110.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c index d611ec9e5325..5ebf17f3de1e 100644 --- a/sound/soc/samsung/tm2_wm5110.c +++ b/sound/soc/samsung/tm2_wm5110.c @@ -523,10 +523,14 @@ static int tm2_probe(struct platform_device *pdev) return ret; } - ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); if (ret < 0) { - dev_err(dev, "Audio routing is not specified or invalid\n"); - return ret; + /* Backwards compatible way */ + ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + if (ret < 0) { + dev_err(dev, "Audio routing is not specified or invalid\n"); + return ret; + } } card->aux_dev[0].dlc.of_node = of_parse_phandle(dev->of_node, -- cgit v1.2.3 From 2e6f979037d5ae35c0ed38e2b63e9876eb7bc65f Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 17 Aug 2023 09:42:52 +0800 Subject: 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(-) (limited to 'sound') 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 }, {} -- cgit v1.2.3 From 7f018db19bf7cb5ba3e39ed9e51c8c5f2488dfb0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 18:02:44 +0200 Subject: 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 --- sound/core/init.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'sound') 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); -- cgit v1.2.3 From 6a66b01de48855d92450904ccfafda9d692efbb9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 18:02:45 +0200 Subject: 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 --- sound/core/control.c | 14 ++++++++------ sound/core/control_led.c | 4 ++-- sound/usb/media.c | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) (limited to 'sound') 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; -- cgit v1.2.3 From bc41a7228cedc39395d032b2502975e53b7a9180 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 18:02:46 +0200 Subject: 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 --- sound/aoa/soundbus/i2sbus/pcm.c | 4 ++-- sound/core/pcm.c | 22 +++++++++++++--------- sound/usb/media.c | 2 +- 3 files changed, 16 insertions(+), 12 deletions(-) (limited to 'sound') 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; -- cgit v1.2.3 From 897c8882df5875fe0bbc3e93ee8e9ba4a2c6ca0d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 18:02:47 +0200 Subject: 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 --- sound/core/hwdep.c | 38 +++++++++++++++++++++----------------- sound/pci/hda/hda_hwdep.c | 4 ++-- 2 files changed, 23 insertions(+), 19 deletions(-) (limited to 'sound') 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; } -- cgit v1.2.3 From ea29a02fd802d8df8202819f0a50d4ebb960bb2a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 18:02:48 +0200 Subject: 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 --- sound/core/rawmidi.c | 29 +++++++++++++---------------- sound/core/ump.c | 8 ++++---- 2 files changed, 17 insertions(+), 20 deletions(-) (limited to 'sound') 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); -- cgit v1.2.3 From b53a41ee9c7281d961a29a3524bcaacfc9020dd5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 18:02:49 +0200 Subject: 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 --- sound/core/compress_offload.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'sound') 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; } -- cgit v1.2.3 From 911fcb76e39e3b85507bae7ccf78af7fc09acdb8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 18:02:50 +0200 Subject: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From 2419891e3ffdd50b17fb3aca49accc8e64b1f363 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 18:02:51 +0200 Subject: 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(-) (limited to 'sound') 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); } -- cgit v1.2.3 From 01ed7f3535a2c59d27cb7e78cf62eb81d2bbf2ec Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 Aug 2023 18:02:52 +0200 Subject: 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 --- sound/core/init.c | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'sound') 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) { -- cgit v1.2.3 From c4c3c32d088d5a432d3c40efef80d1b64743b6bc Mon Sep 17 00:00:00 2001 From: Maso Huang Date: Thu, 17 Aug 2023 18:13:33 +0800 Subject: ASoC: mediatek: mt7986: add common header Add header files for register definition and structure. Signed-off-by: Maso Huang Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230817101338.18782-2-maso.huang@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt7986/mt7986-afe-common.h | 49 +++++++ sound/soc/mediatek/mt7986/mt7986-reg.h | 196 ++++++++++++++++++++++++++ 2 files changed, 245 insertions(+) create mode 100644 sound/soc/mediatek/mt7986/mt7986-afe-common.h create mode 100644 sound/soc/mediatek/mt7986/mt7986-reg.h (limited to 'sound') diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-common.h b/sound/soc/mediatek/mt7986/mt7986-afe-common.h new file mode 100644 index 000000000000..fc3bb31e5167 --- /dev/null +++ b/sound/soc/mediatek/mt7986/mt7986-afe-common.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt7986-afe-common.h -- MediaTek 7986 audio driver definitions + * + * Copyright (c) 2023 MediaTek Inc. + * Authors: Vic Wu + * Maso Huang + */ + +#ifndef _MT_7986_AFE_COMMON_H_ +#define _MT_7986_AFE_COMMON_H_ + +#include +#include +#include +#include +#include "../common/mtk-base-afe.h" + +enum { + MT7986_MEMIF_DL1, + MT7986_MEMIF_VUL12, + MT7986_MEMIF_NUM, + MT7986_DAI_ETDM = MT7986_MEMIF_NUM, + MT7986_DAI_NUM, +}; + +enum { + MT7986_IRQ_0, + MT7986_IRQ_1, + MT7986_IRQ_2, + MT7986_IRQ_NUM, +}; + +struct mt7986_afe_private { + struct clk_bulk_data *clks; + int num_clks; + + int pm_runtime_bypass_reg_ctl; + + /* dai */ + void *dai_priv[MT7986_DAI_NUM]; +}; + +unsigned int mt7986_afe_rate_transform(struct device *dev, + unsigned int rate); + +/* dai register */ +int mt7986_dai_etdm_register(struct mtk_base_afe *afe); +#endif diff --git a/sound/soc/mediatek/mt7986/mt7986-reg.h b/sound/soc/mediatek/mt7986/mt7986-reg.h new file mode 100644 index 000000000000..c2b200743c3f --- /dev/null +++ b/sound/soc/mediatek/mt7986/mt7986-reg.h @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt7986-reg.h -- MediaTek 7986 audio driver reg definition + * + * Copyright (c) 2023 MediaTek Inc. + * Authors: Vic Wu + * Maso Huang + */ + +#ifndef _MT7986_REG_H_ +#define _MT7986_REG_H_ + +#define AUDIO_TOP_CON2 0x0008 +#define AUDIO_TOP_CON4 0x0010 +#define AUDIO_ENGEN_CON0 0x0014 +#define AFE_IRQ_MCU_EN 0x0100 +#define AFE_IRQ_MCU_STATUS 0x0120 +#define AFE_IRQ_MCU_CLR 0x0128 +#define AFE_IRQ0_MCU_CFG0 0x0140 +#define AFE_IRQ0_MCU_CFG1 0x0144 +#define AFE_IRQ1_MCU_CFG0 0x0148 +#define AFE_IRQ1_MCU_CFG1 0x014c +#define AFE_IRQ2_MCU_CFG0 0x0150 +#define AFE_IRQ2_MCU_CFG1 0x0154 +#define ETDM_IN5_CON0 0x13f0 +#define ETDM_IN5_CON1 0x13f4 +#define ETDM_IN5_CON2 0x13f8 +#define ETDM_IN5_CON3 0x13fc +#define ETDM_IN5_CON4 0x1400 +#define ETDM_OUT5_CON0 0x1570 +#define ETDM_OUT5_CON4 0x1580 +#define ETDM_OUT5_CON5 0x1584 +#define ETDM_4_7_COWORK_CON0 0x15e0 +#define ETDM_4_7_COWORK_CON1 0x15e4 +#define AFE_CONN018_1 0x1b44 +#define AFE_CONN018_4 0x1b50 +#define AFE_CONN019_1 0x1b64 +#define AFE_CONN019_4 0x1b70 +#define AFE_CONN124_1 0x2884 +#define AFE_CONN124_4 0x2890 +#define AFE_CONN125_1 0x28a4 +#define AFE_CONN125_4 0x28b0 +#define AFE_CONN_RS_0 0x3920 +#define AFE_CONN_RS_3 0x392c +#define AFE_CONN_16BIT_0 0x3960 +#define AFE_CONN_16BIT_3 0x396c +#define AFE_CONN_24BIT_0 0x3980 +#define AFE_CONN_24BIT_3 0x398c +#define AFE_MEMIF_CON0 0x3d98 +#define AFE_MEMIF_RD_MON 0x3da0 +#define AFE_MEMIF_WR_MON 0x3da4 +#define AFE_DL0_BASE_MSB 0x3e40 +#define AFE_DL0_BASE 0x3e44 +#define AFE_DL0_CUR_MSB 0x3e48 +#define AFE_DL0_CUR 0x3e4c +#define AFE_DL0_END_MSB 0x3e50 +#define AFE_DL0_END 0x3e54 +#define AFE_DL0_RCH_MON 0x3e58 +#define AFE_DL0_LCH_MON 0x3e5c +#define AFE_DL0_CON0 0x3e60 +#define AFE_VUL0_BASE_MSB 0x4220 +#define AFE_VUL0_BASE 0x4224 +#define AFE_VUL0_CUR_MSB 0x4228 +#define AFE_VUL0_CUR 0x422c +#define AFE_VUL0_END_MSB 0x4230 +#define AFE_VUL0_END 0x4234 +#define AFE_VUL0_CON0 0x4238 + +#define AFE_MAX_REGISTER AFE_VUL0_CON0 +#define AFE_IRQ_STATUS_BITS 0x7 +#define AFE_IRQ_CNT_SHIFT 0 +#define AFE_IRQ_CNT_MASK 0xffffff + +/* AUDIO_TOP_CON2 */ +#define CLK_OUT5_PDN BIT(14) +#define CLK_OUT5_PDN_MASK BIT(14) +#define CLK_IN5_PDN BIT(7) +#define CLK_IN5_PDN_MASK BIT(7) + +/* AUDIO_TOP_CON4 */ +#define PDN_APLL_TUNER2 BIT(12) +#define PDN_APLL_TUNER2_MASK BIT(12) + +/* AUDIO_ENGEN_CON0 */ +#define AUD_APLL2_EN BIT(3) +#define AUD_APLL2_EN_MASK BIT(3) +#define AUD_26M_EN BIT(0) +#define AUD_26M_EN_MASK BIT(0) + +/* AFE_DL0_CON0 */ +#define DL0_ON_SFT 28 +#define DL0_ON_MASK 0x1 +#define DL0_ON_MASK_SFT BIT(28) +#define DL0_MINLEN_SFT 20 +#define DL0_MINLEN_MASK 0xf +#define DL0_MINLEN_MASK_SFT (0xf << 20) +#define DL0_MODE_SFT 8 +#define DL0_MODE_MASK 0x1f +#define DL0_MODE_MASK_SFT (0x1f << 8) +#define DL0_PBUF_SIZE_SFT 5 +#define DL0_PBUF_SIZE_MASK 0x3 +#define DL0_PBUF_SIZE_MASK_SFT (0x3 << 5) +#define DL0_MONO_SFT 4 +#define DL0_MONO_MASK 0x1 +#define DL0_MONO_MASK_SFT BIT(4) +#define DL0_HALIGN_SFT 2 +#define DL0_HALIGN_MASK 0x1 +#define DL0_HALIGN_MASK_SFT BIT(2) +#define DL0_HD_MODE_SFT 0 +#define DL0_HD_MODE_MASK 0x3 +#define DL0_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_VUL0_CON0 */ +#define VUL0_ON_SFT 28 +#define VUL0_ON_MASK 0x1 +#define VUL0_ON_MASK_SFT BIT(28) +#define VUL0_MODE_SFT 8 +#define VUL0_MODE_MASK 0x1f +#define VUL0_MODE_MASK_SFT (0x1f << 8) +#define VUL0_MONO_SFT 4 +#define VUL0_MONO_MASK 0x1 +#define VUL0_MONO_MASK_SFT BIT(4) +#define VUL0_HALIGN_SFT 2 +#define VUL0_HALIGN_MASK 0x1 +#define VUL0_HALIGN_MASK_SFT BIT(2) +#define VUL0_HD_MODE_SFT 0 +#define VUL0_HD_MODE_MASK 0x3 +#define VUL0_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_IRQ_MCU_CON */ +#define IRQ_MCU_MODE_SFT 4 +#define IRQ_MCU_MODE_MASK 0x1f +#define IRQ_MCU_MODE_MASK_SFT (0x1f << 4) +#define IRQ_MCU_ON_SFT 0 +#define IRQ_MCU_ON_MASK 0x1 +#define IRQ_MCU_ON_MASK_SFT BIT(0) +#define IRQ0_MCU_CLR_SFT 0 +#define IRQ0_MCU_CLR_MASK 0x1 +#define IRQ0_MCU_CLR_MASK_SFT BIT(0) +#define IRQ1_MCU_CLR_SFT 1 +#define IRQ1_MCU_CLR_MASK 0x1 +#define IRQ1_MCU_CLR_MASK_SFT BIT(1) +#define IRQ2_MCU_CLR_SFT 2 +#define IRQ2_MCU_CLR_MASK 0x1 +#define IRQ2_MCU_CLR_MASK_SFT BIT(2) + +/* ETDM_IN5_CON2 */ +#define IN_CLK_SRC(x) ((x) << 10) +#define IN_CLK_SRC_SFT 10 +#define IN_CLK_SRC_MASK GENMASK(12, 10) + +/* ETDM_IN5_CON3 */ +#define IN_SEL_FS(x) ((x) << 26) +#define IN_SEL_FS_SFT 26 +#define IN_SEL_FS_MASK GENMASK(30, 26) + +/* ETDM_IN5_CON4 */ +#define IN_RELATCH(x) ((x) << 20) +#define IN_RELATCH_SFT 20 +#define IN_RELATCH_MASK GENMASK(24, 20) +#define IN_CLK_INV BIT(18) +#define IN_CLK_INV_MASK BIT(18) + +/* ETDM_IN5_CON0 & ETDM_OUT5_CON0 */ +#define RELATCH_SRC_MASK GENMASK(30, 28) +#define ETDM_CH_NUM_MASK GENMASK(27, 23) +#define ETDM_WRD_LEN_MASK GENMASK(20, 16) +#define ETDM_BIT_LEN_MASK GENMASK(15, 11) +#define ETDM_FMT_MASK GENMASK(8, 6) +#define ETDM_SYNC BIT(1) +#define ETDM_SYNC_MASK BIT(1) +#define ETDM_EN BIT(0) +#define ETDM_EN_MASK BIT(0) + +/* ETDM_OUT5_CON4 */ +#define OUT_RELATCH(x) ((x) << 24) +#define OUT_RELATCH_SFT 24 +#define OUT_RELATCH_MASK GENMASK(28, 24) +#define OUT_CLK_SRC(x) ((x) << 6) +#define OUT_CLK_SRC_SFT 6 +#define OUT_CLK_SRC_MASK GENMASK(8, 6) +#define OUT_SEL_FS(x) (x) +#define OUT_SEL_FS_SFT 0 +#define OUT_SEL_FS_MASK GENMASK(4, 0) + +/* ETDM_OUT5_CON5 */ +#define ETDM_CLK_DIV BIT(12) +#define ETDM_CLK_DIV_MASK BIT(12) +#define OUT_CLK_INV BIT(9) +#define OUT_CLK_INV_MASK BIT(9) + +/* ETDM_4_7_COWORK_CON0 */ +#define OUT_SEL(x) ((x) << 12) +#define OUT_SEL_SFT 12 +#define OUT_SEL_MASK GENMASK(15, 12) +#endif -- cgit v1.2.3 From 9f8df795ae8daa0051fe15b27c7a3b3842d3d91f Mon Sep 17 00:00:00 2001 From: Maso Huang Date: Thu, 17 Aug 2023 18:13:34 +0800 Subject: ASoC: mediatek: mt7986: support etdm in platform driver Add mt7986 etdm dai driver support. Signed-off-by: Maso Huang Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230817101338.18782-3-maso.huang@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt7986/mt7986-dai-etdm.c | 411 ++++++++++++++++++++++++++++ 1 file changed, 411 insertions(+) create mode 100644 sound/soc/mediatek/mt7986/mt7986-dai-etdm.c (limited to 'sound') diff --git a/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c new file mode 100644 index 000000000000..e523d33846fe --- /dev/null +++ b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c @@ -0,0 +1,411 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek ALSA SoC Audio DAI eTDM Control + * + * Copyright (c) 2023 MediaTek Inc. + * Authors: Vic Wu + * Maso Huang + */ + +#include +#include +#include +#include +#include "mt7986-afe-common.h" +#include "mt7986-reg.h" + +#define HOPPING_CLK 0 +#define APLL_CLK 1 +#define MTK_DAI_ETDM_FORMAT_I2S 0 +#define MTK_DAI_ETDM_FORMAT_DSPA 4 +#define MTK_DAI_ETDM_FORMAT_DSPB 5 + +enum { + MTK_ETDM_RATE_8K = 0, + MTK_ETDM_RATE_12K = 1, + MTK_ETDM_RATE_16K = 2, + MTK_ETDM_RATE_24K = 3, + MTK_ETDM_RATE_32K = 4, + MTK_ETDM_RATE_48K = 5, + MTK_ETDM_RATE_96K = 7, + MTK_ETDM_RATE_192K = 9, + MTK_ETDM_RATE_11K = 16, + MTK_ETDM_RATE_22K = 17, + MTK_ETDM_RATE_44K = 18, + MTK_ETDM_RATE_88K = 19, + MTK_ETDM_RATE_176K = 20, +}; + +struct mtk_dai_etdm_priv { + bool bck_inv; + bool lrck_inv; + bool slave_mode; + unsigned int format; +}; + +static unsigned int mt7986_etdm_rate_transform(struct device *dev, unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_ETDM_RATE_8K; + case 11025: + return MTK_ETDM_RATE_11K; + case 12000: + return MTK_ETDM_RATE_12K; + case 16000: + return MTK_ETDM_RATE_16K; + case 22050: + return MTK_ETDM_RATE_22K; + case 24000: + return MTK_ETDM_RATE_24K; + case 32000: + return MTK_ETDM_RATE_32K; + case 44100: + return MTK_ETDM_RATE_44K; + case 48000: + return MTK_ETDM_RATE_48K; + case 88200: + return MTK_ETDM_RATE_88K; + case 96000: + return MTK_ETDM_RATE_96K; + case 176400: + return MTK_ETDM_RATE_176K; + case 192000: + return MTK_ETDM_RATE_192K; + default: + dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n", + __func__, rate, MTK_ETDM_RATE_48K); + return MTK_ETDM_RATE_48K; + } +} + +static int get_etdm_wlen(unsigned int bitwidth) +{ + return bitwidth <= 16 ? 16 : 32; +} + +/* dai component */ +/* interconnection */ + +static const struct snd_kcontrol_new o124_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I032_Switch", AFE_CONN124_1, 0, 1, 0), +}; + +static const struct snd_kcontrol_new o125_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I033_Switch", AFE_CONN125_1, 1, 1, 0), +}; + +static const struct snd_soc_dapm_widget mtk_dai_etdm_widgets[] = { + + /* DL */ + SND_SOC_DAPM_MIXER("I150", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I151", SND_SOC_NOPM, 0, 0, NULL, 0), + /* UL */ + SND_SOC_DAPM_MIXER("O124", SND_SOC_NOPM, 0, 0, o124_mix, ARRAY_SIZE(o124_mix)), + SND_SOC_DAPM_MIXER("O125", SND_SOC_NOPM, 0, 0, o125_mix, ARRAY_SIZE(o125_mix)), +}; + +static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = { + {"I150", NULL, "ETDM Capture"}, + {"I151", NULL, "ETDM Capture"}, + {"ETDM Playback", NULL, "O124"}, + {"ETDM Playback", NULL, "O125"}, + {"O124", "I032_Switch", "I032"}, + {"O125", "I033_Switch", "I033"}, +}; + +/* dai ops */ +static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt7986_afe_private *afe_priv = afe->platform_priv; + int ret; + + ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks); + if (ret) + return dev_err_probe(afe->dev, ret, "Failed to enable clocks\n"); + + regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK, 0); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK, 0); + + return 0; +} + +static void mtk_dai_etdm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt7986_afe_private *afe_priv = afe->platform_priv; + + regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK, + CLK_OUT5_PDN); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK, + CLK_IN5_PDN); + + clk_bulk_disable_unprepare(afe_priv->num_clks, afe_priv->clks); +} + +static unsigned int get_etdm_ch_fixup(unsigned int channels) +{ + if (channels > 16) + return 24; + else if (channels > 8) + return 16; + else if (channels > 4) + return 8; + else if (channels > 2) + return 4; + else + return 2; +} + +static int mtk_dai_etdm_config(struct mtk_base_afe *afe, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai, + int stream) +{ + struct mt7986_afe_private *afe_priv = afe->platform_priv; + struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id]; + unsigned int rate = params_rate(params); + unsigned int etdm_rate = mt7986_etdm_rate_transform(afe->dev, rate); + unsigned int afe_rate = mt7986_afe_rate_transform(afe->dev, rate); + unsigned int channels = params_channels(params); + unsigned int bit_width = params_width(params); + unsigned int wlen = get_etdm_wlen(bit_width); + unsigned int val = 0; + unsigned int mask = 0; + + dev_dbg(afe->dev, "%s(), stream %d, rate %u, bitwidth %u\n", + __func__, stream, rate, bit_width); + + /* CON0 */ + mask |= ETDM_BIT_LEN_MASK; + val |= FIELD_PREP(ETDM_BIT_LEN_MASK, bit_width - 1); + mask |= ETDM_WRD_LEN_MASK; + val |= FIELD_PREP(ETDM_WRD_LEN_MASK, wlen - 1); + mask |= ETDM_FMT_MASK; + val |= FIELD_PREP(ETDM_FMT_MASK, etdm_data->format); + mask |= ETDM_CH_NUM_MASK; + val |= FIELD_PREP(ETDM_CH_NUM_MASK, get_etdm_ch_fixup(channels) - 1); + mask |= RELATCH_SRC_MASK; + val |= FIELD_PREP(RELATCH_SRC_MASK, APLL_CLK); + + switch (stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + /* set ETDM_OUT5_CON0 */ + regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, mask, val); + + /* set ETDM_OUT5_CON4 */ + regmap_update_bits(afe->regmap, ETDM_OUT5_CON4, + OUT_RELATCH_MASK, OUT_RELATCH(afe_rate)); + regmap_update_bits(afe->regmap, ETDM_OUT5_CON4, + OUT_CLK_SRC_MASK, OUT_CLK_SRC(APLL_CLK)); + regmap_update_bits(afe->regmap, ETDM_OUT5_CON4, + OUT_SEL_FS_MASK, OUT_SEL_FS(etdm_rate)); + + /* set ETDM_OUT5_CON5 */ + regmap_update_bits(afe->regmap, ETDM_OUT5_CON5, + ETDM_CLK_DIV_MASK, ETDM_CLK_DIV); + break; + case SNDRV_PCM_STREAM_CAPTURE: + /* set ETDM_IN5_CON0 */ + regmap_update_bits(afe->regmap, ETDM_IN5_CON0, mask, val); + regmap_update_bits(afe->regmap, ETDM_IN5_CON0, + ETDM_SYNC_MASK, ETDM_SYNC); + + /* set ETDM_IN5_CON2 */ + regmap_update_bits(afe->regmap, ETDM_IN5_CON2, + IN_CLK_SRC_MASK, IN_CLK_SRC(APLL_CLK)); + + /* set ETDM_IN5_CON3 */ + regmap_update_bits(afe->regmap, ETDM_IN5_CON3, + IN_SEL_FS_MASK, IN_SEL_FS(etdm_rate)); + + /* set ETDM_IN5_CON4 */ + regmap_update_bits(afe->regmap, ETDM_IN5_CON4, + IN_RELATCH_MASK, IN_RELATCH(afe_rate)); + break; + default: + break; + } + + return 0; +} + +static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_PLAYBACK); + mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_CAPTURE); + + return 0; +} + +static int mtk_dai_etdm_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + dev_dbg(afe->dev, "%s(), cmd %d, dai id %d\n", __func__, cmd, dai->id); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK, + ETDM_EN); + regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK, + ETDM_EN); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK, + 0); + regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK, + 0); + break; + default: + break; + } + + return 0; +} + +static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt7986_afe_private *afe_priv = afe->platform_priv; + struct mtk_dai_etdm_priv *etdm_data; + void *priv_data; + + switch (dai->id) { + case MT7986_DAI_ETDM: + break; + default: + dev_warn(afe->dev, "%s(), id %d not support\n", + __func__, dai->id); + return -EINVAL; + } + + priv_data = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_etdm_priv), + GFP_KERNEL); + if (!priv_data) + return -ENOMEM; + + afe_priv->dai_priv[dai->id] = priv_data; + etdm_data = afe_priv->dai_priv[dai->id]; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + etdm_data->format = MTK_DAI_ETDM_FORMAT_I2S; + break; + case SND_SOC_DAIFMT_DSP_A: + etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPA; + break; + case SND_SOC_DAIFMT_DSP_B: + etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPB; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + etdm_data->bck_inv = false; + etdm_data->lrck_inv = false; + break; + case SND_SOC_DAIFMT_NB_IF: + etdm_data->bck_inv = false; + etdm_data->lrck_inv = true; + break; + case SND_SOC_DAIFMT_IB_NF: + etdm_data->bck_inv = true; + etdm_data->lrck_inv = false; + break; + case SND_SOC_DAIFMT_IB_IF: + etdm_data->bck_inv = true; + etdm_data->lrck_inv = true; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + etdm_data->slave_mode = true; + break; + case SND_SOC_DAIFMT_CBS_CFS: + etdm_data->slave_mode = false; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_etdm_ops = { + .startup = mtk_dai_etdm_startup, + .shutdown = mtk_dai_etdm_shutdown, + .hw_params = mtk_dai_etdm_hw_params, + .trigger = mtk_dai_etdm_trigger, + .set_fmt = mtk_dai_etdm_set_fmt, +}; + +/* dai driver */ +#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { + { + .name = "ETDM", + .id = MT7986_DAI_ETDM, + .capture = { + .stream_name = "ETDM Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ETDM_RATES, + .formats = MTK_ETDM_FORMATS, + }, + .playback = { + .stream_name = "ETDM Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ETDM_RATES, + .formats = MTK_ETDM_FORMATS, + }, + .ops = &mtk_dai_etdm_ops, + .symmetric_rate = 1, + .symmetric_sample_bits = 1, + }, +}; + +int mt7986_dai_etdm_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_etdm_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_etdm_driver); + + dai->dapm_widgets = mtk_dai_etdm_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_etdm_widgets); + dai->dapm_routes = mtk_dai_etdm_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_etdm_routes); + + return 0; +} -- cgit v1.2.3 From 8d0d4884ba2cdabc823dc263c987bb22aae5fa5e Mon Sep 17 00:00:00 2001 From: Maso Huang Date: Thu, 17 Aug 2023 18:13:35 +0800 Subject: ASoC: mediatek: mt7986: add platform driver Add mt7986 platform driver. Signed-off-by: Maso Huang Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230817101338.18782-4-maso.huang@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 10 + sound/soc/mediatek/Makefile | 1 + sound/soc/mediatek/mt7986/Makefile | 8 + sound/soc/mediatek/mt7986/mt7986-afe-pcm.c | 622 +++++++++++++++++++++++++++++ 4 files changed, 641 insertions(+) create mode 100644 sound/soc/mediatek/mt7986/Makefile create mode 100644 sound/soc/mediatek/mt7986/mt7986-afe-pcm.c (limited to 'sound') diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 90db67e0ce4f..558827755a8d 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -54,6 +54,16 @@ config SND_SOC_MT6797_MT6351 Select Y if you have such device. If unsure select "N". +config SND_SOC_MT7986 + tristate "ASoC support for Mediatek MT7986 chip" + depends on ARCH_MEDIATEK + select SND_SOC_MEDIATEK + help + This adds ASoC platform driver support for MediaTek MT7986 chip + that can be used with other codecs. + Select Y if you have such device. + If unsure select "N". + config SND_SOC_MT8173 tristate "ASoC support for Mediatek MT8173 chip" depends on ARCH_MEDIATEK diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile index 3de38cfc69e5..3938e7f75c2e 100644 --- a/sound/soc/mediatek/Makefile +++ b/sound/soc/mediatek/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_SND_SOC_MEDIATEK) += common/ obj-$(CONFIG_SND_SOC_MT2701) += mt2701/ obj-$(CONFIG_SND_SOC_MT6797) += mt6797/ +obj-$(CONFIG_SND_SOC_MT7986) += mt7986/ obj-$(CONFIG_SND_SOC_MT8173) += mt8173/ obj-$(CONFIG_SND_SOC_MT8183) += mt8183/ obj-$(CONFIG_SND_SOC_MT8186) += mt8186/ diff --git a/sound/soc/mediatek/mt7986/Makefile b/sound/soc/mediatek/mt7986/Makefile new file mode 100644 index 000000000000..de0742a67cae --- /dev/null +++ b/sound/soc/mediatek/mt7986/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 + +# platform driver +snd-soc-mt7986-afe-objs := \ + mt7986-afe-pcm.o \ + mt7986-dai-etdm.o + +obj-$(CONFIG_SND_SOC_MT7986) += snd-soc-mt7986-afe.o diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c new file mode 100644 index 000000000000..d497e1129889 --- /dev/null +++ b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c @@ -0,0 +1,622 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek ALSA SoC AFE platform driver for MT7986 + * + * Copyright (c) 2023 MediaTek Inc. + * Authors: Vic Wu + * Maso Huang + */ + +#include +#include +#include +#include +#include +#include + +#include "mt7986-afe-common.h" +#include "mt7986-reg.h" +#include "../common/mtk-afe-platform-driver.h" +#include "../common/mtk-afe-fe-dai.h" + +enum { + MTK_AFE_RATE_8K = 0, + MTK_AFE_RATE_11K = 1, + MTK_AFE_RATE_12K = 2, + MTK_AFE_RATE_16K = 4, + MTK_AFE_RATE_22K = 5, + MTK_AFE_RATE_24K = 6, + MTK_AFE_RATE_32K = 8, + MTK_AFE_RATE_44K = 9, + MTK_AFE_RATE_48K = 10, + MTK_AFE_RATE_88K = 13, + MTK_AFE_RATE_96K = 14, + MTK_AFE_RATE_176K = 17, + MTK_AFE_RATE_192K = 18, +}; + +enum { + CLK_INFRA_AUD_BUS_CK = 0, + CLK_INFRA_AUD_26M_CK, + CLK_INFRA_AUD_L_CK, + CLK_INFRA_AUD_AUD_CK, + CLK_INFRA_AUD_EG2_CK, + CLK_NUM +}; + +static const char *aud_clks[CLK_NUM] = { + [CLK_INFRA_AUD_BUS_CK] = "aud_bus_ck", + [CLK_INFRA_AUD_26M_CK] = "aud_26m_ck", + [CLK_INFRA_AUD_L_CK] = "aud_l_ck", + [CLK_INFRA_AUD_AUD_CK] = "aud_aud_ck", + [CLK_INFRA_AUD_EG2_CK] = "aud_eg2_ck", +}; + +unsigned int mt7986_afe_rate_transform(struct device *dev, unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_RATE_8K; + case 11025: + return MTK_AFE_RATE_11K; + case 12000: + return MTK_AFE_RATE_12K; + case 16000: + return MTK_AFE_RATE_16K; + case 22050: + return MTK_AFE_RATE_22K; + case 24000: + return MTK_AFE_RATE_24K; + case 32000: + return MTK_AFE_RATE_32K; + case 44100: + return MTK_AFE_RATE_44K; + case 48000: + return MTK_AFE_RATE_48K; + case 88200: + return MTK_AFE_RATE_88K; + case 96000: + return MTK_AFE_RATE_96K; + case 176400: + return MTK_AFE_RATE_176K; + case 192000: + return MTK_AFE_RATE_192K; + default: + dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n", + __func__, rate, MTK_AFE_RATE_48K); + return MTK_AFE_RATE_48K; + } +} + +static const struct snd_pcm_hardware mt7986_afe_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .period_bytes_min = 256, + .period_bytes_max = 4 * 48 * 1024, + .periods_min = 2, + .periods_max = 256, + .buffer_bytes_max = 8 * 48 * 1024, + .fifo_size = 0, +}; + +static int mt7986_memif_fs(struct snd_pcm_substream *substream, + unsigned int rate) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); + + return mt7986_afe_rate_transform(afe->dev, rate); +} + +static int mt7986_irq_fs(struct snd_pcm_substream *substream, + unsigned int rate) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); + + return mt7986_afe_rate_transform(afe->dev, rate); +} + +#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mt7986_memif_dai_driver[] = { + /* FE DAIs: memory intefaces to CPU */ + { + .name = "DL1", + .id = MT7986_MEMIF_DL1, + .playback = { + .stream_name = "DL1", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL1", + .id = MT7986_MEMIF_VUL12, + .capture = { + .stream_name = "UL1", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, +}; + +static const struct snd_kcontrol_new o018_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I150_Switch", AFE_CONN018_4, 22, 1, 0), +}; + +static const struct snd_kcontrol_new o019_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I151_Switch", AFE_CONN019_4, 23, 1, 0), +}; + +static const struct snd_soc_dapm_widget mt7986_memif_widgets[] = { + /* DL */ + SND_SOC_DAPM_MIXER("I032", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I033", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* UL */ + SND_SOC_DAPM_MIXER("O018", SND_SOC_NOPM, 0, 0, + o018_mix, ARRAY_SIZE(o018_mix)), + SND_SOC_DAPM_MIXER("O019", SND_SOC_NOPM, 0, 0, + o019_mix, ARRAY_SIZE(o019_mix)), +}; + +static const struct snd_soc_dapm_route mt7986_memif_routes[] = { + {"I032", NULL, "DL1"}, + {"I033", NULL, "DL1"}, + {"UL1", NULL, "O018"}, + {"UL1", NULL, "O019"}, + {"O018", "I150_Switch", "I150"}, + {"O019", "I151_Switch", "I151"}, +}; + +static const struct snd_soc_component_driver mt7986_afe_pcm_dai_component = { + .name = "mt7986-afe-pcm-dai", +}; + +static const struct mtk_base_memif_data memif_data[MT7986_MEMIF_NUM] = { + [MT7986_MEMIF_DL1] = { + .name = "DL1", + .id = MT7986_MEMIF_DL1, + .reg_ofs_base = AFE_DL0_BASE, + .reg_ofs_cur = AFE_DL0_CUR, + .reg_ofs_end = AFE_DL0_END, + .reg_ofs_base_msb = AFE_DL0_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL0_CUR_MSB, + .reg_ofs_end_msb = AFE_DL0_END_MSB, + .fs_reg = AFE_DL0_CON0, + .fs_shift = DL0_MODE_SFT, + .fs_maskbit = DL0_MODE_MASK, + .mono_reg = AFE_DL0_CON0, + .mono_shift = DL0_MONO_SFT, + .enable_reg = AFE_DL0_CON0, + .enable_shift = DL0_ON_SFT, + .hd_reg = AFE_DL0_CON0, + .hd_shift = DL0_HD_MODE_SFT, + .hd_align_reg = AFE_DL0_CON0, + .hd_align_mshift = DL0_HALIGN_SFT, + .pbuf_reg = AFE_DL0_CON0, + .pbuf_shift = DL0_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL0_CON0, + .minlen_shift = DL0_MINLEN_SFT, + }, + [MT7986_MEMIF_VUL12] = { + .name = "VUL12", + .id = MT7986_MEMIF_VUL12, + .reg_ofs_base = AFE_VUL0_BASE, + .reg_ofs_cur = AFE_VUL0_CUR, + .reg_ofs_end = AFE_VUL0_END, + .reg_ofs_base_msb = AFE_VUL0_BASE_MSB, + .reg_ofs_cur_msb = AFE_VUL0_CUR_MSB, + .reg_ofs_end_msb = AFE_VUL0_END_MSB, + .fs_reg = AFE_VUL0_CON0, + .fs_shift = VUL0_MODE_SFT, + .fs_maskbit = VUL0_MODE_MASK, + .mono_reg = AFE_VUL0_CON0, + .mono_shift = VUL0_MONO_SFT, + .enable_reg = AFE_VUL0_CON0, + .enable_shift = VUL0_ON_SFT, + .hd_reg = AFE_VUL0_CON0, + .hd_shift = VUL0_HD_MODE_SFT, + .hd_align_reg = AFE_VUL0_CON0, + .hd_align_mshift = VUL0_HALIGN_SFT, + }, +}; + +static const struct mtk_base_irq_data irq_data[MT7986_IRQ_NUM] = { + [MT7986_IRQ_0] = { + .id = MT7986_IRQ_0, + .irq_cnt_reg = AFE_IRQ0_MCU_CFG1, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ0_MCU_CFG0, + .irq_fs_shift = IRQ_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ0_MCU_CFG0, + .irq_en_shift = IRQ_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ0_MCU_CLR_SFT, + }, + [MT7986_IRQ_1] = { + .id = MT7986_IRQ_1, + .irq_cnt_reg = AFE_IRQ1_MCU_CFG1, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ1_MCU_CFG0, + .irq_fs_shift = IRQ_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ1_MCU_CFG0, + .irq_en_shift = IRQ_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ1_MCU_CLR_SFT, + }, + [MT7986_IRQ_2] = { + .id = MT7986_IRQ_2, + .irq_cnt_reg = AFE_IRQ2_MCU_CFG1, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ2_MCU_CFG0, + .irq_fs_shift = IRQ_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ2_MCU_CFG0, + .irq_en_shift = IRQ_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ2_MCU_CLR_SFT, + }, +}; + +static bool mt7986_is_volatile_reg(struct device *dev, unsigned int reg) +{ + /* + * Those auto-gen regs are read-only, so put it as volatile because + * volatile registers cannot be cached, which means that they cannot + * be set when power is off + */ + + switch (reg) { + case AFE_DL0_CUR_MSB: + case AFE_DL0_CUR: + case AFE_DL0_RCH_MON: + case AFE_DL0_LCH_MON: + case AFE_VUL0_CUR_MSB: + case AFE_VUL0_CUR: + case AFE_IRQ_MCU_STATUS: + case AFE_MEMIF_RD_MON: + case AFE_MEMIF_WR_MON: + return true; + default: + return false; + }; +} + +static const struct regmap_config mt7986_afe_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .volatile_reg = mt7986_is_volatile_reg, + .max_register = AFE_MAX_REGISTER, + .num_reg_defaults_raw = ((AFE_MAX_REGISTER / 4) + 1), +}; + +static int mt7986_init_clock(struct mtk_base_afe *afe) +{ + struct mt7986_afe_private *afe_priv = afe->platform_priv; + int ret, i; + + afe_priv->clks = devm_kcalloc(afe->dev, CLK_NUM, + sizeof(*afe_priv->clks), GFP_KERNEL); + if (!afe_priv->clks) + return -ENOMEM; + afe_priv->num_clks = CLK_NUM; + + for (i = 0; i < afe_priv->num_clks; i++) + afe_priv->clks[i].id = aud_clks[i]; + + ret = devm_clk_bulk_get(afe->dev, afe_priv->num_clks, afe_priv->clks); + if (ret) + return dev_err_probe(afe->dev, ret, "Failed to get clocks\n"); + + return 0; +} + +static irqreturn_t mt7986_afe_irq_handler(int irq_id, void *dev) +{ + struct mtk_base_afe *afe = dev; + struct mtk_base_afe_irq *irq; + u32 mcu_en, status, status_mcu; + int i, ret; + irqreturn_t irq_ret = IRQ_HANDLED; + + /* get irq that is sent to MCU */ + regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en); + + ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status); + /* only care IRQ which is sent to MCU */ + status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS; + + if (ret || status_mcu == 0) { + dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x, mcu_en 0x%x\n", + __func__, ret, status, mcu_en); + + irq_ret = IRQ_NONE; + goto err_irq; + } + + for (i = 0; i < MT7986_MEMIF_NUM; i++) { + struct mtk_base_afe_memif *memif = &afe->memif[i]; + + if (!memif->substream) + continue; + + if (memif->irq_usage < 0) + continue; + + irq = &afe->irqs[memif->irq_usage]; + + if (status_mcu & (1 << irq->irq_data->irq_en_shift)) + snd_pcm_period_elapsed(memif->substream); + } + +err_irq: + /* clear irq */ + regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, status_mcu); + + return irq_ret; +} + +static int mt7986_afe_runtime_suspend(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + struct mt7986_afe_private *afe_priv = afe->platform_priv; + + if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl) + goto skip_regmap; + + /* disable clk*/ + regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0x3fff); + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK, 0); + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK, 0); + + /* make sure all irq status are cleared, twice intended */ + regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CLR, 0xffff, 0xffff); + +skip_regmap: + clk_bulk_disable_unprepare(afe_priv->num_clks, afe_priv->clks); + + return 0; +} + +static int mt7986_afe_runtime_resume(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + struct mt7986_afe_private *afe_priv = afe->platform_priv; + int ret; + + ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks); + if (ret) + return dev_err_probe(afe->dev, ret, "Failed to enable clocks\n"); + + if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl) + return 0; + + /* enable clk*/ + regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0); + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK, + AUD_APLL2_EN); + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK, + AUD_26M_EN); + + return 0; +} + +static int mt7986_afe_component_probe(struct snd_soc_component *component) +{ + return mtk_afe_add_sub_dai_control(component); +} + +static const struct snd_soc_component_driver mt7986_afe_component = { + .name = AFE_PCM_NAME, + .probe = mt7986_afe_component_probe, + .pointer = mtk_afe_pcm_pointer, + .pcm_construct = mtk_afe_pcm_new, +}; + +static int mt7986_dai_memif_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mt7986_memif_dai_driver; + dai->num_dai_drivers = ARRAY_SIZE(mt7986_memif_dai_driver); + + dai->dapm_widgets = mt7986_memif_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mt7986_memif_widgets); + dai->dapm_routes = mt7986_memif_routes; + dai->num_dapm_routes = ARRAY_SIZE(mt7986_memif_routes); + + return 0; +} + +typedef int (*dai_register_cb)(struct mtk_base_afe *); +static const dai_register_cb dai_register_cbs[] = { + mt7986_dai_etdm_register, + mt7986_dai_memif_register, +}; + +static int mt7986_afe_pcm_dev_probe(struct platform_device *pdev) +{ + struct mtk_base_afe *afe; + struct mt7986_afe_private *afe_priv; + struct device *dev; + int i, irq_id, ret; + + afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); + if (!afe) + return -ENOMEM; + platform_set_drvdata(pdev, afe); + + afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv), + GFP_KERNEL); + if (!afe->platform_priv) + return -ENOMEM; + + 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)) + return PTR_ERR(afe->base_addr); + + /* initial audio related clock */ + ret = mt7986_init_clock(afe); + if (ret) + return dev_err_probe(dev, ret, "Cannot initialize clocks\n"); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + /* enable clock for regcache get default value from hw */ + afe_priv->pm_runtime_bypass_reg_ctl = true; + pm_runtime_get_sync(&pdev->dev); + + afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr, + &mt7986_afe_regmap_config); + + pm_runtime_put_sync(&pdev->dev); + if (IS_ERR(afe->regmap)) + return PTR_ERR(afe->regmap); + + afe_priv->pm_runtime_bypass_reg_ctl = false; + + /* init memif */ + afe->memif_size = MT7986_MEMIF_NUM; + afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif), + GFP_KERNEL); + if (!afe->memif) + return -ENOMEM; + + for (i = 0; i < afe->memif_size; i++) { + afe->memif[i].data = &memif_data[i]; + afe->memif[i].irq_usage = -1; + } + + mutex_init(&afe->irq_alloc_lock); + + /* irq initialize */ + afe->irqs_size = MT7986_IRQ_NUM; + afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs), + GFP_KERNEL); + if (!afe->irqs) + return -ENOMEM; + + for (i = 0; i < afe->irqs_size; i++) + afe->irqs[i].irq_data = &irq_data[i]; + + /* request irq */ + irq_id = platform_get_irq(pdev, 0); + if (irq_id < 0) { + ret = irq_id; + return dev_err_probe(dev, ret, "No irq found\n"); + } + ret = devm_request_irq(dev, irq_id, mt7986_afe_irq_handler, + IRQF_TRIGGER_NONE, "asys-isr", (void *)afe); + if (ret) + return dev_err_probe(dev, ret, "Failed to request irq for asys-isr\n"); + + /* init sub_dais */ + INIT_LIST_HEAD(&afe->sub_dais); + + for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) { + ret = dai_register_cbs[i](afe); + if (ret) + return dev_err_probe(dev, ret, "DAI register failed, i: %d\n", i); + } + + /* init dai_driver and component_driver */ + ret = mtk_afe_combine_sub_dai(afe); + if (ret) + return dev_err_probe(dev, ret, "mtk_afe_combine_sub_dai fail\n"); + + afe->mtk_afe_hardware = &mt7986_afe_hardware; + afe->memif_fs = mt7986_memif_fs; + afe->irq_fs = mt7986_irq_fs; + + afe->runtime_resume = mt7986_afe_runtime_resume; + afe->runtime_suspend = mt7986_afe_runtime_suspend; + + /* register component */ + ret = devm_snd_soc_register_component(&pdev->dev, + &mt7986_afe_component, + NULL, 0); + if (ret) + return dev_err_probe(dev, ret, "Cannot register AFE component\n"); + + ret = devm_snd_soc_register_component(afe->dev, + &mt7986_afe_pcm_dai_component, + afe->dai_drivers, + afe->num_dai_drivers); + if (ret) + return dev_err_probe(dev, ret, "Cannot register PCM DAI component\n"); + + return 0; +} + +static void mt7986_afe_pcm_dev_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + mt7986_afe_runtime_suspend(&pdev->dev); +} + +static const struct of_device_id mt7986_afe_pcm_dt_match[] = { + { .compatible = "mediatek,mt7986-afe" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mt7986_afe_pcm_dt_match); + +static const struct dev_pm_ops mt7986_afe_pm_ops = { + SET_RUNTIME_PM_OPS(mt7986_afe_runtime_suspend, + mt7986_afe_runtime_resume, NULL) +}; + +static struct platform_driver mt7986_afe_pcm_driver = { + .driver = { + .name = "mt7986-audio", + .of_match_table = mt7986_afe_pcm_dt_match, + .pm = &mt7986_afe_pm_ops, + }, + .probe = mt7986_afe_pcm_dev_probe, + .remove_new = mt7986_afe_pcm_dev_remove, +}; +module_platform_driver(mt7986_afe_pcm_driver); + +MODULE_DESCRIPTION("MediaTek SoC AFE platform driver for ALSA MT7986"); +MODULE_AUTHOR("Vic Wu "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 9873277fc2ea6e517602c29cb336bb1e43ff528c Mon Sep 17 00:00:00 2001 From: Maso Huang Date: Thu, 17 Aug 2023 18:13:36 +0800 Subject: ASoC: mediatek: mt7986: add machine driver with wm8960 Add support for mt7986 board with wm8960. Signed-off-by: Maso Huang Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230817101338.18782-5-maso.huang@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 10 ++ sound/soc/mediatek/mt7986/Makefile | 1 + sound/soc/mediatek/mt7986/mt7986-wm8960.c | 196 ++++++++++++++++++++++++++++++ 3 files changed, 207 insertions(+) create mode 100644 sound/soc/mediatek/mt7986/mt7986-wm8960.c (limited to 'sound') diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 558827755a8d..8d1bc8814486 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -64,6 +64,16 @@ config SND_SOC_MT7986 Select Y if you have such device. If unsure select "N". +config SND_SOC_MT7986_WM8960 + tristate "ASoc Audio driver for MT7986 with WM8960 codec" + depends on SND_SOC_MT7986 && I2C + select SND_SOC_WM8960 + help + This adds support for ASoC machine driver for MediaTek MT7986 + boards with the WM8960 codecs. + Select Y if you have such device. + If unsure select "N". + config SND_SOC_MT8173 tristate "ASoC support for Mediatek MT8173 chip" depends on ARCH_MEDIATEK diff --git a/sound/soc/mediatek/mt7986/Makefile b/sound/soc/mediatek/mt7986/Makefile index de0742a67cae..fc4c82559b29 100644 --- a/sound/soc/mediatek/mt7986/Makefile +++ b/sound/soc/mediatek/mt7986/Makefile @@ -6,3 +6,4 @@ snd-soc-mt7986-afe-objs := \ mt7986-dai-etdm.o obj-$(CONFIG_SND_SOC_MT7986) += snd-soc-mt7986-afe.o +obj-$(CONFIG_SND_SOC_MT7986_WM8960) += mt7986-wm8960.o diff --git a/sound/soc/mediatek/mt7986/mt7986-wm8960.c b/sound/soc/mediatek/mt7986/mt7986-wm8960.c new file mode 100644 index 000000000000..364d13b1c426 --- /dev/null +++ b/sound/soc/mediatek/mt7986/mt7986-wm8960.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * mt7986-wm8960.c -- MT7986-WM8960 ALSA SoC machine driver + * + * Copyright (c) 2023 MediaTek Inc. + * Authors: Vic Wu + * Maso Huang + */ + +#include +#include + +#include "mt7986-afe-common.h" + +struct mt7986_wm8960_priv { + struct device_node *platform_node; + struct device_node *codec_node; +}; + +static const struct snd_soc_dapm_widget mt7986_wm8960_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("AMIC", NULL), +}; + +static const struct snd_kcontrol_new mt7986_wm8960_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("AMIC"), +}; + +SND_SOC_DAILINK_DEFS(playback, + DAILINK_COMP_ARRAY(COMP_CPU("DL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture, + DAILINK_COMP_ARRAY(COMP_CPU("UL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(codec, + DAILINK_COMP_ARRAY(COMP_CPU("ETDM")), + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8960-hifi")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link mt7986_wm8960_dai_links[] = { + /* FE */ + { + .name = "wm8960-playback", + .stream_name = "wm8960-playback", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback), + }, + { + .name = "wm8960-capture", + .stream_name = "wm8960-capture", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture), + }, + /* BE */ + { + .name = "wm8960-codec", + .no_pcm = 1, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS | + SND_SOC_DAIFMT_GATED, + .dpcm_playback = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(codec), + }, +}; + +static struct snd_soc_card mt7986_wm8960_card = { + .name = "mt7986-wm8960", + .owner = THIS_MODULE, + .dai_link = mt7986_wm8960_dai_links, + .num_links = ARRAY_SIZE(mt7986_wm8960_dai_links), + .controls = mt7986_wm8960_controls, + .num_controls = ARRAY_SIZE(mt7986_wm8960_controls), + .dapm_widgets = mt7986_wm8960_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt7986_wm8960_widgets), +}; + +static int mt7986_wm8960_machine_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &mt7986_wm8960_card; + struct snd_soc_dai_link *dai_link; + struct device_node *platform, *codec; + struct mt7986_wm8960_priv *priv; + int ret, i; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform = of_get_child_by_name(pdev->dev.of_node, "platform"); + + if (platform) { + priv->platform_node = of_parse_phandle(platform, "sound-dai", 0); + of_node_put(platform); + + if (!priv->platform_node) { + dev_err(&pdev->dev, "Failed to parse platform/sound-dai property\n"); + return -EINVAL; + } + } else { + dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); + return -EINVAL; + } + + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platforms->name) + continue; + dai_link->platforms->of_node = priv->platform_node; + } + + card->dev = &pdev->dev; + + codec = of_get_child_by_name(pdev->dev.of_node, "codec"); + + if (codec) { + priv->codec_node = of_parse_phandle(codec, "sound-dai", 0); + of_node_put(codec); + + if (!priv->codec_node) { + of_node_put(priv->platform_node); + dev_err(&pdev->dev, "Failed to parse codec/sound-dai property\n"); + return -EINVAL; + } + } else { + of_node_put(priv->platform_node); + dev_err(&pdev->dev, "Property 'codec' missing or invalid\n"); + return -EINVAL; + } + + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->codecs->name) + continue; + dai_link->codecs->of_node = priv->codec_node; + } + + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); + if (ret) { + dev_err(&pdev->dev, "Failed to parse audio-routing: %d\n", ret); + goto err_of_node_put; + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) { + dev_err(&pdev->dev, "%s snd_soc_register_card fail: %d\n", __func__, ret); + goto err_of_node_put; + } + +err_of_node_put: + of_node_put(priv->codec_node); + of_node_put(priv->platform_node); + return ret; +} + +static void mt7986_wm8960_machine_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct mt7986_wm8960_priv *priv = snd_soc_card_get_drvdata(card); + + of_node_put(priv->codec_node); + of_node_put(priv->platform_node); +} + +static const struct of_device_id mt7986_wm8960_machine_dt_match[] = { + {.compatible = "mediatek,mt7986-wm8960-sound"}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mt7986_wm8960_machine_dt_match); + +static struct platform_driver mt7986_wm8960_machine = { + .driver = { + .name = "mt7986-wm8960", + .of_match_table = mt7986_wm8960_machine_dt_match, + }, + .probe = mt7986_wm8960_machine_probe, + .remove_new = mt7986_wm8960_machine_remove, +}; + +module_platform_driver(mt7986_wm8960_machine); + +/* Module information */ +MODULE_DESCRIPTION("MT7986 WM8960 ALSA SoC machine driver"); +MODULE_AUTHOR("Vic Wu "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("mt7986 wm8960 soc card"); -- cgit v1.2.3 From a9b5f21073c0c687068f17e23385ec43fc643b08 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 17 Aug 2023 16:03:17 +0200 Subject: ASoC: rt5640: Convert to just use GPIO descriptors The RT5640 driver is already using GPIO descriptors for some stuff, all that is needed is to convert the remaining LDO1 control line to also use descriptors. Simplify the code using gpiod_get_optional() and drop the special "of" parsing function: these descriptors need not come from device tree and it's optional so hey. Keep some NULL checks around the GPIO operations even though gpiolib is essentially NULL-tolerant, because by checking for whether we have a valid GPIO descriptor or not we can avoid a 400 ms delay which is great. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230817-descriptors-asoc-rt-v2-1-02fa2ca3e5b0@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 55 +++++++++++++---------------------------------- sound/soc/codecs/rt5640.h | 2 +- 2 files changed, 16 insertions(+), 41 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index eceed8209787..8920726c38e8 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -12,11 +12,10 @@ #include #include #include -#include +#include #include #include #include -#include #include #include #include @@ -2812,8 +2811,8 @@ static int rt5640_suspend(struct snd_soc_component *component) rt5640_reset(component); regcache_cache_only(rt5640->regmap, true); regcache_mark_dirty(rt5640->regmap); - if (gpio_is_valid(rt5640->ldo1_en)) - gpio_set_value_cansleep(rt5640->ldo1_en, 0); + if (rt5640->ldo1_en) + gpiod_set_value_cansleep(rt5640->ldo1_en, 0); return 0; } @@ -2822,8 +2821,8 @@ static int rt5640_resume(struct snd_soc_component *component) { struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); - if (gpio_is_valid(rt5640->ldo1_en)) { - gpio_set_value_cansleep(rt5640->ldo1_en, 1); + if (rt5640->ldo1_en) { + gpiod_set_value_cansleep(rt5640->ldo1_en, 1); msleep(400); } @@ -2986,22 +2985,6 @@ static const struct acpi_device_id rt5640_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match); #endif -static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np) -{ - rt5640->ldo1_en = of_get_named_gpio(np, "realtek,ldo1-en-gpios", 0); - /* - * LDO1_EN is optional (it may be statically tied on the board). - * -ENOENT means that the property doesn't exist, i.e. there is no - * GPIO, so is not an error. Any other error code means the property - * exists, but could not be parsed. - */ - if (!gpio_is_valid(rt5640->ldo1_en) && - (rt5640->ldo1_en != -ENOENT)) - return rt5640->ldo1_en; - - return 0; -} - static int rt5640_i2c_probe(struct i2c_client *i2c) { struct rt5640_priv *rt5640; @@ -3015,12 +2998,16 @@ static int rt5640_i2c_probe(struct i2c_client *i2c) return -ENOMEM; i2c_set_clientdata(i2c, rt5640); - if (i2c->dev.of_node) { - ret = rt5640_parse_dt(rt5640, i2c->dev.of_node); - if (ret) - return ret; - } else - rt5640->ldo1_en = -EINVAL; + rt5640->ldo1_en = devm_gpiod_get_optional(&i2c->dev, + "realtek,ldo1-en", + GPIOD_OUT_HIGH); + if (IS_ERR(rt5640->ldo1_en)) + return PTR_ERR(rt5640->ldo1_en); + + if (rt5640->ldo1_en) { + gpiod_set_consumer_name(rt5640->ldo1_en, "RT5640 LDO1_EN"); + msleep(400); + } rt5640->regmap = devm_regmap_init_i2c(i2c, &rt5640_regmap); if (IS_ERR(rt5640->regmap)) { @@ -3030,18 +3017,6 @@ static int rt5640_i2c_probe(struct i2c_client *i2c) return ret; } - if (gpio_is_valid(rt5640->ldo1_en)) { - ret = devm_gpio_request_one(&i2c->dev, rt5640->ldo1_en, - GPIOF_OUT_INIT_HIGH, - "RT5640 LDO1_EN"); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to request LDO1_EN %d: %d\n", - rt5640->ldo1_en, ret); - return ret; - } - msleep(400); - } - regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val); if (val != RT5640_DEVICE_ID) { dev_err(&i2c->dev, diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 9847a1ae01f4..94b9a502f7f9 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -2138,7 +2138,7 @@ struct rt5640_priv { struct regmap *regmap; struct clk *mclk; - int ldo1_en; /* GPIO for LDO1_EN */ + struct gpio_desc *ldo1_en; /* GPIO for LDO1_EN */ int irq; int jd_gpio_irq; int sysclk; -- cgit v1.2.3 From 647a3c4c33cd2c3902cdc07c50f3129166d715f5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 17 Aug 2023 16:03:18 +0200 Subject: ASoC: rt5665: Convert to use GPIO descriptors The RT5665 driver has some stub support for GPIO descriptors going back to the initial driver commit, where there are two GPIO descriptors for the LDO and headphone detection defined in the device state. Well, let's make use of the descriptor properly. We remove the global GPIO number from the platform data, but it is still possible to create board files using GPIO descriptor tables, if desired. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230817-descriptors-asoc-rt-v2-2-02fa2ca3e5b0@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 525713c33d71..a39de4a7df00 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -15,8 +15,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -4659,9 +4658,6 @@ static int rt5665_parse_dt(struct rt5665_priv *rt5665, struct device *dev) of_property_read_u32(dev->of_node, "realtek,jd-src", &rt5665->pdata.jd_src); - rt5665->pdata.ldo1_en = of_get_named_gpio(dev->of_node, - "realtek,ldo1-en-gpios", 0); - return 0; } @@ -4795,10 +4791,13 @@ static int rt5665_i2c_probe(struct i2c_client *i2c) return ret; } - if (gpio_is_valid(rt5665->pdata.ldo1_en)) { - if (devm_gpio_request_one(&i2c->dev, rt5665->pdata.ldo1_en, - GPIOF_OUT_INIT_HIGH, "rt5665")) - dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); + + rt5665->gpiod_ldo1_en = devm_gpiod_get_optional(&i2c->dev, + "realtek,ldo1-en", + GPIOD_OUT_HIGH); + if (IS_ERR(rt5665->gpiod_ldo1_en)) { + dev_err(&i2c->dev, "Failed gpio request ldo1_en\n"); + return PTR_ERR(rt5665->gpiod_ldo1_en); } /* Sleep for 300 ms miniumum */ -- cgit v1.2.3 From ab2a5d17064436585807f2ece5e6b4b03769a11f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 17 Aug 2023 16:03:19 +0200 Subject: ASoC: rt5668: Convert to use GPIO descriptors Convert the RT5668 to use GPIO descriptors and drop the legacy GPIO headers. We remove the global GPIO number from the platform data, but it is still possible to create board files using GPIO descriptor tables, if desired. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230817-descriptors-asoc-rt-v2-3-02fa2ca3e5b0@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5668.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index f04c810fd710..4623b3e62487 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -15,8 +15,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -43,6 +42,7 @@ static const char *rt5668_supply_names[RT5668_NUM_SUPPLIES] = { struct rt5668_priv { struct snd_soc_component *component; struct rt5668_platform_data pdata; + struct gpio_desc *ldo1_en; struct regmap *regmap; struct snd_soc_jack *hs_jack; struct regulator_bulk_data supplies[RT5668_NUM_SUPPLIES]; @@ -2393,9 +2393,6 @@ static int rt5668_parse_dt(struct rt5668_priv *rt5668, struct device *dev) of_property_read_u32(dev->of_node, "realtek,jd-src", &rt5668->pdata.jd_src); - rt5668->pdata.ldo1_en = of_get_named_gpio(dev->of_node, - "realtek,ldo1-en-gpios", 0); - return 0; } @@ -2497,10 +2494,12 @@ static int rt5668_i2c_probe(struct i2c_client *i2c) return ret; } - if (gpio_is_valid(rt5668->pdata.ldo1_en)) { - if (devm_gpio_request_one(&i2c->dev, rt5668->pdata.ldo1_en, - GPIOF_OUT_INIT_HIGH, "rt5668")) - dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); + rt5668->ldo1_en = devm_gpiod_get_optional(&i2c->dev, + "realtek,ldo1-en", + GPIOD_OUT_HIGH); + if (IS_ERR(rt5668->ldo1_en)) { + dev_err(&i2c->dev, "Fail gpio request ldo1_en\n"); + return PTR_ERR(rt5668->ldo1_en); } /* Sleep for 300 ms miniumum */ -- cgit v1.2.3 From ed11701751d43fb2318c625e65e0507b5234f8a5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 17 Aug 2023 16:03:20 +0200 Subject: ASoC: rt5682: Convert to use GPIO descriptors Convert the RT5682 to use GPIO descriptors and drop the legacy GPIO headers. We remove the global GPIO number from the platform data, but it is still possible to create board files using GPIO descriptor tables, if desired. Make sure to make sure SDW devices can associate with an LDO1 EN descriptor too, if they so desire by putting the lookup into the common code. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230817-descriptors-asoc-rt-v2-4-02fa2ca3e5b0@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682-i2c.c | 11 ++++------- sound/soc/codecs/rt5682-sdw.c | 5 +++++ sound/soc/codecs/rt5682.c | 20 +++++++++++++++----- sound/soc/codecs/rt5682.h | 3 +++ 4 files changed, 27 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c index fb8ffb5b2ff6..b05b4f73d8aa 100644 --- a/sound/soc/codecs/rt5682-i2c.c +++ b/sound/soc/codecs/rt5682-i2c.c @@ -15,8 +15,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -170,11 +169,9 @@ static int rt5682_i2c_probe(struct i2c_client *i2c) return ret; } - if (gpio_is_valid(rt5682->pdata.ldo1_en)) { - if (devm_gpio_request_one(&i2c->dev, rt5682->pdata.ldo1_en, - GPIOF_OUT_INIT_HIGH, "rt5682")) - dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); - } + ret = rt5682_get_ldo1(rt5682, &i2c->dev); + if (ret) + return ret; /* Sleep for 300 ms miniumum */ usleep_range(300000, 350000); diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 65e9c6dc1a54..e67c2e19cb1a 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -320,6 +320,11 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap, return ret; } + + ret = rt5682_get_ldo1(rt5682, dev); + if (ret) + return ret; + regcache_cache_only(rt5682->sdw_regmap, true); regcache_cache_only(rt5682->regmap, true); diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 694c581070d9..e3aca9c785a0 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -15,8 +15,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -3094,9 +3093,6 @@ int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev) device_property_read_u32(dev, "realtek,dmic-delay-ms", &rt5682->pdata.dmic_delay); - rt5682->pdata.ldo1_en = of_get_named_gpio(dev->of_node, - "realtek,ldo1-en-gpios", 0); - if (device_property_read_string_array(dev, "clock-output-names", rt5682->pdata.dai_clk_names, RT5682_DAI_NUM_CLKS) < 0) @@ -3111,6 +3107,20 @@ int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev) } EXPORT_SYMBOL_GPL(rt5682_parse_dt); +int rt5682_get_ldo1(struct rt5682_priv *rt5682, struct device *dev) +{ + rt5682->ldo1_en = devm_gpiod_get_optional(dev, + "realtek,ldo1-en", + GPIOD_OUT_HIGH); + if (IS_ERR(rt5682->ldo1_en)) { + dev_err(dev, "Fail gpio request ldo1_en\n"); + return PTR_ERR(rt5682->ldo1_en); + } + + return 0; +} +EXPORT_SYMBOL_GPL(rt5682_get_ldo1); + void rt5682_calibrate(struct rt5682_priv *rt5682) { int value, count; diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h index 1a43d595f341..b2d9e87af259 100644 --- a/sound/soc/codecs/rt5682.h +++ b/sound/soc/codecs/rt5682.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -1430,6 +1431,7 @@ struct rt5682_priv { struct snd_soc_component *component; struct device *i2c_dev; struct rt5682_platform_data pdata; + struct gpio_desc *ldo1_en; struct regmap *regmap; struct regmap *sdw_regmap; struct snd_soc_jack *hs_jack; @@ -1481,6 +1483,7 @@ int rt5682_register_component(struct device *dev); void rt5682_calibrate(struct rt5682_priv *rt5682); void rt5682_reset(struct rt5682_priv *rt5682); int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev); +int rt5682_get_ldo1(struct rt5682_priv *rt5682, struct device *dev); int rt5682_register_dai_clks(struct rt5682_priv *rt5682); -- cgit v1.2.3 From 8793bee716452e5e2f9bf085fbe01f9e3d1e659f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 17 Aug 2023 16:03:21 +0200 Subject: ASoC: rt5682s: Convert to use GPIO descriptors Convert the RT5682S to use GPIO descriptors and drop the legacy GPIO headers. We remove the global GPIO number from the platform data, but it is still possible to create board files using GPIO descriptor tables, if desired. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230817-descriptors-asoc-rt-v2-5-02fa2ca3e5b0@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682s.c | 16 +++++++--------- sound/soc/codecs/rt5682s.h | 2 ++ 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index c77c675bd5f5..68ac5ea50396 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -15,8 +15,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -2973,9 +2972,6 @@ static int rt5682s_parse_dt(struct rt5682s_priv *rt5682s, struct device *dev) device_property_read_u32(dev, "realtek,amic-delay-ms", &rt5682s->pdata.amic_delay); - rt5682s->pdata.ldo1_en = of_get_named_gpio(dev->of_node, - "realtek,ldo1-en-gpios", 0); - if (device_property_read_string_array(dev, "clock-output-names", rt5682s->pdata.dai_clk_names, RT5682S_DAI_NUM_CLKS) < 0) @@ -3172,10 +3168,12 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c) return ret; } - if (gpio_is_valid(rt5682s->pdata.ldo1_en)) { - if (devm_gpio_request_one(&i2c->dev, rt5682s->pdata.ldo1_en, - GPIOF_OUT_INIT_HIGH, "rt5682s")) - dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); + rt5682s->ldo1_en = devm_gpiod_get_optional(&i2c->dev, + "realtek,ldo1-en", + GPIOD_OUT_HIGH); + if (IS_ERR(rt5682s->ldo1_en)) { + dev_err(&i2c->dev, "Fail gpio request ldo1_en\n"); + return PTR_ERR(rt5682s->ldo1_en); } /* Sleep for 50 ms minimum */ diff --git a/sound/soc/codecs/rt5682s.h b/sound/soc/codecs/rt5682s.h index caa7733b430f..1d79d432d0d8 100644 --- a/sound/soc/codecs/rt5682s.h +++ b/sound/soc/codecs/rt5682s.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -1446,6 +1447,7 @@ enum { struct rt5682s_priv { struct snd_soc_component *component; struct rt5682s_platform_data pdata; + struct gpio_desc *ldo1_en; struct regmap *regmap; struct snd_soc_jack *hs_jack; struct regulator_bulk_data supplies[RT5682S_NUM_SUPPLIES]; -- cgit v1.2.3 From a707885aff6cfa4f2abcb33ca684044afe4e632c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 18 Aug 2023 09:09:13 +0200 Subject: 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(-) (limited to 'sound') 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; } -- cgit v1.2.3 From 828b871ac11a2a7d7c061e2a29a0f0a1225c694a Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Thu, 17 Aug 2023 17:37:39 +0800 Subject: 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(+) (limited to 'sound') 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. -- cgit v1.2.3 From 3babae915f4c15d76a5134e55806a1c1588e2865 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Fri, 18 Aug 2023 16:58:35 +0800 Subject: 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(-) (limited to 'sound') 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), -- cgit v1.2.3 From 5be27f1e3ec98975c18a91e220d4847d0dec9671 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Fri, 18 Aug 2023 16:58:36 +0800 Subject: 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 (limited to 'sound') 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); -- cgit v1.2.3 From cf393babb37a1679a1ec1d864df1090353465e23 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:13 +0200 Subject: 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 --- sound/core/pcm_lib.c | 111 +++++++++++++++++++++++++++++------------------- sound/core/pcm_native.c | 2 +- 2 files changed, 68 insertions(+), 45 deletions(-) (limited to 'sound') 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) -- cgit v1.2.3 From 561b4fa9c1111292ec975a04ecd8372ac0256e1e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:14 +0200 Subject: 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 --- sound/core/memory.c | 56 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 8 deletions(-) (limited to 'sound') 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); -- cgit v1.2.3 From 526a19b3e3ea7cde61c8ac0dcb2796756ef4fa16 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:15 +0200 Subject: 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(-) (limited to 'sound') 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, }; -- cgit v1.2.3 From e2964cd7ef58bd97f7acd5340e71d6b7e260fb2d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:16 +0200 Subject: 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(-) (limited to 'sound') 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, }; -- cgit v1.2.3 From 9d0fdc602de9d4368ce58da158725d2c43765fd1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:17 +0200 Subject: 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(-) (limited to 'sound') 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 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 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_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, }; -- cgit v1.2.3 From 07ee02a2e12e1b97bdd04fa3e42a67380a60054e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:18 +0200 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From 49aa6ed94c5ee3a85fd503748e2df3a432c2a0ec Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:19 +0200 Subject: 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(-) (limited to 'sound') 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) -{ - 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) + struct iov_iter *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, }; /* -- cgit v1.2.3 From 75bd8e3f4c812aa64e9b162cf094087552105f4e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:20 +0200 Subject: 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(-) (limited to 'sound') 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, }; -- cgit v1.2.3 From 50496aa216d564fb24783e1c94a2a12c0ef303a6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:21 +0200 Subject: 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(-) (limited to 'sound') 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, }; -- cgit v1.2.3 From c3abdf06a9e51d8e4cf97bc58b4b966a254b560f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:22 +0200 Subject: 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(-) (limited to 'sound') 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, }; -- cgit v1.2.3 From 90ed231177d3ca88b8a424e7c9e344a3e4577bbe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:23 +0200 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From 2098765e952714d01a5cd615f5a80733762097c0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:24 +0200 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From 2f432f4702134fac27677f13aba69ed830984f75 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:25 +0200 Subject: 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(-) (limited to 'sound') 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, }; -- cgit v1.2.3 From 390244f5ba355a97ff9764d9946fe37eb1b195ce Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:26 +0200 Subject: 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(-) (limited to 'sound') 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,56 +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) -{ - 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; - - 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) +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; @@ -663,8 +631,8 @@ static int alsa_cap_copy_kernel(struct snd_pcm_substream *substream, 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, -- cgit v1.2.3 From 62da99b56f0b43435896c4a5eca050631c99ce4f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:27 +0200 Subject: 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(-) (limited to 'sound') 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'. -- cgit v1.2.3 From 66201cacc33d740057bd64af6371ad846cff376f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:29 +0200 Subject: 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 --- sound/soc/soc-component.c | 18 ++++++++++++++++++ sound/soc/soc-pcm.c | 4 +++- 2 files changed, 21 insertions(+), 1 deletion(-) (limited to 'sound') 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; -- cgit v1.2.3 From 95396d83e96cc1b7887562d07ff0324c11e744db Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:30 +0200 Subject: 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(-) (limited to 'sound') 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) -- cgit v1.2.3 From ce2d8ed8d809e70e1eb260b2e02a7be0ba0c0211 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:31 +0200 Subject: 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(-) (limited to 'sound') 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, }; -- cgit v1.2.3 From 56b00d10ffd4dcd6b068c2290ffabf0ae2d49789 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:32 +0200 Subject: 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(-) (limited to 'sound') 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, }; -- cgit v1.2.3 From 9bebd65443c1379f6643397bf4854d6f80a8358c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:33 +0200 Subject: 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 --- sound/soc/atmel/mchp-pdmc.c | 2 +- sound/soc/soc-generic-dmaengine-pcm.c | 5 ++--- sound/soc/stm/stm32_sai_sub.c | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'sound') 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); -- cgit v1.2.3 From 205d3e030a02b18a6bc1ca590965871a803163f2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:35 +0200 Subject: 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 --- sound/soc/soc-component.c | 20 -------------------- sound/soc/soc-pcm.c | 2 -- 2 files changed, 22 deletions(-) (limited to 'sound') 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) -- cgit v1.2.3 From 6c0217b11066b9bcd6d8f1f8bd11c0610e536e04 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Aug 2023 21:01:36 +0200 Subject: 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 --- sound/core/pcm_lib.c | 18 +----------------- sound/core/pcm_native.c | 2 +- 2 files changed, 2 insertions(+), 18 deletions(-) (limited to 'sound') 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) -- cgit v1.2.3 From aa98697c7dbd8dcb30841ca48456e7d534209d6d Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Fri, 18 Aug 2023 02:37:32 +0000 Subject: ASoC: rt5645: improve the depop sequences of CBJ detection This patch will improve the depop function of CBJ detection before the headphone playback when the system resumes. We also want to complete the CBJ detection in the system-level resume function. It could avoid triggering the detection at the playing state of headphones. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20230818023732.2153170-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index e49aa28280e0..038d93e20883 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -80,6 +80,7 @@ static const struct reg_sequence init_list[] = { static const struct reg_sequence rt5650_init_list[] = { {0xf6, 0x0100}, + {RT5645_PWR_ANLG1, 0x02}, }; static const struct reg_default rt5645_reg[] = { @@ -1696,6 +1697,9 @@ static void hp_amp_power(struct snd_soc_component *component, int on) regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00); snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140); + snd_soc_component_update_bits(component, RT5645_PWR_ANLG1, + RT5645_PWR_HP_L | RT5645_PWR_HP_R, + RT5645_PWR_HP_L | RT5645_PWR_HP_R); msleep(90); } else { /* depop parameters */ @@ -1743,7 +1747,8 @@ static void hp_amp_power(struct snd_soc_component *component, int on) snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140); msleep(100); snd_soc_component_write(component, RT5645_DEPOP_M1, 0x0001); - + snd_soc_component_update_bits(component, RT5645_PWR_ANLG1, + RT5645_PWR_HP_L | RT5645_PWR_HP_R, 0); } else { snd_soc_component_update_bits(component, RT5645_DEPOP_M1, RT5645_HP_SG_MASK | @@ -3150,7 +3155,7 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse unsigned int val; if (jack_insert) { - regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06); + regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0206); /* for jack type detect */ snd_soc_dapm_force_enable_pin(dapm, "LDO2"); @@ -3195,6 +3200,8 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse if (rt5645->pdata.level_trigger_irq) regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR); + + regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06); } else { /* jack out */ rt5645->jack_type = 0; @@ -4003,13 +4010,13 @@ static int rt5645_i2c_probe(struct i2c_client *i2c) regmap_write(rt5645->regmap, RT5645_AD_DA_MIXER, 0x8080); - ret = regmap_register_patch(rt5645->regmap, init_list, + ret = regmap_multi_reg_write(rt5645->regmap, init_list, ARRAY_SIZE(init_list)); if (ret != 0) dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); if (rt5645->codec_type == CODEC_TYPE_RT5650) { - ret = regmap_register_patch(rt5645->regmap, rt5650_init_list, + ret = regmap_multi_reg_write(rt5645->regmap, rt5650_init_list, ARRAY_SIZE(rt5650_init_list)); if (ret != 0) dev_warn(&i2c->dev, "Apply rt5650 patch failed: %d\n", @@ -4220,8 +4227,7 @@ static int __maybe_unused rt5645_sys_resume(struct device *dev) if (rt5645->hp_jack) { rt5645->jack_type = 0; - queue_delayed_work(system_power_efficient_wq, - &rt5645->jack_detect_work, msecs_to_jiffies(0)); + rt5645_jack_detect_work(&rt5645->jack_detect_work.work); } return 0; } -- cgit v1.2.3 From 919a4a941863c539e982d34903e93d9777316f7d Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Fri, 18 Aug 2023 11:03:14 +0300 Subject: ASoC: amd: acp: Add kcontrols and widgets per-codec in common code Commit 7ac3404c2e21 ("ASoC: amd: acp: Map missing jack kcontrols") adds card kcontrols and DAPM widgets corresponding to jacks for Headphone and Headset Mic. But these were already being added in acp-legacy-mach.c and acp-sof-mach.c, so this causes a probe error: sof_mach rt5682s-hs-rt1019: control 2:0:0:Headphone Jack Switch:0 is already present sof_mach rt5682s-hs-rt1019: ASoC: Failed to add Headphone Jack Switch: -16 sof_mach rt5682s-hs-rt1019: devm_snd_soc_register_card(sof-rt5682s-hs-rt1019) failed: -16 sof_mach: probe of rt5682s-hs-rt1019 failed with error -16 Removing the new duplicates from the common code might be enough to fix the issue. But some of the codecs use different kcontrols and widgets. NAU8821 alone has an "Int Mic". MAX98360A has a single "Spk", while RT1019 has "Left Spk" and "Right Spk" (and two codec instances with name prefixes). Since there are per-codec differences, add the kcontrols and widgets in the common code as each dai-link is being initialized, instead of in the two machine drivers' probe(). Also, MAX98388 has Left and Right instances, but uses a single "SPK" widget. That seems weird, so normalize it to use two widgets (one per each instance like RT1019) while we're adding controls. Fixes: 7ac3404c2e21 ("ASoC: amd: acp: Map missing jack kcontrols") Signed-off-by: Alper Nebi Yasak Link: https://lore.kernel.org/r/20230818080314.32991-1-alpernebiyasak@gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-legacy-mach.c | 22 +----------- sound/soc/amd/acp/acp-mach-common.c | 68 +++++++++++++++++++++++++++++++++++-- sound/soc/amd/acp/acp-sof-mach.c | 21 +----------- 3 files changed, 67 insertions(+), 44 deletions(-) (limited to 'sound') diff --git a/sound/soc/amd/acp/acp-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c index 676ad50638d0..6d57d17ddfd7 100644 --- a/sound/soc/amd/acp/acp-legacy-mach.c +++ b/sound/soc/amd/acp/acp-legacy-mach.c @@ -75,23 +75,6 @@ static struct acp_card_drvdata rt5682s_rt1019_rmb_data = { .tdm_mode = false, }; -static const struct snd_kcontrol_new acp_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Spk"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), - -}; - -static const struct snd_soc_dapm_widget acp_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), -}; - static int acp_asoc_probe(struct platform_device *pdev) { struct snd_soc_card *card = NULL; @@ -110,11 +93,8 @@ static int acp_asoc_probe(struct platform_device *pdev) card->dev = dev; card->owner = THIS_MODULE; card->name = pdev->id_entry->name; - card->dapm_widgets = acp_widgets; - card->num_dapm_widgets = ARRAY_SIZE(acp_widgets); - card->controls = acp_controls; - card->num_controls = ARRAY_SIZE(acp_controls); card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data; + /* Widgets and controls added per-codec in acp-mach-common.c */ acp_card_drvdata = card->drvdata; dmi_id = dmi_first_match(acp_quirk_table); diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index f3abaa182fbb..a06af82b8056 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -513,6 +513,16 @@ SND_SOC_DAILINK_DEF(rt1019, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1019:00", "rt1019-aif"), COMP_CODEC("i2c-10EC1019:01", "rt1019-aif"))); +static const struct snd_kcontrol_new rt1019_controls[] = { + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), +}; + +static const struct snd_soc_dapm_widget rt1019_widgets[] = { + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), +}; + static const struct snd_soc_dapm_route rt1019_map_lr[] = { { "Left Spk", NULL, "Left SPO" }, { "Right Spk", NULL, "Right SPO" }, @@ -533,10 +543,25 @@ static int acp_card_rt1019_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 != RT1019) return -EINVAL; + ret = snd_soc_dapm_new_controls(&card->dapm, rt1019_widgets, + ARRAY_SIZE(rt1019_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, rt1019_controls, + ARRAY_SIZE(rt1019_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + return snd_soc_dapm_add_routes(&rtd->card->dapm, rt1019_map_lr, ARRAY_SIZE(rt1019_map_lr)); } @@ -667,6 +692,14 @@ static const struct snd_soc_ops acp_card_rt1019_ops = { SND_SOC_DAILINK_DEF(max98360a, DAILINK_COMP_ARRAY(COMP_CODEC("MX98360A:00", "HiFi"))); +static const struct snd_kcontrol_new max98360a_controls[] = { + SOC_DAPM_PIN_SWITCH("Spk"), +}; + +static const struct snd_soc_dapm_widget max98360a_widgets[] = { + SND_SOC_DAPM_SPK("Spk", NULL), +}; + static const struct snd_soc_dapm_route max98360a_map[] = { {"Spk", NULL, "Speaker"}, }; @@ -675,10 +708,25 @@ static int acp_card_maxim_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 != MAX98360A) return -EINVAL; + ret = snd_soc_dapm_new_controls(&card->dapm, max98360a_widgets, + ARRAY_SIZE(max98360a_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, max98360a_controls, + ARRAY_SIZE(max98360a_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + return snd_soc_dapm_add_routes(&rtd->card->dapm, max98360a_map, ARRAY_SIZE(max98360a_map)); } @@ -744,13 +792,19 @@ 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_kcontrol_new max98388_controls[] = { + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), +}; + static const struct snd_soc_dapm_widget max98388_widgets[] = { - SND_SOC_DAPM_SPK("SPK", NULL), + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), }; static const struct snd_soc_dapm_route max98388_map[] = { - { "SPK", NULL, "Left BE_OUT" }, - { "SPK", NULL, "Right BE_OUT" }, + { "Left Spk", NULL, "Left BE_OUT" }, + { "Right Spk", NULL, "Right BE_OUT" }, }; static struct snd_soc_codec_conf max98388_conf[] = { @@ -803,6 +857,14 @@ static int acp_card_max98388_init(struct snd_soc_pcm_runtime *rtd) /* Don't need to add routes if widget addition failed */ return ret; } + + ret = snd_soc_add_card_controls(card, max98388_controls, + ARRAY_SIZE(max98388_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + return snd_soc_dapm_add_routes(&rtd->card->dapm, max98388_map, ARRAY_SIZE(max98388_map)); } diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c index a1c893f33f74..5223033a122f 100644 --- a/sound/soc/amd/acp/acp-sof-mach.c +++ b/sound/soc/amd/acp/acp-sof-mach.c @@ -94,22 +94,6 @@ static struct acp_card_drvdata sof_nau8821_max98388_data = { .tdm_mode = false, }; -static const struct snd_kcontrol_new acp_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Spk"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), -}; - -static const struct snd_soc_dapm_widget acp_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), -}; - static int acp_sof_probe(struct platform_device *pdev) { struct snd_soc_card *card = NULL; @@ -128,11 +112,8 @@ static int acp_sof_probe(struct platform_device *pdev) card->dev = dev; card->owner = THIS_MODULE; card->name = pdev->id_entry->name; - card->dapm_widgets = acp_widgets; - card->num_dapm_widgets = ARRAY_SIZE(acp_widgets); - card->controls = acp_controls; - card->num_controls = ARRAY_SIZE(acp_controls); card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data; + /* Widgets and controls added per-codec in acp-mach-common.c */ acp_card_drvdata = card->drvdata; dmi_id = dmi_first_match(acp_quirk_table); -- cgit v1.2.3 From 9f533734640649883cd1f4d4ebb024858d49a0b6 Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Fri, 18 Aug 2023 20:48:52 +0800 Subject: 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(-) (limited to 'sound') 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 -- cgit v1.2.3 From fc918cbe874eee0950b6425c1b30bcd4860dc076 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 4 Aug 2023 11:46:02 +0100 Subject: ASoC: cs42l43: Add support for the cs42l43 The CS42L43 is an audio CODEC with integrated MIPI SoundWire interface (Version 1.2.1 compliant), I2C, SPI, and I2S/TDM interfaces designed for portable applications. It provides a high dynamic range, stereo DAC for headphone output, two integrated Class D amplifiers for loudspeakers, and two ADCs for wired headset microphone input or stereo line input. PDM inputs are provided for digital microphones. The ASoC component provides the majority of the functionality of the device, all the audio functions. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20230804104602.395892-7-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 16 + sound/soc/codecs/Makefile | 4 + sound/soc/codecs/cs42l43-jack.c | 946 ++++++++++++++++ sound/soc/codecs/cs42l43-sdw.c | 74 ++ sound/soc/codecs/cs42l43.c | 2278 +++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/cs42l43.h | 131 +++ 6 files changed, 3449 insertions(+) create mode 100644 sound/soc/codecs/cs42l43-jack.c create mode 100644 sound/soc/codecs/cs42l43-sdw.c create mode 100644 sound/soc/codecs/cs42l43.c create mode 100644 sound/soc/codecs/cs42l43.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c2de4ee72183..49367d49b416 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -74,6 +74,8 @@ config SND_SOC_ALL_CODECS imply SND_SOC_CS35L56_SDW imply SND_SOC_CS42L42 imply SND_SOC_CS42L42_SDW + imply SND_SOC_CS42L43 + imply SND_SOC_CS42L43_SDW imply SND_SOC_CS42L51_I2C imply SND_SOC_CS42L52 imply SND_SOC_CS42L56 @@ -789,6 +791,20 @@ config SND_SOC_CS42L42_SDW help Enable support for Cirrus Logic CS42L42 codec with Soundwire control +config SND_SOC_CS42L43 + tristate "Cirrus Logic CS42L43 CODEC" + depends on MFD_CS42L43 + help + Select this to support the audio functions of the Cirrus Logic + CS42L43 PC CODEC. + +config SND_SOC_CS42L43_SDW + tristate "Cirrus Logic CS42L43 CODEC (SoundWire)" + depends on SND_SOC_CS42L43 && MFD_CS42L43_SDW + help + Select this to support the audio functions of the Cirrus Logic + CS42L43 PC CODEC over SoundWire. + config SND_SOC_CS42L51 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index b48a9a323b84..20d1a841991d 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -75,6 +75,8 @@ snd-soc-cs35l56-sdw-objs := cs35l56-sdw.o snd-soc-cs42l42-objs := cs42l42.o snd-soc-cs42l42-i2c-objs := cs42l42-i2c.o snd-soc-cs42l42-sdw-objs := cs42l42-sdw.o +snd-soc-cs42l43-objs := cs42l43.o cs42l43-jack.o +snd-soc-cs42l43-sdw-objs := cs42l43-sdw.o snd-soc-cs42l51-objs := cs42l51.o snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o snd-soc-cs42l52-objs := cs42l52.o @@ -457,6 +459,8 @@ obj-$(CONFIG_SND_SOC_CS35L56_SDW) += snd-soc-cs35l56-sdw.o obj-$(CONFIG_SND_SOC_CS42L42_CORE) += snd-soc-cs42l42.o obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42-i2c.o obj-$(CONFIG_SND_SOC_CS42L42_SDW) += snd-soc-cs42l42-sdw.o +obj-$(CONFIG_SND_SOC_CS42L43) += snd-soc-cs42l43.o +obj-$(CONFIG_SND_SOC_CS42L43_SDW) += snd-soc-cs42l43-sdw.o obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c new file mode 100644 index 000000000000..92e37bc1df9d --- /dev/null +++ b/sound/soc/codecs/cs42l43-jack.c @@ -0,0 +1,946 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// CS42L43 CODEC driver jack handling +// +// Copyright (C) 2022-2023 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cs42l43.h" + +static const unsigned int cs42l43_accdet_us[] = { + 20, 100, 1000, 10000, 50000, 75000, 100000, 200000 +}; + +static const unsigned int cs42l43_accdet_db_ms[] = { + 0, 125, 250, 500, 750, 1000, 1250, 1500 +}; + +static const unsigned int cs42l43_accdet_ramp_ms[] = { 10, 40, 90, 170 }; + +static const unsigned int cs42l43_accdet_bias_sense[] = { + 14, 23, 41, 50, 60, 68, 86, 95, 0, +}; + +static int cs42l43_find_index(struct cs42l43_codec *priv, const char * const prop, + unsigned int defval, unsigned int *val, + const unsigned int *values, const int nvalues) +{ + struct cs42l43 *cs42l43 = priv->core; + int i, ret; + + ret = device_property_read_u32(cs42l43->dev, prop, &defval); + if (ret != -EINVAL && ret < 0) { + dev_err(priv->dev, "Property %s malformed: %d\n", prop, ret); + return ret; + } + + if (val) + *val = defval; + + for (i = 0; i < nvalues; i++) + if (defval == values[i]) + return i; + + dev_err(priv->dev, "Invalid value for property %s: %d\n", prop, defval); + return -EINVAL; +} + +int cs42l43_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *d) +{ + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + /* This tip sense invert is always set, HW wants an inverted signal */ + unsigned int tip_deb = CS42L43_TIPSENSE_INV_MASK; + unsigned int hs2 = 0x2 << CS42L43_HSDET_MODE_SHIFT; + unsigned int autocontrol = 0, pdncntl = 0; + int ret; + + dev_dbg(priv->dev, "Configure accessory detect\n"); + + ret = pm_runtime_resume_and_get(priv->dev); + if (ret) { + dev_err(priv->dev, "Failed to resume for jack config: %d\n", ret); + return ret; + } + + mutex_lock(&priv->jack_lock); + + priv->jack_hp = jack; + + if (!jack) + goto done; + + ret = device_property_count_u32(cs42l43->dev, "cirrus,buttons-ohms"); + if (ret != -EINVAL) { + if (ret < 0) { + dev_err(priv->dev, "Property cirrus,buttons-ohms malformed: %d\n", + ret); + goto error; + } + + if (ret > CS42L43_N_BUTTONS) { + ret = -EINVAL; + dev_err(priv->dev, "Property cirrus,buttons-ohms too many entries\n"); + goto error; + } + + device_property_read_u32_array(cs42l43->dev, "cirrus,buttons-ohms", + priv->buttons, ret); + } else { + priv->buttons[0] = 70; + priv->buttons[1] = 185; + priv->buttons[2] = 355; + priv->buttons[3] = 735; + } + + ret = cs42l43_find_index(priv, "cirrus,detect-us", 10000, &priv->detect_us, + cs42l43_accdet_us, ARRAY_SIZE(cs42l43_accdet_us)); + if (ret < 0) + goto error; + + hs2 |= ret << CS42L43_AUTO_HSDET_TIME_SHIFT; + + priv->bias_low = device_property_read_bool(cs42l43->dev, "cirrus,bias-low"); + + ret = cs42l43_find_index(priv, "cirrus,bias-ramp-ms", 170, + &priv->bias_ramp_ms, cs42l43_accdet_ramp_ms, + ARRAY_SIZE(cs42l43_accdet_ramp_ms)); + if (ret < 0) + goto error; + + hs2 |= ret << CS42L43_HSBIAS_RAMP_SHIFT; + + ret = cs42l43_find_index(priv, "cirrus,bias-sense-microamp", 0, + &priv->bias_sense_ua, cs42l43_accdet_bias_sense, + ARRAY_SIZE(cs42l43_accdet_bias_sense)); + if (ret < 0) + goto error; + + if (priv->bias_sense_ua) + autocontrol |= ret << CS42L43_HSBIAS_SENSE_TRIP_SHIFT; + + if (!device_property_read_bool(cs42l43->dev, "cirrus,button-automute")) + autocontrol |= CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK; + + ret = device_property_read_u32(cs42l43->dev, "cirrus,tip-debounce-ms", + &priv->tip_debounce_ms); + if (ret < 0 && ret != -EINVAL) { + dev_err(priv->dev, "Property cirrus,tip-debounce-ms malformed: %d\n", ret); + goto error; + } + + /* This tip sense invert is set normally, as TIPSENSE_INV already inverted */ + if (device_property_read_bool(cs42l43->dev, "cirrus,tip-invert")) + autocontrol |= 0x1 << CS42L43_JACKDET_INV_SHIFT; + + if (device_property_read_bool(cs42l43->dev, "cirrus,tip-disable-pullup")) + autocontrol |= 0x1 << CS42L43_JACKDET_MODE_SHIFT; + else + autocontrol |= 0x3 << CS42L43_JACKDET_MODE_SHIFT; + + ret = cs42l43_find_index(priv, "cirrus,tip-fall-db-ms", 500, + NULL, cs42l43_accdet_db_ms, + ARRAY_SIZE(cs42l43_accdet_db_ms)); + if (ret < 0) + goto error; + + tip_deb |= ret << CS42L43_TIPSENSE_FALLING_DB_TIME_SHIFT; + + ret = cs42l43_find_index(priv, "cirrus,tip-rise-db-ms", 500, + NULL, cs42l43_accdet_db_ms, + ARRAY_SIZE(cs42l43_accdet_db_ms)); + if (ret < 0) + goto error; + + tip_deb |= ret << CS42L43_TIPSENSE_RISING_DB_TIME_SHIFT; + + if (device_property_read_bool(cs42l43->dev, "cirrus,use-ring-sense")) { + unsigned int ring_deb = 0; + + priv->use_ring_sense = true; + + /* HW wants an inverted signal, so invert the invert */ + if (!device_property_read_bool(cs42l43->dev, "cirrus,ring-invert")) + ring_deb |= CS42L43_RINGSENSE_INV_MASK; + + if (!device_property_read_bool(cs42l43->dev, + "cirrus,ring-disable-pullup")) + ring_deb |= CS42L43_RINGSENSE_PULLUP_PDNB_MASK; + + ret = cs42l43_find_index(priv, "cirrus,ring-fall-db-ms", 500, + NULL, cs42l43_accdet_db_ms, + ARRAY_SIZE(cs42l43_accdet_db_ms)); + if (ret < 0) + goto error; + + ring_deb |= ret << CS42L43_RINGSENSE_FALLING_DB_TIME_SHIFT; + + ret = cs42l43_find_index(priv, "cirrus,ring-rise-db-ms", 500, + NULL, cs42l43_accdet_db_ms, + ARRAY_SIZE(cs42l43_accdet_db_ms)); + if (ret < 0) + goto error; + + ring_deb |= ret << CS42L43_RINGSENSE_RISING_DB_TIME_SHIFT; + pdncntl |= CS42L43_RING_SENSE_EN_MASK; + + regmap_update_bits(cs42l43->regmap, CS42L43_RINGSENSE_DEB_CTRL, + CS42L43_RINGSENSE_INV_MASK | + CS42L43_RINGSENSE_PULLUP_PDNB_MASK | + CS42L43_RINGSENSE_FALLING_DB_TIME_MASK | + CS42L43_RINGSENSE_RISING_DB_TIME_MASK, + ring_deb); + } + + regmap_update_bits(cs42l43->regmap, CS42L43_TIPSENSE_DEB_CTRL, + CS42L43_TIPSENSE_INV_MASK | + CS42L43_TIPSENSE_FALLING_DB_TIME_MASK | + CS42L43_TIPSENSE_RISING_DB_TIME_MASK, tip_deb); + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HSBIAS_RAMP_MASK | CS42L43_HSDET_MODE_MASK | + CS42L43_AUTO_HSDET_TIME_MASK, hs2); + +done: + ret = 0; + + regmap_update_bits(cs42l43->regmap, CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, + CS42L43_JACKDET_MODE_MASK | CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK | + CS42L43_HSBIAS_SENSE_TRIP_MASK, autocontrol); + regmap_update_bits(cs42l43->regmap, CS42L43_PDNCNTL, + CS42L43_RING_SENSE_EN_MASK, pdncntl); + + dev_dbg(priv->dev, "Successfully configured accessory detect\n"); + +error: + mutex_unlock(&priv->jack_lock); + + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); + + return ret; +} + +static void cs42l43_start_hs_bias(struct cs42l43_codec *priv, bool force_high) +{ + struct cs42l43 *cs42l43 = priv->core; + unsigned int val = 0x3 << CS42L43_HSBIAS_MODE_SHIFT; + + dev_dbg(priv->dev, "Start headset bias\n"); + + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HS_CLAMP_DISABLE_MASK, CS42L43_HS_CLAMP_DISABLE_MASK); + + if (!force_high && priv->bias_low) + val = 0x2 << CS42L43_HSBIAS_MODE_SHIFT; + + regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1, + CS42L43_HSBIAS_MODE_MASK, val); + + msleep(priv->bias_ramp_ms); +} + +static void cs42l43_stop_hs_bias(struct cs42l43_codec *priv) +{ + struct cs42l43 *cs42l43 = priv->core; + + dev_dbg(priv->dev, "Stop headset bias\n"); + + regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1, + CS42L43_HSBIAS_MODE_MASK, 0x1 << CS42L43_HSBIAS_MODE_SHIFT); + + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HS_CLAMP_DISABLE_MASK, 0); +} + +irqreturn_t cs42l43_bias_detect_clamp(int irq, void *data) +{ + struct cs42l43_codec *priv = data; + + queue_delayed_work(system_wq, &priv->bias_sense_timeout, + msecs_to_jiffies(250)); + + return IRQ_HANDLED; +} + +#define CS42L43_JACK_PRESENT 0x3 +#define CS42L43_JACK_ABSENT 0x0 + +#define CS42L43_JACK_OPTICAL (SND_JACK_MECHANICAL | SND_JACK_AVOUT) +#define CS42L43_JACK_HEADPHONE (SND_JACK_MECHANICAL | SND_JACK_HEADPHONE) +#define CS42L43_JACK_HEADSET (SND_JACK_MECHANICAL | SND_JACK_HEADSET) +#define CS42L43_JACK_LINEOUT (SND_JACK_MECHANICAL | SND_JACK_LINEOUT) +#define CS42L43_JACK_LINEIN (SND_JACK_MECHANICAL | SND_JACK_LINEIN) +#define CS42L43_JACK_EXTENSION (SND_JACK_MECHANICAL) +#define CS42L43_JACK_BUTTONS (SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | \ + SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5) + +static inline bool cs42l43_jack_present(struct cs42l43_codec *priv) +{ + struct cs42l43 *cs42l43 = priv->core; + unsigned int sts = 0; + + regmap_read(cs42l43->regmap, CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS, &sts); + + sts = (sts >> CS42L43_TIPSENSE_PLUG_DB_STS_SHIFT) & CS42L43_JACK_PRESENT; + + return sts == CS42L43_JACK_PRESENT; +} + +static void cs42l43_start_button_detect(struct cs42l43_codec *priv) +{ + struct cs42l43 *cs42l43 = priv->core; + unsigned int val = 0x3 << CS42L43_BUTTON_DETECT_MODE_SHIFT; + + dev_dbg(priv->dev, "Start button detect\n"); + + priv->button_detect_running = true; + + if (priv->bias_low) + val = 0x1 << CS42L43_BUTTON_DETECT_MODE_SHIFT; + + regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1, + CS42L43_BUTTON_DETECT_MODE_MASK | + CS42L43_MIC_LVL_DET_DISABLE_MASK, val); + + if (priv->bias_sense_ua) { + regmap_update_bits(cs42l43->regmap, + CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, + CS42L43_HSBIAS_SENSE_EN_MASK | + CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, + CS42L43_HSBIAS_SENSE_EN_MASK | + CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK); + } +} + +static void cs42l43_stop_button_detect(struct cs42l43_codec *priv) +{ + struct cs42l43 *cs42l43 = priv->core; + + dev_dbg(priv->dev, "Stop button detect\n"); + + if (priv->bias_sense_ua) { + regmap_update_bits(cs42l43->regmap, + CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, + CS42L43_HSBIAS_SENSE_EN_MASK | + CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, 0); + } + + regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1, + CS42L43_BUTTON_DETECT_MODE_MASK | + CS42L43_MIC_LVL_DET_DISABLE_MASK, + CS42L43_MIC_LVL_DET_DISABLE_MASK); + + priv->button_detect_running = false; +} + +#define CS42L43_BUTTON_COMB_MAX 512 +#define CS42L43_BUTTON_ROUT 2210 + +void cs42l43_button_press_work(struct work_struct *work) +{ + struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec, + button_press_work.work); + struct cs42l43 *cs42l43 = priv->core; + unsigned int buttons = 0; + unsigned int val = 0; + int i, ret; + + ret = pm_runtime_resume_and_get(priv->dev); + if (ret) { + dev_err(priv->dev, "Failed to resume for button press: %d\n", ret); + return; + } + + mutex_lock(&priv->jack_lock); + + if (!priv->button_detect_running) { + dev_dbg(priv->dev, "Spurious button press IRQ\n"); + goto error; + } + + regmap_read(cs42l43->regmap, CS42L43_DETECT_STATUS_1, &val); + + /* Bail if jack removed, the button is irrelevant and likely invalid */ + if (!cs42l43_jack_present(priv)) { + dev_dbg(priv->dev, "Button ignored due to removal\n"); + goto error; + } + + if (val & CS42L43_HSBIAS_CLAMP_STS_MASK) { + dev_dbg(priv->dev, "Button ignored due to bias sense\n"); + goto error; + } + + val = (val & CS42L43_HSDET_DC_STS_MASK) >> CS42L43_HSDET_DC_STS_SHIFT; + val = ((CS42L43_BUTTON_COMB_MAX << 20) / (val + 1)) - (1 << 20); + if (val) + val = (CS42L43_BUTTON_ROUT << 20) / val; + else + val = UINT_MAX; + + for (i = 0; i < CS42L43_N_BUTTONS; i++) { + if (val < priv->buttons[i]) { + buttons = SND_JACK_BTN_0 >> i; + dev_dbg(priv->dev, "Detected button %d at %d Ohms\n", i, val); + break; + } + } + + if (!buttons) + dev_dbg(priv->dev, "Unrecognised button: %d Ohms\n", val); + + snd_soc_jack_report(priv->jack_hp, buttons, CS42L43_JACK_BUTTONS); + +error: + mutex_unlock(&priv->jack_lock); + + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); +} + +irqreturn_t cs42l43_button_press(int irq, void *data) +{ + struct cs42l43_codec *priv = data; + + // Wait for 2 full cycles of comb filter to ensure good reading + queue_delayed_work(system_wq, &priv->button_press_work, + msecs_to_jiffies(10)); + + return IRQ_HANDLED; +} + +void cs42l43_button_release_work(struct work_struct *work) +{ + struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec, + button_release_work); + int ret; + + ret = pm_runtime_resume_and_get(priv->dev); + if (ret) { + dev_err(priv->dev, "Failed to resume for button release: %d\n", ret); + return; + } + + mutex_lock(&priv->jack_lock); + + if (priv->button_detect_running) { + dev_dbg(priv->dev, "Button release IRQ\n"); + + snd_soc_jack_report(priv->jack_hp, 0, CS42L43_JACK_BUTTONS); + } else { + dev_dbg(priv->dev, "Spurious button release IRQ\n"); + } + + mutex_unlock(&priv->jack_lock); + + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); +} + +irqreturn_t cs42l43_button_release(int irq, void *data) +{ + struct cs42l43_codec *priv = data; + + queue_work(system_wq, &priv->button_release_work); + + return IRQ_HANDLED; +} + +void cs42l43_bias_sense_timeout(struct work_struct *work) +{ + struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec, + bias_sense_timeout.work); + struct cs42l43 *cs42l43 = priv->core; + int ret; + + ret = pm_runtime_resume_and_get(priv->dev); + if (ret) { + dev_err(priv->dev, "Failed to resume for bias sense: %d\n", ret); + return; + } + + mutex_lock(&priv->jack_lock); + + if (cs42l43_jack_present(priv) && priv->button_detect_running) { + dev_dbg(priv->dev, "Bias sense timeout out, restore bias\n"); + + regmap_update_bits(cs42l43->regmap, + CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, + CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, 0); + regmap_update_bits(cs42l43->regmap, + CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, + CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, + CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK); + } + + mutex_unlock(&priv->jack_lock); + + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); +} + +static void cs42l43_start_load_detect(struct cs42l43_codec *priv) +{ + struct cs42l43 *cs42l43 = priv->core; + + dev_dbg(priv->dev, "Start load detect\n"); + + snd_soc_dapm_mutex_lock(snd_soc_component_get_dapm(priv->component)); + + priv->load_detect_running = true; + + if (priv->hp_ena) { + unsigned long time_left; + + reinit_completion(&priv->hp_shutdown); + + regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8, + CS42L43_HP_EN_MASK, 0); + + time_left = wait_for_completion_timeout(&priv->hp_shutdown, + msecs_to_jiffies(CS42L43_HP_TIMEOUT_MS)); + if (!time_left) + dev_err(priv->dev, "Load detect HP power down timed out\n"); + } + + regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3, + CS42L43_ADC1_EN_MASK | CS42L43_ADC2_EN_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG2, CS42L43_HP_HPF_EN_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1, + CS42L43_HSBIAS_MODE_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_CTRL, + CS42L43_ADPTPWR_MODE_MASK, 0x4 << CS42L43_ADPTPWR_MODE_SHIFT); + regmap_update_bits(cs42l43->regmap, CS42L43_PGAVOL, + CS42L43_HP_DIG_VOL_RAMP_MASK | CS42L43_HP_ANA_VOL_RAMP_MASK, 0x6); + regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG1, + CS42L43_HP_MSTR_VOL_CTRL_EN_MASK, 0); + + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HS_CLAMP_DISABLE_MASK, CS42L43_HS_CLAMP_DISABLE_MASK); + + regmap_update_bits(cs42l43->regmap, CS42L43_LOADDETENA, + CS42L43_HPLOAD_DET_EN_MASK, + CS42L43_HPLOAD_DET_EN_MASK); + + snd_soc_dapm_mutex_unlock(snd_soc_component_get_dapm(priv->component)); +} + +static void cs42l43_stop_load_detect(struct cs42l43_codec *priv) +{ + struct cs42l43 *cs42l43 = priv->core; + + dev_dbg(priv->dev, "Stop load detect\n"); + + snd_soc_dapm_mutex_lock(snd_soc_component_get_dapm(priv->component)); + + regmap_update_bits(cs42l43->regmap, CS42L43_LOADDETENA, + CS42L43_HPLOAD_DET_EN_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HS_CLAMP_DISABLE_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG1, + CS42L43_HP_MSTR_VOL_CTRL_EN_MASK, + CS42L43_HP_MSTR_VOL_CTRL_EN_MASK); + regmap_update_bits(cs42l43->regmap, CS42L43_PGAVOL, + CS42L43_HP_DIG_VOL_RAMP_MASK | CS42L43_HP_ANA_VOL_RAMP_MASK, + 0x4 << CS42L43_HP_DIG_VOL_RAMP_SHIFT); + regmap_update_bits(cs42l43->regmap, CS42L43_CTRL, + CS42L43_ADPTPWR_MODE_MASK, 0x7 << CS42L43_ADPTPWR_MODE_SHIFT); + regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1, + CS42L43_HSBIAS_MODE_MASK, 0x1 << CS42L43_HSBIAS_MODE_SHIFT); + regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG2, + CS42L43_HP_HPF_EN_MASK, CS42L43_HP_HPF_EN_MASK); + + regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3, + CS42L43_ADC1_EN_MASK | CS42L43_ADC2_EN_MASK, + priv->adc_ena); + + if (priv->hp_ena) { + unsigned long time_left; + + reinit_completion(&priv->hp_startup); + + regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8, + CS42L43_HP_EN_MASK, priv->hp_ena); + + time_left = wait_for_completion_timeout(&priv->hp_startup, + msecs_to_jiffies(CS42L43_HP_TIMEOUT_MS)); + if (!time_left) + dev_err(priv->dev, "Load detect HP restore timed out\n"); + } + + priv->load_detect_running = false; + + snd_soc_dapm_mutex_unlock(snd_soc_component_get_dapm(priv->component)); +} + +static int cs42l43_run_load_detect(struct cs42l43_codec *priv, bool mic) +{ + struct cs42l43 *cs42l43 = priv->core; + unsigned int val = 0; + unsigned long time_left; + + reinit_completion(&priv->load_detect); + + cs42l43_start_load_detect(priv); + time_left = wait_for_completion_timeout(&priv->load_detect, + msecs_to_jiffies(CS42L43_LOAD_TIMEOUT_MS)); + cs42l43_stop_load_detect(priv); + + if (!time_left) + return -ETIMEDOUT; + + regmap_read(cs42l43->regmap, CS42L43_LOADDETRESULTS, &val); + + dev_dbg(priv->dev, "Headphone load detect: 0x%x\n", val); + + /* Bail if jack removed, the load is irrelevant and likely invalid */ + if (!cs42l43_jack_present(priv)) + return -ENODEV; + + if (mic) { + cs42l43_start_hs_bias(priv, false); + cs42l43_start_button_detect(priv); + + return CS42L43_JACK_HEADSET; + } + + switch (val & CS42L43_AMP3_RES_DET_MASK) { + case 0x0: // low impedance + case 0x1: // high impedance + return CS42L43_JACK_HEADPHONE; + case 0x2: // lineout + case 0x3: // Open circuit + return CS42L43_JACK_LINEOUT; + default: + return -EINVAL; + } +} + +static int cs42l43_run_type_detect(struct cs42l43_codec *priv) +{ + struct cs42l43 *cs42l43 = priv->core; + int timeout_ms = ((2 * priv->detect_us) / 1000) + 200; + unsigned int type = 0xff; + unsigned long time_left; + + reinit_completion(&priv->type_detect); + + cs42l43_start_hs_bias(priv, true); + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HSDET_MODE_MASK, 0x3 << CS42L43_HSDET_MODE_SHIFT); + + time_left = wait_for_completion_timeout(&priv->type_detect, + msecs_to_jiffies(timeout_ms)); + + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HSDET_MODE_MASK, 0x2 << CS42L43_HSDET_MODE_SHIFT); + cs42l43_stop_hs_bias(priv); + + if (!time_left) + return -ETIMEDOUT; + + regmap_read(cs42l43->regmap, CS42L43_HS_STAT, &type); + + dev_dbg(priv->dev, "Type detect: 0x%x\n", type); + + /* Bail if jack removed, the type is irrelevant and likely invalid */ + if (!cs42l43_jack_present(priv)) + return -ENODEV; + + switch (type & CS42L43_HSDET_TYPE_STS_MASK) { + case 0x0: // CTIA + case 0x1: // OMTP + return cs42l43_run_load_detect(priv, true); + case 0x2: // 3-pole + return cs42l43_run_load_detect(priv, false); + case 0x3: // Open-circuit + return CS42L43_JACK_EXTENSION; + default: + return -EINVAL; + } +} + +static void cs42l43_clear_jack(struct cs42l43_codec *priv) +{ + struct cs42l43 *cs42l43 = priv->core; + + cs42l43_stop_button_detect(priv); + cs42l43_stop_hs_bias(priv); + + regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL1, + CS42L43_PGA_WIDESWING_MODE_EN_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL2, + CS42L43_PGA_WIDESWING_MODE_EN_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CTRL, + CS42L43_JACK_STEREO_CONFIG_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HSDET_MODE_MASK | CS42L43_HSDET_MANUAL_MODE_MASK, + 0x2 << CS42L43_HSDET_MODE_SHIFT); + + snd_soc_jack_report(priv->jack_hp, 0, 0xFFFF); +} + +void cs42l43_tip_sense_work(struct work_struct *work) +{ + struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec, + tip_sense_work.work); + struct cs42l43 *cs42l43 = priv->core; + unsigned int sts = 0; + unsigned int tip, ring; + int ret, report; + + ret = pm_runtime_resume_and_get(priv->dev); + if (ret) { + dev_err(priv->dev, "Failed to resume for tip work: %d\n", ret); + return; + } + + mutex_lock(&priv->jack_lock); + + regmap_read(cs42l43->regmap, CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS, &sts); + + dev_dbg(priv->dev, "Tip sense: 0x%x\n", sts); + + tip = (sts >> CS42L43_TIPSENSE_PLUG_DB_STS_SHIFT) & CS42L43_JACK_PRESENT; + ring = (sts >> CS42L43_RINGSENSE_PLUG_DB_STS_SHIFT) & CS42L43_JACK_PRESENT; + + if (tip == CS42L43_JACK_PRESENT) { + if (cs42l43->sdw && !priv->jack_present) { + priv->jack_present = true; + pm_runtime_get(priv->dev); + } + + if (priv->use_ring_sense && ring == CS42L43_JACK_ABSENT) { + report = CS42L43_JACK_OPTICAL; + } else { + report = cs42l43_run_type_detect(priv); + if (report < 0) { + dev_err(priv->dev, "Jack detect failed: %d\n", report); + goto error; + } + } + + snd_soc_jack_report(priv->jack_hp, report, report); + } else { + priv->jack_override = 0; + + cs42l43_clear_jack(priv); + + if (cs42l43->sdw && priv->jack_present) { + pm_runtime_put(priv->dev); + priv->jack_present = false; + } + } + +error: + mutex_unlock(&priv->jack_lock); + + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); +} + +irqreturn_t cs42l43_tip_sense(int irq, void *data) +{ + struct cs42l43_codec *priv = data; + + cancel_delayed_work(&priv->bias_sense_timeout); + cancel_delayed_work(&priv->tip_sense_work); + cancel_delayed_work(&priv->button_press_work); + cancel_work(&priv->button_release_work); + + queue_delayed_work(system_long_wq, &priv->tip_sense_work, + msecs_to_jiffies(priv->tip_debounce_ms)); + + return IRQ_HANDLED; +} + +enum cs42l43_raw_jack { + CS42L43_JACK_RAW_CTIA = 0, + CS42L43_JACK_RAW_OMTP, + CS42L43_JACK_RAW_HEADPHONE, + CS42L43_JACK_RAW_LINE_OUT, + CS42L43_JACK_RAW_LINE_IN, + CS42L43_JACK_RAW_MICROPHONE, + CS42L43_JACK_RAW_OPTICAL, +}; + +#define CS42L43_JACK_3_POLE_SWITCHES ((0x2 << CS42L43_HSDET_MANUAL_MODE_SHIFT) | \ + CS42L43_AMP3_4_GNDREF_HS3_SEL_MASK | \ + CS42L43_AMP3_4_GNDREF_HS4_SEL_MASK | \ + CS42L43_HSBIAS_GNDREF_HS3_SEL_MASK | \ + CS42L43_HSBIAS_GNDREF_HS4_SEL_MASK | \ + CS42L43_HSGND_HS3_SEL_MASK | \ + CS42L43_HSGND_HS4_SEL_MASK) + +static const struct cs42l43_jack_override_mode { + unsigned int hsdet_mode; + unsigned int mic_ctrl; + unsigned int clamp_ctrl; + int report; +} cs42l43_jack_override_modes[] = { + [CS42L43_JACK_RAW_CTIA] = { + .hsdet_mode = CS42L43_AMP3_4_GNDREF_HS3_SEL_MASK | + CS42L43_HSBIAS_GNDREF_HS3_SEL_MASK | + CS42L43_HSBIAS_OUT_HS4_SEL_MASK | + CS42L43_HSGND_HS3_SEL_MASK, + .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK, + .report = CS42L43_JACK_HEADSET, + }, + [CS42L43_JACK_RAW_OMTP] = { + .hsdet_mode = (0x1 << CS42L43_HSDET_MANUAL_MODE_SHIFT) | + CS42L43_AMP3_4_GNDREF_HS4_SEL_MASK | + CS42L43_HSBIAS_GNDREF_HS4_SEL_MASK | + CS42L43_HSBIAS_OUT_HS3_SEL_MASK | + CS42L43_HSGND_HS4_SEL_MASK, + .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK, + .report = CS42L43_JACK_HEADSET, + }, + [CS42L43_JACK_RAW_HEADPHONE] = { + .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES, + .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK, + .report = CS42L43_JACK_HEADPHONE, + }, + [CS42L43_JACK_RAW_LINE_OUT] = { + .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES, + .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK, + .report = CS42L43_JACK_LINEOUT, + }, + [CS42L43_JACK_RAW_LINE_IN] = { + .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES, + .mic_ctrl = 0x2 << CS42L43_JACK_STEREO_CONFIG_SHIFT, + .report = CS42L43_JACK_LINEIN, + }, + [CS42L43_JACK_RAW_MICROPHONE] = { + .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES, + .mic_ctrl = (0x3 << CS42L43_JACK_STEREO_CONFIG_SHIFT) | + CS42L43_HS1_BIAS_EN_MASK | CS42L43_HS2_BIAS_EN_MASK, + .report = CS42L43_JACK_LINEIN, + }, + [CS42L43_JACK_RAW_OPTICAL] = { + .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES, + .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK, + .report = CS42L43_JACK_OPTICAL, + }, +}; + +static const char * const cs42l43_jack_text[] = { + "None", "CTIA", "OMTP", "Headphone", "Line-Out", + "Line-In", "Microphone", "Optical", +}; + +SOC_ENUM_SINGLE_VIRT_DECL(cs42l43_jack_enum, cs42l43_jack_text); + +int cs42l43_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + + mutex_lock(&priv->jack_lock); + ucontrol->value.integer.value[0] = priv->jack_override; + mutex_unlock(&priv->jack_lock); + + return 0; +} + +int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int override = ucontrol->value.integer.value[0]; + + BUILD_BUG_ON(ARRAY_SIZE(cs42l43_jack_override_modes) != + ARRAY_SIZE(cs42l43_jack_text) - 1); + + if (override >= e->items) + return -EINVAL; + + mutex_lock(&priv->jack_lock); + + if (!cs42l43_jack_present(priv)) { + mutex_unlock(&priv->jack_lock); + return -EBUSY; + } + + if (override == priv->jack_override) { + mutex_unlock(&priv->jack_lock); + return 0; + } + + priv->jack_override = override; + + cs42l43_clear_jack(priv); + + if (!override) { + queue_delayed_work(system_long_wq, &priv->tip_sense_work, 0); + } else { + override--; + + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HSDET_MODE_MASK | + CS42L43_HSDET_MANUAL_MODE_MASK | + CS42L43_AMP3_4_GNDREF_HS3_SEL_MASK | + CS42L43_AMP3_4_GNDREF_HS4_SEL_MASK | + CS42L43_HSBIAS_GNDREF_HS3_SEL_MASK | + CS42L43_HSBIAS_GNDREF_HS4_SEL_MASK | + CS42L43_HSBIAS_OUT_HS3_SEL_MASK | + CS42L43_HSBIAS_OUT_HS4_SEL_MASK | + CS42L43_HSGND_HS3_SEL_MASK | + CS42L43_HSGND_HS4_SEL_MASK, + cs42l43_jack_override_modes[override].hsdet_mode); + regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CTRL, + CS42L43_HS2_BIAS_EN_MASK | CS42L43_HS1_BIAS_EN_MASK | + CS42L43_JACK_STEREO_CONFIG_MASK, + cs42l43_jack_override_modes[override].mic_ctrl); + regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL, + CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK, + cs42l43_jack_override_modes[override].clamp_ctrl); + + switch (override) { + case CS42L43_JACK_RAW_CTIA: + case CS42L43_JACK_RAW_OMTP: + cs42l43_start_hs_bias(priv, false); + cs42l43_start_button_detect(priv); + break; + case CS42L43_JACK_RAW_LINE_IN: + regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL1, + CS42L43_PGA_WIDESWING_MODE_EN_MASK, + CS42L43_PGA_WIDESWING_MODE_EN_MASK); + regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL2, + CS42L43_PGA_WIDESWING_MODE_EN_MASK, + CS42L43_PGA_WIDESWING_MODE_EN_MASK); + break; + case CS42L43_JACK_RAW_MICROPHONE: + cs42l43_start_hs_bias(priv, false); + break; + default: + break; + } + + snd_soc_jack_report(priv->jack_hp, + cs42l43_jack_override_modes[override].report, + cs42l43_jack_override_modes[override].report); + } + + mutex_unlock(&priv->jack_lock); + + return 1; +} diff --git a/sound/soc/codecs/cs42l43-sdw.c b/sound/soc/codecs/cs42l43-sdw.c new file mode 100644 index 000000000000..55ac5fe8c3db --- /dev/null +++ b/sound/soc/codecs/cs42l43-sdw.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// CS42L43 CODEC driver SoundWire handling +// +// Copyright (C) 2022-2023 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cs42l43.h" + +int cs42l43_sdw_add_peripheral(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(dai->component); + struct sdw_stream_runtime *sdw_stream = snd_soc_dai_get_dma_data(dai, substream); + struct sdw_slave *sdw = dev_to_sdw_dev(priv->dev->parent); + struct sdw_stream_config sconfig = {0}; + struct sdw_port_config pconfig = {0}; + int ret; + + if (!sdw_stream) + return -EINVAL; + + snd_sdw_params_to_config(substream, params, &sconfig, &pconfig); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + pconfig.num = dai->id; + else + pconfig.num = dai->id; + + ret = sdw_stream_add_slave(sdw, &sconfig, &pconfig, 1, sdw_stream); + if (ret) { + dev_err(priv->dev, "Failed to add sdw stream: %d\n", ret); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_add_peripheral, SND_SOC_CS42L43); + +int cs42l43_sdw_remove_peripheral(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(dai->component); + struct sdw_stream_runtime *sdw_stream = snd_soc_dai_get_dma_data(dai, substream); + struct sdw_slave *sdw = dev_to_sdw_dev(priv->dev->parent); + + if (!sdw_stream) + return -EINVAL; + + return sdw_stream_remove_slave(sdw, sdw_stream); +} +EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_remove_peripheral, SND_SOC_CS42L43); + +int cs42l43_sdw_set_stream(struct snd_soc_dai *dai, void *sdw_stream, int direction) +{ + snd_soc_dai_dma_data_set(dai, direction, sdw_stream); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_set_stream, SND_SOC_CS42L43); + +MODULE_DESCRIPTION("CS42L43 CODEC SoundWire Driver"); +MODULE_AUTHOR("Charles Keepax "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c new file mode 100644 index 000000000000..55a79219af35 --- /dev/null +++ b/sound/soc/codecs/cs42l43.c @@ -0,0 +1,2278 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// CS42L43 CODEC driver +// +// Copyright (C) 2022-2023 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cs42l43.h" + +#define CS42L43_DECL_MUX(name, reg) \ +static SOC_VALUE_ENUM_SINGLE_DECL(cs42l43_##name##_enum, reg, \ + 0, CS42L43_MIXER_SRC_MASK, \ + cs42l43_mixer_texts, cs42l43_mixer_values); \ +static const struct snd_kcontrol_new cs42l43_##name##_mux = \ + SOC_DAPM_ENUM("Route", cs42l43_##name##_enum) + +#define CS42L43_DECL_MIXER(name, reg) \ + CS42L43_DECL_MUX(name##_in1, reg); \ + CS42L43_DECL_MUX(name##_in2, reg + 0x4); \ + CS42L43_DECL_MUX(name##_in3, reg + 0x8); \ + CS42L43_DECL_MUX(name##_in4, reg + 0xC) + +#define CS42L43_DAPM_MUX(name_str, name) \ + SND_SOC_DAPM_MUX(name_str " Input", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_mux) + +#define CS42L43_DAPM_MIXER(name_str, name) \ + SND_SOC_DAPM_MUX(name_str " Input 1", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_in1_mux), \ + SND_SOC_DAPM_MUX(name_str " Input 2", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_in2_mux), \ + SND_SOC_DAPM_MUX(name_str " Input 3", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_in3_mux), \ + SND_SOC_DAPM_MUX(name_str " Input 4", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_in4_mux), \ + SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0) + +#define CS42L43_BASE_ROUTES(name_str) \ + { name_str, "Tone Generator 1", "Tone 1" }, \ + { name_str, "Tone Generator 2", "Tone 2" }, \ + { name_str, "Decimator 1", "Decimator 1" }, \ + { name_str, "Decimator 2", "Decimator 2" }, \ + { name_str, "Decimator 3", "Decimator 3" }, \ + { name_str, "Decimator 4", "Decimator 4" }, \ + { name_str, "ASPRX1", "ASPRX1" }, \ + { name_str, "ASPRX2", "ASPRX2" }, \ + { name_str, "ASPRX3", "ASPRX3" }, \ + { name_str, "ASPRX4", "ASPRX4" }, \ + { name_str, "ASPRX5", "ASPRX5" }, \ + { name_str, "ASPRX6", "ASPRX6" }, \ + { name_str, "DP5RX1", "DP5RX1" }, \ + { name_str, "DP5RX2", "DP5RX2" }, \ + { name_str, "DP6RX1", "DP6RX1" }, \ + { name_str, "DP6RX2", "DP6RX2" }, \ + { name_str, "DP7RX1", "DP7RX1" }, \ + { name_str, "DP7RX2", "DP7RX2" }, \ + { name_str, "ASRC INT1", "ASRC_INT1" }, \ + { name_str, "ASRC INT2", "ASRC_INT2" }, \ + { name_str, "ASRC INT3", "ASRC_INT3" }, \ + { name_str, "ASRC INT4", "ASRC_INT4" }, \ + { name_str, "ASRC DEC1", "ASRC_DEC1" }, \ + { name_str, "ASRC DEC2", "ASRC_DEC2" }, \ + { name_str, "ASRC DEC3", "ASRC_DEC3" }, \ + { name_str, "ASRC DEC4", "ASRC_DEC4" }, \ + { name_str, "ISRC1 INT1", "ISRC1INT1" }, \ + { name_str, "ISRC1 INT2", "ISRC1INT2" }, \ + { name_str, "ISRC1 DEC1", "ISRC1DEC1" }, \ + { name_str, "ISRC1 DEC2", "ISRC1DEC2" }, \ + { name_str, "ISRC2 INT1", "ISRC2INT1" }, \ + { name_str, "ISRC2 INT2", "ISRC2INT2" }, \ + { name_str, "ISRC2 DEC1", "ISRC2DEC1" }, \ + { name_str, "ISRC2 DEC2", "ISRC2DEC2" }, \ + { name_str, "EQ1", "EQ" }, \ + { name_str, "EQ2", "EQ" } + +#define CS42L43_MUX_ROUTES(name_str, widget) \ + { widget, NULL, name_str " Input" }, \ + { name_str " Input", NULL, "Mixer Core" }, \ + CS42L43_BASE_ROUTES(name_str " Input") + +#define CS42L43_MIXER_ROUTES(name_str, widget) \ + { name_str " Mixer", NULL, name_str " Input 1" }, \ + { name_str " Mixer", NULL, name_str " Input 2" }, \ + { name_str " Mixer", NULL, name_str " Input 3" }, \ + { name_str " Mixer", NULL, name_str " Input 4" }, \ + { widget, NULL, name_str " Mixer" }, \ + { name_str " Mixer", NULL, "Mixer Core" }, \ + CS42L43_BASE_ROUTES(name_str " Input 1"), \ + CS42L43_BASE_ROUTES(name_str " Input 2"), \ + CS42L43_BASE_ROUTES(name_str " Input 3"), \ + CS42L43_BASE_ROUTES(name_str " Input 4") + +#define CS42L43_MIXER_VOLUMES(name_str, base) \ + SOC_SINGLE_RANGE_TLV(name_str " Input 1 Volume", base, \ + CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \ + cs42l43_mixer_tlv), \ + SOC_SINGLE_RANGE_TLV(name_str " Input 2 Volume", base + 4, \ + CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \ + cs42l43_mixer_tlv), \ + SOC_SINGLE_RANGE_TLV(name_str " Input 3 Volume", base + 8, \ + CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \ + cs42l43_mixer_tlv), \ + SOC_SINGLE_RANGE_TLV(name_str " Input 4 Volume", base + 12, \ + CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \ + cs42l43_mixer_tlv) + +#define CS42L43_IRQ_ERROR(name) \ +static irqreturn_t cs42l43_##name(int irq, void *data) \ +{ \ + struct cs42l43_codec *priv = data; \ + dev_err(priv->dev, "Error " #name " IRQ\n"); \ + return IRQ_HANDLED; \ +} + +CS42L43_IRQ_ERROR(pll_lost_lock) +CS42L43_IRQ_ERROR(spkr_clock_stop) +CS42L43_IRQ_ERROR(spkl_clock_stop) +CS42L43_IRQ_ERROR(spkr_brown_out) +CS42L43_IRQ_ERROR(spkl_brown_out) +CS42L43_IRQ_ERROR(spkr_therm_shutdown) +CS42L43_IRQ_ERROR(spkl_therm_shutdown) +CS42L43_IRQ_ERROR(spkr_therm_warm) +CS42L43_IRQ_ERROR(spkl_therm_warm) +CS42L43_IRQ_ERROR(spkr_sc_detect) +CS42L43_IRQ_ERROR(spkl_sc_detect) +CS42L43_IRQ_ERROR(hp_ilimit) + +#define CS42L43_IRQ_COMPLETE(name) \ +static irqreturn_t cs42l43_##name(int irq, void *data) \ +{ \ + struct cs42l43_codec *priv = data; \ + dev_dbg(priv->dev, #name " completed\n"); \ + complete(&priv->name); \ + return IRQ_HANDLED; \ +} + +CS42L43_IRQ_COMPLETE(pll_ready) +CS42L43_IRQ_COMPLETE(hp_startup) +CS42L43_IRQ_COMPLETE(hp_shutdown) +CS42L43_IRQ_COMPLETE(type_detect) +CS42L43_IRQ_COMPLETE(spkr_shutdown) +CS42L43_IRQ_COMPLETE(spkl_shutdown) +CS42L43_IRQ_COMPLETE(spkr_startup) +CS42L43_IRQ_COMPLETE(spkl_startup) +CS42L43_IRQ_COMPLETE(load_detect) + +static irqreturn_t cs42l43_mic_shutter(int irq, void *data) +{ + struct cs42l43_codec *priv = data; + const char * const controls[] = { + "Decimator 1 Switch", + "Decimator 2 Switch", + "Decimator 3 Switch", + "Decimator 4 Switch", + }; + int i, ret; + + dev_dbg(priv->dev, "Microphone shutter changed\n"); + + if (!priv->component) + return IRQ_NONE; + + for (i = 0; i < ARRAY_SIZE(controls); i++) { + ret = snd_soc_component_notify_control(priv->component, + controls[i]); + if (ret) + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + +static irqreturn_t cs42l43_spk_shutter(int irq, void *data) +{ + struct cs42l43_codec *priv = data; + int ret; + + dev_dbg(priv->dev, "Speaker shutter changed\n"); + + if (!priv->component) + return IRQ_NONE; + + ret = snd_soc_component_notify_control(priv->component, + "Speaker Digital Switch"); + if (ret) + return IRQ_NONE; + + return IRQ_HANDLED; +} + +static const unsigned int cs42l43_sample_rates[] = { + 8000, 16000, 24000, 32000, 44100, 48000, 96000, 192000, +}; + +#define CS42L43_CONSUMER_RATE_MASK 0xFF +#define CS42L43_PROVIDER_RATE_MASK 0xEF // 44.1k only supported as consumer + +static const struct snd_pcm_hw_constraint_list cs42l43_constraint = { + .count = ARRAY_SIZE(cs42l43_sample_rates), + .list = cs42l43_sample_rates, +}; + +static int cs42l43_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + int provider = !!regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2, + CS42L43_ASP_MASTER_MODE_MASK); + + if (provider) + priv->constraint.mask = CS42L43_PROVIDER_RATE_MASK; + else + priv->constraint.mask = CS42L43_CONSUMER_RATE_MASK; + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &priv->constraint); +} + +static int cs42l43_convert_sample_rate(unsigned int rate) +{ + switch (rate) { + case 8000: + return 0x11; + case 16000: + return 0x12; + case 24000: + return 0x02; + case 32000: + return 0x13; + case 44100: + return 0x0B; + case 48000: + return 0x03; + case 96000: + return 0x04; + case 192000: + return 0x05; + default: + return -EINVAL; + } +} + +static int cs42l43_set_sample_rate(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(dai->component); + struct cs42l43 *cs42l43 = priv->core; + int ret; + + ret = cs42l43_convert_sample_rate(params_rate(params)); + if (ret < 0) { + dev_err(priv->dev, "Failed to convert sample rate: %d\n", ret); + return ret; + } + + //FIXME: For now lets just set sample rate 1, this needs expanded in the future + regmap_update_bits(cs42l43->regmap, CS42L43_SAMPLE_RATE1, + CS42L43_SAMPLE_RATE_MASK, ret); + + return 0; +} + +static int cs42l43_asp_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(dai->component); + struct cs42l43 *cs42l43 = priv->core; + int dsp_mode = !!regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CTRL, + CS42L43_ASP_FSYNC_MODE_MASK); + int provider = !!regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2, + CS42L43_ASP_MASTER_MODE_MASK); + int n_chans = params_channels(params); + int data_width = params_width(params); + int n_slots = n_chans; + int slot_width = data_width; + int frame, bclk_target, i; + unsigned int reg; + int *slots; + + if (priv->n_slots) { + n_slots = priv->n_slots; + slot_width = priv->slot_width; + } + + if (!dsp_mode && (n_slots & 0x1)) { + dev_dbg(priv->dev, "Forcing balanced channels on ASP\n"); + n_slots++; + } + + frame = n_slots * slot_width; + bclk_target = params_rate(params) * frame; + + if (provider) { + unsigned int gcd_nm = gcd(bclk_target, CS42L43_INTERNAL_SYSCLK); + int n = bclk_target / gcd_nm; + int m = CS42L43_INTERNAL_SYSCLK / gcd_nm; + + if (n > (CS42L43_ASP_BCLK_N_MASK >> CS42L43_ASP_BCLK_N_SHIFT) || + m > CS42L43_ASP_BCLK_M_MASK) { + dev_err(priv->dev, "Can't produce %dHz bclk\n", bclk_target); + return -EINVAL; + } + + dev_dbg(priv->dev, "bclk %d/%d = %dHz, with %dx%d frame\n", + n, m, bclk_target, n_slots, slot_width); + + regmap_update_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG1, + CS42L43_ASP_BCLK_N_MASK | CS42L43_ASP_BCLK_M_MASK, + n << CS42L43_ASP_BCLK_N_SHIFT | + m << CS42L43_ASP_BCLK_M_SHIFT); + regmap_update_bits(cs42l43->regmap, CS42L43_ASP_FSYNC_CTRL1, + CS42L43_ASP_FSYNC_M_MASK, frame); + } + + regmap_update_bits(cs42l43->regmap, CS42L43_ASP_FSYNC_CTRL4, + CS42L43_ASP_NUM_BCLKS_PER_FSYNC_MASK, + frame << CS42L43_ASP_NUM_BCLKS_PER_FSYNC_SHIFT); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + reg = CS42L43_ASP_TX_CH1_CTRL; + slots = priv->tx_slots; + } else { + reg = CS42L43_ASP_RX_CH1_CTRL; + slots = priv->rx_slots; + } + + for (i = 0; i < n_chans; i++, reg += 4) { + int slot_phase = dsp_mode | (i & CS42L43_ASP_CH_SLOT_PHASE_MASK); + int slot_pos; + + if (dsp_mode) + slot_pos = slots[i] * slot_width; + else + slot_pos = (slots[i] / 2) * slot_width; + + dev_dbg(priv->dev, "Configure channel %d at slot %d (%d,%d)\n", + i, slots[i], slot_pos, slot_phase); + + regmap_update_bits(cs42l43->regmap, reg, + CS42L43_ASP_CH_WIDTH_MASK | + CS42L43_ASP_CH_SLOT_MASK | + CS42L43_ASP_CH_SLOT_PHASE_MASK, + ((data_width - 1) << CS42L43_ASP_CH_WIDTH_SHIFT) | + (slot_pos << CS42L43_ASP_CH_SLOT_SHIFT) | + slot_phase); + } + + return cs42l43_set_sample_rate(substream, params, dai); +} + +static int cs42l43_asp_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + int provider = regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2, + CS42L43_ASP_MASTER_MODE_MASK); + struct snd_soc_dapm_route routes[] = { + { "BCLK", NULL, "FSYNC" }, + }; + unsigned int asp_ctrl = 0; + unsigned int data_ctrl = 0; + unsigned int fsync_ctrl = 0; + unsigned int clk_config = 0; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + data_ctrl |= 2 << CS42L43_ASP_FSYNC_FRAME_START_DLY_SHIFT; + fallthrough; + case SND_SOC_DAIFMT_DSP_B: + asp_ctrl |= CS42L43_ASP_FSYNC_MODE_MASK; + data_ctrl |= CS42L43_ASP_FSYNC_FRAME_START_PHASE_MASK; + break; + case SND_SOC_DAIFMT_I2S: + data_ctrl |= 2 << CS42L43_ASP_FSYNC_FRAME_START_DLY_SHIFT; + break; + case SND_SOC_DAIFMT_LEFT_J: + data_ctrl |= CS42L43_ASP_FSYNC_FRAME_START_PHASE_MASK; + break; + default: + dev_err(priv->dev, "Unsupported DAI format 0x%x\n", + fmt & SND_SOC_DAIFMT_FORMAT_MASK); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + if (provider) + snd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes)); + break; + case SND_SOC_DAIFMT_CBP_CFP: + if (!provider) + snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes)); + clk_config |= CS42L43_ASP_MASTER_MODE_MASK; + break; + default: + dev_err(priv->dev, "Unsupported ASP mode 0x%x\n", + fmt & SND_SOC_DAIFMT_MASTER_MASK); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + clk_config |= CS42L43_ASP_BCLK_INV_MASK; /* Yes BCLK_INV = NB */ + break; + case SND_SOC_DAIFMT_IB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + clk_config |= CS42L43_ASP_BCLK_INV_MASK; + fsync_ctrl |= CS42L43_ASP_FSYNC_IN_INV_MASK | + CS42L43_ASP_FSYNC_OUT_INV_MASK; + break; + case SND_SOC_DAIFMT_IB_IF: + fsync_ctrl |= CS42L43_ASP_FSYNC_IN_INV_MASK | + CS42L43_ASP_FSYNC_OUT_INV_MASK; + break; + default: + dev_err(priv->dev, "Unsupported invert mode 0x%x\n", + fmt & SND_SOC_DAIFMT_INV_MASK); + return -EINVAL; + } + + regmap_update_bits(cs42l43->regmap, CS42L43_ASP_CTRL, + CS42L43_ASP_FSYNC_MODE_MASK, + asp_ctrl); + regmap_update_bits(cs42l43->regmap, CS42L43_ASP_DATA_CTRL, + CS42L43_ASP_FSYNC_FRAME_START_DLY_MASK | + CS42L43_ASP_FSYNC_FRAME_START_PHASE_MASK, + data_ctrl); + regmap_update_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2, + CS42L43_ASP_MASTER_MODE_MASK | + CS42L43_ASP_BCLK_INV_MASK, + clk_config); + regmap_update_bits(cs42l43->regmap, CS42L43_ASP_FSYNC_CTRL3, + CS42L43_ASP_FSYNC_IN_INV_MASK | + CS42L43_ASP_FSYNC_OUT_INV_MASK, + fsync_ctrl); + + return 0; +} + +static void cs42l43_mask_to_slots(struct cs42l43_codec *priv, unsigned int mask, int *slots) +{ + int i; + + for (i = 0; i < CS42L43_ASP_MAX_CHANNELS; ++i) { + int slot = ffs(mask) - 1; + + if (slot < 0) + return; + + slots[i] = slot; + + mask &= ~(1 << slot); + } + + if (mask) + dev_warn(priv->dev, "Too many channels in TDM mask\n"); +} + +static int cs42l43_asp_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + + priv->n_slots = slots; + priv->slot_width = slot_width; + + if (!slots) { + tx_mask = CS42L43_DEFAULT_SLOTS; + rx_mask = CS42L43_DEFAULT_SLOTS; + } + + cs42l43_mask_to_slots(priv, tx_mask, priv->tx_slots); + cs42l43_mask_to_slots(priv, rx_mask, priv->rx_slots); + + return 0; +} + +static const struct snd_soc_dai_ops cs42l43_asp_ops = { + .startup = cs42l43_startup, + .hw_params = cs42l43_asp_hw_params, + .set_fmt = cs42l43_asp_set_fmt, + .set_tdm_slot = cs42l43_asp_set_tdm_slot, +}; + +static int cs42l43_sdw_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int ret; + + ret = cs42l43_sdw_add_peripheral(substream, params, dai); + if (ret) + return ret; + + return cs42l43_set_sample_rate(substream, params, dai); +}; + +static const struct snd_soc_dai_ops cs42l43_sdw_ops = { + .startup = cs42l43_startup, + .set_stream = cs42l43_sdw_set_stream, + .hw_params = cs42l43_sdw_hw_params, + .hw_free = cs42l43_sdw_remove_peripheral, +}; + +#define CS42L43_ASP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) +#define CS42L43_SDW_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_driver cs42l43_dais[] = { + { + .name = "cs42l43-asp", + .ops = &cs42l43_asp_ops, + .symmetric_rate = 1, + .capture = { + .stream_name = "ASP Capture", + .channels_min = 1, + .channels_max = CS42L43_ASP_MAX_CHANNELS, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS42L43_ASP_FORMATS, + }, + .playback = { + .stream_name = "ASP Playback", + .channels_min = 1, + .channels_max = CS42L43_ASP_MAX_CHANNELS, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS42L43_ASP_FORMATS, + }, + }, + { + .name = "cs42l43-dp1", + .id = 1, + .ops = &cs42l43_sdw_ops, + .capture = { + .stream_name = "DP1 Capture", + .channels_min = 1, + .channels_max = 4, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS42L43_SDW_FORMATS, + }, + }, + { + .name = "cs42l43-dp2", + .id = 2, + .ops = &cs42l43_sdw_ops, + .capture = { + .stream_name = "DP2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS42L43_SDW_FORMATS, + }, + }, + { + .name = "cs42l43-dp3", + .id = 3, + .ops = &cs42l43_sdw_ops, + .capture = { + .stream_name = "DP3 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS42L43_SDW_FORMATS, + }, + }, + { + .name = "cs42l43-dp4", + .id = 4, + .ops = &cs42l43_sdw_ops, + .capture = { + .stream_name = "DP4 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS42L43_SDW_FORMATS, + }, + }, + { + .name = "cs42l43-dp5", + .id = 5, + .ops = &cs42l43_sdw_ops, + .playback = { + .stream_name = "DP5 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS42L43_SDW_FORMATS, + }, + }, + { + .name = "cs42l43-dp6", + .id = 6, + .ops = &cs42l43_sdw_ops, + .playback = { + .stream_name = "DP6 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS42L43_SDW_FORMATS, + }, + }, + { + .name = "cs42l43-dp7", + .id = 7, + .ops = &cs42l43_sdw_ops, + .playback = { + .stream_name = "DP7 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS42L43_SDW_FORMATS, + }, + }, +}; + +static const DECLARE_TLV_DB_SCALE(cs42l43_mixer_tlv, -3200, 100, 0); + +static const char * const cs42l43_ramp_text[] = { + "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB", + "15ms/6dB", "30ms/6dB", +}; + +static const char * const cs42l43_adc1_input_text[] = { "IN1", "IN2" }; + +static SOC_ENUM_SINGLE_DECL(cs42l43_adc1_input, CS42L43_ADC_B_CTRL1, + CS42L43_ADC_AIN_SEL_SHIFT, + cs42l43_adc1_input_text); + +static const struct snd_kcontrol_new cs42l43_adc1_input_ctl = + SOC_DAPM_ENUM("ADC1 Input", cs42l43_adc1_input); + +static const char * const cs42l43_dec_mode_text[] = { "ADC", "PDM" }; + +static SOC_ENUM_SINGLE_VIRT_DECL(cs42l43_dec1_mode, cs42l43_dec_mode_text); +static SOC_ENUM_SINGLE_VIRT_DECL(cs42l43_dec2_mode, cs42l43_dec_mode_text); + +static const struct snd_kcontrol_new cs42l43_dec_mode_ctl[] = { + SOC_DAPM_ENUM("Decimator 1 Mode", cs42l43_dec1_mode), + SOC_DAPM_ENUM("Decimator 2 Mode", cs42l43_dec2_mode), +}; + +static const char * const cs42l43_pdm_clk_text[] = { + "3.072MHz", "1.536MHz", "768kHz", +}; + +static SOC_ENUM_SINGLE_DECL(cs42l43_pdm1_clk, CS42L43_PDM_CONTROL, + CS42L43_PDM1_CLK_DIV_SHIFT, cs42l43_pdm_clk_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_pdm2_clk, CS42L43_PDM_CONTROL, + CS42L43_PDM2_CLK_DIV_SHIFT, cs42l43_pdm_clk_text); + +static DECLARE_TLV_DB_SCALE(cs42l43_adc_tlv, -600, 600, 0); +static DECLARE_TLV_DB_SCALE(cs42l43_dec_tlv, -6400, 50, 0); + +static const char * const cs42l43_wnf_corner_text[] = { + "160Hz", "180Hz", "200Hz", "220Hz", "240Hz", "260Hz", "280Hz", "300Hz", +}; + +static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL1, + CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL2, + CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL3, + CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL4, + CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text); + +static const char * const cs42l43_hpf_corner_text[] = { + "3Hz", "12Hz", "48Hz", "96Hz", +}; + +static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL1, + CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL2, + CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL3, + CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL4, + CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text); + +static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_ramp_up, CS42L43_DECIM_VOL_CTRL_CH1_CH2, + CS42L43_DECIM1_VI_RAMP_SHIFT, cs42l43_ramp_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_ramp_down, CS42L43_DECIM_VOL_CTRL_CH1_CH2, + CS42L43_DECIM1_VD_RAMP_SHIFT, cs42l43_ramp_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_ramp_up, CS42L43_DECIM_VOL_CTRL_CH1_CH2, + CS42L43_DECIM2_VI_RAMP_SHIFT, cs42l43_ramp_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_ramp_down, CS42L43_DECIM_VOL_CTRL_CH1_CH2, + CS42L43_DECIM2_VD_RAMP_SHIFT, cs42l43_ramp_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_ramp_up, CS42L43_DECIM_VOL_CTRL_CH3_CH4, + CS42L43_DECIM3_VI_RAMP_SHIFT, cs42l43_ramp_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_ramp_down, CS42L43_DECIM_VOL_CTRL_CH3_CH4, + CS42L43_DECIM3_VD_RAMP_SHIFT, cs42l43_ramp_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_ramp_up, CS42L43_DECIM_VOL_CTRL_CH3_CH4, + CS42L43_DECIM4_VI_RAMP_SHIFT, cs42l43_ramp_text); +static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_ramp_down, CS42L43_DECIM_VOL_CTRL_CH3_CH4, + CS42L43_DECIM4_VD_RAMP_SHIFT, cs42l43_ramp_text); + +static DECLARE_TLV_DB_SCALE(cs42l43_speaker_tlv, -6400, 50, 0); + +static SOC_ENUM_SINGLE_DECL(cs42l43_speaker_ramp_up, CS42L43_AMP1_2_VOL_RAMP, + CS42L43_AMP1_2_VI_RAMP_SHIFT, cs42l43_ramp_text); + +static SOC_ENUM_SINGLE_DECL(cs42l43_speaker_ramp_down, CS42L43_AMP1_2_VOL_RAMP, + CS42L43_AMP1_2_VD_RAMP_SHIFT, cs42l43_ramp_text); + +static DECLARE_TLV_DB_SCALE(cs42l43_headphone_tlv, -11450, 50, 1); + +static const char * const cs42l43_headphone_ramp_text[] = { + "1", "2", "4", "6", "8", "11", "12", "16", "22", "24", "33", "36", "44", + "48", "66", "72", +}; + +static SOC_ENUM_SINGLE_DECL(cs42l43_headphone_ramp, CS42L43_PGAVOL, + CS42L43_HP_PATH_VOL_RAMP_SHIFT, + cs42l43_headphone_ramp_text); + +static const char * const cs42l43_tone_freq_text[] = { + "1kHz", "2kHz", "4kHz", "6kHz", "8kHz", +}; + +static SOC_ENUM_SINGLE_DECL(cs42l43_tone1_freq, CS42L43_TONE_CH1_CTRL, + CS42L43_TONE_FREQ_SHIFT, cs42l43_tone_freq_text); + +static SOC_ENUM_SINGLE_DECL(cs42l43_tone2_freq, CS42L43_TONE_CH2_CTRL, + CS42L43_TONE_FREQ_SHIFT, cs42l43_tone_freq_text); + +static const char * const cs42l43_mixer_texts[] = { + "None", + "Tone Generator 1", "Tone Generator 2", + "Decimator 1", "Decimator 2", "Decimator 3", "Decimator 4", + "ASPRX1", "ASPRX2", "ASPRX3", "ASPRX4", "ASPRX5", "ASPRX6", + "DP5RX1", "DP5RX2", "DP6RX1", "DP6RX2", "DP7RX1", "DP7RX2", + "ASRC INT1", "ASRC INT2", "ASRC INT3", "ASRC INT4", + "ASRC DEC1", "ASRC DEC2", "ASRC DEC3", "ASRC DEC4", + "ISRC1 INT1", "ISRC1 INT2", + "ISRC1 DEC1", "ISRC1 DEC2", + "ISRC2 INT1", "ISRC2 INT2", + "ISRC2 DEC1", "ISRC2 DEC2", + "EQ1", "EQ2", +}; + +static const unsigned int cs42l43_mixer_values[] = { + 0x00, // None + 0x04, 0x05, // Tone Generator 1, 2 + 0x10, 0x11, 0x12, 0x13, // Decimator 1, 2, 3, 4 + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, // ASPRX1,2,3,4,5,6 + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, // DP5, 6, 7RX1, 2 + 0x40, 0x41, 0x42, 0x43, // ASRC INT1, 2, 3, 4 + 0x44, 0x45, 0x46, 0x47, // ASRC DEC1, 2, 3, 4 + 0x50, 0x51, // ISRC1 INT1, 2 + 0x52, 0x53, // ISRC1 DEC1, 2 + 0x54, 0x55, // ISRC2 INT1, 2 + 0x56, 0x57, // ISRC2 DEC1, 2 + 0x58, 0x59, // EQ1, 2 +}; + +CS42L43_DECL_MUX(asptx1, CS42L43_ASPTX1_INPUT); +CS42L43_DECL_MUX(asptx2, CS42L43_ASPTX2_INPUT); +CS42L43_DECL_MUX(asptx3, CS42L43_ASPTX3_INPUT); +CS42L43_DECL_MUX(asptx4, CS42L43_ASPTX4_INPUT); +CS42L43_DECL_MUX(asptx5, CS42L43_ASPTX5_INPUT); +CS42L43_DECL_MUX(asptx6, CS42L43_ASPTX6_INPUT); + +CS42L43_DECL_MUX(dp1tx1, CS42L43_SWIRE_DP1_CH1_INPUT); +CS42L43_DECL_MUX(dp1tx2, CS42L43_SWIRE_DP1_CH2_INPUT); +CS42L43_DECL_MUX(dp1tx3, CS42L43_SWIRE_DP1_CH3_INPUT); +CS42L43_DECL_MUX(dp1tx4, CS42L43_SWIRE_DP1_CH4_INPUT); +CS42L43_DECL_MUX(dp2tx1, CS42L43_SWIRE_DP2_CH1_INPUT); +CS42L43_DECL_MUX(dp2tx2, CS42L43_SWIRE_DP2_CH2_INPUT); +CS42L43_DECL_MUX(dp3tx1, CS42L43_SWIRE_DP3_CH1_INPUT); +CS42L43_DECL_MUX(dp3tx2, CS42L43_SWIRE_DP3_CH2_INPUT); +CS42L43_DECL_MUX(dp4tx1, CS42L43_SWIRE_DP4_CH1_INPUT); +CS42L43_DECL_MUX(dp4tx2, CS42L43_SWIRE_DP4_CH2_INPUT); + +CS42L43_DECL_MUX(asrcint1, CS42L43_ASRC_INT1_INPUT1); +CS42L43_DECL_MUX(asrcint2, CS42L43_ASRC_INT2_INPUT1); +CS42L43_DECL_MUX(asrcint3, CS42L43_ASRC_INT3_INPUT1); +CS42L43_DECL_MUX(asrcint4, CS42L43_ASRC_INT4_INPUT1); +CS42L43_DECL_MUX(asrcdec1, CS42L43_ASRC_DEC1_INPUT1); +CS42L43_DECL_MUX(asrcdec2, CS42L43_ASRC_DEC2_INPUT1); +CS42L43_DECL_MUX(asrcdec3, CS42L43_ASRC_DEC3_INPUT1); +CS42L43_DECL_MUX(asrcdec4, CS42L43_ASRC_DEC4_INPUT1); + +CS42L43_DECL_MUX(isrc1int1, CS42L43_ISRC1INT1_INPUT1); +CS42L43_DECL_MUX(isrc1int2, CS42L43_ISRC1INT2_INPUT1); +CS42L43_DECL_MUX(isrc1dec1, CS42L43_ISRC1DEC1_INPUT1); +CS42L43_DECL_MUX(isrc1dec2, CS42L43_ISRC1DEC2_INPUT1); +CS42L43_DECL_MUX(isrc2int1, CS42L43_ISRC2INT1_INPUT1); +CS42L43_DECL_MUX(isrc2int2, CS42L43_ISRC2INT2_INPUT1); +CS42L43_DECL_MUX(isrc2dec1, CS42L43_ISRC2DEC1_INPUT1); +CS42L43_DECL_MUX(isrc2dec2, CS42L43_ISRC2DEC2_INPUT1); + +CS42L43_DECL_MUX(spdif1, CS42L43_SPDIF1_INPUT1); +CS42L43_DECL_MUX(spdif2, CS42L43_SPDIF2_INPUT1); + +CS42L43_DECL_MIXER(eq1, CS42L43_EQ1MIX_INPUT1); +CS42L43_DECL_MIXER(eq2, CS42L43_EQ2MIX_INPUT1); + +CS42L43_DECL_MIXER(amp1, CS42L43_AMP1MIX_INPUT1); +CS42L43_DECL_MIXER(amp2, CS42L43_AMP2MIX_INPUT1); + +CS42L43_DECL_MIXER(amp3, CS42L43_AMP3MIX_INPUT1); +CS42L43_DECL_MIXER(amp4, CS42L43_AMP4MIX_INPUT1); + +static int cs42l43_dapm_get_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + int ret; + + snd_soc_dapm_mutex_lock(dapm); + ret = snd_soc_get_volsw(kcontrol, ucontrol); + snd_soc_dapm_mutex_unlock(dapm); + + return ret; +} + +static int cs42l43_dapm_put_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + int ret; + + snd_soc_dapm_mutex_lock(dapm); + ret = snd_soc_put_volsw(kcontrol, ucontrol); + snd_soc_dapm_mutex_unlock(dapm); + + return ret; +} + +static int cs42l43_dapm_get_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + int ret; + + snd_soc_dapm_mutex_lock(dapm); + ret = snd_soc_get_enum_double(kcontrol, ucontrol); + snd_soc_dapm_mutex_unlock(dapm); + + return ret; +} + +static int cs42l43_dapm_put_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + int ret; + + snd_soc_dapm_mutex_lock(dapm); + ret = snd_soc_put_enum_double(kcontrol, ucontrol); + snd_soc_dapm_mutex_unlock(dapm); + + return ret; +} + +static int cs42l43_eq_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + + memcpy(ucontrol->value.integer.value, priv->eq_coeffs, sizeof(priv->eq_coeffs)); + + return 0; +} + +static int cs42l43_eq_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + + snd_soc_dapm_mutex_lock(dapm); + + memcpy(priv->eq_coeffs, ucontrol->value.integer.value, sizeof(priv->eq_coeffs)); + + snd_soc_dapm_mutex_unlock(dapm); + + return 0; +} + +static void cs42l43_spk_vu_sync(struct cs42l43_codec *priv) +{ + struct cs42l43 *cs42l43 = priv->core; + + mutex_lock(&priv->spk_vu_lock); + + regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1, + CS42L43_AMP1_2_VU_MASK, CS42L43_AMP1_2_VU_MASK); + regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1, + CS42L43_AMP1_2_VU_MASK, 0); + + mutex_unlock(&priv->spk_vu_lock); +} + +static int cs42l43_shutter_get(struct cs42l43_codec *priv, unsigned int shift) +{ + struct cs42l43 *cs42l43 = priv->core; + unsigned int val; + int ret; + + ret = pm_runtime_resume_and_get(priv->dev); + if (ret) { + dev_err(priv->dev, "Failed to resume for shutters: %d\n", ret); + return ret; + } + + /* + * SHUTTER_CONTROL is a mix of volatile and non-volatile bits, so must + * be cached for the non-volatiles, so drop it from the cache here so + * we force a read. + */ + ret = regcache_drop_region(cs42l43->regmap, CS42L43_SHUTTER_CONTROL, + CS42L43_SHUTTER_CONTROL); + if (ret) { + dev_err(priv->dev, "Failed to drop shutter from cache: %d\n", ret); + goto error; + } + + ret = regmap_read(cs42l43->regmap, CS42L43_SHUTTER_CONTROL, &val); + if (ret) { + dev_err(priv->dev, "Failed to check shutter status: %d\n", ret); + goto error; + } + + ret = !(val & BIT(shift)); + + dev_dbg(priv->dev, "%s shutter is %s\n", + BIT(shift) == CS42L43_STATUS_MIC_SHUTTER_MUTE_MASK ? "Mic" : "Speaker", + ret ? "open" : "closed"); + +error: + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); + + return ret; +} + +static int cs42l43_decim_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + int ret; + + ret = cs42l43_shutter_get(priv, CS42L43_STATUS_MIC_SHUTTER_MUTE_SHIFT); + if (ret < 0) + return ret; + else if (!ret) + ucontrol->value.integer.value[0] = ret; + else + ret = cs42l43_dapm_get_volsw(kcontrol, ucontrol); + + return ret; +} + +static int cs42l43_spk_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + int ret; + + ret = cs42l43_shutter_get(priv, CS42L43_STATUS_SPK_SHUTTER_MUTE_SHIFT); + if (ret < 0) + return ret; + else if (!ret) + ucontrol->value.integer.value[0] = ret; + else + ret = snd_soc_get_volsw(kcontrol, ucontrol); + + return ret; +} + +static int cs42l43_spk_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + int ret; + + ret = snd_soc_put_volsw(kcontrol, ucontrol); + if (ret > 0) + cs42l43_spk_vu_sync(priv); + + return ret; +} + +static const struct snd_kcontrol_new cs42l43_controls[] = { + SOC_ENUM_EXT("Jack Override", cs42l43_jack_enum, + cs42l43_jack_get, cs42l43_jack_put), + + SOC_DOUBLE_R_SX_TLV("ADC Volume", CS42L43_ADC_B_CTRL1, CS42L43_ADC_B_CTRL2, + CS42L43_ADC_PGA_GAIN_SHIFT, + 0xF, 5, cs42l43_adc_tlv), + + SOC_DOUBLE("PDM1 Invert Switch", CS42L43_DMIC_PDM_CTRL, + CS42L43_PDM1L_INV_SHIFT, CS42L43_PDM1R_INV_SHIFT, 1, 0), + SOC_DOUBLE("PDM2 Invert Switch", CS42L43_DMIC_PDM_CTRL, + CS42L43_PDM2L_INV_SHIFT, CS42L43_PDM2R_INV_SHIFT, 1, 0), + SOC_ENUM("PDM1 Clock", cs42l43_pdm1_clk), + SOC_ENUM("PDM2 Clock", cs42l43_pdm2_clk), + + SOC_SINGLE("Decimator 1 WNF Switch", CS42L43_DECIM_HPF_WNF_CTRL1, + CS42L43_DECIM_WNF_EN_SHIFT, 1, 0), + SOC_SINGLE("Decimator 2 WNF Switch", CS42L43_DECIM_HPF_WNF_CTRL2, + CS42L43_DECIM_WNF_EN_SHIFT, 1, 0), + SOC_SINGLE("Decimator 3 WNF Switch", CS42L43_DECIM_HPF_WNF_CTRL3, + CS42L43_DECIM_WNF_EN_SHIFT, 1, 0), + SOC_SINGLE("Decimator 4 WNF Switch", CS42L43_DECIM_HPF_WNF_CTRL4, + CS42L43_DECIM_WNF_EN_SHIFT, 1, 0), + + SOC_ENUM("Decimator 1 WNF Corner Frequency", cs42l43_dec1_wnf_corner), + SOC_ENUM("Decimator 2 WNF Corner Frequency", cs42l43_dec2_wnf_corner), + SOC_ENUM("Decimator 3 WNF Corner Frequency", cs42l43_dec3_wnf_corner), + SOC_ENUM("Decimator 4 WNF Corner Frequency", cs42l43_dec4_wnf_corner), + + SOC_SINGLE("Decimator 1 HPF Switch", CS42L43_DECIM_HPF_WNF_CTRL1, + CS42L43_DECIM_HPF_EN_SHIFT, 1, 0), + SOC_SINGLE("Decimator 2 HPF Switch", CS42L43_DECIM_HPF_WNF_CTRL2, + CS42L43_DECIM_HPF_EN_SHIFT, 1, 0), + SOC_SINGLE("Decimator 3 HPF Switch", CS42L43_DECIM_HPF_WNF_CTRL3, + CS42L43_DECIM_HPF_EN_SHIFT, 1, 0), + SOC_SINGLE("Decimator 4 HPF Switch", CS42L43_DECIM_HPF_WNF_CTRL4, + CS42L43_DECIM_HPF_EN_SHIFT, 1, 0), + + SOC_ENUM("Decimator 1 HPF Corner Frequency", cs42l43_dec1_hpf_corner), + SOC_ENUM("Decimator 2 HPF Corner Frequency", cs42l43_dec2_hpf_corner), + SOC_ENUM("Decimator 3 HPF Corner Frequency", cs42l43_dec3_hpf_corner), + SOC_ENUM("Decimator 4 HPF Corner Frequency", cs42l43_dec4_hpf_corner), + + SOC_SINGLE_TLV("Decimator 1 Volume", CS42L43_DECIM_VOL_CTRL_CH1_CH2, + CS42L43_DECIM1_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv), + SOC_SINGLE_EXT("Decimator 1 Switch", CS42L43_DECIM_VOL_CTRL_CH1_CH2, + CS42L43_DECIM1_MUTE_SHIFT, 1, 1, + cs42l43_decim_get, cs42l43_dapm_put_volsw), + SOC_SINGLE_TLV("Decimator 2 Volume", CS42L43_DECIM_VOL_CTRL_CH1_CH2, + CS42L43_DECIM2_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv), + SOC_SINGLE_EXT("Decimator 2 Switch", CS42L43_DECIM_VOL_CTRL_CH1_CH2, + CS42L43_DECIM2_MUTE_SHIFT, 1, 1, + cs42l43_decim_get, cs42l43_dapm_put_volsw), + SOC_SINGLE_TLV("Decimator 3 Volume", CS42L43_DECIM_VOL_CTRL_CH3_CH4, + CS42L43_DECIM3_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv), + SOC_SINGLE_EXT("Decimator 3 Switch", CS42L43_DECIM_VOL_CTRL_CH3_CH4, + CS42L43_DECIM3_MUTE_SHIFT, 1, 1, + cs42l43_decim_get, cs42l43_dapm_put_volsw), + SOC_SINGLE_TLV("Decimator 4 Volume", CS42L43_DECIM_VOL_CTRL_CH3_CH4, + CS42L43_DECIM4_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv), + SOC_SINGLE_EXT("Decimator 4 Switch", CS42L43_DECIM_VOL_CTRL_CH3_CH4, + CS42L43_DECIM4_MUTE_SHIFT, 1, 1, + cs42l43_decim_get, cs42l43_dapm_put_volsw), + + SOC_ENUM_EXT("Decimator 1 Ramp Up", cs42l43_dec1_ramp_up, + cs42l43_dapm_get_enum, cs42l43_dapm_put_enum), + SOC_ENUM_EXT("Decimator 1 Ramp Down", cs42l43_dec1_ramp_down, + cs42l43_dapm_get_enum, cs42l43_dapm_put_enum), + SOC_ENUM_EXT("Decimator 2 Ramp Up", cs42l43_dec2_ramp_up, + cs42l43_dapm_get_enum, cs42l43_dapm_put_enum), + SOC_ENUM_EXT("Decimator 2 Ramp Down", cs42l43_dec2_ramp_down, + cs42l43_dapm_get_enum, cs42l43_dapm_put_enum), + SOC_ENUM_EXT("Decimator 3 Ramp Up", cs42l43_dec3_ramp_up, + cs42l43_dapm_get_enum, cs42l43_dapm_put_enum), + SOC_ENUM_EXT("Decimator 3 Ramp Down", cs42l43_dec3_ramp_down, + cs42l43_dapm_get_enum, cs42l43_dapm_put_enum), + SOC_ENUM_EXT("Decimator 4 Ramp Up", cs42l43_dec4_ramp_up, + cs42l43_dapm_get_enum, cs42l43_dapm_put_enum), + SOC_ENUM_EXT("Decimator 4 Ramp Down", cs42l43_dec4_ramp_down, + cs42l43_dapm_get_enum, cs42l43_dapm_put_enum), + + SOC_DOUBLE_R_EXT("Speaker Digital Switch", + CS42L43_INTP_VOLUME_CTRL1, CS42L43_INTP_VOLUME_CTRL2, + CS42L43_AMP_MUTE_SHIFT, 1, 1, + cs42l43_spk_get, cs42l43_spk_put), + + SOC_DOUBLE_R_EXT_TLV("Speaker Digital Volume", + CS42L43_INTP_VOLUME_CTRL1, CS42L43_INTP_VOLUME_CTRL2, + CS42L43_AMP_VOL_SHIFT, + 0xBF, 0, snd_soc_get_volsw, cs42l43_spk_put, + cs42l43_speaker_tlv), + + SOC_ENUM("Speaker Ramp Up", cs42l43_speaker_ramp_up), + SOC_ENUM("Speaker Ramp Down", cs42l43_speaker_ramp_down), + + CS42L43_MIXER_VOLUMES("Speaker L", CS42L43_AMP1MIX_INPUT1), + CS42L43_MIXER_VOLUMES("Speaker R", CS42L43_AMP2MIX_INPUT1), + + SOC_DOUBLE_SX_TLV("Headphone Digital Volume", CS42L43_HPPATHVOL, + CS42L43_AMP3_PATH_VOL_SHIFT, CS42L43_AMP4_PATH_VOL_SHIFT, + 0x11B, 229, cs42l43_headphone_tlv), + + SOC_DOUBLE("Headphone Invert Switch", CS42L43_DACCNFG1, + CS42L43_AMP3_INV_SHIFT, CS42L43_AMP4_INV_SHIFT, 1, 0), + + SOC_SINGLE("Headphone Zero Cross Switch", CS42L43_PGAVOL, + CS42L43_HP_PATH_VOL_ZC_SHIFT, 1, 0), + SOC_SINGLE("Headphone Ramp Switch", CS42L43_PGAVOL, + CS42L43_HP_PATH_VOL_SFT_SHIFT, 1, 0), + SOC_ENUM("Headphone Ramp Rate", cs42l43_headphone_ramp), + + CS42L43_MIXER_VOLUMES("Headphone L", CS42L43_AMP3MIX_INPUT1), + CS42L43_MIXER_VOLUMES("Headphone R", CS42L43_AMP4MIX_INPUT1), + + SOC_ENUM("Tone 1 Frequency", cs42l43_tone1_freq), + SOC_ENUM("Tone 2 Frequency", cs42l43_tone2_freq), + + SOC_DOUBLE_EXT("EQ Switch", + CS42L43_MUTE_EQ_IN0, CS42L43_MUTE_EQ_CH1_SHIFT, + CS42L43_MUTE_EQ_CH2_SHIFT, 1, 1, + cs42l43_dapm_get_volsw, cs42l43_dapm_put_volsw), + + SND_SOC_BYTES_E("EQ Coefficients", 0, CS42L43_N_EQ_COEFFS, + cs42l43_eq_get, cs42l43_eq_put), + + CS42L43_MIXER_VOLUMES("EQ1", CS42L43_EQ1MIX_INPUT1), + CS42L43_MIXER_VOLUMES("EQ2", CS42L43_EQ2MIX_INPUT1), +}; + +static int cs42l43_eq_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + unsigned int val; + int i, ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_update_bits(cs42l43->regmap, CS42L43_MUTE_EQ_IN0, + CS42L43_MUTE_EQ_CH1_MASK | CS42L43_MUTE_EQ_CH2_MASK, + CS42L43_MUTE_EQ_CH1_MASK | CS42L43_MUTE_EQ_CH2_MASK); + + regmap_update_bits(cs42l43->regmap, CS42L43_COEFF_RD_WR0, + CS42L43_WRITE_MODE_MASK, CS42L43_WRITE_MODE_MASK); + + for (i = 0; i < CS42L43_N_EQ_COEFFS; i++) + regmap_write(cs42l43->regmap, CS42L43_COEFF_DATA_IN0, + priv->eq_coeffs[i]); + + regmap_update_bits(cs42l43->regmap, CS42L43_COEFF_RD_WR0, + CS42L43_WRITE_MODE_MASK, 0); + + return 0; + case SND_SOC_DAPM_POST_PMU: + ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_INIT_DONE0, + val, (val & CS42L43_INITIALIZE_DONE_MASK), + 2000, 10000); + if (ret) + dev_err(priv->dev, "Failed to start EQs: %d\n", ret); + + regmap_update_bits(cs42l43->regmap, CS42L43_MUTE_EQ_IN0, + CS42L43_MUTE_EQ_CH1_MASK | CS42L43_MUTE_EQ_CH2_MASK, 0); + return ret; + default: + return 0; + } +} + +struct cs42l43_pll_config { + unsigned int freq; + + unsigned int div; + unsigned int mode; + unsigned int cal; +}; + +static const struct cs42l43_pll_config cs42l43_pll_configs[] = { + { 2400000, 0x50000000, 0x1, 0xA4 }, + { 3000000, 0x40000000, 0x1, 0x83 }, + { 3072000, 0x40000000, 0x3, 0x80 }, +}; + +static int cs42l43_set_pll(struct cs42l43_codec *priv, unsigned int src, + unsigned int freq) +{ + struct cs42l43 *cs42l43 = priv->core; + + lockdep_assert_held(&cs42l43->pll_lock); + + if (priv->refclk_src == src && priv->refclk_freq == freq) + return 0; + + if (regmap_test_bits(cs42l43->regmap, CS42L43_CTRL_REG, CS42L43_PLL_EN_MASK)) { + dev_err(priv->dev, "PLL active, can't change configuration\n"); + return -EBUSY; + } + + switch (src) { + case CS42L43_SYSCLK_MCLK: + case CS42L43_SYSCLK_SDW: + dev_dbg(priv->dev, "Source PLL from %s at %uHz\n", + src ? "SoundWire" : "MCLK", freq); + + priv->refclk_src = src; + priv->refclk_freq = freq; + + return 0; + default: + dev_err(priv->dev, "Invalid PLL source: 0x%x\n", src); + return -EINVAL; + } +} + +static int cs42l43_enable_pll(struct cs42l43_codec *priv) +{ + static const struct reg_sequence enable_seq[] = { + { CS42L43_OSC_DIV_SEL, 0x0, }, + { CS42L43_MCLK_SRC_SEL, CS42L43_OSC_PLL_MCLK_SEL_MASK, 5, }, + }; + struct cs42l43 *cs42l43 = priv->core; + const struct cs42l43_pll_config *config = NULL; + unsigned int div = 0; + unsigned int freq = priv->refclk_freq; + unsigned long time_left; + + lockdep_assert_held(&cs42l43->pll_lock); + + if (priv->refclk_src == CS42L43_SYSCLK_SDW) { + if (!freq) + freq = cs42l43->sdw_freq; + else if (!cs42l43->sdw_freq) + cs42l43->sdw_freq = freq; + } + + dev_dbg(priv->dev, "Enabling PLL at %uHz\n", freq); + + while (freq > cs42l43_pll_configs[ARRAY_SIZE(cs42l43_pll_configs) - 1].freq) { + div++; + freq /= 2; + } + + if (div <= CS42L43_PLL_REFCLK_DIV_MASK) { + int i; + + for (i = 0; i < ARRAY_SIZE(cs42l43_pll_configs); i++) { + if (freq == cs42l43_pll_configs[i].freq) { + config = &cs42l43_pll_configs[i]; + break; + } + } + } + + if (!config) { + dev_err(priv->dev, "No suitable PLL config: 0x%x, %uHz\n", div, freq); + return -EINVAL; + } + + regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL, + CS42L43_PLL_REFCLK_DIV_MASK | CS42L43_PLL_REFCLK_SRC_MASK, + div << CS42L43_PLL_REFCLK_DIV_SHIFT | + priv->refclk_src << CS42L43_PLL_REFCLK_SRC_SHIFT); + regmap_write(cs42l43->regmap, CS42L43_FDIV_FRAC, config->div); + regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG, + CS42L43_PLL_MODE_BYPASS_500_MASK | + CS42L43_PLL_MODE_BYPASS_1029_MASK, + config->mode << CS42L43_PLL_MODE_BYPASS_1029_SHIFT); + regmap_update_bits(cs42l43->regmap, CS42L43_CAL_RATIO, + CS42L43_PLL_CAL_RATIO_MASK, config->cal); + regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL, + CS42L43_PLL_REFCLK_EN_MASK, CS42L43_PLL_REFCLK_EN_MASK); + + reinit_completion(&priv->pll_ready); + + regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG, + CS42L43_PLL_EN_MASK, CS42L43_PLL_EN_MASK); + + time_left = wait_for_completion_timeout(&priv->pll_ready, + msecs_to_jiffies(CS42L43_PLL_TIMEOUT_MS)); + if (!time_left) { + regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG, + CS42L43_PLL_EN_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL, + CS42L43_PLL_REFCLK_EN_MASK, 0); + + dev_err(priv->dev, "Timeout out waiting for PLL\n"); + return -ETIMEDOUT; + } + + if (priv->refclk_src == CS42L43_SYSCLK_SDW) + cs42l43->sdw_pll_active = true; + + dev_dbg(priv->dev, "PLL locked in %ums\n", 200 - jiffies_to_msecs(time_left)); + + /* + * Reads are not allowed over Soundwire without OSC_DIV2_EN or the PLL, + * but you can not change to PLL with OSC_DIV2_EN set. So ensure the whole + * change over happens under the regmap lock to prevent any reads. + */ + regmap_multi_reg_write(cs42l43->regmap, enable_seq, ARRAY_SIZE(enable_seq)); + + return 0; +} + +static int cs42l43_disable_pll(struct cs42l43_codec *priv) +{ + static const struct reg_sequence disable_seq[] = { + { CS42L43_MCLK_SRC_SEL, 0x0, 5, }, + { CS42L43_OSC_DIV_SEL, CS42L43_OSC_DIV2_EN_MASK, }, + }; + struct cs42l43 *cs42l43 = priv->core; + + dev_dbg(priv->dev, "Disabling PLL\n"); + + lockdep_assert_held(&cs42l43->pll_lock); + + regmap_multi_reg_write(cs42l43->regmap, disable_seq, ARRAY_SIZE(disable_seq)); + regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG, CS42L43_PLL_EN_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL, + CS42L43_PLL_REFCLK_EN_MASK, 0); + + cs42l43->sdw_pll_active = false; + + return 0; +} + +static int cs42l43_pll_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + int ret; + + mutex_lock(&cs42l43->pll_lock); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (priv->refclk_src == CS42L43_SYSCLK_MCLK) { + ret = clk_prepare_enable(priv->mclk); + if (ret) { + dev_err(priv->dev, "Failed to enable MCLK: %d\n", ret); + break; + } + } + + ret = cs42l43_enable_pll(priv); + break; + case SND_SOC_DAPM_POST_PMD: + ret = cs42l43_disable_pll(priv); + + if (priv->refclk_src == CS42L43_SYSCLK_MCLK) + clk_disable_unprepare(priv->mclk); + break; + default: + break; + } + + mutex_unlock(&cs42l43->pll_lock); + + return ret; +} + +static int cs42l43_dapm_wait_completion(struct completion *pmu, struct completion *pmd, + int event, int timeout_ms) +{ + unsigned long time_left; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + reinit_completion(pmu); + return 0; + case SND_SOC_DAPM_PRE_PMD: + reinit_completion(pmd); + return 0; + case SND_SOC_DAPM_POST_PMU: + time_left = wait_for_completion_timeout(pmu, msecs_to_jiffies(timeout_ms)); + break; + case SND_SOC_DAPM_POST_PMD: + time_left = wait_for_completion_timeout(pmd, msecs_to_jiffies(timeout_ms)); + break; + default: + return 0; + } + + if (!time_left) + return -ETIMEDOUT; + else + return 0; +} + +static int cs42l43_spkr_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + + return cs42l43_dapm_wait_completion(&priv->spkr_startup, + &priv->spkr_shutdown, event, + CS42L43_SPK_TIMEOUT_MS); +} + +static int cs42l43_spkl_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + + return cs42l43_dapm_wait_completion(&priv->spkl_startup, + &priv->spkl_shutdown, event, + CS42L43_SPK_TIMEOUT_MS); +} + +static int cs42l43_hp_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + unsigned int mask = 1 << w->shift; + unsigned int val = 0; + int ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + val = mask; + fallthrough; + case SND_SOC_DAPM_PRE_PMD: + priv->hp_ena &= ~mask; + priv->hp_ena |= val; + + ret = cs42l43_dapm_wait_completion(&priv->hp_startup, + &priv->hp_shutdown, event, + CS42L43_HP_TIMEOUT_MS); + if (ret) + return ret; + + if (!priv->load_detect_running) + regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8, + mask, val); + break; + case SND_SOC_DAPM_POST_PMU: + case SND_SOC_DAPM_POST_PMD: + if (priv->load_detect_running) + break; + + ret = cs42l43_dapm_wait_completion(&priv->hp_startup, + &priv->hp_shutdown, event, + CS42L43_HP_TIMEOUT_MS); + if (ret) + return ret; + break; + default: + break; + } + + return 0; +} + +static int cs42l43_mic_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + unsigned int reg, ramp, mute; + unsigned int *val; + int ret; + + switch (w->shift) { + case CS42L43_ADC1_EN_SHIFT: + case CS42L43_PDM1_DIN_L_EN_SHIFT: + reg = CS42L43_DECIM_VOL_CTRL_CH1_CH2; + ramp = CS42L43_DECIM1_VD_RAMP_MASK; + mute = CS42L43_DECIM1_MUTE_MASK; + val = &priv->decim_cache[0]; + break; + case CS42L43_ADC2_EN_SHIFT: + case CS42L43_PDM1_DIN_R_EN_SHIFT: + reg = CS42L43_DECIM_VOL_CTRL_CH1_CH2; + ramp = CS42L43_DECIM2_VD_RAMP_MASK; + mute = CS42L43_DECIM2_MUTE_MASK; + val = &priv->decim_cache[1]; + break; + case CS42L43_PDM2_DIN_L_EN_SHIFT: + reg = CS42L43_DECIM_VOL_CTRL_CH3_CH4; + ramp = CS42L43_DECIM3_VD_RAMP_MASK; + mute = CS42L43_DECIM3_MUTE_MASK; + val = &priv->decim_cache[2]; + break; + case CS42L43_PDM2_DIN_R_EN_SHIFT: + reg = CS42L43_DECIM_VOL_CTRL_CH3_CH4; + ramp = CS42L43_DECIM4_VD_RAMP_MASK; + mute = CS42L43_DECIM4_MUTE_MASK; + val = &priv->decim_cache[3]; + break; + default: + dev_err(priv->dev, "Invalid microphone shift: %d\n", w->shift); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = regmap_read(cs42l43->regmap, reg, val); + if (ret) { + dev_err(priv->dev, + "Failed to cache decimator settings: %d\n", + ret); + return ret; + } + + regmap_update_bits(cs42l43->regmap, reg, mute | ramp, mute); + break; + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(cs42l43->regmap, reg, mute | ramp, *val); + break; + default: + break; + } + + return 0; +} + +static int cs42l43_adc_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + unsigned int mask = 1 << w->shift; + unsigned int val = 0; + int ret; + + ret = cs42l43_mic_ev(w, kcontrol, event); + if (ret) + return ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + val = mask; + fallthrough; + case SND_SOC_DAPM_PRE_PMD: + priv->adc_ena &= ~mask; + priv->adc_ena |= val; + + if (!priv->load_detect_running) + regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3, + mask, val); + fallthrough; + default: + return 0; + } +} + +static const struct snd_soc_dapm_widget cs42l43_widgets[] = { + SND_SOC_DAPM_SUPPLY("PLL", SND_SOC_NOPM, 0, 0, cs42l43_pll_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_INPUT("ADC1_IN1_P"), + SND_SOC_DAPM_INPUT("ADC1_IN1_N"), + SND_SOC_DAPM_INPUT("ADC1_IN2_P"), + SND_SOC_DAPM_INPUT("ADC1_IN2_N"), + SND_SOC_DAPM_INPUT("ADC2_IN_P"), + SND_SOC_DAPM_INPUT("ADC2_IN_N"), + + SND_SOC_DAPM_INPUT("PDM1_DIN"), + SND_SOC_DAPM_INPUT("PDM2_DIN"), + + SND_SOC_DAPM_MUX("ADC1 Input", SND_SOC_NOPM, 0, 0, &cs42l43_adc1_input_ctl), + + SND_SOC_DAPM_PGA_E("ADC1", SND_SOC_NOPM, CS42L43_ADC1_EN_SHIFT, 0, NULL, 0, + cs42l43_adc_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA_E("ADC2", SND_SOC_NOPM, CS42L43_ADC2_EN_SHIFT, 0, NULL, 0, + cs42l43_adc_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_PGA_E("PDM1L", CS42L43_BLOCK_EN3, CS42L43_PDM1_DIN_L_EN_SHIFT, + 0, NULL, 0, cs42l43_mic_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_E("PDM1R", CS42L43_BLOCK_EN3, CS42L43_PDM1_DIN_R_EN_SHIFT, + 0, NULL, 0, cs42l43_mic_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_E("PDM2L", CS42L43_BLOCK_EN3, CS42L43_PDM2_DIN_L_EN_SHIFT, + 0, NULL, 0, cs42l43_mic_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_E("PDM2R", CS42L43_BLOCK_EN3, CS42L43_PDM2_DIN_R_EN_SHIFT, + 0, NULL, 0, cs42l43_mic_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_MUX("Decimator 1 Mode", SND_SOC_NOPM, 0, 0, + &cs42l43_dec_mode_ctl[0]), + SND_SOC_DAPM_MUX("Decimator 2 Mode", SND_SOC_NOPM, 0, 0, + &cs42l43_dec_mode_ctl[1]), + + SND_SOC_DAPM_PGA("Decimator 1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Decimator 2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Decimator 3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Decimator 4", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("FSYNC", 0, CS42L43_ASP_CTRL, CS42L43_ASP_FSYNC_EN_SHIFT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("BCLK", 1, CS42L43_ASP_CTRL, CS42L43_ASP_BCLK_EN_SHIFT, + 0, NULL, 0), + + SND_SOC_DAPM_AIF_OUT("ASPTX1", NULL, 0, + CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH1_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX2", NULL, 1, + CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH2_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX3", NULL, 2, + CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH3_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX4", NULL, 3, + CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH4_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX5", NULL, 4, + CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH5_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX6", NULL, 5, + CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH6_EN_SHIFT, 0), + + SND_SOC_DAPM_AIF_IN("ASPRX1", NULL, 0, + CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH1_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_IN("ASPRX2", NULL, 1, + CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH2_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_IN("ASPRX3", NULL, 2, + CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH3_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_IN("ASPRX4", NULL, 3, + CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH4_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_IN("ASPRX5", NULL, 4, + CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH5_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_IN("ASPRX6", NULL, 5, + CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH6_EN_SHIFT, 0), + + SND_SOC_DAPM_AIF_OUT("DP1TX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP1TX2", NULL, 1, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP1TX3", NULL, 2, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP1TX4", NULL, 3, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_OUT("DP2TX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP2TX2", NULL, 1, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_OUT("DP3TX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP3TX2", NULL, 1, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_OUT("DP4TX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP4TX2", NULL, 1, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("DP5RX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DP5RX2", NULL, 1, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("DP6RX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DP6RX2", NULL, 1, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("DP7RX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DP7RX2", NULL, 1, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_REGULATOR_SUPPLY("vdd-amp", 0, 0), + + SND_SOC_DAPM_PGA_E("AMP1", CS42L43_BLOCK_EN10, CS42L43_AMP1_EN_SHIFT, 0, NULL, 0, + cs42l43_spkl_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("AMP2", CS42L43_BLOCK_EN10, CS42L43_AMP2_EN_SHIFT, 0, NULL, 0, + cs42l43_spkr_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_OUTPUT("AMP1_OUT_P"), + SND_SOC_DAPM_OUTPUT("AMP1_OUT_N"), + SND_SOC_DAPM_OUTPUT("AMP2_OUT_P"), + SND_SOC_DAPM_OUTPUT("AMP2_OUT_N"), + + SND_SOC_DAPM_PGA("SPDIF", CS42L43_BLOCK_EN11, CS42L43_SPDIF_EN_SHIFT, + 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("SPDIF_TX"), + + SND_SOC_DAPM_PGA_E("HP", SND_SOC_NOPM, CS42L43_HP_EN_SHIFT, 0, NULL, 0, + cs42l43_hp_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_OUTPUT("AMP3_OUT"), + SND_SOC_DAPM_OUTPUT("AMP4_OUT"), + + SND_SOC_DAPM_SIGGEN("Tone"), + SND_SOC_DAPM_SUPPLY("Tone Generator", CS42L43_BLOCK_EN9, CS42L43_TONE_EN_SHIFT, + 0, NULL, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Tone 1", CS42L43_TONE_CH1_CTRL, + CS42L43_TONE_SEL_SHIFT, CS42L43_TONE_SEL_MASK, 0xA, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Tone 2", CS42L43_TONE_CH2_CTRL, + CS42L43_TONE_SEL_SHIFT, CS42L43_TONE_SEL_MASK, 0xA, 0), + + SND_SOC_DAPM_SUPPLY("ISRC1", CS42L43_BLOCK_EN5, CS42L43_ISRC1_BANK_EN_SHIFT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ISRC2", CS42L43_BLOCK_EN5, CS42L43_ISRC2_BANK_EN_SHIFT, + 0, NULL, 0), + + SND_SOC_DAPM_PGA("ISRC1INT2", CS42L43_ISRC1_CTRL, + CS42L43_ISRC_INT2_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ISRC1INT1", CS42L43_ISRC1_CTRL, + CS42L43_ISRC_INT1_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ISRC1DEC2", CS42L43_ISRC1_CTRL, + CS42L43_ISRC_DEC2_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ISRC1DEC1", CS42L43_ISRC1_CTRL, + CS42L43_ISRC_DEC1_EN_SHIFT, 0, NULL, 0), + + SND_SOC_DAPM_PGA("ISRC2INT2", CS42L43_ISRC2_CTRL, + CS42L43_ISRC_INT2_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ISRC2INT1", CS42L43_ISRC2_CTRL, + CS42L43_ISRC_INT1_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ISRC2DEC2", CS42L43_ISRC2_CTRL, + CS42L43_ISRC_DEC2_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ISRC2DEC1", CS42L43_ISRC2_CTRL, + CS42L43_ISRC_DEC1_EN_SHIFT, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("ASRC_INT", CS42L43_BLOCK_EN4, + CS42L43_ASRC_INT_BANK_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ASRC_DEC", CS42L43_BLOCK_EN4, + CS42L43_ASRC_DEC_BANK_EN_SHIFT, 0, NULL, 0), + + SND_SOC_DAPM_PGA("ASRC_INT1", CS42L43_ASRC_INT_ENABLES, + CS42L43_ASRC_INT1_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ASRC_INT2", CS42L43_ASRC_INT_ENABLES, + CS42L43_ASRC_INT2_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ASRC_INT3", CS42L43_ASRC_INT_ENABLES, + CS42L43_ASRC_INT3_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ASRC_INT4", CS42L43_ASRC_INT_ENABLES, + CS42L43_ASRC_INT4_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ASRC_DEC1", CS42L43_ASRC_DEC_ENABLES, + CS42L43_ASRC_DEC1_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ASRC_DEC2", CS42L43_ASRC_DEC_ENABLES, + CS42L43_ASRC_DEC2_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ASRC_DEC3", CS42L43_ASRC_DEC_ENABLES, + CS42L43_ASRC_DEC3_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("ASRC_DEC4", CS42L43_ASRC_DEC_ENABLES, + CS42L43_ASRC_DEC4_EN_SHIFT, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("EQ Clock", CS42L43_BLOCK_EN7, CS42L43_EQ_EN_SHIFT, + 0, NULL, 0), + SND_SOC_DAPM_PGA_E("EQ", CS42L43_START_EQZ0, CS42L43_START_FILTER_SHIFT, + 0, NULL, 0, cs42l43_eq_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_SUPPLY("Mixer Core", CS42L43_BLOCK_EN6, CS42L43_MIXER_EN_SHIFT, + 0, NULL, 0), + CS42L43_DAPM_MUX("ASPTX1", asptx1), + CS42L43_DAPM_MUX("ASPTX2", asptx2), + CS42L43_DAPM_MUX("ASPTX3", asptx3), + CS42L43_DAPM_MUX("ASPTX4", asptx4), + CS42L43_DAPM_MUX("ASPTX5", asptx5), + CS42L43_DAPM_MUX("ASPTX6", asptx6), + + CS42L43_DAPM_MUX("DP1TX1", dp1tx1), + CS42L43_DAPM_MUX("DP1TX2", dp1tx2), + CS42L43_DAPM_MUX("DP1TX3", dp1tx3), + CS42L43_DAPM_MUX("DP1TX4", dp1tx4), + CS42L43_DAPM_MUX("DP2TX1", dp2tx1), + CS42L43_DAPM_MUX("DP2TX2", dp2tx2), + CS42L43_DAPM_MUX("DP3TX1", dp3tx1), + CS42L43_DAPM_MUX("DP3TX2", dp3tx2), + CS42L43_DAPM_MUX("DP4TX1", dp4tx1), + CS42L43_DAPM_MUX("DP4TX2", dp4tx2), + + CS42L43_DAPM_MUX("ASRC INT1", asrcint1), + CS42L43_DAPM_MUX("ASRC INT2", asrcint2), + CS42L43_DAPM_MUX("ASRC INT3", asrcint3), + CS42L43_DAPM_MUX("ASRC INT4", asrcint4), + CS42L43_DAPM_MUX("ASRC DEC1", asrcdec1), + CS42L43_DAPM_MUX("ASRC DEC2", asrcdec2), + CS42L43_DAPM_MUX("ASRC DEC3", asrcdec3), + CS42L43_DAPM_MUX("ASRC DEC4", asrcdec4), + + CS42L43_DAPM_MUX("ISRC1INT1", isrc1int1), + CS42L43_DAPM_MUX("ISRC1INT2", isrc1int2), + CS42L43_DAPM_MUX("ISRC1DEC1", isrc1dec1), + CS42L43_DAPM_MUX("ISRC1DEC2", isrc1dec2), + CS42L43_DAPM_MUX("ISRC2INT1", isrc2int1), + CS42L43_DAPM_MUX("ISRC2INT2", isrc2int2), + CS42L43_DAPM_MUX("ISRC2DEC1", isrc2dec1), + CS42L43_DAPM_MUX("ISRC2DEC2", isrc2dec2), + + CS42L43_DAPM_MUX("SPDIF1", spdif1), + CS42L43_DAPM_MUX("SPDIF2", spdif2), + + CS42L43_DAPM_MIXER("EQ1", eq1), + CS42L43_DAPM_MIXER("EQ2", eq2), + + CS42L43_DAPM_MIXER("Speaker L", amp1), + CS42L43_DAPM_MIXER("Speaker R", amp2), + + CS42L43_DAPM_MIXER("Headphone L", amp3), + CS42L43_DAPM_MIXER("Headphone R", amp4), +}; + +static const struct snd_soc_dapm_route cs42l43_routes[] = { + { "ADC1_IN1_P", NULL, "PLL" }, + { "ADC1_IN1_N", NULL, "PLL" }, + { "ADC1_IN2_P", NULL, "PLL" }, + { "ADC1_IN2_N", NULL, "PLL" }, + { "ADC2_IN_P", NULL, "PLL" }, + { "ADC2_IN_N", NULL, "PLL" }, + { "PDM1_DIN", NULL, "PLL" }, + { "PDM2_DIN", NULL, "PLL" }, + { "AMP1_OUT_P", NULL, "PLL" }, + { "AMP1_OUT_N", NULL, "PLL" }, + { "AMP2_OUT_P", NULL, "PLL" }, + { "AMP2_OUT_N", NULL, "PLL" }, + { "SPDIF_TX", NULL, "PLL" }, + { "HP", NULL, "PLL" }, + { "AMP3_OUT", NULL, "PLL" }, + { "AMP4_OUT", NULL, "PLL" }, + { "Tone 1", NULL, "PLL" }, + { "Tone 2", NULL, "PLL" }, + { "ASP Playback", NULL, "PLL" }, + { "ASP Capture", NULL, "PLL" }, + { "DP1 Capture", NULL, "PLL" }, + { "DP2 Capture", NULL, "PLL" }, + { "DP3 Capture", NULL, "PLL" }, + { "DP4 Capture", NULL, "PLL" }, + { "DP5 Playback", NULL, "PLL" }, + { "DP6 Playback", NULL, "PLL" }, + { "DP7 Playback", NULL, "PLL" }, + + { "ADC1 Input", "IN1", "ADC1_IN1_P" }, + { "ADC1 Input", "IN1", "ADC1_IN1_N" }, + { "ADC1 Input", "IN2", "ADC1_IN2_P" }, + { "ADC1 Input", "IN2", "ADC1_IN2_N" }, + + { "ADC1", NULL, "ADC1 Input" }, + { "ADC2", NULL, "ADC2_IN_P" }, + { "ADC2", NULL, "ADC2_IN_N" }, + + { "PDM1L", NULL, "PDM1_DIN" }, + { "PDM1R", NULL, "PDM1_DIN" }, + { "PDM2L", NULL, "PDM2_DIN" }, + { "PDM2R", NULL, "PDM2_DIN" }, + + { "Decimator 1 Mode", "PDM", "PDM1L" }, + { "Decimator 1 Mode", "ADC", "ADC1" }, + { "Decimator 2 Mode", "PDM", "PDM1R" }, + { "Decimator 2 Mode", "ADC", "ADC2" }, + + { "Decimator 1", NULL, "Decimator 1 Mode" }, + { "Decimator 2", NULL, "Decimator 2 Mode" }, + { "Decimator 3", NULL, "PDM2L" }, + { "Decimator 4", NULL, "PDM2R" }, + + { "ASP Capture", NULL, "ASPTX1" }, + { "ASP Capture", NULL, "ASPTX2" }, + { "ASP Capture", NULL, "ASPTX3" }, + { "ASP Capture", NULL, "ASPTX4" }, + { "ASP Capture", NULL, "ASPTX5" }, + { "ASP Capture", NULL, "ASPTX6" }, + { "ASPTX1", NULL, "BCLK" }, + { "ASPTX2", NULL, "BCLK" }, + { "ASPTX3", NULL, "BCLK" }, + { "ASPTX4", NULL, "BCLK" }, + { "ASPTX5", NULL, "BCLK" }, + { "ASPTX6", NULL, "BCLK" }, + + { "ASPRX1", NULL, "ASP Playback" }, + { "ASPRX2", NULL, "ASP Playback" }, + { "ASPRX3", NULL, "ASP Playback" }, + { "ASPRX4", NULL, "ASP Playback" }, + { "ASPRX5", NULL, "ASP Playback" }, + { "ASPRX6", NULL, "ASP Playback" }, + { "ASPRX1", NULL, "BCLK" }, + { "ASPRX2", NULL, "BCLK" }, + { "ASPRX3", NULL, "BCLK" }, + { "ASPRX4", NULL, "BCLK" }, + { "ASPRX5", NULL, "BCLK" }, + { "ASPRX6", NULL, "BCLK" }, + + { "DP1 Capture", NULL, "DP1TX1" }, + { "DP1 Capture", NULL, "DP1TX2" }, + { "DP1 Capture", NULL, "DP1TX3" }, + { "DP1 Capture", NULL, "DP1TX4" }, + + { "DP2 Capture", NULL, "DP2TX1" }, + { "DP2 Capture", NULL, "DP2TX2" }, + + { "DP3 Capture", NULL, "DP3TX1" }, + { "DP3 Capture", NULL, "DP3TX2" }, + + { "DP4 Capture", NULL, "DP4TX1" }, + { "DP4 Capture", NULL, "DP4TX2" }, + + { "DP5RX1", NULL, "DP5 Playback" }, + { "DP5RX2", NULL, "DP5 Playback" }, + + { "DP6RX1", NULL, "DP6 Playback" }, + { "DP6RX2", NULL, "DP6 Playback" }, + + { "DP7RX1", NULL, "DP7 Playback" }, + { "DP7RX2", NULL, "DP7 Playback" }, + + { "AMP1", NULL, "vdd-amp" }, + { "AMP2", NULL, "vdd-amp" }, + + { "AMP1_OUT_P", NULL, "AMP1" }, + { "AMP1_OUT_N", NULL, "AMP1" }, + { "AMP2_OUT_P", NULL, "AMP2" }, + { "AMP2_OUT_N", NULL, "AMP2" }, + + { "SPDIF_TX", NULL, "SPDIF" }, + + { "AMP3_OUT", NULL, "HP" }, + { "AMP4_OUT", NULL, "HP" }, + + { "Tone 1", NULL, "Tone" }, + { "Tone 1", NULL, "Tone Generator" }, + { "Tone 2", NULL, "Tone" }, + { "Tone 2", NULL, "Tone Generator" }, + + { "ISRC1INT2", NULL, "ISRC1" }, + { "ISRC1INT1", NULL, "ISRC1" }, + { "ISRC1DEC2", NULL, "ISRC1" }, + { "ISRC1DEC1", NULL, "ISRC1" }, + + { "ISRC2INT2", NULL, "ISRC2" }, + { "ISRC2INT1", NULL, "ISRC2" }, + { "ISRC2DEC2", NULL, "ISRC2" }, + { "ISRC2DEC1", NULL, "ISRC2" }, + + { "ASRC_INT1", NULL, "ASRC_INT" }, + { "ASRC_INT2", NULL, "ASRC_INT" }, + { "ASRC_INT3", NULL, "ASRC_INT" }, + { "ASRC_INT4", NULL, "ASRC_INT" }, + { "ASRC_DEC1", NULL, "ASRC_DEC" }, + { "ASRC_DEC2", NULL, "ASRC_DEC" }, + { "ASRC_DEC3", NULL, "ASRC_DEC" }, + { "ASRC_DEC4", NULL, "ASRC_DEC" }, + + { "EQ", NULL, "EQ Clock" }, + + CS42L43_MUX_ROUTES("ASPTX1", "ASPTX1"), + CS42L43_MUX_ROUTES("ASPTX2", "ASPTX2"), + CS42L43_MUX_ROUTES("ASPTX3", "ASPTX3"), + CS42L43_MUX_ROUTES("ASPTX4", "ASPTX4"), + CS42L43_MUX_ROUTES("ASPTX5", "ASPTX5"), + CS42L43_MUX_ROUTES("ASPTX6", "ASPTX6"), + + CS42L43_MUX_ROUTES("DP1TX1", "DP1TX1"), + CS42L43_MUX_ROUTES("DP1TX2", "DP1TX2"), + CS42L43_MUX_ROUTES("DP1TX3", "DP1TX3"), + CS42L43_MUX_ROUTES("DP1TX4", "DP1TX4"), + CS42L43_MUX_ROUTES("DP2TX1", "DP2TX1"), + CS42L43_MUX_ROUTES("DP2TX2", "DP2TX2"), + CS42L43_MUX_ROUTES("DP3TX1", "DP3TX1"), + CS42L43_MUX_ROUTES("DP3TX2", "DP3TX2"), + CS42L43_MUX_ROUTES("DP4TX1", "DP4TX1"), + CS42L43_MUX_ROUTES("DP4TX2", "DP4TX2"), + + CS42L43_MUX_ROUTES("ASRC INT1", "ASRC_INT1"), + CS42L43_MUX_ROUTES("ASRC INT2", "ASRC_INT2"), + CS42L43_MUX_ROUTES("ASRC INT3", "ASRC_INT3"), + CS42L43_MUX_ROUTES("ASRC INT4", "ASRC_INT4"), + CS42L43_MUX_ROUTES("ASRC DEC1", "ASRC_DEC1"), + CS42L43_MUX_ROUTES("ASRC DEC2", "ASRC_DEC2"), + CS42L43_MUX_ROUTES("ASRC DEC3", "ASRC_DEC3"), + CS42L43_MUX_ROUTES("ASRC DEC4", "ASRC_DEC4"), + + CS42L43_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"), + CS42L43_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"), + CS42L43_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"), + CS42L43_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"), + CS42L43_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"), + CS42L43_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"), + CS42L43_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"), + CS42L43_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"), + + CS42L43_MUX_ROUTES("SPDIF1", "SPDIF"), + CS42L43_MUX_ROUTES("SPDIF2", "SPDIF"), + + CS42L43_MIXER_ROUTES("EQ1", "EQ"), + CS42L43_MIXER_ROUTES("EQ2", "EQ"), + + CS42L43_MIXER_ROUTES("Speaker L", "AMP1"), + CS42L43_MIXER_ROUTES("Speaker R", "AMP2"), + + CS42L43_MIXER_ROUTES("Headphone L", "HP"), + CS42L43_MIXER_ROUTES("Headphone R", "HP"), +}; + +static int cs42l43_set_sysclk(struct snd_soc_component *component, int clk_id, + int src, unsigned int freq, int dir) +{ + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + int ret; + + mutex_lock(&cs42l43->pll_lock); + ret = cs42l43_set_pll(priv, src, freq); + mutex_unlock(&cs42l43->pll_lock); + + return ret; +} + +static int cs42l43_component_probe(struct snd_soc_component *component) +{ + struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); + struct cs42l43 *cs42l43 = priv->core; + + snd_soc_component_init_regmap(component, cs42l43->regmap); + + cs42l43_mask_to_slots(priv, CS42L43_DEFAULT_SLOTS, priv->tx_slots); + cs42l43_mask_to_slots(priv, CS42L43_DEFAULT_SLOTS, priv->rx_slots); + + priv->component = component; + priv->constraint = cs42l43_constraint; + + return 0; +} + +static const struct snd_soc_component_driver cs42l43_component_drv = { + .name = "cs42l43-codec", + + .probe = cs42l43_component_probe, + .set_sysclk = cs42l43_set_sysclk, + .set_jack = cs42l43_set_jack, + + .endianness = 1, + + .controls = cs42l43_controls, + .num_controls = ARRAY_SIZE(cs42l43_controls), + .dapm_widgets = cs42l43_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs42l43_widgets), + .dapm_routes = cs42l43_routes, + .num_dapm_routes = ARRAY_SIZE(cs42l43_routes), +}; + +struct cs42l43_irq { + unsigned int irq; + const char *name; + irq_handler_t handler; +}; + +static const struct cs42l43_irq cs42l43_irqs[] = { + { CS42L43_PLL_LOST_LOCK, "pll lost lock", cs42l43_pll_lost_lock }, + { CS42L43_PLL_READY, "pll ready", cs42l43_pll_ready }, + { CS42L43_HP_STARTUP_DONE, "hp startup", cs42l43_hp_startup }, + { CS42L43_HP_SHUTDOWN_DONE, "hp shutdown", cs42l43_hp_shutdown }, + { CS42L43_HSDET_DONE, "type detect", cs42l43_type_detect }, + { CS42L43_TIPSENSE_UNPLUG_PDET, "tip sense unplug", cs42l43_tip_sense }, + { CS42L43_TIPSENSE_PLUG_PDET, "tip sense plug", cs42l43_tip_sense }, + { CS42L43_DC_DETECT1_TRUE, "button press", cs42l43_button_press }, + { CS42L43_DC_DETECT1_FALSE, "button release", cs42l43_button_release }, + { CS42L43_HSBIAS_CLAMPED, "hsbias detect clamp", cs42l43_bias_detect_clamp }, + { CS42L43_AMP2_CLK_STOP_FAULT, "spkr clock stop", cs42l43_spkr_clock_stop }, + { CS42L43_AMP1_CLK_STOP_FAULT, "spkl clock stop", cs42l43_spkl_clock_stop }, + { CS42L43_AMP2_VDDSPK_FAULT, "spkr brown out", cs42l43_spkr_brown_out }, + { CS42L43_AMP1_VDDSPK_FAULT, "spkl brown out", cs42l43_spkl_brown_out }, + { CS42L43_AMP2_SHUTDOWN_DONE, "spkr shutdown", cs42l43_spkr_shutdown }, + { CS42L43_AMP1_SHUTDOWN_DONE, "spkl shutdown", cs42l43_spkl_shutdown }, + { CS42L43_AMP2_STARTUP_DONE, "spkr startup", cs42l43_spkr_startup }, + { CS42L43_AMP1_STARTUP_DONE, "spkl startup", cs42l43_spkl_startup }, + { CS42L43_AMP2_THERM_SHDN, "spkr thermal shutdown", cs42l43_spkr_therm_shutdown }, + { CS42L43_AMP1_THERM_SHDN, "spkl thermal shutdown", cs42l43_spkl_therm_shutdown }, + { CS42L43_AMP2_THERM_WARN, "spkr thermal warning", cs42l43_spkr_therm_warm }, + { CS42L43_AMP1_THERM_WARN, "spkl thermal warning", cs42l43_spkl_therm_warm }, + { CS42L43_AMP2_SCDET, "spkr short circuit", cs42l43_spkr_sc_detect }, + { CS42L43_AMP1_SCDET, "spkl short circuit", cs42l43_spkl_sc_detect }, + { CS42L43_HP_ILIMIT, "hp ilimit", cs42l43_hp_ilimit }, + { CS42L43_HP_LOADDET_DONE, "load detect done", cs42l43_load_detect }, +}; + +static int cs42l43_request_irq(struct cs42l43_codec *priv, + struct irq_domain *dom, const char * const name, + unsigned int irq, irq_handler_t handler) +{ + int ret; + + ret = irq_create_mapping(dom, irq); + if (ret < 0) + return dev_err_probe(priv->dev, ret, "Failed to map IRQ %s\n", name); + + dev_dbg(priv->dev, "Request IRQ %d for %s\n", ret, name); + + ret = devm_request_threaded_irq(priv->dev, ret, NULL, handler, IRQF_ONESHOT, + name, priv); + if (ret) + return dev_err_probe(priv->dev, ret, "Failed to request IRQ %s\n", name); + + return 0; +} + +static int cs42l43_shutter_irq(struct cs42l43_codec *priv, + struct irq_domain *dom, unsigned int shutter, + const char * const open_name, + const char * const close_name, + irq_handler_t handler) +{ + unsigned int open_irq, close_irq; + int ret; + + switch (shutter) { + case 0x1: + dev_warn(priv->dev, "Manual shutters, notifications not available\n"); + return 0; + case 0x2: + open_irq = CS42L43_GPIO1_RISE; + close_irq = CS42L43_GPIO1_FALL; + break; + case 0x4: + open_irq = CS42L43_GPIO2_RISE; + close_irq = CS42L43_GPIO2_FALL; + break; + case 0x8: + open_irq = CS42L43_GPIO3_RISE; + close_irq = CS42L43_GPIO3_FALL; + break; + default: + return 0; + } + + ret = cs42l43_request_irq(priv, dom, close_name, close_irq, handler); + if (ret) + return ret; + + return cs42l43_request_irq(priv, dom, open_name, open_irq, handler); +} + +static int cs42l43_codec_probe(struct platform_device *pdev) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent); + struct cs42l43_codec *priv; + struct irq_domain *dom; + unsigned int val; + int i, ret; + + dom = irq_find_matching_fwnode(dev_fwnode(cs42l43->dev), DOMAIN_BUS_ANY); + if (!dom) + return -EPROBE_DEFER; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + priv->core = cs42l43; + + platform_set_drvdata(pdev, priv); + + mutex_init(&priv->jack_lock); + mutex_init(&priv->spk_vu_lock); + + init_completion(&priv->hp_startup); + init_completion(&priv->hp_shutdown); + init_completion(&priv->spkr_shutdown); + init_completion(&priv->spkl_shutdown); + init_completion(&priv->spkr_startup); + init_completion(&priv->spkl_startup); + init_completion(&priv->pll_ready); + init_completion(&priv->type_detect); + init_completion(&priv->load_detect); + + INIT_DELAYED_WORK(&priv->tip_sense_work, cs42l43_tip_sense_work); + INIT_DELAYED_WORK(&priv->bias_sense_timeout, cs42l43_bias_sense_timeout); + INIT_DELAYED_WORK(&priv->button_press_work, cs42l43_button_press_work); + INIT_WORK(&priv->button_release_work, cs42l43_button_release_work); + + pm_runtime_set_autosuspend_delay(priv->dev, 100); + pm_runtime_use_autosuspend(priv->dev); + pm_runtime_set_active(priv->dev); + pm_runtime_get_noresume(priv->dev); + devm_pm_runtime_enable(priv->dev); + + for (i = 0; i < ARRAY_SIZE(cs42l43_irqs); i++) { + ret = cs42l43_request_irq(priv, dom, cs42l43_irqs[i].name, + cs42l43_irqs[i].irq, cs42l43_irqs[i].handler); + if (ret) + goto err_pm; + } + + ret = regmap_read(cs42l43->regmap, CS42L43_SHUTTER_CONTROL, &val); + if (ret) { + dev_err(priv->dev, "Failed to check shutter source: %d\n", ret); + goto err_pm; + } + + ret = cs42l43_shutter_irq(priv, dom, val & CS42L43_MIC_SHUTTER_CFG_MASK, + "mic shutter open", "mic shutter close", + cs42l43_mic_shutter); + if (ret) + goto err_pm; + + ret = cs42l43_shutter_irq(priv, dom, (val & CS42L43_SPK_SHUTTER_CFG_MASK) >> + CS42L43_SPK_SHUTTER_CFG_SHIFT, + "spk shutter open", "spk shutter close", + cs42l43_spk_shutter); + if (ret) + goto err_pm; + + // Don't use devm as we need to get against the MFD device + priv->mclk = clk_get_optional(cs42l43->dev, "mclk"); + if (IS_ERR(priv->mclk)) { + dev_err_probe(priv->dev, PTR_ERR(priv->mclk), "Failed to get mclk\n"); + goto err_pm; + } + + ret = devm_snd_soc_register_component(priv->dev, &cs42l43_component_drv, + cs42l43_dais, ARRAY_SIZE(cs42l43_dais)); + if (ret) { + dev_err_probe(priv->dev, ret, "Failed to register component\n"); + goto err_clk; + } + + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); + + return 0; + +err_clk: + clk_put(priv->mclk); +err_pm: + pm_runtime_put_sync(priv->dev); + + return ret; +} + +static int cs42l43_codec_remove(struct platform_device *pdev) +{ + struct cs42l43_codec *priv = platform_get_drvdata(pdev); + + clk_put(priv->mclk); + + return 0; +} + +static int __maybe_unused cs42l43_codec_runtime_resume(struct device *dev) +{ + struct cs42l43_codec *priv = dev_get_drvdata(dev); + + dev_dbg(priv->dev, "Runtime resume\n"); + + // Toggle the speaker volume update incase the speaker volume was synced + cs42l43_spk_vu_sync(priv); + + return 0; +} + +static const struct dev_pm_ops cs42l43_codec_pm_ops = { + SET_RUNTIME_PM_OPS(NULL, cs42l43_codec_runtime_resume, NULL) +}; + +static const struct platform_device_id cs42l43_codec_id_table[] = { + { "cs42l43-codec", }, + {} +}; +MODULE_DEVICE_TABLE(platform, cs42l43_codec_id_table); + +static struct platform_driver cs42l43_codec_driver = { + .driver = { + .name = "cs42l43-codec", + .pm = &cs42l43_codec_pm_ops, + }, + + .probe = cs42l43_codec_probe, + .remove = cs42l43_codec_remove, + .id_table = cs42l43_codec_id_table, +}; +module_platform_driver(cs42l43_codec_driver); + +MODULE_IMPORT_NS(SND_SOC_CS42L43); + +MODULE_DESCRIPTION("CS42L43 CODEC Driver"); +MODULE_AUTHOR("Charles Keepax "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42l43.h b/sound/soc/codecs/cs42l43.h new file mode 100644 index 000000000000..bf4f728eea3e --- /dev/null +++ b/sound/soc/codecs/cs42l43.h @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * CS42L43 CODEC driver internal data + * + * Copyright (C) 2022-2023 Cirrus Logic, Inc. and + * Cirrus Logic International Semiconductor Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CS42L43_ASOC_INT_H +#define CS42L43_ASOC_INT_H + +#define CS42L43_INTERNAL_SYSCLK 24576000 +#define CS42L43_DEFAULT_SLOTS 0x3F + +#define CS42L43_PLL_TIMEOUT_MS 200 +#define CS42L43_SPK_TIMEOUT_MS 100 +#define CS42L43_HP_TIMEOUT_MS 2000 +#define CS42L43_LOAD_TIMEOUT_MS 1000 + +#define CS42L43_ASP_MAX_CHANNELS 6 +#define CS42L43_N_EQ_COEFFS 15 + +#define CS42L43_N_BUTTONS 6 + +struct cs42l43_codec { + struct device *dev; + struct cs42l43 *core; + struct snd_soc_component *component; + + struct clk *mclk; + + int n_slots; + int slot_width; + int tx_slots[CS42L43_ASP_MAX_CHANNELS]; + int rx_slots[CS42L43_ASP_MAX_CHANNELS]; + struct snd_pcm_hw_constraint_list constraint; + + u32 eq_coeffs[CS42L43_N_EQ_COEFFS]; + + unsigned int refclk_src; + unsigned int refclk_freq; + struct completion pll_ready; + + unsigned int decim_cache[4]; + unsigned int adc_ena; + unsigned int hp_ena; + + struct completion hp_startup; + struct completion hp_shutdown; + struct completion spkr_shutdown; + struct completion spkl_shutdown; + struct completion spkr_startup; + struct completion spkl_startup; + // Lock to ensure speaker VU updates don't clash + struct mutex spk_vu_lock; + + // Lock for all jack detect operations + struct mutex jack_lock; + struct snd_soc_jack *jack_hp; + + bool use_ring_sense; + unsigned int tip_debounce_ms; + unsigned int bias_low; + unsigned int bias_sense_ua; + unsigned int bias_ramp_ms; + unsigned int detect_us; + unsigned int buttons[CS42L43_N_BUTTONS]; + + struct delayed_work tip_sense_work; + struct delayed_work bias_sense_timeout; + struct delayed_work button_press_work; + struct work_struct button_release_work; + struct completion type_detect; + struct completion load_detect; + + bool load_detect_running; + bool button_detect_running; + bool jack_present; + int jack_override; +}; + +#if IS_REACHABLE(CONFIG_SND_SOC_CS42L43_SDW) + +int cs42l43_sdw_add_peripheral(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); +int cs42l43_sdw_remove_peripheral(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +int cs42l43_sdw_set_stream(struct snd_soc_dai *dai, void *sdw_stream, int direction); + +#else + +static inline int cs42l43_sdw_add_peripheral(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + return -EINVAL; +} + +#define cs42l43_sdw_remove_peripheral NULL +#define cs42l43_sdw_set_stream NULL + +#endif + +int cs42l43_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *d); +void cs42l43_bias_sense_timeout(struct work_struct *work); +void cs42l43_tip_sense_work(struct work_struct *work); +void cs42l43_button_press_work(struct work_struct *work); +void cs42l43_button_release_work(struct work_struct *work); +irqreturn_t cs42l43_bias_detect_clamp(int irq, void *data); +irqreturn_t cs42l43_button_press(int irq, void *data); +irqreturn_t cs42l43_button_release(int irq, void *data); +irqreturn_t cs42l43_tip_sense(int irq, void *data); +int cs42l43_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); + +extern const struct soc_enum cs42l43_jack_enum; + +#endif /* CS42L43_ASOC_INT_H */ -- cgit v1.2.3 From f286620b5dc974fe281d8feed6e228fd2f39d013 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 21 Aug 2023 09:00:03 +0100 Subject: 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(-) (limited to 'sound') 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), -- cgit v1.2.3 From ef24388225f87f2604522fe86fafacc271ec4a29 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 21 Aug 2023 14:36:26 +0300 Subject: ASoC: SOF: ipc4-topology: Modify pipeline params based on SRC output format Modify the pipeline_params based on the SRC output format and set the sink_rate in the IPC data. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Reviewed-by: Seppo Ingalsuo Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230821113629.5017-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 633f6040d712..8bc12f12888d 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1838,10 +1838,10 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc4_src *src = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt; + struct sof_ipc4_audio_format *out_audio_fmt; struct sof_ipc4_audio_format *in_fmt; u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; - struct snd_interval *rate; - int ret; + int ret, output_format_index; ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->base_config, pipeline_params, available_fmt); @@ -1853,22 +1853,23 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); - ret = sof_ipc4_init_output_audio_fmt(sdev, &src->base_config, available_fmt, - out_ref_rate, out_ref_channels, out_ref_valid_bits); - if (ret < 0) { + output_format_index = sof_ipc4_init_output_audio_fmt(sdev, &src->base_config, + available_fmt, out_ref_rate, + out_ref_channels, out_ref_valid_bits); + if (output_format_index < 0) { dev_err(sdev->dev, "Failed to initialize output format for %s", swidget->widget->name); + return output_format_index; } /* update pipeline memory usage */ sof_ipc4_update_resource_usage(sdev, swidget, &src->base_config); - /* update pipeline_params for sink widgets */ - rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE); - rate->min = src->sink_rate; - rate->max = rate->min; + out_audio_fmt = &available_fmt->output_pin_fmts[output_format_index].audio_fmt; + src->sink_rate = out_audio_fmt->sampling_frequency; - return 0; + /* update pipeline_params for sink widgets */ + return sof_ipc4_update_hw_params(sdev, pipeline_params, out_audio_fmt); } static int -- cgit v1.2.3 From 56ecc164040b3685f6cb36b4d513d73d0f88140b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 21 Aug 2023 14:36:27 +0300 Subject: ASoC: SOF: ipc4-topology: Fix the output reference params for SRC For playback, the SRC sink rate must be configured based on the requested output format which is restricted to only handle DAI's that support a single audio format for now. For capture, the SRC module should convert the rate to match the rate requested by the PCM hw_params. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Reviewed-by: Seppo Ingalsuo Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230821113629.5017-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 8bc12f12888d..39649fddf16a 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1839,19 +1839,39 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, struct sof_ipc4_src *src = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt; struct sof_ipc4_audio_format *out_audio_fmt; - struct sof_ipc4_audio_format *in_fmt; + struct sof_ipc4_audio_format *in_audio_fmt; u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; - int ret, output_format_index; + int output_format_index, input_format_index; - ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->base_config, - pipeline_params, available_fmt); - if (ret < 0) - return ret; + input_format_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->base_config, + pipeline_params, available_fmt); + if (input_format_index < 0) + return input_format_index; - in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; - out_ref_rate = in_fmt->sampling_frequency; - out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); - out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + /* + * For playback, the SRC sink rate will be configured based on the requested output + * format, which is restricted to only deal with DAI's with a single format for now. + */ + if (dir == SNDRV_PCM_STREAM_PLAYBACK && available_fmt->num_output_formats > 1) { + dev_err(sdev->dev, "Invalid number of output formats: %d for SRC %s\n", + available_fmt->num_output_formats, swidget->widget->name); + return -EINVAL; + } + + /* + * SRC does not perform format conversion, so the output channels and valid bit depth must + * be the same as that of the input. + */ + in_audio_fmt = &available_fmt->input_pin_fmts[input_format_index].audio_fmt; + out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_audio_fmt->fmt_cfg); + out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_audio_fmt->fmt_cfg); + + /* + * For capture, the SRC module should convert the rate to match the rate requested by the + * PCM hw_params. Set the reference params based on the fe_params unconditionally as it + * will be ignored for playback anyway. + */ + out_ref_rate = params_rate(fe_params); output_format_index = sof_ipc4_init_output_audio_fmt(sdev, &src->base_config, available_fmt, out_ref_rate, -- cgit v1.2.3 From 769e8f6cd7182c95d4bd37491e13300ff067c7a7 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 21 Aug 2023 14:36:28 +0300 Subject: ASoC: SOF: ipc4-topology: Fix pipeline params at the output of copier When we walk the list of connected widgets from the source to the sink to prepare all widgets, the pipeline_params must be modified to reflect the output audio format at each widget. But, the copier only modifies the sample format in the pipeline_params. So, fix it to also modify the rate and channels. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Reviewed-by: Seppo Ingalsuo Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230821113629.5017-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 39649fddf16a..310aadd97d28 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1349,25 +1349,6 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s } #endif -static int ipc4_set_fmt_mask(struct snd_mask *fmt, unsigned int bit_depth) -{ - switch (bit_depth) { - case 16: - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); - break; - case 24: - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - break; - case 32: - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); - break; - default: - return -EINVAL; - } - - return 0; -} - static int sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *fe_params, @@ -1381,8 +1362,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *ref_params; struct sof_ipc4_copier *ipc4_copier; struct snd_sof_dai *dai; - struct snd_mask *fmt; - int out_sample_valid_bits; u32 gtw_cfg_config_length; u32 dma_config_tlv_size = 0; void **ipc_config_data; @@ -1664,11 +1643,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, } /* modify the input params for the next widget */ - fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT); - out_sample_valid_bits = - SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg); - snd_mask_none(fmt); - ret = ipc4_set_fmt_mask(fmt, out_sample_valid_bits); + ret = sof_ipc4_update_hw_params(sdev, pipeline_params, &copier_data->out_format); if (ret) return ret; -- cgit v1.2.3 From 70b0924b22efe2135222a2c7141a83dfe0c78779 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 21 Aug 2023 14:36:29 +0300 Subject: ASoC: SOF: ipc4-topology: Modify the reference output valid_bits for copier If the copier has only output valid_bits across all its output formats, the reference for selecting the output format must be set that instead of the valid_bits from the selected input format. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Seppo Ingalsuo Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230821113629.5017-5-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 58 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 310aadd97d28..eff43635a88f 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1349,6 +1349,31 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s } #endif +static bool sof_ipc4_copier_is_single_format(struct snd_sof_dev *sdev, + struct sof_ipc4_pin_format *pin_fmts, + u32 pin_fmts_size) +{ + struct sof_ipc4_audio_format *fmt; + u32 valid_bits; + int i; + + fmt = &pin_fmts[0].audio_fmt; + valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); + + /* check if all output formats in topology are the same */ + for (i = 1; i < pin_fmts_size; i++) { + u32 _valid_bits; + + fmt = &pin_fmts[i].audio_fmt; + _valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); + + if (_valid_bits != valid_bits) + return false; + } + + return true; +} + static int sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *fe_params, @@ -1371,6 +1396,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, u32 out_ref_rate, out_ref_channels; u32 deep_buffer_dma_ms = 0; int output_fmt_index; + bool single_output_format; dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id); @@ -1504,6 +1530,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, return ret; /* set the reference params for output format selection */ + single_output_format = sof_ipc4_copier_is_single_format(sdev, + available_fmt->output_pin_fmts, + available_fmt->num_output_formats); switch (swidget->id) { case snd_soc_dapm_aif_in: case snd_soc_dapm_dai_out: @@ -1514,17 +1543,21 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; out_ref_rate = in_fmt->sampling_frequency; out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); - out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + + if (!single_output_format) + out_ref_valid_bits = + SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); break; } case snd_soc_dapm_aif_out: case snd_soc_dapm_dai_in: - out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); - if (out_ref_valid_bits < 0) - return out_ref_valid_bits; - out_ref_rate = params_rate(fe_params); out_ref_channels = params_channels(fe_params); + if (!single_output_format) { + out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); + if (out_ref_valid_bits < 0) + return out_ref_valid_bits; + } break; default: /* @@ -1534,6 +1567,21 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, return -EINVAL; } + /* + * if the output format is the same across all available output formats, choose + * that as the reference. + */ + if (single_output_format) { + struct sof_ipc4_audio_format *out_fmt; + + out_fmt = &available_fmt->output_pin_fmts[0].audio_fmt; + out_ref_valid_bits = + SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg); + } + + dev_dbg(sdev->dev, "copier %s: reference output rate %d, channels %d valid_bits %d\n", + swidget->widget->name, out_ref_rate, out_ref_channels, out_ref_valid_bits); + output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &copier_data->base_config, available_fmt, out_ref_rate, out_ref_channels, out_ref_valid_bits); -- cgit v1.2.3 From 5fadc941d07530d681f3b7ec91e56d8445bc3825 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 21 Aug 2023 13:18:57 +0200 Subject: 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(-) (limited to 'sound') 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; } -- cgit v1.2.3 From 1c80cc055b3f9fb72606d58c27eb2486c4b919a7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 20 Aug 2023 19:26:34 +0200 Subject: 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(-) (limited to 'sound') 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; } -- cgit v1.2.3 From 17a1eab7b70d85fc5711f37bb6e530b771736bb7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 20 Aug 2023 19:26:35 +0200 Subject: 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(-) (limited to 'sound') 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, -- cgit v1.2.3 From d0dab6b76a9f05bd25d7ad957c3275a9dec42a06 Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Wed, 9 Aug 2023 18:05:20 +0530 Subject: ASoC: SOF: amd: Add sof support for vangogh platform Add pci driver and platform driver to enable SOF support on ACP5x architecture based Vangogh platform. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20230809123534.287707-1-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/Kconfig | 12 ++- sound/soc/sof/amd/Makefile | 4 +- sound/soc/sof/amd/acp-dsp-offset.h | 8 +- sound/soc/sof/amd/acp.h | 9 ++- sound/soc/sof/amd/pci-vangogh.c | 105 +++++++++++++++++++++++++ sound/soc/sof/amd/vangogh.c | 156 +++++++++++++++++++++++++++++++++++++ 6 files changed, 290 insertions(+), 4 deletions(-) create mode 100644 sound/soc/sof/amd/pci-vangogh.c create mode 100644 sound/soc/sof/amd/vangogh.c (limited to 'sound') diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig index 7dbc8df5cfe6..f2faa08f0c0e 100644 --- a/sound/soc/sof/amd/Kconfig +++ b/sound/soc/sof/amd/Kconfig @@ -2,7 +2,7 @@ # 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) 2021 Advanced Micro Devices, Inc. All rights reserved. +# Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. config SND_SOC_SOF_AMD_TOPLEVEL tristate "SOF support for AMD audio DSPs" @@ -34,6 +34,16 @@ config SND_SOC_SOF_AMD_RENOIR help Select this option for SOF support on AMD Renoir platform +config SND_SOC_SOF_AMD_VANGOGH + tristate "SOF support for VANGOGH" + depends on SND_SOC_SOF_PCI + select SND_SOC_SOF_AMD_COMMON + help + Select this option for SOF support + on AMD Vangogh platform. + Say Y if you want to enable SOF on Vangogh. + If unsure select "N". + config SND_SOC_SOF_AMD_REMBRANDT tristate "SOF support for REMBRANDT" depends on SND_SOC_SOF_PCI diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index ef9f7df4e379..f3b375e67a6f 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -2,13 +2,15 @@ # 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) 2021 Advanced Micro Devices, Inc. All rights reserved. +# Copyright(c) 2021, 2023 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 +snd-sof-amd-vangogh-objs := pci-vangogh.o vangogh.o obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o obj-$(CONFIG_SND_SOC_SOF_AMD_RENOIR) +=snd-sof-amd-renoir.o obj-$(CONFIG_SND_SOC_SOF_AMD_REMBRANDT) +=snd-sof-amd-rembrandt.o +obj-$(CONFIG_SND_SOC_SOF_AMD_VANGOGH) +=snd-sof-amd-vangogh.o diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 920155dee819..19ef2b4c46d6 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -3,7 +3,7 @@ * 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) 2021 Advanced Micro Devices, Inc. All rights reserved. + * Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. * * Author: Ajit Kumar Pandey */ @@ -49,27 +49,33 @@ #define ACP_CONTROL 0x1004 #define ACP3X_I2S_PIN_CONFIG 0x1400 +#define ACP5X_I2S_PIN_CONFIG 0x1400 #define ACP6X_I2S_PIN_CONFIG 0x1440 /* Registers offsets from ACP_PGFSM block */ #define ACP3X_PGFSM_BASE 0x141C +#define ACP5X_PGFSM_BASE 0x1424 #define ACP6X_PGFSM_BASE 0x1024 #define PGFSM_CONTROL_OFFSET 0x0 #define PGFSM_STATUS_OFFSET 0x4 #define ACP3X_CLKMUX_SEL 0x1424 +#define ACP5X_CLKMUX_SEL 0x142C #define ACP6X_CLKMUX_SEL 0x102C /* Registers from ACP_INTR block */ #define ACP3X_EXT_INTR_STAT 0x1808 +#define ACP5X_EXT_INTR_STAT 0x1808 #define ACP6X_EXT_INTR_STAT 0x1A0C #define ACP3X_DSP_SW_INTR_BASE 0x1814 +#define ACP5X_DSP_SW_INTR_BASE 0x1814 #define ACP6X_DSP_SW_INTR_BASE 0x1808 #define DSP_SW_INTR_CNTL_OFFSET 0x0 #define DSP_SW_INTR_STAT_OFFSET 0x4 #define DSP_SW_INTR_TRIG_OFFSET 0x8 #define ACP_ERROR_STATUS 0x18C4 #define ACP3X_AXI2DAGB_SEM_0 0x1880 +#define ACP5X_AXI2DAGB_SEM_0 0x1884 #define ACP6X_AXI2DAGB_SEM_0 0x1874 /* Registers from ACP_SHA block */ diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 72fa0af971f0..73c3e1373d42 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -3,7 +3,7 @@ * 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) 2021 Advanced Micro Devices, Inc. All rights reserved. + * Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. * * Author: Ajit Kumar Pandey */ @@ -32,6 +32,7 @@ #define ACP_DSP_INTR_EN_MASK 0x00000001 #define ACP3X_SRAM_PTE_OFFSET 0x02050000 +#define ACP5X_SRAM_PTE_OFFSET 0x02050000 #define ACP6X_SRAM_PTE_OFFSET 0x03800000 #define PAGE_SIZE_4K_ENABLE 0x2 #define ACP_PAGE_SIZE 0x1000 @@ -56,9 +57,11 @@ #define ACP_DSP_TO_HOST_IRQ 0x04 #define ACP_RN_PCI_ID 0x01 +#define ACP_VANGOGH_PCI_ID 0x50 #define ACP_RMB_PCI_ID 0x6F #define HOST_BRIDGE_CZN 0x1630 +#define HOST_BRIDGE_VGH 0x1645 #define HOST_BRIDGE_RMB 0x14B5 #define ACP_SHA_STAT 0x8000 #define ACP_PSP_TIMEOUT_US 1000000 @@ -163,6 +166,7 @@ struct acp_dsp_stream { struct sof_amd_acp_desc { unsigned int rev; + const char *name; unsigned int host_bridge_id; u32 pgfsm_base; u32 ext_intr_stat; @@ -253,6 +257,8 @@ extern struct snd_sof_dsp_ops sof_acp_common_ops; extern struct snd_sof_dsp_ops sof_renoir_ops; int sof_renoir_ops_init(struct snd_sof_dev *sdev); +extern struct snd_sof_dsp_ops sof_vangogh_ops; +int sof_vangogh_ops_init(struct snd_sof_dev *sdev); extern struct snd_sof_dsp_ops sof_rembrandt_ops; int sof_rembrandt_ops_init(struct snd_sof_dev *sdev); @@ -282,4 +288,5 @@ static inline const struct sof_amd_acp_desc *get_chip_info(struct snd_sof_pdata int acp_probes_register(struct snd_sof_dev *sdev); void acp_probes_unregister(struct snd_sof_dev *sdev); +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_vangogh_sof_machines[]; #endif diff --git a/sound/soc/sof/amd/pci-vangogh.c b/sound/soc/sof/amd/pci-vangogh.c new file mode 100644 index 000000000000..d8be42fbcb6d --- /dev/null +++ b/sound/soc/sof/amd/pci-vangogh.c @@ -0,0 +1,105 @@ +// 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. All rights reserved. +// +// Authors: Venkata Prasad Potturu + +/*. + * PCI interface for Vangogh ACP device + */ + +#include +#include +#include +#include +#include + +#include "../ops.h" +#include "../sof-pci-dev.h" +#include "../../amd/mach-config.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +#define ACP5X_FUTURE_REG_ACLK_0 0x1864 + +static const struct sof_amd_acp_desc vangogh_chip_info = { + .rev = 5, + .name = "vangogh", + .host_bridge_id = HOST_BRIDGE_VGH, + .pgfsm_base = ACP5X_PGFSM_BASE, + .ext_intr_stat = ACP5X_EXT_INTR_STAT, + .dsp_intr_base = ACP5X_DSP_SW_INTR_BASE, + .sram_pte_offset = ACP5X_SRAM_PTE_OFFSET, + .hw_semaphore_offset = ACP5X_AXI2DAGB_SEM_0, + .acp_clkmux_sel = ACP5X_CLKMUX_SEL, + .probe_reg_offset = ACP5X_FUTURE_REG_ACLK_0, +}; + +static const struct sof_dev_desc vangogh_desc = { + .machines = snd_soc_acpi_amd_vangogh_sof_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .chip_info = &vangogh_chip_info, + .ipc_supported_mask = BIT(SOF_IPC), + .ipc_default = SOF_IPC, + .default_fw_path = { + [SOF_IPC] = "amd/sof", + }, + .default_tplg_path = { + [SOF_IPC] = "amd/sof-tplg", + }, + .default_fw_filename = { + [SOF_IPC] = "sof-vangogh.ri", + }, + .nocodec_tplg_filename = "sof-acp.tplg", + .ops = &sof_vangogh_ops, + .ops_init = sof_vangogh_ops_init, +}; + +static int acp_pci_vgh_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) +{ + unsigned int flag; + + if (pci->revision != ACP_VANGOGH_PCI_ID) + return -ENODEV; + + flag = snd_amd_acp_find_config(pci); + if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC) + return -ENODEV; + + return sof_pci_probe(pci, pci_id); +}; + +static void acp_pci_vgh_remove(struct pci_dev *pci) +{ + sof_pci_remove(pci); +} + +/* PCI IDs */ +static const struct pci_device_id vgh_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID), + .driver_data = (unsigned long)&vangogh_desc}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, vgh_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_amd_vgh_driver = { + .name = KBUILD_MODNAME, + .id_table = vgh_pci_ids, + .probe = acp_pci_vgh_probe, + .remove = acp_pci_vgh_remove, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_amd_vgh_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); diff --git a/sound/soc/sof/amd/vangogh.c b/sound/soc/sof/amd/vangogh.c new file mode 100644 index 000000000000..f3f6bd790788 --- /dev/null +++ b/sound/soc/sof/amd/vangogh.c @@ -0,0 +1,156 @@ +// 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: Venkata Prasad Potturu + +/* + * Hardware interface for Audio DSP on Vangogh platform + */ + +#include +#include + +#include "../ops.h" +#include "../sof-audio.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +#define I2S_HS_INSTANCE 0 +#define I2S_BT_INSTANCE 1 +#define I2S_SP_INSTANCE 2 +#define PDM_DMIC_INSTANCE 3 +#define I2S_HS_VIRTUAL_INSTANCE 4 + +static struct snd_soc_dai_driver vangogh_sof_dai[] = { + [I2S_HS_INSTANCE] = { + .id = I2S_HS_INSTANCE, + .name = "acp-sof-hs", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S HS controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [I2S_BT_INSTANCE] = { + .id = I2S_BT_INSTANCE, + .name = "acp-sof-bt", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S BT controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [I2S_SP_INSTANCE] = { + .id = I2S_SP_INSTANCE, + .name = "acp-sof-sp", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S SP controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [PDM_DMIC_INSTANCE] = { + .id = PDM_DMIC_INSTANCE, + .name = "acp-sof-dmic", + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 4, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [I2S_HS_VIRTUAL_INSTANCE] = { + .id = I2S_HS_VIRTUAL_INSTANCE, + .name = "acp-sof-hs-virtual", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S HS-Virtual controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, +}; + +/* Vangogh ops */ +struct snd_sof_dsp_ops sof_vangogh_ops; +EXPORT_SYMBOL_NS(sof_vangogh_ops, SND_SOC_SOF_AMD_COMMON); + +int sof_vangogh_ops_init(struct snd_sof_dev *sdev) +{ + /* common defaults */ + memcpy(&sof_vangogh_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); + + sof_vangogh_ops.drv = vangogh_sof_dai; + sof_vangogh_ops.num_drv = ARRAY_SIZE(vangogh_sof_dai); + + return 0; +} + +MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); +MODULE_DESCRIPTION("VANGOGH SOF Driver"); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From 6a69b724b2f82b1c44852b432010fbe25f0e2b75 Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Wed, 9 Aug 2023 18:05:21 +0530 Subject: ASoC: SOF: amd: Add support for signed fw image loading Add support for signed firmware code bin and data bin loading for amd platforms. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20230809123534.287707-2-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp-dsp-offset.h | 1 + sound/soc/sof/amd/acp-loader.c | 39 ++++++++++++++++++++++++++++++++++++-- sound/soc/sof/amd/acp.c | 6 +++++- sound/soc/sof/amd/acp.h | 8 ++++++++ 4 files changed, 51 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 19ef2b4c46d6..a913f1cc4c80 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -87,6 +87,7 @@ #define ACP_SHA_DMA_CMD_STS 0x1CC0 #define ACP_SHA_DMA_ERR_STATUS 0x1CC4 #define ACP_SHA_TRANSFER_BYTE_CNT 0x1CC8 +#define ACP_SHA_DMA_INCLUDE_HDR 0x1CCC #define ACP_SHA_PSP_ACK 0x1C74 #define ACP_SCRATCH_REG_0 0x10000 diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index a4bce5a3ae48..a63c00b53a5e 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -3,7 +3,7 @@ // 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) 2021 Advanced Micro Devices, Inc. +// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. // // Authors: Ajit Kumar Pandey @@ -158,7 +158,11 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev) int ret; adata = sdev->pdata->hw_pdata; - size_fw = adata->fw_bin_size; + + if (adata->signed_fw_image) + size_fw = adata->fw_bin_size - ACP_FIRMWARE_SIGNATURE; + else + size_fw = adata->fw_bin_size; page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT; adata->fw_bin_page_count = page_count; @@ -219,3 +223,34 @@ int acp_sof_dsp_run(struct snd_sof_dev *sdev) return 0; } EXPORT_SYMBOL_NS(acp_sof_dsp_run, SND_SOC_SOF_AMD_COMMON); + +int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *plat_data = sdev->pdata; + struct acp_dev_data *adata = plat_data->hw_pdata; + int ret; + + ret = request_firmware(&sdev->basefw.fw, adata->fw_code_bin, sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "sof signed firmware code bin is missing\n"); + return ret; + } else { + dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_code_bin); + } + ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_IRAM, 0, + (void *)sdev->basefw.fw->data, sdev->basefw.fw->size); + + ret = request_firmware(&adata->fw_dbin, adata->fw_data_bin, sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "sof signed firmware data bin is missing\n"); + return ret; + + } else { + dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_data_bin); + } + + ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0, + (void *)adata->fw_dbin->data, adata->fw_dbin->size); + return ret; +} +EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index c450931ae77e..0072a62aa4ef 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -3,7 +3,7 @@ // 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) 2021 Advanced Micro Devices, Inc. All rights reserved. +// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. // // Authors: Vijendar Mukunda // Ajit Kumar Pandey @@ -235,6 +235,9 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, } } + if (adata->signed_fw_image) + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_INCLUDE_HDR, ACP_SHA_HEADER); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_STRT_ADDR, start_addr); snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_DESTINATION_ADDR, dest_addr); snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_MSG_LENGTH, image_length); @@ -527,6 +530,7 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size; sdev->debug_box.size = BOX_SIZE_1024; + adata->signed_fw_image = false; acp_memory_init(sdev); acp_dsp_stream_init(sdev); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 73c3e1373d42..842105330369 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -41,6 +41,7 @@ #define DSP_FW_RUN_ENABLE 0x01 #define ACP_SHA_RUN 0x01 #define ACP_SHA_RESET 0x02 +#define ACP_SHA_HEADER 0x01 #define ACP_DMA_CH_RST 0x01 #define ACP_DMA_CH_GRACEFUL_RST_EN 0x10 #define ACP_ATU_CACHE_INVALID 0x01 @@ -82,6 +83,8 @@ #define SRAM1_SIZE 0x13A000 #define PROBE_STATUS_BIT BIT(31) +#define ACP_FIRMWARE_SIGNATURE 0x100 + enum clock_source { ACP_CLOCK_96M = 0, ACP_CLOCK_48M, @@ -181,15 +184,19 @@ struct sof_amd_acp_desc { /* Common device data struct for ACP devices */ struct acp_dev_data { struct snd_sof_dev *dev; + const struct firmware *fw_dbin; /* DMIC device */ struct platform_device *dmic_dev; unsigned int fw_bin_size; unsigned int fw_data_bin_size; + const char *fw_code_bin; + const char *fw_data_bin; u32 fw_bin_page_count; dma_addr_t sha_dma_addr; u8 *bin_buf; dma_addr_t dma_addr; u8 *data_buf; + bool signed_fw_image; struct dma_descriptor dscr_info[ACP_MAX_DESC]; struct acp_dsp_stream stream_buf[ACP_MAX_STREAM]; struct acp_dsp_stream *dtrace_stream; @@ -214,6 +221,7 @@ int amd_sof_acp_remove(struct snd_sof_dev *sdev); /* DSP Loader callbacks */ int acp_sof_dsp_run(struct snd_sof_dev *sdev); int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev); +int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev); int acp_get_bar_index(struct snd_sof_dev *sdev, u32 type); /* Block IO callbacks */ -- cgit v1.2.3 From f7da88003c53cf0eedabe609324a047b1921dfcc Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Wed, 9 Aug 2023 18:05:22 +0530 Subject: ASoC: SOF: amd: Enable signed firmware image loading for Vangogh platform Enable signed firmware loading for Vangogh platform using dmi quirks. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20230809123534.287707-3-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 31 +++++++++++++++++++++++++++++++ sound/soc/sof/amd/acp.h | 3 +++ sound/soc/sof/amd/vangogh.c | 6 ++++++ 3 files changed, 40 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 0072a62aa4ef..b2e00a10a03e 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -20,6 +20,22 @@ #include "acp.h" #include "acp-dsp-offset.h" +#define SECURED_FIRMWARE 1 + +const struct dmi_system_id acp_sof_quirk_table[] = { + { + /* Valve Jupiter device */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Valve"), + DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "Sephiroth"), + }, + .driver_data = (void *)SECURED_FIRMWARE, + }, + {} +}; +EXPORT_SYMBOL_GPL(acp_sof_quirk_table); + static int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data) { pci_write_config_dword(dev, 0x60, smn_addr); @@ -468,8 +484,10 @@ EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON); int amd_sof_acp_probe(struct snd_sof_dev *sdev) { struct pci_dev *pci = to_pci_dev(sdev->dev); + struct snd_sof_pdata *plat_data = sdev->pdata; struct acp_dev_data *adata; const struct sof_amd_acp_desc *chip; + const struct dmi_system_id *dmi_id; unsigned int addr; int ret; @@ -531,6 +549,19 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) sdev->debug_box.size = BOX_SIZE_1024; adata->signed_fw_image = false; + dmi_id = dmi_first_match(acp_sof_quirk_table); + if (dmi_id && dmi_id->driver_data) { + adata->fw_code_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-code.bin", + plat_data->fw_filename_prefix, + chip->name); + adata->fw_data_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-data.bin", + plat_data->fw_filename_prefix, + chip->name); + adata->signed_fw_image = dmi_id->driver_data; + + dev_dbg(sdev->dev, "fw_code_bin:%s, fw_data_bin:%s\n", adata->fw_code_bin, + adata->fw_data_bin); + } acp_memory_init(sdev); acp_dsp_stream_init(sdev); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 842105330369..19cad4fcf99a 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -11,6 +11,8 @@ #ifndef __SOF_AMD_ACP_H #define __SOF_AMD_ACP_H +#include + #include "../sof-priv.h" #include "../sof-audio.h" @@ -297,4 +299,5 @@ int acp_probes_register(struct snd_sof_dev *sdev); void acp_probes_unregister(struct snd_sof_dev *sdev); extern struct snd_soc_acpi_mach snd_soc_acpi_amd_vangogh_sof_machines[]; +extern const struct dmi_system_id acp_sof_quirk_table[]; #endif diff --git a/sound/soc/sof/amd/vangogh.c b/sound/soc/sof/amd/vangogh.c index f3f6bd790788..de15d21aa6d9 100644 --- a/sound/soc/sof/amd/vangogh.c +++ b/sound/soc/sof/amd/vangogh.c @@ -142,12 +142,18 @@ EXPORT_SYMBOL_NS(sof_vangogh_ops, SND_SOC_SOF_AMD_COMMON); int sof_vangogh_ops_init(struct snd_sof_dev *sdev) { + const struct dmi_system_id *dmi_id; + /* common defaults */ memcpy(&sof_vangogh_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); sof_vangogh_ops.drv = vangogh_sof_dai; sof_vangogh_ops.num_drv = ARRAY_SIZE(vangogh_sof_dai); + dmi_id = dmi_first_match(acp_sof_quirk_table); + if (dmi_id && dmi_id->driver_data) + sof_vangogh_ops.load_firmware = acp_sof_load_signed_firmware; + return 0; } -- cgit v1.2.3 From 8e6657159131f90b746572f6a5bd622b3ccac82d Mon Sep 17 00:00:00 2001 From: Senhong Liu Date: Sat, 19 Aug 2023 06:33:45 -0700 Subject: ASoC: rt5640: fix typos I noticed typos and i fixed them. Signed-off-by: Senhong Liu Link: https://lore.kernel.org/r/20230819133345.39961-1-liusenhong2022@email.szu.edu.cn Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 8920726c38e8..15e1a62b9e57 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2570,7 +2570,7 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "rt5640", rt5640); if (ret) { - dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret); + dev_warn(component->dev, "Failed to request IRQ %d: %d\n", rt5640->irq, ret); rt5640_disable_jack_detect(component); return; } @@ -2625,7 +2625,7 @@ static void rt5640_enable_hda_jack_detect( NULL, rt5640_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT, "rt5640", rt5640); if (ret) { - dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret); + dev_warn(component->dev, "Failed to request IRQ %d: %d\n", rt5640->irq, ret); rt5640->irq = -ENXIO; return; } -- cgit v1.2.3 From 2cbd5304ea393f0ca3aeebec2f6554a32ac02ce3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 01:11:23 +0000 Subject: ASoC: pxa: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202308151142.hoM5o9LV-lkp@intel.com/ Fixes: 446b31e89493 ("ASoC: soc-dai.h: remove unused call back functions") Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/878ra3ubid.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/pxa/pxa2xx-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 10636506b622..437bfccd04f8 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -329,6 +329,8 @@ static int pxa2xx_i2s_remove(struct snd_soc_dai *dai) SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) static const struct snd_soc_dai_ops pxa_i2s_dai_ops = { + .probe = pxa2xx_i2s_probe, + .remove = pxa2xx_i2s_remove, .startup = pxa2xx_i2s_startup, .shutdown = pxa2xx_i2s_shutdown, .trigger = pxa2xx_i2s_trigger, @@ -338,8 +340,6 @@ static const struct snd_soc_dai_ops pxa_i2s_dai_ops = { }; static struct snd_soc_dai_driver pxa_i2s_dai = { - .probe = pxa2xx_i2s_probe, - .remove = pxa2xx_i2s_remove, .playback = { .channels_min = 2, .channels_max = 2, -- cgit v1.2.3 From 26ef47e5ba600ead306ee19e0bf56c1bf59213a3 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 22 Aug 2023 09:54:19 +0300 Subject: ASoC: SOF: ipc4-topology: Add module parameter to ignore the CPC value Add a new module parameter ipc4_ignore_cpc which can be used to force the kernel to ignore the queried CPC value for all firmware modules and use 0 instead. The CPC lookup is still done to report missing configurations and the debug print is going to be different to be explicit that the CPC is ignored and what was the value we would have used. The CPC value is sent to the firmware with the MOD_INIT_INSTANCE message and it is used by the firmware as a parameter for clock scaling. The flag is intended to be used only when there is a need to validate the firmware behavior regarding to clock scaling since the 0 CPC value will force the DSP to run in full speed, disabling the scaling and provides additional counter point to rule out clock management related issues. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20230822065419.24374-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index eff43635a88f..f2a30cd31378 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -17,6 +17,19 @@ #include "ipc4-topology.h" #include "ops.h" +/* + * The ignore_cpc flag can be used to ignore the CPC value for all modules by + * using 0 instead. + * The CPC is sent to the firmware along with the SOF_IPC4_MOD_INIT_INSTANCE + * message and it is used for clock scaling. + * 0 as CPC value will instruct the firmware to use maximum frequency, thus + * deactivating the clock scaling. + */ +static bool ignore_cpc; +module_param_named(ipc4_ignore_cpc, ignore_cpc, bool, 0444); +MODULE_PARM_DESC(ipc4_ignore_cpc, + "Ignore CPC values. This option will disable clock scaling in firmware."); + #define SOF_IPC4_GAIN_PARAM_ID 0 #define SOF_IPC4_TPLG_ABI_SIZE 6 #define SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS 2 @@ -970,9 +983,16 @@ sof_ipc4_update_resource_usage(struct snd_sof_dev *sdev, struct snd_sof_widget * /* Update base_config->cpc from the module manifest */ sof_ipc4_update_cpc_from_manifest(sdev, fw_module, base_config); - dev_dbg(sdev->dev, "%s: ibs / obs / cpc: %u / %u / %u\n", - swidget->widget->name, base_config->ibs, base_config->obs, - base_config->cpc); + if (ignore_cpc) { + dev_dbg(sdev->dev, "%s: ibs / obs: %u / %u, forcing cpc to 0 from %u\n", + swidget->widget->name, base_config->ibs, base_config->obs, + base_config->cpc); + base_config->cpc = 0; + } else { + dev_dbg(sdev->dev, "%s: ibs / obs / cpc: %u / %u / %u\n", + swidget->widget->name, base_config->ibs, base_config->obs, + base_config->cpc); + } } static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev, -- cgit v1.2.3 From 220adc0fda6bbc274fff5825e2fd7d3dcd719e5c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 01:10:59 +0000 Subject: ASoC: fsl: merge DAI call back functions into ops ALSA SoC merges DAI call backs into .ops. This patch merge these into one. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202308152047.psX1QNDh-lkp@intel.com/ Cc: Randy Dunlap Fixes: 446b31e89493 ("ASoC: soc-dai.h: remove unused call back functions") Signed-off-by: Kuninori Morimoto Reported-by: Randy Dunlap Acked-by: Randy Dunlap Tested-by: Randy Dunlap # build-tested Link: https://lore.kernel.org/r/87a5ujubj0.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_psc_ac97.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c index 40a4a2667394..1671bcd4ee3d 100644 --- a/sound/soc/fsl/mpc5200_psc_ac97.c +++ b/sound/soc/fsl/mpc5200_psc_ac97.c @@ -222,6 +222,7 @@ static int psc_ac97_probe(struct snd_soc_dai *cpu_dai) * psc_ac97_dai_template: template CPU Digital Audio Interface */ static const struct snd_soc_dai_ops psc_ac97_analog_ops = { + .probe = psc_ac97_probe, .hw_params = psc_ac97_hw_analog_params, .trigger = psc_ac97_trigger, }; @@ -233,7 +234,6 @@ static const struct snd_soc_dai_ops psc_ac97_digital_ops = { static struct snd_soc_dai_driver psc_ac97_dai[] = { { .name = "mpc5200-psc-ac97.0", - .probe = psc_ac97_probe, .playback = { .stream_name = "AC97 Playback", .channels_min = 1, -- cgit v1.2.3 From aa836152420af94d014ddd677a5f95544abef4f6 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 23 Aug 2023 13:03:33 +0530 Subject: ASoC: SOF: amd: remove unused sha dma interrupt code During initial development time for RN platform, when SHA dma gets completed, SHA DMA engine used to raise the ACP interrupt. In ACP interrupt handler, SHA DMA interrupt got handled. Currently SHA DMA compleition is verified by checking transfer count using read poll time out logic. Remove unused SHA dma interrupt handling code. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20230823073340.2829821-1-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index b2e00a10a03e..630c2c5fe4c7 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -337,14 +337,7 @@ static irqreturn_t acp_irq_thread(int irq, void *context) { struct snd_sof_dev *sdev = context; const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); - unsigned int val, count = ACP_HW_SEM_RETRY_COUNT; - - val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat); - if (val & ACP_SHA_STAT) { - /* Clear SHA interrupt raised by PSP */ - snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, val); - return IRQ_HANDLED; - } + unsigned int count = ACP_HW_SEM_RETRY_COUNT; while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset)) { /* Wait until acquired HW Semaphore lock or timeout */ -- cgit v1.2.3 From 0a1428141f638fc6fba863de40f0dc7ea91a1d47 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 23 Aug 2023 13:03:34 +0530 Subject: ASoC: SOF: amd: enable ACP external global interrupt Previously ACP SOF firmware used to enable the ACP external global interrupt register. This will restrict to report ACP host interrupts only after firmware loading is successful. This register needs to be set from host driver to handle other ACP interrupts(SoundWire Interrupts) before loading the ACP firmware. Add field for external interrupt enable register in acp descriptor structure and enable the external interrupt enable register. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20230823073340.2829821-2-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 3 +++ sound/soc/sof/amd/acp.h | 1 + 2 files changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 630c2c5fe4c7..651b56388cb6 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -420,6 +420,9 @@ static int acp_reset(struct snd_sof_dev *sdev) dev_err(sdev->dev, "timeout in releasing reset\n"); snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK); + if (desc->ext_intr_enb) + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_enb, 0x01); + return ret; } diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 19cad4fcf99a..97bcada822ef 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -174,6 +174,7 @@ struct sof_amd_acp_desc { const char *name; unsigned int host_bridge_id; u32 pgfsm_base; + u32 ext_intr_enb; u32 ext_intr_stat; u32 dsp_intr_base; u32 sram_pte_offset; -- cgit v1.2.3 From 60eb816ed850b33f5410b1223c5d4d935a6ceb79 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 23 Aug 2023 13:03:35 +0530 Subject: ASoC: SOF: amd: add module parameter for firmware debug Add module parameter for firmware debug. If firmware debug flag is enabled, clear the fusion stall bit which is required for enabling firmware debugging through JTAG. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20230823073340.2829821-3-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp-loader.c | 3 ++- sound/soc/sof/amd/acp.c | 5 +++++ sound/soc/sof/amd/acp.h | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index a63c00b53a5e..a427673cfb03 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -207,6 +207,7 @@ EXPORT_SYMBOL_NS(acp_dsp_pre_fw_run, SND_SOC_SOF_AMD_COMMON); int acp_sof_dsp_run(struct snd_sof_dev *sdev) { + struct acp_dev_data *adata = sdev->pdata->hw_pdata; const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); int val; @@ -215,7 +216,7 @@ int acp_sof_dsp_run(struct snd_sof_dev *sdev) dev_dbg(sdev->dev, "ACP_DSP0_RUNSTALL : 0x%0x\n", val); /* Some platforms won't support fusion DSP,keep offset zero for no support */ - if (desc->fusion_dsp_offset) { + if (desc->fusion_dsp_offset && adata->enable_fw_debug) { snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->fusion_dsp_offset, ACP_DSP_RUN); val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->fusion_dsp_offset); dev_dbg(sdev->dev, "ACP_DSP0_FUSION_RUNSTALL : 0x%0x\n", val); diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 651b56388cb6..ebc985e2aaad 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -22,6 +22,10 @@ #define SECURED_FIRMWARE 1 +static bool enable_fw_debug; +module_param(enable_fw_debug, bool, 0444); +MODULE_PARM_DESC(enable_fw_debug, "Enable Firmware debug"); + const struct dmi_system_id acp_sof_quirk_table[] = { { /* Valve Jupiter device */ @@ -558,6 +562,7 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) dev_dbg(sdev->dev, "fw_code_bin:%s, fw_data_bin:%s\n", adata->fw_code_bin, adata->fw_data_bin); } + adata->enable_fw_debug = enable_fw_debug; acp_memory_init(sdev); acp_dsp_stream_init(sdev); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 97bcada822ef..4dcceb764769 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -205,6 +205,7 @@ struct acp_dev_data { struct acp_dsp_stream *dtrace_stream; struct pci_dev *smn_dev; struct acp_dsp_stream *probe_stream; + bool enable_fw_debug; }; void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); -- cgit v1.2.3 From f3b2f8b7158026e7a0ab67f5e36c195cdb4c1bf8 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 23 Aug 2023 13:03:36 +0530 Subject: ASoC: SOF: amd: remove redundant clock mux selection register write ACP clock mux selection register is already programmed during acp init sequence. Remove the redundant register write. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20230823073340.2829821-4-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index ebc985e2aaad..61faae74d637 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -464,7 +464,6 @@ EXPORT_SYMBOL_NS(amd_sof_acp_suspend, SND_SOC_SOF_AMD_COMMON); int amd_sof_acp_resume(struct snd_sof_dev *sdev) { - const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); int ret; ret = acp_init(sdev); @@ -472,12 +471,7 @@ int amd_sof_acp_resume(struct snd_sof_dev *sdev) dev_err(sdev->dev, "ACP Init failed\n"); return ret; } - - snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK); - - ret = acp_memory_init(sdev); - - return ret; + return acp_memory_init(sdev); } EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON); -- cgit v1.2.3 From 0d9e4cf5b66e0ffca3d8cf8e9a111d4793877afe Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 23 Aug 2023 13:03:37 +0530 Subject: ASoC: SOF: amd: add conditional check for acp_clkmux_sel register Few AMD platforms require ACP ACLK as clock source. Add conditional check for clock mux selection register for switching between internal clock and ACP ACLK. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20230823073340.2829821-5-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 61faae74d637..eceba9b794ab 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -423,7 +423,9 @@ static int acp_reset(struct snd_sof_dev *sdev) if (ret < 0) dev_err(sdev->dev, "timeout in releasing reset\n"); - snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK); + if (desc->acp_clkmux_sel) + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK); + if (desc->ext_intr_enb) snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_enb, 0x01); -- cgit v1.2.3 From 3d02e1c439b4140215b624d423aa3c7554b17a5a Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 23 Aug 2023 13:03:38 +0530 Subject: ASoC: SOF: amd: clear panic mask status when panic occurs Due to scratch memory persistence, Once the DSP panic is reported, need to clear the panic mask after handling DSP panic. Otherwise, It results in DSP panic on next reboot. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20230823073340.2829821-6-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp-ipc.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c index 81a2c096a185..fcb54f545fea 100644 --- a/sound/soc/sof/amd/acp-ipc.c +++ b/sound/soc/sof/amd/acp-ipc.c @@ -170,6 +170,8 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) if ((status & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { snd_sof_dsp_panic(sdev, sdev->dsp_box.offset + sizeof(status), true); + status = 0; + acp_mailbox_write(sdev, sdev->dsp_box.offset, &status, sizeof(status)); return IRQ_HANDLED; } snd_sof_ipc_msgs_rx(sdev); @@ -199,6 +201,8 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) acp_mailbox_read(sdev, sdev->debug_box.offset, &status, sizeof(u32)); if ((status & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { snd_sof_dsp_panic(sdev, sdev->dsp_oops_offset, true); + status = 0; + acp_mailbox_write(sdev, sdev->debug_box.offset, &status, sizeof(status)); return IRQ_HANDLED; } -- cgit v1.2.3 From 38592ae6dc9f84b7a994c43de2136b8115ca30f6 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 23 Aug 2023 13:03:39 +0530 Subject: ASoC: SOF: amd: clear dsp to host interrupt status DSP_SW_INTR_STAT_OFFSET is a common interrupt register which will be accessed by both ACP firmware and driver. This register contains register bits corresponds to host to dsp interrupts and vice versa. when dsp to host interrupt is reported, only clear dsp to host interrupt bit in DSP_SW_INTR_STAT_OFFSET. Fixes: 2e7c6652f9b8 ("ASoC: SOF: amd: Fix for handling spurious interrupts from DSP") Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20230823073340.2829821-7-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index eceba9b794ab..19a801908b56 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -367,9 +367,9 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) unsigned int val; val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET); - if (val) { - val |= ACP_DSP_TO_HOST_IRQ; - snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, val); + if (val & ACP_DSP_TO_HOST_IRQ) { + snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, + ACP_DSP_TO_HOST_IRQ); return IRQ_WAKE_THREAD; } -- cgit v1.2.3 From 6dd11b945951315ba4986844f20e83a0c27c1d38 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 22 Aug 2023 22:55:44 +0200 Subject: ASoC: Delete UDA134x/L3 audio codec This codec was used by the deleted S3C board sound/soc/samsung/s3c24xx_uda134x.c. Fixes: 503278c12701 ("ASoC: samsung: remove unused drivers") Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230822-delete-l3-v2-1-b3ffc07348af@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 8 - sound/soc/codecs/Makefile | 4 - sound/soc/codecs/l3.c | 132 ---------- sound/soc/codecs/uda134x.c | 587 --------------------------------------------- sound/soc/codecs/uda134x.h | 33 --- 5 files changed, 764 deletions(-) delete mode 100644 sound/soc/codecs/l3.c delete mode 100644 sound/soc/codecs/uda134x.c delete mode 100644 sound/soc/codecs/uda134x.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 9ddebd135892..95b5bd883215 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -15,7 +15,6 @@ config SND_SOC_ALL_CODECS tristate "Build all ASoC CODEC drivers" depends on COMPILE_TEST imply SND_SOC_88PM860X - imply SND_SOC_L3 imply SND_SOC_AB8500_CODEC imply SND_SOC_AC97_CODEC imply SND_SOC_AD1836 @@ -270,7 +269,6 @@ config SND_SOC_ALL_CODECS imply SND_SOC_TWL4030 imply SND_SOC_TWL6040 imply SND_SOC_UDA1334 - imply SND_SOC_UDA134X imply SND_SOC_UDA1380 imply SND_SOC_WCD9335 imply SND_SOC_WCD934X @@ -1010,9 +1008,6 @@ config SND_SOC_JZ4770_CODEC This driver can also be built as a module. If so, the module will be called snd-soc-jz4770-codec. -config SND_SOC_L3 - tristate - config SND_SOC_DA7210 tristate depends on SND_SOC_I2C_AND_SPI @@ -1969,9 +1964,6 @@ config SND_SOC_UDA1334 and has basic features such as de-emphasis (at 44.1 kHz sampling rate) and mute. -config SND_SOC_UDA134X - tristate - config SND_SOC_UDA1380 tristate depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 95cbb42253e2..c8502a49b40a 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -131,7 +131,6 @@ snd-soc-jz4740-codec-objs := jz4740.o snd-soc-jz4725b-codec-objs := jz4725b.o snd-soc-jz4760-codec-objs := jz4760.o snd-soc-jz4770-codec-objs := jz4770.o -snd-soc-l3-objs := l3.o snd-soc-lm4857-objs := lm4857.o snd-soc-lm49453-objs := lm49453.o snd-soc-lochnagar-sc-objs := lochnagar-sc.o @@ -303,7 +302,6 @@ snd-soc-ts3a227e-objs := ts3a227e.o snd-soc-twl4030-objs := twl4030.o snd-soc-twl6040-objs := twl6040.o snd-soc-uda1334-objs := uda1334.o -snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.o snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o @@ -518,7 +516,6 @@ obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o obj-$(CONFIG_SND_SOC_JZ4725B_CODEC) += snd-soc-jz4725b-codec.o obj-$(CONFIG_SND_SOC_JZ4760_CODEC) += snd-soc-jz4760-codec.o obj-$(CONFIG_SND_SOC_JZ4770_CODEC) += snd-soc-jz4770-codec.o -obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o obj-$(CONFIG_SND_SOC_LM49453) += snd-soc-lm49453.o obj-$(CONFIG_SND_SOC_LOCHNAGAR_SC) += snd-soc-lochnagar-sc.o @@ -687,7 +684,6 @@ obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o obj-$(CONFIG_SND_SOC_UDA1334) += snd-soc-uda1334.o -obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WCD_MBHC) += snd-soc-wcd-mbhc.o obj-$(CONFIG_SND_SOC_WCD9335) += snd-soc-wcd9335.o diff --git a/sound/soc/codecs/l3.c b/sound/soc/codecs/l3.c deleted file mode 100644 index b84f6f1f6800..000000000000 --- a/sound/soc/codecs/l3.c +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * L3 code - * - * Copyright (C) 2008, Christian Pellegrin - * - * based on: - * - * L3 bus algorithm module. - * - * Copyright (C) 2001 Russell King, All Rights Reserved. - */ - -#include -#include -#include -#include -#include - -#include - -/* - * Send one byte of data to the chip. Data is latched into the chip on - * the rising edge of the clock. - */ -static void sendbyte(struct l3_pins *adap, unsigned int byte) -{ - int i; - - for (i = 0; i < 8; i++) { - adap->setclk(adap, 0); - udelay(adap->data_hold); - adap->setdat(adap, byte & 1); - udelay(adap->data_setup); - adap->setclk(adap, 1); - udelay(adap->clock_high); - byte >>= 1; - } -} - -/* - * Send a set of bytes to the chip. We need to pulse the MODE line - * between each byte, but never at the start nor at the end of the - * transfer. - */ -static void sendbytes(struct l3_pins *adap, const u8 *buf, - int len) -{ - int i; - - for (i = 0; i < len; i++) { - if (i) { - udelay(adap->mode_hold); - adap->setmode(adap, 0); - udelay(adap->mode); - } - adap->setmode(adap, 1); - udelay(adap->mode_setup); - sendbyte(adap, buf[i]); - } -} - -int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len) -{ - adap->setclk(adap, 1); - adap->setdat(adap, 1); - adap->setmode(adap, 1); - udelay(adap->mode); - - adap->setmode(adap, 0); - udelay(adap->mode_setup); - sendbyte(adap, addr); - udelay(adap->mode_hold); - - sendbytes(adap, data, len); - - adap->setclk(adap, 1); - adap->setdat(adap, 1); - adap->setmode(adap, 0); - - return len; -} -EXPORT_SYMBOL_GPL(l3_write); - - -static void l3_set_clk(struct l3_pins *adap, int val) -{ - gpio_set_value(adap->gpio_clk, val); -} - -static void l3_set_data(struct l3_pins *adap, int val) -{ - gpio_set_value(adap->gpio_data, val); -} - -static void l3_set_mode(struct l3_pins *adap, int val) -{ - gpio_set_value(adap->gpio_mode, val); -} - -int l3_set_gpio_ops(struct device *dev, struct l3_pins *adap) -{ - int ret; - - if (!adap->use_gpios) - return -EINVAL; - - ret = devm_gpio_request_one(dev, adap->gpio_data, - GPIOF_OUT_INIT_LOW, "l3_data"); - if (ret < 0) - return ret; - adap->setdat = l3_set_data; - - ret = devm_gpio_request_one(dev, adap->gpio_clk, - GPIOF_OUT_INIT_LOW, "l3_clk"); - if (ret < 0) - return ret; - adap->setclk = l3_set_clk; - - ret = devm_gpio_request_one(dev, adap->gpio_mode, - GPIOF_OUT_INIT_LOW, "l3_mode"); - if (ret < 0) - return ret; - adap->setmode = l3_set_mode; - - return 0; -} -EXPORT_SYMBOL_GPL(l3_set_gpio_ops); - -MODULE_DESCRIPTION("L3 bit-banging driver"); -MODULE_AUTHOR("Christian Pellegrin "); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c deleted file mode 100644 index 1a62bec94005..000000000000 --- a/sound/soc/codecs/uda134x.c +++ /dev/null @@ -1,587 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * uda134x.c -- UDA134X ALSA SoC Codec driver - * - * Modifications by Christian Pellegrin - * - * Copyright 2007 Dension Audio Systems Ltd. - * Author: Zoltan Devai - * - * Based on the WM87xx drivers by Liam Girdwood and Richard Purdie - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "uda134x.h" - - -#define UDA134X_RATES SNDRV_PCM_RATE_8000_48000 -#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE) - -struct uda134x_priv { - int sysclk; - int dai_fmt; - - struct snd_pcm_substream *master_substream; - struct snd_pcm_substream *slave_substream; - - struct regmap *regmap; - struct uda134x_platform_data *pd; -}; - -static const struct reg_default uda134x_reg_defaults[] = { - { UDA134X_EA000, 0x04 }, - { UDA134X_EA001, 0x04 }, - { UDA134X_EA010, 0x04 }, - { UDA134X_EA011, 0x00 }, - { UDA134X_EA100, 0x00 }, - { UDA134X_EA101, 0x00 }, - { UDA134X_EA110, 0x00 }, - { UDA134X_EA111, 0x00 }, - { UDA134X_STATUS0, 0x00 }, - { UDA134X_STATUS1, 0x03 }, - { UDA134X_DATA000, 0x00 }, - { UDA134X_DATA001, 0x00 }, - { UDA134X_DATA010, 0x00 }, - { UDA134X_DATA011, 0x00 }, - { UDA134X_DATA1, 0x00 }, -}; - -/* - * Write to the uda134x registers - * - */ -static int uda134x_regmap_write(void *context, unsigned int reg, - unsigned int value) -{ - struct uda134x_platform_data *pd = context; - int ret; - u8 addr; - u8 data = value; - - switch (reg) { - case UDA134X_STATUS0: - case UDA134X_STATUS1: - addr = UDA134X_STATUS_ADDR; - data |= (reg - UDA134X_STATUS0) << 7; - break; - case UDA134X_DATA000: - case UDA134X_DATA001: - case UDA134X_DATA010: - case UDA134X_DATA011: - addr = UDA134X_DATA0_ADDR; - data |= (reg - UDA134X_DATA000) << 6; - break; - case UDA134X_DATA1: - addr = UDA134X_DATA1_ADDR; - break; - default: - /* It's an extended address register */ - addr = (reg | UDA134X_EXTADDR_PREFIX); - - ret = l3_write(&pd->l3, - UDA134X_DATA0_ADDR, &addr, 1); - if (ret != 1) - return -EIO; - - addr = UDA134X_DATA0_ADDR; - data = (value | UDA134X_EXTDATA_PREFIX); - break; - } - - ret = l3_write(&pd->l3, - addr, &data, 1); - if (ret != 1) - return -EIO; - - return 0; -} - -static inline void uda134x_reset(struct snd_soc_component *component) -{ - struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component); - unsigned int mask = 1<<6; - - regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, mask); - msleep(1); - regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, 0); -} - -static int uda134x_mute(struct snd_soc_dai *dai, int mute, int direction) -{ - struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(dai->component); - unsigned int mask = 1<<2; - unsigned int val; - - pr_debug("%s mute: %d\n", __func__, mute); - - if (mute) - val = mask; - else - val = 0; - - return regmap_update_bits(uda134x->regmap, UDA134X_DATA010, mask, val); -} - -static int uda134x_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_component *component = dai->component; - struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component); - struct snd_pcm_runtime *master_runtime; - - if (uda134x->master_substream) { - master_runtime = uda134x->master_substream->runtime; - - pr_debug("%s constraining to %d bits at %d\n", __func__, - master_runtime->sample_bits, - master_runtime->rate); - - snd_pcm_hw_constraint_single(substream->runtime, - SNDRV_PCM_HW_PARAM_RATE, - master_runtime->rate); - - snd_pcm_hw_constraint_single(substream->runtime, - SNDRV_PCM_HW_PARAM_SAMPLE_BITS, - master_runtime->sample_bits); - - uda134x->slave_substream = substream; - } else - uda134x->master_substream = substream; - - return 0; -} - -static void uda134x_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_component *component = dai->component; - struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component); - - if (uda134x->master_substream == substream) - uda134x->master_substream = uda134x->slave_substream; - - uda134x->slave_substream = NULL; -} - -static int uda134x_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_component *component = dai->component; - struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component); - unsigned int hw_params = 0; - - if (substream == uda134x->slave_substream) { - pr_debug("%s ignoring hw_params for slave substream\n", - __func__); - return 0; - } - - pr_debug("%s sysclk: %d, rate:%d\n", __func__, - uda134x->sysclk, params_rate(params)); - - /* set SYSCLK / fs ratio */ - switch (uda134x->sysclk / params_rate(params)) { - case 512: - break; - case 384: - hw_params |= (1<<4); - break; - case 256: - hw_params |= (1<<5); - break; - default: - printk(KERN_ERR "%s unsupported fs\n", __func__); - return -EINVAL; - } - - pr_debug("%s dai_fmt: %d, params_format:%d\n", __func__, - uda134x->dai_fmt, params_format(params)); - - /* set DAI format and word length */ - switch (uda134x->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - break; - case SND_SOC_DAIFMT_RIGHT_J: - switch (params_width(params)) { - case 16: - hw_params |= (1<<1); - break; - case 18: - hw_params |= (1<<2); - break; - case 20: - hw_params |= ((1<<2) | (1<<1)); - break; - default: - printk(KERN_ERR "%s unsupported format (right)\n", - __func__); - return -EINVAL; - } - break; - case SND_SOC_DAIFMT_LEFT_J: - hw_params |= (1<<3); - break; - default: - printk(KERN_ERR "%s unsupported format\n", __func__); - return -EINVAL; - } - - return regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, - STATUS0_SYSCLK_MASK | STATUS0_DAIFMT_MASK, hw_params); -} - -static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -{ - struct snd_soc_component *component = codec_dai->component; - struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component); - - pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__, - clk_id, freq, dir); - - /* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable - because the codec is slave. Of course limitations of the clock - master (the IIS controller) apply. - We'll error out on set_hw_params if it's not OK */ - if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) { - uda134x->sysclk = freq; - return 0; - } - - printk(KERN_ERR "%s unsupported sysclk\n", __func__); - return -EINVAL; -} - -static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_component *component = codec_dai->component; - struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component); - - pr_debug("%s fmt: %08X\n", __func__, fmt); - - /* codec supports only full consumer mode */ - if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) { - printk(KERN_ERR "%s unsupported clocking mode\n", __func__); - return -EINVAL; - } - - /* no support for clock inversion */ - if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) { - printk(KERN_ERR "%s unsupported clock inversion\n", __func__); - return -EINVAL; - } - - /* We can't setup DAI format here as it depends on the word bit num */ - /* so let's just store the value for later */ - uda134x->dai_fmt = fmt; - - return 0; -} - -static int uda134x_set_bias_level(struct snd_soc_component *component, - enum snd_soc_bias_level level) -{ - struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component); - struct uda134x_platform_data *pd = uda134x->pd; - pr_debug("%s bias level %d\n", __func__, level); - - switch (level) { - case SND_SOC_BIAS_ON: - break; - case SND_SOC_BIAS_PREPARE: - /* power on */ - if (pd->power) { - pd->power(1); - regcache_sync(uda134x->regmap); - } - break; - case SND_SOC_BIAS_STANDBY: - break; - case SND_SOC_BIAS_OFF: - /* power off */ - if (pd->power) { - pd->power(0); - regcache_mark_dirty(uda134x->regmap); - } - break; - } - return 0; -} - -static const char *uda134x_dsp_setting[] = {"Flat", "Minimum1", - "Minimum2", "Maximum"}; -static const char *uda134x_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; -static const char *uda134x_mixmode[] = {"Differential", "Analog1", - "Analog2", "Both"}; - -static const struct soc_enum uda134x_mixer_enum[] = { -SOC_ENUM_SINGLE(UDA134X_DATA010, 0, 0x04, uda134x_dsp_setting), -SOC_ENUM_SINGLE(UDA134X_DATA010, 3, 0x04, uda134x_deemph), -SOC_ENUM_SINGLE(UDA134X_EA010, 0, 0x04, uda134x_mixmode), -}; - -static const struct snd_kcontrol_new uda1341_snd_controls[] = { -SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1), -SOC_SINGLE("Capture Volume", UDA134X_EA010, 2, 0x07, 0), -SOC_SINGLE("Analog1 Volume", UDA134X_EA000, 0, 0x1F, 1), -SOC_SINGLE("Analog2 Volume", UDA134X_EA001, 0, 0x1F, 1), - -SOC_SINGLE("Mic Sensitivity", UDA134X_EA010, 2, 7, 0), -SOC_SINGLE("Mic Volume", UDA134X_EA101, 0, 0x1F, 0), - -SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0), -SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0), - -SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]), -SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]), -SOC_ENUM("Input Mux", uda134x_mixer_enum[2]), - -SOC_SINGLE("AGC Switch", UDA134X_EA100, 4, 1, 0), -SOC_SINGLE("AGC Target Volume", UDA134X_EA110, 0, 0x03, 1), -SOC_SINGLE("AGC Timing", UDA134X_EA110, 2, 0x07, 0), - -SOC_SINGLE("DAC +6dB Switch", UDA134X_STATUS1, 6, 1, 0), -SOC_SINGLE("ADC +6dB Switch", UDA134X_STATUS1, 5, 1, 0), -SOC_SINGLE("ADC Polarity Switch", UDA134X_STATUS1, 4, 1, 0), -SOC_SINGLE("DAC Polarity Switch", UDA134X_STATUS1, 3, 1, 0), -SOC_SINGLE("Double Speed Playback Switch", UDA134X_STATUS1, 2, 1, 0), -SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), -}; - -static const struct snd_kcontrol_new uda1340_snd_controls[] = { -SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1), - -SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0), -SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0), - -SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]), -SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]), - -SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), -}; - -static const struct snd_kcontrol_new uda1345_snd_controls[] = { -SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1), - -SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]), - -SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), -}; - -/* UDA1341 has the DAC/ADC power down in STATUS1 */ -static const struct snd_soc_dapm_widget uda1341_dapm_widgets[] = { - SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_STATUS1, 0, 0), - SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_STATUS1, 1, 0), -}; - -/* UDA1340/4/5 has the DAC/ADC pwoer down in DATA0 11 */ -static const struct snd_soc_dapm_widget uda1340_dapm_widgets[] = { - SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_DATA011, 0, 0), - SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_DATA011, 1, 0), -}; - -/* Common DAPM widgets */ -static const struct snd_soc_dapm_widget uda134x_dapm_widgets[] = { - SND_SOC_DAPM_INPUT("VINL1"), - SND_SOC_DAPM_INPUT("VINR1"), - SND_SOC_DAPM_INPUT("VINL2"), - SND_SOC_DAPM_INPUT("VINR2"), - SND_SOC_DAPM_OUTPUT("VOUTL"), - SND_SOC_DAPM_OUTPUT("VOUTR"), -}; - -static const struct snd_soc_dapm_route uda134x_dapm_routes[] = { - { "ADC", NULL, "VINL1" }, - { "ADC", NULL, "VINR1" }, - { "ADC", NULL, "VINL2" }, - { "ADC", NULL, "VINR2" }, - { "VOUTL", NULL, "DAC" }, - { "VOUTR", NULL, "DAC" }, -}; - -static const struct snd_soc_dai_ops uda134x_dai_ops = { - .startup = uda134x_startup, - .shutdown = uda134x_shutdown, - .hw_params = uda134x_hw_params, - .mute_stream = uda134x_mute, - .set_sysclk = uda134x_set_dai_sysclk, - .set_fmt = uda134x_set_dai_fmt, - .no_capture_mute = 1, -}; - -static struct snd_soc_dai_driver uda134x_dai = { - .name = "uda134x-hifi", - /* playback capabilities */ - .playback = { - .stream_name = "Playback", - .channels_min = 1, - .channels_max = 2, - .rates = UDA134X_RATES, - .formats = UDA134X_FORMATS, - }, - /* capture capabilities */ - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = UDA134X_RATES, - .formats = UDA134X_FORMATS, - }, - /* pcm operations */ - .ops = &uda134x_dai_ops, -}; - -static int uda134x_soc_probe(struct snd_soc_component *component) -{ - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); - struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component); - struct uda134x_platform_data *pd = uda134x->pd; - const struct snd_soc_dapm_widget *widgets; - unsigned int num_widgets; - int ret; - - printk(KERN_INFO "UDA134X SoC Audio Codec\n"); - - switch (pd->model) { - case UDA134X_UDA1340: - case UDA134X_UDA1341: - case UDA134X_UDA1344: - case UDA134X_UDA1345: - break; - default: - printk(KERN_ERR "UDA134X SoC codec: " - "unsupported model %d\n", - pd->model); - return -EINVAL; - } - - if (pd->power) - pd->power(1); - - uda134x_reset(component); - - if (pd->model == UDA134X_UDA1341) { - widgets = uda1341_dapm_widgets; - num_widgets = ARRAY_SIZE(uda1341_dapm_widgets); - } else { - widgets = uda1340_dapm_widgets; - num_widgets = ARRAY_SIZE(uda1340_dapm_widgets); - } - - ret = snd_soc_dapm_new_controls(dapm, widgets, num_widgets); - if (ret) { - printk(KERN_ERR "%s failed to register dapm controls: %d", - __func__, ret); - return ret; - } - - switch (pd->model) { - case UDA134X_UDA1340: - case UDA134X_UDA1344: - ret = snd_soc_add_component_controls(component, uda1340_snd_controls, - ARRAY_SIZE(uda1340_snd_controls)); - break; - case UDA134X_UDA1341: - ret = snd_soc_add_component_controls(component, uda1341_snd_controls, - ARRAY_SIZE(uda1341_snd_controls)); - break; - case UDA134X_UDA1345: - ret = snd_soc_add_component_controls(component, uda1345_snd_controls, - ARRAY_SIZE(uda1345_snd_controls)); - break; - default: - printk(KERN_ERR "%s unknown codec type: %d", - __func__, pd->model); - return -EINVAL; - } - - if (ret < 0) { - printk(KERN_ERR "UDA134X: failed to register controls\n"); - return ret; - } - - return 0; -} - -static const struct snd_soc_component_driver soc_component_dev_uda134x = { - .probe = uda134x_soc_probe, - .set_bias_level = uda134x_set_bias_level, - .dapm_widgets = uda134x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets), - .dapm_routes = uda134x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes), - .suspend_bias_off = 1, - .idle_bias_on = 1, - .use_pmdown_time = 1, - .endianness = 1, -}; - -static const struct regmap_config uda134x_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .max_register = UDA134X_DATA1, - .reg_defaults = uda134x_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(uda134x_reg_defaults), - .cache_type = REGCACHE_RBTREE, - - .reg_write = uda134x_regmap_write, -}; - -static int uda134x_codec_probe(struct platform_device *pdev) -{ - struct uda134x_platform_data *pd = pdev->dev.platform_data; - struct uda134x_priv *uda134x; - int ret; - - if (!pd) { - dev_err(&pdev->dev, "Missing L3 bitbang function\n"); - return -ENODEV; - } - - uda134x = devm_kzalloc(&pdev->dev, sizeof(*uda134x), GFP_KERNEL); - if (!uda134x) - return -ENOMEM; - - uda134x->pd = pd; - platform_set_drvdata(pdev, uda134x); - - if (pd->l3.use_gpios) { - ret = l3_set_gpio_ops(&pdev->dev, &uda134x->pd->l3); - if (ret < 0) - return ret; - } - - uda134x->regmap = devm_regmap_init(&pdev->dev, NULL, pd, - &uda134x_regmap_config); - if (IS_ERR(uda134x->regmap)) - return PTR_ERR(uda134x->regmap); - - return devm_snd_soc_register_component(&pdev->dev, - &soc_component_dev_uda134x, &uda134x_dai, 1); -} - -static struct platform_driver uda134x_codec_driver = { - .driver = { - .name = "uda134x-codec", - }, - .probe = uda134x_codec_probe, -}; - -module_platform_driver(uda134x_codec_driver); - -MODULE_DESCRIPTION("UDA134X ALSA soc codec driver"); -MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin "); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/uda134x.h b/sound/soc/codecs/uda134x.h deleted file mode 100644 index 664618c2571c..000000000000 --- a/sound/soc/codecs/uda134x.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _UDA134X_CODEC_H -#define _UDA134X_CODEC_H - -#define UDA134X_L3ADDR 5 -#define UDA134X_DATA0_ADDR ((UDA134X_L3ADDR << 2) | 0) -#define UDA134X_DATA1_ADDR ((UDA134X_L3ADDR << 2) | 1) -#define UDA134X_STATUS_ADDR ((UDA134X_L3ADDR << 2) | 2) - -#define UDA134X_EXTADDR_PREFIX 0xC0 -#define UDA134X_EXTDATA_PREFIX 0xE0 - -/* UDA134X registers */ -#define UDA134X_EA000 0 -#define UDA134X_EA001 1 -#define UDA134X_EA010 2 -#define UDA134X_EA011 3 -#define UDA134X_EA100 4 -#define UDA134X_EA101 5 -#define UDA134X_EA110 6 -#define UDA134X_EA111 7 -#define UDA134X_STATUS0 8 -#define UDA134X_STATUS1 9 -#define UDA134X_DATA000 10 -#define UDA134X_DATA001 11 -#define UDA134X_DATA010 12 -#define UDA134X_DATA011 13 -#define UDA134X_DATA1 14 - -#define STATUS0_DAIFMT_MASK (~(7<<1)) -#define STATUS0_SYSCLK_MASK (~(3<<4)) - -#endif -- cgit v1.2.3 From 014ee0692f29da8b08fed5da0fa14e04698a50f7 Mon Sep 17 00:00:00 2001 From: Seven Lee Date: Wed, 23 Aug 2023 15:12:44 +0800 Subject: ASoC: nau8821: Improve AMIC recording performance. Since the hardware may be designed as a single-ended input, the headset mic record only supports single-ended input on the left side. This patch will enhance microphone recording performance for single-end. Signed-off-by: Seven Lee Link: https://lore.kernel.org/r/20230823071244.1861487-2-wtli@nuvoton.com Signed-off-by: Mark Brown --- sound/soc/codecs/nau8821.c | 42 +++++++++++++++++++++++++++++++++++++++++- sound/soc/codecs/nau8821.h | 25 +++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c index ca6beb2d2649..f307374834b5 100644 --- a/sound/soc/codecs/nau8821.c +++ b/sound/soc/codecs/nau8821.c @@ -624,6 +624,36 @@ static int system_clock_control(struct snd_soc_dapm_widget *w, return 0; } +static int nau8821_left_fepga_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component); + + if (!nau8821->left_input_single_end) + return 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(nau8821->regmap, NAU8821_R77_FEPGA, + NAU8821_ACDC_CTRL_MASK | NAU8821_FEPGA_MODEL_MASK, + NAU8821_ACDC_VREF_MICN | NAU8821_FEPGA_MODEL_AAF); + regmap_update_bits(nau8821->regmap, NAU8821_R76_BOOST, + NAU8821_HP_BOOST_DISCHRG_EN, NAU8821_HP_BOOST_DISCHRG_EN); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(nau8821->regmap, NAU8821_R77_FEPGA, + NAU8821_ACDC_CTRL_MASK | NAU8821_FEPGA_MODEL_MASK, 0); + regmap_update_bits(nau8821->regmap, NAU8821_R76_BOOST, + NAU8821_HP_BOOST_DISCHRG_EN, 0); + break; + default: + break; + } + + return 0; +} + static const struct snd_soc_dapm_widget nau8821_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("System Clock", SND_SOC_NOPM, 0, 0, system_clock_control, SND_SOC_DAPM_POST_PMD), @@ -635,8 +665,10 @@ static const struct snd_soc_dapm_widget nau8821_dapm_widgets[] = { NAU8821_POWERUP_ADCL_SFT, 0), SND_SOC_DAPM_ADC("ADCR Power", NULL, NAU8821_R72_ANALOG_ADC_2, NAU8821_POWERUP_ADCR_SFT, 0), + /* single-ended design only on the left */ SND_SOC_DAPM_PGA_S("Frontend PGA L", 1, NAU8821_R7F_POWER_UP_CONTROL, - NAU8821_PUP_PGA_L_SFT, 0, NULL, 0), + NAU8821_PUP_PGA_L_SFT, 0, nau8821_left_fepga_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_S("Frontend PGA R", 1, NAU8821_R7F_POWER_UP_CONTROL, NAU8821_PUP_PGA_R_SFT, 0, NULL, 0), SND_SOC_DAPM_PGA_S("ADCL Digital path", 0, NAU8821_R01_ENA_CTRL, @@ -1677,6 +1709,8 @@ static int nau8821_read_device_properties(struct device *dev, "nuvoton,jkdet-pull-up"); nau8821->key_enable = device_property_read_bool(dev, "nuvoton,key-enable"); + nau8821->left_input_single_end = device_property_read_bool(dev, + "nuvoton,left-input-single-end"); ret = device_property_read_u32(dev, "nuvoton,jkdet-polarity", &nau8821->jkdet_polarity); if (ret) @@ -1760,6 +1794,12 @@ static void nau8821_init_regs(struct nau8821 *nau8821) NAU8821_ADC_SYNC_DOWN_MASK, NAU8821_ADC_SYNC_DOWN_64); regmap_update_bits(regmap, NAU8821_R2C_DAC_CTRL1, NAU8821_DAC_OVERSAMPLE_MASK, NAU8821_DAC_OVERSAMPLE_64); + if (nau8821->left_input_single_end) { + regmap_update_bits(regmap, NAU8821_R6B_PGA_MUTE, + NAU8821_MUTE_MICNL_EN, NAU8821_MUTE_MICNL_EN); + regmap_update_bits(regmap, NAU8821_R74_MIC_BIAS, + NAU8821_MICBIAS_LOWNOISE_EN, NAU8821_MICBIAS_LOWNOISE_EN); + } } static int nau8821_setup_irq(struct nau8821 *nau8821) diff --git a/sound/soc/codecs/nau8821.h b/sound/soc/codecs/nau8821.h index d962293c218e..00a888ed07ce 100644 --- a/sound/soc/codecs/nau8821.h +++ b/sound/soc/codecs/nau8821.h @@ -433,6 +433,14 @@ #define NAU8821_DAC_CAPACITOR_MSB (0x1 << 1) #define NAU8821_DAC_CAPACITOR_LSB 0x1 +/* MUTE_MIC_L_N (0x6b) */ +#define NAU8821_MUTE_MICNL_SFT 5 +#define NAU8821_MUTE_MICNL_EN (0x1 << NAU8821_MUTE_MICNL_SFT) +#define NAU8821_MUTE_MICNR_SFT 4 +#define NAU8821_MUTE_MICNR_EN (0x1 << NAU8821_MUTE_MICNR_SFT) +#define NAU8821_MUTE_MICRP_SFT 2 +#define NAU8821_MUTE_MICRP_EN (0x1 << NAU8821_MUTE_MICRP_SFT) + /* ANALOG_ADC_1 (0x71) */ #define NAU8821_MICDET_EN_SFT 0 #define NAU8821_MICDET_MASK 0x1 @@ -463,23 +471,39 @@ /* MIC_BIAS (0x74) */ #define NAU8821_MICBIAS_JKR2 (0x1 << 12) +#define NAU8821_MICBIAS_LOWNOISE_SFT 10 +#define NAU8821_MICBIAS_LOWNOISE_EN (0x1 << NAU8821_MICBIAS_LOWNOISE_SFT) #define NAU8821_MICBIAS_POWERUP_SFT 8 +#define NAU8821_MICBIAS_POWERUP_EN (0x1 << NAU8821_MICBIAS_POWERUP_SFT) #define NAU8821_MICBIAS_VOLTAGE_SFT 0 #define NAU8821_MICBIAS_VOLTAGE_MASK 0x7 /* BOOST (0x76) */ #define NAU8821_PRECHARGE_DIS (0x1 << 13) #define NAU8821_GLOBAL_BIAS_EN (0x1 << 12) +#define NAU8821_HP_BOOST_DISCHRG_SFT 11 +#define NAU8821_HP_BOOST_DISCHRG_EN (0x1 << NAU8821_HP_BOOST_DISCHRG_SFT) #define NAU8821_HP_BOOST_DIS_SFT 9 #define NAU8821_HP_BOOST_DIS (0x1 << NAU8821_HP_BOOST_DIS_SFT) #define NAU8821_HP_BOOST_G_DIS (0x1 << 8) #define NAU8821_SHORT_SHUTDOWN_EN (0x1 << 6) /* FEPGA (0x77) */ +#define NAU8821_ACDC_CTRL_SFT 14 +#define NAU8821_ACDC_CTRL_MASK (0x3 << NAU8821_ACDC_CTRL_SFT) +#define NAU8821_ACDC_VREF_MICP (0x1 << NAU8821_ACDC_CTRL_SFT) +#define NAU8821_ACDC_VREF_MICN (0x2 << NAU8821_ACDC_CTRL_SFT) #define NAU8821_FEPGA_MODEL_SFT 4 #define NAU8821_FEPGA_MODEL_MASK (0xf << NAU8821_FEPGA_MODEL_SFT) +#define NAU8821_FEPGA_MODEL_AAF (0x1 << NAU8821_FEPGA_MODEL_SFT) +#define NAU8821_FEPGA_MODEL_DIS (0x2 << NAU8821_FEPGA_MODEL_SFT) +#define NAU8821_FEPGA_MODEL_IMP12K (0x8 << NAU8821_FEPGA_MODEL_SFT) #define NAU8821_FEPGA_MODER_SFT 0 #define NAU8821_FEPGA_MODER_MASK 0xf +#define NAU8821_FEPGA_MODER_AAF 0x1 +#define NAU8821_FEPGA_MODER_DIS 0x2 +#define NAU8821_FEPGA_MODER_IMP12K 0x8 + /* PGA_GAIN (0x7e) */ #define NAU8821_PGA_GAIN_L_SFT 8 @@ -543,6 +567,7 @@ struct nau8821 { bool jkdet_enable; bool jkdet_pull_enable; bool jkdet_pull_up; + bool left_input_single_end; int jkdet_polarity; int jack_insert_debounce; int jack_eject_debounce; -- cgit v1.2.3 From bd4cee2fdf69b56c2bf3e7ec7c2e12b81e08005c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 23:50:31 +0000 Subject: ASoC: rsnd: enable clk_i approximate rate usage Basically Renesas sound ADG is assuming that it has accurately divisible input clock. But sometimes / some board might not have it. The clk_i from CPG is used for such case. It can't calculate accurate division, but can be used as approximate rate. This patch enable clk_i for such case. Signed-off-by: Kuninori Morimoto Acked-by: Adnan Ali Tested-by: Vincenzo De Michele Tested-by: Patrick Keil Link: https://lore.kernel.org/r/87msyizlfd.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 0b8926600d90..c490d43aa18c 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -491,6 +491,7 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) unsigned long req_Hz[ADG_HZ_SIZE]; int clkout_size; int i, req_size; + int approximate = 0; const char *parent_clk_name = NULL; const char * const *clkout_name; int brg_table[] = { @@ -537,6 +538,26 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) * rsnd_adg_ssi_clk_try_start() * rsnd_ssi_master_clk_start() */ + + /* + * [APPROXIMATE] + * + * clk_i (internal clock) can't create accurate rate, it will be approximate rate. + * + * + * + * clk_i needs x2 of required maximum rate. + * see + * - Minimum division of BRRA/BRRB + * - rsnd_ssi_clk_query() + * + * Sample Settings for TDM 8ch, 32bit width + * + * 8(ch) x 32(bit) x 44100(Hz) x 2 = 22579200 + * 8(ch) x 32(bit) x 48000(Hz) x 2 = 24576000 + * + * clock-frequency = <22579200 24576000>; + */ for_each_rsnd_clkin(clk, adg, i) { rate = clk_get_rate(clk); @@ -544,6 +565,10 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) continue; /* BRGA */ + + if (i == CLKI) + /* see [APPROXIMATE] */ + rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_441]) * req_Hz[ADG_HZ_441]; if (!adg->brg_rate[ADG_HZ_441] && (0 == rate % 44100)) { div = 6; if (req_Hz[ADG_HZ_441]) @@ -555,10 +580,16 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) ckr |= brg_table[i] << 20; if (req_Hz[ADG_HZ_441]) parent_clk_name = __clk_get_name(clk); + if (i == CLKI) + approximate = 1; } } /* BRGB */ + + if (i == CLKI) + /* see [APPROXIMATE] */ + rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_48]) * req_Hz[ADG_HZ_48]; if (!adg->brg_rate[ADG_HZ_48] && (0 == rate % 48000)) { div = 6; if (req_Hz[ADG_HZ_48]) @@ -570,10 +601,15 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) ckr |= brg_table[i] << 16; if (req_Hz[ADG_HZ_48]) parent_clk_name = __clk_get_name(clk); + if (i == CLKI) + approximate = 1; } } } + if (approximate) + dev_info(dev, "It uses CLK_I as approximate rate"); + clkout_name = clkout_name_gen2; clkout_size = ARRAY_SIZE(clkout_name_gen2); if (rsnd_is_gen4(priv)) -- cgit v1.2.3 From d059cd40aea6deae716bc6588f24e7b6b421f822 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 23:50:36 +0000 Subject: ASoC: rsnd: setup clock-out only when all conditions are right Current adg.c doesn't assume that requested clock out divide condition doesn't match. In such case, it will indicate strange message, and will register NULL clock, etc. It is just a DT setting miss, but is confusable. This patch check all conditions for it. Reported-by: Vincenzo De Michele Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87lee2zlf7.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index c490d43aa18c..919339b75a25 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -607,6 +607,10 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) } } + if (!(adg->brg_rate[ADG_HZ_48] && req_Hz[ADG_HZ_48]) && + !(adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441])) + goto rsnd_adg_get_clkout_end; + if (approximate) dev_info(dev, "It uses CLK_I as approximate rate"); -- cgit v1.2.3 From 80d4984f38631b1157dd51214ccd3d2fc6d56fbb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 23:50:48 +0000 Subject: ASoC: rsnd: tidyup brga/brgb default value default value for brga/brgb should be 0xff instead of 0x2. This patch tidyup it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87jztmzlew.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 919339b75a25..4acfb92e44f3 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -502,8 +502,8 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) }; ckr = 0; - brga = 2; /* default 1/6 */ - brgb = 2; /* default 1/6 */ + brga = 0xff; /* default */ + brgb = 0xff; /* default */ /* * ADG supports BRRA/BRRB output only -- cgit v1.2.3 From ab0233747f9cf6ba6c6d0c60c1e0e2533db00302 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 23:50:54 +0000 Subject: ASoC: rsnd: remove default division of clock out Current adg has default division for BRRA/BRRB, but it was created at very beginning of the driver implementation, and is now an unnecessary settings. Because it has this default division, unexpected clockout might be selected. For example if it requests only 44.1kHz base clockout, unrequested 48kHz base clockout also will be selected. This patch remove default division of clock out Reported-by: Vincenzo De Michele Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87il96zlep.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 4acfb92e44f3..25d3316a50d1 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -485,7 +485,6 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) struct device_node *np = dev->of_node; struct property *prop; u32 ckr, brgx, brga, brgb; - u32 rate, div; u32 req_rate[ADG_HZ_SIZE] = {}; uint32_t count = 0; unsigned long req_Hz[ADG_HZ_SIZE]; @@ -559,6 +558,8 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) * clock-frequency = <22579200 24576000>; */ for_each_rsnd_clkin(clk, adg, i) { + u32 rate, div; + rate = clk_get_rate(clk); if (0 == rate) /* not used */ @@ -569,10 +570,8 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) if (i == CLKI) /* see [APPROXIMATE] */ rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_441]) * req_Hz[ADG_HZ_441]; - if (!adg->brg_rate[ADG_HZ_441] && (0 == rate % 44100)) { - div = 6; - if (req_Hz[ADG_HZ_441]) - div = rate / req_Hz[ADG_HZ_441]; + if (!adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441] && (0 == rate % 44100)) { + div = rate / req_Hz[ADG_HZ_441]; brgx = rsnd_adg_calculate_brgx(div); if (BRRx_MASK(brgx) == brgx) { brga = brgx; @@ -590,10 +589,8 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) if (i == CLKI) /* see [APPROXIMATE] */ rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_48]) * req_Hz[ADG_HZ_48]; - if (!adg->brg_rate[ADG_HZ_48] && (0 == rate % 48000)) { - div = 6; - if (req_Hz[ADG_HZ_48]) - div = rate / req_Hz[ADG_HZ_48]; + if (!adg->brg_rate[ADG_HZ_48] && req_Hz[ADG_HZ_48] && (0 == rate % 48000)) { + div = rate / req_Hz[ADG_HZ_48]; brgx = rsnd_adg_calculate_brgx(div); if (BRRx_MASK(brgx) == brgx) { brgb = brgx; -- cgit v1.2.3 From 4acdf9aedd5624aae9335d70a9324d5aaec4034d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 23:51:02 +0000 Subject: ASoC: rsnd: setup BRGCKR/BRRA/BRRB on rsnd_adg_clk_control() Current adg.c will configure BRGCKR/BRRA/BRRB to output clock when it start sound. OTAH, rsnd_adg_clk_enable() will enables clk_a/b/c when driver was probed. But it is strange, these should be set in the same time. This patch fixup it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87h6oqzlei.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 25d3316a50d1..230c48648af3 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -358,8 +358,6 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) ckr = 0x80000000; /* BRGB output = 48kHz */ rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr | ckr); - rsnd_mod_write(adg_mod, BRRA, adg->brga); - rsnd_mod_write(adg_mod, BRRB, adg->brgb); dev_dbg(dev, "CLKOUT is based on BRG%c (= %dHz)\n", (ckr) ? 'B' : 'A', @@ -372,9 +370,16 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) { struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct rsnd_mod *adg_mod = rsnd_mod_get(adg); struct clk *clk; int i; + if (enable) { + rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr); + rsnd_mod_write(adg_mod, BRRA, adg->brga); + rsnd_mod_write(adg_mod, BRRB, adg->brgb); + } + for_each_rsnd_clkin(clk, adg, i) { if (enable) { clk_prepare_enable(clk); -- cgit v1.2.3 From d6d6c513f5d2d14651336fb4e30f097822b46f29 Mon Sep 17 00:00:00 2001 From: Xingyu Wu Date: Mon, 21 Aug 2023 22:41:48 +0800 Subject: ASoC: dwc: Use ops to get platform data Use of_device_get_match_data() to get platform data. Signed-off-by: Xingyu Wu Link: https://lore.kernel.org/r/20230821144151.207339-3-xingyu.wu@starfivetech.com Signed-off-by: Mark Brown --- sound/soc/dwc/dwc-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index 0a4698008d64..e70d41d57dfd 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -691,7 +691,7 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, static int dw_i2s_probe(struct platform_device *pdev) { - const struct i2s_platform_data *pdata = pdev->dev.platform_data; + const struct i2s_platform_data *pdata = of_device_get_match_data(&pdev->dev); struct dw_i2s_dev *dev; struct resource *res; int ret, irq; -- cgit v1.2.3 From 52ea7c0543f8a39da8a6fc17a5ab36b7b58d5431 Mon Sep 17 00:00:00 2001 From: Xingyu Wu Date: Mon, 21 Aug 2023 22:41:49 +0800 Subject: ASoC: dwc: i2s: Add StarFive JH7110 SoC support Add StarFive JH7110(TX0/TX1/RX channels) SoC support in the designware I2S driver and a flag to check if it is on the JH7110 SoC. These channels need to enable clocks, resets and syscon register on the JH7110 SoC. So add init ops in platform data for the JH7110 SoC to do this. Their resets should be deassert before changing the parent of clocks so these are done in the init ops of platform data. The I2S controllers use DMA controller by platform data on the JH7110 and their settings about snd_dmaengine_dai_dma_data() should be added in the dw_configure_dai_by_pd(). And use dmaengine PCM registration if these do not have IRQ on the JH7110 SoC. Signed-off-by: Xingyu Wu Link: https://lore.kernel.org/r/20230821144151.207339-4-xingyu.wu@starfivetech.com Signed-off-by: Mark Brown --- sound/soc/dwc/dwc-i2s.c | 304 ++++++++++++++++++++++++++++++++++++++++++++---- sound/soc/dwc/local.h | 1 + 2 files changed, 284 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index e70d41d57dfd..5ab1b3eb2d28 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -198,7 +199,8 @@ static void i2s_start(struct dw_i2s_dev *dev, else i2s_write_reg(dev->i2s_base, IRER, 1); - if (dev->use_pio) + /* I2S needs to enable IRQ to make a handshake with DMAC on the JH7110 SoC */ + if (dev->use_pio || dev->is_jh7110) i2s_enable_irqs(dev, substream->stream, config->chan_nr); else i2s_enable_dma(dev, substream->stream); @@ -216,7 +218,7 @@ static void i2s_stop(struct dw_i2s_dev *dev, else i2s_write_reg(dev->i2s_base, IRER, 0); - if (dev->use_pio) + if (dev->use_pio || dev->is_jh7110) i2s_disable_irqs(dev, substream->stream, 8); else i2s_disable_dma(dev, substream->stream); @@ -227,6 +229,21 @@ static void i2s_stop(struct dw_i2s_dev *dev, } } +static int dw_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); + + if (dev->is_jh7110) { + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai_link *dai_link = rtd->dai_link; + + dai_link->trigger_stop = SND_SOC_TRIGGER_ORDER_LDC; + } + + return 0; +} + static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) { u32 ch_reg; @@ -453,6 +470,7 @@ static int dw_i2s_dai_probe(struct snd_soc_dai *dai) static const struct snd_soc_dai_ops dw_i2s_dai_ops = { .probe = dw_i2s_dai_probe, + .startup = dw_i2s_startup, .hw_params = dw_i2s_hw_params, .prepare = dw_i2s_prepare, .trigger = dw_i2s_trigger, @@ -637,17 +655,39 @@ static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev, if (dev->quirks & DW_I2S_QUIRK_16BIT_IDX_OVERRIDE) idx = 1; - /* Set DMA slaves info */ - dev->play_dma_data.pd.data = pdata->play_dma_data; - dev->capture_dma_data.pd.data = pdata->capture_dma_data; - dev->play_dma_data.pd.addr = res->start + I2S_TXDMA; - dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA; - dev->play_dma_data.pd.max_burst = 16; - dev->capture_dma_data.pd.max_burst = 16; - dev->play_dma_data.pd.addr_width = bus_widths[idx]; - dev->capture_dma_data.pd.addr_width = bus_widths[idx]; - dev->play_dma_data.pd.filter = pdata->filter; - dev->capture_dma_data.pd.filter = pdata->filter; + + if (dev->is_jh7110) { + /* Use platform data and snd_dmaengine_dai_dma_data struct at the same time */ + u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2); + u32 idx2; + + if (COMP1_TX_ENABLED(comp1)) { + idx2 = COMP1_TX_WORDSIZE_0(comp1); + dev->play_dma_data.dt.addr = res->start + I2S_TXDMA; + dev->play_dma_data.dt.fifo_size = dev->fifo_th * 2 * + (fifo_width[idx2]) >> 8; + dev->play_dma_data.dt.maxburst = 16; + } + if (COMP1_RX_ENABLED(comp1)) { + idx2 = COMP2_RX_WORDSIZE_0(comp2); + dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA; + dev->capture_dma_data.dt.fifo_size = dev->fifo_th * 2 * + (fifo_width[idx2] >> 8); + dev->capture_dma_data.dt.maxburst = 16; + } + } else { + /* Set DMA slaves info */ + dev->play_dma_data.pd.data = pdata->play_dma_data; + dev->capture_dma_data.pd.data = pdata->capture_dma_data; + dev->play_dma_data.pd.addr = res->start + I2S_TXDMA; + dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA; + dev->play_dma_data.pd.max_burst = 16; + dev->capture_dma_data.pd.max_burst = 16; + dev->play_dma_data.pd.addr_width = bus_widths[idx]; + dev->capture_dma_data.pd.addr_width = bus_widths[idx]; + dev->play_dma_data.pd.filter = pdata->filter; + dev->capture_dma_data.pd.filter = pdata->filter; + } return 0; } @@ -689,6 +729,190 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, } +/* clocks initialization with master mode on JH7110 SoC */ +static int jh7110_i2s_crg_master_init(struct dw_i2s_dev *dev) +{ + static struct clk_bulk_data clks[] = { + { .id = "mclk" }, + { .id = "mclk_ext" }, + { .id = "mclk_inner" }, + { .id = "apb" }, + { .id = "i2sclk" }, + }; + struct reset_control *resets = devm_reset_control_array_get_exclusive(dev->dev); + int ret; + struct clk *pclk; + struct clk *bclk_mst; + struct clk *mclk; + struct clk *mclk_ext; + struct clk *mclk_inner; + + if (IS_ERR(resets)) + return dev_err_probe(dev->dev, PTR_ERR(resets), "failed to get i2s resets\n"); + + ret = clk_bulk_get(dev->dev, ARRAY_SIZE(clks), clks); + if (ret) + return dev_err_probe(dev->dev, ret, "failed to get i2s clocks\n"); + + mclk = clks[0].clk; + mclk_ext = clks[1].clk; + mclk_inner = clks[2].clk; + pclk = clks[3].clk; + bclk_mst = clks[4].clk; + + ret = clk_prepare_enable(pclk); + if (ret) + goto exit; + + /* Use inner mclk first and avoid uninitialized gpio for external mclk */ + ret = clk_set_parent(mclk, mclk_inner); + if (ret) + goto err_dis_pclk; + + ret = clk_prepare_enable(bclk_mst); + if (ret) + goto err_dis_pclk; + + /* deassert resets before set clock parent */ + ret = reset_control_deassert(resets); + if (ret) + goto err_dis_all; + + /* external clock (12.288MHz) for Audio */ + ret = clk_set_parent(mclk, mclk_ext); + if (ret) + goto err_dis_all; + + /* i2sclk will be got and enabled repeatedly later and should be disabled now. */ + clk_disable_unprepare(bclk_mst); + clk_bulk_put(ARRAY_SIZE(clks), clks); + dev->is_jh7110 = true; + + return 0; + +err_dis_all: + clk_disable_unprepare(bclk_mst); +err_dis_pclk: + clk_disable_unprepare(pclk); +exit: + clk_bulk_put(ARRAY_SIZE(clks), clks); + return ret; +} + +/* clocks initialization with slave mode on JH7110 SoC */ +static int jh7110_i2s_crg_slave_init(struct dw_i2s_dev *dev) +{ + static struct clk_bulk_data clks[] = { + { .id = "mclk" }, + { .id = "mclk_ext" }, + { .id = "apb" }, + { .id = "bclk_ext" }, + { .id = "lrck_ext" }, + { .id = "bclk" }, + { .id = "lrck" }, + { .id = "mclk_inner" }, + { .id = "i2sclk" }, + }; + struct reset_control *resets = devm_reset_control_array_get_exclusive(dev->dev); + int ret; + struct clk *pclk; + struct clk *bclk_mst; + struct clk *bclk_ext; + struct clk *lrck_ext; + struct clk *bclk; + struct clk *lrck; + struct clk *mclk; + struct clk *mclk_ext; + struct clk *mclk_inner; + + if (IS_ERR(resets)) + return dev_err_probe(dev->dev, PTR_ERR(resets), "failed to get i2s resets\n"); + + ret = clk_bulk_get(dev->dev, ARRAY_SIZE(clks), clks); + if (ret) + return dev_err_probe(dev->dev, ret, "failed to get i2s clocks\n"); + + mclk = clks[0].clk; + mclk_ext = clks[1].clk; + pclk = clks[2].clk; + bclk_ext = clks[3].clk; + lrck_ext = clks[4].clk; + bclk = clks[5].clk; + lrck = clks[6].clk; + mclk_inner = clks[7].clk; + bclk_mst = clks[8].clk; + + ret = clk_prepare_enable(pclk); + if (ret) + goto exit; + + ret = clk_set_parent(mclk, mclk_inner); + if (ret) + goto err_dis_pclk; + + ret = clk_prepare_enable(bclk_mst); + if (ret) + goto err_dis_pclk; + + ret = reset_control_deassert(resets); + if (ret) + goto err_dis_all; + + /* The sources of BCLK and LRCK are the external codec. */ + ret = clk_set_parent(bclk, bclk_ext); + if (ret) + goto err_dis_all; + + ret = clk_set_parent(lrck, lrck_ext); + if (ret) + goto err_dis_all; + + ret = clk_set_parent(mclk, mclk_ext); + if (ret) + goto err_dis_all; + + /* The i2sclk will be got and enabled repeatedly later and should be disabled now. */ + clk_disable_unprepare(bclk_mst); + clk_bulk_put(ARRAY_SIZE(clks), clks); + dev->is_jh7110 = true; + + return 0; + +err_dis_all: + clk_disable_unprepare(bclk_mst); +err_dis_pclk: + clk_disable_unprepare(pclk); +exit: + clk_bulk_put(ARRAY_SIZE(clks), clks); + return ret; +} + +/* Special syscon initialization about RX channel with slave mode on JH7110 SoC */ +static int jh7110_i2srx_crg_init(struct dw_i2s_dev *dev) +{ + struct regmap *regmap; + unsigned int args[2]; + + regmap = syscon_regmap_lookup_by_phandle_args(dev->dev->of_node, + "starfive,syscon", + 2, args); + if (IS_ERR(regmap)) + return dev_err_probe(dev->dev, PTR_ERR(regmap), "getting the regmap failed\n"); + + /* Enable I2Srx with syscon register, args[0]: offset, args[1]: mask */ + regmap_update_bits(regmap, args[0], args[1], args[1]); + + return jh7110_i2s_crg_slave_init(dev); +} + +static int jh7110_i2stx0_clk_cfg(struct i2s_clk_config_data *config) +{ + struct dw_i2s_dev *dev = container_of(config, struct dw_i2s_dev, config); + u32 bclk_rate = config->sample_rate * 64; + + return clk_set_rate(dev->clk, bclk_rate); +} + static int dw_i2s_probe(struct platform_device *pdev) { const struct i2s_platform_data *pdata = of_device_get_match_data(&pdev->dev); @@ -712,15 +936,25 @@ static int dw_i2s_probe(struct platform_device *pdev) if (IS_ERR(dev->i2s_base)) return PTR_ERR(dev->i2s_base); - dev->reset = devm_reset_control_array_get_optional_shared(&pdev->dev); - if (IS_ERR(dev->reset)) - return PTR_ERR(dev->reset); + dev->dev = &pdev->dev; + dev->is_jh7110 = false; + if (pdata) { + if (pdata->i2s_pd_init) { + ret = pdata->i2s_pd_init(dev); + if (ret) + return ret; + } + } - ret = reset_control_deassert(dev->reset); - if (ret) - return ret; + if (!dev->is_jh7110) { + dev->reset = devm_reset_control_array_get_optional_shared(&pdev->dev); + if (IS_ERR(dev->reset)) + return PTR_ERR(dev->reset); - dev->dev = &pdev->dev; + ret = reset_control_deassert(dev->reset); + if (ret) + return ret; + } irq = platform_get_irq_optional(pdev, 0); if (irq >= 0) { @@ -779,7 +1013,7 @@ static int dw_i2s_probe(struct platform_device *pdev) goto err_clk_disable; } - if (!pdata) { + if (!pdata || dev->is_jh7110) { if (irq >= 0) { ret = dw_pcm_register(pdev); dev->use_pio = true; @@ -821,8 +1055,36 @@ static void dw_i2s_remove(struct platform_device *pdev) } #ifdef CONFIG_OF +static const struct i2s_platform_data jh7110_i2stx0_data = { + .cap = DWC_I2S_PLAY | DW_I2S_MASTER, + .channel = TWO_CHANNEL_SUPPORT, + .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, + .snd_rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000, + .i2s_clk_cfg = jh7110_i2stx0_clk_cfg, + .i2s_pd_init = jh7110_i2s_crg_master_init, +}; + +static const struct i2s_platform_data jh7110_i2stx1_data = { + .cap = DWC_I2S_PLAY | DW_I2S_SLAVE, + .channel = TWO_CHANNEL_SUPPORT, + .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, + .snd_rates = SNDRV_PCM_RATE_8000_192000, + .i2s_pd_init = jh7110_i2s_crg_slave_init, +}; + +static const struct i2s_platform_data jh7110_i2srx_data = { + .cap = DWC_I2S_RECORD | DW_I2S_SLAVE, + .channel = TWO_CHANNEL_SUPPORT, + .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, + .snd_rates = SNDRV_PCM_RATE_8000_192000, + .i2s_pd_init = jh7110_i2srx_crg_init, +}; + static const struct of_device_id dw_i2s_of_match[] = { { .compatible = "snps,designware-i2s", }, + { .compatible = "starfive,jh7110-i2stx0", .data = &jh7110_i2stx0_data, }, + { .compatible = "starfive,jh7110-i2stx1", .data = &jh7110_i2stx1_data,}, + { .compatible = "starfive,jh7110-i2srx", .data = &jh7110_i2srx_data,}, {}, }; diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h index 4ce96bac2f39..dce88c9ad5f3 100644 --- a/sound/soc/dwc/local.h +++ b/sound/soc/dwc/local.h @@ -123,6 +123,7 @@ struct dw_i2s_dev { u32 fifo_th; u32 l_reg; u32 r_reg; + bool is_jh7110; /* Flag for StarFive JH7110 SoC */ /* data related to DMA transfers b/w i2s and DMAC */ union dw_i2s_snd_dma_data play_dma_data; -- cgit v1.2.3 From ea2cb26a98378b60be8e952eca801130c1da4c73 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 23 Aug 2023 00:19:42 +0000 Subject: ASoC: audio-graph-card2: add comment for format property We don't need to have "format" property on DT any more if CPU/Codec driver has .auto_selectable_formats settings on snd_soc_dai_ops. The sample dtsi doesn't have it. To avoid user confusion, this patch indicates it on comment. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87edjuzk2p.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card2-custom-sample.dtsi | 7 +++++++ sound/soc/generic/audio-graph-card2.c | 12 ++++++++++++ 2 files changed, 19 insertions(+) (limited to 'sound') diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi index 2ac0de3c21da..8acaa2ddb335 100644 --- a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi +++ b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi @@ -34,6 +34,13 @@ * ... * }; * + * + * Below sample doesn't use "format" property, + * because test-component driver (test-cpu/test-codec) is supporting + * snd_soc_dai_ops :: .auto_selectable_formats. + * see + * snd_soc_runtime_get_dai_fmt() + * linux/sound/soc/generic/test-component.c :: test_dai_formats */ / { /* diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 98732468a992..b1c675c6b6db 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -47,6 +47,18 @@ see graph_parse_daifmt(). + "format" property is no longer needed on DT if both CPU/Codec drivers are + supporting snd_soc_dai_ops :: .auto_selectable_formats. + see + snd_soc_runtime_get_dai_fmt() + + sample driver + linux/sound/soc/sh/rcar/core.c + linux/sound/soc/codecs/ak4613.c + linux/sound/soc/codecs/pcm3168a.c + linux/sound/soc/soc-utils.c + linux/sound/soc/generic/test-component.c + ************************************ Normal Audio-Graph ************************************ -- cgit v1.2.3 From a74048432fbb30e7a574747f6e1f47aef17010b0 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 23 Aug 2023 09:32:50 -0700 Subject: ASoC: cs42l43: Initialize ret in default case in cs42l43_pll_ev() clang warns (or errors with CONFIG_WERROR=y): sound/soc/codecs/cs42l43.c:1371:2: error: variable 'ret' is used uninitialized whenever switch default is taken [-Werror,-Wsometimes-uninitialized] 1371 | default: | ^~~~~~~ sound/soc/codecs/cs42l43.c:1377:9: note: uninitialized use occurs here 1377 | return ret; | ^~~ sound/soc/codecs/cs42l43.c:1349:9: note: initialize the variable 'ret' to silence this warning 1349 | int ret; | ^ | = 0 1 error generated. Initialize ret to 0 in the default case, as there was nothing to do for other event types. Closes: https://github.com/ClangBuiltLinux/linux/issues/1922 Fixes: fc918cbe874e ("ASoC: cs42l43: Add support for the cs42l43") Signed-off-by: Nathan Chancellor Link: https://lore.kernel.org/r/20230823-cs42l43_pll_ev-init-ret-v1-1-5836f1ad5dad@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l43.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c index 55a79219af35..18178ffa82f2 100644 --- a/sound/soc/codecs/cs42l43.c +++ b/sound/soc/codecs/cs42l43.c @@ -1369,6 +1369,7 @@ static int cs42l43_pll_ev(struct snd_soc_dapm_widget *w, clk_disable_unprepare(priv->mclk); break; default: + ret = 0; break; } -- cgit v1.2.3 From 581523ee3652ea6c1012b2ccbb8588c9c77ef4bb Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Wed, 23 Aug 2023 15:39:56 +0100 Subject: 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(+) (limited to 'sound') 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 }, {} }; -- cgit v1.2.3 From 93dc18e11b1ab2d485b69f91c973e6b83e47ebd0 Mon Sep 17 00:00:00 2001 From: SungHwan Jung Date: Wed, 23 Aug 2023 20:40:51 +0900 Subject: 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(+) (limited to 'sound') 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), -- cgit v1.2.3 From 22459ef3a9dea5249c250b30046c3b31cc684da9 Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Tue, 22 Aug 2023 19:05:41 +0400 Subject: 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(-) (limited to 'sound') 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; } -- cgit v1.2.3 From 67de40c9df94037769967ba28c7d951afb45b7fb Mon Sep 17 00:00:00 2001 From: Su Hui Date: Wed, 23 Aug 2023 10:52:13 +0800 Subject: 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(-) (limited to 'sound') 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]) -- cgit v1.2.3 From 5f11dd938fe7657899ca79b2ffc4d708e43f4737 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 24 Aug 2023 09:51:05 +0200 Subject: 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(-) (limited to 'sound') 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: -- cgit v1.2.3 From 1761f4cc114af531020ea190df6a24dd288a8221 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 24 Aug 2023 09:51:06 +0200 Subject: 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(+) (limited to 'sound') 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; } -- cgit v1.2.3 From b2bcbd031d34d1ba1f491b9152474cf9f6d4d51b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 24 Aug 2023 09:51:07 +0200 Subject: 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 --- sound/core/ump.c | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) (limited to 'sound') 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); -- cgit v1.2.3 From 2b59332ead54870ed0f1a8b122a1d640a4865fdc Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 24 Aug 2023 11:39:02 +0100 Subject: ASoC: cs42l43: Use new-style PM runtime macros Update to the newer style PM runtime macros, no functional change. Signed-off-by: Charles Keepax Date: Thu, 24 Aug 2023 02:02:49 +0000 Subject: ASoC: audio-graph-card.c: move audio_graph_parse_of() Current audio-graph-card functions definition are like below (A)' static int graph_get_dais_count(); (B) int audio_graph_parse_of(...) { ... (A) ret = graph_get_dais_count(); ... } (A) static int graph_get_dais_count(...) { ... } (C) We don't need to have (A)' definition if audio_graph_parse_of() (B) was defined at (C). This patch moves (B) to (C). Signed-off-by: Kuninori Morimoto owner = THIS_MODULE; - card->dev = dev; - - ret = graph_get_dais_count(priv, li); - if (ret < 0) - return ret; - - if (!li->link) - return -EINVAL; - - ret = asoc_simple_init_priv(priv, li); - if (ret < 0) - return ret; - - priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); - if (IS_ERR(priv->pa_gpio)) { - ret = PTR_ERR(priv->pa_gpio); - dev_err(dev, "failed to get amplifier gpio: %d\n", ret); - return ret; - } - - ret = asoc_simple_parse_widgets(card, NULL); - if (ret < 0) - return ret; - - ret = asoc_simple_parse_routing(card, NULL); - if (ret < 0) - return ret; - - memset(li, 0, sizeof(*li)); - ret = graph_for_each_link(priv, li, - graph_dai_link_of, - graph_dai_link_of_dpcm); - if (ret < 0) - goto err; - - ret = asoc_simple_parse_card_name(card, NULL); - if (ret < 0) - goto err; - - snd_soc_card_set_drvdata(card, priv); - - asoc_simple_debug_info(priv); - - ret = devm_snd_soc_register_card(dev, card); - if (ret < 0) - goto err; - - devm_kfree(dev, li); - return 0; - -err: - asoc_simple_clean_reference(card); - - return dev_err_probe(dev, ret, "parse error\n"); -} -EXPORT_SYMBOL_GPL(audio_graph_parse_of); - static int graph_count_noml(struct asoc_simple_priv *priv, struct device_node *cpu_ep, struct device_node *codec_ep, @@ -612,6 +541,74 @@ static int graph_get_dais_count(struct asoc_simple_priv *priv, graph_count_dpcm); } +int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev) +{ + struct snd_soc_card *card = simple_priv_to_card(priv); + struct link_info *li; + int ret; + + li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL); + if (!li) + return -ENOMEM; + + card->owner = THIS_MODULE; + card->dev = dev; + + ret = graph_get_dais_count(priv, li); + if (ret < 0) + return ret; + + if (!li->link) + return -EINVAL; + + ret = asoc_simple_init_priv(priv, li); + if (ret < 0) + return ret; + + priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); + if (IS_ERR(priv->pa_gpio)) { + ret = PTR_ERR(priv->pa_gpio); + dev_err(dev, "failed to get amplifier gpio: %d\n", ret); + return ret; + } + + ret = asoc_simple_parse_widgets(card, NULL); + if (ret < 0) + return ret; + + ret = asoc_simple_parse_routing(card, NULL); + if (ret < 0) + return ret; + + memset(li, 0, sizeof(*li)); + ret = graph_for_each_link(priv, li, + graph_dai_link_of, + graph_dai_link_of_dpcm); + if (ret < 0) + goto err; + + ret = asoc_simple_parse_card_name(card, NULL); + if (ret < 0) + goto err; + + snd_soc_card_set_drvdata(card, priv); + + asoc_simple_debug_info(priv); + + ret = devm_snd_soc_register_card(dev, card); + if (ret < 0) + goto err; + + devm_kfree(dev, li); + return 0; + +err: + asoc_simple_clean_reference(card); + + return dev_err_probe(dev, ret, "parse error\n"); +} +EXPORT_SYMBOL_GPL(audio_graph_parse_of); + static int graph_probe(struct platform_device *pdev) { struct asoc_simple_priv *priv; -- cgit v1.2.3 From 8886e1b03669c498f7a24bc5e483f46db5e81f82 Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Thu, 24 Aug 2023 12:17:10 -0700 Subject: ASoC: codecs: Fix error code in aw88261_i2c_probe() Passing zero to dev_err_probe is a success which is incorrect when i2c_check_functionality() fails. Fix this by passing -ENXIO instead of zero to dev_err_probe(). Fixes: 028a2ae25691 ("ASoC: codecs: Add aw88261 amplifier driver") Reported-by: kernel test robot adapter, I2C_FUNC_I2C); if (!ret) - return dev_err_probe(&i2c->dev, ret, "check_functionality failed"); + return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed"); aw88261 = devm_kzalloc(&i2c->dev, sizeof(*aw88261), GFP_KERNEL); if (!aw88261) -- cgit v1.2.3 From 199cd64140f222c66b68ebe288a3fcd0570e2e41 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Thu, 24 Aug 2023 22:38:37 +0300 Subject: ASoC: soc-core.c: Do not error if a DAI link component is not found A recent cleanup of soc_dai_link_sanity_check() is responsible for generating lots of confusing errors before returning -EPROBE_DEFER: acp5x_mach acp5x_mach.0: ASoC: Component acp5x_i2s_dma.0 not found for link acp5x-8821-play [...] acp5x_mach acp5x_mach.0: ASoC: Component spi-VLV1776:00 not found for link acp5x-CS35L41-Stereo [...] acp5x_mach acp5x_mach.0: ASoC: Component spi-VLV1776:01 not found for link acp5x-CS35L41-Stereo Switch back to the initial behaviour of logging those messages on KERN_DEBUG level instead of KERN_ERR. While at it, use the correct form of the verb in 'component_not_find' label. Fixes: 0e66a2c69409 ("ASoC: soc-core.c: cleanup soc_dai_link_sanity_check()") Signed-off-by: Cristian Ciocaltea 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); +component_not_found: + dev_dbg(card->dev, "ASoC: Component %s not found for link %s\n", dlc->name, link->name); return -EPROBE_DEFER; dai_empty: -- cgit v1.2.3 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: 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(-) (limited to 'sound') 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); -- cgit v1.2.3 From c99c26b16c1544534ebd6a5f27a034f3e44d2597 Mon Sep 17 00:00:00 2001 From: Fabian Vogt Date: Thu, 24 Aug 2023 20:39:48 +0200 Subject: 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(+) (limited to 'sound') 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), -- cgit v1.2.3 From 61698d3fbdcd36b65ab524183c73de8bc0693a1f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 25 Aug 2023 11:28:19 +0200 Subject: 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(+) (limited to 'sound') 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 -- cgit v1.2.3 From 4aa69d64e43edb51a4ecff7d301e9f881eb2d3f5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 26 Aug 2023 09:21:51 +0200 Subject: 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(-) (limited to 'sound') 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; -- cgit v1.2.3 From ab574d1629552b6831cd91b926b38092c15d6142 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 28 Aug 2023 12:19:24 +0200 Subject: ALSA: usb-audio: Don't try to submit URBs after disconnection USB-audio driver can still submit URBs while the device is being disconnected, and it may result in spurious error messages like: usb 1-2: cannot submit urb (err = -19) usb 1-2: Unable to submit urb #0: -19 at snd_usb_queue_pending_output_urbs usb 1-2: cannot submit urb 0, error -19: no device Although those are harmless, they are just ugly. This patch tries to avoid spewing such error messages when the device is already at the disconnected state. It also skips the superfluous xfer notification, too. Link: https://lore.kernel.org/r/20230828101924.27107-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index a385e85c4650..8f65349a06d3 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -505,13 +505,18 @@ int snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep, return -EPIPE; } - err = usb_submit_urb(ctx->urb, GFP_ATOMIC); + if (!atomic_read(&ep->chip->shutdown)) + err = usb_submit_urb(ctx->urb, GFP_ATOMIC); + else + err = -ENODEV; if (err < 0) { - usb_audio_err(ep->chip, - "Unable to submit urb #%d: %d at %s\n", - ctx->index, err, __func__); - if (!in_stream_lock) - notify_xrun(ep); + if (!atomic_read(&ep->chip->shutdown)) { + usb_audio_err(ep->chip, + "Unable to submit urb #%d: %d at %s\n", + ctx->index, err, __func__); + if (!in_stream_lock) + notify_xrun(ep); + } return -EPIPE; } @@ -575,12 +580,17 @@ static void snd_complete_urb(struct urb *urb) prepare_inbound_urb(ep, ctx); } - err = usb_submit_urb(urb, GFP_ATOMIC); + if (!atomic_read(&ep->chip->shutdown)) + err = usb_submit_urb(urb, GFP_ATOMIC); + else + err = -ENODEV; if (err == 0) return; - usb_audio_err(ep->chip, "cannot submit urb (err = %d)\n", err); - notify_xrun(ep); + if (!atomic_read(&ep->chip->shutdown)) { + usb_audio_err(ep->chip, "cannot submit urb (err = %d)\n", err); + notify_xrun(ep); + } exit_clear: clear_bit(ctx->index, &ep->active_mask); @@ -1603,11 +1613,15 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) goto __error; } - err = usb_submit_urb(urb, GFP_ATOMIC); + if (!atomic_read(&ep->chip->shutdown)) + err = usb_submit_urb(urb, GFP_ATOMIC); + else + err = -ENODEV; if (err < 0) { - usb_audio_err(ep->chip, - "cannot submit urb %d, error %d: %s\n", - i, err, usb_error_string(err)); + if (!atomic_read(&ep->chip->shutdown)) + usb_audio_err(ep->chip, + "cannot submit urb %d, error %d: %s\n", + i, err, usb_error_string(err)); goto __error; } set_bit(i, &ep->active_mask); -- cgit v1.2.3 From 8d2a0cdf52299d1f83a7707c5ca6b0c811339aba Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 28 Aug 2023 13:35:37 +0200 Subject: ASoC: dwc: i2s: Fix unused functions A few newly added functions aren't built unless CONFIG_OF is set, which result in the build failure due to defined-but-not-used errors. Put "#ifdef CONFIG_OF" around those functions to suppress the build error. Fixes: 52ea7c0543f8 ("ASoC: dwc: i2s: Add StarFive JH7110 SoC support") Link: https://lore.kernel.org/r/20230828113537.27600-1-tiwai@suse.de Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/dwc/dwc-i2s.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index 5ab1b3eb2d28..22c004179214 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -729,6 +729,7 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, } +#ifdef CONFIG_OF /* clocks initialization with master mode on JH7110 SoC */ static int jh7110_i2s_crg_master_init(struct dw_i2s_dev *dev) { @@ -912,6 +913,7 @@ static int jh7110_i2stx0_clk_cfg(struct i2s_clk_config_data *config) return clk_set_rate(dev->clk, bclk_rate); } +#endif /* CONFIG_OF */ static int dw_i2s_probe(struct platform_device *pdev) { -- cgit v1.2.3 From 358040e3807754944dbddf948a23c6d914297ed7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 29 Aug 2023 15:43:44 +0200 Subject: ALSA: pcm: Fix missing fixup call in compat hw_refine ioctl The update of rate_num/den and msbits were factored out to fixup_unreferenced_params() function to be called explicitly after the hw_refine or hw_params procedure. It's called from snd_pcm_hw_refine_user(), but it's forgotten in the PCM compat ioctl. This ended up with the incomplete rate_num/den and msbits parameters when 32bit compat ioctl is used. This patch adds the missing call in snd_pcm_ioctl_hw_params_compat(). Reported-by: Meng_Cai@novatek.com.cn Fixes: f9a076bff053 ("ALSA: pcm: calculate non-mask/non-interval parameters always when possible") Reviewed-by: Takashi Sakamoto Reviewed-by: Jaroslav Kysela Cc: Link: https://lore.kernel.org/r/20230829134344.31588-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/pcm_compat.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 42c2ada8e888..c96483091f30 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -253,10 +253,14 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, goto error; } - if (refine) + if (refine) { err = snd_pcm_hw_refine(substream, data); - else + if (err < 0) + goto error; + err = fixup_unreferenced_params(substream, data); + } else { err = snd_pcm_hw_params(substream, data); + } if (err < 0) goto error; if (copy_to_user(data32, data, sizeof(*data32)) || -- cgit v1.2.3